Skip to content

Commit 05cdf4a

Browse files
committed
Consider reference, pointer, and pointer-to-member TemplateArguments to be different if they have different types.
For the Itanium ABI, this implements the mangling rule suggested in itanium-cxx-abi/cxx-abi#47, namely mangling such template arguments as being cast to the parameter type in the case where the template name is overloadable. This can cause a mangling change for rare cases, where * the template argument declaration is converted from its declared type to the type of the template parameter, and * the template parameter either has a deduced type or is a parameter of a function template. However, such changes are necessary to avoid mangling collisions. The ABI changes can be reversed with -fclang-abi-compat=11 or earlier. Re-commit with a fix for the regression introduced last time: don't expect parameters and arguments to line up inside an <unresolved-name> mangling. Differential Revision: https://reviews.llvm.org/D91488
1 parent abbd57e commit 05cdf4a

File tree

8 files changed

+413
-98
lines changed

8 files changed

+413
-98
lines changed

clang/include/clang/Basic/LangOptions.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,10 @@ class LangOptions : public LangOptionsBase {
155155

156156
/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
157157
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
158-
/// vector member on the stack instead of using registers, and to not
159-
/// properly mangle substitutions for template names in some cases.
158+
/// vector member on the stack instead of using registers, to not properly
159+
/// mangle substitutions for template names in some cases, and to mangle
160+
/// declaration template arguments without a cast to the parameter type
161+
/// even when that can lead to mangling collisions.
160162
Ver11,
161163

162164
/// Conform to the underlying platform's C and C++ ABIs as closely

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 243 additions & 85 deletions
Large diffs are not rendered by default.

clang/lib/AST/StmtProfile.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
21932193
break;
21942194

21952195
case TemplateArgument::Declaration:
2196+
VisitType(Arg.getParamTypeForDecl());
2197+
// FIXME: Do we need to recursively decompose template parameter objects?
21962198
VisitDecl(Arg.getAsDecl());
21972199
break;
21982200

@@ -2201,8 +2203,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
22012203
break;
22022204

22032205
case TemplateArgument::Integral:
2204-
Arg.getAsIntegral().Profile(ID);
22052206
VisitType(Arg.getIntegralType());
2207+
Arg.getAsIntegral().Profile(ID);
22062208
break;
22072209

22082210
case TemplateArgument::Expression:

clang/lib/AST/TemplateBase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
244244
break;
245245

246246
case Declaration:
247+
getParamTypeForDecl().Profile(ID);
247248
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
248249
break;
249250

clang/test/CodeGenCXX/clang-abi-compat.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
// 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
2-
// 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
3-
// 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
4-
// 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
5-
// 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
6-
// 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
7-
// 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
1+
// 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
2+
// 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
3+
// 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
4+
// 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
5+
// 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
6+
// 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
7+
// 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
8+
// 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
9+
// 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
810

911
typedef __attribute__((vector_size(8))) long long v1xi64;
1012
void clang39(v1xi64) {}
@@ -27,3 +29,29 @@ namespace mangle_template_prefix {
2729
void g() { f<T>(1, 2); }
2830
}
2931

32+
int arg;
33+
template<const int *> struct clang12_unchanged {};
34+
// CHECK: @_Z4test17clang12_unchangedIXadL_Z3argEEE
35+
void test(clang12_unchanged<&arg>) {}
36+
37+
#if __cplusplus >= 201703L
38+
// PRE12-CXX17: @_Z4test15clang12_changedIXadL_Z3argEEE
39+
// V12-CXX17: @_Z4test15clang12_changedIXcvPKiadL_Z3argEEE
40+
template<auto> struct clang12_changed {};
41+
void test(clang12_changed<(const int*)&arg>) {}
42+
#endif
43+
44+
// PRE12: @_Z9clang12_aIXadL_Z3argEEEvv
45+
// V12: @_Z9clang12_aIXcvPKiadL_Z3argEEEvv
46+
template<const int *> void clang12_a() {}
47+
template void clang12_a<&arg>();
48+
49+
// PRE12: @_Z9clang12_bIXadL_Z3arrEEEvv
50+
// V12: @_Z9clang12_bIXadsoKcL_Z3arrEEEEvv
51+
extern const char arr[6] = "hello";
52+
template<const char *> void clang12_b() {}
53+
template void clang12_b<arr>();
54+
55+
// CHECK: @_Z9clang12_cIXadL_Z3arrEEEvv
56+
template<const char (*)[6]> void clang12_c() {}
57+
template void clang12_c<&arr>();

clang/test/CodeGenCXX/mangle-class-nttp.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ union E {
124124
template<E> void f() {}
125125

126126
// Union members.
127-
// CHECK: define weak_odr void @_Z1fIXL1EEEEvv(
127+
// CHECK: define weak_odr void @_Z1fIL1EEEvv(
128128
// MSABI: define {{.*}} @"??$f@$7TE@@@@@YAXXZ"
129129
template void f<E{}>();
130130
// CHECK: define weak_odr void @_Z1fIXtl1EEEEvv(
@@ -214,10 +214,10 @@ template<H1> void f() {}
214214
template<H2> void f() {}
215215
template<H3> void f() {}
216216
template<H4> void f() {}
217-
// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv
217+
// CHECK: define weak_odr void @_Z1fIL2H1EEvv
218218
// MSABI: define {{.*}} @"??$f@$7TH1@@@@@YAXXZ"
219219
template void f<H1{}>();
220-
// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv
220+
// CHECK: define weak_odr void @_Z1fIL2H2EEvv
221221
// MSABI: define {{.*}} @"??$f@$7TH2@@@@@YAXXZ"
222222
template void f<H2{}>();
223223
// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv

clang/test/CodeGenCXX/mangle-template.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++11 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
2+
// 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
23
// expected-no-diagnostics
34

45
namespace test1 {
@@ -221,3 +222,115 @@ namespace test16 {
221222
void g() { f<T>(1, 2); }
222223
}
223224

225+
#if __cplusplus >= 202002L
226+
namespace cxx20 {
227+
template<auto> struct A {};
228+
template<typename T, T V> struct B {};
229+
230+
int x;
231+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1xEEEEE(
232+
void f(A<&x>) {}
233+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPiXadL_ZNS_1xEEEEE(
234+
void f(B<int*, &x>) {}
235+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKiadL_ZNS_1xEEEEE(
236+
void f(A<(const int*)&x>) {}
237+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKiXadL_ZNS_1xEEEEE(
238+
void f(B<const int*, &x>) {}
239+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPvadL_ZNS_1xEEEEE(
240+
void f(A<(void*)&x>) {}
241+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPvXadL_ZNS_1xEEEEE(
242+
void f(B<void*, (void*)&x>) {}
243+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKvadL_ZNS_1xEEEEE(
244+
void f(A<(const void*)&x>) {}
245+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadL_ZNS_1xEEEEE(
246+
void f(B<const void*, (const void*)&x>) {}
247+
248+
struct Q { int x; };
249+
250+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1Q1xEEEEE(
251+
void f(A<&Q::x>) {}
252+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEiXadL_ZNS1_1xEEEEE
253+
void f(B<int Q::*, &Q::x>) {}
254+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvMNS_1QEKiadL_ZNS1_1xEEEEE(
255+
void f(A<(const int Q::*)&Q::x>) {}
256+
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEKiXadL_ZNS1_1xEEEEE(
257+
void f(B<const int Q::*, (const int Q::*)&Q::x>) {}
258+
}
259+
#endif
260+
261+
namespace test17 {
262+
// Ensure we mangle the types for non-type template arguments if we've lost
263+
// track of argument / parameter correspondence.
264+
template<int A, int ...B> struct X {};
265+
266+
// CHECK: define {{.*}} @_ZN6test171fILi1EJLi2ELi3ELi4EEEEvNS_1XIXT_EJLi5EXspT0_ELi6EEEE
267+
template<int D, int ...C> void f(X<D, 5u, C..., 6u>) {}
268+
void g() { f<1, 2, 3, 4>({}); }
269+
270+
// Note: there is no J...E here, because we can't form a pack argument, and
271+
// the 5u and 6u are mangled with the original type 'j' (unsigned int) not
272+
// with the resolved type 'i' (signed int).
273+
// CHECK: define {{.*}} @_ZN6test171hILi4EJLi1ELi2ELi3EEEEvNS_1XIXspT0_EXLj5EEXT_EXLj6EEEE
274+
template<int D, int ...C> void h(X<C..., 5u, D, 6u>) {}
275+
void i() { h<4, 1, 2, 3>({}); }
276+
277+
#if __cplusplus >= 201402L
278+
template<int A, const volatile int*> struct Y {};
279+
int n;
280+
// Case 1: &n is a resolved template argument, with a known parameter:
281+
// mangled with no conversion.
282+
// CXX20: define {{.*}} @_ZN6test172j1ILi1EEEvNS_1YIXT_EXadL_ZNS_1nEEEEE
283+
template<int N> void j1(Y<N, (const int*)&n>) {}
284+
// Case 2: &n is an unresolved template argument, with an unknown
285+
// corresopnding parameter: mangled as the source expression.
286+
// CXX20: define {{.*}} @_ZN6test172j2IJLi1EEEEvNS_1YIXspT_EXcvPKiadL_ZNS_1nEEEEE
287+
template<int ...Ns> void j2(Y<Ns..., (const int*)&n>) {}
288+
// Case 3: &n is a resolved template argument, with a known parameter, but
289+
// for a template that can be overloaded on type: mangled with the parameter type.
290+
// CXX20: define {{.*}} @_ZN6test172j3ILi1EEEvDTplT_clL_ZNS_1yIXcvPVKiadL_ZNS_1nEEEEEivEEE
291+
template<const volatile int*> int y();
292+
template<int N> void j3(decltype(N + y<(const int*)&n>())) {}
293+
void k() {
294+
j1<1>(Y<1, &n>());
295+
j2<1>(Y<1, &n>());
296+
j3<1>(0);
297+
}
298+
#endif
299+
}
300+
301+
namespace partially_dependent_template_args {
302+
namespace test1 {
303+
template<bool B> struct enable { using type = int; };
304+
template<typename ...> struct and_ { static constexpr bool value = true; };
305+
template<typename T> inline typename enable<and_<T, T, T>::value>::type f(T) {}
306+
// FIXME: GCC and ICC form a J...E mangling for the pack here. Clang
307+
// doesn't do so when mangling an <unresolved-prefix>. It's not clear who's
308+
// right. See https://github.com/itanium-cxx-abi/cxx-abi/issues/113.
309+
// CHECK: @_ZN33partially_dependent_template_args5test11fIiEENS0_6enableIXsr4and_IT_S3_S3_EE5valueEE4typeES3_
310+
void g() { f(0); }
311+
}
312+
313+
namespace test2 {
314+
struct X { int n; };
315+
template<unsigned> int f(X);
316+
317+
template<typename T> void g1(decltype(f<0>(T()))) {}
318+
template<typename T> void g2(decltype(f<0>({}) + T())) {}
319+
template<typename T> void g3(decltype(f<0>(X{}) + T())) {}
320+
template<int N> void g4(decltype(f<0>(X{N})));
321+
322+
// The first of these mangles the unconverted argument Li0E because the
323+
// callee is unresolved, the rest mangle the converted argument Lj0E
324+
// because the callee is resolved.
325+
void h() {
326+
// CHECK: @_ZN33partially_dependent_template_args5test22g1INS0_1XEEEvDTcl1fIXLi0EEEcvT__EEE
327+
g1<X>({});
328+
// CHECK: @_ZN33partially_dependent_template_args5test22g2IiEEvDTplclL_ZNS0_1fILj0EEEiNS0_1XEEilEEcvT__EE
329+
g2<int>({});
330+
// CHECK: @_ZN33partially_dependent_template_args5test22g3IiEEvDTplclL_ZNS0_1fILj0EEEiNS0_1XEEtlS3_EEcvT__EE
331+
g3<int>({});
332+
// CHECK: @_ZN33partially_dependent_template_args5test22g4ILi0EEEvDTclL_ZNS0_1fILj0EEEiNS0_1XEEtlS3_T_EEE
333+
g4<0>({});
334+
}
335+
}
336+
}

clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ namespace Auto {
187187
int &r = f(B<&a>());
188188
float &s = f(B<&b>());
189189

190+
void type_affects_identity(B<&a>) {}
191+
void type_affects_identity(B<(const int*)&a>) {}
192+
void type_affects_identity(B<(void*)&a>) {}
193+
void type_affects_identity(B<(const void*)&a>) {}
194+
190195
// pointers to members
191196
template<typename T, auto *T::*p> struct B<p> {};
192197
template<typename T, auto **T::*p> struct B<p> {};
@@ -198,6 +203,12 @@ namespace Auto {
198203
char &u = f(B<&X::p>());
199204
short &v = f(B<&X::pp>());
200205

206+
struct Y : X {};
207+
void type_affects_identity(B<&X::n>) {}
208+
void type_affects_identity(B<(int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
209+
void type_affects_identity(B<(const int X::*)&X::n>) {}
210+
void type_affects_identity(B<(const int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
211+
201212
// A case where we need to do auto-deduction, and check whether the
202213
// resulting dependent types match during partial ordering. These
203214
// templates are not ordered due to the mismatching function parameter.

0 commit comments

Comments
 (0)