summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Parse/ParseTemplate.cpp')
-rw-r--r--gnu/llvm/tools/clang/lib/Parse/ParseTemplate.cpp430
1 files changed, 282 insertions, 148 deletions
diff --git a/gnu/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/gnu/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
index 611c0779b16..063f7ccea32 100644
--- a/gnu/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
+++ b/gnu/llvm/tools/clang/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(DeclaratorContext 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(DeclaratorContext Context,
///
/// explicit-specialization: [ C++ temp.expl.spec]
/// 'template' '<' '>' declaration
-Decl *
-Parser::ParseTemplateDeclarationOrSpecialization(DeclaratorContext 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(DeclaratorContext 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(DeclaratorContext Context,
/// declaration. Will be AS_none for namespace-scope declarations.
///
/// \returns the new declaration.
-Decl *
-Parser::ParseSingleDeclarationAfterTemplate(
- DeclaratorContext 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");
@@ -373,7 +360,7 @@ bool
Parser::ParseTemplateParameterList(const unsigned Depth,
SmallVectorImpl<NamedDecl*> &TemplateParams) {
while (1) {
-
+
if (NamedDecl *TmpParam
= ParseTemplateParameter(Depth, TemplateParams.size())) {
TemplateParams.push_back(TmpParam);
@@ -403,7 +390,7 @@ Parser::ParseTemplateParameterList(const 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)) {
@@ -416,23 +403,23 @@ bool Parser::isStartOfTemplateTypeParameter() {
case tok::greatergreater:
case tok::ellipsis:
return true;
-
+
case tok::identifier:
- // This may be either a type-parameter or an elaborated-type-specifier.
+ // This may be either a type-parameter or an elaborated-type-specifier.
// We have to look further.
break;
-
+
default:
return false;
}
-
+
switch (GetLookAheadToken(2).getKind()) {
case tok::equal:
case tok::comma:
case tok::greater:
case tok::greatergreater:
return true;
-
+
default:
return false;
}
@@ -477,7 +464,7 @@ bool Parser::isStartOfTemplateTypeParameter() {
/// 'class' identifier[opt] '=' type-id
/// 'typename' ...[opt] identifier[opt]
/// 'typename' identifier[opt] '=' type-id
-/// 'template' '<' template-parameter-list '>'
+/// 'template' '<' template-parameter-list '>'
/// 'class' ...[opt] identifier[opt]
/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
/// = id-expression
@@ -488,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.
@@ -616,7 +617,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
-
+
// Get the identifier, if given.
SourceLocation NameLoc;
IdentifierInfo *ParamName = nullptr;
@@ -651,16 +652,16 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (TryConsumeToken(tok::equal, EqualLoc)) {
DefaultArg = ParseTemplateTemplateArgument();
if (DefaultArg.isInvalid()) {
- Diag(Tok.getLocation(),
+ Diag(Tok.getLocation(),
diag::err_default_template_template_parameter_not_template);
SkipUntil(tok::comma, tok::greater, tok::greatergreater,
StopAtSemi | StopBeforeMatch);
}
}
-
+
return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc,
- ParamList, EllipsisLoc,
- ParamName, NameLoc, Depth,
+ ParamList, EllipsisLoc,
+ ParamName, NameLoc, Depth,
Position, EqualLoc, DefaultArg);
}
@@ -713,8 +714,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
}
// Create the parameter.
- return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
- Depth, Position, EqualLoc,
+ return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
+ Depth, Position, EqualLoc,
DefaultArg.get());
}
@@ -740,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
@@ -761,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:
@@ -786,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:
@@ -793,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
@@ -819,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;
@@ -834,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
@@ -924,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
@@ -1014,7 +1045,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build a template-id annotation token that can be processed
// later.
Tok.setKind(tok::annot_template_id);
-
+
IdentifierInfo *TemplateII =
TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier
? TemplateName.Identifier
@@ -1028,7 +1059,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
-
+
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
@@ -1045,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,
@@ -1090,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))
@@ -1104,13 +1135,13 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
// C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be the name
// of a class template or an alias template, expressed as id-expression.
- //
+ //
// We parse an id-expression that refers to a class template or alias
// template. The grammar we parse is:
//
// nested-name-specifier[opt] template[opt] identifier ...[opt]
//
- // followed by a token that terminates a template argument, such as ',',
+ // followed by a token that terminates a template argument, such as ',',
// '>', or (in some cases) '>>'.
CXXScopeSpec SS; // nested-name-specifier, if present
ParseOptionalCXXScopeSpecifier(SS, nullptr,
@@ -1119,10 +1150,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
ParsedTemplateArgument Result;
SourceLocation EllipsisLoc;
if (SS.isSet() && Tok.is(tok::kw_template)) {
- // Parse the optional 'template' keyword following the
+ // Parse the optional 'template' keyword following the
// nested-name-specifier.
SourceLocation TemplateKWLoc = ConsumeToken();
-
+
if (Tok.is(tok::identifier)) {
// We appear to have a dependent template name.
UnqualifiedId Name;
@@ -1160,16 +1191,16 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
/*EnteringContext=*/false, Template, MemberOfUnknownSpecialization);
if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
// We have an id-expression that refers to a class template or
- // (C++0x) alias template.
+ // (C++0x) alias template.
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
}
}
-
+
// If this is a pack expansion, build it as such.
if (EllipsisLoc.isValid() && !Result.isInvalid())
Result = Actions.ActOnPackExpansion(Result, EllipsisLoc);
-
+
return Result;
}
@@ -1191,19 +1222,15 @@ 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, DeclaratorContext::TemplateTypeArgContext);
- if (TypeArg.isInvalid())
- return ParsedTemplateArgument();
-
- return ParsedTemplateArgument(ParsedTemplateArgument::Type,
- TypeArg.get().getAsOpaquePtr(),
- Loc);
+ /*Range=*/nullptr, DeclaratorContext::TemplateArgContext);
+ return Actions.ActOnTemplateTypeArgument(TypeArg);
}
-
+
// Try to parse a template template argument.
{
TentativeParsingAction TPA(*this);
@@ -1214,35 +1241,35 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
TPA.Commit();
return TemplateTemplateArgument;
}
-
+
// Revert this tentative parse to parse a non-type template argument.
TPA.Revert();
}
-
- // Parse a non-type template argument.
+
+ // Parse a non-type template argument.
SourceLocation Loc = Tok.getLocation();
ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast);
if (ExprArg.isInvalid() || !ExprArg.get())
return ParsedTemplateArgument();
- return ParsedTemplateArgument(ParsedTemplateArgument::NonType,
+ return ParsedTemplateArgument(ParsedTemplateArgument::NonType,
ExprArg.get(), Loc);
}
-/// \brief Determine whether the current tokens can only be parsed as a
-/// template argument list (starting with the '<') and never 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) {
struct AlwaysRevertAction : TentativeParsingAction {
AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { }
~AlwaysRevertAction() { Revert(); }
} Tentative(*this);
-
+
while (Skip) {
ConsumeAnyToken();
--Skip;
}
-
+
// '<'
if (!TryConsumeToken(tok::less))
return false;
@@ -1250,11 +1277,11 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
// An empty template argument list.
if (Tok.is(tok::greater))
return true;
-
+
// See whether we have declaration specifiers, which indicate a type.
while (isCXXDeclarationSpecifier() == TPResult::True)
ConsumeAnyToken();
-
+
// If we have a '>' or a ',' then this is a template argument list.
return Tok.isOneOf(tok::greater, tok::comma);
}
@@ -1267,7 +1294,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
/// template-argument-list ',' template-argument
bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
-
+
ColonProtectionRAIIObject ColonProtection(*this, false);
do {
@@ -1283,7 +1310,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
// Save this template argument.
TemplateArgs.push_back(Arg);
-
+
// If the next token is a comma, consume it and keep reading
// arguments.
} while (TryConsumeToken(tok::comma));
@@ -1291,7 +1318,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
return false;
}
-/// \brief Parse a C++ explicit template instantiation
+/// Parse a C++ explicit template instantiation
/// (C++ [temp.explicit]).
///
/// explicit-instantiation:
@@ -1302,16 +1329,15 @@ 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 {
@@ -1329,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;
@@ -1420,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)) {
@@ -1436,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;
+}