diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
commit | 486754660bb926339aefcf012a3f848592babb8b (patch) | |
tree | ecdbc446c9876f4f120f701c243373cd3cb43db3 /lib/Parse/ParseTemplate.cpp | |
parent | 55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff) |
Notes
Diffstat (limited to 'lib/Parse/ParseTemplate.cpp')
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 383 |
1 files changed, 259 insertions, 124 deletions
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 56a16b9e02711..f7a69c482e17a 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -21,27 +21,22 @@ #include "clang/Sema/Scope.h" using namespace clang; -/// \brief Parse a template declaration, explicit instantiation, or +/// Parse a template declaration, explicit instantiation, or /// explicit specialization. -Decl * -Parser::ParseDeclarationStartingWithTemplate(unsigned Context, - SourceLocation &DeclEnd, - AccessSpecifier AS, - AttributeList *AccessAttrs) { +Decl *Parser::ParseDeclarationStartingWithTemplate( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS) { ObjCDeclContextSwitch ObjCDC(*this); if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { - return ParseExplicitInstantiation(Context, - SourceLocation(), ConsumeToken(), - DeclEnd, AS); + return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), + DeclEnd, AccessAttrs, AS); } - return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS, - AccessAttrs); + return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, + AS); } - - -/// \brief Parse a template declaration or an explicit specialization. +/// Parse a template declaration or an explicit specialization. /// /// Template declarations include one or more template parameter lists /// and either the function or class template declaration. Explicit @@ -56,11 +51,9 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context, /// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration -Decl * -Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, - SourceLocation &DeclEnd, - AccessSpecifier AS, - AttributeList *AccessAttrs) { +Decl *Parser::ParseTemplateDeclarationOrSpecialization( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS) { assert(Tok.isOneOf(tok::kw_export, tok::kw_template) && "Token does not start a template declaration."); @@ -149,15 +142,13 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); // Parse the actual template declaration. - return ParseSingleDeclarationAfterTemplate(Context, - ParsedTemplateInfo(&ParamLists, - isSpecialization, - LastParamListWasEmpty), - ParsingTemplateParams, - DeclEnd, AS, AccessAttrs); + return ParseSingleDeclarationAfterTemplate( + Context, + ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), + ParsingTemplateParams, DeclEnd, AccessAttrs, AS); } -/// \brief Parse a single declaration that declares a template, +/// Parse a single declaration that declares a template, /// template specialization, or explicit instantiation of a template. /// /// \param DeclEnd will receive the source location of the last token @@ -167,14 +158,10 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, /// declaration. Will be AS_none for namespace-scope declarations. /// /// \returns the new declaration. -Decl * -Parser::ParseSingleDeclarationAfterTemplate( - unsigned Context, - const ParsedTemplateInfo &TemplateInfo, - ParsingDeclRAIIObject &DiagsFromTParams, - SourceLocation &DeclEnd, - AccessSpecifier AS, - AttributeList *AccessAttrs) { +Decl *Parser::ParseSingleDeclarationAfterTemplate( + DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS) { assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && "Template information required"); @@ -186,7 +173,7 @@ Parser::ParseSingleDeclarationAfterTemplate( return ParseStaticAssertDeclaration(DeclEnd); } - if (Context == Declarator::MemberContext) { + if (Context == DeclaratorContext::MemberContext) { // We are parsing a member template. ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo, &DiagsFromTParams); @@ -234,7 +221,7 @@ Parser::ParseSingleDeclarationAfterTemplate( DS.takeAttributesFrom(prefixAttrs); // Parse the declarator. - ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context); + ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { @@ -255,7 +242,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Function definitions are only allowed at file scope and in C++ classes. // The C++ inline method definition case is handled elsewhere, so we only // need to handle the file scope definition case. - if (Context != Declarator::FileContext) { + if (Context != DeclaratorContext::FileContext) { Diag(Tok, diag::err_function_definition_not_allowed); SkipMalformedDecl(); return nullptr; @@ -271,7 +258,8 @@ Parser::ParseSingleDeclarationAfterTemplate( } if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { - if (DeclaratorInfo.getName().getKind() != UnqualifiedId::IK_TemplateId) { + if (DeclaratorInfo.getName().getKind() != + UnqualifiedIdKind::IK_TemplateId) { // If the declarator-id is not a template-id, issue a diagnostic and // recover by ignoring the 'template' keyword. Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0; @@ -369,7 +357,7 @@ bool Parser::ParseTemplateParameters( /// template-parameter /// template-parameter-list ',' template-parameter bool -Parser::ParseTemplateParameterList(unsigned Depth, +Parser::ParseTemplateParameterList(const unsigned Depth, SmallVectorImpl<NamedDecl*> &TemplateParams) { while (1) { @@ -402,7 +390,7 @@ Parser::ParseTemplateParameterList(unsigned Depth, return true; } -/// \brief Determine whether the parser is at the start of a template +/// Determine whether the parser is at the start of a template /// type parameter. bool Parser::isStartOfTemplateTypeParameter() { if (Tok.is(tok::kw_class)) { @@ -487,6 +475,20 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); + // Is there just a typo in the input code? ('typedef' instead of 'typename') + if (Tok.is(tok::kw_typedef)) { + Diag(Tok.getLocation(), diag::err_expected_template_parameter); + + Diag(Tok.getLocation(), diag::note_meant_to_use_typename) + << FixItHint::CreateReplacement(CharSourceRange::getCharRange( + Tok.getLocation(), Tok.getEndLoc()), + "typename"); + + Tok.setKind(tok::kw_typename); + + return ParseTypeParameter(Depth, Position); + } + // If it's none of the above, then it must be a parameter declaration. // NOTE: This will pick up errors in the closure of the template parameter // list (e.g., template < ; Check here to implement >> style closures. @@ -546,7 +548,7 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { ParsedType DefaultArg; if (TryConsumeToken(tok::equal, EqualLoc)) DefaultArg = ParseTypeName(/*Range=*/nullptr, - Declarator::TemplateTypeArgContext).get(); + DeclaratorContext::TemplateTypeArgContext).get(); return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc, KeyLoc, ParamName, NameLoc, Depth, Position, @@ -676,10 +678,10 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // declarators (parts of declarators?) are accepted for parameters. DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, - DSC_template_param); + DeclSpecContext::DSC_template_param); // Parse this as a typename. - Declarator ParamDecl(DS, Declarator::TemplateParamContext); + Declarator ParamDecl(DS, DeclaratorContext::TemplateParamContext); ParseDeclarator(ParamDecl); if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { Diag(Tok.getLocation(), diag::err_expected_template_parameter); @@ -739,7 +741,7 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, AlreadyHasEllipsis, D.hasName()); } -/// \brief Parses a '>' at the end of a template list. +/// Parses a '>' at the end of a template list. /// /// If this function encounters '>>', '>>>', '>=', or '>>=', it tries /// to determine if these tokens were supposed to be a '>' followed by @@ -760,6 +762,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, // What will be left once we've consumed the '>'. tok::TokenKind RemainingToken; const char *ReplacementStr = "> >"; + bool MergeWithNextToken = false; switch (Tok.getKind()) { default: @@ -785,6 +788,15 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, case tok::greaterequal: RemainingToken = tok::equal; ReplacementStr = "> ="; + + // Join two adjacent '=' tokens into one, for cases like: + // void (*p)() = f<int>; + // return f<int>==p; + if (NextToken().is(tok::equal) && + areTokensAdjacent(Tok, NextToken())) { + RemainingToken = tok::equalequal; + MergeWithNextToken = true; + } break; case tok::greatergreaterequal: @@ -792,22 +804,35 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, break; } - // This template-id is terminated by a token which starts with a '>'. Outside - // C++11, this is now error recovery, and in C++11, this is error recovery if - // the token isn't '>>' or '>>>'. - // '>>>' is for CUDA, where this sequence of characters is parsed into - // tok::greatergreatergreater, rather than two separate tokens. + // This template-id is terminated by a token that starts with a '>'. + // Outside C++11 and Objective-C, this is now error recovery. + // + // C++11 allows this when the token is '>>', and in CUDA + C++11 mode, we + // extend that treatment to also apply to the '>>>' token. // - // We always allow this for Objective-C type parameter and type argument - // lists. - RAngleLoc = Tok.getLocation(); + // Objective-C allows this in its type parameter / argument lists. + + SourceLocation TokBeforeGreaterLoc = PrevTokLocation; + SourceLocation TokLoc = Tok.getLocation(); Token Next = NextToken(); + + // Whether splitting the current token after the '>' would undesirably result + // in the remaining token pasting with the token after it. This excludes the + // MergeWithNextToken cases, which we've already handled. + bool PreventMergeWithNextToken = + (RemainingToken == tok::greater || + RemainingToken == tok::greatergreater) && + (Next.isOneOf(tok::greater, tok::greatergreater, + tok::greatergreatergreater, tok::equal, tok::greaterequal, + tok::greatergreaterequal, tok::equalequal)) && + areTokensAdjacent(Tok, Next); + + // Diagnose this situation as appropriate. if (!ObjCGenericList) { - // The source range of the '>>' or '>=' at the start of the token. - CharSourceRange ReplacementRange = - CharSourceRange::getCharRange(RAngleLoc, - Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), - getLangOpts())); + // The source range of the replaced token(s). + CharSourceRange ReplacementRange = CharSourceRange::getCharRange( + TokLoc, Lexer::AdvanceToTokenCharacter(TokLoc, 2, PP.getSourceManager(), + getLangOpts())); // A hint to put a space between the '>>'s. In order to make the hint as // clear as possible, we include the characters either side of the space in @@ -818,13 +843,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, // A hint to put another space after the token, if it would otherwise be // lexed differently. FixItHint Hint2; - if ((RemainingToken == tok::greater || - RemainingToken == tok::greatergreater) && - (Next.isOneOf(tok::greater, tok::greatergreater, - tok::greatergreatergreater, tok::equal, - tok::greaterequal, tok::greatergreaterequal, - tok::equalequal)) && - areTokensAdjacent(Tok, Next)) + if (PreventMergeWithNextToken) Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); unsigned DiagId = diag::err_two_right_angle_brackets_need_space; @@ -833,55 +852,68 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; else if (Tok.is(tok::greaterequal)) DiagId = diag::err_right_angle_bracket_equal_needs_space; - Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + Diag(TokLoc, DiagId) << Hint1 << Hint2; } + // Find the "length" of the resulting '>' token. This is not always 1, as it + // can contain escaped newlines. + unsigned GreaterLength = Lexer::getTokenPrefixLength( + TokLoc, 1, PP.getSourceManager(), getLangOpts()); + + // Annotate the source buffer to indicate that we split the token after the + // '>'. This allows us to properly find the end of, and extract the spelling + // of, the '>' token later. + RAngleLoc = PP.SplitToken(TokLoc, GreaterLength); + // Strip the initial '>' from the token. - Token PrevTok = Tok; - if (RemainingToken == tok::equal && Next.is(tok::equal) && - areTokensAdjacent(Tok, Next)) { - // Join two adjacent '=' tokens into one, for cases like: - // void (*p)() = f<int>; - // return f<int>==p; + bool CachingTokens = PP.IsPreviousCachedToken(Tok); + + Token Greater = Tok; + Greater.setLocation(RAngleLoc); + Greater.setKind(tok::greater); + Greater.setLength(GreaterLength); + + unsigned OldLength = Tok.getLength(); + if (MergeWithNextToken) { ConsumeToken(); - Tok.setKind(tok::equalequal); - Tok.setLength(Tok.getLength() + 1); - } else { - Tok.setKind(RemainingToken); - Tok.setLength(Tok.getLength() - 1); + OldLength += Tok.getLength(); } - Tok.setLocation(Lexer::AdvanceToTokenCharacter(RAngleLoc, 1, - PP.getSourceManager(), - getLangOpts())); - - // The advance from '>>' to '>' in a ObjectiveC template argument list needs - // to be properly reflected in the token cache to allow correct interaction - // between annotation and backtracking. - if (ObjCGenericList && PrevTok.getKind() == tok::greatergreater && - RemainingToken == tok::greater && PP.IsPreviousCachedToken(PrevTok)) { - PrevTok.setKind(RemainingToken); - PrevTok.setLength(1); - // Break tok::greatergreater into two tok::greater but only add the second - // one in case the client asks to consume the last token. + + Tok.setKind(RemainingToken); + Tok.setLength(OldLength - GreaterLength); + + // Split the second token if lexing it normally would lex a different token + // (eg, the fifth token in 'A<B>>>' should re-lex as '>', not '>>'). + SourceLocation AfterGreaterLoc = TokLoc.getLocWithOffset(GreaterLength); + if (PreventMergeWithNextToken) + AfterGreaterLoc = PP.SplitToken(AfterGreaterLoc, Tok.getLength()); + Tok.setLocation(AfterGreaterLoc); + + // Update the token cache to match what we just did if necessary. + if (CachingTokens) { + // If the previous cached token is being merged, delete it. + if (MergeWithNextToken) + PP.ReplacePreviousCachedToken({}); + if (ConsumeLastToken) - PP.ReplacePreviousCachedToken({PrevTok, Tok}); + PP.ReplacePreviousCachedToken({Greater, Tok}); else - PP.ReplacePreviousCachedToken({PrevTok}); + PP.ReplacePreviousCachedToken({Greater}); } - if (!ConsumeLastToken) { - // Since we're not supposed to consume the '>' token, we need to push - // this token and revert the current token back to the '>'. + if (ConsumeLastToken) { + PrevTokLocation = RAngleLoc; + } else { + PrevTokLocation = TokBeforeGreaterLoc; PP.EnterToken(Tok); - Tok.setKind(tok::greater); - Tok.setLength(1); - Tok.setLocation(RAngleLoc); + Tok = Greater; } + return false; } -/// \brief Parses a template-id that after the template name has +/// Parses a template-id that after the template name has /// already been parsed. /// /// This routine takes care of parsing the enclosed template argument @@ -923,7 +955,7 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, /*ObjCGenericList=*/false); } -/// \brief Replace the tokens that form a simple-template-id with an +/// Replace the tokens that form a simple-template-id with an /// annotation token containing the complete template-id. /// /// The first token in the stream must be the name of a template that @@ -1015,12 +1047,12 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, Tok.setKind(tok::annot_template_id); IdentifierInfo *TemplateII = - TemplateName.getKind() == UnqualifiedId::IK_Identifier + TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier ? TemplateName.Identifier : nullptr; OverloadedOperatorKind OpKind = - TemplateName.getKind() == UnqualifiedId::IK_Identifier + TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier ? OO_None : TemplateName.OperatorFunctionId.Operator; @@ -1044,7 +1076,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, return false; } -/// \brief Replaces a template-id annotation token with a type +/// Replaces a template-id annotation token with a type /// annotation token. /// /// If there was a failure when forming the type from the template-id, @@ -1089,12 +1121,12 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) { PP.AnnotateCachedTokens(Tok); } -/// \brief Determine whether the given token can end a template argument. +/// Determine whether the given token can end a template argument. static bool isEndOfTemplateArgument(Token Tok) { return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater); } -/// \brief Parse a C++ template template argument. +/// Parse a C++ template template argument. ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) && !Tok.is(tok::annot_cxxscope)) @@ -1190,17 +1222,13 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // argument before trying to disambiguate. EnterExpressionEvaluationContext EnterConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, + /*ExprContext=*/Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); if (isCXXTypeId(TypeIdAsTemplateArgument)) { - SourceLocation Loc = Tok.getLocation(); - TypeResult TypeArg = ParseTypeName(/*Range=*/nullptr, - Declarator::TemplateTypeArgContext); - if (TypeArg.isInvalid()) - return ParsedTemplateArgument(); - - return ParsedTemplateArgument(ParsedTemplateArgument::Type, - TypeArg.get().getAsOpaquePtr(), - Loc); + TypeResult TypeArg = ParseTypeName( + /*Range=*/nullptr, DeclaratorContext::TemplateArgContext); + return Actions.ActOnTemplateTypeArgument(TypeArg); } // Try to parse a template template argument. @@ -1228,7 +1256,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { ExprArg.get(), Loc); } -/// \brief Determine whether the current tokens can only be parsed as a +/// Determine whether the current tokens can only be parsed as a /// template argument list (starting with the '<') and never as a '<' /// expression. bool Parser::IsTemplateArgumentList(unsigned Skip) { @@ -1290,27 +1318,26 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { return false; } -/// \brief Parse a C++ explicit template instantiation +/// Parse a C++ explicit template instantiation /// (C++ [temp.explicit]). /// /// explicit-instantiation: /// 'extern' [opt] 'template' declaration /// /// Note that the 'extern' is a GNU extension and C++11 feature. -Decl *Parser::ParseExplicitInstantiation(unsigned Context, +Decl *Parser::ParseExplicitInstantiation(DeclaratorContext Context, SourceLocation ExternLoc, SourceLocation TemplateLoc, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS) { // This isn't really required here. ParsingDeclRAIIObject ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); - return ParseSingleDeclarationAfterTemplate(Context, - ParsedTemplateInfo(ExternLoc, - TemplateLoc), - ParsingTemplateParams, - DeclEnd, AS); + return ParseSingleDeclarationAfterTemplate( + Context, ParsedTemplateInfo(ExternLoc, TemplateLoc), + ParsingTemplateParams, DeclEnd, AccessAttrs, AS); } SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { @@ -1328,7 +1355,7 @@ void Parser::LateTemplateParserCallback(void *P, LateParsedTemplate &LPT) { ((Parser *)P)->ParseLateTemplatedFuncDef(LPT); } -/// \brief Late parse a C++ function template in Microsoft mode. +/// Late parse a C++ function template in Microsoft mode. void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { if (!LPT.D) return; @@ -1419,7 +1446,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { delete *I; } -/// \brief Lex a delayed template function for late parsing. +/// Lex a delayed template function for late parsing. void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) { tok::TokenKind kind = Tok.getKind(); if (!ConsumeAndStoreFunctionPrologue(Toks)) { @@ -1435,3 +1462,111 @@ void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) { } } } + +/// We've parsed something that could plausibly be intended to be a template +/// name (\p LHS) followed by a '<' token, and the following code can't possibly +/// be an expression. Determine if this is likely to be a template-id and if so, +/// diagnose it. +bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) { + TentativeParsingAction TPA(*this); + // FIXME: We could look at the token sequence in a lot more detail here. + if (SkipUntil(tok::greater, tok::greatergreater, tok::greatergreatergreater, + StopAtSemi | StopBeforeMatch)) { + TPA.Commit(); + + SourceLocation Greater; + ParseGreaterThanInTemplateList(Greater, true, false); + Actions.diagnoseExprIntendedAsTemplateName(getCurScope(), LHS, + Less, Greater); + return true; + } + + // There's no matching '>' token, this probably isn't supposed to be + // interpreted as a template-id. Parse it as an (ill-formed) comparison. + TPA.Revert(); + return false; +} + +void Parser::checkPotentialAngleBracket(ExprResult &PotentialTemplateName) { + assert(Tok.is(tok::less) && "not at a potential angle bracket"); + + bool DependentTemplateName = false; + if (!Actions.mightBeIntendedToBeTemplateName(PotentialTemplateName, + DependentTemplateName)) + return; + + // OK, this might be a name that the user intended to be parsed as a + // template-name, followed by a '<' token. Check for some easy cases. + + // If we have potential_template<>, then it's supposed to be a template-name. + if (NextToken().is(tok::greater) || + (getLangOpts().CPlusPlus11 && + NextToken().isOneOf(tok::greatergreater, tok::greatergreatergreater))) { + SourceLocation Less = ConsumeToken(); + SourceLocation Greater; + ParseGreaterThanInTemplateList(Greater, true, false); + Actions.diagnoseExprIntendedAsTemplateName( + getCurScope(), PotentialTemplateName, Less, Greater); + // FIXME: Perform error recovery. + PotentialTemplateName = ExprError(); + return; + } + + // If we have 'potential_template<type-id', assume it's supposed to be a + // template-name if there's a matching '>' later on. + { + // FIXME: Avoid the tentative parse when NextToken() can't begin a type. + TentativeParsingAction TPA(*this); + SourceLocation Less = ConsumeToken(); + if (isTypeIdUnambiguously() && + diagnoseUnknownTemplateId(PotentialTemplateName, Less)) { + TPA.Commit(); + // FIXME: Perform error recovery. + PotentialTemplateName = ExprError(); + return; + } + TPA.Revert(); + } + + // Otherwise, remember that we saw this in case we see a potentially-matching + // '>' token later on. + AngleBracketTracker::Priority Priority = + (DependentTemplateName ? AngleBracketTracker::DependentName + : AngleBracketTracker::PotentialTypo) | + (Tok.hasLeadingSpace() ? AngleBracketTracker::SpaceBeforeLess + : AngleBracketTracker::NoSpaceBeforeLess); + AngleBrackets.add(*this, PotentialTemplateName.get(), Tok.getLocation(), + Priority); +} + +bool Parser::checkPotentialAngleBracketDelimiter( + const AngleBracketTracker::Loc &LAngle, const Token &OpToken) { + // If a comma in an expression context is followed by a type that can be a + // template argument and cannot be an expression, then this is ill-formed, + // but might be intended to be part of a template-id. + if (OpToken.is(tok::comma) && isTypeIdUnambiguously() && + diagnoseUnknownTemplateId(LAngle.TemplateName, LAngle.LessLoc)) { + AngleBrackets.clear(*this); + return true; + } + + // If a context that looks like a template-id is followed by '()', then + // this is ill-formed, but might be intended to be a template-id + // followed by '()'. + if (OpToken.is(tok::greater) && Tok.is(tok::l_paren) && + NextToken().is(tok::r_paren)) { + Actions.diagnoseExprIntendedAsTemplateName( + getCurScope(), LAngle.TemplateName, LAngle.LessLoc, + OpToken.getLocation()); + AngleBrackets.clear(*this); + return true; + } + + // After a '>' (etc), we're no longer potentially in a construct that's + // intended to be treated as a template-id. + if (OpToken.is(tok::greater) || + (getLangOpts().CPlusPlus11 && + OpToken.isOneOf(tok::greatergreater, tok::greatergreatergreater))) + AngleBrackets.clear(*this); + return false; +} |