r360827 - Make tentative parsing to detect template-argument-lists less aggressive
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed May 15 16:36:14 PDT 2019
Author: rsmith
Date: Wed May 15 16:36:14 2019
New Revision: 360827
URL: http://llvm.org/viewvc/llvm-project?rev=360827&view=rev
Log:
Make tentative parsing to detect template-argument-lists less aggressive
(and less wrong).
It's not correct to assume that X<something, Type> is always a
template-id; there are a few cases where the comma takes us into a
non-expression syntactic context in which 'Type' might be permissible.
Stop doing that.
This slightly regresses our error recovery on the cases where the
construct is intended to be a template-id. We typically do still manage
to diagnose a missing 'template' keyword, but we realize this too late
to properly recover from the error.
This fixes a regression introduced by r360308.
Modified:
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/test/Parser/cxx-template-argument.cpp
cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=360827&r1=360826&r2=360827&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Wed May 15 16:36:14 2019
@@ -2065,33 +2065,31 @@ Parser::TPResult Parser::isTemplateArgum
if (!TryConsumeToken(tok::less))
return TPResult::False;
+ // We can't do much to tell an expression apart from a template-argument,
+ // but one good distinguishing factor is that a "decl-specifier" not
+ // followed by '(' or '{' can't appear in an expression.
bool InvalidAsTemplateArgumentList = false;
- while (true) {
- // We can't do much to tell an expression apart from a template-argument,
- // but one good distinguishing factor is that a "decl-specifier" not
- // followed by '(' or '{' can't appear in an expression.
- if (isCXXDeclarationSpecifier(
- TPResult::False, &InvalidAsTemplateArgumentList) == TPResult::True)
- return TPResult::True;
-
- // That didn't help, try the next template-argument.
- SkipUntil({tok::comma, tok::greater, tok::greatergreater,
- tok::greatergreatergreater},
- StopAtSemi | StopBeforeMatch);
- switch (Tok.getKind()) {
- case tok::comma:
- ConsumeToken();
- break;
+ if (isCXXDeclarationSpecifier(TPResult::False,
+ &InvalidAsTemplateArgumentList) ==
+ TPResult::True)
+ return TPResult::True;
+ if (InvalidAsTemplateArgumentList)
+ return TPResult::False;
- case tok::greater:
- case tok::greatergreater:
- case tok::greatergreatergreater:
- if (InvalidAsTemplateArgumentList)
- return TPResult::False;
- return TPResult::Ambiguous;
+ // FIXME: In many contexts, X<thing1, Type> can only be a
+ // template-argument-list. But that's not true in general:
+ //
+ // using b = int;
+ // void f() {
+ // int a = A<B, b, c = C>D; // OK, declares b, not a template-id.
+ //
+ // X<Y<0, int> // ', int>' might be end of X's template argument list
+ //
+ // We might be able to disambiguate a few more cases if we're careful.
- default:
- return TPResult::False;
- }
- }
+ // A template-argument-list must be terminated by a '>'.
+ if (SkipUntil({tok::greater, tok::greatergreater, tok::greatergreatergreater},
+ StopAtSemi | StopBeforeMatch))
+ return TPResult::Ambiguous;
+ return TPResult::False;
}
Modified: cfe/trunk/test/Parser/cxx-template-argument.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-argument.cpp?rev=360827&r1=360826&r2=360827&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx-template-argument.cpp (original)
+++ cfe/trunk/test/Parser/cxx-template-argument.cpp Wed May 15 16:36:14 2019
@@ -127,3 +127,14 @@ namespace PR18793 {
template<typename T, T> struct S {};
template<typename T> int g(S<T, (T())> *);
}
+
+namespace r360308_regression {
+ template<typename> struct S1 { static int const n = 0; };
+ template<int, typename> struct S2 { typedef int t; };
+ template<typename T> struct S3 { typename S2<S1<T>::n < 0, int>::t n; };
+
+ template<typename FT> bool f(FT p) {
+ const bool a = p.first<FT(0), b = p.second>FT(0);
+ return a == b;
+ }
+}
Modified: cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp?rev=360827&r1=360826&r2=360827&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp (original)
+++ cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp Wed May 15 16:36:14 2019
@@ -7,7 +7,7 @@ struct X {
t->operator+<U const, 1>(1); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}}
t->f1<int const, 2>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}
- t->f1<3, int const>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}
+ t->f1<3, int const>(1); // expected-error{{missing 'template' keyword prior to dependent template name 'f1'}}
T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
@@ -15,7 +15,7 @@ struct X {
(*t).f2<N>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
(*t).f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
T::f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
- T::f2<0, int>(0); // expected-error{{use 'template' keyword to treat 'f2' as a dependent template name}}
+ T::f2<0, int>(0); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
T::foo<N < 2 || N >= 4>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}
@@ -83,12 +83,12 @@ template<int N, typename T> void f(T t)
T::g<mb>(0);
// ... but this one must be a template-id.
- T::g<mb, int>(0); // expected-error {{use 'template' keyword to treat 'g' as a dependent template name}} expected-error {{no matching function}}
+ T::g<mb, int>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}}
}
struct Y {
template <int> void f(int);
- template <int = 0> static void g(int); // expected-warning 0-1{{extension}} expected-note {{candidate}}
+ template <int = 0> static void g(int); // expected-warning 0-1{{extension}}
};
void q() { void (*p)(int) = Y::g; }
template void f<0>(Y); // expected-note {{in instantiation of}}
More information about the cfe-commits
mailing list