aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Parse/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/Parser.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Parse/Parser.cpp616
1 files changed, 418 insertions, 198 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/Parser.cpp b/contrib/llvm-project/clang/lib/Parse/Parser.cpp
index 9b0f921b4269..0b092181bca7 100644
--- a/contrib/llvm-project/clang/lib/Parse/Parser.cpp
+++ b/contrib/llvm-project/clang/lib/Parse/Parser.cpp
@@ -13,6 +13,7 @@
#include "clang/Parse/Parser.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/FileManager.h"
#include "clang/Parse/ParseDiagnostic.h"
@@ -21,6 +22,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/TimeProfiler.h"
using namespace clang;
@@ -49,10 +51,10 @@ IdentifierInfo *Parser::getSEHExceptKeyword() {
}
Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
- : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
- GreaterThanIsOperator(true), ColonIsSacred(false),
- InMessageExpression(false), TemplateParameterDepth(0),
- ParsingInObjCContainer(false) {
+ : PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions),
+ Diags(PP.getDiagnostics()), GreaterThanIsOperator(true),
+ ColonIsSacred(false), InMessageExpression(false),
+ TemplateParameterDepth(0), ParsingInObjCContainer(false) {
SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
Tok.startToken();
Tok.setKind(tok::eof);
@@ -68,6 +70,11 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
PP.addCommentHandler(CommentSemaHandler.get());
PP.setCodeCompletionHandler(*this);
+
+ Actions.ParseTypeFromStringCallback =
+ [this](StringRef TypeStr, StringRef Context, SourceLocation IncludeLoc) {
+ return this->ParseTypeFromString(TypeStr, Context, IncludeLoc);
+ };
}
DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
@@ -153,7 +160,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
return true;
}
-bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
+bool Parser::ExpectAndConsumeSemi(unsigned DiagID, StringRef TokenUsed) {
if (TryConsumeToken(tok::semi))
return false;
@@ -172,7 +179,7 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
return false;
}
- return ExpectAndConsume(tok::semi, DiagID);
+ return ExpectAndConsume(tok::semi, DiagID , TokenUsed);
}
void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
@@ -279,7 +286,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
// We always want this function to skip at least one token if the first token
// isn't T and if not at EOF.
bool isFirstTokenSkipped = true;
- while (1) {
+ while (true) {
// If we found one of the tokens, stop and return true.
for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) {
if (Tok.is(Toks[i])) {
@@ -309,15 +316,24 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
return false;
case tok::annot_pragma_openmp:
+ case tok::annot_attr_openmp:
case tok::annot_pragma_openmp_end:
// Stop before an OpenMP pragma boundary.
if (OpenMPDirectiveParsing)
return false;
ConsumeAnnotationToken();
break;
+ case tok::annot_pragma_openacc:
+ case tok::annot_pragma_openacc_end:
+ // Stop before an OpenACC pragma boundary.
+ if (OpenACCDirectiveParsing)
+ return false;
+ ConsumeAnnotationToken();
+ break;
case tok::annot_module_begin:
case tok::annot_module_end:
case tok::annot_module_include:
+ case tok::annot_repl_input_end:
// Stop before we change submodules. They generally indicate a "good"
// place to pick up parsing again (except in the special case where
// we're trying to skip to EOF).
@@ -385,7 +401,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
case tok::semi:
if (HasFlagsSet(Flags, StopAtSemi))
return false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
// Skip this token.
ConsumeAnyToken();
@@ -494,6 +510,7 @@ void Parser::Initialize() {
Ident_instancetype = nullptr;
Ident_final = nullptr;
Ident_sealed = nullptr;
+ Ident_abstract = nullptr;
Ident_override = nullptr;
Ident_GNU_final = nullptr;
Ident_import = nullptr;
@@ -503,10 +520,12 @@ void Parser::Initialize() {
Ident_vector = nullptr;
Ident_bool = nullptr;
+ Ident_Bool = nullptr;
Ident_pixel = nullptr;
if (getLangOpts().AltiVec || getLangOpts().ZVector) {
Ident_vector = &PP.getIdentifierTable().get("vector");
Ident_bool = &PP.getIdentifierTable().get("bool");
+ Ident_Bool = &PP.getIdentifierTable().get("_Bool");
}
if (getLangOpts().AltiVec)
Ident_pixel = &PP.getIdentifierTable().get("pixel");
@@ -518,7 +537,8 @@ void Parser::Initialize() {
Ident_strict = nullptr;
Ident_replacement = nullptr;
- Ident_language = Ident_defined_in = Ident_generated_declaration = nullptr;
+ Ident_language = Ident_defined_in = Ident_generated_declaration = Ident_USR =
+ nullptr;
Ident__except = nullptr;
@@ -577,15 +597,20 @@ void Parser::DestroyTemplateIds() {
/// top-level-declaration-seq[opt] private-module-fragment[opt]
///
/// Note that in C, it is an error if there is no first declaration.
-bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
+bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result,
+ Sema::ModuleImportState &ImportState) {
Actions.ActOnStartOfTranslationUnit();
+ // For C++20 modules, a module decl must be the first in the TU. We also
+ // need to track module imports.
+ ImportState = Sema::ModuleImportState::FirstDecl;
+ bool NoTopLevelDecls = ParseTopLevelDecl(Result, ImportState);
+
// C11 6.9p1 says translation units must have at least one top-level
// declaration. C++ doesn't have this restriction. We also don't want to
// complain if we have a precompiled header, although technically if the PCH
// is empty we should still emit the (pedantic) diagnostic.
// If the main file is a header, we're only pretending it's a TU; don't warn.
- bool NoTopLevelDecls = ParseTopLevelDecl(Result, true);
if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() &&
!getLangOpts().CPlusPlus && !getLangOpts().IsHeaderFile)
Diag(diag::ext_empty_translation_unit);
@@ -599,7 +624,8 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
/// top-level-declaration:
/// declaration
/// [C++20] module-import-declaration
-bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
+bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
+ Sema::ModuleImportState &ImportState) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);
// Skip over the EOF token, flagging end of previous input for incremental
@@ -619,8 +645,8 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
goto module_decl;
// Note: no need to handle kw_import here. We only form kw_import under
- // the Modules TS, and in that case 'export import' is parsed as an
- // export-declaration containing an import-declaration.
+ // the Standard C++ Modules, and in that case 'export import' is parsed as
+ // an export-declaration containing an import-declaration.
// Recognize context-sensitive C++20 'export module' and 'export import'
// declarations.
@@ -643,37 +669,49 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
case tok::kw_module:
module_decl:
- Result = ParseModuleDecl(IsFirstDecl);
+ Result = ParseModuleDecl(ImportState);
return false;
- // tok::kw_import is handled by ParseExternalDeclaration. (Under the Modules
- // TS, an import can occur within an export block.)
+ case tok::kw_import:
import_decl: {
- Decl *ImportDecl = ParseModuleImport(SourceLocation());
+ Decl *ImportDecl = ParseModuleImport(SourceLocation(), ImportState);
Result = Actions.ConvertDeclToDeclGroup(ImportDecl);
return false;
}
- case tok::annot_module_include:
- Actions.ActOnModuleInclude(Tok.getLocation(),
- reinterpret_cast<Module *>(
- Tok.getAnnotationValue()));
+ case tok::annot_module_include: {
+ auto Loc = Tok.getLocation();
+ Module *Mod = reinterpret_cast<Module *>(Tok.getAnnotationValue());
+ // FIXME: We need a better way to disambiguate C++ clang modules and
+ // standard C++ modules.
+ if (!getLangOpts().CPlusPlusModules || !Mod->isHeaderUnit())
+ Actions.ActOnModuleInclude(Loc, Mod);
+ else {
+ DeclResult Import =
+ Actions.ActOnModuleImport(Loc, SourceLocation(), Loc, Mod);
+ Decl *ImportDecl = Import.isInvalid() ? nullptr : Import.get();
+ Result = Actions.ConvertDeclToDeclGroup(ImportDecl);
+ }
ConsumeAnnotationToken();
return false;
+ }
case tok::annot_module_begin:
Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
ConsumeAnnotationToken();
+ ImportState = Sema::ModuleImportState::NotACXX20Module;
return false;
case tok::annot_module_end:
Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
ConsumeAnnotationToken();
+ ImportState = Sema::ModuleImportState::NotACXX20Module;
return false;
case tok::eof:
+ case tok::annot_repl_input_end:
// Check whether -fmax-tokens= was reached.
if (PP.getMaxTokens() != 0 && PP.getTokenCount() > PP.getMaxTokens()) {
PP.Diag(Tok.getLocation(), diag::warn_max_tokens_total)
@@ -686,8 +724,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
// Late template parsing can begin.
Actions.SetLateTemplateParser(LateTemplateParserCallback, nullptr, this);
- if (!PP.isIncrementalProcessingEnabled())
- Actions.ActOnEndOfTranslationUnit();
+ Actions.ActOnEndOfTranslationUnit();
//else don't tell Sema that we ended parsing: more input might come.
return true;
@@ -710,15 +747,39 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
break;
}
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
-
- Result = ParseExternalDeclaration(attrs);
+ 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))
+ ;
+
+ Result = ParseExternalDeclaration(DeclAttrs, DeclSpecAttrs);
+ // An empty Result might mean a line with ';' or some parsing error, ignore
+ // it.
+ if (Result) {
+ if (ImportState == Sema::ModuleImportState::FirstDecl)
+ // First decl was not modular.
+ ImportState = Sema::ModuleImportState::NotACXX20Module;
+ else if (ImportState == Sema::ModuleImportState::ImportAllowed)
+ // Non-imports disallow further imports.
+ ImportState = Sema::ModuleImportState::ImportFinished;
+ else if (ImportState ==
+ Sema::ModuleImportState::PrivateFragmentImportAllowed)
+ // Non-imports disallow further imports.
+ ImportState = Sema::ModuleImportState::PrivateFragmentImportFinished;
+ }
return false;
}
/// ParseExternalDeclaration:
///
+/// The `Attrs` that are passed in are C++11 attributes and appertain to the
+/// declaration.
+///
/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
/// function-definition
/// declaration
@@ -741,10 +802,11 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
///
/// [C++0x/GNU] 'extern' 'template' declaration
///
-/// [Modules-TS] module-import-declaration
+/// [C++20] module-import-declaration
///
Parser::DeclGroupPtrTy
-Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
+Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
+ ParsedAttributes &DeclSpecAttrs,
ParsingDeclSpec *DS) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -781,11 +843,15 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
HandlePragmaFPContract();
return nullptr;
case tok::annot_pragma_fenv_access:
+ case tok::annot_pragma_fenv_access_ms:
HandlePragmaFEnvAccess();
return nullptr;
case tok::annot_pragma_fenv_round:
HandlePragmaFEnvRound();
return nullptr;
+ case tok::annot_pragma_cx_limited_range:
+ HandlePragmaCXLimitedRange();
+ return nullptr;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
return nullptr;
@@ -795,10 +861,13 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return nullptr;
+ case tok::annot_attr_openmp:
case tok::annot_pragma_openmp: {
AccessSpecifier AS = AS_none;
- return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
+ return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
}
+ case tok::annot_pragma_openacc:
+ return ParseOpenACCDirectiveDecl();
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return nullptr;
@@ -817,7 +886,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
SingleDecl =
- Actions.ActOnEmptyDeclaration(getCurScope(), attrs, Tok.getLocation());
+ Actions.ActOnEmptyDeclaration(getCurScope(), Attrs, Tok.getLocation());
ConsumeExtraSemi(OutsideFunction);
break;
case tok::r_brace:
@@ -831,10 +900,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseExternalDeclaration(attrs);
+ return ParseExternalDeclaration(Attrs, DeclSpecAttrs);
}
case tok::kw_asm: {
- ProhibitAttributes(attrs);
+ ProhibitAttributes(Attrs);
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc;
@@ -859,7 +928,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
break;
}
case tok::at:
- return ParseObjCAtDirectives(attrs);
+ return ParseObjCAtDirectives(Attrs, DeclSpecAttrs);
case tok::minus:
case tok::plus:
if (!getLangOpts().ObjC) {
@@ -870,28 +939,41 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
SingleDecl = ParseObjCMethodDefinition();
break;
case tok::code_completion:
+ cutOffParsing();
if (CurParsedObjCImpl) {
// Code-complete Objective-C methods even without leading '-'/'+' prefix.
Actions.CodeCompleteObjCMethodDecl(getCurScope(),
- /*IsInstanceMethod=*/None,
+ /*IsInstanceMethod=*/std::nullopt,
/*ReturnType=*/nullptr);
}
- Actions.CodeCompleteOrdinaryName(
- getCurScope(),
- CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace);
- cutOffParsing();
+
+ Sema::ParserCompletionContext PCC;
+ if (CurParsedObjCImpl) {
+ PCC = Sema::PCC_ObjCImplementation;
+ } else if (PP.isIncrementalProcessingEnabled()) {
+ PCC = Sema::PCC_TopLevelOrExpression;
+ } else {
+ PCC = Sema::PCC_Namespace;
+ };
+ Actions.CodeCompleteOrdinaryName(getCurScope(), PCC);
return nullptr;
- case tok::kw_import:
- SingleDecl = ParseModuleImport(SourceLocation());
- break;
+ case tok::kw_import: {
+ Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module;
+ if (getLangOpts().CPlusPlusModules) {
+ llvm_unreachable("not expecting a c++20 import here");
+ ProhibitAttributes(Attrs);
+ }
+ SingleDecl = ParseModuleImport(SourceLocation(), IS);
+ } break;
case tok::kw_export:
- if (getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS) {
+ if (getLangOpts().CPlusPlusModules) {
+ ProhibitAttributes(Attrs);
SingleDecl = ParseExportDeclaration();
break;
}
// This must be 'export template'. Parse it so we can diagnose our lack
// of support.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -901,9 +983,19 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs);
}
+ case tok::kw_cbuffer:
+ case tok::kw_tbuffer:
+ if (getLangOpts().HLSL) {
+ SourceLocation DeclEnd;
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs);
+ }
+ goto dont_know;
+
case tok::kw_static:
// Parse (then ignore) 'static' prior to a template instantiation. This is
// a GCC extension that we intentionally do not support.
@@ -911,7 +1003,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs);
}
goto dont_know;
@@ -922,7 +1015,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// Inline namespaces. Allowed as an extension even in C++03.
if (NextKind == tok::kw_namespace) {
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs);
}
// Parse (then ignore) 'inline' prior to a template instantiation. This is
@@ -931,7 +1025,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 1;
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs);
}
}
goto dont_know;
@@ -946,7 +1041,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
SourceLocation DeclEnd;
return Actions.ConvertDeclToDeclGroup(ParseExplicitInstantiation(
- DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, attrs));
+ DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, Attrs));
}
goto dont_know;
@@ -966,8 +1061,13 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ConsumeToken();
return nullptr;
}
+ if (getLangOpts().IncrementalExtensions &&
+ !isDeclarationStatement(/*DisambiguatingWithExpression=*/true))
+ return ParseTopLevelStmtDecl();
+
// We can't tell whether this is a function-definition or declaration yet.
- return ParseDeclarationOrFunctionDefinition(attrs, DS);
+ if (!SingleDecl)
+ return ParseDeclarationOrFunctionDefinition(Attrs, DeclSpecAttrs, DS);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1004,7 +1104,7 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
// Handle K&R C argument lists: int X(f) int f; {}
if (!getLangOpts().CPlusPlus &&
Declarator.getFunctionTypeInfo().isKNRPrototype())
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(ImplicitTypenameContext::No);
if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) {
const Token &KW = NextToken();
@@ -1031,10 +1131,18 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
/// [OMP] threadprivate-directive
/// [OMP] allocate-directive [TODO]
///
-Parser::DeclGroupPtrTy
-Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
- ParsingDeclSpec &DS,
- AccessSpecifier AS) {
+Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
+ ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs,
+ ParsingDeclSpec &DS, AccessSpecifier AS) {
+ // Because we assume that the DeclSpec has not yet been initialised, we simply
+ // overwrite the source range and attribute the provided leading declspec
+ // attributes.
+ assert(DS.getSourceRange().isInvalid() &&
+ "expected uninitialised source range");
+ DS.SetRangeStart(DeclSpecAttrs.Range.getBegin());
+ DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd());
+ DS.takeAttributesFrom(DeclSpecAttrs);
+
MaybeParseMicrosoftAttributes(DS.getAttributes());
// Parse the common declaration-specifiers piece.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,
@@ -1073,14 +1181,13 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
? DS.getTypeSpecTypeLoc().getLocWithOffset(
LengthOfTSTToken(DS.getTypeSpecType()))
: SourceLocation();
- ProhibitAttributes(attrs, CorrectLocationForAttributes);
+ ProhibitAttributes(Attrs, CorrectLocationForAttributes);
ConsumeToken();
RecordDecl *AnonRecord = nullptr;
- Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
- DS, AnonRecord);
+ Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(
+ getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord);
DS.complete(TheDecl);
- if (getLangOpts().OpenCL)
- Actions.setCurrentOpenCLExtensionForDecl(TheDecl);
+ Actions.ActOnDefinedDeclarationSpecifier(TheDecl);
if (AnonRecord) {
Decl* decls[] = {AnonRecord, TheDecl};
return Actions.BuildDeclaratorGroup(decls);
@@ -1088,7 +1195,8 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- DS.takeAttributesFrom(attrs);
+ if (DS.hasTagDefinition())
+ Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl());
// ObjC2 allows prefix attributes on class interfaces and protocols.
// FIXME: This still needs better diagnostics. We should only accept
@@ -1104,6 +1212,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
}
DS.abort();
+ DS.takeAttributesFrom(Attrs);
const char *PrevSpec = nullptr;
unsigned DiagID;
@@ -1127,19 +1236,26 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
if (getLangOpts().CPlusPlus && isTokenStringLiteral() &&
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
+ ProhibitAttributes(Attrs);
Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- return ParseDeclGroup(DS, DeclaratorContext::File);
+ return ParseDeclGroup(DS, DeclaratorContext::File, Attrs);
}
-Parser::DeclGroupPtrTy
-Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
- ParsingDeclSpec *DS,
- AccessSpecifier AS) {
+Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
+ ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs,
+ ParsingDeclSpec *DS, AccessSpecifier AS) {
+ // Add an enclosing time trace scope for a bunch of small scopes with
+ // "EvaluateAsConstExpr".
+ llvm::TimeTraceScope TimeScope("ParseDeclarationOrFunctionDefinition", [&]() {
+ return Tok.getLocation().printToString(
+ Actions.getASTContext().getSourceManager());
+ });
+
if (DS) {
- return ParseDeclOrFunctionDefInternal(attrs, *DS, AS);
+ return ParseDeclOrFunctionDefInternal(Attrs, DeclSpecAttrs, *DS, AS);
} else {
ParsingDeclSpec PDS(*this);
// Must temporarily exit the objective-c container scope for
@@ -1147,7 +1263,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
// afterwards.
ObjCDeclContextSwitch ObjCDC(*this);
- return ParseDeclOrFunctionDefInternal(attrs, PDS, AS);
+ return ParseDeclOrFunctionDefInternal(Attrs, DeclSpecAttrs, PDS, AS);
}
}
@@ -1168,15 +1284,21 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
LateParsedAttrList *LateParsedAttrs) {
+ llvm::TimeTraceScope TimeScope("ParseFunctionDefinition", [&]() {
+ return Actions.GetNameForDeclarator(D).getName().getAsString();
+ });
+
// Poison SEH identifiers so they are flagged as illegal in function bodies.
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
- // If this is C90 and the declspecs were completely missing, fudge in an
+ // If this is C89 and the declspecs were completely missing, fudge in an
// implicit int. We do this here because this is the only place where
// declaration-specifiers are completely optional in the grammar.
- if (getLangOpts().ImplicitInt && D.getDeclSpec().isEmpty()) {
+ if (getLangOpts().isImplicitIntRequired() && D.getDeclSpec().isEmpty()) {
+ Diag(D.getIdentifierLoc(), diag::warn_missing_type_specifier)
+ << D.getDeclSpec().getSourceRange();
const char *PrevSpec;
unsigned DiagID;
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
@@ -1213,7 +1335,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// a definition. Late parsed attributes are checked at the end.
if (Tok.isNot(tok::equal)) {
for (const ParsedAttr &AL : D.getAttributes())
- if (AL.isKnownToGCC() && !AL.isCXX11Attribute())
+ if (AL.isKnownToGCC() && !AL.isStandardAttributeSyntax())
Diag(AL.getLoc(), diag::warn_attribute_on_function_definition) << AL;
}
@@ -1277,72 +1399,92 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope);
- // Tell the actions module that we have entered a function definition with the
- // specified Declarator for the function.
- Sema::SkipBodyInfo SkipBody;
- Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D,
- TemplateInfo.TemplateParams
- ? *TemplateInfo.TemplateParams
- : MultiTemplateParamsArg(),
- &SkipBody);
-
- if (SkipBody.ShouldSkip) {
- SkipFunctionBody();
- return Res;
- }
-
- // Break out of the ParsingDeclarator context before we parse the body.
- D.complete(Res);
-
- // Break out of the ParsingDeclSpec context, too. This const_cast is
- // safe because we're always the sole owner.
- D.getMutableDeclSpec().abort();
-
- // With abbreviated function templates - we need to explicitly add depth to
- // account for the implicit template parameter list induced by the template.
- if (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res))
- if (Template->isAbbreviated() &&
- Template->getTemplateParameters()->getParam(0)->isImplicit())
- // First template parameter is implicit - meaning no explicit template
- // parameter list was specified.
- CurTemplateDepthTracker.addDepth(1);
-
+ // Parse function body eagerly if it is either '= delete;' or '= default;' as
+ // ActOnStartOfFunctionDef needs to know whether the function is deleted.
+ Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other;
+ SourceLocation KWLoc;
if (TryConsumeToken(tok::equal)) {
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
- bool Delete = false;
- SourceLocation KWLoc;
if (TryConsumeToken(tok::kw_delete, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_defaulted_deleted_function
: diag::ext_defaulted_deleted_function)
- << 1 /* deleted */;
- Actions.SetDeclDeleted(Res, KWLoc);
- Delete = true;
+ << 1 /* deleted */;
+ BodyKind = Sema::FnBodyKind::Delete;
} else if (TryConsumeToken(tok::kw_default, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_defaulted_deleted_function
: diag::ext_defaulted_deleted_function)
- << 0 /* defaulted */;
- Actions.SetDeclDefaulted(Res, KWLoc);
+ << 0 /* defaulted */;
+ BodyKind = Sema::FnBodyKind::Default;
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
}
if (Tok.is(tok::comma)) {
Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
- << Delete;
+ << (BodyKind == Sema::FnBodyKind::Delete);
SkipUntil(tok::semi);
} else if (ExpectAndConsume(tok::semi, diag::err_expected_after,
- Delete ? "delete" : "default")) {
+ BodyKind == Sema::FnBodyKind::Delete
+ ? "delete"
+ : "default")) {
SkipUntil(tok::semi);
}
+ }
+ // Tell the actions module that we have entered a function definition with the
+ // specified Declarator for the function.
+ Sema::SkipBodyInfo SkipBody;
+ Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D,
+ TemplateInfo.TemplateParams
+ ? *TemplateInfo.TemplateParams
+ : MultiTemplateParamsArg(),
+ &SkipBody, BodyKind);
+
+ if (SkipBody.ShouldSkip) {
+ // Do NOT enter SkipFunctionBody if we already consumed the tokens.
+ if (BodyKind == Sema::FnBodyKind::Other)
+ SkipFunctionBody();
+
+ // ExpressionEvaluationContext is pushed in ActOnStartOfFunctionDef
+ // and it would be popped in ActOnFinishFunctionBody.
+ // We pop it explcitly here since ActOnFinishFunctionBody won't get called.
+ //
+ // Do not call PopExpressionEvaluationContext() if it is a lambda because
+ // one is already popped when finishing the lambda in BuildLambdaExpr().
+ //
+ // FIXME: It looks not easy to balance PushExpressionEvaluationContext()
+ // and PopExpressionEvaluationContext().
+ if (!isLambdaCallOperator(dyn_cast_if_present<FunctionDecl>(Res)))
+ Actions.PopExpressionEvaluationContext();
+ return Res;
+ }
+
+ // Break out of the ParsingDeclarator context before we parse the body.
+ D.complete(Res);
+
+ // Break out of the ParsingDeclSpec context, too. This const_cast is
+ // safe because we're always the sole owner.
+ D.getMutableDeclSpec().abort();
+
+ if (BodyKind != Sema::FnBodyKind::Other) {
+ Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind);
Stmt *GeneratedBody = Res ? Res->getBody() : nullptr;
Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false);
return Res;
}
+ // With abbreviated function templates - we need to explicitly add depth to
+ // account for the implicit template parameter list induced by the template.
+ if (const auto *Template = dyn_cast_if_present<FunctionTemplateDecl>(Res);
+ Template && Template->isAbbreviated() &&
+ Template->getTemplateParameters()->getParam(0)->isImplicit())
+ // First template parameter is implicit - meaning no explicit template
+ // parameter list was specified.
+ CurTemplateDepthTracker.addDepth(1);
+
if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) &&
trySkippingFunctionBody()) {
BodyScope.Exit();
@@ -1408,7 +1550,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
Scope::FunctionDeclarationScope | Scope::DeclScope);
// Read all the argument declarations.
- while (isDeclarationSpecifier()) {
+ while (isDeclarationSpecifier(ImplicitTypenameContext::No)) {
SourceLocation DSStart = Tok.getLocation();
// Parse the common declaration-specifiers piece.
@@ -1440,11 +1582,12 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
}
// Parse the first declarator attached to this declspec.
- Declarator ParmDeclarator(DS, DeclaratorContext::KNRTypeList);
+ Declarator ParmDeclarator(DS, ParsedAttributesView::none(),
+ DeclaratorContext::KNRTypeList);
ParseDeclarator(ParmDeclarator);
// Handle the full declarator list.
- while (1) {
+ while (true) {
// If attributes are present, parse them.
MaybeParseGNUAttributes(ParmDeclarator);
@@ -1529,7 +1672,7 @@ ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) {
ExprResult AsmString(ParseStringLiteralExpression());
if (!AsmString.isInvalid()) {
const auto *SL = cast<StringLiteral>(AsmString.get());
- if (!SL->isAscii()) {
+ if (!SL->isOrdinary()) {
Diag(Tok, diag::err_asm_operand_wide_string_literal)
<< SL->isWide()
<< SL->getSourceRange();
@@ -1620,8 +1763,12 @@ void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) {
///
/// \param CCC Indicates how to perform typo-correction for this name. If NULL,
/// no typo correction will be performed.
+/// \param AllowImplicitTypename Whether we are in a context where a dependent
+/// nested-name-specifier without typename is treated as a type (e.g.
+/// T::type).
Parser::AnnotatedNameKind
-Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
+Parser::TryAnnotateName(CorrectionCandidateCallback *CCC,
+ ImplicitTypenameContext AllowImplicitTypename) {
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
const bool EnteringContext = false;
@@ -1630,12 +1777,13 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus &&
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
EnteringContext))
return ANK_Error;
if (Tok.isNot(tok::identifier) || SS.isInvalid()) {
- if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation))
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+ AllowImplicitTypename))
return ANK_Error;
return ANK_Unresolved;
}
@@ -1645,10 +1793,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
// FIXME: Move the tentative declaration logic into ClassifyName so we can
// typo-correct to tentatively-declared identifiers.
- if (isTentativelyDeclared(Name)) {
+ if (isTentativelyDeclared(Name) && SS.isEmpty()) {
// Identifier has been tentatively declared, and thus cannot be resolved as
// an expression. Fall back to annotating it as a type.
- if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation))
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+ AllowImplicitTypename))
return ANK_Error;
return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl;
}
@@ -1695,6 +1844,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
break;
case Sema::NC_Type: {
+ if (TryAltiVecVectorToken())
+ // vector has been found as a type id when altivec is enabled but
+ // this is followed by a declaration specifier so this is really the
+ // altivec vector token. Leave it unannotated.
+ break;
SourceLocation BeginLoc = NameLoc;
if (SS.isNotEmpty())
BeginLoc = SS.getBeginLoc();
@@ -1736,6 +1890,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
return ANK_Success;
case Sema::NC_NonType:
+ if (TryAltiVecVectorToken())
+ // vector has been found as a non-type id when altivec is enabled but
+ // this is followed by a declaration specifier so this is really the
+ // altivec vector token. Leave it unannotated.
+ break;
Tok.setKind(tok::annot_non_type);
setNonTypeAnnotation(Tok, Classification.getNonTypeDecl());
Tok.setLocation(NameLoc);
@@ -1765,32 +1924,26 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
AnnotateScopeToken(SS, !WasScopeAnnotation);
return ANK_TemplateName;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
+ case Sema::NC_Concept:
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
case Sema::NC_UndeclaredTemplate: {
- // We have a type, variable or function template followed by '<'.
- ConsumeToken();
- UnqualifiedId Id;
- Id.setIdentifier(Name, NameLoc);
- if (AnnotateTemplateIdToken(
- TemplateTy::make(Classification.getTemplateName()),
- Classification.getTemplateNameKind(), SS, SourceLocation(), Id))
- return ANK_Error;
- return ANK_Success;
- }
- case Sema::NC_Concept: {
- UnqualifiedId Id;
- Id.setIdentifier(Name, NameLoc);
+ bool IsConceptName = Classification.getKind() == Sema::NC_Concept;
+ // We have a template name followed by '<'. Consume the identifier token so
+ // we reach the '<' and annotate it.
if (Next.is(tok::less))
- // We have a concept name followed by '<'. Consume the identifier token so
- // we reach the '<' and annotate it.
ConsumeToken();
+ UnqualifiedId Id;
+ Id.setIdentifier(Name, NameLoc);
if (AnnotateTemplateIdToken(
TemplateTy::make(Classification.getTemplateName()),
Classification.getTemplateNameKind(), SS, SourceLocation(), Id,
- /*AllowTypeAnnotation=*/false, /*TypeConstraint=*/true))
+ /*AllowTypeAnnotation=*/!IsConceptName,
+ /*TypeConstraint=*/IsConceptName))
return ANK_Error;
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
return ANK_Success;
}
}
@@ -1834,11 +1987,12 @@ bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
///
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
-bool Parser::TryAnnotateTypeOrScopeToken() {
+bool Parser::TryAnnotateTypeOrScopeToken(
+ ImplicitTypenameContext AllowImplicitTypename) {
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
- Tok.is(tok::kw___super)) &&
+ Tok.is(tok::kw___super) || Tok.is(tok::kw_auto)) &&
"Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
@@ -1851,7 +2005,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
if (getLangOpts().MSVCCompat && NextToken().is(tok::kw_typedef)) {
Token TypedefToken;
PP.Lex(TypedefToken);
- bool Result = TryAnnotateTypeOrScopeToken();
+ bool Result = TryAnnotateTypeOrScopeToken(AllowImplicitTypename);
PP.EnterToken(Tok, /*IsReinject=*/true);
Tok = TypedefToken;
if (!Result)
@@ -1868,7 +2022,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false, nullptr,
/*IsTypename*/ true))
return true;
@@ -1877,7 +2031,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
Tok.is(tok::annot_decltype)) {
// Attempt to recover by skipping the invalid 'typename'
if (Tok.is(tok::annot_decltype) ||
- (!TryAnnotateTypeOrScopeToken() && Tok.isAnnotation())) {
+ (!TryAnnotateTypeOrScopeToken(AllowImplicitTypename) &&
+ Tok.isAnnotation())) {
unsigned DiagID = diag::err_expected_qualified_after_typename;
// MS compatibility: MSVC permits using known types with typename.
// e.g. "typedef typename T* pointer_type"
@@ -1939,26 +2094,28 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus)
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext*/ false))
return true;
- return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation);
+ return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+ AllowImplicitTypename);
}
/// Try to annotate a type or scope token, having already parsed an
/// optional scope specifier. \p IsNewScope should be \c true unless the scope
/// specifier was extracted from an existing tok::annot_cxxscope annotation.
-bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
- bool IsNewScope) {
+bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(
+ CXXScopeSpec &SS, bool IsNewScope,
+ ImplicitTypenameContext AllowImplicitTypename) {
if (Tok.is(tok::identifier)) {
// Determine whether the identifier is a type name.
if (ParsedType Ty = Actions.getTypeName(
*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
false, NextToken().is(tok::period), nullptr,
/*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo*/true,
- /*IsClassTemplateDeductionContext*/true)) {
+ /*NonTrivialTypeSourceInfo=*/true,
+ /*IsClassTemplateDeductionContext=*/true, AllowImplicitTypename)) {
SourceLocation BeginLoc = Tok.getLocation();
if (SS.isNotEmpty()) // it was a C++ qualified type name.
BeginLoc = SS.getBeginLoc();
@@ -1995,9 +2152,9 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
}
if (!getLangOpts().CPlusPlus) {
- // If we're in C, we can't have :: tokens at all (the lexer won't return
- // them). If the identifier is not a type, then it can't be scope either,
- // just early exit.
+ // If we're in C, the only place we can have :: tokens is C23
+ // attribute which is parsed elsewhere. If the identifier is not a type,
+ // then it can't be scope either, just early exit.
return false;
}
@@ -2044,7 +2201,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
// template-id annotation in a context where we weren't allowed
// to produce a type annotation token. Update the template-id
// annotation token to a type annotation token now.
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
return false;
}
}
@@ -2070,7 +2227,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
EnteringContext))
return true;
if (SS.isEmpty())
@@ -2102,7 +2259,7 @@ bool Parser::isTokenEqualOrEqualTypo() {
Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal)
<< Kind
<< FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::equal:
return true;
}
@@ -2113,22 +2270,22 @@ SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
PrevTokLocation = Tok.getLocation();
for (Scope *S = getCurScope(); S; S = S->getParent()) {
- if (S->getFlags() & Scope::FnScope) {
+ if (S->isFunctionScope()) {
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
Sema::PCC_RecoveryInFunction);
- cutOffParsing();
return PrevTokLocation;
}
- if (S->getFlags() & Scope::ClassScope) {
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
+ if (S->isClassScope()) {
cutOffParsing();
+ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
return PrevTokLocation;
}
}
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace);
cutOffParsing();
+ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace);
return PrevTokLocation;
}
@@ -2181,7 +2338,7 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
// Parse nested-name-specifier.
if (getLangOpts().CPlusPlus)
ParseOptionalCXXScopeSpecifier(Result.SS, /*ObjectType=*/nullptr,
- /*ObjectHadErrors=*/false,
+ /*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
// Check nested-name specifier.
@@ -2255,9 +2412,10 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
// Parse the declarations.
// FIXME: Support module import within __if_exists?
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
+ ParsedAttributes Attrs(AttrFactory);
+ MaybeParseCXX11Attributes(Attrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs);
if (Result && !getCurScope()->getParent())
Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
}
@@ -2267,7 +2425,7 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
/// Parse a declaration beginning with the 'module' keyword or C++20
/// context-sensitive keyword (optionally preceded by 'export').
///
-/// module-declaration: [Modules TS + P0629R0]
+/// module-declaration: [C++20]
/// 'export'[opt] 'module' module-name attribute-specifier-seq[opt] ';'
///
/// global-module-fragment: [C++2a]
@@ -2277,7 +2435,8 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
/// attribute-specifier-seq[opt] ';'
/// private-module-fragment: [C++2a]
/// 'module' ':' 'private' ';' top-level-declaration-seq[opt]
-Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) {
+Parser::DeclGroupPtrTy
+Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
SourceLocation StartLoc = Tok.getLocation();
Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export)
@@ -2297,7 +2456,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) {
// Parse a global-module-fragment, if present.
if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) {
SourceLocation SemiLoc = ConsumeToken();
- if (!IsFirstDecl) {
+ if (ImportState != Sema::ModuleImportState::FirstDecl) {
Diag(StartLoc, diag::err_global_module_introducer_not_at_start)
<< SourceRange(StartLoc, SemiLoc);
return nullptr;
@@ -2306,6 +2465,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) {
Diag(StartLoc, diag::err_module_fragment_exported)
<< /*global*/0 << FixItHint::CreateRemoval(StartLoc);
}
+ ImportState = Sema::ModuleImportState::GlobalFragment;
return Actions.ActOnGlobalModuleFragmentDecl(ModuleLoc);
}
@@ -2320,52 +2480,59 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) {
SourceLocation PrivateLoc = ConsumeToken();
DiagnoseAndSkipCXX11Attributes();
ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi);
+ ImportState = ImportState == Sema::ModuleImportState::ImportAllowed
+ ? Sema::ModuleImportState::PrivateFragmentImportAllowed
+ : Sema::ModuleImportState::PrivateFragmentImportFinished;
return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc);
}
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
- if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false))
+ if (ParseModuleName(ModuleLoc, Path, /*IsImport*/ false))
return nullptr;
// Parse the optional module-partition.
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
if (Tok.is(tok::colon)) {
SourceLocation ColonLoc = ConsumeToken();
- SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
- if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/false))
+ if (!getLangOpts().CPlusPlusModules)
+ Diag(ColonLoc, diag::err_unsupported_module_partition)
+ << SourceRange(ColonLoc, Partition.back().second);
+ // Recover by ignoring the partition name.
+ else if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/ false))
return nullptr;
-
- // FIXME: Support module partition declarations.
- Diag(ColonLoc, diag::err_unsupported_module_partition)
- << SourceRange(ColonLoc, Partition.back().second);
- // Recover by parsing as a non-partition.
}
// We don't support any module attributes yet; just parse them and diagnose.
- ParsedAttributesWithRange Attrs(AttrFactory);
+ ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
- ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr);
+ ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr,
+ diag::err_keyword_not_module_attr,
+ /*DiagnoseEmptyAttrs=*/false,
+ /*WarnOnUnknownAttrs=*/true);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
- return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, IsFirstDecl);
+ return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition,
+ ImportState);
}
/// Parse a module import declaration. This is essentially the same for
-/// Objective-C and the C++ Modules TS, except for the leading '@' (in ObjC)
-/// and the trailing optional attributes (in C++).
+/// Objective-C and C++20 except for the leading '@' (in ObjC) and the
+/// trailing optional attributes (in C++).
///
/// [ObjC] @import declaration:
/// '@' 'import' module-name ';'
/// [ModTS] module-import-declaration:
/// 'import' module-name attribute-specifier-seq[opt] ';'
-/// [C++2a] module-import-declaration:
+/// [C++20] module-import-declaration:
/// 'export'[opt] 'import' module-name
/// attribute-specifier-seq[opt] ';'
/// 'export'[opt] 'import' module-partition
/// attribute-specifier-seq[opt] ';'
/// 'export'[opt] 'import' header-name
/// attribute-specifier-seq[opt] ';'
-Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
+Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
+ Sema::ModuleImportState &ImportState) {
SourceLocation StartLoc = AtLoc.isInvalid() ? Tok.getLocation() : AtLoc;
SourceLocation ExportLoc;
@@ -2377,9 +2544,10 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
bool IsObjCAtImport = Tok.isObjCAtKeyword(tok::objc_import);
SourceLocation ImportLoc = ConsumeToken();
+ // For C++20 modules, we can have "name" or ":Partition name" as valid input.
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ bool IsPartition = false;
Module *HeaderUnit = nullptr;
-
if (Tok.is(tok::header_name)) {
// This is a header import that the preprocessor decided we should skip
// because it was malformed in some way. Parse and ignore it; it's already
@@ -2389,24 +2557,28 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
// This is a header import that the preprocessor mapped to a module import.
HeaderUnit = reinterpret_cast<Module *>(Tok.getAnnotationValue());
ConsumeAnnotationToken();
- } else if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon)) {
+ } else if (Tok.is(tok::colon)) {
SourceLocation ColonLoc = ConsumeToken();
- if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
+ if (!getLangOpts().CPlusPlusModules)
+ Diag(ColonLoc, diag::err_unsupported_module_partition)
+ << SourceRange(ColonLoc, Path.back().second);
+ // Recover by leaving partition empty.
+ else if (ParseModuleName(ColonLoc, Path, /*IsImport*/ true))
return nullptr;
-
- // FIXME: Support module partition import.
- Diag(ColonLoc, diag::err_unsupported_module_partition)
- << SourceRange(ColonLoc, Path.back().second);
- return nullptr;
+ else
+ IsPartition = true;
} else {
- if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
+ if (ParseModuleName(ImportLoc, Path, /*IsImport*/ true))
return nullptr;
}
- ParsedAttributesWithRange Attrs(AttrFactory);
+ ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
// We don't support any module import attributes yet.
- ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr);
+ ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr,
+ diag::err_keyword_not_import_attr,
+ /*DiagnoseEmptyAttrs=*/false,
+ /*WarnOnUnknownAttrs=*/true);
if (PP.hadModuleLoaderFatalFailure()) {
// With a fatal failure in the module loader, we abort parsing.
@@ -2414,12 +2586,60 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
return nullptr;
}
+ // Diagnose mis-imports.
+ bool SeenError = true;
+ switch (ImportState) {
+ case Sema::ModuleImportState::ImportAllowed:
+ SeenError = false;
+ break;
+ case Sema::ModuleImportState::FirstDecl:
+ // If we found an import decl as the first declaration, we must be not in
+ // a C++20 module unit or we are in an invalid state.
+ ImportState = Sema::ModuleImportState::NotACXX20Module;
+ [[fallthrough]];
+ case Sema::ModuleImportState::NotACXX20Module:
+ // We can only import a partition within a module purview.
+ if (IsPartition)
+ Diag(ImportLoc, diag::err_partition_import_outside_module);
+ else
+ SeenError = false;
+ break;
+ case Sema::ModuleImportState::GlobalFragment:
+ case Sema::ModuleImportState::PrivateFragmentImportAllowed:
+ // We can only have pre-processor directives in the global module fragment
+ // which allows pp-import, but not of a partition (since the global module
+ // does not have partitions).
+ // We cannot import a partition into a private module fragment, since
+ // [module.private.frag]/1 disallows private module fragments in a multi-
+ // TU module.
+ if (IsPartition || (HeaderUnit && HeaderUnit->Kind !=
+ Module::ModuleKind::ModuleHeaderUnit))
+ Diag(ImportLoc, diag::err_import_in_wrong_fragment)
+ << IsPartition
+ << (ImportState == Sema::ModuleImportState::GlobalFragment ? 0 : 1);
+ else
+ SeenError = false;
+ break;
+ case Sema::ModuleImportState::ImportFinished:
+ case Sema::ModuleImportState::PrivateFragmentImportFinished:
+ if (getLangOpts().CPlusPlusModules)
+ Diag(ImportLoc, diag::err_import_not_allowed_here);
+ else
+ SeenError = false;
+ break;
+ }
+ if (SeenError) {
+ ExpectAndConsumeSemi(diag::err_module_expected_semi);
+ return nullptr;
+ }
+
DeclResult Import;
if (HeaderUnit)
Import =
Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, HeaderUnit);
else if (!Path.empty())
- Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path);
+ Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path,
+ IsPartition);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
if (Import.isInvalid())
return nullptr;
@@ -2428,16 +2648,16 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
// the header is parseable. Emit a warning to make the user aware.
if (IsObjCAtImport && AtLoc.isValid()) {
auto &SrcMgr = PP.getSourceManager();
- auto *FE = SrcMgr.getFileEntryForID(SrcMgr.getFileID(AtLoc));
- if (FE && llvm::sys::path::parent_path(FE->getDir()->getName())
- .endswith(".framework"))
+ auto FE = SrcMgr.getFileEntryRefForID(SrcMgr.getFileID(AtLoc));
+ if (FE && llvm::sys::path::parent_path(FE->getDir().getName())
+ .ends_with(".framework"))
Diags.Report(AtLoc, diag::warn_atimport_in_framework_header);
}
return Import.get();
}
-/// Parse a C++ Modules TS / Objective-C module name (both forms use the same
+/// Parse a C++ / Objective-C module name (both forms use the same
/// grammar).
///
/// module-name:
@@ -2452,8 +2672,8 @@ bool Parser::ParseModuleName(
while (true) {
if (!Tok.is(tok::identifier)) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteModuleImport(UseLoc, Path);
cutOffParsing();
+ Actions.CodeCompleteModuleImport(UseLoc, Path);
return true;
}