345 changes: 260 additions & 85 deletions clang/lib/AST/ItaniumMangle.cpp

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2193,6 +2193,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
break;

case TemplateArgument::Declaration:
VisitType(Arg.getParamTypeForDecl());
// FIXME: Do we need to recursively decompose template parameter objects?
VisitDecl(Arg.getAsDecl());
break;

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

case TemplateArgument::Integral:
Arg.getAsIntegral().Profile(ID);
VisitType(Arg.getIntegralType());
Arg.getAsIntegral().Profile(ID);
break;

case TemplateArgument::Expression:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/TemplateBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
break;

case Declaration:
getParamTypeForDecl().Profile(ID);
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
break;

Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6631,8 +6631,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;

// Create the template argument.
Converted =
TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), ParamType);
Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
S.Context.getCanonicalType(ParamType));
S.MarkAnyDeclReferenced(Arg->getBeginLoc(), Entity, false);
return false;
}
Expand Down Expand Up @@ -6753,7 +6753,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
Converted = TemplateArgument(Arg);
} else {
ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
Converted = TemplateArgument(D, ParamType);
Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
}
return Invalid;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);

E->setDecl(readDeclAs<ValueDecl>());
E->D = readDeclAs<ValueDecl>();
E->setLocation(readSourceLocation());
E->DNLoc = Record.readDeclarationNameLoc(E->getDecl()->getDeclName());
}
Expand Down
42 changes: 35 additions & 7 deletions clang/test/CodeGenCXX/clang-abi-compat.cpp
Original file line number Diff line number Diff line change
@@ -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) {}
Expand All @@ -27,3 +29,29 @@ namespace mangle_template_prefix {
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>();
6 changes: 3 additions & 3 deletions clang/test/CodeGenCXX/mangle-class-nttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ union E {
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(
Expand Down Expand Up @@ -214,10 +214,10 @@ template<H1> void f() {}
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
Expand Down
121 changes: 121 additions & 0 deletions clang/test/CodeGenCXX/mangle-template.cpp
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -221,3 +222,123 @@ namespace test16 {
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

namespace test17 {
// Ensure we mangle the types for non-type template arguments if we've lost
// track of argument / parameter correspondence.
template<int A, int ...B> struct X {};

// CHECK: define {{.*}} @_ZN6test171fILi1EJLi2ELi3ELi4EEEEvNS_1XIXT_EJLi5EXspT0_ELi6EEEE
template<int D, int ...C> void f(X<D, 5u, C..., 6u>) {}
void g() { f<1, 2, 3, 4>({}); }

// Note: there is no J...E here, because we can't form a pack argument, and
// the 5u and 6u are mangled with the original type 'j' (unsigned int) not
// with the resolved type 'i' (signed int).
// CHECK: define {{.*}} @_ZN6test171hILi4EJLi1ELi2ELi3EEEEvNS_1XIXspT0_EXLj5EEXT_EXLj6EEEE
template<int D, int ...C> void h(X<C..., 5u, D, 6u>) {}
void i() { h<4, 1, 2, 3>({}); }

#if __cplusplus >= 201402L
template<int A, const volatile int*> struct Y {};
int n;
// Case 1: &n is a resolved template argument, with a known parameter:
// mangled with no conversion.
// CXX20: define {{.*}} @_ZN6test172j1ILi1EEEvNS_1YIXT_EXadL_ZNS_1nEEEEE
template<int N> void j1(Y<N, (const int*)&n>) {}
// Case 2: &n is an unresolved template argument, with an unknown
// corresopnding parameter: mangled as the source expression.
// CXX20: define {{.*}} @_ZN6test172j2IJLi1EEEEvNS_1YIXspT_EXcvPKiadL_ZNS_1nEEEEE
template<int ...Ns> void j2(Y<Ns..., (const int*)&n>) {}
// Case 3: &n is a resolved template argument, with a known parameter, but
// for a template that can be overloaded on type: mangled with the parameter type.
// CXX20: define {{.*}} @_ZN6test172j3ILi1EEEvDTplT_clL_ZNS_1yIXcvPVKiadL_ZNS_1nEEEEEivEEE
template<const volatile int*> int y();
template<int N> void j3(decltype(N + y<(const int*)&n>())) {}
void k() {
j1<1>(Y<1, &n>());
j2<1>(Y<1, &n>());
j3<1>(0);
}
#endif
}

namespace partially_dependent_template_args {
namespace test1 {
template<bool B> struct enable { using type = int; };
template<typename ...> struct and_ { static constexpr bool value = true; };
template<typename T> inline typename enable<and_<T, T, T>::value>::type f(T) {}
// FIXME: GCC and ICC form a J...E mangling for the pack here. Clang
// doesn't do so when mangling an <unresolved-prefix>. It's not clear who's
// right. See https://github.com/itanium-cxx-abi/cxx-abi/issues/113.
// CHECK: @_ZN33partially_dependent_template_args5test11fIiEENS0_6enableIXsr4and_IT_S3_S3_EE5valueEE4typeES3_
void g() { f(0); }
}

namespace test2 {
struct X { int n; };
template<unsigned> int f(X);

template<typename T> void g1(decltype(f<0>(T()))) {}
template<typename T> void g2(decltype(f<0>({}) + T())) {}
template<typename T> void g3(decltype(f<0>(X{}) + T())) {}
template<int N> void g4(decltype(f<0>(X{N})));

// The first of these mangles the unconverted argument Li0E because the
// callee is unresolved, the rest mangle the converted argument Lj0E
// because the callee is resolved.
void h() {
// CHECK: @_ZN33partially_dependent_template_args5test22g1INS0_1XEEEvDTcl1fIXLi0EEEcvT__EEE
g1<X>({});
// CHECK: @_ZN33partially_dependent_template_args5test22g2IiEEvDTplclL_ZNS0_1fILj0EEEiNS0_1XEEilEEcvT__EE
g2<int>({});
// CHECK: @_ZN33partially_dependent_template_args5test22g3IiEEvDTplclL_ZNS0_1fILj0EEEiNS0_1XEEtlS3_EEcvT__EE
g3<int>({});
// CHECK: @_ZN33partially_dependent_template_args5test22g4ILi0EEEvDTclL_ZNS0_1fILj0EEEiNS0_1XEEtlS3_T_EEE
g4<0>({});
}
}
}

namespace fixed_size_parameter_pack {
template<typename ...T> struct A {
template<T ...> struct B {};
};
template<int ...Ns> void f(A<unsigned, char, long long>::B<0, Ns...>);
void g() { f<1, 2>({}); }
}
12 changes: 12 additions & 0 deletions clang/test/SemaTemplate/temp_arg_nontype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,15 @@ namespace type_of_pack {
}
};
}

namespace match_type_after_substitution {
template<typename T> struct X {};
X<int> y;
template<typename T, X<T> &Y> struct B {
typedef B<T, Y> Self;
};

// These two formulations should resolve to the same type.
typedef B<int, y> Z;
typedef Z::Self Z;
}
11 changes: 11 additions & 0 deletions clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ namespace Auto {
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> {};
Expand All @@ -198,6 +203,12 @@ namespace Auto {
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.
Expand Down