summaryrefslogtreecommitdiff
path: root/lib/Parse/ParseTemplate.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
commit486754660bb926339aefcf012a3f848592babb8b (patch)
treeecdbc446c9876f4f120f701c243373cd3cb43db3 /lib/Parse/ParseTemplate.cpp
parent55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff)
Notes
Diffstat (limited to 'lib/Parse/ParseTemplate.cpp')
-rw-r--r--lib/Parse/ParseTemplate.cpp383
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;
+}