Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -1540,6 +1540,11 @@ } Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const { + if (isa(this)) + // Namespaces never have module linkage. It is the entities within them + // that [may] do. + return nullptr; + Module *M = getOwningModule(); if (!M) return nullptr; Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -508,7 +508,7 @@ void mangleNameWithAbiTags(GlobalDecl GD, const AbiTagList *AdditionalAbiTags); - void mangleModuleName(const Module *M); + void mangleModuleName(const NamedDecl *ND); void mangleModuleNamePrefix(StringRef Name); void mangleTemplateName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, @@ -704,7 +704,8 @@ if (VD->isExternC()) return false; - // Variables at global scope with non-internal linkage are not mangled. + // Non-module variables at global scope with non-internal linkage are not + // mangled const DeclContext *DC = getEffectiveDeclContext(D); // Check for extern variable declared locally. if (DC->isFunctionOrMethod() && D->hasLinkage()) @@ -712,7 +713,8 @@ DC = getEffectiveParentContext(DC); if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage && !CXXNameMangler::shouldHaveAbiTags(*this, VD) && - !isa(VD)) + !isa(VD) && + !VD->getOwningModuleForLinkage()) return false; } @@ -985,14 +987,6 @@ return; } - // Do not mangle the owning module for an external linkage declaration. - // This enables backwards-compatibility with non-modular code, and is - // a valid choice since conflicts are not permitted by C++ Modules TS - // [basic.def.odr]/6.2. - if (!ND->hasExternalFormalLinkage()) - if (Module *M = ND->getOwningModuleForLinkage()) - mangleModuleName(M); - // Closures can require a nested-name mangling even if they're semantically // in the global namespace. if (const NamedDecl *PrefixND = getClosurePrefix(ND)) { @@ -1016,26 +1010,26 @@ mangleNestedName(GD, DC, AdditionalAbiTags); } -void CXXNameMangler::mangleModuleName(const Module *M) { - // Implement the C++ Modules TS name mangling proposal; see - // https://gcc.gnu.org/wiki/cxx-modules?action=AttachFile - // - // ::= W + E - // ::= W * E - Out << 'W'; - mangleModuleNamePrefix(M->Name); - Out << 'E'; +void CXXNameMangler::mangleModuleName(const NamedDecl *ND) { + // The updated module-ts proposal. + // See https://github.com/itanium-cxx-abi/cxx-abi/issues/134 + if (ND->isExternallyVisible()) + if (Module *M = ND->getOwningModuleForLinkage()) + mangleModuleNamePrefix(M->Name); } +// ::= +// ::= +// ::= +// ::= W +// ::= W P +// FIXME: deal with partitions void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) { - // ::= _ # 0 < seq-id < 10 - // ::= W _ # otherwise + // ::= S _ auto It = ModuleSubstitutions.find(Name); if (It != ModuleSubstitutions.end()) { - if (It->second < 10) - Out << '_' << static_cast('0' + It->second); - else - Out << 'W' << (It->second - 10) << '_'; + Out << 'S'; + mangleSeqID(It->second); return; } @@ -1047,8 +1041,8 @@ else mangleModuleNamePrefix(Parts.first); - Out << Parts.second.size() << Parts.second; - ModuleSubstitutions.insert({Name, ModuleSubstitutions.size()}); + Out << 'W' << Parts.second.size() << Parts.second; + ModuleSubstitutions.insert({Name, SeqID++}); } void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD, @@ -1073,6 +1067,7 @@ if (isStdNamespace(IgnoreLinkageSpecDecls(getEffectiveDeclContext(ND)))) Out << "St"; + mangleModuleName(ND); mangleUnqualifiedName(GD, AdditionalAbiTags); } @@ -1685,6 +1680,8 @@ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); } else { manglePrefix(DC, NoFunction); + if (DC->isFileContext()) + mangleModuleName(ND); mangleUnqualifiedName(GD, AdditionalAbiTags); } @@ -2053,7 +2050,10 @@ mangleClosurePrefix(PrefixND, NoFunction); mangleUnqualifiedName(ND, nullptr); } else { - manglePrefix(getEffectiveDeclContext(ND), NoFunction); + const DeclContext *DC = getEffectiveDeclContext(ND); + manglePrefix(DC, NoFunction); + if (DC->isFileContext()) + mangleModuleName(ND); mangleUnqualifiedName(ND, nullptr); } @@ -2107,7 +2107,10 @@ if (const auto *TTP = dyn_cast(ND)) { mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); } else { - manglePrefix(getEffectiveDeclContext(ND), NoFunction); + const DeclContext *DC = getEffectiveDeclContext(ND); + manglePrefix(DC, NoFunction); + if (DC->isFileContext()) + mangleModuleName(ND); if (isa(ND) || isa(ND)) mangleUnqualifiedName(GD, nullptr); else @@ -6037,6 +6040,9 @@ if (!isStdNamespace(getEffectiveDeclContext(TD))) return false; + if (TD->getOwningModuleForLinkage()) + return false; + // ::= Sa # ::std::allocator if (TD->getIdentifier()->isStr("allocator")) { Out << "Sa"; Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp =================================================================== --- clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp +++ clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp @@ -1,21 +1,21 @@ // RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module -// CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global -// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3, +// CHECK-DAG: @_ZW6Module19extern_var_exported = external {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module19inline_var_exported = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module18const_var_exported = available_externally {{(dso_local )?}}constant i32 3, // -// CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = available_externally {{(dso_local )?}}global i32 0, -// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = available_externally {{(dso_local )?}}constant i32 3, +// CHECK-DAG: @_ZW6Module25extern_var_module_linkage = external {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module25static_var_module_linkage = available_externally {{(dso_local )?}}global i32 0, +// CHECK-DAG: @_ZW6Module24const_var_module_linkage = available_externally {{(dso_local )?}}constant i32 3, module Module; void use() { - // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv + // CHECK: define linkonce_odr {{.*}}@_ZW6Module20used_inline_exportedv used_inline_exported(); - // CHECK: declare {{.*}}@_Z18noninline_exportedv + // CHECK: declare {{.*}}@_ZW6Module18noninline_exportedv noninline_exported(); (void)&extern_var_exported; @@ -23,13 +23,13 @@ (void)&const_var_exported; // FIXME: This symbol should not be visible here. - // CHECK: declare {{.*}}@_ZW6ModuleE26used_static_module_linkagev + // CHECK: declare {{.*}}@_ZW6Module26used_static_module_linkagev used_static_module_linkage(); - // CHECK: define linkonce_odr {{.*}}@_ZW6ModuleE26used_inline_module_linkagev + // CHECK: define linkonce_odr {{.*}}@_ZW6Module26used_inline_module_linkagev used_inline_module_linkage(); - // CHECK: declare {{.*}}@_ZW6ModuleE24noninline_module_linkagev + // CHECK: declare {{.*}}@_ZW6Module24noninline_module_linkagev noninline_module_linkage(); (void)&extern_var_module_linkage; Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm =================================================================== --- clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm +++ clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm @@ -6,24 +6,24 @@ // CHECK-DAG: @_ZL23const_var_global_module = internal constant // // For ABI compatibility, these symbols do not include the module name. -// CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module19extern_var_exported = external {{(dso_local )?}}global // FIXME: Should this be 'weak_odr global'? Presumably it must be, since we // can discard this global and its initializer (if any), and other TUs are not // permitted to run the initializer for this variable. -// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @const_var_exported = {{(dso_local )?}}constant +// CHECK-DAG: @_ZW6Module19inline_var_exported = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module18const_var_exported = {{(dso_local )?}}constant // -// CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module25extern_var_module_linkage = external {{(dso_local )?}}global // FIXME: Should this be 'weak_odr global'? Presumably it must be, since we // can discard this global and its initializer (if any), and other TUs are not // permitted to run the initializer for this variable. -// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = {{(dso_local )?}}global -// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = {{(dso_local )?}}constant +// CHECK-DAG: @_ZW6Module25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module25static_var_module_linkage = {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module24const_var_module_linkage = {{(dso_local )?}}constant // -// CHECK-DAG: @_ZW6ModuleE25unused_var_module_linkage = {{(dso_local )?}}global i32 4 -// CHECK-DAG: @_ZW6ModuleE32unused_static_var_module_linkage = {{(dso_local )?}}global i32 5 -// CHECK-DAG: @_ZW6ModuleE31unused_const_var_module_linkage = {{(dso_local )?}}constant i32 7 +// CHECK-DAG: @_ZW6Module25unused_var_module_linkage = {{(dso_local )?}}global i32 4 +// CHECK-DAG: @_ZW6Module32unused_static_var_module_linkage = {{(dso_local )?}}global i32 5 +// CHECK-DAG: @_ZW6Module31unused_const_var_module_linkage = {{(dso_local )?}}constant i32 7 static void unused_static_global_module() {} static void used_static_global_module() {} @@ -64,7 +64,7 @@ inline int inline_var_exported; const int const_var_exported = 3; - // CHECK: define {{(dso_local )?}}void {{.*}}@_Z18noninline_exportedv + // CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6Module18noninline_exportedv void noninline_exported() { (void)&extern_var_exported; (void)&inline_var_exported; @@ -75,9 +75,9 @@ // FIXME: Ideally we wouldn't emit this as its name is not visible outside this // TU, but this module interface might contain a template that can use this // function so we conservatively emit it for now. -// CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6ModuleE28unused_static_module_linkagev +// CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6Module28unused_static_module_linkagev static void unused_static_module_linkage() {} -// CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6ModuleE26used_static_module_linkagev +// CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6Module26used_static_module_linkagev static void used_static_module_linkage() {} inline void unused_inline_module_linkage() {} @@ -88,10 +88,10 @@ static int static_var_module_linkage; const int const_var_module_linkage = 3; -// CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6ModuleE24noninline_module_linkagev +// CHECK: define {{(dso_local )?}}void {{.*}}@_ZW6Module24noninline_module_linkagev void noninline_module_linkage() { used_static_module_linkage(); - // CHECK: define linkonce_odr {{.*}}@_ZW6ModuleE26used_inline_module_linkagev + // CHECK: define linkonce_odr {{.*}}@_ZW6Module26used_inline_module_linkagev used_inline_module_linkage(); (void)&extern_var_module_linkage; @@ -109,5 +109,5 @@ struct b {}; struct c {}; }; -// CHECK: define {{(dso_local )?}}void @_ZW6ModuleE1fW_0EN1a1bEW_0ENS_1cE( +// CHECK: define {{(dso_local )?}}void @_ZW6Module1fNS_1a1bENS0_1cE( void f(a::b, a::c) {} Index: clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp =================================================================== --- clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp +++ clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp @@ -1,16 +1,16 @@ // RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t // RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module -// CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global -// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global -// CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3 +// CHECK-DAG: @_ZW6Module19extern_var_exported = external {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module19inline_var_exported = linkonce_odr {{(dso_local )?}}global +// CHECK-DAG: @_ZW6Module18const_var_exported = available_externally {{(dso_local )?}}constant i32 3 import Module; void use() { - // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv + // CHECK: define linkonce_odr {{.*}}@_ZW6Module20used_inline_exportedv used_inline_exported(); - // CHECK: declare {{.*}}@_Z18noninline_exportedv + // CHECK: declare {{.*}}@_ZW6Module18noninline_exportedv noninline_exported(); (void)&extern_var_exported; Index: clang/test/CXX/modules-ts/basic/basic.link/p3.cppm =================================================================== --- clang/test/CXX/modules-ts/basic/basic.link/p3.cppm +++ clang/test/CXX/modules-ts/basic/basic.link/p3.cppm @@ -3,9 +3,9 @@ export module M; -// CHECK-DAG: @_ZW1ME1a ={{.*}} constant i32 1 +// CHECK-DAG: @_ZW1M1a ={{.*}} constant i32 1 const int a = 1; -// CHECK-DAG: @b ={{.*}} constant i32 2 +// CHECK-DAG: @_ZW1M1b ={{.*}} constant i32 2 export const int b = 2; export int f() { return a + b; } Index: clang/test/CXX/modules-ts/codegen-basics.cppm =================================================================== --- clang/test/CXX/modules-ts/codegen-basics.cppm +++ clang/test/CXX/modules-ts/codegen-basics.cppm @@ -4,14 +4,14 @@ export module FooBar; export { - // CHECK-DAG: define{{.*}} i32 @_Z1fv( + // CHECK-DAG: define{{.*}} i32 @_ZW6FooBar1fv( int f() { return 0; } } -// CHECK-DAG: define weak_odr void @_ZW6FooBarE2f2v( +// CHECK-DAG: define weak_odr void @_ZW6FooBar2f2v( inline void f2() {} -// CHECK-DAG: define{{.*}} void @_ZW6FooBarE2f3v( +// CHECK-DAG: define{{.*}} void @_ZW6FooBar2f3v( static void f3() {} export void use_f3() { f3(); } Index: clang/test/CodeGenCXX/cxx20-module-extern-1.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx20-module-extern-1.cppm @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s + +// module-purview extern "C++" semantics not implemented +// XFAIL: * + +export module FOO; +extern "C++" export class A; +export class B; + +// CHECK-DAG: void @_ZW3FOO3FooP1APNS_1B( +export void Foo (A *, B*) { +} + +extern "C++" { +// CHECK-DAG: void @_Z3BarP1APW3FOO1B( +export void Bar (A *, B*) { +} +} Index: clang/test/CodeGenCXX/cxx20-module-nested-1.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx20-module-nested-1.cppm @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++20 -fmodules-ts %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s +module; +# 4 __FILE__ 1 +namespace Outer::Inner { +class X; +// CHECK-DAG: define dso_local void @_ZN5Outer5Inner3BarERNS0_1XE( +void Bar (X &) {} +} // namespace Outer::Inner +# 10 "" 2 +export module FOO; +namespace Outer { +class Y; +namespace Inner { +// CHECK-DAG: define dso_local void @_ZN5Outer5InnerW3FOO2FnERNS0_1XERNS_S1_1YE( +void Fn (X &, Y &){} // #1 +} // namespace Inner +} // namespace Outer Index: clang/test/CodeGenCXX/cxx20-module-nested-2.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx20-module-nested-2.cppm @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s +export module FOO; +namespace Outer { +class Y; +class Inner { + class X; + void Fn (X &, Y &); // #2 +}; +// CHECK-DAG: define dso_local void @_ZN5OuterW3FOO5Inner2FnERNS1_1XERNS_S0_1YE( +void Inner::Fn (X &, Y &) {} +} + Index: clang/test/CodeGenCXX/cxx20-module-std-subst-1.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx20-module-std-subst-1.cppm @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s + +module; +# 5 __FILE__ 1 +class Pooh; +class Piglet; +# 8 "" 2 + +export module std; // might happen, you can't say it won't! + +namespace std { +export template class allocator { +// just for testing, not real! +void M (T *); +template U *N (T *); +}; + +template void allocator::M (T *) {} +template template U *allocator::N (T *) { +return nullptr; +} + +// CHECK-DAG: void @_ZNStW3std9allocatorIiE1MEPi( +template void allocator::M (int *); +// CHECK-DAG: @_ZNStW3std9allocatorIiE1NIfEEPT_Pi( +template float *allocator::N (int *); +} + +// CHECK-DAG: @_ZNStW3std9allocatorI4PoohE1MEPS1_( +template void std::allocator::M (Pooh *); +// CHECK-DAG: @_ZNStW3std9allocatorI4PoohE1NI6PigletEEPT_PS1_( +template Piglet *std::allocator::N (Pooh *); Index: clang/test/CodeGenCXX/cxx20-module-sub-1.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx20-module-sub-1.cppm @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s + +export module FOO.BAR; +export class A; +namespace Bob { +export class B; + +// CHECK-DAG: void @_ZN3BobW3FOOW3BAR3BarEPS1_1APNS_S1_1BE( +export void Bar (A *, B*) { +} +} + +// CHECK-DAG: void @_ZW3FOOW3BAR3FooPS0_1APN3BobS0_1BE( +export void Foo (A *, Bob::B*) { +} Index: clang/test/CodeGenCXX/cxx20-module-sub-2.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx20-module-sub-2.cppm @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++20 %S/cxx20-module-sub-1.cppm -triple %itanium_abi_triple -emit-module-interface -o %t +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s + +export module FOO.BAZ; +import FOO.BAR; + +namespace Bob { + +// CHECK-DAG: void @_ZN3BobW3FOOW3BAZ3FooEPS0_W3BAR1APNS_S2_1BE( +void Foo (A *, B*) { +} +} + +// CHECK-DAG: void @_ZW3FOOW3BAZ3BarPS_W3BAR1APN3BobS1_1BE( +void Bar (A *, Bob::B*) { +} Index: clang/test/CodeGenCXX/cxx20-module-tmpl-1.cppm =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx20-module-tmpl-1.cppm @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s + +export module FOO; + +class One; +class Two; + +export template struct TPL +{ +void M (T *); +template void N (T *, U*); +}; + +template +void TPL::M (T *) {} + +template template void TPL::N (T *, U*) {} + +// CHECK-DAG: void @_ZNW3FOO3TPLIS_3OneE1MEPS1_( +template void TPL::M (One *); +// CHECK-DAG: void @_ZNW3FOO3TPLIS_3OneE1NIS_3TwoEEvPS1_PT_( +template void TPL::N (One *, Two *); + +namespace NMS { +class One; +class Two; + +export template struct TPL +{ +void M (T *); +template void N (T *, U*); +}; + +template +void TPL::M (T *) {} + +template template void TPL::N (T *, U*) {} + +// CHECK-DAG: void @_ZN3NMSW3FOO3TPLINS_S0_3OneEE1MEPS2_( +template void TPL::M (One *); +// CHECK-DAG: void @_ZN3NMSW3FOO3TPLINS_S0_3OneEE1NINS_S0_3TwoEEEvPS2_PT_ +template void TPL::N (One *, Two *); +}