aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>2023-03-03 10:31:48 +0800
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>2023-03-03 10:31:48 +0800
commitbf52ead24ca4fe1b73bceec7bba3abfe15541649 (patch)
tree356336638558c02b5ad2f31be9060cd1642c2985 /clang/lib/Sema
parent87cf39aa349b83ae3b7d16c30ac7a8ffa0ad098c (diff)
downloadllvm-bf52ead24ca4fe1b73bceec7bba3abfe15541649.zip
llvm-bf52ead24ca4fe1b73bceec7bba3abfe15541649.tar.gz
llvm-bf52ead24ca4fe1b73bceec7bba3abfe15541649.tar.bz2
[C++20] [Modules] Support to export declarations in language linkage
Close https://github.com/llvm/llvm-project/issues/60405 See the discussion in the above link for the background. What the patch does: - Rename `Module::ModuleKind::GlobalModuleFragment` to `Module::ModuleKind::ExplicitGlobalModuleFragment`. - Add another module kind `ImplicitGlobalModuleFragment` to `ModuleKind`. - Create an implicit global module fragment for the language linkage declarations inside a module purview. - If the language linkage lives inside the scope of an export decl, the created modules is marked as exported to outer modules. - In fact, Sema will only create at most 2 implicit global module fragments to avoid creating a lot of unnecessary modules in the edging case. Reviewed By: iains Differential Revision: https://reviews.llvm.org/D144367
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.cpp4
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp12
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp12
-rw-r--r--clang/lib/Sema/SemaLookup.cpp2
-rw-r--r--clang/lib/Sema/SemaModule.cpp50
5 files changed, 51 insertions, 29 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 90dd553..7257547 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1202,8 +1202,8 @@ void Sema::ActOnEndOfTranslationUnit() {
// A global-module-fragment is only permitted within a module unit.
bool DiagnosedMissingModuleDeclaration = false;
- if (!ModuleScopes.empty() &&
- ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) {
+ if (!ModuleScopes.empty() && ModuleScopes.back().Module->Kind ==
+ Module::ExplicitGlobalModuleFragment) {
Diag(ModuleScopes.back().BeginLoc,
diag::err_module_declaration_missing_after_global_module_introducer);
DiagnosedMissingModuleDeclaration = true;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index cf74fcb..ae8b8d6 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -16362,14 +16362,8 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
/// If the declaration is already in global module fragment, we don't
/// need to attach it again.
if (getLangOpts().CPlusPlusModules && isCurrentModulePurview()) {
- Module *GlobalModule =
- PushGlobalModuleFragment(ExternLoc);
- /// According to [module.reach]p3.2,
- /// The declaration in global module fragment is reachable if it is not
- /// discarded. And the discarded declaration should be deleted. So it
- /// doesn't matter mark the declaration in global module fragment as
- /// reachable here.
- D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported);
+ Module *GlobalModule = PushImplicitGlobalModuleFragment(
+ ExternLoc, /*IsExported=*/D->isInExportDeclContext());
D->setLocalOwningModule(GlobalModule);
}
@@ -16395,7 +16389,7 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S,
// need to pop it.
if (getLangOpts().CPlusPlusModules && getCurrentModule() &&
getCurrentModule()->isGlobalModule() && getCurrentModule()->Parent)
- PopGlobalModuleFragment();
+ PopImplicitGlobalModuleFragment();
PopDeclContext();
return LinkageSpec;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b0cf221..e7f3852 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3023,10 +3023,10 @@ void Sema::DeclareGlobalNewDelete() {
// The implicitly declared "std::bad_alloc" should live in global module
// fragment.
- if (GlobalModuleFragment) {
+ if (TheGlobalModuleFragment) {
getStdBadAlloc()->setModuleOwnershipKind(
Decl::ModuleOwnershipKind::ReachableWhenImported);
- getStdBadAlloc()->setLocalOwningModule(GlobalModuleFragment);
+ getStdBadAlloc()->setLocalOwningModule(TheGlobalModuleFragment);
}
}
if (!StdAlignValT && getLangOpts().AlignedAllocation) {
@@ -3038,10 +3038,10 @@ void Sema::DeclareGlobalNewDelete() {
// The implicitly declared "std::align_val_t" should live in global module
// fragment.
- if (GlobalModuleFragment) {
+ if (TheGlobalModuleFragment) {
AlignValT->setModuleOwnershipKind(
Decl::ModuleOwnershipKind::ReachableWhenImported);
- AlignValT->setLocalOwningModule(GlobalModuleFragment);
+ AlignValT->setLocalOwningModule(TheGlobalModuleFragment);
}
AlignValT->setIntegerType(Context.getSizeType());
@@ -3170,10 +3170,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// module all the time. But in the implementation, the global module
// is only meaningful when we're in a module unit. So here we attach
// these allocation functions to global module conditionally.
- if (GlobalModuleFragment) {
+ if (TheGlobalModuleFragment) {
Alloc->setModuleOwnershipKind(
Decl::ModuleOwnershipKind::ReachableWhenImported);
- Alloc->setLocalOwningModule(GlobalModuleFragment);
+ Alloc->setLocalOwningModule(TheGlobalModuleFragment);
}
Alloc->addAttr(VisibilityAttr::CreateImplicit(
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 5a5428c..aeeb490 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1579,7 +1579,7 @@ bool Sema::isUsableModule(const Module *M) {
// [module.global.frag]p1:
// The global module fragment can be used to provide declarations that are
// attached to the global module and usable within the module unit.
- if (M == GlobalModuleFragment ||
+ if (M == TheGlobalModuleFragment ||
// If M is the module we're parsing, it should be usable. This covers the
// private module fragment. The private module fragment is usable only if
// it is within the current module unit. And it must be the current
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 59891ec..8c120d2 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -233,7 +233,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
}
assert((!getLangOpts().CPlusPlusModules ||
- SeenGMF == (bool)this->GlobalModuleFragment) &&
+ SeenGMF == (bool)this->TheGlobalModuleFragment) &&
"mismatched global module state");
// In C++20, the module-declaration must be the first declaration if there
@@ -358,7 +358,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
break;
}
- if (!this->GlobalModuleFragment) {
+ if (!this->TheGlobalModuleFragment) {
ModuleScopes.push_back({});
if (getLangOpts().ModulesLocalVisibility)
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
@@ -408,10 +408,11 @@ Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc,
// C++20 [basic.link]/2:
// A private-module-fragment shall appear only in a primary module
// interface unit.
- switch (ModuleScopes.empty() ? Module::GlobalModuleFragment
+ switch (ModuleScopes.empty() ? Module::ExplicitGlobalModuleFragment
: ModuleScopes.back().Module->Kind) {
case Module::ModuleMapModule:
- case Module::GlobalModuleFragment:
+ case Module::ExplicitGlobalModuleFragment:
+ case Module::ImplicitGlobalModuleFragment:
case Module::ModulePartitionImplementation:
case Module::ModulePartitionInterface:
case Module::ModuleHeaderUnit:
@@ -958,25 +959,52 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc) {
// We shouldn't create new global module fragment if there is already
// one.
- if (!GlobalModuleFragment) {
+ if (!TheGlobalModuleFragment) {
ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
- GlobalModuleFragment = Map.createGlobalModuleFragmentForModuleUnit(
+ TheGlobalModuleFragment = Map.createGlobalModuleFragmentForModuleUnit(
BeginLoc, getCurrentModule());
}
- assert(GlobalModuleFragment && "module creation should not fail");
+ assert(TheGlobalModuleFragment && "module creation should not fail");
// Enter the scope of the global module.
- ModuleScopes.push_back({BeginLoc, GlobalModuleFragment,
+ ModuleScopes.push_back({BeginLoc, TheGlobalModuleFragment,
/*ModuleInterface=*/false,
/*OuterVisibleModules=*/{}});
- VisibleModules.setVisible(GlobalModuleFragment, BeginLoc);
+ VisibleModules.setVisible(TheGlobalModuleFragment, BeginLoc);
- return GlobalModuleFragment;
+ return TheGlobalModuleFragment;
}
void Sema::PopGlobalModuleFragment() {
- assert(!ModuleScopes.empty() && getCurrentModule()->isGlobalModule() &&
+ assert(!ModuleScopes.empty() &&
+ getCurrentModule()->isExplicitGlobalModule() &&
+ "left the wrong module scope, which is not global module fragment");
+ ModuleScopes.pop_back();
+}
+
+Module *Sema::PushImplicitGlobalModuleFragment(SourceLocation BeginLoc,
+ bool IsExported) {
+ Module **M = IsExported ? &TheExportedImplicitGlobalModuleFragment
+ : &TheImplicitGlobalModuleFragment;
+ if (!*M) {
+ ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
+ *M = Map.createImplicitGlobalModuleFragmentForModuleUnit(
+ BeginLoc, IsExported, getCurrentModule());
+ }
+ assert(*M && "module creation should not fail");
+
+ // Enter the scope of the global module.
+ ModuleScopes.push_back({BeginLoc, *M,
+ /*ModuleInterface=*/false,
+ /*OuterVisibleModules=*/{}});
+ VisibleModules.setVisible(*M, BeginLoc);
+ return *M;
+}
+
+void Sema::PopImplicitGlobalModuleFragment() {
+ assert(!ModuleScopes.empty() &&
+ getCurrentModule()->isImplicitGlobalModule() &&
"left the wrong module scope, which is not global module fragment");
ModuleScopes.pop_back();
}