summaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseTemplate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Parse/ParseTemplate.cpp')
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp429
1 files changed, 214 insertions, 215 deletions
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 1b9301b6591dc..3ef73f5791239 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -22,6 +22,16 @@
#include "llvm/Support/TimeProfiler.h"
using namespace clang;
+/// Re-enter a possible template scope, creating as many template parameter
+/// scopes as necessary.
+/// \return The number of template parameter scopes entered.
+unsigned Parser::ReenterTemplateScopes(MultiParseScope &S, Decl *D) {
+ return Actions.ActOnReenterTemplateScope(D, [&] {
+ S.Enter(Scope::TemplateParamScope);
+ return Actions.getCurScope();
+ });
+}
+
/// Parse a template declaration, explicit instantiation, or
/// explicit specialization.
Decl *Parser::ParseDeclarationStartingWithTemplate(
@@ -67,8 +77,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
"Token does not start a template declaration.");
- // Enter template-parameter scope.
- ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
+ MultiParseScope TemplateParamScopes(*this);
// Tell the action that names should be checked in the context of
// the declaration to come.
@@ -116,7 +125,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
// Parse the '<' template-parameter-list '>'
SourceLocation LAngleLoc, RAngleLoc;
SmallVector<NamedDecl*, 4> TemplateParams;
- if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+ if (ParseTemplateParameters(TemplateParamScopes,
+ CurTemplateDepthTracker.getDepth(),
TemplateParams, LAngleLoc, RAngleLoc)) {
// Skip until the semi-colon or a '}'.
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
@@ -150,9 +160,6 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get()));
} while (Tok.isOneOf(tok::kw_export, tok::kw_template));
- unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope;
- ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);
-
// Parse the actual template declaration.
if (Tok.is(tok::kw_concept))
return ParseConceptDefinition(
@@ -240,6 +247,8 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
// Parse the declarator.
ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
+ if (TemplateInfo.TemplateParams)
+ DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
ParseDeclarator(DeclaratorInfo);
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
@@ -251,9 +260,9 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
}
llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() {
- return DeclaratorInfo.getIdentifier() != nullptr
- ? DeclaratorInfo.getIdentifier()->getName()
- : "<unknown>";
+ return std::string(DeclaratorInfo.getIdentifier() != nullptr
+ ? DeclaratorInfo.getIdentifier()->getName()
+ : "<unknown>");
});
LateParsedAttrList LateParsedAttrs(true);
@@ -361,9 +370,11 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
DiagnoseAndSkipCXX11Attributes();
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
- /*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr,
- /*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) ||
+ if (ParseOptionalCXXScopeSpecifier(
+ SS, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false, /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ /*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) ||
SS.isInvalid()) {
SkipUntil(tok::semi);
return nullptr;
@@ -374,12 +385,12 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
diag::err_concept_definition_not_identifier);
UnqualifiedId Result;
- if (ParseUnqualifiedId(SS, /*EnteringContext=*/false,
+ if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false, /*EnteringContext=*/false,
/*AllowDestructorName=*/false,
/*AllowConstructorName=*/false,
/*AllowDeductionGuide=*/false,
- /*ObjectType=*/ParsedType(), /*TemplateKWLoc=*/nullptr,
- Result)) {
+ /*TemplateKWLoc=*/nullptr, Result)) {
SkipUntil(tok::semi);
return nullptr;
}
@@ -426,8 +437,9 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
///
/// \returns true if an error occurred, false otherwise.
bool Parser::ParseTemplateParameters(
- unsigned Depth, SmallVectorImpl<NamedDecl *> &TemplateParams,
- SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) {
+ MultiParseScope &TemplateScopes, unsigned Depth,
+ SmallVectorImpl<NamedDecl *> &TemplateParams, SourceLocation &LAngleLoc,
+ SourceLocation &RAngleLoc) {
// Get the template parameter list.
if (!TryConsumeToken(tok::less, LAngleLoc)) {
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
@@ -436,8 +448,11 @@ bool Parser::ParseTemplateParameters(
// Try to parse the template parameter list.
bool Failed = false;
- if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater))
+ // FIXME: Missing greatergreatergreater support.
+ if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) {
+ TemplateScopes.Enter(Scope::TemplateParamScope);
Failed = ParseTemplateParameterList(Depth, TemplateParams);
+ }
if (Tok.is(tok::greatergreater)) {
// No diagnostic required here: a template-parameter-list can only be
@@ -499,10 +514,7 @@ Parser::ParseTemplateParameterList(const unsigned Depth,
/// Determine whether the parser is at the start of a template
/// type parameter.
-/// \param ScopeError will receive true if there was an error parsing a
-/// scope specifier at the current location.
-bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
- ScopeError = false;
+Parser::TPResult Parser::isStartOfTemplateTypeParameter() {
if (Tok.is(tok::kw_class)) {
// "class" may be the start of an elaborated-type-specifier or a
// type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter.
@@ -512,7 +524,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
case tok::greater:
case tok::greatergreater:
case tok::ellipsis:
- return true;
+ return TPResult::True;
case tok::identifier:
// This may be either a type-parameter or an elaborated-type-specifier.
@@ -520,7 +532,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
break;
default:
- return false;
+ return TPResult::False;
}
switch (GetLookAheadToken(2).getKind()) {
@@ -528,51 +540,28 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
case tok::comma:
case tok::greater:
case tok::greatergreater:
- return true;
+ return TPResult::True;
default:
- return false;
+ return TPResult::False;
}
}
- bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
- CXXScopeSpec SS;
- ScopeError =
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
- /*EnteringContext=*/false,
- /*MayBePseudoDestructor=*/nullptr,
- // If this is not a type-constraint, then
- // this scope-spec is part of the typename
- // of a non-type template parameter
- /*IsTypename=*/true, /*LastII=*/nullptr,
- // We won't find concepts in
- // non-namespaces anyway, so might as well
- // parse this correctly for possible type
- // names.
- /*OnlyNamespace=*/false);
- if (ScopeError)
- return false;
- if (TryAnnotateTypeConstraint(SS))
- return false;
- bool IsTypeConstraint = isTypeConstraintAnnotation();
- if (!IsTypeConstraint && SS.isNotEmpty()) {
- // This isn't a type-constraint but we've already parsed this scope
- // specifier - annotate it.
- AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation);
- return false;
- }
+ if (TryAnnotateTypeConstraint())
+ return TPResult::Error;
- if (IsTypeConstraint &&
+ if (isTypeConstraintAnnotation() &&
// Next token might be 'auto' or 'decltype', indicating that this
// type-constraint is in fact part of a placeholder-type-specifier of a
// non-type template parameter.
- !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
- return true;
+ !GetLookAheadToken(Tok.is(tok::annot_cxxscope) ? 2 : 1)
+ .isOneOf(tok::kw_auto, tok::kw_decltype))
+ return TPResult::True;
// 'typedef' is a reasonably-common typo/thinko for 'typename', and is
// ill-formed otherwise.
if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef))
- return false;
+ return TPResult::False;
// C++ [temp.param]p2:
// There is no semantic difference between class and typename in a
@@ -592,17 +581,17 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
case tok::greater:
case tok::greatergreater:
case tok::ellipsis:
- return true;
+ return TPResult::True;
case tok::kw_typename:
case tok::kw_typedef:
case tok::kw_class:
// These indicate that a comma was missed after a type parameter, not that
// we have found a non-type parameter.
- return true;
+ return TPResult::True;
default:
- return false;
+ return TPResult::False;
}
}
@@ -627,13 +616,9 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
/// typename
///
NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
- // We could be facing a type-constraint, which (could) start a type parameter.
- // Annotate it now (we might end up not using it if we determine this
- // type-constraint is in fact part of a placeholder-type-specifier of a
- // non-type template parameter.
- bool ScopeError;
- if (isStartOfTemplateTypeParameter(ScopeError)) {
+ switch (isStartOfTemplateTypeParameter()) {
+ case TPResult::True:
// Is there just a typo in the input code? ('typedef' instead of
// 'typename')
if (Tok.is(tok::kw_typedef)) {
@@ -649,8 +634,10 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
}
return ParseTypeParameter(Depth, Position);
- }
- if (ScopeError) {
+ case TPResult::False:
+ break;
+
+ case TPResult::Error: {
// We return an invalid parameter as opposed to null to avoid having bogus
// diagnostics about an empty template parameter list.
// FIXME: Fix ParseTemplateParameterList to better handle nullptr results
@@ -670,6 +657,11 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
StopAtSemi | StopBeforeMatch);
return ErrorParam;
}
+
+ case TPResult::Ambiguous:
+ llvm_unreachable("template param classification can't be ambiguous");
+ }
+
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
@@ -682,15 +674,15 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
/// Check whether the current token is a template-id annotation denoting a
/// type-constraint.
bool Parser::isTypeConstraintAnnotation() {
- if (Tok.isNot(tok::annot_template_id))
+ const Token &T = Tok.is(tok::annot_cxxscope) ? NextToken() : Tok;
+ if (T.isNot(tok::annot_template_id))
return false;
const auto *ExistingAnnot =
- static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ static_cast<TemplateIdAnnotation *>(T.getAnnotationValue());
return ExistingAnnot->Kind == TNK_Concept_template;
}
-/// Try parsing a type-constraint construct at the current location, after the
-/// optional scope specifier.
+/// Try parsing a type-constraint at the current location.
///
/// type-constraint:
/// nested-name-specifier[opt] concept-name
@@ -698,35 +690,62 @@ bool Parser::isTypeConstraintAnnotation() {
/// '<' template-argument-list[opt] '>'[opt]
///
/// \returns true if an error occurred, and false otherwise.
-bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {
- if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier))
+bool Parser::TryAnnotateTypeConstraint() {
+ if (!getLangOpts().CPlusPlus20)
return false;
+ CXXScopeSpec SS;
+ bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false,
+ /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ // If this is not a type-constraint, then
+ // this scope-spec is part of the typename
+ // of a non-type template parameter
+ /*IsTypename=*/true, /*LastII=*/nullptr,
+ // We won't find concepts in
+ // non-namespaces anyway, so might as well
+ // parse this correctly for possible type
+ // names.
+ /*OnlyNamespace=*/false))
+ return true;
- UnqualifiedId PossibleConceptName;
- PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
- Tok.getLocation());
-
- TemplateTy PossibleConcept;
- bool MemberOfUnknownSpecialization = false;
- auto TNK = Actions.isTemplateName(getCurScope(), SS,
- /*hasTemplateKeyword=*/false,
- PossibleConceptName,
- /*ObjectType=*/ParsedType(),
- /*EnteringContext=*/false,
- PossibleConcept,
- MemberOfUnknownSpecialization);
- assert(!MemberOfUnknownSpecialization
- && "Member when we only allowed namespace scope qualifiers??");
- if (!PossibleConcept || TNK != TNK_Concept_template)
- return false;
+ if (Tok.is(tok::identifier)) {
+ UnqualifiedId PossibleConceptName;
+ PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
+ Tok.getLocation());
+
+ TemplateTy PossibleConcept;
+ bool MemberOfUnknownSpecialization = false;
+ auto TNK = Actions.isTemplateName(getCurScope(), SS,
+ /*hasTemplateKeyword=*/false,
+ PossibleConceptName,
+ /*ObjectType=*/ParsedType(),
+ /*EnteringContext=*/false,
+ PossibleConcept,
+ MemberOfUnknownSpecialization,
+ /*Disambiguation=*/true);
+ if (MemberOfUnknownSpecialization || !PossibleConcept ||
+ TNK != TNK_Concept_template) {
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return false;
+ }
- // At this point we're sure we're dealing with a constrained parameter. It
- // may or may not have a template parameter list following the concept name.
- return AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
- /*TemplateKWLoc=*/SourceLocation(),
- PossibleConceptName,
- /*AllowTypeAnnotation=*/false,
- /*TypeConstraint=*/true);
+ // At this point we're sure we're dealing with a constrained parameter. It
+ // may or may not have a template parameter list following the concept
+ // name.
+ if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
+ /*TemplateKWLoc=*/SourceLocation(),
+ PossibleConceptName,
+ /*AllowTypeAnnotation=*/false,
+ /*TypeConstraint=*/true))
+ return true;
+ }
+
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return false;
}
/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
@@ -739,13 +758,18 @@ bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {
/// 'typename' ...[opt][C++0x] identifier[opt]
/// 'typename' identifier[opt] '=' type-id
NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
- assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) &&
+ assert((Tok.isOneOf(tok::kw_class, tok::kw_typename) ||
+ isTypeConstraintAnnotation()) &&
"A type-parameter starts with 'class', 'typename' or a "
"type-constraint");
+ CXXScopeSpec TypeConstraintSS;
TemplateIdAnnotation *TypeConstraint = nullptr;
bool TypenameKeyword = false;
SourceLocation KeyLoc;
+ ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false,
+ /*EnteringContext*/ false);
if (Tok.is(tok::annot_template_id)) {
// Consume the 'type-constraint'.
TypeConstraint =
@@ -754,6 +778,9 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
"stray non-concept template-id annotation");
KeyLoc = ConsumeAnnotationToken();
} else {
+ assert(TypeConstraintSS.isEmpty() &&
+ "expected type constraint after scope specifier");
+
// Consume the 'class' or 'typename' keyword.
TypenameKeyword = Tok.is(tok::kw_typename);
KeyLoc = ConsumeToken();
@@ -795,7 +822,8 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
ParsedType DefaultArg;
if (TryConsumeToken(tok::equal, EqualLoc))
DefaultArg = ParseTypeName(/*Range=*/nullptr,
- DeclaratorContext::TemplateTypeArgContext).get();
+ DeclaratorContext::TemplateTypeArgContext)
+ .get();
NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(),
TypenameKeyword, EllipsisLoc,
@@ -804,10 +832,11 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
DefaultArg,
TypeConstraint != nullptr);
- if (TypeConstraint)
- Actions.ActOnTypeConstraint(TypeConstraint,
+ if (TypeConstraint) {
+ Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint,
cast<TemplateTypeParmDecl>(NewDecl),
EllipsisLoc);
+ }
return NewDecl;
}
@@ -832,9 +861,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
SmallVector<NamedDecl*,8> TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
{
- ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
- if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
- RAngleLoc)) {
+ MultiParseScope TemplateParmScope(*this);
+ if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams,
+ LAngleLoc, RAngleLoc)) {
return nullptr;
}
}
@@ -972,7 +1001,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// Create the parameter.
return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
- Depth, Position, EqualLoc,
+ Depth, Position, EqualLoc,
DefaultArg.get());
}
@@ -1013,7 +1042,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 '>'.
@@ -1023,7 +1053,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:
@@ -1202,16 +1233,17 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
if (Invalid) {
// Try to find the closing '>'.
- 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 true;
}
}
- return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken,
- /*ObjCGenericList=*/false);
+ return ParseGreaterThanInTemplateList(LAngleLoc, RAngleLoc, ConsumeLastToken,
+ /*ObjCGenericList=*/false) ||
+ Invalid;
}
/// Replace the tokens that form a simple-template-id with an
@@ -1262,12 +1294,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
bool AllowTypeAnnotation,
bool TypeConstraint) {
assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++");
- assert(Template && (Tok.is(tok::less) || TypeConstraint) &&
+ assert((Tok.is(tok::less) || TypeConstraint) &&
"Parser isn't at the beginning of a template-id");
assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be "
"a type annotation");
assert((!TypeConstraint || TNK == TNK_Concept_template) && "type-constraint "
"must accompany a concept name");
+ assert((Template || TNK == TNK_Non_template) && "missing template name");
// Consume the template-name.
SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();
@@ -1275,40 +1308,31 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
+ bool ArgsInvalid = false;
if (!TypeConstraint || Tok.is(tok::less)) {
- bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
- TemplateArgs,
- RAngleLoc);
-
- if (Invalid) {
- // If we failed to parse the template ID but skipped ahead to a >, we're not
- // going to be able to form a token annotation. Eat the '>' if present.
- TryConsumeToken(tok::greater);
- // FIXME: Annotate the token stream so we don't produce the same errors
- // again if we're doing this annotation as part of a tentative parse.
+ ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
+ TemplateArgs, RAngleLoc);
+ // If we couldn't recover from invalid arguments, don't form an annotation
+ // token -- we don't know how much to annotate.
+ // FIXME: This can lead to duplicate diagnostics if we retry parsing this
+ // template-id in another context. Try to annotate anyway?
+ if (RAngleLoc.isInvalid())
return true;
- }
}
ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
- TypeResult Type = Actions.ActOnTemplateIdType(
- getCurScope(), SS, TemplateKWLoc, Template, TemplateName.Identifier,
- TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc);
- if (Type.isInvalid()) {
- // If we failed to parse the template ID but skipped ahead to a >, we're
- // not going to be able to form a token annotation. Eat the '>' if
- // present.
- TryConsumeToken(tok::greater);
- // FIXME: Annotate the token stream so we don't produce the same errors
- // again if we're doing this annotation as part of a tentative parse.
- return true;
- }
+ TypeResult Type = ArgsInvalid
+ ? TypeError()
+ : Actions.ActOnTemplateIdType(
+ getCurScope(), SS, TemplateKWLoc, Template,
+ TemplateName.Identifier, TemplateNameLoc,
+ LAngleLoc, TemplateArgsPtr, RAngleLoc);
Tok.setKind(tok::annot_typename);
- setTypeAnnotation(Tok, Type.get());
+ setTypeAnnotation(Tok, Type);
if (SS.isNotEmpty())
Tok.setLocation(SS.getBeginLoc());
else if (TemplateKWLoc.isValid())
@@ -1331,8 +1355,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
: TemplateName.OperatorFunctionId.Operator;
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
- SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
- LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
+ TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+ LAngleLoc, RAngleLoc, TemplateArgs, ArgsInvalid, TemplateIds);
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
@@ -1357,39 +1381,37 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
/// a type annotation token will still be created, but will have a
/// NULL type pointer to signify an error.
///
+/// \param SS The scope specifier appearing before the template-id, if any.
+///
/// \param IsClassName Is this template-id appearing in a context where we
/// know it names a class, such as in an elaborated-type-specifier or
/// base-specifier? ('typename' and 'template' are unneeded and disallowed
/// in those contexts.)
-void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
+void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
+ bool IsClassName) {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- assert((TemplateId->Kind == TNK_Type_template ||
- TemplateId->Kind == TNK_Dependent_template_name ||
- TemplateId->Kind == TNK_Undeclared_template) &&
+ assert(TemplateId->mightBeType() &&
"Only works for type and dependent templates");
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
- TypeResult Type
- = Actions.ActOnTemplateIdType(getCurScope(),
- TemplateId->SS,
- TemplateId->TemplateKWLoc,
- TemplateId->Template,
- TemplateId->Name,
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
- TemplateArgsPtr,
- TemplateId->RAngleLoc,
- /*IsCtorOrDtorName*/false,
- IsClassName);
+ TypeResult Type =
+ TemplateId->isInvalid()
+ ? TypeError()
+ : Actions.ActOnTemplateIdType(
+ getCurScope(), SS, TemplateId->TemplateKWLoc,
+ TemplateId->Template, TemplateId->Name,
+ TemplateId->TemplateNameLoc, TemplateId->LAngleLoc,
+ TemplateArgsPtr, TemplateId->RAngleLoc,
+ /*IsCtorOrDtorName*/ false, IsClassName);
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
- setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
- if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name.
- Tok.setLocation(TemplateId->SS.getBeginLoc());
+ setTypeAnnotation(Tok, Type);
+ if (SS.isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(SS.getBeginLoc());
// End location stays the same
// Replace the template-id annotation token, and possible the scope-specifier
@@ -1399,7 +1421,9 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
/// Determine whether the given token can end a template argument.
static bool isEndOfTemplateArgument(Token Tok) {
- return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater);
+ // FIXME: Handle '>>>'.
+ return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater,
+ tok::greatergreatergreater);
}
/// Parse a C++ template template argument.
@@ -1420,7 +1444,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
// 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,
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+ /*ObjectHadErrors=*/false,
/*EnteringContext=*/false);
ParsedTemplateArgument Result;
@@ -1438,15 +1463,14 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
TryConsumeToken(tok::ellipsis, EllipsisLoc);
- // If the next token signals the end of a template argument,
- // then we have a dependent template name that could be a template
- // template argument.
+ // If the next token signals the end of a template argument, then we have
+ // a (possibly-dependent) template name that could be a template template
+ // argument.
TemplateTy Template;
if (isEndOfTemplateArgument(Tok) &&
- Actions.ActOnDependentTemplateName(
- getCurScope(), SS, TemplateKWLoc, Name,
- /*ObjectType=*/nullptr,
- /*EnteringContext=*/false, Template))
+ Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Name,
+ /*ObjectType=*/nullptr,
+ /*EnteringContext=*/false, Template))
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
} else if (Tok.is(tok::identifier)) {
@@ -1550,10 +1574,8 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc);
- if (Arg.isInvalid()) {
- SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
+ if (Arg.isInvalid())
return true;
- }
// Save this template argument.
TemplateArgs.push_back(Arg);
@@ -1607,6 +1629,9 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
if (!LPT.D)
return;
+ // Destroy TemplateIdAnnotations when we're done, if possible.
+ DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);
+
// Get the FunctionDecl.
FunctionDecl *FunD = LPT.D->getAsFunction();
// Track template parameter depth.
@@ -1616,40 +1641,22 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
Sema::ContextRAII GlobalSavedContext(
Actions, Actions.Context.getTranslationUnitDecl());
- SmallVector<ParseScope*, 4> TemplateParamScopeStack;
-
- // Get the list of DeclContexts to reenter. For inline methods, we only want
- // to push the DeclContext of the outermost class. This matches the way the
- // parser normally parses bodies of inline methods when the outermost class is
- // complete.
- struct ContainingDC {
- ContainingDC(DeclContext *DC, bool ShouldPush) : Pair(DC, ShouldPush) {}
- llvm::PointerIntPair<DeclContext *, 1, bool> Pair;
- DeclContext *getDC() { return Pair.getPointer(); }
- bool shouldPushDC() { return Pair.getInt(); }
- };
- SmallVector<ContainingDC, 4> DeclContextsToReenter;
- DeclContext *DD = FunD;
- DeclContext *NextContaining = Actions.getContainingDC(DD);
- while (DD && !DD->isTranslationUnit()) {
- bool ShouldPush = DD == NextContaining;
- DeclContextsToReenter.push_back({DD, ShouldPush});
- if (ShouldPush)
- NextContaining = Actions.getContainingDC(DD);
- DD = DD->getLexicalParent();
- }
-
- // Reenter template scopes from outermost to innermost.
- for (ContainingDC CDC : reverse(DeclContextsToReenter)) {
- TemplateParamScopeStack.push_back(
- new ParseScope(this, Scope::TemplateParamScope));
- unsigned NumParamLists = Actions.ActOnReenterTemplateScope(
- getCurScope(), cast<Decl>(CDC.getDC()));
- CurTemplateDepthTracker.addDepth(NumParamLists);
- if (CDC.shouldPushDC()) {
- TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
- Actions.PushDeclContext(Actions.getCurScope(), CDC.getDC());
- }
+ MultiParseScope Scopes(*this);
+
+ // Get the list of DeclContexts to reenter.
+ SmallVector<DeclContext*, 4> DeclContextsToReenter;
+ for (DeclContext *DC = FunD; DC && !DC->isTranslationUnit();
+ DC = DC->getLexicalParent())
+ DeclContextsToReenter.push_back(DC);
+
+ // Reenter scopes from outermost to innermost.
+ for (DeclContext *DC : reverse(DeclContextsToReenter)) {
+ CurTemplateDepthTracker.addDepth(
+ ReenterTemplateScopes(Scopes, cast<Decl>(DC)));
+ Scopes.Enter(Scope::DeclScope);
+ // We'll reenter the function context itself below.
+ if (DC != FunD)
+ Actions.PushDeclContext(Actions.getCurScope(), DC);
}
assert(!LPT.Toks.empty() && "Empty body!");
@@ -1670,8 +1677,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
Scope::CompoundStmtScope);
// Recreate the containing function DeclContext.
- Sema::ContextRAII FunctionSavedContext(Actions,
- Actions.getContainingDC(FunD));
+ Sema::ContextRAII FunctionSavedContext(Actions, FunD->getLexicalParent());
Actions.ActOnStartOfFunctionDef(getCurScope(), FunD);
@@ -1695,13 +1701,6 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
} else
Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
}
-
- // Exit scopes.
- FnScope.Exit();
- SmallVectorImpl<ParseScope *>::reverse_iterator I =
- TemplateParamScopeStack.rbegin();
- for (; I != TemplateParamScopeStack.rend(); ++I)
- delete *I;
}
/// Lex a delayed template function for late parsing.
@@ -1733,7 +1732,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;
@@ -1762,7 +1761,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.