diff options
Diffstat (limited to 'clang/lib/Parse/ParseTemplate.cpp')
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 429 |
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. |