forked from OSchip/llvm-project
[clang][ABI] New C++20 module mangling scheme
Implement a demangleable strong ownership symbol mangling. * The original module symbol mangling scheme turned out to be undemangleable. * The hoped-for C++17 compatibility of weak ownership turns out to be fragile * C++20 now has better ways of controlling C++17 compatibility The issue is captured on the ABI list at: https://github.com/itanium-cxx-abi/cxx-abi/issues/134 GCC implements this new mangling. The old mangling is unceremoniously dropped. No backwards compatibility, no deprectated old-mangling flag. It was always labelled experimental. (Old and new manglings cannot be confused.) Reviewed By: dblaikie Differential Revision: https://reviews.llvm.org/D122256
This commit is contained in:
parent
d6887256c2
commit
ae4dce8659
|
@ -1547,6 +1547,11 @@ LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) {
|
|||
}
|
||||
|
||||
Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
|
||||
if (isa<NamespaceDecl>(this))
|
||||
// Namespaces never have module linkage. It is the entities within them
|
||||
// that [may] do.
|
||||
return nullptr;
|
||||
|
||||
Module *M = getOwningModule();
|
||||
if (!M)
|
||||
return nullptr;
|
||||
|
|
|
@ -438,6 +438,7 @@ public:
|
|||
void mangleType(QualType T);
|
||||
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
|
||||
void mangleLambdaSig(const CXXRecordDecl *Lambda);
|
||||
void mangleModuleNamePrefix(StringRef Name);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -473,22 +474,21 @@ private:
|
|||
|
||||
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<NamedDecl>(GD.getDecl())->getDeclName(), UnknownArity,
|
||||
AdditionalAbiTags);
|
||||
mangleUnqualifiedName(GD, cast<NamedDecl>(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 +733,8 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
|
|||
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 +742,8 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
|
|||
DC = getEffectiveParentContext(DC);
|
||||
if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage &&
|
||||
!CXXNameMangler::shouldHaveAbiTags(*this, VD) &&
|
||||
!isa<VarTemplateSpecializationDecl>(VD))
|
||||
!isa<VarTemplateSpecializationDecl>(VD) &&
|
||||
!VD->getOwningModuleForLinkage())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1016,14 +1018,6 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
|
|||
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 +1029,35 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
|
|||
// 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
|
||||
//
|
||||
// <module-name> ::= W <unscoped-name>+ E
|
||||
// ::= W <module-subst> <unscoped-name>* 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());
|
||||
}
|
||||
|
||||
// <module-name> ::= <module-subname>
|
||||
// ::= <module-name> <module-subname>
|
||||
// ::= <substitution>
|
||||
// <module-subname> ::= W <source-name>
|
||||
// ::= W P <source-name> # not (yet) needed
|
||||
void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) {
|
||||
// <module-subst> ::= _ <seq-id> # 0 < seq-id < 10
|
||||
// ::= W <seq-id - 10> _ # otherwise
|
||||
// <substitution> ::= S <seq-id> _
|
||||
auto It = ModuleSubstitutions.find(Name);
|
||||
if (It != ModuleSubstitutions.end()) {
|
||||
if (It->second < 10)
|
||||
Out << '_' << static_cast<char>('0' + It->second);
|
||||
else
|
||||
Out << 'W' << (It->second - 10) << '_';
|
||||
Out << 'S';
|
||||
mangleSeqID(It->second);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1078,8 +1069,9 @@ void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) {
|
|||
else
|
||||
mangleModuleNamePrefix(Parts.first);
|
||||
|
||||
Out << 'W';
|
||||
Out << Parts.second.size() << Parts.second;
|
||||
ModuleSubstitutions.insert({Name, ModuleSubstitutions.size()});
|
||||
ModuleSubstitutions.insert({Name, SeqID++});
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
|
||||
|
@ -1088,27 +1080,27 @@ void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
|
|||
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<NamedDecl>(GD.getDecl());
|
||||
// <unscoped-name> ::= <unqualified-name>
|
||||
// ::= St <unqualified-name> # ::std::
|
||||
|
||||
if (isStdNamespace(Context.getEffectiveDeclContext(ND)))
|
||||
assert(!isa<LinkageSpecDecl>(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<TemplateDecl>(GD.getDecl());
|
||||
// <unscoped-template-name> ::= <unscoped-name>
|
||||
// ::= <substitution>
|
||||
|
@ -1121,9 +1113,10 @@ void CXXNameMangler::mangleUnscopedTemplateName(
|
|||
"template template param cannot have abi tags");
|
||||
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
|
||||
} else if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(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 +1392,19 @@ void CXXNameMangler::mangleUnresolvedName(
|
|||
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<NamedDecl>(GD.getDecl());
|
||||
unsigned Arity = KnownArity;
|
||||
// <unqualified-name> ::= <operator-name>
|
||||
// <unqualified-name> ::= [<module-name>] <operator-name>
|
||||
// ::= <ctor-dtor-name>
|
||||
// ::= <source-name>
|
||||
// ::= [<module-name>] <source-name>
|
||||
// ::= [<module-name>] DC <source-name>* E
|
||||
|
||||
if (ND && DC && DC->isFileContext())
|
||||
mangleModuleName(ND);
|
||||
|
||||
unsigned Arity = KnownArity;
|
||||
switch (Name.getNameKind()) {
|
||||
case DeclarationName::Identifier: {
|
||||
const IdentifierInfo *II = Name.getAsIdentifierInfo();
|
||||
|
@ -1418,8 +1415,6 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
|
|||
//
|
||||
// <unqualified-name> ::= DC <source-name>* 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 +1711,7 @@ void CXXNameMangler::mangleNestedName(GlobalDecl GD,
|
|||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
} else {
|
||||
manglePrefix(DC, NoFunction);
|
||||
mangleUnqualifiedName(GD, AdditionalAbiTags);
|
||||
mangleUnqualifiedName(GD, DC, AdditionalAbiTags);
|
||||
}
|
||||
|
||||
Out << 'E';
|
||||
|
@ -1746,7 +1741,7 @@ void CXXNameMangler::mangleNestedNameWithClosurePrefix(
|
|||
Out << 'N';
|
||||
|
||||
mangleClosurePrefix(PrefixND);
|
||||
mangleUnqualifiedName(GD, AdditionalAbiTags);
|
||||
mangleUnqualifiedName(GD, nullptr, AdditionalAbiTags);
|
||||
|
||||
Out << 'E';
|
||||
}
|
||||
|
@ -1824,7 +1819,7 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
|
|||
// 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<BlockDecl>(D)) {
|
||||
if (const NamedDecl *PrefixND = getClosurePrefix(BD))
|
||||
mangleClosurePrefix(PrefixND, true /*NoFunction*/);
|
||||
|
@ -1855,7 +1850,7 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
|
|||
assert(!AdditionalAbiTags && "Block cannot have additional abi tags");
|
||||
mangleUnqualifiedBlock(BD);
|
||||
} else {
|
||||
mangleUnqualifiedName(GD, AdditionalAbiTags);
|
||||
mangleUnqualifiedName(GD, DC, AdditionalAbiTags);
|
||||
}
|
||||
|
||||
if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) {
|
||||
|
@ -2082,10 +2077,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
|
|||
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 +2134,13 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
|
|||
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
|
||||
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
|
||||
} else {
|
||||
manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
|
||||
const DeclContext *DC = Context.getEffectiveDeclContext(ND);
|
||||
manglePrefix(DC, NoFunction);
|
||||
if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(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 +2181,9 @@ void CXXNameMangler::mangleClosurePrefix(const NamedDecl *ND, bool NoFunction) {
|
|||
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';
|
||||
|
@ -6027,6 +6026,9 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name,
|
|||
if (TemplateArgs[0].getAsType() != A)
|
||||
return false;
|
||||
|
||||
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6058,6 +6060,9 @@ bool CXXNameMangler::isStdCharSpecialization(
|
|||
!isSpecializedAs(TemplateArgs[2].getAsType(), "allocator", A))
|
||||
return false;
|
||||
|
||||
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6075,6 +6080,9 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
|
|||
if (!isStdNamespace(Context.getEffectiveDeclContext(TD)))
|
||||
return false;
|
||||
|
||||
if (TD->getOwningModuleForLinkage())
|
||||
return false;
|
||||
|
||||
// <substitution> ::= Sa # ::std::allocator
|
||||
if (TD->getIdentifier()->isStr("allocator")) {
|
||||
Out << "Sa";
|
||||
|
@ -6094,6 +6102,9 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
|
|||
if (!isStdNamespace(Context.getEffectiveDeclContext(SD)))
|
||||
return false;
|
||||
|
||||
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())
|
||||
return false;
|
||||
|
||||
// <substitution> ::= Ss # ::std::basic_string<char,
|
||||
// ::std::char_traits<char>,
|
||||
// ::std::allocator<char> >
|
||||
|
|
|
@ -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 use() {
|
|||
(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;
|
||||
|
|
|
@ -5,25 +5,26 @@
|
|||
// CHECK-DAG: @_ZL24static_var_global_module = internal global
|
||||
// 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
|
||||
// With strong-ownership, the module is mangled into exported symbols
|
||||
// that are attached to a named module.
|
||||
// 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 +65,7 @@ export {
|
|||
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 +76,9 @@ export {
|
|||
// 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 +89,10 @@ inline int inline_var_module_linkage;
|
|||
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 +110,5 @@ struct a {
|
|||
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) {}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export module Foo;
|
||||
export void Exported();
|
||||
void Module();
|
|
@ -0,0 +1,11 @@
|
|||
module;
|
||||
# 5 __FILE__ 1
|
||||
namespace std {
|
||||
template <typename A> struct allocator {};
|
||||
template <typename C, typename T, typename A>
|
||||
class basic_string;
|
||||
} // namespace std
|
||||
# 12 "" 2
|
||||
export module RenameString;
|
||||
export template <typename C, typename T>
|
||||
using str = std::basic_string<C, T, std::allocator<C>>;
|
|
@ -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
|
|
@ -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*) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// 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() {
|
||||
}
|
|
@ -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: void @_ZN5Outer5Inner3BarERNS0_1XE(
|
||||
void Bar (X &) {}
|
||||
} // namespace Outer::Inner
|
||||
# 10 "" 2
|
||||
export module FOO;
|
||||
namespace Outer {
|
||||
class Y;
|
||||
namespace Inner {
|
||||
// CHECK-DAG: void @_ZN5Outer5InnerW3FOO2FnERNS0_1XERNS_S1_1YE(
|
||||
void Fn (X &, Y &){} // #1
|
||||
} // namespace Inner
|
||||
} // namespace Outer
|
|
@ -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: void @_ZN5OuterW3FOO5Inner2FnERNS1_1XERNS_S0_1YE(
|
||||
void Inner::Fn (X &, Y &) {}
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
|
@ -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() {
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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<typename T> class allocator {
|
||||
// just for testing, not real!
|
||||
void M (T *);
|
||||
template <typename U> U *N (T *);
|
||||
};
|
||||
|
||||
template<typename T> void allocator<T>::M (T *) {}
|
||||
template<typename T> template<typename U> U *allocator<T>::N (T *) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// CHECK-DAG: void @_ZNStW3std9allocatorIiE1MEPi(
|
||||
template void allocator<int>::M (int *);
|
||||
// CHECK-DAG: @_ZNStW3std9allocatorIiE1NIfEEPT_Pi(
|
||||
template float *allocator<int>::N<float> (int *);
|
||||
}
|
||||
|
||||
// CHECK-DAG: @_ZNStW3std9allocatorI4PoohE1MEPS1_(
|
||||
template void std::allocator<Pooh>::M (Pooh *);
|
||||
// CHECK-DAG: @_ZNStW3std9allocatorI4PoohE1NI6PigletEEPT_PS1_(
|
||||
template Piglet *std::allocator<Pooh>::N<Piglet> (Pooh *);
|
|
@ -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 <typename T> 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<char, std::char_traits<char>> &s) {
|
||||
}
|
|
@ -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 <typename A> 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<char, std::char_traits<char>> &s) {
|
||||
}
|
|
@ -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*) {
|
||||
}
|
|
@ -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*) {
|
||||
}
|
|
@ -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<typename T> struct TPL
|
||||
{
|
||||
void M (T *);
|
||||
template<typename U> void N (T *, U*);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void TPL<T>::M (T *) {}
|
||||
|
||||
template<typename T> template<typename U> void TPL<T>::N (T *, U*) {}
|
||||
|
||||
// CHECK-DAG: void @_ZNW3FOO3TPLIS_3OneE1MEPS1_(
|
||||
template void TPL<One>::M (One *);
|
||||
// CHECK-DAG: void @_ZNW3FOO3TPLIS_3OneE1NIS_3TwoEEvPS1_PT_(
|
||||
template void TPL<One>::N<Two> (One *, Two *);
|
||||
|
||||
namespace NMS {
|
||||
class One;
|
||||
class Two;
|
||||
|
||||
export template<typename T> struct TPL
|
||||
{
|
||||
void M (T *);
|
||||
template<typename U> void N (T *, U*);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void TPL<T>::M (T *) {}
|
||||
|
||||
template<typename T> template<typename U> void TPL<T>::N (T *, U*) {}
|
||||
|
||||
// CHECK-DAG: void @_ZN3NMSW3FOO3TPLINS_S0_3OneEE1MEPS2_(
|
||||
template void TPL<One>::M (One *);
|
||||
// CHECK-DAG: void @_ZN3NMSW3FOO3TPLINS_S0_3OneEE1NINS_S0_3TwoEEEvPS2_PT_
|
||||
template void TPL<One>::N<Two> (One *, Two *);
|
||||
}
|
Loading…
Reference in New Issue