Index: clang/include/clang/Basic/Module.h =================================================================== --- clang/include/clang/Basic/Module.h +++ clang/include/clang/Basic/Module.h @@ -153,6 +153,10 @@ 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 SubModules; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2204,6 +2204,11 @@ 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: Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -16144,6 +16144,20 @@ 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::Visible); + D->setLocalOwningModule(GlobalModule); + } + CurContext->addDecl(D); PushDeclContext(S, D); return D; @@ -16160,6 +16174,10 @@ LinkageSpecDecl* LSDecl = cast(LinkageSpec); LSDecl->setRBraceLoc(RBraceLoc); } + + if (getLangOpts().CPlusPlusModules) + PopGlobalModuleFragment(); + PopDeclContext(); return LinkageSpec; } Index: clang/lib/Sema/SemaModule.cpp =================================================================== --- clang/lib/Sema/SemaModule.cpp +++ clang/lib/Sema/SemaModule.cpp @@ -68,15 +68,8 @@ // 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(); @@ -708,3 +701,24 @@ return D; } + +Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc, + bool IsImplicit) { + ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap(); + Module *GlobalModule = Map.createGlobalModuleFragmentForModuleUnit(BeginLoc); + 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(); +} Index: clang/test/CXX/module/module.linkage_specification/Inputs/h1.h =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/Inputs/h1.h @@ -0,0 +1,12 @@ +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(); +} Index: clang/test/CXX/module/module.linkage_specification/Inputs/h2.h =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/Inputs/h2.h @@ -0,0 +1 @@ +extern "C++" class CPP; Index: clang/test/CXX/module/module.linkage_specification/Inputs/h4.h =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/Inputs/h4.h @@ -0,0 +1 @@ +extern "C" struct C; Index: clang/test/CXX/module/module.linkage_specification/Inputs/h5.h =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/Inputs/h5.h @@ -0,0 +1 @@ +extern "C++" int a; Index: clang/test/CXX/module/module.linkage_specification/p1.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/p1.cpp @@ -0,0 +1,35 @@ +// 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; +} +} Index: clang/test/CXX/module/module.linkage_specification/p2.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/p2.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++20 %s -verify +// expected-no-diagnostics +module; + +#include "Inputs/h2.h" + +export module x; + +extern "C++" class CPP {}; Index: clang/test/CXX/module/module.linkage_specification/p3.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/p3.cpp @@ -0,0 +1,7 @@ +// 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 {}; Index: clang/test/CXX/module/module.linkage_specification/p4.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/p4.cpp @@ -0,0 +1,13 @@ +// 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; +}; Index: clang/test/CXX/module/module.linkage_specification/p5.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/p5.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++20 %s -verify +// expected-no-diagnostics +module; + +#include "Inputs/h4.h" + +export module x; + +extern "C++" int a = 5; Index: clang/test/CodeGenCXX/Inputs/module-extern-C.h =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/Inputs/module-extern-C.h @@ -0,0 +1,7 @@ +extern "C" void foo(); +extern "C" { +void bar(); +int baz(); +double double_func(); +} +extern "C++" class CPP; Index: clang/test/CodeGenCXX/module-extern-C.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/module-extern-C.cpp @@ -0,0 +1,27 @@ +// 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; +} +}