Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10837,6 +10837,10 @@ "redefinition of module '%0'">; def note_prev_module_definition : Note<"previously defined here">; def note_prev_module_definition_from_ast_file : Note<"module loaded from '%0'">; +def err_module_langugae_linkage_no_global : Error < + "The declaration %0 appears within a linkage-specification should be " + "attached to global module. But the compiler failed to search the global " + "module.">; def err_module_not_defined : Error< "definition of module '%0' is not available; use -fmodule-file= to specify " "path to precompiled module interface">; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2174,6 +2174,7 @@ }; /// The modules we're currently parsing. llvm::SmallVector ModuleScopes; + Module *GlobalModule = nullptr; /// Namespace definitions that we will export when they finish. llvm::SmallPtrSet DeferredExportedNamespaces; @@ -2183,6 +2184,8 @@ return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; } + Module *getGlobalModule() const { return GlobalModule; } + VisibleModuleSet VisibleModules; public: Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -9337,6 +9337,23 @@ } } + // C++ [module.unit]p7.2 + // Otherwise, if the declaration + // - ... + // - ... + // - appears within a linkage-specification + // it is attached to the global module. + if (Module *M = NewFD->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit && + (NewFD->isExternCContext() || NewFD->isExternCXXContext())) { + if (!GlobalModule) + Diag(NewFD->getLocation(), + diag::err_module_langugae_linkage_no_global) + << NewFD->getName(); + NewFD->setLocalOwningModule(GlobalModule); + NewFD->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Unowned); + } + if (isFriend) { if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl(); @@ -16405,6 +16422,22 @@ New->setModulePrivate(); } + // C++ [module.unit]p7.2 + // Otherwise, if the declaration + // - ... + // - ... + // - appears within a linkage-specification + // it is attached to the global module. + if (Module *M = New->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit && + (New->isExternCContext() || New->isExternCXXContext())) { + if (!GlobalModule) + Diag(New->getLocation(), diag::err_module_langugae_linkage_no_global) + << New->getName(); + New->setLocalOwningModule(GlobalModule); + New->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Unowned); + } + // If this is a specialization of a member class (of a class template), // check the specialization. if (isMemberSpecialization && CheckMemberSpecialization(New, Previous)) Index: clang/lib/Sema/SemaModule.cpp =================================================================== --- clang/lib/Sema/SemaModule.cpp +++ clang/lib/Sema/SemaModule.cpp @@ -66,10 +66,13 @@ return nullptr; } + assert( + !GlobalModule && + "Global module already created but didn't covered by the check above."); // 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); + GlobalModule = Map.createGlobalModuleFragmentForModuleUnit(ModuleLoc); assert(GlobalModule && "module creation should not fail"); // Enter the scope of the global module. 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 @@ +extern "C" void foo(); \ No newline at end of file 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; \ No newline at end of file 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; \ No newline at end of file Index: clang/test/CXX/module/module.linkage_specification/p1.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.linkage_specification/p1.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++2a %s -verify +// expected-no-diagnostics +module; + +#include "Inputs/h1.h" + +export module x; + +extern "C" void foo() { + return; +} 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++2a %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,5 @@ +// RUN: %clang_cc1 -std=c++2a %s -verify +export module x; + +extern "C" void foo(); // expected-error {{The declaration foo appears within a linkage-specification should be attached to global module. But the compiler failed to search the global module.}} +extern "C++" class CPP {}; // expected-error {{The declaration CPP appears within a linkage-specification should be attached to global module. But the compiler failed to search the global module.}} 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++2a %s -verify +// expected-no-diagnostics +module; + +#include "Inputs/h4.h" + +export module x; + +extern "C" struct C { + int a; + int b; + double d; +}; \ No newline at end of file