return Kind == ModuleInterfaceUnit || Kind == PrivateModuleFragment;
}
+ /// Does this Module scope describe a fragment of the global module within
+ /// some C++ module.
+ bool isGlobalModule() const { return Kind == GlobalModuleFragment; }
+
private:
/// The submodules of this module, indexed by name.
std::vector<Module *> SubModules;
///
/// We model the global module fragment as a submodule of the module
/// interface unit. Unfortunately, we can't create the module interface
- /// unit's Module until later, because we don't know what it will be called.
- Module *createGlobalModuleFragmentForModuleUnit(SourceLocation Loc);
+ /// unit's Module until later, because we don't know what it will be called
+ /// usually. See C++20 [module.unit]/7.2 for the case we could know its
+ /// parent.
+ Module *createGlobalModuleFragmentForModuleUnit(SourceLocation Loc,
+ Module *Parent = nullptr);
/// Create a global module fragment for a C++ module interface unit.
Module *createPrivateModuleFragmentForInterfaceUnit(Module *Parent,
return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module;
}
+ /// Enter the scope of the global module.
+ Module *PushGlobalModuleFragment(SourceLocation BeginLoc, bool IsImplicit);
+ /// Leave the scope of the global module.
+ void PopGlobalModuleFragment();
+
VisibleModuleSet VisibleModules;
public:
return std::make_pair(Result, true);
}
-Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc) {
- PendingSubmodules.emplace_back(
- new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
- /*IsExplicit*/ true, NumCreatedModules++));
- PendingSubmodules.back()->Kind = Module::GlobalModuleFragment;
- return PendingSubmodules.back().get();
+Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc,
+ Module *Parent) {
+ auto *Result = new Module("<global>", Loc, Parent, /*IsFramework*/ false,
+ /*IsExplicit*/ true, NumCreatedModules++);
+ Result->Kind = Module::GlobalModuleFragment;
+ // If the created module isn't owned by a parent, send it to PendingSubmodules
+ // to wait for its parent.
+ if (!Result->Parent)
+ PendingSubmodules.emplace_back(Result);
+ return Result;
}
Module *
LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, ExternLoc,
LangStr->getExprLoc(), Language,
LBraceLoc.isValid());
+
+ /// C++ [module.unit]p7.2.3
+ /// - Otherwise, if the declaration
+ /// - ...
+ /// - ...
+ /// - appears within a linkage-specification,
+ /// it is attached to the global module.
+ if (getLangOpts().CPlusPlusModules) {
+ Module *GlobalModule =
+ PushGlobalModuleFragment(ExternLoc, /*IsImplicit=*/true);
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+ D->setLocalOwningModule(GlobalModule);
+ }
+
CurContext->addDecl(D);
PushDeclContext(S, D);
return D;
LinkageSpecDecl* LSDecl = cast<LinkageSpecDecl>(LinkageSpec);
LSDecl->setRBraceLoc(RBraceLoc);
}
+
+ if (getLangOpts().CPlusPlusModules)
+ PopGlobalModuleFragment();
+
PopDeclContext();
return LinkageSpec;
}
// 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.createGlobalModuleFragmentForModuleUnit(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);
+ Module *GlobalModule =
+ PushGlobalModuleFragment(ModuleLoc, /*IsImplicit=*/false);
// All declarations created from now on are owned by the global module.
auto *TU = Context.getTranslationUnitDecl();
return D;
}
+
+Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc,
+ bool IsImplicit) {
+ ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
+ Module *GlobalModule =
+ Map.createGlobalModuleFragmentForModuleUnit(BeginLoc, getCurrentModule());
+ assert(GlobalModule && "module creation should not fail");
+
+ // Enter the scope of the global module.
+ ModuleScopes.push_back({BeginLoc, GlobalModule,
+ /*ModuleInterface=*/false,
+ /*ImplicitGlobalModuleFragment=*/IsImplicit});
+ VisibleModules.setVisible(GlobalModule, BeginLoc);
+
+ return GlobalModule;
+}
+
+void Sema::PopGlobalModuleFragment() {
+ assert(!ModuleScopes.empty() && getCurrentModule()->isGlobalModule() &&
+ "left the wrong module scope, which is not global module fragment");
+ ModuleScopes.pop_back();
+}
--- /dev/null
+module;
+#include "h2.h"
+export module X;
+
+extern "C++" class CPP {
+public:
+ void print() {}
+};
--- /dev/null
+extern "C" void foo();
+extern "C" {
+void bar();
+int baz();
+double double_func();
+}
+
+extern "C++" {
+void bar_cpp();
+int baz_cpp();
+double double_func_cpp();
+}
--- /dev/null
+extern "C++" class CPP;
--- /dev/null
+extern "C" struct C;
--- /dev/null
+extern "C++" int a;
--- /dev/null
+// RUN: %clang_cc1 -std=c++20 %s -verify
+// expected-no-diagnostics
+module;
+
+#include "Inputs/h1.h"
+
+export module x;
+
+extern "C" void foo() {
+ return;
+}
+
+extern "C" {
+void bar() {
+ return;
+}
+int baz() {
+ return 3;
+}
+double double_func() {
+ return 5.0;
+}
+}
+
+extern "C++" {
+void bar_cpp() {
+ return;
+}
+int baz_cpp() {
+ return 3;
+}
+double double_func_cpp() {
+ return 5.0;
+}
+}
--- /dev/null
+// RUN: %clang_cc1 -std=c++20 %s -verify
+// expected-no-diagnostics
+module;
+
+#include "Inputs/h2.h"
+
+export module x;
+
+extern "C++" class CPP {};
--- /dev/null
+// This tests whether the global module would be created when the program don't declare it explicitly.
+// RUN: %clang_cc1 -std=c++20 %s -verify
+// expected-no-diagnostics
+export module x;
+
+extern "C" void foo();
+extern "C++" class CPP {};
--- /dev/null
+// RUN: %clang_cc1 -std=c++20 %s -verify
+// expected-no-diagnostics
+module;
+
+#include "Inputs/h4.h"
+
+export module x;
+
+extern "C" struct C {
+ int a;
+ int b;
+ double d;
+};
--- /dev/null
+// RUN: %clang_cc1 -std=c++20 %s -verify
+// expected-no-diagnostics
+module;
+
+#include "Inputs/h4.h"
+
+export module x;
+
+extern "C++" int a = 5;
--- /dev/null
+// RUN: rm -fr %t
+// RUN: mkdir %t
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %S/Inputs/CPP.cppm -I%S/Inputs -o %t/X.pcm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %s -verify
+module;
+#include "Inputs/h2.h"
+export module use;
+import X;
+void printX(CPP *cpp) {
+ cpp->print(); // expected-error {{'CPP' must be defined before it is used}}
+ // expected-error@-1 {{'CPP' must be defined before it is used}}
+ // expected-error@-2 {{no member named 'print' in 'CPP'}}
+ // expected-note@Inputs/CPP.cppm:5 {{definition here is not reachable}}
+ // expected-note@Inputs/CPP.cppm:5 {{definition here is not reachable}}
+}
--- /dev/null
+extern "C" void foo();
+extern "C" {
+void bar();
+int baz();
+double double_func();
+}
+extern "C++" class CPP;
--- /dev/null
+// RUN: %clang_cc1 -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
+
+module;
+
+#include "Inputs/module-extern-C.h"
+
+export module x;
+
+// CHECK: define dso_local void @foo()
+extern "C" void foo() {
+ return;
+}
+
+extern "C" {
+// CHECK: define dso_local void @bar()
+void bar() {
+ return;
+}
+// CHECK: define dso_local i32 @baz()
+int baz() {
+ return 3;
+}
+// CHECK: define dso_local double @double_func()
+double double_func() {
+ return 5.0;
+}
+}