summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDecl.cpp
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/Sema/SemaDecl.cpp
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/Sema/SemaDecl.cpp')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp121
1 files changed, 101 insertions, 20 deletions
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