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.cpp328
1 files changed, 209 insertions, 119 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/Parser.cpp b/contrib/llvm-project/clang/lib/Parse/Parser.cpp
index ffa1e0f027f1..6f63d01bc8ad 100644
--- a/contrib/llvm-project/clang/lib/Parse/Parser.cpp
+++ b/contrib/llvm-project/clang/lib/Parse/Parser.cpp
@@ -581,15 +581,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);
@@ -603,7 +608,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
@@ -647,13 +653,12 @@ 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;
}
@@ -669,12 +674,14 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
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:
@@ -714,15 +721,28 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
break;
}
- ParsedAttributesWithRange attrs(AttrFactory);
+ ParsedAttributes attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
Result = ParseExternalDeclaration(attrs);
+ // 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;
+ }
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
@@ -747,9 +767,8 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
///
/// [Modules-TS] module-import-declaration
///
-Parser::DeclGroupPtrTy
-Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
- ParsingDeclSpec *DS) {
+Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
+ ParsingDeclSpec *DS) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -803,7 +822,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
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_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
@@ -823,7 +842,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:
@@ -837,10 +856,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);
}
case tok::kw_asm: {
- ProhibitAttributes(attrs);
+ ProhibitAttributes(Attrs);
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc;
@@ -865,7 +884,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
break;
}
case tok::at:
- return ParseObjCAtDirectives(attrs);
+ return ParseObjCAtDirectives(Attrs);
case tok::minus:
case tok::plus:
if (!getLangOpts().ObjC) {
@@ -887,11 +906,17 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
getCurScope(),
CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace);
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) {
+ ProhibitAttributes(Attrs);
SingleDecl = ParseExportDeclaration();
break;
}
@@ -907,7 +932,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ EmptyDeclSpecAttrs);
}
case tok::kw_static:
@@ -917,7 +944,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ EmptyDeclSpecAttrs);
}
goto dont_know;
@@ -928,7 +957,9 @@ 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);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ EmptyDeclSpecAttrs);
}
// Parse (then ignore) 'inline' prior to a template instantiation. This is
@@ -937,7 +968,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 1;
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ EmptyDeclSpecAttrs);
}
}
goto dont_know;
@@ -952,7 +985,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;
@@ -973,7 +1006,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
return nullptr;
}
// We can't tell whether this is a function-definition or declaration yet.
- return ParseDeclarationOrFunctionDefinition(attrs, DS);
+ return ParseDeclarationOrFunctionDefinition(Attrs, DS);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1037,10 +1070,8 @@ 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, ParsingDeclSpec &DS, AccessSpecifier AS) {
MaybeParseMicrosoftAttributes(DS.getAttributes());
// Parse the common declaration-specifiers piece.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,
@@ -1079,11 +1110,11 @@ 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 (AnonRecord) {
Decl* decls[] = {AnonRecord, TheDecl};
@@ -1092,8 +1123,6 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- DS.takeAttributesFrom(attrs);
-
// ObjC2 allows prefix attributes on class interfaces and protocols.
// FIXME: This still needs better diagnostics. We should only accept
// attributes here, no types, etc.
@@ -1108,6 +1137,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
}
DS.abort();
+ DS.takeAttributesFrom(Attrs);
const char *PrevSpec = nullptr;
unsigned DiagID;
@@ -1131,19 +1161,18 @@ 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, ParsingDeclSpec *DS, AccessSpecifier AS) {
if (DS) {
- return ParseDeclOrFunctionDefInternal(attrs, *DS, AS);
+ return ParseDeclOrFunctionDefInternal(Attrs, *DS, AS);
} else {
ParsingDeclSpec PDS(*this);
// Must temporarily exit the objective-c container scope for
@@ -1151,7 +1180,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
// afterwards.
ObjCDeclContextSwitch ObjCDC(*this);
- return ParseDeclOrFunctionDefInternal(attrs, PDS, AS);
+ return ParseDeclOrFunctionDefInternal(Attrs, PDS, AS);
}
}
@@ -1177,10 +1206,12 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
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();
@@ -1281,6 +1312,41 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope);
+ // 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 '='");
+
+ if (TryConsumeToken(tok::kw_delete, KWLoc)) {
+ Diag(KWLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_defaulted_deleted_function
+ : diag::ext_defaulted_deleted_function)
+ << 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 */;
+ 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)
+ << (BodyKind == Sema::FnBodyKind::Delete);
+ SkipUntil(tok::semi);
+ } else if (ExpectAndConsume(tok::semi, diag::err_expected_after,
+ 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;
@@ -1288,10 +1354,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
TemplateInfo.TemplateParams
? *TemplateInfo.TemplateParams
: MultiTemplateParamsArg(),
- &SkipBody);
+ &SkipBody, BodyKind);
if (SkipBody.ShouldSkip) {
- SkipFunctionBody();
+ // Do NOT enter SkipFunctionBody if we already consumed the tokens.
+ if (BodyKind == Sema::FnBodyKind::Other)
+ SkipFunctionBody();
+
return Res;
}
@@ -1302,6 +1371,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// 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 (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res))
@@ -1311,42 +1387,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// parameter list was specified.
CurTemplateDepthTracker.addDepth(1);
- 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;
- } 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);
- } 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;
- SkipUntil(tok::semi);
- } else if (ExpectAndConsume(tok::semi, diag::err_expected_after,
- Delete ? "delete" : "default")) {
- SkipUntil(tok::semi);
- }
-
- Stmt *GeneratedBody = Res ? Res->getBody() : nullptr;
- Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false);
- return Res;
- }
-
if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) &&
trySkippingFunctionBody()) {
BodyScope.Exit();
@@ -1444,7 +1484,8 @@ 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.
@@ -1533,7 +1574,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();
@@ -2127,14 +2168,14 @@ 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);
return PrevTokLocation;
}
- if (S->getFlags() & Scope::ClassScope) {
+ if (S->isClassScope()) {
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
return PrevTokLocation;
@@ -2269,9 +2310,9 @@ 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);
+ DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs);
if (Result && !getCurScope()->getParent())
Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
}
@@ -2291,7 +2332,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)
@@ -2311,7 +2353,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;
@@ -2320,6 +2362,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);
}
@@ -2334,52 +2377,56 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) {
SourceLocation PrivateLoc = ConsumeToken();
DiagnoseAndSkipCXX11Attributes();
ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi);
+ ImportState = Sema::ModuleImportState::PrivateFragment;
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,
+ /*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;
@@ -2391,9 +2438,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
@@ -2403,24 +2451,27 @@ 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,
+ /*DiagnoseEmptyAttrs=*/false,
+ /*WarnOnUnknownAttrs=*/true);
if (PP.hadModuleLoaderFatalFailure()) {
// With a fatal failure in the module loader, we abort parsing.
@@ -2428,12 +2479,51 @@ 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:
+ 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:
+ // We can only have pre-processor directives in the global module
+ // fragment. We cannot import a named modules here, however we have a
+ // header unit import.
+ if (!HeaderUnit || HeaderUnit->Kind != Module::ModuleKind::ModuleHeaderUnit)
+ Diag(ImportLoc, diag::err_import_in_wrong_fragment) << IsPartition << 0;
+ else
+ SeenError = false;
+ break;
+ case Sema::ModuleImportState::ImportFinished:
+ if (getLangOpts().CPlusPlusModules)
+ Diag(ImportLoc, diag::err_import_not_allowed_here);
+ else
+ SeenError = false;
+ break;
+ case Sema::ModuleImportState::PrivateFragment:
+ Diag(ImportLoc, diag::err_import_in_wrong_fragment) << IsPartition << 1;
+ 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;
@@ -2442,8 +2532,8 @@ 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())
+ auto FE = SrcMgr.getFileEntryRefForID(SrcMgr.getFileID(AtLoc));
+ if (FE && llvm::sys::path::parent_path(FE->getDir().getName())
.endswith(".framework"))
Diags.Report(AtLoc, diag::warn_atimport_in_framework_header);
}