summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-04-14 08:06:59 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-04-14 08:06:59 +0000
commitd652bdd05f1c6a7f732fc01009ce68f7190d0e3d (patch)
treea803f9072874de1deca5bcc531ce1dbad1d2f11a /clang/lib
parentde20429cfc00f8d962c41a42024e8309bdda29ed (diff)
downloadbcm5719-llvm-d652bdd05f1c6a7f732fc01009ce68f7190d0e3d.tar.gz
bcm5719-llvm-d652bdd05f1c6a7f732fc01009ce68f7190d0e3d.zip
[c++20] Parsing support for module-declarations, import-declarations,
and the global and private module fragment. For now, the private module fragment introducer is ignored, but use of the global module fragment introducer should be properly enforced. llvm-svn: 358353
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Lex/PPDirectives.cpp4
-rw-r--r--clang/lib/Lex/Preprocessor.cpp1
-rw-r--r--clang/lib/Parse/Parser.cpp202
-rw-r--r--clang/lib/Sema/Sema.cpp32
-rw-r--r--clang/lib/Sema/SemaDecl.cpp121
5 files changed, 298 insertions, 62 deletions
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index c4adec83fb1..b3778c1d6f8 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -1648,6 +1648,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
EndLoc, LookupFrom, LookupFromFile);
switch (Action.Kind) {
case ImportAction::None:
+ case ImportAction::SkippedModuleImport:
break;
case ImportAction::ModuleBegin:
EnterAnnotationToken(SourceRange(HashLoc, EndLoc),
@@ -2034,6 +2035,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
switch (Action) {
case Skip:
// If we don't need to enter the file, stop now.
+ if (Module *M = SuggestedModule.getModule())
+ return {ImportAction::SkippedModuleImport, M};
return {ImportAction::None};
case IncludeLimitReached:
@@ -2117,6 +2120,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
return {ImportAction::ModuleBegin, M};
}
+ assert(!IsImportDecl && "failed to diagnose missing module for import decl");
return {ImportAction::None};
}
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 48d4a62ab7d..ebd4ae07ba4 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -1168,6 +1168,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
LLVM_FALLTHROUGH;
case ImportAction::ModuleImport:
+ case ImportAction::SkippedModuleImport:
// We chose to import (or textually enter) the file. Convert the
// header-name token into a header unit annotation token.
Suffix[0].setKind(tok::annot_header_unit);
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index b477e1f8bbc..d1920a9ae7a 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -460,6 +460,8 @@ void Parser::Initialize() {
Ident_sealed = nullptr;
Ident_override = nullptr;
Ident_GNU_final = nullptr;
+ Ident_import = nullptr;
+ Ident_module = nullptr;
Ident_super = &PP.getIdentifierTable().get("super");
@@ -512,6 +514,11 @@ void Parser::Initialize() {
PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block);
}
+ if (getLangOpts().CPlusPlusModules) {
+ Ident_import = PP.getIdentifierInfo("import");
+ Ident_module = PP.getIdentifierInfo("module");
+ }
+
Actions.Initialize();
// Prime the lexer look-ahead.
@@ -525,6 +532,16 @@ void Parser::LateTemplateParserCleanupCallback(void *P) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds);
}
+/// Parse the first top-level declaration in a translation unit.
+///
+/// translation-unit:
+/// [C] external-declaration
+/// [C] translation-unit external-declaration
+/// [C++] top-level-declaration-seq[opt]
+/// [C++20] global-module-fragment[opt] module-declaration
+/// 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) {
Actions.ActOnStartOfTranslationUnit();
@@ -532,7 +549,7 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
// 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.
- bool NoTopLevelDecls = ParseTopLevelDecl(Result);
+ bool NoTopLevelDecls = ParseTopLevelDecl(Result, true);
if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() &&
!getLangOpts().CPlusPlus)
Diag(diag::ext_empty_translation_unit);
@@ -542,7 +559,11 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
/// action tells us to. This returns true if the EOF was encountered.
-bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
+///
+/// top-level-declaration:
+/// declaration
+/// [C++20] module-import-declaration
+bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
// Skip over the EOF token, flagging end of previous input for incremental
@@ -557,13 +578,46 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
return false;
case tok::kw_export:
- if (NextToken().isNot(tok::kw_module))
+ switch (NextToken().getKind()) {
+ case tok::kw_module:
+ 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.
+
+ // Recognize context-sensitive C++20 'export module' and 'export import'
+ // declarations.
+ case tok::identifier: {
+ IdentifierInfo *II = NextToken().getIdentifierInfo();
+ if ((II == Ident_module || II == Ident_import) &&
+ GetLookAheadToken(2).isNot(tok::coloncolon)) {
+ if (II == Ident_module)
+ goto module_decl;
+ else
+ goto import_decl;
+ }
break;
- LLVM_FALLTHROUGH;
+ }
+
+ default:
+ break;
+ }
+ break;
+
case tok::kw_module:
- Result = ParseModuleDecl();
+ module_decl:
+ Result = ParseModuleDecl(IsFirstDecl);
return false;
+ // tok::kw_import is handled by ParseExternalDeclaration. (Under the Modules
+ // TS, an import can occur within an export block.)
+ import_decl: {
+ Decl *ImportDecl = ParseModuleImport(SourceLocation());
+ Result = Actions.ConvertDeclToDeclGroup(ImportDecl);
+ return false;
+ }
+
case tok::annot_module_include:
Actions.ActOnModuleInclude(Tok.getLocation(),
reinterpret_cast<Module *>(
@@ -595,6 +649,21 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
//else don't tell Sema that we ended parsing: more input might come.
return true;
+ case tok::identifier:
+ // C++2a [basic.link]p3:
+ // A token sequence beginning with 'export[opt] module' or
+ // 'export[opt] import' and not immediately followed by '::'
+ // is never interpreted as the declaration of a top-level-declaration.
+ if ((Tok.getIdentifierInfo() == Ident_module ||
+ Tok.getIdentifierInfo() == Ident_import) &&
+ NextToken().isNot(tok::coloncolon)) {
+ if (Tok.getIdentifierInfo() == Ident_module)
+ goto module_decl;
+ else
+ goto import_decl;
+ }
+ break;
+
default:
break;
}
@@ -2074,38 +2143,83 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
Braces.consumeClose();
}
-/// Parse a C++ Modules TS module declaration, which appears at the beginning
-/// of a module interface, module partition, or module implementation file.
+/// Parse a declaration beginning with the 'module' keyword or C++20
+/// context-sensitive keyword (optionally preceded by 'export').
///
-/// module-declaration: [Modules TS + P0273R0 + P0629R0]
-/// 'export'[opt] 'module' 'partition'[opt]
-/// module-name attribute-specifier-seq[opt] ';'
+/// module-declaration: [Modules TS + P0629R0]
+/// 'export'[opt] 'module' module-name attribute-specifier-seq[opt] ';'
///
-/// Note that 'partition' is a context-sensitive keyword.
-Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
+/// global-module-fragment: [C++2a]
+/// 'module' ';' top-level-declaration-seq[opt]
+/// module-declaration: [C++2a]
+/// 'export'[opt] 'module' module-name module-partition[opt]
+/// attribute-specifier-seq[opt] ';'
+/// private-module-fragment: [C++2a]
+/// 'module' ':' 'private' ';' top-level-declaration-seq[opt]
+Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) {
SourceLocation StartLoc = Tok.getLocation();
Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export)
? Sema::ModuleDeclKind::Interface
: Sema::ModuleDeclKind::Implementation;
- assert(Tok.is(tok::kw_module) && "not a module declaration");
+ assert(
+ (Tok.is(tok::kw_module) ||
+ (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_module)) &&
+ "not a module declaration");
SourceLocation ModuleLoc = ConsumeToken();
- if (Tok.is(tok::identifier) && NextToken().is(tok::identifier) &&
- Tok.getIdentifierInfo()->isStr("partition")) {
- // If 'partition' is present, this must be a module interface unit.
- if (MDK != Sema::ModuleDeclKind::Interface)
- Diag(Tok.getLocation(), diag::err_module_implementation_partition)
- << FixItHint::CreateInsertion(ModuleLoc, "export ");
- MDK = Sema::ModuleDeclKind::Partition;
+ // Attributes appear after the module name, not before.
+ if (Tok.is(tok::l_square))
+ CheckProhibitedCXX11Attribute();
+
+ // Parse a global-module-fragment, if present.
+ if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) {
+ SourceLocation SemiLoc = ConsumeToken();
+ if (!IsFirstDecl) {
+ Diag(StartLoc, diag::err_global_module_introducer_not_at_start)
+ << SourceRange(StartLoc, SemiLoc);
+ return nullptr;
+ }
+ if (MDK == Sema::ModuleDeclKind::Interface) {
+ Diag(StartLoc, diag::err_module_fragment_exported)
+ << /*global*/0 << FixItHint::CreateRemoval(StartLoc);
+ }
+ return Actions.ActOnGlobalModuleFragmentDecl(ModuleLoc);
+ }
+
+ // Parse a private-module-fragment, if present.
+ if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon) &&
+ NextToken().is(tok::kw_private)) {
+ if (MDK == Sema::ModuleDeclKind::Interface) {
+ Diag(StartLoc, diag::err_module_fragment_exported)
+ << /*private*/1 << FixItHint::CreateRemoval(StartLoc);
+ }
ConsumeToken();
+ SourceLocation PrivateLoc = ConsumeToken();
+ if (Tok.is(tok::l_square))
+ CheckProhibitedCXX11Attribute();
+ ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi);
+ return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc);
}
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false))
return nullptr;
+ // Parse the optional module-partition.
+ if (Tok.is(tok::colon)) {
+ SourceLocation ColonLoc = ConsumeToken();
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
+ 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);
MaybeParseCXX11Attributes(Attrs);
@@ -2113,7 +2227,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
ExpectAndConsumeSemi(diag::err_module_expected_semi);
- return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path);
+ return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, IsFirstDecl);
}
/// Parse a module import declaration. This is essentially the same for
@@ -2124,17 +2238,50 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
/// '@' 'import' module-name ';'
/// [ModTS] module-import-declaration:
/// 'import' module-name attribute-specifier-seq[opt] ';'
+/// [C++2a] 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) {
- assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import)
+ SourceLocation StartLoc = AtLoc.isInvalid() ? Tok.getLocation() : AtLoc;
+
+ SourceLocation ExportLoc;
+ TryConsumeToken(tok::kw_export, ExportLoc);
+
+ assert((AtLoc.isInvalid() ? Tok.isOneOf(tok::kw_import, tok::identifier)
: Tok.isObjCAtKeyword(tok::objc_import)) &&
"Improper start to module import");
bool IsObjCAtImport = Tok.isObjCAtKeyword(tok::objc_import);
SourceLocation ImportLoc = ConsumeToken();
- SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc;
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
- if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
+ 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
+ // been diagnosed.
+ ConsumeToken();
+ } else if (Tok.is(tok::annot_header_unit)) {
+ // 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)) {
+ SourceLocation ColonLoc = ConsumeToken();
+ if (ParseModuleName(ImportLoc, 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 {
+ if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
+ return nullptr;
+ }
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
@@ -2147,7 +2294,12 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
return nullptr;
}
- DeclResult Import = Actions.ActOnModuleImport(StartLoc, ImportLoc, Path);
+ DeclResult Import;
+ if (HeaderUnit)
+ Import =
+ Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, HeaderUnit);
+ else if (!Path.empty())
+ Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
if (Import.isInvalid())
return nullptr;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index bc4fdfbe58e..befe6ac7630 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -849,24 +849,11 @@ void Sema::ActOnStartOfTranslationUnit() {
if (getLangOpts().ModulesTS &&
(getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface ||
getLangOpts().getCompilingModule() == LangOptions::CMK_None)) {
+ // We start in an implied global module fragment.
SourceLocation StartOfTU =
SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
-
- // We start in the global module; all those declarations are implicitly
- // module-private (though they do not have module linkage).
- auto &Map = PP.getHeaderSearchInfo().getModuleMap();
- auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(StartOfTU);
- assert(GlobalModule && "module creation should not fail");
-
- // Enter the scope of the global module.
- ModuleScopes.push_back({});
- ModuleScopes.back().Module = GlobalModule;
- VisibleModules.setVisible(GlobalModule, StartOfTU);
-
- // All declarations created from now on are owned by the global module.
- auto *TU = Context.getTranslationUnitDecl();
- TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
- TU->setLocalOwningModule(GlobalModule);
+ ActOnGlobalModuleFragmentDecl(StartOfTU);
+ ModuleScopes.back().ImplicitGlobalModuleFragment = true;
}
}
@@ -997,13 +984,24 @@ void Sema::ActOnEndOfTranslationUnit() {
checkUndefinedButUsed(*this);
}
+ // A global-module-fragment is only permitted within a module unit.
+ bool DiagnosedMissingModuleDeclaration = false;
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment &&
+ !ModuleScopes.back().ImplicitGlobalModuleFragment) {
+ Diag(ModuleScopes.back().BeginLoc,
+ diag::err_module_declaration_missing_after_global_module_introducer);
+ DiagnosedMissingModuleDeclaration = true;
+ }
+
if (TUKind == TU_Module) {
// If we are building a module interface unit, we need to have seen the
// module declaration by now.
if (getLangOpts().getCompilingModule() ==
LangOptions::CMK_ModuleInterface &&
(ModuleScopes.empty() ||
- ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) {
+ ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) &&
+ !DiagnosedMissingModuleDeclaration) {
// FIXME: Make a better guess as to where to put the module declaration.
Diag(getSourceManager().getLocForStartOfFile(
getSourceManager().getMainFileID()),
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fa29e8c904f..cb1a5b684a5 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -17016,12 +17016,44 @@ static void checkModuleImportContext(Sema &S, Module *M,
}
}
-Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
- SourceLocation ModuleLoc,
- ModuleDeclKind MDK,
- ModuleIdPath Path) {
- assert(getLangOpts().ModulesTS &&
- "should only have module decl in modules TS");
+Sema::DeclGroupPtrTy
+Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) {
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) {
+ // Under -std=c++2a -fmodules-ts, we can find an explicit 'module;' after
+ // already implicitly entering the global module fragment. That's OK.
+ assert(getLangOpts().CPlusPlusModules && getLangOpts().ModulesTS &&
+ "unexpectedly encountered multiple global module fragment decls");
+ ModuleScopes.back().BeginLoc = ModuleLoc;
+ return nullptr;
+ }
+
+ // We start in the global module; all those declarations are implicitly
+ // module-private (though they do not have module linkage).
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(ModuleLoc);
+ assert(GlobalModule && "module creation should not fail");
+
+ // Enter the scope of the global module.
+ ModuleScopes.push_back({});
+ ModuleScopes.back().BeginLoc = ModuleLoc;
+ ModuleScopes.back().Module = GlobalModule;
+ VisibleModules.setVisible(GlobalModule, ModuleLoc);
+
+ // All declarations created from now on are owned by the global module.
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+ TU->setLocalOwningModule(GlobalModule);
+
+ // FIXME: Consider creating an explicit representation of this declaration.
+ return nullptr;
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
+ ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl) {
+ assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) &&
+ "should only have module decl in Modules TS or C++20");
// A module implementation unit requires that we are not compiling a module
// of any kind. A module interface unit requires that we are not compiling a
@@ -17051,19 +17083,40 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
return nullptr;
}
- assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
+ assert(ModuleScopes.size() <= 1 && "expected to be at global module scope");
// FIXME: Most of this work should be done by the preprocessor rather than
// here, in order to support macro import.
// Only one module-declaration is permitted per source file.
- if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
Diag(ModuleLoc, diag::err_module_redeclaration);
Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
diag::note_prev_module_declaration);
return nullptr;
}
+ // Find the global module fragment we're adopting into this module, if any.
+ Module *GlobalModuleFragment = nullptr;
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment)
+ GlobalModuleFragment = ModuleScopes.back().Module;
+
+ // In C++20, the module-declaration must be the first declaration if there
+ // is no global module fragment.
+ if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !GlobalModuleFragment) {
+ Diag(ModuleLoc, diag::err_module_decl_not_at_start);
+ SourceLocation BeginLoc =
+ ModuleScopes.empty()
+ ? SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID())
+ : ModuleScopes.back().BeginLoc;
+ if (BeginLoc.isValid()) {
+ Diag(BeginLoc, diag::note_global_module_introducer_missing)
+ << FixItHint::CreateInsertion(BeginLoc, "module;\n");
+ }
+ }
+
// Flatten the dots in a module name. Unlike Clang's hierarchical module map
// modules, the dots here are just another character that can appear in a
// module name.
@@ -17105,15 +17158,11 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
// Create a Module for the module that we're defining.
Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- ModuleScopes.front().Module);
+ GlobalModuleFragment);
assert(Mod && "module creation should not fail");
break;
}
- case ModuleDeclKind::Partition:
- // FIXME: Check we are in a submodule of the named module.
- return nullptr;
-
case ModuleDeclKind::Implementation:
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
PP.getIdentifierInfo(ModuleName), Path[0].second);
@@ -17124,12 +17173,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
// Create an empty module interface unit for error recovery.
Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- ModuleScopes.front().Module);
+ GlobalModuleFragment);
}
break;
}
- // Switch from the global module to the named module.
+ if (!GlobalModuleFragment) {
+ ModuleScopes.push_back({});
+ if (getLangOpts().ModulesLocalVisibility)
+ ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
+ }
+
+ // Switch from the global module fragment (if any) to the named module.
+ ModuleScopes.back().BeginLoc = StartLoc;
ModuleScopes.back().Module = Mod;
ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation;
VisibleModules.setVisible(Mod, ModuleLoc);
@@ -17146,6 +17202,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
}
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
+ SourceLocation ExportLoc,
SourceLocation ImportLoc,
ModuleIdPath Path) {
// Flatten the module path for a Modules TS module name.
@@ -17167,6 +17224,13 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
if (!Mod)
return true;
+ return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path);
+}
+
+DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
+ SourceLocation ExportLoc,
+ SourceLocation ImportLoc,
+ Module *Mod, ModuleIdPath Path) {
VisibleModules.setVisible(Mod, ImportLoc);
checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
@@ -17176,12 +17240,15 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
// silently ignoring the import.
// Import-from-implementation is valid in the Modules TS. FIXME: Should we
// warn on a redundant import of the current module?
+ // FIXME: Import of a module from an implementation partition of the same
+ // module is permitted.
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
- (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS))
+ (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) {
Diag(ImportLoc, getLangOpts().isCompilingModule()
? diag::err_module_self_import
: diag::err_module_import_in_implementation)
<< Mod->getFullModuleName() << getLangOpts().CurrentModule;
+ }
SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
@@ -17195,16 +17262,30 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
IdentifierLocs.push_back(Path[I].second);
}
+ // If this was a header import, pad out with dummy locations.
+ // FIXME: Pass in and use the location of the header-name token in this case.
+ if (Path.empty()) {
+ for (; ModCheck; ModCheck = ModCheck->Parent) {
+ IdentifierLocs.push_back(SourceLocation());
+ }
+ }
+
ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc,
Mod, IdentifierLocs);
+ CurContext->addDecl(Import);
+
+ // Sequence initialization of the imported module before that of the current
+ // module, if any.
if (!ModuleScopes.empty())
Context.addModuleInitializer(ModuleScopes.back().Module, Import);
- CurContext->addDecl(Import);
// Re-export the module if needed.
- if (Import->isExported() &&
- !ModuleScopes.empty() && ModuleScopes.back().ModuleInterface)
- getCurrentModule()->Exports.emplace_back(Mod, false);
+ if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) {
+ if (ExportLoc.isValid() || Import->isExported())
+ getCurrentModule()->Exports.emplace_back(Mod, false);
+ } else if (ExportLoc.isValid()) {
+ Diag(ExportLoc, diag::err_export_not_in_module_interface);
+ }
return Import;
}
OpenPOWER on IntegriCloud