rsmith updated this revision to Diff 310741.
rsmith added a comment.
Rebase.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D91488/new/
https://reviews.llvm.org/D91488
Files:
clang/include/clang/Basic/LangOptions.h
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/StmtProfile.cpp
clang/lib/AST/TemplateBase.cpp
clang/test/CodeGenCXX/clang-abi-compat.cpp
clang/test/CodeGenCXX/mangle-class-nttp.cpp
clang/test/CodeGenCXX/mangle-template.cpp
clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
Index: clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
===================================================================
--- clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -187,6 +187,11 @@
int &r = f(B<&a>());
float &s = f(B<&b>());
+ void type_affects_identity(B<&a>) {}
+ void type_affects_identity(B<(const int*)&a>) {}
+ void type_affects_identity(B<(void*)&a>) {}
+ void type_affects_identity(B<(const void*)&a>) {}
+
// pointers to members
template<typename T, auto *T::*p> struct B<p> {};
template<typename T, auto **T::*p> struct B<p> {};
@@ -198,6 +203,12 @@
char &u = f(B<&X::p>());
short &v = f(B<&X::pp>());
+ struct Y : X {};
+ void type_affects_identity(B<&X::n>) {}
+ void type_affects_identity(B<(int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
+ void type_affects_identity(B<(const int X::*)&X::n>) {}
+ void type_affects_identity(B<(const int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
+
// A case where we need to do auto-deduction, and check whether the
// resulting dependent types match during partial ordering. These
// templates are not ordered due to the mismatching function parameter.
Index: clang/test/CodeGenCXX/mangle-template.cpp
===================================================================
--- clang/test/CodeGenCXX/mangle-template.cpp
+++ clang/test/CodeGenCXX/mangle-template.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++11 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
+// RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++20 -emit-llvm -triple x86_64-linux-gnu -o - %s | FileCheck %s --check-prefixes=CHECK,CXX20
// expected-no-diagnostics
namespace test1 {
@@ -221,3 +222,38 @@
void g() { f<T>(1, 2); }
}
+#if __cplusplus >= 202002L
+namespace cxx20 {
+ template<auto> struct A {};
+ template<typename T, T V> struct B {};
+
+ int x;
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1xEEEEE(
+ void f(A<&x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPiXadL_ZNS_1xEEEEE(
+ void f(B<int*, &x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKiadL_ZNS_1xEEEEE(
+ void f(A<(const int*)&x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKiXadL_ZNS_1xEEEEE(
+ void f(B<const int*, &x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPvadL_ZNS_1xEEEEE(
+ void f(A<(void*)&x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPvXadL_ZNS_1xEEEEE(
+ void f(B<void*, (void*)&x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKvadL_ZNS_1xEEEEE(
+ void f(A<(const void*)&x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadL_ZNS_1xEEEEE(
+ void f(B<const void*, (const void*)&x>) {}
+
+ struct Q { int x; };
+
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1Q1xEEEEE(
+ void f(A<&Q::x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEiXadL_ZNS1_1xEEEEE
+ void f(B<int Q::*, &Q::x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvMNS_1QEKiadL_ZNS1_1xEEEEE(
+ void f(A<(const int Q::*)&Q::x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEKiXadL_ZNS1_1xEEEEE(
+ void f(B<const int Q::*, (const int Q::*)&Q::x>) {}
+}
+#endif
Index: clang/test/CodeGenCXX/mangle-class-nttp.cpp
===================================================================
--- clang/test/CodeGenCXX/mangle-class-nttp.cpp
+++ clang/test/CodeGenCXX/mangle-class-nttp.cpp
@@ -124,7 +124,7 @@
template<E> void f() {}
// Union members.
-// CHECK: define weak_odr void @_Z1fIXL1EEEEvv(
+// CHECK: define weak_odr void @_Z1fIL1EEEvv(
// MSABI: define {{.*}} @"??$f@$7TE@@@@@YAXXZ"
template void f<E{}>();
// CHECK: define weak_odr void @_Z1fIXtl1EEEEvv(
@@ -214,10 +214,10 @@
template<H2> void f() {}
template<H3> void f() {}
template<H4> void f() {}
-// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv
+// CHECK: define weak_odr void @_Z1fIL2H1EEvv
// MSABI: define {{.*}} @"??$f@$7TH1@@@@@YAXXZ"
template void f<H1{}>();
-// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv
+// CHECK: define weak_odr void @_Z1fIL2H2EEvv
// MSABI: define {{.*}} @"??$f@$7TH2@@@@@YAXXZ"
template void f<H2{}>();
// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv
Index: clang/test/CodeGenCXX/clang-abi-compat.cpp
===================================================================
--- clang/test/CodeGenCXX/clang-abi-compat.cpp
+++ clang/test/CodeGenCXX/clang-abi-compat.cpp
@@ -1,10 +1,12 @@
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=PRE39,PRE5,PRE12 %s
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefixes=PRE39,PRE5,PRE12 %s
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,PRE5,PRE12 %s
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,PRE5,PRE12 %s
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,V5,PRE12 %s
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=11 %s -emit-llvm -o - | FileCheck --check-prefixes=V11,V5,PRE12 %s
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=V39,V5,V12 %s
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,PRE5,PRE12 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,PRE5,PRE12 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=11 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17 %s
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,V12 %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,V12,V12-CXX17 %s
typedef __attribute__((vector_size(8))) long long v1xi64;
void clang39(v1xi64) {}
@@ -27,3 +29,29 @@
void g() { f<T>(1, 2); }
}
+int arg;
+template<const int *> struct clang12_unchanged {};
+// CHECK: @_Z4test17clang12_unchangedIXadL_Z3argEEE
+void test(clang12_unchanged<&arg>) {}
+
+#if __cplusplus >= 201703L
+// PRE12-CXX17: @_Z4test15clang12_changedIXadL_Z3argEEE
+// V12-CXX17: @_Z4test15clang12_changedIXcvPKiadL_Z3argEEE
+template<auto> struct clang12_changed {};
+void test(clang12_changed<(const int*)&arg>) {}
+#endif
+
+// PRE12: @_Z9clang12_aIXadL_Z3argEEEvv
+// V12: @_Z9clang12_aIXcvPKiadL_Z3argEEEvv
+template<const int *> void clang12_a() {}
+template void clang12_a<&arg>();
+
+// PRE12: @_Z9clang12_bIXadL_Z3arrEEEvv
+// V12: @_Z9clang12_bIXadsoKcL_Z3arrEEEEvv
+extern const char arr[6] = "hello";
+template<const char *> void clang12_b() {}
+template void clang12_b<arr>();
+
+// CHECK: @_Z9clang12_cIXadL_Z3arrEEEvv
+template<const char (*)[6]> void clang12_c() {}
+template void clang12_c<&arr>();
Index: clang/lib/AST/TemplateBase.cpp
===================================================================
--- clang/lib/AST/TemplateBase.cpp
+++ clang/lib/AST/TemplateBase.cpp
@@ -244,6 +244,7 @@
break;
case Declaration:
+ getParamTypeForDecl().Profile(ID);
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
break;
Index: clang/lib/AST/StmtProfile.cpp
===================================================================
--- clang/lib/AST/StmtProfile.cpp
+++ clang/lib/AST/StmtProfile.cpp
@@ -2193,6 +2193,8 @@
break;
case TemplateArgument::Declaration:
+ VisitType(Arg.getParamTypeForDecl());
+ // FIXME: Do we need to recursively decompose template parameter objects?
VisitDecl(Arg.getAsDecl());
break;
@@ -2201,8 +2203,8 @@
break;
case TemplateArgument::Integral:
- Arg.getAsIntegral().Profile(ID);
VisitType(Arg.getIntegralType());
+ Arg.getAsIntegral().Profile(ID);
break;
case TemplateArgument::Expression:
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -551,13 +551,15 @@
void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
void mangleCXXDtorType(CXXDtorType T);
- void mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs,
+ void mangleTemplateArgs(TemplateName TN,
+ const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ void mangleTemplateArgs(TemplateName TN, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateArgumentList &AL);
- void mangleTemplateArg(TemplateArgument A);
- void mangleValueInTemplateArg(QualType T, const APValue &V);
+ void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL);
+ void mangleTemplateArg(TemplateArgument A, bool NeedExactType);
+ void mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel,
+ bool NeedExactType = false);
void mangleTemplateParameter(unsigned Depth, unsigned Index);
@@ -823,6 +825,11 @@
return GlobalDecl();
}
+static TemplateName asTemplateName(GlobalDecl GD) {
+ const TemplateDecl *TD = dyn_cast_or_null<TemplateDecl>(GD.getDecl());
+ return TemplateName(const_cast<TemplateDecl*>(TD));
+}
+
void CXXNameMangler::mangleName(GlobalDecl GD) {
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
@@ -899,7 +906,7 @@
const TemplateArgumentList *TemplateArgs = nullptr;
if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) {
mangleUnscopedTemplateName(TD, AdditionalAbiTags);
- mangleTemplateArgs(*TemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
return;
}
@@ -952,7 +959,7 @@
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD, nullptr);
- mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
} else {
mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
}
@@ -1102,7 +1109,8 @@
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
+ mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
+ TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
} else if (const auto *DTST =
@@ -1115,7 +1123,7 @@
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
addSubstitution(QualType(DTST, 0));
}
} else {
@@ -1258,7 +1266,7 @@
// The <simple-id> and on <operator-name> productions end in an optional
// <template-args>.
if (TemplateArgs)
- mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(TemplateName(), TemplateArgs, NumTemplateArgs);
}
void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
@@ -1303,10 +1311,9 @@
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63.
- Out << "TAX";
+ Out << "TA";
mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(),
- TPO->getValue());
- Out << "E";
+ TPO->getValue(), /*TopLevel=*/true);
break;
}
@@ -1458,10 +1465,13 @@
case DeclarationName::CXXConstructorName: {
const CXXRecordDecl *InheritedFrom = nullptr;
+ TemplateName InheritedTemplateName;
const TemplateArgumentList *InheritedTemplateArgs = nullptr;
if (auto Inherited =
cast<CXXConstructorDecl>(ND)->getInheritedConstructor()) {
InheritedFrom = Inherited.getConstructor()->getParent();
+ InheritedTemplateName =
+ TemplateName(Inherited.getConstructor()->getPrimaryTemplate());
InheritedTemplateArgs =
Inherited.getConstructor()->getTemplateSpecializationArgs();
}
@@ -1478,7 +1488,7 @@
// FIXME: The template arguments are part of the enclosing prefix or
// nested-name, but it's more convenient to mangle them here.
if (InheritedTemplateArgs)
- mangleTemplateArgs(*InheritedTemplateArgs);
+ mangleTemplateArgs(InheritedTemplateName, *InheritedTemplateArgs);
writeAbiTags(ND, AdditionalAbiTags);
break;
@@ -1567,7 +1577,7 @@
const TemplateArgumentList *TemplateArgs = nullptr;
if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) {
mangleTemplatePrefix(TD, NoFunction);
- mangleTemplateArgs(*TemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
}
else {
manglePrefix(DC, NoFunction);
@@ -1584,7 +1594,7 @@
Out << 'N';
mangleTemplatePrefix(TD);
- mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
Out << 'E';
}
@@ -1811,8 +1821,8 @@
= cast<NamedDecl>(Context)->getIdentifier()) {
mangleSourceName(Name);
const TemplateArgumentList *TemplateArgs = nullptr;
- if (isTemplate(cast<NamedDecl>(Context), TemplateArgs))
- mangleTemplateArgs(*TemplateArgs);
+ if (GlobalDecl TD = isTemplate(cast<NamedDecl>(Context), TemplateArgs))
+ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
Out << 'M';
}
}
@@ -1903,7 +1913,7 @@
const TemplateArgumentList *TemplateArgs = nullptr;
if (GlobalDecl TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
- mangleTemplateArgs(*TemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
} else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
mangleUnqualifiedName(ND, nullptr);
@@ -2162,7 +2172,7 @@
}
}
- mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
+ mangleTemplateArgs(TN, TST->getArgs(), TST->getNumArgs());
break;
}
@@ -2178,8 +2188,10 @@
case Type::DependentTemplateSpecialization: {
const DependentTemplateSpecializationType *DTST =
cast<DependentTemplateSpecializationType>(Ty);
+ TemplateName Template = getASTContext().getDependentTemplateName(
+ DTST->getQualifier(), DTST->getIdentifier());
mangleSourceName(DTST->getIdentifier());
- mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
break;
}
@@ -3507,8 +3519,8 @@
Out << "u" << VendorQualifier.size() << VendorQualifier;
Out << "I";
- mangleTemplateArg(T->getRowExpr());
- mangleTemplateArg(T->getColumnExpr());
+ mangleTemplateArg(T->getRowExpr(), false);
+ mangleTemplateArg(T->getColumnExpr(), false);
mangleType(T->getElementType());
Out << "E";
}
@@ -3581,7 +3593,7 @@
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
addSubstitution(QualType(T, 0));
}
}
@@ -3633,7 +3645,7 @@
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs());
Out << 'E';
}
@@ -3733,7 +3745,7 @@
llvm::APSInt BW(32, true);
BW = T->getNumBits();
TemplateArgument TA(Context.getASTContext(), BW, getASTContext().IntTy);
- mangleTemplateArgs(&TA, 1);
+ mangleTemplateArgs(TemplateName(), &TA, 1);
if (T->isUnsigned())
Out << "j";
else
@@ -3743,7 +3755,7 @@
void CXXNameMangler::mangleType(const DependentExtIntType *T) {
Out << "U7_ExtInt";
TemplateArgument TA(T->getNumBitsExpr());
- mangleTemplateArgs(&TA, 1);
+ mangleTemplateArgs(TemplateName(), &TA, 1);
if (T->isUnsigned())
Out << "j";
else
@@ -4632,7 +4644,7 @@
if (SPE->isPartiallySubstituted()) {
Out << "sP";
for (const auto &A : SPE->getPartialArguments())
- mangleTemplateArg(A);
+ mangleTemplateArg(A, false);
Out << "E";
break;
}
@@ -4820,33 +4832,71 @@
}
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs,
+namespace {
+// Helper to provide ancillary information on a template used to mangle its
+// arguments.
+struct TemplateArgManglingInfo {
+ TemplateDecl *ResolvedTemplate = nullptr;
+
+ TemplateArgManglingInfo(TemplateName TN) {
+ if (TemplateDecl *TD = TN.getAsTemplateDecl())
+ ResolvedTemplate = TD;
+ }
+
+ /// Do we need to mangle template arguments with exactly correct types?
+ bool needExactType(unsigned I) const {
+ // We need correct types when the template-name is unresolved or when it
+ // names a template that is able to be overloaded.
+ if (!ResolvedTemplate)
+ return true;
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ResolvedTemplate)) {
+ auto *RD = dyn_cast<CXXRecordDecl>(FTD->getDeclContext());
+ if (!RD || !RD->isGenericLambda())
+ return true;
+ }
+
+ // Otherwise, we only need a correct type if the parameter has a deduced
+ // type.
+ auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(
+ ResolvedTemplate->getTemplateParameters()->getParam(I));
+ return NTTP && NTTP->getType()->getContainedDeducedType();
+ }
+};
+}
+
+void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
+ const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
+ TemplateArgManglingInfo Info(TN);
for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(TemplateArgs[i].getArgument());
+ mangleTemplateArg(TemplateArgs[i].getArgument(), Info.needExactType(i));
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) {
+void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
+ const TemplateArgumentList &AL) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
+ TemplateArgManglingInfo Info(TN);
for (unsigned i = 0, e = AL.size(); i != e; ++i)
- mangleTemplateArg(AL[i]);
+ mangleTemplateArg(AL[i], Info.needExactType(i));
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
+ const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
+ TemplateArgManglingInfo Info(TN);
for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(TemplateArgs[i]);
+ mangleTemplateArg(TemplateArgs[i], Info.needExactType(i));
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
+void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
@@ -4900,28 +4950,30 @@
// Template parameter objects are modeled by reproducing a source form
// produced as if by aggregate initialization.
if (A.getParamTypeForDecl()->isRecordType()) {
- Out << 'X';
auto *TPO = cast<TemplateParamObjectDecl>(D);
mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(),
- TPO->getValue());
- Out << 'E';
+ TPO->getValue(), /*TopLevel=*/true,
+ NeedExactType);
break;
}
- // Clang produces AST's where pointer-to-member-function expressions
- // and pointer-to-function expressions are represented as a declaration not
- // an expression. We compensate for it here to produce the correct mangling.
- bool compensateMangling = !A.getParamTypeForDecl()->isReferenceType();
- if (compensateMangling) {
- Out << 'X';
- mangleOperatorName(OO_Amp, 1);
- }
-
- mangleDeclRefExpr(D);
-
- if (compensateMangling)
- Out << 'E';
-
+ ASTContext &Ctx = Context.getASTContext();
+ APValue Value;
+ if (D->isCXXInstanceMember())
+ Value = APValue(D, false, {});
+ else if (D->getType()->isArrayType() &&
+ Ctx.hasSimilarType(Ctx.getDecayedType(D->getType()),
+ A.getParamTypeForDecl()) &&
+ Ctx.getLangOpts().getClangABICompat() >
+ LangOptions::ClangABI::Ver11)
+ // Build a value corresponding to this implicit array-to-pointer decay.
+ Value = APValue(APValue::LValueBase(D), CharUnits::Zero(),
+ {APValue::LValuePathEntry::ArrayIndex(0)}, false);
+ else
+ Value = APValue(APValue::LValueBase(D), CharUnits::Zero(),
+ ArrayRef<APValue::LValuePathEntry>(), false);
+ mangleValueInTemplateArg(A.getParamTypeForDecl(), Value, /*TopLevel=*/true,
+ NeedExactType);
break;
}
case TemplateArgument::NullPtr: {
@@ -4932,7 +4984,7 @@
// <template-arg> ::= J <template-arg>* E
Out << 'J';
for (const auto &P : A.pack_elements())
- mangleTemplateArg(P);
+ mangleTemplateArg(P, NeedExactType);
Out << 'E';
}
}
@@ -5028,11 +5080,36 @@
llvm_unreachable("Unhandled APValue::ValueKind enum");
}
-void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
+static QualType getLValueType(ASTContext &Ctx, const APValue &LV) {
+ QualType T = LV.getLValueBase().getType();
+ for (APValue::LValuePathEntry E : LV.getLValuePath()) {
+ if (const ArrayType *AT = Ctx.getAsArrayType(T))
+ T = AT->getElementType();
+ else if (const FieldDecl *FD =
+ dyn_cast<FieldDecl>(E.getAsBaseOrMember().getPointer()))
+ T = FD->getType();
+ else
+ T = Ctx.getRecordType(
+ cast<CXXRecordDecl>(E.getAsBaseOrMember().getPointer()));
+ }
+ return T;
+}
+
+void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
+ bool TopLevel,
+ bool NeedExactType) {
// Ignore all top-level cv-qualifiers, to match GCC.
Qualifiers Quals;
T = getASTContext().getUnqualifiedArrayType(T, Quals);
+ // A top-level expression that's not a primary expression is wrapped in X...E.
+ bool IsPrimaryExpr = true;
+ auto NotPrimaryExpr = [&] {
+ if (TopLevel && IsPrimaryExpr)
+ Out << 'X';
+ IsPrimaryExpr = false;
+ };
+
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63.
switch (V.getKind()) {
case APValue::None:
@@ -5040,7 +5117,7 @@
Out << 'L';
mangleType(T);
Out << 'E';
- return;
+ break;
case APValue::AddrLabelDiff:
llvm_unreachable("unexpected value kind in template argument");
@@ -5068,18 +5145,20 @@
}
// <expression> ::= tl <type> <braced-expression>* E
+ NotPrimaryExpr();
Out << "tl";
mangleType(T);
for (unsigned I = 0, N = Bases.size(); I != N; ++I)
- mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I));
+ mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I), false);
for (unsigned I = 0, N = Fields.size(); I != N; ++I) {
if (Fields[I]->isUnnamedBitfield())
continue;
mangleValueInTemplateArg(Fields[I]->getType(),
- V.getStructField(Fields[I]->getFieldIndex()));
+ V.getStructField(Fields[I]->getFieldIndex()),
+ false);
}
Out << 'E';
- return;
+ break;
}
case APValue::Union: {
@@ -5090,24 +5169,26 @@
Out << 'L';
mangleType(T);
Out << 'E';
- return;
+ break;
}
// <braced-expression> ::= di <field source-name> <braced-expression>
+ NotPrimaryExpr();
Out << "tl";
mangleType(T);
if (!isZeroInitialized(T, V)) {
Out << "di";
mangleSourceName(FD->getIdentifier());
- mangleValueInTemplateArg(FD->getType(), V.getUnionValue());
+ mangleValueInTemplateArg(FD->getType(), V.getUnionValue(), false);
}
Out << 'E';
- return;
+ break;
}
case APValue::Array: {
QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0);
+ NotPrimaryExpr();
Out << "tl";
mangleType(T);
@@ -5123,40 +5204,42 @@
const APValue &Elem = I < V.getArrayInitializedElts()
? V.getArrayInitializedElt(I)
: V.getArrayFiller();
- mangleValueInTemplateArg(ElemT, Elem);
+ mangleValueInTemplateArg(ElemT, Elem, false);
}
Out << 'E';
- return;
+ break;
}
case APValue::Vector: {
const VectorType *VT = T->castAs<VectorType>();
+ NotPrimaryExpr();
Out << "tl";
mangleType(T);
unsigned N = V.getVectorLength();
while (N && isZeroInitialized(VT->getElementType(), V.getVectorElt(N - 1)))
--N;
for (unsigned I = 0; I != N; ++I)
- mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I));
+ mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I), false);
Out << 'E';
- return;
+ break;
}
case APValue::Int:
mangleIntegerLiteral(T, V.getInt());
- return;
+ break;
case APValue::Float:
mangleFloatLiteral(T, V.getFloat());
- return;
+ break;
case APValue::FixedPoint:
mangleFixedPointLiteral();
- return;
+ break;
case APValue::ComplexFloat: {
const ComplexType *CT = T->castAs<ComplexType>();
+ NotPrimaryExpr();
Out << "tl";
mangleType(T);
if (!V.getComplexFloatReal().isPosZero() ||
@@ -5165,11 +5248,12 @@
if (!V.getComplexFloatImag().isPosZero())
mangleFloatLiteral(CT->getElementType(), V.getComplexFloatImag());
Out << 'E';
- return;
+ break;
}
case APValue::ComplexInt: {
const ComplexType *CT = T->castAs<ComplexType>();
+ NotPrimaryExpr();
Out << "tl";
mangleType(T);
if (V.getComplexIntReal().getBoolValue() ||
@@ -5178,7 +5262,7 @@
if (V.getComplexIntImag().getBoolValue())
mangleIntegerLiteral(CT->getElementType(), V.getComplexIntImag());
Out << 'E';
- return;
+ break;
}
case APValue::LValue: {
@@ -5188,7 +5272,7 @@
if (V.isNullPointer()) {
mangleNullPointer(T);
- return;
+ break;
}
APValue::LValueBase B = V.getLValueBase();
@@ -5199,54 +5283,82 @@
if (Offset.isZero()) {
// This is reinterpret_cast<T*>(0), not a null pointer. Mangle this as
// a cast, because L <type> 0 E means something else.
+ NotPrimaryExpr();
Out << "rc";
mangleType(T);
Out << "Li0E";
+ if (TopLevel)
+ Out << 'E';
} else {
Out << "L";
mangleType(T);
Out << Offset.getQuantity() << 'E';
}
- return;
+ break;
}
+ ASTContext &Ctx = Context.getASTContext();
+
enum { Base, Offset, Path } Kind;
if (!V.hasLValuePath()) {
// Mangle as (T*)((char*)&base + N).
if (T->isReferenceType()) {
+ NotPrimaryExpr();
Out << "decvP";
mangleType(T->getPointeeType());
} else {
+ NotPrimaryExpr();
Out << "cv";
mangleType(T);
}
Out << "plcvPcad";
Kind = Offset;
} else {
- if (T->isPointerType())
- Out << "ad";
if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) {
+ NotPrimaryExpr();
+ // A final conversion to the template parameter's type is usually
+ // folded into the 'so' mangling, but we can't do that for 'void*'
+ // parameters without introducing collisions.
+ if (NeedExactType && T->isVoidPointerType()) {
+ Out << "cv";
+ mangleType(T);
+ }
+ if (T->isPointerType())
+ Out << "ad";
Out << "so";
- mangleType(T->getPointeeType());
+ mangleType(T->isVoidPointerType()
+ ? getLValueType(Ctx, V).getUnqualifiedType()
+ : T->getPointeeType());
Kind = Path;
} else {
+ if (NeedExactType &&
+ !Ctx.hasSameType(T->getPointeeType(), getLValueType(Ctx, V)) &&
+ Ctx.getLangOpts().getClangABICompat() >
+ LangOptions::ClangABI::Ver11) {
+ NotPrimaryExpr();
+ Out << "cv";
+ mangleType(T);
+ }
+ if (T->isPointerType()) {
+ NotPrimaryExpr();
+ Out << "ad";
+ }
Kind = Base;
}
}
- QualType TypeSoFar;
+ QualType TypeSoFar = B.getType();
if (auto *VD = B.dyn_cast<const ValueDecl*>()) {
Out << 'L';
mangle(VD);
Out << 'E';
- TypeSoFar = VD->getType();
} else if (auto *E = B.dyn_cast<const Expr*>()) {
+ NotPrimaryExpr();
mangleExpression(E);
- TypeSoFar = E->getType();
} else if (auto TI = B.dyn_cast<TypeInfoLValue>()) {
+ NotPrimaryExpr();
Out << "ti";
mangleType(QualType(TI.getType(), 0));
- TypeSoFar = B.getTypeInfoType();
} else {
// We should never see dynamic allocations here.
llvm_unreachable("unexpected lvalue base kind in template argument");
@@ -5258,7 +5370,7 @@
case Offset:
Out << 'L';
- mangleType(Context.getASTContext().getPointerDiffType());
+ mangleType(Ctx.getPointerDiffType());
mangleNumber(V.getLValueOffset().getQuantity());
Out << 'E';
break;
@@ -5289,8 +5401,7 @@
}
TypeSoFar = FD->getType();
} else {
- TypeSoFar =
- Context.getASTContext().getRecordType(cast<CXXRecordDecl>(D));
+ TypeSoFar = Ctx.getRecordType(cast<CXXRecordDecl>(D));
}
}
}
@@ -5301,19 +5412,30 @@
break;
}
- return;
+ break;
}
case APValue::MemberPointer:
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
if (!V.getMemberPointerDecl()) {
mangleNullPointer(T);
- return;
+ break;
}
+ ASTContext &Ctx = Context.getASTContext();
+
+ NotPrimaryExpr();
if (!V.getMemberPointerPath().empty()) {
Out << "mc";
mangleType(T);
+ } else if (NeedExactType &&
+ !Ctx.hasSameType(
+ T->castAs<MemberPointerType>()->getPointeeType(),
+ V.getMemberPointerDecl()->getType()) &&
+ Ctx.getLangOpts().getClangABICompat() >
+ LangOptions::ClangABI::Ver11) {
+ Out << "cv";
+ mangleType(T);
}
Out << "adL";
mangle(V.getMemberPointerDecl());
@@ -5325,8 +5447,11 @@
mangleNumber(Offset.getQuantity());
Out << 'E';
}
- return;
+ break;
}
+
+ if (TopLevel && !IsPrimaryExpr)
+ Out << 'E';
}
void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -155,8 +155,10 @@
/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
- /// vector member on the stack instead of using registers, and to not
- /// properly mangle substitutions for template names in some cases.
+ /// vector member on the stack instead of using registers, to not properly
+ /// mangle substitutions for template names in some cases, and to mangle
+ /// declaration template arguments without a cast to the parameter type
+ /// even when that can lead to mangling collisions.
Ver11,
/// Conform to the underlying platform's C and C++ ABIs as closely
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits