diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
commit | 2298981669bf3bd63335a4be179bc0f96823a8f4 (patch) | |
tree | 1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/Parse/ParseTemplate.cpp | |
parent | 9a83721404652cea39e9f02ae3e3b5c964602a5c (diff) |
Notes
Diffstat (limited to 'lib/Parse/ParseTemplate.cpp')
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 156 |
1 files changed, 116 insertions, 40 deletions
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index e0a7cc6e856db..9bb5b6eac37e2 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -1,9 +1,8 @@ //===--- ParseTemplate.cpp - Template Parsing -----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -19,6 +18,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; /// Parse a template declaration, explicit instantiation, or @@ -49,6 +49,15 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( /// template-declaration: [C++ temp] /// 'export'[opt] 'template' '<' template-parameter-list '>' declaration /// +/// template-declaration: [C++2a] +/// template-head declaration +/// template-head concept-definition +/// +/// TODO: requires-clause +/// template-head: [C++2a] +/// 'template' '<' template-parameter-list '>' +/// requires-clause[opt] +/// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration Decl *Parser::ParseTemplateDeclarationOrSpecialization( @@ -142,6 +151,12 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); // Parse the actual template declaration. + if (Tok.is(tok::kw_concept)) + return ParseConceptDefinition( + ParsedTemplateInfo(&ParamLists, isSpecialization, + LastParamListWasEmpty), + DeclEnd); + return ParseSingleDeclarationAfterTemplate( Context, ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), @@ -232,6 +247,12 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( return nullptr; } + llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() { + return DeclaratorInfo.getIdentifier() != nullptr + ? DeclaratorInfo.getIdentifier()->getName() + : "<unknown>"; + }); + LateParsedAttrList LateParsedAttrs(true); if (DeclaratorInfo.isFunctionDeclarator()) MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); @@ -282,7 +303,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( return ParseFunctionDefinition( DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists, /*isSpecialization=*/true, - /*LastParamListWasEmpty=*/true), + /*lastParameterListWasEmpty=*/true), &LateParsedAttrs); } } @@ -309,6 +330,85 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( return ThisDecl; } +/// \brief Parse a single declaration that declares a concept. +/// +/// \param DeclEnd will receive the source location of the last token +/// within this declaration. +/// +/// \returns the new declaration. +Decl * +Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd) { + assert(TemplateInfo.Kind != ParsedTemplateInfo::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::ext_concept_legacy_bool_keyword) << + FixItHint::CreateRemoval(SourceLocation(BoolKWLoc)); + + DiagnoseAndSkipCXX11Attributes(); + + CXXScopeSpec SS; + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*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, /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, + /*ObjectType=*/ParsedType(), /*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; + } + + IdentifierInfo *Id = Result.Identifier; + SourceLocation IdLoc = Result.getBeginLoc(); + + DiagnoseAndSkipCXX11Attributes(); + + if (!TryConsumeToken(tok::equal)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::equal; + SkipUntil(tok::semi); + return nullptr; + } + + ExprResult ConstraintExprResult = + Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + if (ConstraintExprResult.isInvalid()) { + SkipUntil(tok::semi); + return nullptr; + } + + DeclEnd = Tok.getLocation(); + ExpectAndConsumeSemi(diag::err_expected_semi_declaration); + Expr *ConstraintExpr = ConstraintExprResult.get(); + return Actions.ActOnConceptDefinition(getCurScope(), + *TemplateInfo.TemplateParams, + Id, IdLoc, ConstraintExpr); +} + /// ParseTemplateParameters - Parses a template-parameter-list enclosed in /// angle brackets. Depth is the depth of this template-parameter-list, which /// is the number of template headers directly enclosing this template header. @@ -913,7 +1013,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, PrevTokLocation = RAngleLoc; } else { PrevTokLocation = TokBeforeGreaterLoc; - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject=*/true); Tok = Greater; } @@ -1025,6 +1125,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // 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; } @@ -1033,13 +1135,15 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { TypeResult Type = Actions.ActOnTemplateIdType( - SS, TemplateKWLoc, Template, TemplateName.Identifier, + 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; } @@ -1102,14 +1206,16 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); assert((TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name) && + TemplateId->Kind == TNK_Dependent_template_name || + TemplateId->Kind == TNK_Undeclared_template) && "Only works for type and dependent templates"); ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult Type - = Actions.ActOnTemplateIdType(TemplateId->SS, + = Actions.ActOnTemplateIdType(getCurScope(), + TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, @@ -1266,36 +1372,6 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { ExprArg.get(), Loc); } -/// Determine whether the current tokens can only be parsed as a -/// template argument list (starting with the '<') and never as a '<' -/// expression. -bool Parser::IsTemplateArgumentList(unsigned Skip) { - struct AlwaysRevertAction : TentativeParsingAction { - AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } - ~AlwaysRevertAction() { Revert(); } - } Tentative(*this); - - while (Skip) { - ConsumeAnyToken(); - --Skip; - } - - // '<' - if (!TryConsumeToken(tok::less)) - return false; - - // An empty template argument list. - if (Tok.is(tok::greater)) - return true; - - // See whether we have declaration specifiers, which indicate a type. - while (isCXXDeclarationSpecifier() == TPResult::True) - ConsumeAnyToken(); - - // If we have a '>' or a ',' then this is a template argument list. - return Tok.isOneOf(tok::greater, tok::comma); -} - /// ParseTemplateArgumentList - Parse a C++ template-argument-list /// (C++ [temp.names]). Returns true if there was an error. /// @@ -1420,7 +1496,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // 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); + PP.EnterTokenStream(LPT.Toks, true, /*IsReinject*/true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); |