diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e57a5703a7732e83cb65cfade86becf546adc089..66c1d35cbf8e75da21e1030974cd09e5317f7487 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2166,6 +2166,8 @@ private: // C++ 14.3: Template arguments [temp.arg] typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList; + bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, + bool ConsumeLastToken); bool ParseTemplateIdAfterTemplateName(TemplateTy Template, SourceLocation TemplateNameLoc, const CXXScopeSpec &SS, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 3b252d083e765536e7e346396aa949c9993b53c8..6f162fa19129b1e01a198cbcf79cee3579860323 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1200,12 +1200,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, } // Consume the '>'. - if (Tok.isNot(tok::greater)) { - Diag(Tok, diag::err_expected_greater); + if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true)) return true; - } - - EndLoc = ConsumeToken(); // Convert the list of protocols identifiers into a list of protocol decls. Actions.FindProtocolDeclaration(WarnOnDeclarations, diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index f227089acfb9d55e60d8290648cdb194832021bb..80a3a910cce56f2e9b27d4c6ebf72f622ea2dd73 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -665,52 +665,17 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { DefaultArg.take()); } -/// \brief Parses a template-id that after the template name has -/// already been parsed. -/// -/// This routine takes care of parsing the enclosed template argument -/// list ('<' template-parameter-list [opt] '>') and placing the -/// results into a form that can be transferred to semantic analysis. +/// \brief Parses a '>' at the end of a template list. /// -/// \param Template the template declaration produced by isTemplateName -/// -/// \param TemplateNameLoc the source location of the template name +/// If this function encounters '>>', '>>>', '>=', or '>>=', it tries +/// to determine if these tokens were supposed to be a '>' followed by +/// '>', '>>', '>=', or '>='. It emits an appropriate diagnostic if necessary. /// -/// \param SS if non-NULL, the nested-name-specifier preceding the -/// template name. +/// \param RAngleLoc the location of the consumed '>'. /// -/// \param ConsumeLastToken if true, then we will consume the last -/// token that forms the template-id. Otherwise, we will leave the -/// last token in the stream (e.g., so that it can be replaced with an -/// annotation token). -bool -Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, - SourceLocation TemplateNameLoc, - const CXXScopeSpec &SS, - bool ConsumeLastToken, - SourceLocation &LAngleLoc, - TemplateArgList &TemplateArgs, - SourceLocation &RAngleLoc) { - assert(Tok.is(tok::less) && "Must have already parsed the template-name"); - - // Consume the '<'. - LAngleLoc = ConsumeToken(); - - // Parse the optional template-argument-list. - bool Invalid = false; - { - GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); - if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) - Invalid = ParseTemplateArgumentList(TemplateArgs); - - if (Invalid) { - // Try to find the closing '>'. - SkipUntil(tok::greater, true, !ConsumeLastToken); - - return true; - } - } - +/// \param ConsumeLastToken if true, the '>' is not consumed. +bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, + bool ConsumeLastToken) { // What will be left once we've consumed the '>'. tok::TokenKind RemainingToken; const char *ReplacementStr = "> >"; @@ -809,10 +774,59 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, Tok.setLength(1); Tok.setLocation(RAngleLoc); } - return false; } + +/// \brief Parses a template-id that after the template name has +/// already been parsed. +/// +/// This routine takes care of parsing the enclosed template argument +/// list ('<' template-parameter-list [opt] '>') and placing the +/// results into a form that can be transferred to semantic analysis. +/// +/// \param Template the template declaration produced by isTemplateName +/// +/// \param TemplateNameLoc the source location of the template name +/// +/// \param SS if non-NULL, the nested-name-specifier preceding the +/// template name. +/// +/// \param ConsumeLastToken if true, then we will consume the last +/// token that forms the template-id. Otherwise, we will leave the +/// last token in the stream (e.g., so that it can be replaced with an +/// annotation token). +bool +Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, + SourceLocation TemplateNameLoc, + const CXXScopeSpec &SS, + bool ConsumeLastToken, + SourceLocation &LAngleLoc, + TemplateArgList &TemplateArgs, + SourceLocation &RAngleLoc) { + assert(Tok.is(tok::less) && "Must have already parsed the template-name"); + + // Consume the '<'. + LAngleLoc = ConsumeToken(); + + // Parse the optional template-argument-list. + bool Invalid = false; + { + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) + Invalid = ParseTemplateArgumentList(TemplateArgs); + + if (Invalid) { + // Try to find the closing '>'. + SkipUntil(tok::greater, true, !ConsumeLastToken); + + return true; + } + } + + return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken); +} + /// \brief Replace the tokens that form a simple-template-id with an /// annotation token containing the complete template-id. /// diff --git a/test/Parser/objcxx11-protocol-in-template.mm b/test/Parser/objcxx11-protocol-in-template.mm new file mode 100644 index 0000000000000000000000000000000000000000..8cb499396d420e9f0c9ce86fbaa2c130ba752106 --- /dev/null +++ b/test/Parser/objcxx11-protocol-in-template.mm @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s + +template<class T> class vector {}; +@protocol P @end + +#if __cplusplus >= 201103L + // expected-no-diagnostics +#else + // expected-error@14{{a space is required between consecutive right angle brackets}} + // expected-error@15{{a space is required between consecutive right angle brackets}} +#endif + +vector<id<P>> v; +vector<vector<id<P>>> v2;