rsmith updated this revision to Diff 303611.
rsmith marked an inline comment as done.
rsmith added a comment.

- Factor out duplicated mangling of null pointers.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D89998/new/

https://reviews.llvm.org/D89998

Files:
  clang/lib/AST/APValue.cpp
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/MicrosoftMangle.cpp
  clang/test/CodeGenCXX/mangle-class-nttp.cpp
  clang/test/CodeGenCXX/mangle-ms-templates.cpp
  clang/test/CodeGenCXX/template-param-objects.cpp

Index: clang/test/CodeGenCXX/template-param-objects.cpp
===================================================================
--- clang/test/CodeGenCXX/template-param-objects.cpp
+++ clang/test/CodeGenCXX/template-param-objects.cpp
@@ -1,12 +1,19 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=ITANIUM,CHECK
+// RUN: %clang_cc1 -triple x86_64-windows -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=MSABI,CHECK
 
 struct S { char buf[32]; };
 template<S s> constexpr const char *begin() { return s.buf; }
 template<S s> constexpr const char *end() { return s.buf + __builtin_strlen(s.buf); }
 
-// CHECK: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]] = linkonce_odr constant { <{ [11 x i8], [21 x i8] }> } { <{ [11 x i8], [21 x i8] }> <{ [11 x i8] c"hello world", [21 x i8] zeroinitializer }> }, comdat
+// ITANIUM: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]]
+// MSABI: [[HELLO:@"[?][?]__N2US@@3D0GI@@0GF@@0GM@@0GM@@0GP@@0CA@@0HH@@0GP@@0HC@@0GM@@0GE@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@"]]
+// CHECK-SAME: = linkonce_odr constant { <{ [11 x i8], [21 x i8] }> } { <{ [11 x i8], [21 x i8] }> <{ [11 x i8] c"hello world", [21 x i8] zeroinitializer }> }, comdat
 
-// CHECK: @p = global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0)
+// ITANIUM: @p
+// MSABI: @"?p@@3PEBDEB"
+// CHECK-SAME: global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0)
 const char *p = begin<S{"hello world"}>();
-// CHECK: @q = global i8* getelementptr (i8, i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0), i64 11)
+// ITANIUM: @q
+// MSABI: @"?q@@3PEBDEB"
+// CHECK-SAME: global i8* getelementptr (i8, i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0), i64 11)
 const char *q = end<S{"hello world"}>();
Index: clang/test/CodeGenCXX/mangle-ms-templates.cpp
===================================================================
--- clang/test/CodeGenCXX/mangle-ms-templates.cpp
+++ clang/test/CodeGenCXX/mangle-ms-templates.cpp
@@ -310,3 +310,20 @@
 template struct UUIDType4<&__uuidof(uuid)>;
 // CHECK: "?bar@?$UUIDType4@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ"
 // CHECK: "?foo@?$UUIDType3@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ"
+
+#ifdef _WIN64
+template<__int128 N> struct Int128 {};
+template<unsigned __int128 N> struct UInt128 {};
+// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0A@@@@Z"(
+void fun_int128(Int128<0>) {}
+// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0?0@@@Z"(
+void fun_int128(Int128<-1>) {}
+// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"(
+void fun_int128(Int128<(__int128)9223372036854775807 * (__int128)9223372036854775807>) {}
+// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0A@@@@Z"(
+void fun_uint128(UInt128<0>) {}
+// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0?0@@@Z"(
+void fun_uint128(UInt128<(unsigned __int128)-1>) {}
+// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"(
+void fun_uint128(UInt128<(unsigned __int128)9223372036854775807 * (unsigned __int128)9223372036854775807>) {}
+#endif
Index: clang/test/CodeGenCXX/mangle-class-nttp.cpp
===================================================================
--- clang/test/CodeGenCXX/mangle-class-nttp.cpp
+++ clang/test/CodeGenCXX/mangle-class-nttp.cpp
@@ -1,75 +1,111 @@
 // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-windows -emit-llvm -o - | FileCheck %s --check-prefix=MSABI
 
 #define fold(x) (__builtin_constant_p(x) ? (x) : (x))
 
-struct A { int a, b; };
+struct A { int a; const int b; };
 template<A> void f() {}
 
 // CHECK: define weak_odr void @_Z1fIXtl1ALi1ELi2EEEEvv(
+// MSABI: define {{.*}} @"??$f@$2UA@@H00$$CBH01@@@YAXXZ"
 template void f<A{1, 2}>();
 
-struct B { int *p; int k; };
+struct B { const int *p; int k; };
 template<B> void f() {}
 
 int n = 0;
 // CHECK: define weak_odr void @_Z1fIXtl1BadL_Z1nEEEEvv(
+// MSABI: define {{.*}} @"??$f@$2UB@@PEBH1?n@@3HAH0A@@@@YAXXZ"
 template void f<B{&n}>();
-// CHECK: define weak_odr void @_Z1fIXtl1BLPi0ELi1EEEEvv(
+// CHECK: define weak_odr void @_Z1fIXtl1BLPKi0ELi1EEEEvv(
+// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H00@@@YAXXZ"
 template void f<B{nullptr, 1}>();
 // CHECK: define weak_odr void @_Z1fIXtl1BEEEvv(
+// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H0A@@@@YAXXZ"
 template void f<B{nullptr}>();
-// CHECK: define weak_odr void @_Z1fIXtl1BLPi32EEEEvv(
+#ifndef _WIN32
+// FIXME: MSVC crashes on the first of these and mangles the second the same as
+// the nullptr version. Check the output is correct once we have a reference to
+// compare against.
+// CHECK: define weak_odr void @_Z1fIXtl1BLPKi32EEEEvv(
 template void f<B{fold((int*)32)}>();
-// CHECK: define weak_odr void @_Z1fIXtl1BrcPiLi0EEEEEvv(
+// CHECK: define weak_odr void @_Z1fIXtl1BrcPKiLi0EEEEvv(
 template void f<B{fold(reinterpret_cast<int*>(0))}>();
+#endif
 
 // Pointers to subobjects.
 struct Nested { union { int k; int arr[2]; }; } nested[2];
-struct Derived : A, Nested {} derived;
-// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z6nestedE_EEEEvv
+struct Derived : A, Nested { int z; } extern derived;
+#ifndef _WIN32
+// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE_EEEEvv
+// FIXME: MSVC generates the garbage mangling ??$f@$2UB@@PEAH0A@H0A@@@@YAXXZ
+// for this.
 template void f<B{&nested[0].k}>();
-// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z6nestedE16_0pEEEEvv
+// FIXME: MSVC crashes on these.
+// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE16_0pEEEEvv
 template void f<B{&nested[1].arr[2]}>();
-// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z7derivedE8pEEEEvv
+// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE8pEEEEvv
 template void f<B{&derived.b + 1}>();
-// CHECK: define weak_odr void @_Z1fIXtl1BcvPiplcvPcadL_Z7derivedELl16EEEEvv
+// CHECK: define weak_odr void @_Z1fIXtl1BcvPKiplcvPcadL_Z7derivedELl16EEEEvv
 template void f<B{fold(&derived.b + 3)}>();
+#endif
 
 // References to subobjects.
-struct BR { int &r; };
+struct BR { const int &r; };
 template<BR> void f() {}
-// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z6nestedE_EEEEvv
+#ifndef _WIN32
+// FIXME: MSVC produces garbage manglings for these.
+// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE_EEEEvv
 template void f<BR{nested[0].k}>();
-// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z6nestedE12_0EEEEvv
+// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE12_0EEEEvv
 template void f<BR{nested[1].arr[1]}>();
-// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z7derivedE4EEEEvv
+// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE4EEEEvv
 template void f<BR{derived.b}>();
-// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPiplcvPcadL_Z7derivedELl16EEEEvv
+// FIXME: Crashes MSVC.
+// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPKiplcvPcadL_Z7derivedELl16EEEEvv
 template void f<BR{fold(*(&derived.b + 3))}>();
+#endif
 
 // Qualification conversions.
 struct C { const int *p; };
 template<C> void f() {}
+#ifndef _WIN32
+// FIXME: MSVC produces a garbage mangling for this.
 // CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv
 template void f<C{&derived.b}>();
+#endif
 
 // Pointers to members.
 struct D { const int Derived::*p; int k; };
 template<D> void f() {}
 // CHECK: define weak_odr void @_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H00@@@YAXXZ"
 template void f<D{nullptr, 1}>();
 // CHECK: define weak_odr void @_Z1fIXtl1DEEEvv
+// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H0A@@@@YAXXZ"
 template void f<D{nullptr}>();
+// CHECK: define weak_odr void @_Z1fIXtl1DadL_ZN7Derived1zEEEEEvv
+// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BA@H0A@@@@YAXXZ"
+template void f<D{&Derived::z}>();
+#ifndef _WIN32
 // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1aEEEEEEvv
+// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H0A@@@@YAXXZ"
 template void f<D{&A::a}>();
 // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1bEEEEEEvv
+// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H03H0A@@@@YAXXZ"
 template void f<D{&A::b}>();
 // FIXME: Is the Ut_1 mangling here correct?
-// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8EEEEvv
-template void f<D{&Nested::k}>();
+// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8ELi2EEEEvv
+// FIXME: This mangles the same as &A::a (bug in the MS ABI).
+// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H01@@@YAXXZ"
+template void f<D{&Nested::k, 2}>();
 struct MoreDerived : A, Derived { int z; };
 // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv
+// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BI@H0A@@@@YAXXZ"
 template void f<D{(int Derived::*)&MoreDerived::z}>();
+#endif
+
+// FIXME: Pointers to member functions.
 
 union E {
   int n;
@@ -82,20 +118,47 @@
 
 // Union members.
 // CHECK: define weak_odr void @_Z1fIXL1EEEEvv(
+// FIXME: MSVC rejects this; check this is the mangling MSVC uses when they
+// start accepting.
+// MSABI: define {{.*}} @"??$f@$2TE@@@@@YAXXZ"
 template void f<E{}>();
 // CHECK: define weak_odr void @_Z1fIXtl1EEEEvv(
+// MSABI: define {{.*}} @"??$f@$2TE@@H0A@@@@YAXXZ"
 template void f<E(0)>();
 // CHECK: define weak_odr void @_Z1fIXtl1Edi1nLi42EEEEvv(
+// MSABI: define {{.*}} @"??$f@$2TE@@H0CK@@@@YAXXZ"
 template void f<E(42)>();
 // CHECK: define weak_odr void @_Z1fIXtl1Edi1fLf00000000EEEEvv(
+// MSABI: define {{.*}} @"??$f@$2TE@@MAA@@@@YAXXZ"
 template void f<E(0.f)>();
 
+// immintrin.h vector types.
+typedef float __m128 __attribute__((__vector_size__(16)));
+typedef double __m128d __attribute__((__vector_size__(16)));
+typedef long long __m128i __attribute__((__vector_size__(16)));
+struct M128 { __m128 a; };
+struct M128D { __m128d b; };
+struct M128I { __m128i c; };
+template<M128> void f() {}
+template<M128D> void f() {}
+template<M128I> void f() {}
+// MSABI: define {{.*}} @"??$f@$2UM128@@2T__m128@@3MADPIAAAAA@@AEAAAAAAA@@AEAEAAAAA@@AEAIAAAAA@@@@@@@YAXXZ"
+template void f<M128{1, 2, 3, 4}>();
+// MSABI: define {{.*}} @"??$f@$2UM128D@@2U__m128d@@3NBDPPAAAAAAAAAAAAA@@BEAAAAAAAAAAAAAAA@@@@@@@YAXXZ"
+template void f<M128D{1, 2}>();
+// FIXME: We define __m128i as a vector of long long, whereas MSVC appears to
+// mangle it as if it were a vector of char.
+// MSABI-FIXME: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3D00@01@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@@@YAXXZ"
+// MSABI: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3_J00@01@@@@@@YAXXZ"
+template void f<M128I{1, 2}>();
+
 // Extensions, and dropping trailing zero-initialized elements of 'tl'
 // manglings.
 typedef int __attribute__((ext_vector_type(3))) VI3;
 struct F { VI3 v; _Complex int ci; _Complex float cf; };
 template<F> void f() {}
 // CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000ELf40e00000EEEEEvv
+// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H00@01@02@@@2U?$_Complex@H@3@0304@2U?$_Complex@M@3@AEAMAAAAA@AEAOAAAAA@@@@@YAXXZ"
 template void f<F{{1, 2, 3}, {4, 5}, {6, 7}}>();
 // CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000EEEEEvv
 template void f<F{{1, 2, 3}, {4, 5}, {6, 0}}>();
@@ -110,4 +173,171 @@
 // CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1EEEEEvv
 template void f<F{{1, 0, 0}, {0, 0}, {0, 0}}>();
 // CHECK: define weak_odr void @_Z1fIXtl1FEEEvv
+// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H0A@@0A@@0A@@@@2U?$_Complex@H@3@0A@0A@@2U?$_Complex@M@3@AA@AA@@@@@YAXXZ"
 template void f<F{{0, 0, 0}, {0, 0}, {0, 0}}>();
+
+// Unnamed bit-fields.
+struct G {
+  int : 3;
+  int a : 4;
+  int : 5;
+  int b : 6;
+  int : 7;
+};
+template<G> void f() {}
+// CHECK: define weak_odr void @_Z1fIXtl1GEEEvv
+// MSABI: define {{.*}} @"??$f@$2UG@@H0A@H0A@@@@YAXXZ"
+template void f<(G())>();
+// CHECK: define weak_odr void @_Z1fIXtl1GLi1EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UG@@H00H0A@@@@YAXXZ"
+template void f<G{1}>();
+// CHECK: define weak_odr void @_Z1fIXtl1GLi1ELi2EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UG@@H00H01@@@YAXXZ"
+template void f<G{1, 2}>();
+// CHECK: define weak_odr void @_Z1fIXtl1GLin8ELin32EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UG@@H0?7H0?CA@@@@YAXXZ"
+template void f<G{-8, -32}>();
+
+// Empty and nearly-empty unions.
+// Some of the MSVC manglings here are our invention, because MSVC rejects, but
+// seem likely to be right.
+union H1 {};
+union H2 { int : 1, : 2, : 3; };
+union H3 { int : 1, a, : 2, b, : 3; };
+struct H4 { H2 h2; };
+template<H1> void f() {}
+template<H2> void f() {}
+template<H3> void f() {}
+template<H4> void f() {}
+// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv
+// MSABI: define {{.*}} @"??$f@$2TH1@@@@@YAXXZ"
+template void f<H1{}>();
+// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv
+// MSABI: define {{.*}} @"??$f@$2TH2@@@@@YAXXZ"
+template void f<H2{}>();
+// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv
+// MSABI: define {{.*}} @"??$f@$2TH3@@H0A@@@@YAXXZ"
+template void f<H3{.a = 0}>();
+// CHECK: define weak_odr void @_Z1fIXtl2H3di1aLi1EEEEvv
+// MSABI: define {{.*}} @"??$f@$2TH3@@H00@@@YAXXZ"
+template void f<H3{.a = 1}>();
+// FIXME: Leads to mangling collision under MS ABI; same mangling as the {.a = 0} case.
+#ifndef _WIN32
+// CHECK: define weak_odr void @_Z1fIXtl2H3di1bLi0EEEEvv
+template void f<H3{.b = 0}>();
+#endif
+// CHECK: define weak_odr void @_Z1fIXtl2H4EEEvv
+// MSABI: define {{.*}} @"??$f@$2UH4@@2TH2@@@@@@YAXXZ"
+template void f<H4{}>();
+
+// Floating-point.
+struct I {
+  float f;
+  double d;
+  long double ld;
+};
+template<I> void f() {}
+// CHECK: define weak_odr void @_Z1fIXtl1IEEEvv
+// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OBA@@@@YAXXZ"
+template void f<I{0.0, 0.0, 0.0}>();
+// CHECK: define weak_odr void @_Z1fIXtl1ILf80000000ELd8000000000000000ELe80000000000000000000EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UI@@MAIAAAAAAA@NBIAAAAAAAAAAAAAAA@OBIAAAAAAAAAAAAAAA@@@@YAXXZ"
+template void f<I{-0.0, -0.0, -0.0}>();
+// CHECK: define weak_odr void @_Z1fIXtl1ILf3f800000ELd4000000000000000ELec000c000000000000000EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UI@@MADPIAAAAA@NBEAAAAAAAAAAAAAAA@OBMAAIAAAAAAAAAAAA@@@@YAXXZ"
+template void f<I{1.0, 2.0, -3.0}>();
+// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000000ELe3bcd8000000000000000EEEEvv
+// Note that "small integer" special-case manglings 'A@', '0', '1', ... are
+// used here and represent tiny denormal values!
+// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OB0@@@YAXXZ"
+template void f<I{0.0, 0.2e-323, 0.5e-323}>();
+// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000002ELebbce8000000000000000EEEEvv
+// ... but the special-case '?' mangling for bit 63 being set is not used.
+// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NB1OBIAAAAAAAAAAAAAAC@@@@YAXXZ"
+template void f<I{0.0, 1.0e-323, -1.0e-323}>();
+
+// Base classes and members of class type.
+struct J1 { int a, b; };
+struct JEmpty {};
+struct J2 { int c, d; };
+struct J : J1, JEmpty, J2 { int e; };
+template<J> void f() {}
+// CHECK: define weak_odr void @_Z1fIXtl1JEEEvv
+// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H0A@H0A@@2UJEmpty@@@2UJ2@@H0A@H0A@@H0A@@@@YAXXZ"
+template void f<J{}>();
+// CHECK: define weak_odr void @_Z1fIXtl1Jtl2J1Li1ELi2EEtl6JEmptyEtl2J2Li3ELi4EELi5EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H00H01@2UJEmpty@@@2UJ2@@H02H03@H04@@@YAXXZ"
+template void f<J{{1, 2}, {}, {3, 4}, 5}>();
+
+struct J3 { J1 j1; };
+template<J3> void f() {}
+// CHECK: define {{.*}} @_Z1fIXtl2J3tl2J1Li1ELi2EEEEEvv
+// MSABI: define {{.*}} @"??$f@$2UJ3@@2UJ1@@H00H01@@@@YAXXZ"
+template void f<J3{1, 2}>();
+
+// Arrays.
+struct K { int n[2][3]; };
+template<K> void f() {}
+// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2EEEEEEvv
+// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@0A@@@@3H0A@@0A@@0A@@@@@@@@YAXXZ"
+template void f<K{1, 2}>();
+// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2ELi3EEtlS1_Li4ELi5ELi6EEEEEEvv
+// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@02@@@3H03@04@05@@@@@@@YAXXZ"
+template void f<K{1, 2, 3, 4, 5, 6}>();
+
+struct K1 { int a, b; };
+struct K2 : K1 { int c; };
+struct K3 { K2 k2[2]; };
+template<K3> void f() {}
+// CHECK: define {{.*}} @_Z1fIXtl2K3tlA2_2K2tlS1_tl2K1Li1EEEEEEEvv
+// MSABI: define {{.*}} @"??$f@$2UK3@@3UK2@@2U2@2UK1@@H00H0A@@H0A@@@2U2@2U3@H0A@H0A@@H0A@@@@@@@YAXXZ"
+template void f<K3{1}>();
+template void f<K3{1, 2, 3, 4, 5, 6}>();
+
+namespace CvQualifiers {
+  struct A { const int a; int *const b; int c; };
+  template<A> void f() {}
+  // CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1AELi0ELPi0ELi1EEEEEvv
+  // MSABI: define {{.*}} @"??$f@$2UA@CvQualifiers@@$$CBH0A@QEAH0A@H00@@CvQualifiers@@YAXXZ"
+  template void f<A{.c = 1}>();
+
+  using T1 = const int;
+  using T2 = T1[5];
+  using T3 = const T2;
+  struct B { T3 arr; };
+  template<B> void f() {}
+  // CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1BEtlA5_iLi1ELi2ELi3ELi4ELi5EEEEEEvv
+  // MSABI: define {{.*}} @"??$f@$2UB@CvQualifiers@@3$$CBH00@01@02@03@04@@@@CvQualifiers@@YAXXZ"
+  template void f<B{1, 2, 3, 4, 5}>();
+}
+
+struct L {
+  signed char a = -1;
+  unsigned char b = -1;
+  short c = -1;
+  unsigned short d = -1;
+  int e = -1;
+  unsigned int f = -1;
+  long g = -1;
+  unsigned long h = -1;
+  long long i = -1;
+  unsigned long long j = -1;
+};
+template<L> void f() {}
+// CHECK: define {{.*}} @_Z1fIXtl1LLan1ELh255ELsn1ELt65535ELin1ELj4294967295ELln1ELm18446744073709551615ELxn1ELy18446744073709551615EEEEvv
+// MSABI: define {{.*}} @"??$f@$2UL@@C0?0E0PP@F0?0G0PPPP@H0?0I0PPPPPPPP@J0?0K0PPPPPPPP@_J0?0_K0?0@@@YAXXZ"
+template void f<L{}>();
+
+// Template parameter objects.
+struct M { int n; };
+template<M a> constexpr const M &f() { return a; }
+// CHECK: define {{.*}} @_Z1fIXtl1MLi42EEEERKS0_v
+// CHECK: ret {{.*}} @_ZTAXtl1MLi42EEE
+// MSABI: define {{.*}} @"??$f@$2UM@@H0CK@@@@YAAEBUM@@XZ"
+// MSABI: ret {{.*}} @"??__N2UM@@H0CK@@@"
+template const M &f<M{42}>();
+
+template<const M *p> void g() {}
+// CHECK: define {{.*}} @_Z1gIXadL_ZTAXtl1MLi10EEEEEEvv
+// MSABI: define {{.*}} @"??$g@$1??__N2UM@@H09@@@@YAXXZ"
+template void g<&f<M{10}>()>();
Index: clang/lib/AST/MicrosoftMangle.cpp
===================================================================
--- clang/lib/AST/MicrosoftMangle.cpp
+++ clang/lib/AST/MicrosoftMangle.cpp
@@ -308,12 +308,17 @@
   void mangleName(const NamedDecl *ND);
   void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle);
   void mangleVariableEncoding(const VarDecl *VD);
-  void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD);
+  void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD,
+                               StringRef Prefix = "$");
   void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
-                                   const CXXMethodDecl *MD);
+                                   const CXXMethodDecl *MD,
+                                   StringRef Prefix = "$");
   void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
                                 const MethodVFTableLocation &ML);
   void mangleNumber(int64_t Number);
+  void mangleNumber(llvm::APSInt Number);
+  void mangleFloat(llvm::APFloat Number);
+  void mangleBits(llvm::APInt Number);
   void mangleTagTypeKind(TagTypeKind TK);
   void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName,
                               ArrayRef<StringRef> NestedNames = None);
@@ -388,6 +393,8 @@
                           const TemplateArgumentList &TemplateArgs);
   void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA,
                          const NamedDecl *Parm);
+  void mangleTemplateArgValue(QualType T, const APValue &V,
+                              bool WithScalarType = true);
 
   void mangleObjCProtocol(const ObjCProtocolDecl *PD);
   void mangleObjCLifetime(const QualType T, Qualifiers Quals,
@@ -504,10 +511,8 @@
     // 'const struct __s_GUID'.
     Out << "3U__s_GUID@@B";
   else if (isa<TemplateParamObjectDecl>(D)) {
-    DiagnosticsEngine &Diags = Context.getDiags();
-    unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
-      "cannot mangle template parameter objects yet");
-    Diags.Report(SourceLocation(), DiagID);
+    // Template parameter objects don't get a <type-encoding>; their type is
+    // specified as part of their value.
   } else
     llvm_unreachable("Tried to mangle unexpected NamedDecl!");
 }
@@ -599,7 +604,8 @@
 }
 
 void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
-                                                      const ValueDecl *VD) {
+                                                      const ValueDecl *VD,
+                                                      StringRef Prefix) {
   // <member-data-pointer> ::= <integer-literal>
   //                       ::= $F <number> <number>
   //                       ::= $G <number> <number> <number>
@@ -631,7 +637,7 @@
   case MSInheritanceModel::Unspecified: Code = 'G'; break;
   }
 
-  Out << '$' << Code;
+  Out << Prefix << Code;
 
   mangleNumber(FieldOffset);
 
@@ -646,7 +652,8 @@
 
 void
 MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
-                                                     const CXXMethodDecl *MD) {
+                                                     const CXXMethodDecl *MD,
+                                                     StringRef Prefix) {
   // <member-function-pointer> ::= $1? <name>
   //                           ::= $H? <name> <number>
   //                           ::= $I? <name> <number> <number>
@@ -668,7 +675,7 @@
   uint64_t VBTableOffset = 0;
   uint64_t VBPtrOffset = 0;
   if (MD) {
-    Out << '$' << Code << '?';
+    Out << Prefix << Code << '?';
     if (MD->isVirtual()) {
       MicrosoftVTableContext *VTContext =
           cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
@@ -691,12 +698,12 @@
   } else {
     // Null single inheritance member functions are encoded as a simple nullptr.
     if (IM == MSInheritanceModel::Single) {
-      Out << "$0A@";
+      Out << Prefix << "0A@";
       return;
     }
     if (IM == MSInheritanceModel::Unspecified)
       VBTableOffset = -1;
-    Out << '$' << Code;
+    Out << Prefix << Code;
   }
 
   if (inheritanceModelHasNVOffsetField(/*IsMemberFunction=*/true, IM))
@@ -735,32 +742,63 @@
 }
 
 void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
+  mangleNumber(llvm::APSInt(llvm::APInt(64, Number), /*IsUnsigned*/false));
+}
+
+void MicrosoftCXXNameMangler::mangleNumber(llvm::APSInt Number) {
+  // MSVC never mangles any integer wider than 64 bits. In general it appears
+  // to convert every integer to signed 64 bit before mangling (including
+  // unsigned 64 bit values). Do the same, but preserve bits beyond the bottom
+  // 64.
+  llvm::APInt Value =
+      Number.isSigned() ? Number.sextOrSelf(64) : Number.zextOrSelf(64);
+
   // <non-negative integer> ::= A@              # when Number == 0
   //                        ::= <decimal digit> # when 1 <= Number <= 10
   //                        ::= <hex digit>+ @  # when Number >= 10
   //
   // <number>               ::= [?] <non-negative integer>
 
-  uint64_t Value = static_cast<uint64_t>(Number);
-  if (Number < 0) {
+  if (Value.isNegative()) {
     Value = -Value;
     Out << '?';
   }
+  mangleBits(Value);
+}
 
+void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) {
+  using llvm::APFloat;
+
+  switch (APFloat::SemanticsToEnum(Number.getSemantics())) {
+  case APFloat::S_IEEEsingle: Out << 'A'; break;
+  case APFloat::S_IEEEdouble: Out << 'B'; break;
+
+  // The following are all Clang extensions. We try to pick manglings that are
+  // unlikely to conflict with MSVC's scheme.
+  case APFloat::S_IEEEhalf: Out << 'V'; break;
+  case APFloat::S_BFloat: Out << 'W'; break;
+  case APFloat::S_x87DoubleExtended: Out << 'X'; break;
+  case APFloat::S_IEEEquad: Out << 'Y'; break;
+  case APFloat::S_PPCDoubleDouble: Out << 'Z'; break;
+  }
+
+  mangleBits(Number.bitcastToAPInt());
+}
+
+void MicrosoftCXXNameMangler::mangleBits(llvm::APInt Value) {
   if (Value == 0)
     Out << "A@";
-  else if (Value >= 1 && Value <= 10)
+  else if (Value.uge(1) && Value.ule(10))
     Out << (Value - 1);
   else {
     // Numbers that are not encoded as decimal digits are represented as nibbles
     // in the range of ASCII characters 'A' to 'P'.
     // The number 0x123450 would be encoded as 'BCDEFA'
-    char EncodedNumberBuffer[sizeof(uint64_t) * 2];
-    MutableArrayRef<char> BufferRef(EncodedNumberBuffer);
-    MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
-    for (; Value != 0; Value >>= 4)
-      *I++ = 'A' + (Value & 0xf);
-    Out.write(I.base(), I - BufferRef.rbegin());
+    llvm::SmallString<32> EncodedNumberBuffer;
+    for (; Value != 0; Value.lshrInPlace(4))
+      EncodedNumberBuffer.push_back('A' + (Value & 0xf).getZExtValue());
+    std::reverse(EncodedNumberBuffer.begin(), EncodedNumberBuffer.end());
+    Out.write(EncodedNumberBuffer.data(), EncodedNumberBuffer.size());
     Out << '@';
   }
 }
@@ -914,6 +952,13 @@
         break;
       }
 
+      if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
+        Out << "?__N";
+        mangleTemplateArgValue(TPO->getType().getUnqualifiedType(),
+                               TPO->getValue());
+        break;
+      }
+
       // We must have an anonymous struct.
       const TagDecl *TD = cast<TagDecl>(ND);
       if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
@@ -1382,10 +1427,7 @@
 
   Out << "0";
 
-  if (Value.isSigned())
-    mangleNumber(Value.getSExtValue());
-  else
-    mangleNumber(Value.getZExtValue());
+  mangleNumber(Value);
 }
 
 void MicrosoftCXXNameMangler::mangleExpression(
@@ -1433,6 +1475,7 @@
   //                ::= <member-function-pointer>
   //                ::= $E? <name> <type-encoding>
   //                ::= $1? <name> <type-encoding>
+  //                ::= $2  <type> <value>  # class NTTP
   //                ::= $0A@
   //                ::= <template-args>
 
@@ -1462,6 +1505,11 @@
         mangleName(FD);
         mangleFunctionEncoding(FD, /*ShouldMangle=*/true);
       }
+    } else if (TA.getParamTypeForDecl()->isRecordType()) {
+      Out << "$";
+      auto *TPO = cast<TemplateParamObjectDecl>(ND);
+      mangleTemplateArgValue(TPO->getType().getUnqualifiedType(),
+                             TPO->getValue());
     } else {
       mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?");
     }
@@ -1544,6 +1592,168 @@
   }
 }
 
+void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
+                                                     const APValue &V,
+                                                     bool WithScalarType) {
+  switch (V.getKind()) {
+  case APValue::None:
+  case APValue::Indeterminate:
+    // FIXME: MSVC doesn't allow this, so we can't be sure how it should be
+    // mangled.
+    if (WithScalarType)
+      mangleType(T, SourceRange(), QMM_Escape);
+    Out << '@';
+    return;
+
+  case APValue::Int:
+    if (WithScalarType)
+      mangleType(T, SourceRange(), QMM_Escape);
+    Out << '0';
+    mangleNumber(V.getInt());
+    return;
+
+  case APValue::Float:
+    if (WithScalarType)
+      mangleType(T, SourceRange(), QMM_Escape);
+    mangleFloat(V.getFloat());
+    return;
+
+  case APValue::LValue: {
+    if (WithScalarType)
+      mangleType(T, SourceRange(), QMM_Escape);
+
+    APValue::LValueBase Base = V.getLValueBase();
+    if (Base.isNull())
+      Out << "0A@";
+    else if (auto *VD = Base.dyn_cast<const ValueDecl*>())
+      mangle(VD, T->isReferenceType() ? "E?" : "1?");
+    else
+      break;
+
+    // FIXME: MSVC doesn't support template arguments referring to subobjects
+    // yet (it either mangles such template arguments as null pointers or
+    // small integers or crashes). It's probably the intent to mangle the
+    // declaration followed by an offset, but that's not what actually happens.
+    // For now just bail.
+    if (!V.hasLValuePath() || !V.getLValuePath().empty() ||
+        V.isLValueOnePastTheEnd())
+      break;
+
+    return;
+  }
+
+  case APValue::MemberPointer: {
+    if (WithScalarType)
+      mangleType(T, SourceRange(), QMM_Escape);
+
+    // FIXME: The below manglings don't include a conversion, so bail if there
+    // would be one. MSVC mangles the (possibly converted) value of the
+    // pointer-to-member object as if it were a struct, leading to collisions
+    // in some cases.
+    if (!V.getMemberPointerPath().empty())
+      break;
+
+    const CXXRecordDecl *RD =
+        T->castAs<MemberPointerType>()->getMostRecentCXXRecordDecl();
+    const ValueDecl *D = V.getMemberPointerDecl();
+    if (T->isMemberDataPointerType())
+      mangleMemberDataPointer(RD, D, "");
+    else
+      mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), "");
+    return;
+  }
+
+  case APValue::Struct: {
+    Out << '2';
+    mangleType(T, SourceRange(), QMM_Escape);
+    const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+    assert(RD && "unexpected type for record value");
+
+    unsigned BaseIndex = 0;
+    for (const CXXBaseSpecifier &B : RD->bases())
+      mangleTemplateArgValue(B.getType(), V.getStructBase(BaseIndex++));
+    for (const FieldDecl *FD : RD->fields())
+      if (!FD->isUnnamedBitfield())
+        mangleTemplateArgValue(FD->getType(),
+                               V.getStructField(FD->getFieldIndex()));
+    Out << '@';
+    return;
+  }
+
+  case APValue::Union:
+    Out << '2';
+    mangleType(T, SourceRange(), QMM_Escape);
+    // FIXME: MSVC doesn't mangle the active member, only the type, leading to
+    // collisions if more than one member has the same type.
+    // FIXME: MSVC doesn't yet support unions with no active member, but
+    // there's an obvious mangling for that, so we use it.
+    if (const FieldDecl *FD = V.getUnionField())
+      mangleTemplateArgValue(FD->getType(), V.getUnionValue());
+    Out << '@';
+    return;
+
+  case APValue::ComplexInt:
+    // We mangle complex types as structs, so mangle the value as a struct too.
+    Out << '2';
+    mangleType(T, SourceRange(), QMM_Escape);
+    Out << '0';
+    mangleNumber(V.getComplexIntReal());
+    Out << '0';
+    mangleNumber(V.getComplexIntImag());
+    Out << '@';
+    return;
+
+  case APValue::ComplexFloat:
+    Out << '2';
+    mangleType(T, SourceRange(), QMM_Escape);
+    mangleFloat(V.getComplexFloatReal());
+    mangleFloat(V.getComplexFloatImag());
+    Out << '@';
+    return;
+
+  case APValue::Array: {
+    Out << '3';
+    QualType ElemT = getASTContext().getAsArrayType(T)->getElementType();
+    mangleType(ElemT, SourceRange(), QMM_Escape);
+    for (unsigned I = 0, N = V.getArraySize(); I != N; ++I) {
+      const APValue &ElemV = I < V.getArrayInitializedElts()
+                                 ? V.getArrayInitializedElt(I)
+                                 : V.getArrayFiller();
+      mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false);
+      Out << '@';
+    }
+    Out << '@';
+    return;
+  }
+
+  case APValue::Vector: {
+    // __m128 is mangled as a struct containing an array. We follow this
+    // approach for all vector types.
+    Out << '2';
+    mangleType(T, SourceRange(), QMM_Escape);
+    Out << '3';
+    QualType ElemT = T->castAs<VectorType>()->getElementType();
+    mangleType(ElemT, SourceRange(), QMM_Escape);
+    for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I) {
+      const APValue &ElemV = V.getVectorElt(I);
+      mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false);
+      Out << '@';
+    }
+    Out << "@@";
+    return;
+  }
+
+  case APValue::AddrLabelDiff:
+  case APValue::FixedPoint:
+    break;
+  }
+
+  DiagnosticsEngine &Diags = Context.getDiags();
+  unsigned DiagID = Diags.getCustomDiagID(
+      DiagnosticsEngine::Error, "cannot mangle this template argument yet");
+  Diags.Report(DiagID);
+}
+
 void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) {
   llvm::SmallString<64> TemplateMangling;
   llvm::raw_svector_ostream Stream(TemplateMangling);
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -534,6 +534,10 @@
   void mangleAArch64FixedSveVectorType(const DependentVectorType *T);
 
   void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
+  void mangleFloatLiteral(QualType T, const llvm::APFloat &V);
+  void mangleFixedPointLiteral();
+  void mangleNullPointer(QualType T);
+
   void mangleMemberExprBase(const Expr *base, bool isArrow);
   void mangleMemberExpr(const Expr *base, bool isArrow,
                         NestedNameSpecifier *qualifier,
@@ -1055,6 +1059,27 @@
   Out.write(buffer.data(), numCharacters);
 }
 
+void CXXNameMangler::mangleFloatLiteral(QualType T, const llvm::APFloat &V) {
+  Out << 'L';
+  mangleType(T);
+  mangleFloat(V);
+  Out << 'E';
+}
+
+void CXXNameMangler::mangleFixedPointLiteral() {
+  DiagnosticsEngine &Diags = Context.getDiags();
+  unsigned DiagID = Diags.getCustomDiagID(
+      DiagnosticsEngine::Error, "cannot mangle fixed point literals yet");
+  Diags.Report(DiagID);
+}
+
+void CXXNameMangler::mangleNullPointer(QualType T) {
+  //  <expr-primary> ::= L <type> 0 E
+  Out << 'L';
+  mangleType(T);
+  Out << "0E";
+}
+
 void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
   if (Value.isSigned() && Value.isNegative()) {
     Out << 'n';
@@ -3944,7 +3969,6 @@
   case Expr::PseudoObjectExprClass:
   case Expr::AtomicExprClass:
   case Expr::SourceLocExprClass:
-  case Expr::FixedPointLiteralClass:
   case Expr::BuiltinBitCastExprClass:
   {
     if (!NullOut) {
@@ -4518,13 +4542,14 @@
 
   case Expr::FloatingLiteralClass: {
     const FloatingLiteral *FL = cast<FloatingLiteral>(E);
-    Out << 'L';
-    mangleType(FL->getType());
-    mangleFloat(FL->getValue());
-    Out << 'E';
+    mangleFloatLiteral(FL->getType(), FL->getValue());
     break;
   }
 
+  case Expr::FixedPointLiteralClass:
+    mangleFixedPointLiteral();
+    break;
+
   case Expr::CharacterLiteralClass:
     Out << 'L';
     mangleType(E->getType());
@@ -4587,9 +4612,7 @@
 
   case Expr::GNUNullExprClass:
     // Mangle as if an integer literal 0.
-    Out << 'L';
-    mangleType(E->getType());
-    Out << "0E";
+    mangleIntegerLiteral(E->getType(), llvm::APSInt(32));
     break;
 
   case Expr::CXXNullPtrLiteralExprClass: {
@@ -4874,8 +4897,9 @@
 
     // Template parameter objects are modeled by reproducing a source form
     // produced as if by aggregate initialization.
-    if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) {
+    if (A.getParamTypeForDecl()->isRecordType()) {
       Out << 'X';
+      auto *TPO = cast<TemplateParamObjectDecl>(D);
       mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(),
                                TPO->getValue());
       Out << 'E';
@@ -4891,11 +4915,7 @@
       mangleOperatorName(OO_Amp, 1);
     }
 
-    Out << 'L';
-    // References to external entities use the mangled name; if the name would
-    // not normally be mangled then mangle it as unqualified.
-    mangle(D);
-    Out << 'E';
+    mangleDeclRefExpr(D);
 
     if (compensateMangling)
       Out << 'E';
@@ -4903,10 +4923,7 @@
     break;
   }
   case TemplateArgument::NullPtr: {
-    //  <expr-primary> ::= L <type> 0 E
-    Out << 'L';
-    mangleType(A.getNullPtrType());
-    Out << "0E";
+    mangleNullPointer(A.getNullPtrType());
     break;
   }
   case TemplateArgument::Pack: {
@@ -4921,59 +4938,80 @@
 
 /// Determine whether a given value is equivalent to zero-initialization for
 /// the purpose of discarding a trailing portion of a 'tl' mangling.
-static bool isZeroInitialized(const APValue &V) {
-  // FIXME: mangleValueInTemplateArg has quadratic time complexity due to using
-  // this. We could do the same thing in linear time, for example by instead
-  // mangling the whole value speculatively and retroactively deleting the
-  // longest trailing part of each 'tl' mangling that is equivalent to zero-
-  // initialization.
+///
+/// Note that this is not in general equivalent to determining whether the
+/// value has an all-zeroes bit pattern.
+static bool isZeroInitialized(QualType T, const APValue &V) {
+  // FIXME: mangleValueInTemplateArg has quadratic time complexity in
+  // pathological cases due to using this, but it's a little awkward
+  // to do this in linear time in general.
   switch (V.getKind()) {
   case APValue::None:
   case APValue::Indeterminate:
   case APValue::AddrLabelDiff:
     return false;
 
-  case APValue::Struct:
-    for (unsigned I = 0, N = V.getStructNumBases(); I != N; ++I)
-      if (!isZeroInitialized(V.getStructBase(I)))
+  case APValue::Struct: {
+    const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+    assert(RD && "unexpected type for record value");
+    unsigned I = 0;
+    for (const CXXBaseSpecifier &BS : RD->bases()) {
+      if (!isZeroInitialized(BS.getType(), V.getStructBase(I)))
         return false;
-    // FIXME: Ignore anonymous bit-fields.
-    for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I)
-      if (!isZeroInitialized(V.getStructField(I)))
+      ++I;
+    }
+    I = 0;
+    for (const FieldDecl *FD : RD->fields()) {
+      if (!FD->isUnnamedBitfield() &&
+          !isZeroInitialized(FD->getType(), V.getStructField(I)))
         return false;
+      ++I;
+    }
     return true;
+  }
 
   case APValue::Union: {
-    const FieldDecl *FD = V.getUnionField();
-    // FIXME: Empty unions are always zero-initialized.
-    if (!FD || FD->getFieldIndex() != 0)
-      return false;
-    return isZeroInitialized(V.getUnionValue());
+    const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+    assert(RD && "unexpected type for union value");
+    // Zero-initialization zeroes the first non-unnamed-bitfield field, if any.
+    for (const FieldDecl *FD : RD->fields()) {
+      if (!FD->isUnnamedBitfield())
+        return V.getUnionField() && declaresSameEntity(FD, V.getUnionField()) &&
+               isZeroInitialized(FD->getType(), V.getUnionValue());
+    }
+    // If there are no fields (other than unnamed bitfields), the value is
+    // necessarily zero-initialized.
+    return true;
   }
 
-  case APValue::Array:
+  case APValue::Array: {
+    QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0);
     for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I)
-      if (!isZeroInitialized(V.getArrayInitializedElt(I)))
+      if (!isZeroInitialized(ElemT, V.getArrayInitializedElt(I)))
         return false;
-    return !V.hasArrayFiller() || isZeroInitialized(V.getArrayFiller());
+    return !V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller());
+  }
 
-  case APValue::Vector:
+  case APValue::Vector: {
+    const VectorType *VT = T->castAs<VectorType>();
     for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I)
-      if (!isZeroInitialized(V.getVectorElt(I)))
+      if (!isZeroInitialized(VT->getElementType(), V.getVectorElt(I)))
         return false;
     return true;
+  }
 
   case APValue::Int:
     return !V.getInt();
 
   case APValue::Float:
-    return V.getFloat().isZero();
+    return V.getFloat().isPosZero();
 
   case APValue::FixedPoint:
     return !V.getFixedPoint().getValue();
 
   case APValue::ComplexFloat:
-    return V.getComplexFloatReal().isZero() && V.getComplexFloatImag().isZero();
+    return V.getComplexFloatReal().isPosZero() &&
+           V.getComplexFloatImag().isPosZero();
 
   case APValue::ComplexInt:
     return !V.getComplexIntReal() && !V.getComplexIntImag();
@@ -4987,6 +5025,10 @@
 }
 
 void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
+  // Ignore all top-level cv-qualifiers, to match GCC.
+  Qualifiers Quals;
+  T = getASTContext().getUnqualifiedArrayType(T, Quals);
+
   // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63.
   switch (V.getKind()) {
   case APValue::None:
@@ -5003,31 +5045,34 @@
     const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
     assert(RD && "unexpected type for record value");
 
-    unsigned NBases = V.getStructNumBases();
-    unsigned NFields = V.getStructNumFields();
-    // FIXME: Ignore anonymous bit-fields.
-    while (NFields && isZeroInitialized(V.getStructField(NFields - 1)))
-      --NFields;
-    if (!NFields)
-      while (NBases && isZeroInitialized(V.getStructBase(NBases - 1)))
-        --NBases;
+    // Drop trailing zero-initialized elements.
+    llvm::SmallVector<const FieldDecl *, 16> Fields(RD->field_begin(),
+                                                    RD->field_end());
+    while (
+        !Fields.empty() &&
+        (Fields.back()->isUnnamedBitfield() ||
+         isZeroInitialized(Fields.back()->getType(),
+                           V.getStructField(Fields.back()->getFieldIndex())))) {
+      Fields.pop_back();
+    }
+    llvm::ArrayRef<CXXBaseSpecifier> Bases(RD->bases_begin(), RD->bases_end());
+    if (Fields.empty()) {
+      while (!Bases.empty() &&
+             isZeroInitialized(Bases.back().getType(),
+                               V.getStructBase(Bases.size() - 1)))
+        Bases = Bases.drop_back();
+    }
 
     // <expression> ::= tl <type> <braced-expression>* E
     Out << "tl";
     mangleType(T);
-    unsigned BaseIndex = 0;
-    for (const CXXBaseSpecifier &BS : RD->bases()) {
-      if (BaseIndex == NBases)
-        break;
-      mangleValueInTemplateArg(BS.getType(), V.getStructBase(BaseIndex++));
-    }
-    for (const FieldDecl *FD : RD->fields()) {
-      if (FD->getFieldIndex() == NFields)
-        break;
-      if (FD->isUnnamedBitfield())
+    for (unsigned I = 0, N = Bases.size(); I != N; ++I)
+      mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I));
+    for (unsigned I = 0, N = Fields.size(); I != N; ++I) {
+      if (Fields[I]->isUnnamedBitfield())
         continue;
-      mangleValueInTemplateArg(FD->getType(),
-                               V.getStructField(FD->getFieldIndex()));
+      mangleValueInTemplateArg(Fields[I]->getType(),
+                               V.getStructField(Fields[I]->getFieldIndex()));
     }
     Out << 'E';
     return;
@@ -5048,7 +5093,7 @@
     // <braced-expression> ::= di <field source-name> <braced-expression>
     Out << "tl";
     mangleType(T);
-    if (!isZeroInitialized(V)) {
+    if (!isZeroInitialized(T, V)) {
       Out << "di";
       mangleSourceName(FD->getIdentifier());
       mangleValueInTemplateArg(FD->getType(), V.getUnionValue());
@@ -5058,17 +5103,16 @@
   }
 
   case APValue::Array: {
-    const ArrayType *AT = Context.getASTContext().getAsArrayType(T);
-    assert(AT && "unexpected type for array value");
+    QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0);
 
     Out << "tl";
     mangleType(T);
 
     // Drop trailing zero-initialized elements.
     unsigned N = V.getArraySize();
-    if (!V.hasArrayFiller() || isZeroInitialized(V.getArrayFiller())) {
+    if (!V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller())) {
       N = V.getArrayInitializedElts();
-      while (N && isZeroInitialized(V.getArrayInitializedElt(N - 1)))
+      while (N && isZeroInitialized(ElemT, V.getArrayInitializedElt(N - 1)))
         --N;
     }
 
@@ -5076,7 +5120,7 @@
       const APValue &Elem = I < V.getArrayInitializedElts()
                                 ? V.getArrayInitializedElt(I)
                                 : V.getArrayFiller();
-      mangleValueInTemplateArg(AT->getElementType(), Elem);
+      mangleValueInTemplateArg(ElemT, Elem);
     }
     Out << 'E';
     return;
@@ -5088,7 +5132,7 @@
     Out << "tl";
     mangleType(T);
     unsigned N = V.getVectorLength();
-    while (N && isZeroInitialized(V.getVectorElt(N - 1)))
+    while (N && isZeroInitialized(VT->getElementType(), V.getVectorElt(N - 1)))
       --N;
     for (unsigned I = 0; I != N; ++I)
       mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I));
@@ -5101,33 +5145,22 @@
     return;
 
   case APValue::Float:
-    Out << 'L';
-    mangleType(T);
-    mangleFloat(V.getFloat());
-    Out << 'E';
+    mangleFloatLiteral(T, V.getFloat());
     return;
 
   case APValue::FixedPoint:
-    llvm_unreachable("Fixed point types are disabled for c++");
+    mangleFixedPointLiteral();
     return;
 
   case APValue::ComplexFloat: {
     const ComplexType *CT = T->castAs<ComplexType>();
     Out << "tl";
     mangleType(T);
-    if (V.getComplexFloatReal().isNonZero() ||
-        V.getComplexFloatImag().isNonZero()) {
-      Out << 'L';
-      mangleType(CT->getElementType());
-      mangleFloat(V.getComplexFloatReal());
-      Out << 'E';
-    }
-    if (V.getComplexFloatImag().isNonZero()) {
-      Out << 'L';
-      mangleType(CT->getElementType());
-      mangleFloat(V.getComplexFloatImag());
-      Out << 'E';
-    }
+    if (!V.getComplexFloatReal().isPosZero() ||
+        !V.getComplexFloatImag().isPosZero())
+      mangleFloatLiteral(CT->getElementType(), V.getComplexFloatReal());
+    if (!V.getComplexFloatImag().isPosZero())
+      mangleFloatLiteral(CT->getElementType(), V.getComplexFloatImag());
     Out << 'E';
     return;
   }
@@ -5151,9 +5184,7 @@
            "unexpected type for LValue template arg");
 
     if (V.isNullPointer()) {
-      Out << "L";
-      mangleType(T);
-      Out << "0E";
+      mangleNullPointer(T);
       return;
     }
 
@@ -5167,7 +5198,7 @@
         // a cast, because L <type> 0 E means something else.
         Out << "rc";
         mangleType(T);
-        Out << "Li0EE";
+        Out << "Li0E";
       } else {
         Out << "L";
         mangleType(T);
@@ -5273,9 +5304,7 @@
   case APValue::MemberPointer:
     // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
     if (!V.getMemberPointerDecl()) {
-      Out << 'L';
-      mangleType(T);
-      Out << "0E";
+      mangleNullPointer(T);
       return;
     }
 
Index: clang/lib/AST/APValue.cpp
===================================================================
--- clang/lib/AST/APValue.cpp
+++ clang/lib/AST/APValue.cpp
@@ -1040,9 +1040,6 @@
       if (VD && MergeLV(getLVForDecl(VD, computation)))
         break;
     } else if (const auto TI = V.getLValueBase().dyn_cast<TypeInfoLValue>()) {
-      // FIXME: Claim that typeinfo(T) has the same linkage as T. This isn't
-      // correct across all ABIs, but for now it shouldn't matter as such
-      // values aren't permitted within template arguments.
       if (MergeLV(getLVForType(*TI.getType(), computation)))
         break;
     } else if (const Expr *E = V.getLValueBase().dyn_cast<const Expr *>()) {
@@ -1050,6 +1047,8 @@
       // lifetime-extended temporaries.
       // FIXME: These should be modeled as having the
       // LifetimeExtendedTemporaryDecl itself as the base.
+      // FIXME: If we permit Objective-C object literals in template arguments,
+      // they should not imply internal linkage.
       auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
       if (!MTE || MTE->getStorageDuration() == SD_FullExpression)
         return LinkageInfo::internal();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D89998: [... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D899... John McCall via Phabricator via cfe-commits
    • [PATCH] D899... Reid Kleckner via Phabricator via cfe-commits
    • [PATCH] D899... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D899... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D899... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D899... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D899... John McCall via Phabricator via cfe-commits
    • [PATCH] D899... Richard Smith - zygoloid via Phabricator via cfe-commits

Reply via email to