Skip to content

Commit ae4dce8

Browse files
committed
[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: itanium-cxx-abi/cxx-abi#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
1 parent d688725 commit ae4dce8

23 files changed

+379
-104
lines changed

clang/lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,11 @@ LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) {
15471547
}
15481548

15491549
Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
1550+
if (isa<NamespaceDecl>(this))
1551+
// Namespaces never have module linkage. It is the entities within them
1552+
// that [may] do.
1553+
return nullptr;
1554+
15501555
Module *M = getOwningModule();
15511556
if (!M)
15521557
return nullptr;

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ class CXXNameMangler {
438438
void mangleType(QualType T);
439439
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
440440
void mangleLambdaSig(const CXXRecordDecl *Lambda);
441+
void mangleModuleNamePrefix(StringRef Name);
441442

442443
private:
443444

@@ -473,22 +474,21 @@ class CXXNameMangler {
473474

474475
void mangleNameWithAbiTags(GlobalDecl GD,
475476
const AbiTagList *AdditionalAbiTags);
476-
void mangleModuleName(const Module *M);
477-
void mangleModuleNamePrefix(StringRef Name);
477+
void mangleModuleName(const NamedDecl *ND);
478478
void mangleTemplateName(const TemplateDecl *TD,
479479
const TemplateArgument *TemplateArgs,
480480
unsigned NumTemplateArgs);
481-
void mangleUnqualifiedName(GlobalDecl GD,
481+
void mangleUnqualifiedName(GlobalDecl GD, const DeclContext *DC,
482482
const AbiTagList *AdditionalAbiTags) {
483-
mangleUnqualifiedName(GD, cast<NamedDecl>(GD.getDecl())->getDeclName(), UnknownArity,
484-
AdditionalAbiTags);
483+
mangleUnqualifiedName(GD, cast<NamedDecl>(GD.getDecl())->getDeclName(), DC,
484+
UnknownArity, AdditionalAbiTags);
485485
}
486486
void mangleUnqualifiedName(GlobalDecl GD, DeclarationName Name,
487-
unsigned KnownArity,
487+
const DeclContext *DC, unsigned KnownArity,
488488
const AbiTagList *AdditionalAbiTags);
489-
void mangleUnscopedName(GlobalDecl GD,
489+
void mangleUnscopedName(GlobalDecl GD, const DeclContext *DC,
490490
const AbiTagList *AdditionalAbiTags);
491-
void mangleUnscopedTemplateName(GlobalDecl GD,
491+
void mangleUnscopedTemplateName(GlobalDecl GD, const DeclContext *DC,
492492
const AbiTagList *AdditionalAbiTags);
493493
void mangleSourceName(const IdentifierInfo *II);
494494
void mangleRegCallName(const IdentifierInfo *II);
@@ -733,15 +733,17 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
733733
if (VD->isExternC())
734734
return false;
735735

736-
// Variables at global scope with non-internal linkage are not mangled.
736+
// Variables at global scope are not mangled unless they have internal
737+
// linkage or are specializations or are attached to a named module.
737738
const DeclContext *DC = getEffectiveDeclContext(D);
738739
// Check for extern variable declared locally.
739740
if (DC->isFunctionOrMethod() && D->hasLinkage())
740741
while (!DC->isFileContext())
741742
DC = getEffectiveParentContext(DC);
742743
if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage &&
743744
!CXXNameMangler::shouldHaveAbiTags(*this, VD) &&
744-
!isa<VarTemplateSpecializationDecl>(VD))
745+
!isa<VarTemplateSpecializationDecl>(VD) &&
746+
!VD->getOwningModuleForLinkage())
745747
return false;
746748
}
747749

@@ -1016,14 +1018,6 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
10161018
return;
10171019
}
10181020

1019-
// Do not mangle the owning module for an external linkage declaration.
1020-
// This enables backwards-compatibility with non-modular code, and is
1021-
// a valid choice since conflicts are not permitted by C++ Modules TS
1022-
// [basic.def.odr]/6.2.
1023-
if (!ND->hasExternalFormalLinkage())
1024-
if (Module *M = ND->getOwningModuleForLinkage())
1025-
mangleModuleName(M);
1026-
10271021
// Closures can require a nested-name mangling even if they're semantically
10281022
// in the global namespace.
10291023
if (const NamedDecl *PrefixND = getClosurePrefix(ND)) {
@@ -1035,38 +1029,35 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
10351029
// Check if we have a template.
10361030
const TemplateArgumentList *TemplateArgs = nullptr;
10371031
if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) {
1038-
mangleUnscopedTemplateName(TD, AdditionalAbiTags);
1032+
mangleUnscopedTemplateName(TD, DC, AdditionalAbiTags);
10391033
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
10401034
return;
10411035
}
10421036

1043-
mangleUnscopedName(GD, AdditionalAbiTags);
1037+
mangleUnscopedName(GD, DC, AdditionalAbiTags);
10441038
return;
10451039
}
10461040

10471041
mangleNestedName(GD, DC, AdditionalAbiTags);
10481042
}
10491043

1050-
void CXXNameMangler::mangleModuleName(const Module *M) {
1051-
// Implement the C++ Modules TS name mangling proposal; see
1052-
// https://gcc.gnu.org/wiki/cxx-modules?action=AttachFile
1053-
//
1054-
// <module-name> ::= W <unscoped-name>+ E
1055-
// ::= W <module-subst> <unscoped-name>* E
1056-
Out << 'W';
1057-
mangleModuleNamePrefix(M->Name);
1058-
Out << 'E';
1044+
void CXXNameMangler::mangleModuleName(const NamedDecl *ND) {
1045+
if (ND->isExternallyVisible())
1046+
if (Module *M = ND->getOwningModuleForLinkage())
1047+
mangleModuleNamePrefix(M->getPrimaryModuleInterfaceName());
10591048
}
10601049

1050+
// <module-name> ::= <module-subname>
1051+
// ::= <module-name> <module-subname>
1052+
// ::= <substitution>
1053+
// <module-subname> ::= W <source-name>
1054+
// ::= W P <source-name> # not (yet) needed
10611055
void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) {
1062-
// <module-subst> ::= _ <seq-id> # 0 < seq-id < 10
1063-
// ::= W <seq-id - 10> _ # otherwise
1056+
// <substitution> ::= S <seq-id> _
10641057
auto It = ModuleSubstitutions.find(Name);
10651058
if (It != ModuleSubstitutions.end()) {
1066-
if (It->second < 10)
1067-
Out << '_' << static_cast<char>('0' + It->second);
1068-
else
1069-
Out << 'W' << (It->second - 10) << '_';
1059+
Out << 'S';
1060+
mangleSeqID(It->second);
10701061
return;
10711062
}
10721063

@@ -1078,8 +1069,9 @@ void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) {
10781069
else
10791070
mangleModuleNamePrefix(Parts.first);
10801071

1072+
Out << 'W';
10811073
Out << Parts.second.size() << Parts.second;
1082-
ModuleSubstitutions.insert({Name, ModuleSubstitutions.size()});
1074+
ModuleSubstitutions.insert({Name, SeqID++});
10831075
}
10841076

10851077
void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
@@ -1088,27 +1080,27 @@ void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
10881080
const DeclContext *DC = Context.getEffectiveDeclContext(TD);
10891081

10901082
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
1091-
mangleUnscopedTemplateName(TD, nullptr);
1083+
mangleUnscopedTemplateName(TD, DC, nullptr);
10921084
mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
10931085
} else {
10941086
mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
10951087
}
10961088
}
10971089

1098-
void CXXNameMangler::mangleUnscopedName(GlobalDecl GD,
1090+
void CXXNameMangler::mangleUnscopedName(GlobalDecl GD, const DeclContext *DC,
10991091
const AbiTagList *AdditionalAbiTags) {
1100-
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
11011092
// <unscoped-name> ::= <unqualified-name>
11021093
// ::= St <unqualified-name> # ::std::
11031094

1104-
if (isStdNamespace(Context.getEffectiveDeclContext(ND)))
1095+
assert(!isa<LinkageSpecDecl>(DC) && "unskipped LinkageSpecDecl");
1096+
if (isStdNamespace(DC))
11051097
Out << "St";
11061098

1107-
mangleUnqualifiedName(GD, AdditionalAbiTags);
1099+
mangleUnqualifiedName(GD, DC, AdditionalAbiTags);
11081100
}
11091101

11101102
void CXXNameMangler::mangleUnscopedTemplateName(
1111-
GlobalDecl GD, const AbiTagList *AdditionalAbiTags) {
1103+
GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags) {
11121104
const TemplateDecl *ND = cast<TemplateDecl>(GD.getDecl());
11131105
// <unscoped-template-name> ::= <unscoped-name>
11141106
// ::= <substitution>
@@ -1121,9 +1113,10 @@ void CXXNameMangler::mangleUnscopedTemplateName(
11211113
"template template param cannot have abi tags");
11221114
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
11231115
} else if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND)) {
1124-
mangleUnscopedName(GD, AdditionalAbiTags);
1116+
mangleUnscopedName(GD, DC, AdditionalAbiTags);
11251117
} else {
1126-
mangleUnscopedName(GD.getWithDecl(ND->getTemplatedDecl()), AdditionalAbiTags);
1118+
mangleUnscopedName(GD.getWithDecl(ND->getTemplatedDecl()), DC,
1119+
AdditionalAbiTags);
11271120
}
11281121

11291122
addSubstitution(ND);
@@ -1399,15 +1392,19 @@ void CXXNameMangler::mangleUnresolvedName(
13991392
mangleTemplateArgs(TemplateName(), TemplateArgs, NumTemplateArgs);
14001393
}
14011394

1402-
void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
1403-
DeclarationName Name,
1404-
unsigned KnownArity,
1405-
const AbiTagList *AdditionalAbiTags) {
1395+
void CXXNameMangler::mangleUnqualifiedName(
1396+
GlobalDecl GD, DeclarationName Name, const DeclContext *DC,
1397+
unsigned KnownArity, const AbiTagList *AdditionalAbiTags) {
14061398
const NamedDecl *ND = cast_or_null<NamedDecl>(GD.getDecl());
1407-
unsigned Arity = KnownArity;
1408-
// <unqualified-name> ::= <operator-name>
1399+
// <unqualified-name> ::= [<module-name>] <operator-name>
14091400
// ::= <ctor-dtor-name>
1410-
// ::= <source-name>
1401+
// ::= [<module-name>] <source-name>
1402+
// ::= [<module-name>] DC <source-name>* E
1403+
1404+
if (ND && DC && DC->isFileContext())
1405+
mangleModuleName(ND);
1406+
1407+
unsigned Arity = KnownArity;
14111408
switch (Name.getNameKind()) {
14121409
case DeclarationName::Identifier: {
14131410
const IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -1418,8 +1415,6 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
14181415
//
14191416
// <unqualified-name> ::= DC <source-name>* E
14201417
//
1421-
// These can never be referenced across translation units, so we do
1422-
// not need a cross-vendor mangling for anything other than demanglers.
14231418
// Proposed on cxx-abi-dev on 2016-08-12
14241419
Out << "DC";
14251420
for (auto *BD : DD->bindings())
@@ -1716,7 +1711,7 @@ void CXXNameMangler::mangleNestedName(GlobalDecl GD,
17161711
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
17171712
} else {
17181713
manglePrefix(DC, NoFunction);
1719-
mangleUnqualifiedName(GD, AdditionalAbiTags);
1714+
mangleUnqualifiedName(GD, DC, AdditionalAbiTags);
17201715
}
17211716

17221717
Out << 'E';
@@ -1746,7 +1741,7 @@ void CXXNameMangler::mangleNestedNameWithClosurePrefix(
17461741
Out << 'N';
17471742

17481743
mangleClosurePrefix(PrefixND);
1749-
mangleUnqualifiedName(GD, AdditionalAbiTags);
1744+
mangleUnqualifiedName(GD, nullptr, AdditionalAbiTags);
17501745

17511746
Out << 'E';
17521747
}
@@ -1824,7 +1819,7 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
18241819
// Mangle the name relative to the closest enclosing function.
18251820
// equality ok because RD derived from ND above
18261821
if (D == RD) {
1827-
mangleUnqualifiedName(RD, AdditionalAbiTags);
1822+
mangleUnqualifiedName(RD, DC, AdditionalAbiTags);
18281823
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
18291824
if (const NamedDecl *PrefixND = getClosurePrefix(BD))
18301825
mangleClosurePrefix(PrefixND, true /*NoFunction*/);
@@ -1855,7 +1850,7 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
18551850
assert(!AdditionalAbiTags && "Block cannot have additional abi tags");
18561851
mangleUnqualifiedBlock(BD);
18571852
} else {
1858-
mangleUnqualifiedName(GD, AdditionalAbiTags);
1853+
mangleUnqualifiedName(GD, DC, AdditionalAbiTags);
18591854
}
18601855

18611856
if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) {
@@ -2082,10 +2077,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
20822077
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
20832078
} else if (const NamedDecl *PrefixND = getClosurePrefix(ND)) {
20842079
mangleClosurePrefix(PrefixND, NoFunction);
2085-
mangleUnqualifiedName(ND, nullptr);
2080+
mangleUnqualifiedName(ND, nullptr, nullptr);
20862081
} else {
2087-
manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
2088-
mangleUnqualifiedName(ND, nullptr);
2082+
const DeclContext *DC = Context.getEffectiveDeclContext(ND);
2083+
manglePrefix(DC, NoFunction);
2084+
mangleUnqualifiedName(ND, DC, nullptr);
20892085
}
20902086

20912087
addSubstitution(ND);
@@ -2138,11 +2134,13 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
21382134
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
21392135
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
21402136
} else {
2141-
manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
2137+
const DeclContext *DC = Context.getEffectiveDeclContext(ND);
2138+
manglePrefix(DC, NoFunction);
21422139
if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND))
2143-
mangleUnqualifiedName(GD, nullptr);
2140+
mangleUnqualifiedName(GD, DC, nullptr);
21442141
else
2145-
mangleUnqualifiedName(GD.getWithDecl(ND->getTemplatedDecl()), nullptr);
2142+
mangleUnqualifiedName(GD.getWithDecl(ND->getTemplatedDecl()), DC,
2143+
nullptr);
21462144
}
21472145

21482146
addSubstitution(ND);
@@ -2183,8 +2181,9 @@ void CXXNameMangler::mangleClosurePrefix(const NamedDecl *ND, bool NoFunction) {
21832181
mangleTemplatePrefix(TD, NoFunction);
21842182
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
21852183
} else {
2186-
manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
2187-
mangleUnqualifiedName(ND, nullptr);
2184+
const auto *DC = Context.getEffectiveDeclContext(ND);
2185+
manglePrefix(DC, NoFunction);
2186+
mangleUnqualifiedName(ND, DC, nullptr);
21882187
}
21892188

21902189
Out << 'M';
@@ -6027,6 +6026,9 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name,
60276026
if (TemplateArgs[0].getAsType() != A)
60286027
return false;
60296028

6029+
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())
6030+
return false;
6031+
60306032
return true;
60316033
}
60326034

@@ -6058,6 +6060,9 @@ bool CXXNameMangler::isStdCharSpecialization(
60586060
!isSpecializedAs(TemplateArgs[2].getAsType(), "allocator", A))
60596061
return false;
60606062

6063+
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())
6064+
return false;
6065+
60616066
return true;
60626067
}
60636068

@@ -6075,6 +6080,9 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
60756080
if (!isStdNamespace(Context.getEffectiveDeclContext(TD)))
60766081
return false;
60776082

6083+
if (TD->getOwningModuleForLinkage())
6084+
return false;
6085+
60786086
// <substitution> ::= Sa # ::std::allocator
60796087
if (TD->getIdentifier()->isStr("allocator")) {
60806088
Out << "Sa";
@@ -6094,6 +6102,9 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
60946102
if (!isStdNamespace(Context.getEffectiveDeclContext(SD)))
60956103
return false;
60966104

6105+
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())
6106+
return false;
6107+
60976108
// <substitution> ::= Ss # ::std::basic_string<char,
60986109
// ::std::char_traits<char>,
60996110
// ::std::allocator<char> >

clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
11
// RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t
22
// 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
33

4-
// CHECK-DAG: @extern_var_exported = external {{(dso_local )?}}global
5-
// CHECK-DAG: @inline_var_exported = linkonce_odr {{(dso_local )?}}global
6-
// CHECK-DAG: @const_var_exported = available_externally {{(dso_local )?}}constant i32 3,
4+
// CHECK-DAG: @_ZW6Module19extern_var_exported = external {{(dso_local )?}}global
5+
// CHECK-DAG: @_ZW6Module19inline_var_exported = linkonce_odr {{(dso_local )?}}global
6+
// CHECK-DAG: @_ZW6Module18const_var_exported = available_externally {{(dso_local )?}}constant i32 3,
77
//
8-
// CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external {{(dso_local )?}}global
9-
// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global
10-
// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = available_externally {{(dso_local )?}}global i32 0,
11-
// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = available_externally {{(dso_local )?}}constant i32 3,
8+
// CHECK-DAG: @_ZW6Module25extern_var_module_linkage = external {{(dso_local )?}}global
9+
// CHECK-DAG: @_ZW6Module25inline_var_module_linkage = linkonce_odr {{(dso_local )?}}global
10+
// CHECK-DAG: @_ZW6Module25static_var_module_linkage = available_externally {{(dso_local )?}}global i32 0,
11+
// CHECK-DAG: @_ZW6Module24const_var_module_linkage = available_externally {{(dso_local )?}}constant i32 3,
1212

1313
module Module;
1414

1515
void use() {
16-
// CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv
16+
// CHECK: define linkonce_odr {{.*}}@_ZW6Module20used_inline_exportedv
1717
used_inline_exported();
18-
// CHECK: declare {{.*}}@_Z18noninline_exportedv
18+
// CHECK: declare {{.*}}@_ZW6Module18noninline_exportedv
1919
noninline_exported();
2020

2121
(void)&extern_var_exported;
2222
(void)&inline_var_exported;
2323
(void)&const_var_exported;
2424

2525
// FIXME: This symbol should not be visible here.
26-
// CHECK: declare {{.*}}@_ZW6ModuleE26used_static_module_linkagev
26+
// CHECK: declare {{.*}}@_ZW6Module26used_static_module_linkagev
2727
used_static_module_linkage();
2828

29-
// CHECK: define linkonce_odr {{.*}}@_ZW6ModuleE26used_inline_module_linkagev
29+
// CHECK: define linkonce_odr {{.*}}@_ZW6Module26used_inline_module_linkagev
3030
used_inline_module_linkage();
3131

32-
// CHECK: declare {{.*}}@_ZW6ModuleE24noninline_module_linkagev
32+
// CHECK: declare {{.*}}@_ZW6Module24noninline_module_linkagev
3333
noninline_module_linkage();
3434

3535
(void)&extern_var_module_linkage;

0 commit comments

Comments
 (0)