Author: Richard Smith Date: 2020-03-27T18:59:01-07:00 New Revision: 0c42539df3d4c697fa3bf6fc88e94b127d334a57
URL: https://github.com/llvm/llvm-project/commit/0c42539df3d4c697fa3bf6fc88e94b127d334a57 DIFF: https://github.com/llvm/llvm-project/commit/0c42539df3d4c697fa3bf6fc88e94b127d334a57.diff LOG: Improve error recovery from missing '>' in template argument list. Produce the conventional "to match this '<'" note, so that the user knows why we expected a '>', and properly handle '>>' in C++11 onwards. Added: Modified: clang/include/clang/Parse/Parser.h clang/include/clang/Sema/ParsedTemplate.h clang/lib/Parse/ParseObjc.cpp clang/lib/Parse/ParseTemplate.cpp clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp clang/test/CXX/drs/dr3xx.cpp clang/test/Parser/cxx-member-initializers.cpp clang/test/Parser/cxx-template-argument.cpp clang/test/Parser/cxx-template-decl.cpp clang/test/Parser/objc-error-qualified-implementation.m clang/test/SemaCXX/decltype.cpp clang/test/SemaCXX/implicit-exception-spec.cpp clang/test/SemaCXX/injected-class-name-crash.cpp clang/test/SemaObjC/crash-on-type-args-protocols.m clang/test/SemaTemplate/ms-delayed-default-template-args.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 6ebceee006e6..333c96e8cd27 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3160,7 +3160,8 @@ class Parser : public CodeCompletionHandler { // C++ 14.3: Template arguments [temp.arg] typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList; - bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, + bool ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, + SourceLocation &RAngleLoc, bool ConsumeLastToken, bool ObjCGenericList); bool ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h index dd77cbf3b9fe..f0245b93c7eb 100644 --- a/clang/include/clang/Sema/ParsedTemplate.h +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -186,7 +186,7 @@ namespace clang { unsigned NumArgs; /// Whether an error was encountered in the template arguments. - /// If so, NumArgs and the trailing argumentst are best-effort. + /// If so, NumArgs and the trailing arguments are best-effort. bool ArgsInvalid; /// Retrieves a pointer to the template arguments diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 1c6163151386..f0a2a482f063 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -523,10 +523,9 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( SkipUntil(tok::greater, tok::at, StopBeforeMatch); if (Tok.is(tok::greater)) ConsumeToken(); - } else if (ParseGreaterThanInTemplateList(rAngleLoc, + } else if (ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, /*ConsumeLastToken=*/true, /*ObjCGenericList=*/true)) { - Diag(lAngleLoc, diag::note_matching) << "'<'"; SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus, tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace, tok::comma, tok::semi }, @@ -1551,7 +1550,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, } // Consume the '>'. - if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken, + if (ParseGreaterThanInTemplateList(LAngleLoc, EndLoc, consumeLastToken, /*ObjCGenericList=*/false)) return true; @@ -1649,7 +1648,7 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( if (allSingleIdentifiers) { // Parse the closing '>'. SourceLocation rAngleLoc; - (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken, /*ObjCGenericList=*/true); // Let Sema figure out what we parsed. @@ -1755,7 +1754,7 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( // Parse the closing '>'. SourceLocation rAngleLoc; - (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken, /*ObjCGenericList=*/true); if (invalid) { diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 9b49a27b731e..518167321f18 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1031,7 +1031,8 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, /// or argument list. /// /// \returns true, if current token does not start with '>', false otherwise. -bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, +bool Parser::ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, + SourceLocation &RAngleLoc, bool ConsumeLastToken, bool ObjCGenericList) { // What will be left once we've consumed the '>'. @@ -1041,7 +1042,8 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, switch (Tok.getKind()) { default: - Diag(Tok.getLocation(), diag::err_expected) << tok::greater; + Diag(getEndOfPreviousToken(), diag::err_expected) << tok::greater; + Diag(LAngleLoc, diag::note_matching) << tok::less; return true; case tok::greater: @@ -1220,15 +1222,15 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, if (Invalid) { // Try to find the closing '>'. - // FIXME: Handle `>>`, `>>>`. - if (ConsumeLastToken) - SkipUntil(tok::greater, StopAtSemi); + if (getLangOpts().CPlusPlus11) + SkipUntil(tok::greater, tok::greatergreater, + tok::greatergreatergreater, StopAtSemi | StopBeforeMatch); else SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); } } - return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken, + return ParseGreaterThanInTemplateList(LAngleLoc, RAngleLoc, ConsumeLastToken, /*ObjCGenericList=*/false) || Invalid; } @@ -1409,7 +1411,8 @@ void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS, /// Determine whether the given token can end a template argument. static bool isEndOfTemplateArgument(Token Tok) { // FIXME: Handle '>>>'. - return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater); + return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater, + tok::greatergreatergreater); } /// Parse a C++ template template argument. @@ -1742,7 +1745,7 @@ bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) { TPA.Commit(); SourceLocation Greater; - ParseGreaterThanInTemplateList(Greater, true, false); + ParseGreaterThanInTemplateList(Less, Greater, true, false); Actions.diagnoseExprIntendedAsTemplateName(getCurScope(), LHS, Less, Greater); return true; @@ -1771,7 +1774,7 @@ void Parser::checkPotentialAngleBracket(ExprResult &PotentialTemplateName) { NextToken().isOneOf(tok::greatergreater, tok::greatergreatergreater))) { SourceLocation Less = ConsumeToken(); SourceLocation Greater; - ParseGreaterThanInTemplateList(Greater, true, false); + ParseGreaterThanInTemplateList(Less, Greater, true, false); Actions.diagnoseExprIntendedAsTemplateName( getCurScope(), PotentialTemplateName, Less, Greater); // FIXME: Perform error recovery. diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp index ef3b127ef82a..8ac4e9733ebb 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp @@ -60,7 +60,7 @@ namespace AnnexD_example { A a; f < a; #if __cplusplus > 201703L - // expected-error@-2 {{expected '>'}} + // expected-error@-2 {{expected '>'}} expected-note@-2 {{to match this '<'}} #endif (f) < a; } diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp index fad91c6a584d..a1501fa563b1 100644 --- a/clang/test/CXX/drs/dr3xx.cpp +++ b/clang/test/CXX/drs/dr3xx.cpp @@ -20,7 +20,7 @@ namespace dr301 { // dr301: yes (void(*)(S, S))operator+<S>; bool b = (void(*)(S, S))operator- < (void(*)(S, S))operator-; - bool c = (void(*)(S, S))operator+ < + bool c = (void(*)(S, S))operator+ < // expected-note {{to match this '<'}} (void(*)(S, S))operator-; // expected-error {{expected '>'}} } diff --git a/clang/test/Parser/cxx-member-initializers.cpp b/clang/test/Parser/cxx-member-initializers.cpp index bd74af1946b6..f5b09752d72b 100644 --- a/clang/test/Parser/cxx-member-initializers.cpp +++ b/clang/test/Parser/cxx-member-initializers.cpp @@ -62,7 +62,7 @@ namespace PR16480 { // FIXME: This should be valid in the union of C99 and C++11. struct F : X<0> { - F() : X<A<T>().n + (T){}.n>{} {} // expected-error +{{}} + F() : X<A<T>().n + (T){}.n>{} {} // expected-error +{{}} expected-note {{to match}} struct T { int n; }; template<typename> struct A { int n; }; @@ -70,7 +70,7 @@ namespace PR16480 { // FIXME: This is valid now, but may be made ill-formed by DR1607. struct G : X<0> { - G() : X<0 && [](){return 0;}()>{} // expected-error +{{}} + G() : X<0 && [](){return 0;}()>{} // expected-error +{{}} expected-note {{to match}} }; struct Errs : X<0> { @@ -103,5 +103,5 @@ class G { void l(int x = C<int, C<int, int>::C1>().f()) {} // This isn't, but it shouldn't crash. The diagnostics don't matter much. - void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}} expected-error {{expected a type}} expected-error {{expected '>'}} + void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}} expected-error {{expected a type}} expected-error {{expected '>'}} expected-note {{to match}} }; diff --git a/clang/test/Parser/cxx-template-argument.cpp b/clang/test/Parser/cxx-template-argument.cpp index 70945e3aa746..0e72cbfbfb17 100644 --- a/clang/test/Parser/cxx-template-argument.cpp +++ b/clang/test/Parser/cxx-template-argument.cpp @@ -9,8 +9,8 @@ template<typename T> struct A {}; // Check for template argument lists followed by junk // FIXME: The diagnostics here aren't great... -A<int+> int x; // expected-error {{expected '>'}} expected-error {{expected unqualified-id}} -A<int x; // expected-error {{expected '>'}} +A<int+> int x; // expected-error {{expected '>'}} expected-note {{to match this '<'}} expected-error {{expected unqualified-id}} +A<int x; // expected-error {{expected '>'}} expected-note {{to match this '<'}} // PR8912 template <bool> struct S {}; diff --git a/clang/test/Parser/cxx-template-decl.cpp b/clang/test/Parser/cxx-template-decl.cpp index fffe75255c24..14b97f12e357 100644 --- a/clang/test/Parser/cxx-template-decl.cpp +++ b/clang/test/Parser/cxx-template-decl.cpp @@ -233,13 +233,13 @@ namespace broken_baseclause { template<typename T> struct base { }; -struct t1 : base<int, - public: // expected-error {{expected expression}} -}; // expected-error {{expected '>'}} +struct t1 : base<int, // expected-note {{to match this '<'}} + public: // expected-error {{expected expression}} expected-error {{expected '>'}} +}; // expected-error@-1 {{expected '{' after base class list}} -struct t2 : base<int, - public // expected-error {{expected expression}} -}; // expected-error {{expected '>'}} +struct t2 : base<int, // expected-note {{to match this '<'}} + public // expected-error {{expected expression}} expected-error {{expected '>'}} +}; // expected-error@-1 {{expected '{' after base class list}} } diff --git a/clang/test/Parser/objc-error-qualified-implementation.m b/clang/test/Parser/objc-error-qualified-implementation.m index 179e2d27479b..684c388a584e 100644 --- a/clang/test/Parser/objc-error-qualified-implementation.m +++ b/clang/test/Parser/objc-error-qualified-implementation.m @@ -17,13 +17,13 @@ @implementation J < P,P > // expected-error {{@implementation declaration cannot @interface K @end -@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}} expected-note{{to match this '<'}} -@end // expected-error {{expected '>'}} +@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}} expected-error {{expected '>'}} expected-note {{to match this '<'}} +@end // rdar://13920026 @implementation I (Cat) <P> // expected-error {{@implementation declaration cannot be protocol qualified}} - (void) Meth {} @end -@implementation I (Cat1) <P // expected-error {{@implementation declaration cannot be protocol qualified}} -@end // expected-error {{expected '>'}} +@implementation I (Cat1) <P // expected-error {{@implementation declaration cannot be protocol qualified}} expected-error {{expected '>'}} expected-note {{to match this '<'}} +@end diff --git a/clang/test/SemaCXX/decltype.cpp b/clang/test/SemaCXX/decltype.cpp index f06ca226bca2..32c61bbccc84 100644 --- a/clang/test/SemaCXX/decltype.cpp +++ b/clang/test/SemaCXX/decltype.cpp @@ -105,5 +105,6 @@ template<typename> class conditional { }; -void foo(conditional<decltype((1),int>) { // expected-note 2 {{to match this '('}} expected-error {{expected ')'}} +// FIXME: The diagnostics here are produced twice. +void foo(conditional<decltype((1),int>) { // expected-note 2 {{to match this '('}} expected-error {{expected ')'}} expected-note 2{{to match this '<'}} } // expected-error {{expected function body after function declarator}} expected-error 2 {{expected '>'}} expected-error {{expected ')'}} diff --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp index 483ed3ca9440..8545e8422b2a 100644 --- a/clang/test/SemaCXX/implicit-exception-spec.cpp +++ b/clang/test/SemaCXX/implicit-exception-spec.cpp @@ -56,7 +56,7 @@ namespace ExceptionSpecification { namespace DefaultArgument { struct Default { struct T { - T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}} expected-error {{expected '>'}} + T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}} expected-error {{expected '>'}} expected-note {{to match this '<'}} } t; // expected-note {{has no default constructor}} }; } diff --git a/clang/test/SemaCXX/injected-class-name-crash.cpp b/clang/test/SemaCXX/injected-class-name-crash.cpp index 7743717c85fc..a044ba064b58 100644 --- a/clang/test/SemaCXX/injected-class-name-crash.cpp +++ b/clang/test/SemaCXX/injected-class-name-crash.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s template <class T> -struct X : public Foo<Bar { // expected-error {{unknown template name 'Foo'}} expected-error {{use of undeclared identifier 'Bar'}} +struct X : public Foo<Bar { // expected-error {{unknown template name 'Foo'}} expected-error {{use of undeclared identifier 'Bar'}} expected-note {{to match this '<'}} X(); }; // expected-error {{expected '>'}} expected-error {{expected '{' after base class list}} diff --git a/clang/test/SemaObjC/crash-on-type-args-protocols.m b/clang/test/SemaObjC/crash-on-type-args-protocols.m index f7d847851faf..0d902631a28c 100644 --- a/clang/test/SemaObjC/crash-on-type-args-protocols.m +++ b/clang/test/SemaObjC/crash-on-type-args-protocols.m @@ -14,27 +14,27 @@ @interface X : NSObject <X> @class A; #ifdef FIRST -id<X> F1(id<[P> v) { // expected-error {{expected a type}} // expected-error {{use of undeclared identifier 'P'}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} +id<X> F1(id<[P> v) { // expected-error {{expected a type}} expected-error {{use of undeclared identifier 'P'}} expected-error {{use of undeclared identifier 'v'}} expected-note {{to match this '('}} expected-note {{to match this '<'}} return 0; -} +} // expected-error {{expected '>'}} #endif #ifdef SECOND -id<X> F2(id<P[X> v) { // expected-error {{unknown type name 'P'}} // expected-error {{unexpected interface name 'X': expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} +id<X> F2(id<P[X> v) { // expected-error {{unknown type name 'P'}} expected-error {{unexpected interface name 'X': expected expression}} expected-error {{use of undeclared identifier 'v'}} expected-note {{to match this '('}} expected-note {{to match this '<'}} return 0; -} +} // expected-error {{expected '>'}} #endif #ifdef THIRD -id<X> F3(id<P, P *[> v) { // expected-error {{unknown type name 'P'}} // expected-error {{expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} +id<X> F3(id<P, P *[> v) { // expected-error {{unknown type name 'P'}} expected-error {{expected expression}} expected-error {{use of undeclared identifier 'v'}} expected-note {{to match this '('}} expected-note {{to match this '<'}} return 0; -} +} // expected-error {{expected '>'}} #endif #ifdef FOURTH -id<X> F4(id<P, P *(> v { // expected-error {{unknown type name 'P'}} // expected-error {{expected ')'}} // expected-note {{to match this '('}} // expected-note {{to match this '('}} +id<X> F4(id<P, P *(> v { // expected-error {{unknown type name 'P'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-note {{to match this '('}} expected-note {{to match this '<'}} return 0; -} +} // expected-error {{expected '>'}} #endif -// expected-error {{expected '>'}} // expected-error {{expected parameter declarator}} // expected-error {{expected ')'}} // expected-error {{expected function body after function declarator}} +// expected-error {{expected parameter declarator}} // expected-error {{expected ')'}} // expected-error {{expected function body after function declarator}} diff --git a/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp b/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp index 008a9c317fe9..3c4690595524 100644 --- a/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp +++ b/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp @@ -49,9 +49,7 @@ template <typename T> struct Bar { T x; }; template <typename T = Bar<Weber>> // expected-error {{use of undeclared identifier 'Weber'}} struct Foo { static_assert(sizeof(T) == 4, "Bar should have gotten int"); - // FIXME: These diagnostics are bad. -}; // expected-error {{expected ',' or '>' in template-parameter-list}} expected-error {{expected '>'}} -// expected-warning@-1 {{does not declare anything}} +}; typedef int Weber; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits