diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -194,6 +194,8 @@ virtual void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &) = 0; + virtual void mangleModuleInitializer(const Module *Module, raw_ostream &) = 0; + // This has to live here, otherwise the CXXNameMangler won't have access to // it. virtual DiscriminatorOverrideTy getDiscriminatorOverride() const = 0; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/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; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -130,6 +130,8 @@ void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) override; + void mangleModuleInitializer(const Module *Module, raw_ostream &) override; + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { // Lambda closure types are already numbered. if (isLambda(ND)) @@ -438,6 +440,7 @@ void mangleType(QualType T); void mangleNameOrStandardSubstitution(const NamedDecl *ND); void mangleLambdaSig(const CXXRecordDecl *Lambda); + void mangleModuleNamePrefix(StringRef Name, bool IsPartition = false); private: @@ -473,22 +476,21 @@ void mangleNameWithAbiTags(GlobalDecl GD, const AbiTagList *AdditionalAbiTags); - void mangleModuleName(const Module *M); - void mangleModuleNamePrefix(StringRef Name); + void mangleModuleName(const NamedDecl *ND); void mangleTemplateName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); - void mangleUnqualifiedName(GlobalDecl GD, + void mangleUnqualifiedName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags) { - mangleUnqualifiedName(GD, cast(GD.getDecl())->getDeclName(), UnknownArity, - AdditionalAbiTags); + mangleUnqualifiedName(GD, cast(GD.getDecl())->getDeclName(), DC, + UnknownArity, AdditionalAbiTags); } void mangleUnqualifiedName(GlobalDecl GD, DeclarationName Name, - unsigned KnownArity, + const DeclContext *DC, unsigned KnownArity, const AbiTagList *AdditionalAbiTags); - void mangleUnscopedName(GlobalDecl GD, + void mangleUnscopedName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags); - void mangleUnscopedTemplateName(GlobalDecl GD, + void mangleUnscopedTemplateName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags); void mangleSourceName(const IdentifierInfo *II); void mangleRegCallName(const IdentifierInfo *II); @@ -733,7 +735,8 @@ if (VD->isExternC()) return false; - // Variables at global scope with non-internal linkage are not mangled. + // Variables at global scope are not mangled unless they have internal + // linkage or are specializations or are attached to a named module. const DeclContext *DC = getEffectiveDeclContext(D); // Check for extern variable declared locally. if (DC->isFunctionOrMethod() && D->hasLinkage()) @@ -741,7 +744,8 @@ DC = getEffectiveParentContext(DC); if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage && !CXXNameMangler::shouldHaveAbiTags(*this, VD) && - !isa(VD)) + !isa(VD) && + !VD->getOwningModuleForLinkage()) return false; } @@ -1016,14 +1020,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)) { @@ -1035,38 +1031,35 @@ // Check if we have a template. const TemplateArgumentList *TemplateArgs = nullptr; if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) { - mangleUnscopedTemplateName(TD, AdditionalAbiTags); + mangleUnscopedTemplateName(TD, DC, AdditionalAbiTags); mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); return; } - mangleUnscopedName(GD, AdditionalAbiTags); + mangleUnscopedName(GD, DC, AdditionalAbiTags); return; } 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) { + if (ND->isExternallyVisible()) + if (Module *M = ND->getOwningModuleForLinkage()) + mangleModuleNamePrefix(M->getPrimaryModuleInterfaceName()); } -void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) { - // ::= _ # 0 < seq-id < 10 - // ::= W _ # otherwise +// ::= +// ::= +// ::= +// ::= W +// ::= W P +void CXXNameMangler::mangleModuleNamePrefix(StringRef Name, bool IsPartition) { + // ::= 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; } @@ -1075,11 +1068,16 @@ auto Parts = Name.rsplit('.'); if (Parts.second.empty()) Parts.second = Parts.first; - else - mangleModuleNamePrefix(Parts.first); + else { + mangleModuleNamePrefix(Parts.first, IsPartition); + IsPartition = false; + } + Out << 'W'; + if (IsPartition) + Out << 'P'; Out << Parts.second.size() << Parts.second; - ModuleSubstitutions.insert({Name, ModuleSubstitutions.size()}); + ModuleSubstitutions.insert({Name, SeqID++}); } void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD, @@ -1088,27 +1086,27 @@ const DeclContext *DC = Context.getEffectiveDeclContext(TD); if (DC->isTranslationUnit() || isStdNamespace(DC)) { - mangleUnscopedTemplateName(TD, nullptr); + mangleUnscopedTemplateName(TD, DC, nullptr); mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs); } else { mangleNestedName(TD, TemplateArgs, NumTemplateArgs); } } -void CXXNameMangler::mangleUnscopedName(GlobalDecl GD, +void CXXNameMangler::mangleUnscopedName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags) { - const NamedDecl *ND = cast(GD.getDecl()); // ::= // ::= St # ::std:: - if (isStdNamespace(Context.getEffectiveDeclContext(ND))) + assert(!isa(DC) && "unskipped LinkageSpecDecl"); + if (isStdNamespace(DC)) Out << "St"; - mangleUnqualifiedName(GD, AdditionalAbiTags); + mangleUnqualifiedName(GD, DC, AdditionalAbiTags); } void CXXNameMangler::mangleUnscopedTemplateName( - GlobalDecl GD, const AbiTagList *AdditionalAbiTags) { + GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags) { const TemplateDecl *ND = cast(GD.getDecl()); // ::= // ::= @@ -1121,9 +1119,10 @@ "template template param cannot have abi tags"); mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); } else if (isa(ND) || isa(ND)) { - mangleUnscopedName(GD, AdditionalAbiTags); + mangleUnscopedName(GD, DC, AdditionalAbiTags); } else { - mangleUnscopedName(GD.getWithDecl(ND->getTemplatedDecl()), AdditionalAbiTags); + mangleUnscopedName(GD.getWithDecl(ND->getTemplatedDecl()), DC, + AdditionalAbiTags); } addSubstitution(ND); @@ -1399,15 +1398,19 @@ mangleTemplateArgs(TemplateName(), TemplateArgs, NumTemplateArgs); } -void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, - DeclarationName Name, - unsigned KnownArity, - const AbiTagList *AdditionalAbiTags) { +void CXXNameMangler::mangleUnqualifiedName( + GlobalDecl GD, DeclarationName Name, const DeclContext *DC, + unsigned KnownArity, const AbiTagList *AdditionalAbiTags) { const NamedDecl *ND = cast_or_null(GD.getDecl()); - unsigned Arity = KnownArity; - // ::= + // ::= [] // ::= - // ::= + // ::= [] + // ::= [] DC * E + + if (ND && DC && DC->isFileContext()) + mangleModuleName(ND); + + unsigned Arity = KnownArity; switch (Name.getNameKind()) { case DeclarationName::Identifier: { const IdentifierInfo *II = Name.getAsIdentifierInfo(); @@ -1418,8 +1421,6 @@ // // ::= DC * E // - // These can never be referenced across translation units, so we do - // not need a cross-vendor mangling for anything other than demanglers. // Proposed on cxx-abi-dev on 2016-08-12 Out << "DC"; for (auto *BD : DD->bindings()) @@ -1716,7 +1717,7 @@ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); } else { manglePrefix(DC, NoFunction); - mangleUnqualifiedName(GD, AdditionalAbiTags); + mangleUnqualifiedName(GD, DC, AdditionalAbiTags); } Out << 'E'; @@ -1746,7 +1747,7 @@ Out << 'N'; mangleClosurePrefix(PrefixND); - mangleUnqualifiedName(GD, AdditionalAbiTags); + mangleUnqualifiedName(GD, nullptr, AdditionalAbiTags); Out << 'E'; } @@ -1824,7 +1825,7 @@ // Mangle the name relative to the closest enclosing function. // equality ok because RD derived from ND above if (D == RD) { - mangleUnqualifiedName(RD, AdditionalAbiTags); + mangleUnqualifiedName(RD, DC, AdditionalAbiTags); } else if (const BlockDecl *BD = dyn_cast(D)) { if (const NamedDecl *PrefixND = getClosurePrefix(BD)) mangleClosurePrefix(PrefixND, true /*NoFunction*/); @@ -1855,7 +1856,7 @@ assert(!AdditionalAbiTags && "Block cannot have additional abi tags"); mangleUnqualifiedBlock(BD); } else { - mangleUnqualifiedName(GD, AdditionalAbiTags); + mangleUnqualifiedName(GD, DC, AdditionalAbiTags); } if (const NamedDecl *ND = dyn_cast(RD ? RD : D)) { @@ -2082,10 +2083,11 @@ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); } else if (const NamedDecl *PrefixND = getClosurePrefix(ND)) { mangleClosurePrefix(PrefixND, NoFunction); - mangleUnqualifiedName(ND, nullptr); + mangleUnqualifiedName(ND, nullptr, nullptr); } else { - manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction); - mangleUnqualifiedName(ND, nullptr); + const DeclContext *DC = Context.getEffectiveDeclContext(ND); + manglePrefix(DC, NoFunction); + mangleUnqualifiedName(ND, DC, nullptr); } addSubstitution(ND); @@ -2138,11 +2140,13 @@ if (const auto *TTP = dyn_cast(ND)) { mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); } else { - manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction); + const DeclContext *DC = Context.getEffectiveDeclContext(ND); + manglePrefix(DC, NoFunction); if (isa(ND) || isa(ND)) - mangleUnqualifiedName(GD, nullptr); + mangleUnqualifiedName(GD, DC, nullptr); else - mangleUnqualifiedName(GD.getWithDecl(ND->getTemplatedDecl()), nullptr); + mangleUnqualifiedName(GD.getWithDecl(ND->getTemplatedDecl()), DC, + nullptr); } addSubstitution(ND); @@ -2183,8 +2187,9 @@ mangleTemplatePrefix(TD, NoFunction); mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); } else { - manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction); - mangleUnqualifiedName(ND, nullptr); + const auto *DC = Context.getEffectiveDeclContext(ND); + manglePrefix(DC, NoFunction); + mangleUnqualifiedName(ND, DC, nullptr); } Out << 'M'; @@ -6026,6 +6031,9 @@ if (TemplateArgs[0].getAsType() != A) return false; + if (SD->getSpecializedTemplate()->getOwningModuleForLinkage()) + return false; + return true; } @@ -6057,6 +6065,9 @@ !isSpecializedAs(TemplateArgs[2].getAsType(), "allocator", A)) return false; + if (SD->getSpecializedTemplate()->getOwningModuleForLinkage()) + return false; + return true; } @@ -6074,6 +6085,9 @@ if (!isStdNamespace(Context.getEffectiveDeclContext(TD))) return false; + if (TD->getOwningModuleForLinkage()) + return false; + // ::= Sa # ::std::allocator if (TD->getIdentifier()->isStr("allocator")) { Out << "Sa"; @@ -6093,6 +6107,9 @@ if (!isStdNamespace(Context.getEffectiveDeclContext(SD))) return false; + if (SD->getSpecializedTemplate()->getOwningModuleForLinkage()) + return false; + // ::= Ss # ::std::basic_string, // ::std::allocator > @@ -6447,6 +6464,19 @@ Mangler.mangleLambdaSig(Lambda); } +void ItaniumMangleContextImpl::mangleModuleInitializer(const Module *M, + raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZGI"; + Mangler.mangleModuleNamePrefix(M->getPrimaryModuleInterfaceName()); + if (M->isModulePartition()) { + auto Partition = M->Name.find(':'); + Mangler.mangleModuleNamePrefix( + StringRef(&M->Name[Partition + 1], M->Name.size() - Partition - 1), + /*IsPartition*/ true); + } +} + ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { return new ItaniumMangleContextImpl( diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp +++ b/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; diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm +++ b/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) {} diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp +++ b/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; diff --git a/clang/test/CXX/modules-ts/basic/basic.link/p3.cppm b/clang/test/CXX/modules-ts/basic/basic.link/p3.cppm --- a/clang/test/CXX/modules-ts/basic/basic.link/p3.cppm +++ b/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; } diff --git a/clang/test/CXX/modules-ts/codegen-basics.cppm b/clang/test/CXX/modules-ts/codegen-basics.cppm --- a/clang/test/CXX/modules-ts/codegen-basics.cppm +++ b/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(); } diff --git a/clang/test/CodeGenCXX/Inputs/cxx20-module-impl-1a.cpp b/clang/test/CodeGenCXX/Inputs/cxx20-module-impl-1a.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/Inputs/cxx20-module-impl-1a.cpp @@ -0,0 +1,3 @@ +export module Foo; +export void Exported(); +void Module(); diff --git a/clang/test/CodeGenCXX/Inputs/cxx20-module-std-subst-2a.cpp b/clang/test/CodeGenCXX/Inputs/cxx20-module-std-subst-2a.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/Inputs/cxx20-module-std-subst-2a.cpp @@ -0,0 +1,11 @@ +module; +# 5 __FILE__ 1 +namespace std { +template struct allocator {}; +template +class basic_string; +} // namespace std +# 12 "" 2 +export module RenameString; +export template +using str = std::basic_string>; diff --git a/clang/test/CodeGenCXX/cxx20-module-decomp-1.cpp b/clang/test/CodeGenCXX/cxx20-module-decomp-1.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-decomp-1.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s + +export module Foo; + +// CHECK-DAG: @_ZW3Foo3ary = +int ary[2]; + +// CHECK-DAG: @_ZW3FooDC1a1bE = +export auto &[a, b] = ary; + +namespace N { +// CHECK-DAG: @_ZN1NW3FooDC1a1bEE = +export auto &[a, b] = ary; +// CHECK-DAG: @_ZN1NW3FooDC1c1dEE = +auto &[c, d] = ary; +// FIXME: We mangle the module name here, as we give this ModuleInternalLinkage +// That's no longer needed. +// CHECK DAG: @_ZN1MDC1e1fEE = +static auto &__attribute__((used))[e, f] = ary; +} // namespace N diff --git a/clang/test/CodeGenCXX/cxx20-module-extern-1.cppm b/clang/test/CodeGenCXX/cxx20-module-extern-1.cppm new file mode 100644 --- /dev/null +++ b/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*) { +} +} diff --git a/clang/test/CodeGenCXX/cxx20-module-impl-1a.cpp b/clang/test/CodeGenCXX/cxx20-module-impl-1a.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-impl-1a.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++20 %S/Inputs/cxx20-module-impl-1a.cpp -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 + +module Foo; + +// CHECK-DAG: @_ZW3Foo8Exportedv( +void Exported() { +} + +// CHECK-DAG: @_ZW3Foo6Modulev( +void Module() { +} + +// CHECK-DAG: @_ZW3Foo7Module2v( +void Module2() { +} + diff --git a/clang/test/CodeGenCXX/cxx20-module-nested-1.cppm b/clang/test/CodeGenCXX/cxx20-module-nested-1.cppm new file mode 100644 --- /dev/null +++ b/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 diff --git a/clang/test/CodeGenCXX/cxx20-module-nested-2.cppm b/clang/test/CodeGenCXX/cxx20-module-nested-2.cppm new file mode 100644 --- /dev/null +++ b/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 &) {} +} + diff --git a/clang/test/CodeGenCXX/cxx20-module-part-1a.cpp b/clang/test/CodeGenCXX/cxx20-module-part-1a.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-part-1a.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s +export module Foo:inter; + +// CHECK-DAG: @_ZW3Foo4Frobv( +export void Frob() { +} diff --git a/clang/test/CodeGenCXX/cxx20-module-part-1b.cpp b/clang/test/CodeGenCXX/cxx20-module-part-1b.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-part-1b.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s +export module Foo:impl; + +// CHECK-DAG: @_ZW3Foo4Quuxv( +export void Quux() { +} diff --git a/clang/test/CodeGenCXX/cxx20-module-part-1c.cpp b/clang/test/CodeGenCXX/cxx20-module-part-1c.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-part-1c.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++20 %S/cxx20-module-part-1a.cpp -triple %itanium_abi_triple -emit-module-interface -o %t-inter +// RUN: %clang_cc1 -std=c++20 %S/cxx20-module-part-1b.cpp -triple %itanium_abi_triple -emit-module-interface -o %t-impl +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -fmodule-file=Foo:inter=%t-inter -fmodule-file=Foo:impl=%t-impl -emit-llvm -o - | FileCheck %s +export module Foo; +export import :inter; +import :impl; + +void Wrap() { + // CHECK: call void @_ZW3Foo4Frobv() + Frob(); + // CHECK: call void @_ZW3Foo4Quuxv() + Quux(); +} diff --git a/clang/test/CodeGenCXX/cxx20-module-std-subst-1.cppm b/clang/test/CodeGenCXX/cxx20-module-std-subst-1.cppm new file mode 100644 --- /dev/null +++ b/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 *); diff --git a/clang/test/CodeGenCXX/cxx20-module-std-subst-2b.cpp b/clang/test/CodeGenCXX/cxx20-module-std-subst-2b.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-std-subst-2b.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -std=c++20 %S/Inputs/cxx20-module-std-subst-2a.cpp -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; +import RenameString; + +namespace std { +template struct char_traits {}; +} // namespace std + +// use Sb mangling, not Ss as this is not global-module std::char_traits +// std::char_traits. +// CHECK-DAG: void @_ZW3Foo1fRSbIcStS_11char_traitsIcESaIcEE( +void f(str> &s) { +} diff --git a/clang/test/CodeGenCXX/cxx20-module-std-subst-2c.cpp b/clang/test/CodeGenCXX/cxx20-module-std-subst-2c.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-std-subst-2c.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -std=c++20 %S/Inputs/cxx20-module-std-subst-2a.cpp -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 +module; +# 5 __FILE__ 1 +namespace std { +template struct char_traits {}; +} // namespace std +# 9 "" 2 +export module Bar; +import RenameString; + +// Use Ss as this is global-module std::char_traits +// CHECK-DAG: void @_ZW3Bar1gRSs( +void g(str> &s) { +} diff --git a/clang/test/CodeGenCXX/cxx20-module-sub-1a.cppm b/clang/test/CodeGenCXX/cxx20-module-sub-1a.cppm new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-sub-1a.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*) { +} diff --git a/clang/test/CodeGenCXX/cxx20-module-sub-1b.cppm b/clang/test/CodeGenCXX/cxx20-module-sub-1b.cppm new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx20-module-sub-1b.cppm @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++20 %S/cxx20-module-sub-1a.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*) { +} diff --git a/clang/test/CodeGenCXX/cxx20-module-tmpl-1.cppm b/clang/test/CodeGenCXX/cxx20-module-tmpl-1.cppm new file mode 100644 --- /dev/null +++ b/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 *); +}