|  | //===--- ParseTemplate.cpp - Template Parsing -----------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | //  This file implements parsing of C++ templates. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/DeclTemplate.h" | 
|  | #include "clang/AST/ExprCXX.h" | 
|  | #include "clang/Basic/DiagnosticParse.h" | 
|  | #include "clang/Parse/Parser.h" | 
|  | #include "clang/Parse/RAIIObjectsForParser.h" | 
|  | #include "clang/Sema/DeclSpec.h" | 
|  | #include "clang/Sema/EnterExpressionEvaluationContext.h" | 
|  | #include "clang/Sema/ParsedTemplate.h" | 
|  | #include "clang/Sema/Scope.h" | 
|  | using namespace clang; | 
|  |  | 
|  | unsigned Parser::ReenterTemplateScopes(MultiParseScope &S, Decl *D) { | 
|  | return Actions.ActOnReenterTemplateScope(D, [&] { | 
|  | S.Enter(Scope::TemplateParamScope); | 
|  | return Actions.getCurScope(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy | 
|  | Parser::ParseDeclarationStartingWithTemplate(DeclaratorContext Context, | 
|  | SourceLocation &DeclEnd, | 
|  | ParsedAttributes &AccessAttrs) { | 
|  | ObjCDeclContextSwitch ObjCDC(*this); | 
|  |  | 
|  | if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { | 
|  | return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), | 
|  | DeclEnd, AccessAttrs, | 
|  | AccessSpecifier::AS_none); | 
|  | } | 
|  | return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, | 
|  | AccessSpecifier::AS_none); | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy 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."); | 
|  |  | 
|  | MultiParseScope TemplateParamScopes(*this); | 
|  |  | 
|  | // Tell the action that names should be checked in the context of | 
|  | // the declaration to come. | 
|  | ParsingDeclRAIIObject | 
|  | ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); | 
|  |  | 
|  | // Parse multiple levels of template headers within this template | 
|  | // parameter scope, e.g., | 
|  | // | 
|  | //   template<typename T> | 
|  | //     template<typename U> | 
|  | //       class A<T>::B { ... }; | 
|  | // | 
|  | // We parse multiple levels non-recursively so that we can build a | 
|  | // single data structure containing all of the template parameter | 
|  | // lists to easily differentiate between the case above and: | 
|  | // | 
|  | //   template<typename T> | 
|  | //   class A { | 
|  | //     template<typename U> class B; | 
|  | //   }; | 
|  | // | 
|  | // In the first case, the action for declaring A<T>::B receives | 
|  | // both template parameter lists. In the second case, the action for | 
|  | // defining A<T>::B receives just the inner template parameter list | 
|  | // (and retrieves the outer template parameter list from its | 
|  | // context). | 
|  | bool isSpecialization = true; | 
|  | bool LastParamListWasEmpty = false; | 
|  | TemplateParameterLists ParamLists; | 
|  | TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); | 
|  |  | 
|  | do { | 
|  | // Consume the 'export', if any. | 
|  | SourceLocation ExportLoc; | 
|  | TryConsumeToken(tok::kw_export, ExportLoc); | 
|  |  | 
|  | // Consume the 'template', which should be here. | 
|  | SourceLocation TemplateLoc; | 
|  | if (!TryConsumeToken(tok::kw_template, TemplateLoc)) { | 
|  | Diag(Tok.getLocation(), diag::err_expected_template); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Parse the '<' template-parameter-list '>' | 
|  | SourceLocation LAngleLoc, RAngleLoc; | 
|  | SmallVector<NamedDecl*, 4> TemplateParams; | 
|  | if (ParseTemplateParameters(TemplateParamScopes, | 
|  | CurTemplateDepthTracker.getDepth(), | 
|  | TemplateParams, LAngleLoc, RAngleLoc)) { | 
|  | // Skip until the semi-colon or a '}'. | 
|  | SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); | 
|  | TryConsumeToken(tok::semi); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | ExprResult OptionalRequiresClauseConstraintER; | 
|  | if (!TemplateParams.empty()) { | 
|  | isSpecialization = false; | 
|  | ++CurTemplateDepthTracker; | 
|  |  | 
|  | if (TryConsumeToken(tok::kw_requires)) { | 
|  | OptionalRequiresClauseConstraintER = | 
|  | Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( | 
|  | /*IsTrailingRequiresClause=*/false)); | 
|  | if (!OptionalRequiresClauseConstraintER.isUsable()) { | 
|  | // Skip until the semi-colon or a '}'. | 
|  | SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); | 
|  | TryConsumeToken(tok::semi); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | LastParamListWasEmpty = true; | 
|  | } | 
|  |  | 
|  | ParamLists.push_back(Actions.ActOnTemplateParameterList( | 
|  | CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, | 
|  | TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); | 
|  | } while (Tok.isOneOf(tok::kw_export, tok::kw_template)); | 
|  |  | 
|  | ParsedTemplateInfo TemplateInfo(&ParamLists, isSpecialization, | 
|  | LastParamListWasEmpty); | 
|  |  | 
|  | // Parse the actual template declaration. | 
|  | if (Tok.is(tok::kw_concept)) { | 
|  | Decl *ConceptDecl = ParseConceptDefinition(TemplateInfo, DeclEnd); | 
|  | // We need to explicitly pass ConceptDecl to ParsingDeclRAIIObject, so that | 
|  | // delayed diagnostics (e.g. warn_deprecated) have a Decl to work with. | 
|  | ParsingTemplateParams.complete(ConceptDecl); | 
|  | return Actions.ConvertDeclToDeclGroup(ConceptDecl); | 
|  | } | 
|  |  | 
|  | return ParseDeclarationAfterTemplate( | 
|  | Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS); | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy Parser::ParseTemplateDeclarationOrSpecialization( | 
|  | DeclaratorContext Context, SourceLocation &DeclEnd, AccessSpecifier AS) { | 
|  | ParsedAttributes AccessAttrs(AttrFactory); | 
|  | return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, | 
|  | AS); | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy Parser::ParseDeclarationAfterTemplate( | 
|  | DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo, | 
|  | ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd, | 
|  | ParsedAttributes &AccessAttrs, AccessSpecifier AS) { | 
|  | assert(TemplateInfo.Kind != ParsedTemplateKind::NonTemplate && | 
|  | "Template information required"); | 
|  |  | 
|  | if (Tok.is(tok::kw_static_assert)) { | 
|  | // A static_assert declaration may not be templated. | 
|  | Diag(Tok.getLocation(), diag::err_templated_invalid_declaration) | 
|  | << TemplateInfo.getSourceRange(); | 
|  | // Parse the static_assert declaration to improve error recovery. | 
|  | return Actions.ConvertDeclToDeclGroup( | 
|  | ParseStaticAssertDeclaration(DeclEnd)); | 
|  | } | 
|  |  | 
|  | // We are parsing a member template. | 
|  | if (Context == DeclaratorContext::Member) | 
|  | return ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo, | 
|  | &DiagsFromTParams); | 
|  |  | 
|  | ParsedAttributes DeclAttrs(AttrFactory); | 
|  | ParsedAttributes DeclSpecAttrs(AttrFactory); | 
|  |  | 
|  | // GNU attributes are applied to the declaration specification while the | 
|  | // standard attributes are applied to the declaration.  We parse the two | 
|  | // attribute sets into different containters so we can apply them during | 
|  | // the regular parsing process. | 
|  | while (MaybeParseCXX11Attributes(DeclAttrs) || | 
|  | MaybeParseGNUAttributes(DeclSpecAttrs)) | 
|  | ; | 
|  |  | 
|  | if (Tok.is(tok::kw_using)) | 
|  | return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, | 
|  | DeclAttrs); | 
|  |  | 
|  | // Parse the declaration specifiers, stealing any diagnostics from | 
|  | // the template parameters. | 
|  | ParsingDeclSpec DS(*this, &DiagsFromTParams); | 
|  | DS.SetRangeStart(DeclSpecAttrs.Range.getBegin()); | 
|  | DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd()); | 
|  | DS.takeAttributesAppendingingFrom(DeclSpecAttrs); | 
|  |  | 
|  | ParseDeclarationSpecifiers(DS, TemplateInfo, AS, | 
|  | getDeclSpecContextFromDeclaratorContext(Context)); | 
|  |  | 
|  | if (Tok.is(tok::semi)) { | 
|  | ProhibitAttributes(DeclAttrs); | 
|  | DeclEnd = ConsumeToken(); | 
|  | RecordDecl *AnonRecord = nullptr; | 
|  | Decl *Decl = Actions.ParsedFreeStandingDeclSpec( | 
|  | getCurScope(), AS, DS, ParsedAttributesView::none(), | 
|  | TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams | 
|  | : MultiTemplateParamsArg(), | 
|  | TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation, | 
|  | AnonRecord); | 
|  | Actions.ActOnDefinedDeclarationSpecifier(Decl); | 
|  | assert(!AnonRecord && | 
|  | "Anonymous unions/structs should not be valid with template"); | 
|  | DS.complete(Decl); | 
|  | return Actions.ConvertDeclToDeclGroup(Decl); | 
|  | } | 
|  |  | 
|  | if (DS.hasTagDefinition()) | 
|  | Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl()); | 
|  |  | 
|  | // Move the attributes from the prefix into the DS. | 
|  | if (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation) | 
|  | ProhibitAttributes(DeclAttrs); | 
|  |  | 
|  | return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd); | 
|  | } | 
|  |  | 
|  | Decl * | 
|  | Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, | 
|  | SourceLocation &DeclEnd) { | 
|  | assert(TemplateInfo.Kind != ParsedTemplateKind::NonTemplate && | 
|  | "Template information required"); | 
|  | assert(Tok.is(tok::kw_concept) && | 
|  | "ParseConceptDefinition must be called when at a 'concept' keyword"); | 
|  |  | 
|  | ConsumeToken(); // Consume 'concept' | 
|  |  | 
|  | SourceLocation BoolKWLoc; | 
|  | if (TryConsumeToken(tok::kw_bool, BoolKWLoc)) | 
|  | Diag(Tok.getLocation(), diag::err_concept_legacy_bool_keyword) << | 
|  | FixItHint::CreateRemoval(SourceLocation(BoolKWLoc)); | 
|  |  | 
|  | DiagnoseAndSkipCXX11Attributes(); | 
|  |  | 
|  | CXXScopeSpec SS; | 
|  | if (ParseOptionalCXXScopeSpecifier( | 
|  | SS, /*ObjectType=*/nullptr, | 
|  | /*ObjectHasErrors=*/false, /*EnteringContext=*/false, | 
|  | /*MayBePseudoDestructor=*/nullptr, | 
|  | /*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) || | 
|  | SS.isInvalid()) { | 
|  | SkipUntil(tok::semi); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (SS.isNotEmpty()) | 
|  | Diag(SS.getBeginLoc(), | 
|  | diag::err_concept_definition_not_identifier); | 
|  |  | 
|  | UnqualifiedId Result; | 
|  | if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr, | 
|  | /*ObjectHadErrors=*/false, /*EnteringContext=*/false, | 
|  | /*AllowDestructorName=*/false, | 
|  | /*AllowConstructorName=*/false, | 
|  | /*AllowDeductionGuide=*/false, | 
|  | /*TemplateKWLoc=*/nullptr, Result)) { | 
|  | SkipUntil(tok::semi); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (Result.getKind() != UnqualifiedIdKind::IK_Identifier) { | 
|  | Diag(Result.getBeginLoc(), diag::err_concept_definition_not_identifier); | 
|  | SkipUntil(tok::semi); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | const IdentifierInfo *Id = Result.Identifier; | 
|  | SourceLocation IdLoc = Result.getBeginLoc(); | 
|  |  | 
|  | // [C++26][basic.scope.pdecl]/p13 | 
|  | // The locus of a concept-definition is immediately after its concept-name. | 
|  | ConceptDecl *D = Actions.ActOnStartConceptDefinition( | 
|  | getCurScope(), *TemplateInfo.TemplateParams, Id, IdLoc); | 
|  |  | 
|  | ParsedAttributes Attrs(AttrFactory); | 
|  | MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs); | 
|  |  | 
|  | if (!TryConsumeToken(tok::equal)) { | 
|  | Diag(Tok.getLocation(), diag::err_expected) << tok::equal; | 
|  | SkipUntil(tok::semi); | 
|  | if (D) | 
|  | D->setInvalidDecl(); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | ExprResult ConstraintExprResult = ParseConstraintExpression(); | 
|  | if (ConstraintExprResult.isInvalid()) { | 
|  | SkipUntil(tok::semi); | 
|  | if (D) | 
|  | D->setInvalidDecl(); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | DeclEnd = Tok.getLocation(); | 
|  | ExpectAndConsumeSemi(diag::err_expected_semi_declaration); | 
|  | Expr *ConstraintExpr = ConstraintExprResult.get(); | 
|  |  | 
|  | if (!D) | 
|  | return nullptr; | 
|  |  | 
|  | return Actions.ActOnFinishConceptDefinition(getCurScope(), D, ConstraintExpr, | 
|  | Attrs); | 
|  | } | 
|  |  | 
|  | bool Parser::ParseTemplateParameters( | 
|  | 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"; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Try to parse the template parameter list. | 
|  | bool Failed = false; | 
|  | // 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 | 
|  | // followed by a declaration or, for a template template parameter, the | 
|  | // 'class' keyword. Therefore, the second '>' will be diagnosed later. | 
|  | // This matters for elegant diagnosis of: | 
|  | //   template<template<typename>> struct S; | 
|  | Tok.setKind(tok::greater); | 
|  | RAngleLoc = Tok.getLocation(); | 
|  | Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); | 
|  | } else if (!TryConsumeToken(tok::greater, RAngleLoc) && Failed) { | 
|  | Diag(Tok.getLocation(), diag::err_expected) << tok::greater; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool | 
|  | Parser::ParseTemplateParameterList(const unsigned Depth, | 
|  | SmallVectorImpl<NamedDecl*> &TemplateParams) { | 
|  | while (true) { | 
|  |  | 
|  | if (NamedDecl *TmpParam | 
|  | = ParseTemplateParameter(Depth, TemplateParams.size())) { | 
|  | TemplateParams.push_back(TmpParam); | 
|  | } else { | 
|  | // If we failed to parse a template parameter, skip until we find | 
|  | // a comma or closing brace. | 
|  | SkipUntil(tok::comma, tok::greater, tok::greatergreater, | 
|  | StopAtSemi | StopBeforeMatch); | 
|  | } | 
|  |  | 
|  | // Did we find a comma or the end of the template parameter list? | 
|  | if (Tok.is(tok::comma)) { | 
|  | ConsumeToken(); | 
|  | } else if (Tok.isOneOf(tok::greater, tok::greatergreater)) { | 
|  | // Don't consume this... that's done by template parser. | 
|  | break; | 
|  | } else { | 
|  | // Somebody probably forgot to close the template. Skip ahead and | 
|  | // try to get out of the expression. This error is currently | 
|  | // subsumed by whatever goes on in ParseTemplateParameter. | 
|  | Diag(Tok.getLocation(), diag::err_expected_comma_greater); | 
|  | SkipUntil(tok::comma, tok::greater, tok::greatergreater, | 
|  | StopAtSemi | StopBeforeMatch); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | 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. | 
|  | switch (NextToken().getKind()) { | 
|  | case tok::equal: | 
|  | case tok::comma: | 
|  | case tok::greater: | 
|  | case tok::greatergreater: | 
|  | case tok::ellipsis: | 
|  | return TPResult::True; | 
|  |  | 
|  | case tok::identifier: | 
|  | // This may be either a type-parameter or an elaborated-type-specifier. | 
|  | // We have to look further. | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return TPResult::False; | 
|  | } | 
|  |  | 
|  | switch (GetLookAheadToken(2).getKind()) { | 
|  | case tok::equal: | 
|  | case tok::comma: | 
|  | case tok::greater: | 
|  | case tok::greatergreater: | 
|  | return TPResult::True; | 
|  |  | 
|  | default: | 
|  | return TPResult::False; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (TryAnnotateTypeConstraint()) | 
|  | return TPResult::Error; | 
|  |  | 
|  | 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. | 
|  | !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 TPResult::False; | 
|  |  | 
|  | // C++ [temp.param]p2: | 
|  | //   There is no semantic difference between class and typename in a | 
|  | //   template-parameter. typename followed by an unqualified-id | 
|  | //   names a template type parameter. typename followed by a | 
|  | //   qualified-id denotes the type in a non-type | 
|  | //   parameter-declaration. | 
|  | Token Next = NextToken(); | 
|  |  | 
|  | // If we have an identifier, skip over it. | 
|  | if (Next.getKind() == tok::identifier) | 
|  | Next = GetLookAheadToken(2); | 
|  |  | 
|  | switch (Next.getKind()) { | 
|  | case tok::equal: | 
|  | case tok::comma: | 
|  | case tok::greater: | 
|  | case tok::greatergreater: | 
|  | case tok::ellipsis: | 
|  | 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 TPResult::True; | 
|  |  | 
|  | default: | 
|  | return TPResult::False; | 
|  | } | 
|  | } | 
|  |  | 
|  | NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { | 
|  |  | 
|  | switch (isStartOfTemplateTypeParameter()) { | 
|  | case TPResult::True: | 
|  | // 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); | 
|  | 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 | 
|  | //  from here. | 
|  | // Return a NTTP as if there was an error in a scope specifier, the user | 
|  | // probably meant to write the type of a NTTP. | 
|  | DeclSpec DS(getAttrFactory()); | 
|  | DS.SetTypeSpecError(); | 
|  | Declarator D(DS, ParsedAttributesView::none(), | 
|  | DeclaratorContext::TemplateParam); | 
|  | D.SetIdentifier(nullptr, Tok.getLocation()); | 
|  | D.setInvalidType(true); | 
|  | NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter( | 
|  | getCurScope(), D, Depth, Position, /*EqualLoc=*/SourceLocation(), | 
|  | /*DefaultArg=*/nullptr); | 
|  | ErrorParam->setInvalidDecl(true); | 
|  | SkipUntil(tok::comma, tok::greater, tok::greatergreater, | 
|  | 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); | 
|  |  | 
|  | // 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. | 
|  | return ParseNonTypeTemplateParameter(Depth, Position); | 
|  | } | 
|  |  | 
|  | bool Parser::isTypeConstraintAnnotation() { | 
|  | 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 *>(T.getAnnotationValue()); | 
|  | return ExistingAnnot->Kind == TNK_Concept_template; | 
|  | } | 
|  |  | 
|  | bool Parser::TryAnnotateTypeConstraint() { | 
|  | if (!getLangOpts().CPlusPlus20) | 
|  | return false; | 
|  | CXXScopeSpec SS; | 
|  | bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); | 
|  | if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, | 
|  | /*ObjectHasErrors=*/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; | 
|  |  | 
|  | 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. | 
|  | if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS, | 
|  | /*TemplateKWLoc=*/SourceLocation(), | 
|  | PossibleConceptName, | 
|  | /*AllowTypeAnnotation=*/false, | 
|  | /*TypeConstraint=*/true)) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (SS.isNotEmpty()) | 
|  | AnnotateScopeToken(SS, !WasScopeAnnotation); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { | 
|  | 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, | 
|  | /*ObjectHasErrors=*/false, | 
|  | /*EnteringContext*/ false); | 
|  | if (Tok.is(tok::annot_template_id)) { | 
|  | // Consume the 'type-constraint'. | 
|  | TypeConstraint = | 
|  | static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); | 
|  | assert(TypeConstraint->Kind == TNK_Concept_template && | 
|  | "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(); | 
|  | } | 
|  |  | 
|  | // Grab the ellipsis (if given). | 
|  | SourceLocation EllipsisLoc; | 
|  | if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) { | 
|  | Diag(EllipsisLoc, | 
|  | getLangOpts().CPlusPlus11 | 
|  | ? diag::warn_cxx98_compat_variadic_templates | 
|  | : diag::ext_variadic_templates); | 
|  | } | 
|  |  | 
|  | // Grab the template parameter name (if given) | 
|  | SourceLocation NameLoc = Tok.getLocation(); | 
|  | IdentifierInfo *ParamName = nullptr; | 
|  | if (Tok.is(tok::identifier)) { | 
|  | ParamName = Tok.getIdentifierInfo(); | 
|  | ConsumeToken(); | 
|  | } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater, | 
|  | tok::greatergreater)) { | 
|  | // Unnamed template parameter. Don't have to do anything here, just | 
|  | // don't consume this token. | 
|  | } else { | 
|  | Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Recover from misplaced ellipsis. | 
|  | bool AlreadyHasEllipsis = EllipsisLoc.isValid(); | 
|  | if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) | 
|  | DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); | 
|  |  | 
|  | // Grab a default argument (if available). | 
|  | // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before | 
|  | // we introduce the type parameter into the local scope. | 
|  | SourceLocation EqualLoc; | 
|  | ParsedType DefaultArg; | 
|  | std::optional<DelayTemplateIdDestructionRAII> DontDestructTemplateIds; | 
|  | if (TryConsumeToken(tok::equal, EqualLoc)) { | 
|  | // The default argument might contain a lambda declaration; avoid destroying | 
|  | // parsed template ids at the end of that declaration because they can be | 
|  | // used in a type constraint later. | 
|  | DontDestructTemplateIds.emplace(*this, /*DelayTemplateIdDestruction=*/true); | 
|  | // The default argument may declare template parameters, notably | 
|  | // if it contains a generic lambda, so we need to increase | 
|  | // the template depth as these parameters would not be instantiated | 
|  | // at the current level. | 
|  | TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); | 
|  | ++CurTemplateDepthTracker; | 
|  | DefaultArg = | 
|  | ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArg) | 
|  | .get(); | 
|  | } | 
|  |  | 
|  | NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), | 
|  | TypenameKeyword, EllipsisLoc, | 
|  | KeyLoc, ParamName, NameLoc, | 
|  | Depth, Position, EqualLoc, | 
|  | DefaultArg, | 
|  | TypeConstraint != nullptr); | 
|  |  | 
|  | if (TypeConstraint) { | 
|  | Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, | 
|  | cast<TemplateTypeParmDecl>(NewDecl), | 
|  | EllipsisLoc); | 
|  | } | 
|  |  | 
|  | return NewDecl; | 
|  | } | 
|  |  | 
|  | NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, | 
|  | unsigned Position) { | 
|  | assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); | 
|  |  | 
|  | // Handle the template <...> part. | 
|  | SourceLocation TemplateLoc = ConsumeToken(); | 
|  | SmallVector<NamedDecl*,8> TemplateParams; | 
|  | SourceLocation LAngleLoc, RAngleLoc; | 
|  | ExprResult OptionalRequiresClauseConstraintER; | 
|  | { | 
|  | MultiParseScope TemplateParmScope(*this); | 
|  | if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams, | 
|  | LAngleLoc, RAngleLoc)) { | 
|  | return nullptr; | 
|  | } | 
|  | if (TryConsumeToken(tok::kw_requires)) { | 
|  | OptionalRequiresClauseConstraintER = | 
|  | Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( | 
|  | /*IsTrailingRequiresClause=*/false)); | 
|  | if (!OptionalRequiresClauseConstraintER.isUsable()) { | 
|  | SkipUntil(tok::comma, tok::greater, tok::greatergreater, | 
|  | StopAtSemi | StopBeforeMatch); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TemplateNameKind Kind = TemplateNameKind::TNK_Non_template; | 
|  | SourceLocation NameLoc; | 
|  | IdentifierInfo *ParamName = nullptr; | 
|  | SourceLocation EllipsisLoc; | 
|  | bool TypenameKeyword = false; | 
|  |  | 
|  | if (TryConsumeToken(tok::kw_class)) { | 
|  | Kind = TemplateNameKind::TNK_Type_template; | 
|  | } else { | 
|  |  | 
|  | // Provide an ExtWarn if the C++1z feature of using 'typename' here is used. | 
|  | // Generate a meaningful error if the user forgot to put class before the | 
|  | // identifier, comma, or greater. Provide a fixit if the identifier, comma, | 
|  | // or greater appear immediately or after 'struct'. In the latter case, | 
|  | // replace the keyword with 'class'. | 
|  | bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct); | 
|  | const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok; | 
|  | if (Tok.is(tok::kw_typename)) { | 
|  | TypenameKeyword = true; | 
|  | Kind = TemplateNameKind::TNK_Type_template; | 
|  | Diag(Tok.getLocation(), | 
|  | getLangOpts().CPlusPlus17 | 
|  | ? diag::warn_cxx14_compat_template_template_param_typename | 
|  | : diag::ext_template_template_param_typename) | 
|  | << (!getLangOpts().CPlusPlus17 | 
|  | ? FixItHint::CreateReplacement(Tok.getLocation(), "class") | 
|  | : FixItHint()); | 
|  | Kind = TemplateNameKind::TNK_Type_template; | 
|  | } else if (TryConsumeToken(tok::kw_concept)) { | 
|  | Kind = TemplateNameKind::TNK_Concept_template; | 
|  | } else if (TryConsumeToken(tok::kw_auto)) { | 
|  | Kind = TemplateNameKind::TNK_Var_template; | 
|  | } else if (Next.isOneOf(tok::identifier, tok::comma, tok::greater, | 
|  | tok::greatergreater, tok::ellipsis)) { | 
|  | // Provide a fixit if the identifier, comma, | 
|  | // or greater appear immediately or after 'struct'. In the latter case, | 
|  | // replace the keyword with 'class'. | 
|  | Diag(Tok.getLocation(), diag::err_class_on_template_template_param) | 
|  | << getLangOpts().CPlusPlus17 | 
|  | << (Replace | 
|  | ? FixItHint::CreateReplacement(Tok.getLocation(), "class") | 
|  | : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); | 
|  | } | 
|  | if (Replace) | 
|  | ConsumeToken(); | 
|  | } | 
|  |  | 
|  | if (!getLangOpts().CPlusPlus26 && | 
|  | (Kind == TemplateNameKind::TNK_Concept_template || | 
|  | Kind == TemplateNameKind::TNK_Var_template)) { | 
|  | Diag(PrevTokLocation, diag::err_cxx26_template_template_params) | 
|  | << (Kind == TemplateNameKind::TNK_Concept_template); | 
|  | } | 
|  |  | 
|  | // Parse the ellipsis, if given. | 
|  | if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) | 
|  | Diag(EllipsisLoc, | 
|  | getLangOpts().CPlusPlus11 | 
|  | ? diag::warn_cxx98_compat_variadic_templates | 
|  | : diag::ext_variadic_templates); | 
|  |  | 
|  | // Get the identifier, if given. | 
|  | NameLoc = Tok.getLocation(); | 
|  | if (Tok.is(tok::identifier)) { | 
|  | ParamName = Tok.getIdentifierInfo(); | 
|  | ConsumeToken(); | 
|  | } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater, | 
|  | tok::greatergreater)) { | 
|  | // Unnamed template parameter. Don't have to do anything here, just | 
|  | // don't consume this token. | 
|  | } else { | 
|  | Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Recover from misplaced ellipsis. | 
|  | bool AlreadyHasEllipsis = EllipsisLoc.isValid(); | 
|  | if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) | 
|  | DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); | 
|  |  | 
|  | TemplateParameterList *ParamList = Actions.ActOnTemplateParameterList( | 
|  | Depth, SourceLocation(), TemplateLoc, LAngleLoc, TemplateParams, | 
|  | RAngleLoc, OptionalRequiresClauseConstraintER.get()); | 
|  |  | 
|  | // Grab a default argument (if available). | 
|  | // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before | 
|  | // we introduce the template parameter into the local scope. | 
|  | SourceLocation EqualLoc; | 
|  | ParsedTemplateArgument DefaultArg; | 
|  | if (TryConsumeToken(tok::equal, EqualLoc)) { | 
|  | DefaultArg = ParseTemplateTemplateArgument(); | 
|  | if (DefaultArg.isInvalid()) { | 
|  | 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, Kind, TypenameKeyword, ParamList, EllipsisLoc, | 
|  | ParamName, NameLoc, Depth, Position, EqualLoc, DefaultArg); | 
|  | } | 
|  |  | 
|  | NamedDecl * | 
|  | Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { | 
|  | // Parse the declaration-specifiers (i.e., the type). | 
|  | // FIXME: The type should probably be restricted in some way... Not all | 
|  | // declarators (parts of declarators?) are accepted for parameters. | 
|  | DeclSpec DS(AttrFactory); | 
|  | ParsedTemplateInfo TemplateInfo; | 
|  | ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, | 
|  | DeclSpecContext::DSC_template_param); | 
|  |  | 
|  | // Parse this as a typename. | 
|  | Declarator ParamDecl(DS, ParsedAttributesView::none(), | 
|  | DeclaratorContext::TemplateParam); | 
|  | ParseDeclarator(ParamDecl); | 
|  | if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { | 
|  | Diag(Tok.getLocation(), diag::err_expected_template_parameter); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Recover from misplaced ellipsis. | 
|  | SourceLocation EllipsisLoc; | 
|  | if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) | 
|  | DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, ParamDecl); | 
|  |  | 
|  | // If there is a default value, parse it. | 
|  | // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before | 
|  | // we introduce the template parameter into the local scope. | 
|  | SourceLocation EqualLoc; | 
|  | ExprResult DefaultArg; | 
|  | if (TryConsumeToken(tok::equal, EqualLoc)) { | 
|  | if (Tok.is(tok::l_paren) && NextToken().is(tok::l_brace)) { | 
|  | Diag(Tok.getLocation(), diag::err_stmt_expr_in_default_arg) << 1; | 
|  | SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); | 
|  | } else { | 
|  | // C++ [temp.param]p15: | 
|  | //   When parsing a default template-argument for a non-type | 
|  | //   template-parameter, the first non-nested > is taken as the | 
|  | //   end of the template-parameter-list rather than a greater-than | 
|  | //   operator. | 
|  | GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); | 
|  |  | 
|  | // The default argument may declare template parameters, notably | 
|  | // if it contains a generic lambda, so we need to increase | 
|  | // the template depth as these parameters would not be instantiated | 
|  | // at the current level. | 
|  | TemplateParameterDepthRAII CurTemplateDepthTracker( | 
|  | TemplateParameterDepth); | 
|  | ++CurTemplateDepthTracker; | 
|  | EnterExpressionEvaluationContext ConstantEvaluated( | 
|  | Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); | 
|  | DefaultArg = Actions.ActOnConstantExpression(ParseInitializer()); | 
|  | if (DefaultArg.isInvalid()) | 
|  | SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Create the parameter. | 
|  | return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, | 
|  | Depth, Position, EqualLoc, | 
|  | DefaultArg.get()); | 
|  | } | 
|  |  | 
|  | void Parser::DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc, | 
|  | SourceLocation CorrectLoc, | 
|  | bool AlreadyHasEllipsis, | 
|  | bool IdentifierHasName) { | 
|  | FixItHint Insertion; | 
|  | if (!AlreadyHasEllipsis) | 
|  | Insertion = FixItHint::CreateInsertion(CorrectLoc, "..."); | 
|  | Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration) | 
|  | << FixItHint::CreateRemoval(EllipsisLoc) << Insertion | 
|  | << !IdentifierHasName; | 
|  | } | 
|  |  | 
|  | void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, | 
|  | Declarator &D) { | 
|  | assert(EllipsisLoc.isValid()); | 
|  | bool AlreadyHasEllipsis = D.getEllipsisLoc().isValid(); | 
|  | if (!AlreadyHasEllipsis) | 
|  | D.setEllipsisLoc(EllipsisLoc); | 
|  | DiagnoseMisplacedEllipsis(EllipsisLoc, D.getIdentifierLoc(), | 
|  | AlreadyHasEllipsis, D.hasName()); | 
|  | } | 
|  |  | 
|  | bool Parser::ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, | 
|  | SourceLocation &RAngleLoc, | 
|  | bool ConsumeLastToken, | 
|  | bool ObjCGenericList) { | 
|  | // What will be left once we've consumed the '>'. | 
|  | tok::TokenKind RemainingToken; | 
|  | const char *ReplacementStr = "> >"; | 
|  | bool MergeWithNextToken = false; | 
|  |  | 
|  | switch (Tok.getKind()) { | 
|  | default: | 
|  | Diag(getEndOfPreviousToken(), diag::err_expected) << tok::greater; | 
|  | Diag(LAngleLoc, diag::note_matching) << tok::less; | 
|  | return true; | 
|  |  | 
|  | case tok::greater: | 
|  | // Determine the location of the '>' token. Only consume this token | 
|  | // if the caller asked us to. | 
|  | RAngleLoc = Tok.getLocation(); | 
|  | if (ConsumeLastToken) | 
|  | ConsumeToken(); | 
|  | return false; | 
|  |  | 
|  | case tok::greatergreater: | 
|  | RemainingToken = tok::greater; | 
|  | break; | 
|  |  | 
|  | case tok::greatergreatergreater: | 
|  | RemainingToken = tok::greatergreater; | 
|  | break; | 
|  |  | 
|  | 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: | 
|  | RemainingToken = tok::greaterequal; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // 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. | 
|  | // | 
|  | // 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 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 | 
|  | // the replacement, rather than just inserting a space at SecondCharLoc. | 
|  | FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, | 
|  | ReplacementStr); | 
|  |  | 
|  | // A hint to put another space after the token, if it would otherwise be | 
|  | // lexed differently. | 
|  | FixItHint Hint2; | 
|  | if (PreventMergeWithNextToken) | 
|  | Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); | 
|  |  | 
|  | unsigned DiagId = diag::err_two_right_angle_brackets_need_space; | 
|  | if (getLangOpts().CPlusPlus11 && | 
|  | (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater))) | 
|  | 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(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. | 
|  | 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(); | 
|  | OldLength += Tok.getLength(); | 
|  | } | 
|  |  | 
|  | 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({Greater, Tok}); | 
|  | else | 
|  | PP.ReplacePreviousCachedToken({Greater}); | 
|  | } | 
|  |  | 
|  | if (ConsumeLastToken) { | 
|  | PrevTokLocation = RAngleLoc; | 
|  | } else { | 
|  | PrevTokLocation = TokBeforeGreaterLoc; | 
|  | PP.EnterToken(Tok, /*IsReinject=*/true); | 
|  | Tok = Greater; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, | 
|  | SourceLocation &LAngleLoc, | 
|  | TemplateArgList &TemplateArgs, | 
|  | SourceLocation &RAngleLoc, | 
|  | TemplateTy Template) { | 
|  | assert(Tok.is(tok::less) && "Must have already parsed the template-name"); | 
|  |  | 
|  | // Consume the '<'. | 
|  | LAngleLoc = ConsumeToken(); | 
|  |  | 
|  | // Parse the optional template-argument-list. | 
|  | bool Invalid = false; | 
|  | { | 
|  | GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); | 
|  | if (!Tok.isOneOf(tok::greater, tok::greatergreater, | 
|  | tok::greatergreatergreater, tok::greaterequal, | 
|  | tok::greatergreaterequal)) | 
|  | Invalid = ParseTemplateArgumentList(TemplateArgs, Template, LAngleLoc); | 
|  |  | 
|  | if (Invalid) { | 
|  | // Try to find the closing '>'. | 
|  | if (getLangOpts().CPlusPlus11) | 
|  | SkipUntil(tok::greater, tok::greatergreater, | 
|  | tok::greatergreatergreater, StopAtSemi | StopBeforeMatch); | 
|  | else | 
|  | SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); | 
|  | } | 
|  | } | 
|  |  | 
|  | return ParseGreaterThanInTemplateList(LAngleLoc, RAngleLoc, ConsumeLastToken, | 
|  | /*ObjCGenericList=*/false) || | 
|  | Invalid; | 
|  | } | 
|  |  | 
|  | bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, | 
|  | CXXScopeSpec &SS, | 
|  | SourceLocation TemplateKWLoc, | 
|  | UnqualifiedId &TemplateName, | 
|  | bool AllowTypeAnnotation, | 
|  | bool TypeConstraint) { | 
|  | assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); | 
|  | 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(); | 
|  |  | 
|  | // Parse the enclosed template argument list. | 
|  | SourceLocation LAngleLoc, RAngleLoc; | 
|  | TemplateArgList TemplateArgs; | 
|  | bool ArgsInvalid = false; | 
|  | if (!TypeConstraint || Tok.is(tok::less)) { | 
|  | ArgsInvalid = ParseTemplateIdAfterTemplateName( | 
|  | false, LAngleLoc, TemplateArgs, RAngleLoc, Template); | 
|  | // 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 = | 
|  | ArgsInvalid | 
|  | ? TypeError() | 
|  | : Actions.ActOnTemplateIdType( | 
|  | getCurScope(), ElaboratedTypeKeyword::None, | 
|  | /*ElaboratedKeywordLoc=*/SourceLocation(), SS, TemplateKWLoc, | 
|  | Template, TemplateName.Identifier, TemplateNameLoc, LAngleLoc, | 
|  | TemplateArgsPtr, RAngleLoc); | 
|  |  | 
|  | Tok.setKind(tok::annot_typename); | 
|  | setTypeAnnotation(Tok, Type); | 
|  | if (SS.isNotEmpty()) | 
|  | Tok.setLocation(SS.getBeginLoc()); | 
|  | else if (TemplateKWLoc.isValid()) | 
|  | Tok.setLocation(TemplateKWLoc); | 
|  | else | 
|  | Tok.setLocation(TemplateNameLoc); | 
|  | } else { | 
|  | // Build a template-id annotation token that can be processed | 
|  | // later. | 
|  | Tok.setKind(tok::annot_template_id); | 
|  |  | 
|  | const IdentifierInfo *TemplateII = | 
|  | TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier | 
|  | ? TemplateName.Identifier | 
|  | : nullptr; | 
|  |  | 
|  | OverloadedOperatorKind OpKind = | 
|  | TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier | 
|  | ? OO_None | 
|  | : TemplateName.OperatorFunctionId.Operator; | 
|  |  | 
|  | TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( | 
|  | TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, | 
|  | LAngleLoc, RAngleLoc, TemplateArgs, ArgsInvalid, TemplateIds); | 
|  |  | 
|  | Tok.setAnnotationValue(TemplateId); | 
|  | if (TemplateKWLoc.isValid()) | 
|  | Tok.setLocation(TemplateKWLoc); | 
|  | else | 
|  | Tok.setLocation(TemplateNameLoc); | 
|  | } | 
|  |  | 
|  | // Common fields for the annotation token | 
|  | Tok.setAnnotationEndLoc(RAngleLoc); | 
|  |  | 
|  | // In case the tokens were cached, have Preprocessor replace them with the | 
|  | // annotation token. | 
|  | PP.AnnotateCachedTokens(Tok); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void Parser::AnnotateTemplateIdTokenAsType( | 
|  | CXXScopeSpec &SS, ImplicitTypenameContext AllowImplicitTypename, | 
|  | bool IsClassName) { | 
|  | assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); | 
|  |  | 
|  | TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); | 
|  | assert(TemplateId->mightBeType() && | 
|  | "Only works for type and dependent templates"); | 
|  |  | 
|  | ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), | 
|  | TemplateId->NumArgs); | 
|  |  | 
|  | TypeResult Type = | 
|  | TemplateId->isInvalid() | 
|  | ? TypeError() | 
|  | : Actions.ActOnTemplateIdType( | 
|  | getCurScope(), ElaboratedTypeKeyword::None, | 
|  | /*ElaboratedKeywordLoc=*/SourceLocation(), SS, | 
|  | TemplateId->TemplateKWLoc, TemplateId->Template, | 
|  | TemplateId->Name, TemplateId->TemplateNameLoc, | 
|  | TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, | 
|  | /*IsCtorOrDtorName=*/false, IsClassName, AllowImplicitTypename); | 
|  | // Create the new "type" annotation token. | 
|  | Tok.setKind(tok::annot_typename); | 
|  | 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 | 
|  | // that precedes it, with the typename annotation token. | 
|  | PP.AnnotateCachedTokens(Tok); | 
|  | } | 
|  |  | 
|  | /// Determine whether the given token can end a template argument. | 
|  | static bool isEndOfTemplateArgument(Token Tok) { | 
|  | // FIXME: Handle '>>>'. | 
|  | return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater, | 
|  | tok::greatergreatergreater); | 
|  | } | 
|  |  | 
|  | ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { | 
|  | if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) && | 
|  | !Tok.is(tok::annot_cxxscope) && !Tok.is(tok::annot_template_id) && | 
|  | !Tok.is(tok::annot_non_type)) | 
|  | return ParsedTemplateArgument(); | 
|  |  | 
|  | // 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 ',', | 
|  | // '>', or (in some cases) '>>'. | 
|  | CXXScopeSpec SS; // nested-name-specifier, if present | 
|  | ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, | 
|  | /*ObjectHasErrors=*/false, | 
|  | /*EnteringContext=*/false); | 
|  |  | 
|  | ParsedTemplateArgument Result; | 
|  | SourceLocation EllipsisLoc; | 
|  | if (SS.isSet() && Tok.is(tok::kw_template)) { | 
|  | // 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; | 
|  | Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); | 
|  | ConsumeToken(); // the identifier | 
|  |  | 
|  | TryConsumeToken(tok::ellipsis, EllipsisLoc); | 
|  |  | 
|  | // 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.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Name, | 
|  | /*ObjectType=*/nullptr, | 
|  | /*EnteringContext=*/false, Template)) | 
|  | Result = ParsedTemplateArgument(TemplateKWLoc, SS, Template, | 
|  | Name.StartLocation); | 
|  | } | 
|  | } else if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) || | 
|  | Tok.is(tok::annot_non_type)) { | 
|  | // We may have a (non-dependent) template name. | 
|  | TemplateTy Template; | 
|  | UnqualifiedId Name; | 
|  | if (Tok.is(tok::annot_non_type)) { | 
|  | NamedDecl *ND = getNonTypeAnnotation(Tok); | 
|  | if (!isa<VarTemplateDecl>(ND)) | 
|  | return Result; | 
|  | Name.setIdentifier(ND->getIdentifier(), Tok.getLocation()); | 
|  | ConsumeAnnotationToken(); | 
|  | } else if (Tok.is(tok::annot_template_id)) { | 
|  | TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); | 
|  | if (TemplateId->LAngleLoc.isValid()) | 
|  | return Result; | 
|  | Name.setIdentifier(TemplateId->Name, Tok.getLocation()); | 
|  | ConsumeAnnotationToken(); | 
|  | } else { | 
|  | Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); | 
|  | ConsumeToken(); // the identifier | 
|  | } | 
|  |  | 
|  | TryConsumeToken(tok::ellipsis, EllipsisLoc); | 
|  |  | 
|  | if (isEndOfTemplateArgument(Tok)) { | 
|  | bool MemberOfUnknownSpecialization; | 
|  | TemplateNameKind TNK = Actions.isTemplateName( | 
|  | getCurScope(), SS, | 
|  | /*hasTemplateKeyword=*/false, Name, | 
|  | /*ObjectType=*/nullptr, | 
|  | /*EnteringContext=*/false, Template, MemberOfUnknownSpecialization); | 
|  | if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template || | 
|  | TNK == TNK_Var_template || TNK == TNK_Concept_template) { | 
|  | // We have an id-expression that refers to a class template or | 
|  | // (C++0x) alias template. | 
|  | Result = ParsedTemplateArgument(/*TemplateKwLoc=*/SourceLocation(), SS, | 
|  | Template, Name.StartLocation); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Result = Actions.ActOnTemplateTemplateArgument(Result); | 
|  |  | 
|  | // If this is a pack expansion, build it as such. | 
|  | if (EllipsisLoc.isValid() && !Result.isInvalid()) | 
|  | Result = Actions.ActOnPackExpansion(Result, EllipsisLoc); | 
|  |  | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | ParsedTemplateArgument Parser::ParseTemplateArgument() { | 
|  | // C++ [temp.arg]p2: | 
|  | //   In a template-argument, an ambiguity between a type-id and an | 
|  | //   expression is resolved to a type-id, regardless of the form of | 
|  | //   the corresponding template-parameter. | 
|  | // | 
|  | // Therefore, we initially try to parse a type-id - and isCXXTypeId might look | 
|  | // up and annotate an identifier as an id-expression during disambiguation, | 
|  | // so enter the appropriate context for a constant expression template | 
|  | // argument before trying to disambiguate. | 
|  |  | 
|  | EnterExpressionEvaluationContext EnterConstantEvaluated( | 
|  | Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated, | 
|  | /*LambdaContextDecl=*/nullptr, | 
|  | /*ExprContext=*/Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); | 
|  | if (isCXXTypeId(TentativeCXXTypeIdContext::AsTemplateArgument)) { | 
|  | TypeResult TypeArg = ParseTypeName( | 
|  | /*Range=*/nullptr, DeclaratorContext::TemplateArg); | 
|  | return Actions.ActOnTemplateTypeArgument(TypeArg); | 
|  | } | 
|  |  | 
|  | // Try to parse a template template argument. | 
|  | { | 
|  | TentativeParsingAction TPA(*this); | 
|  |  | 
|  | ParsedTemplateArgument TemplateTemplateArgument = | 
|  | ParseTemplateTemplateArgument(); | 
|  | if (!TemplateTemplateArgument.isInvalid()) { | 
|  | TPA.Commit(); | 
|  | return TemplateTemplateArgument; | 
|  | } | 
|  | // Revert this tentative parse to parse a non-type template argument. | 
|  | TPA.Revert(); | 
|  | } | 
|  |  | 
|  | // Parse a non-type template argument. | 
|  | ExprResult ExprArg; | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) | 
|  | ExprArg = ParseBraceInitializer(); | 
|  | else | 
|  | ExprArg = ParseConstantExpressionInExprEvalContext( | 
|  | TypoCorrectionTypeBehavior::AllowBoth); | 
|  | if (ExprArg.isInvalid() || !ExprArg.get()) { | 
|  | return ParsedTemplateArgument(); | 
|  | } | 
|  |  | 
|  | return ParsedTemplateArgument(ParsedTemplateArgument::NonType, | 
|  | ExprArg.get(), Loc); | 
|  | } | 
|  |  | 
|  | bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, | 
|  | TemplateTy Template, | 
|  | SourceLocation OpenLoc) { | 
|  |  | 
|  | ColonProtectionRAIIObject ColonProtection(*this, false); | 
|  |  | 
|  | auto RunSignatureHelp = [&] { | 
|  | if (!Template) | 
|  | return QualType(); | 
|  | CalledSignatureHelp = true; | 
|  | return Actions.CodeCompletion().ProduceTemplateArgumentSignatureHelp( | 
|  | Template, TemplateArgs, OpenLoc); | 
|  | }; | 
|  |  | 
|  | do { | 
|  | PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp); | 
|  | ParsedTemplateArgument Arg = ParseTemplateArgument(); | 
|  | SourceLocation EllipsisLoc; | 
|  | if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) | 
|  | Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc); | 
|  |  | 
|  | if (Arg.isInvalid()) { | 
|  | if (PP.isCodeCompletionReached() && !CalledSignatureHelp) | 
|  | RunSignatureHelp(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // 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)); | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy 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); | 
|  | ParsedTemplateInfo TemplateInfo(ExternLoc, TemplateLoc); | 
|  | return ParseDeclarationAfterTemplate( | 
|  | Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS); | 
|  | } | 
|  |  | 
|  | SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { | 
|  | if (TemplateParams) | 
|  | return getTemplateParamsRange(TemplateParams->data(), | 
|  | TemplateParams->size()); | 
|  |  | 
|  | SourceRange R(TemplateLoc); | 
|  | if (ExternLoc.isValid()) | 
|  | R.setBegin(ExternLoc); | 
|  | return R; | 
|  | } | 
|  |  | 
|  | void Parser::LateTemplateParserCallback(void *P, LateParsedTemplate &LPT) { | 
|  | ((Parser *)P)->ParseLateTemplatedFuncDef(LPT); | 
|  | } | 
|  |  | 
|  | 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. | 
|  | TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); | 
|  |  | 
|  | // To restore the context after late parsing. | 
|  | Sema::ContextRAII GlobalSavedContext( | 
|  | Actions, Actions.Context.getTranslationUnitDecl()); | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | // Parsing should occur with empty FP pragma stack and FP options used in the | 
|  | // point of the template definition. | 
|  | Sema::FpPragmaStackSaveRAII SavedStack(Actions); | 
|  | Actions.resetFPOptions(LPT.FPO); | 
|  |  | 
|  | assert(!LPT.Toks.empty() && "Empty body!"); | 
|  |  | 
|  | // Append the current token at the end of the new token stream so that it | 
|  | // doesn't get lost. | 
|  | LPT.Toks.push_back(Tok); | 
|  | PP.EnterTokenStream(LPT.Toks, true, /*IsReinject*/true); | 
|  |  | 
|  | // Consume the previously pushed token. | 
|  | ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); | 
|  | assert(Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try) && | 
|  | "Inline method not starting with '{', ':' or 'try'"); | 
|  |  | 
|  | // Parse the method body. Function body parsing code is similar enough | 
|  | // to be re-used for method bodies as well. | 
|  | ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope); | 
|  |  | 
|  | // Recreate the containing function DeclContext. | 
|  | Sema::ContextRAII FunctionSavedContext(Actions, FunD->getLexicalParent()); | 
|  |  | 
|  | Actions.ActOnStartOfFunctionDef(getCurScope(), FunD); | 
|  |  | 
|  | if (Tok.is(tok::kw_try)) { | 
|  | ParseFunctionTryBlock(LPT.D, FnScope); | 
|  | } else { | 
|  | if (Tok.is(tok::colon)) | 
|  | ParseConstructorInitializer(LPT.D); | 
|  | else | 
|  | Actions.ActOnDefaultCtorInitializers(LPT.D); | 
|  |  | 
|  | if (Tok.is(tok::l_brace)) { | 
|  | assert((!isa<FunctionTemplateDecl>(LPT.D) || | 
|  | cast<FunctionTemplateDecl>(LPT.D) | 
|  | ->getTemplateParameters() | 
|  | ->getDepth() == TemplateParameterDepth - 1) && | 
|  | "TemplateParameterDepth should be greater than the depth of " | 
|  | "current template being instantiated!"); | 
|  | ParseFunctionStatementBody(LPT.D, FnScope); | 
|  | Actions.UnmarkAsLateParsedTemplate(FunD); | 
|  | } else | 
|  | Actions.ActOnFinishFunctionBody(LPT.D, nullptr); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) { | 
|  | tok::TokenKind kind = Tok.getKind(); | 
|  | if (!ConsumeAndStoreFunctionPrologue(Toks)) { | 
|  | // Consume everything up to (and including) the matching right brace. | 
|  | ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); | 
|  | } | 
|  |  | 
|  | // If we're in a function-try-block, we need to store all the catch blocks. | 
|  | if (kind == tok::kw_try) { | 
|  | while (Tok.is(tok::kw_catch)) { | 
|  | ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); | 
|  | ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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(Less, 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(Less, 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; | 
|  | } |