diff options
author | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
commit | 952eddef9aff85b1e92626e89baaf7a360e2ac85 (patch) | |
tree | df8df0b0067b381eab470a3b8f28d14a552a6340 /test/CodeGenCXX | |
parent | ea266cad53e3d49771fa38103913d3ec7a166694 (diff) | |
download | FreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.zip FreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.tar.gz |
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):
https://llvm.org/svn/llvm-project/cfe/branches/release_34@197841
Diffstat (limited to 'test/CodeGenCXX')
290 files changed, 9650 insertions, 1820 deletions
diff --git a/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp index 3bfecd5..c478e7d 100644 --- a/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp +++ b/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp @@ -4,6 +4,6 @@ namespace nm { struct str { - friend int foo(int arg = 0); + friend void foo(int arg = 0) {}; }; } diff --git a/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp b/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp deleted file mode 100644 index c37f5dc..0000000 --- a/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s - -// CHECK-NOT: i32 6 -struct QVectorTypedData { - int size; - unsigned int sharable : 1; - unsigned short array[1]; -}; - -void foo(QVectorTypedData *X) { - X->array[0] = 123; -} diff --git a/test/CodeGenCXX/2007-05-03-VectorInit.cpp b/test/CodeGenCXX/2007-05-03-VectorInit.cpp index 5bc196f..b22b52a 100644 --- a/test/CodeGenCXX/2007-05-03-VectorInit.cpp +++ b/test/CodeGenCXX/2007-05-03-VectorInit.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -O0 -o - +// RUN: %clang_cc1 -emit-llvm %s -o - // PR1378 typedef float v4sf __attribute__((vector_size(16))); diff --git a/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp b/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp index 7c05535..802f4c3 100644 --- a/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp +++ b/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o /dev/null +// RUN: %clang_cc1 -emit-llvm -g %s -o /dev/null // PR 7104 struct A { diff --git a/test/CodeGenCXX/DynArrayInit.cpp b/test/CodeGenCXX/DynArrayInit.cpp index 4b4c2ec..fb865e3 100644 --- a/test/CodeGenCXX/DynArrayInit.cpp +++ b/test/CodeGenCXX/DynArrayInit.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -O3 -emit-llvm -o - %s | FileCheck %s // PR7490 -// CHECK: define signext i8 @_Z2f0v +// CHECK-LABEL: define signext i8 @_Z2f0v // CHECK: ret i8 0 // CHECK: } inline void* operator new[](unsigned long, void* __p) { return __p; } diff --git a/test/CodeGenCXX/PR5050-constructor-conversion.cpp b/test/CodeGenCXX/PR5050-constructor-conversion.cpp index c50dafb..a1b05eb 100644 --- a/test/CodeGenCXX/PR5050-constructor-conversion.cpp +++ b/test/CodeGenCXX/PR5050-constructor-conversion.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s struct A { A(const A&, int i1 = 1); }; diff --git a/test/CodeGenCXX/aarch64-mangle-neon-vectors.cpp b/test/CodeGenCXX/aarch64-mangle-neon-vectors.cpp new file mode 100644 index 0000000..2514704 --- /dev/null +++ b/test/CodeGenCXX/aarch64-mangle-neon-vectors.cpp @@ -0,0 +1,85 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon %s -emit-llvm -o - | FileCheck %s + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed long long int64_t; +typedef unsigned long long uint64_t; +typedef unsigned char poly8_t; +typedef unsigned short poly16_t; +typedef __fp16 float16_t; +typedef float float32_t; +typedef double float64_t; + +typedef __attribute__((neon_vector_type(8))) int8_t int8x8_t; +typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t; +typedef __attribute__((neon_vector_type(4))) int16_t int16x4_t; +typedef __attribute__((neon_vector_type(8))) int16_t int16x8_t; +typedef __attribute__((neon_vector_type(2))) int int32x2_t; +typedef __attribute__((neon_vector_type(4))) int int32x4_t; +typedef __attribute__((neon_vector_type(2))) int64_t int64x2_t; +typedef __attribute__((neon_vector_type(8))) uint8_t uint8x8_t; +typedef __attribute__((neon_vector_type(16))) uint8_t uint8x16_t; +typedef __attribute__((neon_vector_type(4))) uint16_t uint16x4_t; +typedef __attribute__((neon_vector_type(8))) uint16_t uint16x8_t; +typedef __attribute__((neon_vector_type(2))) unsigned int uint32x2_t; +typedef __attribute__((neon_vector_type(4))) unsigned int uint32x4_t; +typedef __attribute__((neon_vector_type(2))) uint64_t uint64x2_t; +typedef __attribute__((neon_vector_type(4))) float16_t float16x4_t; +typedef __attribute__((neon_vector_type(8))) float16_t float16x8_t; +typedef __attribute__((neon_vector_type(2))) float32_t float32x2_t; +typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t; +typedef __attribute__((neon_vector_type(2))) float64_t float64x2_t; +typedef __attribute__((neon_polyvector_type(8))) poly8_t poly8x8_t; +typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t; +typedef __attribute__((neon_polyvector_type(4))) poly16_t poly16x4_t; +typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t; + +// CHECK: 10__Int8x8_t +void f1(int8x8_t) {} +// CHECK: 11__Int16x4_t +void f2(int16x4_t) {} +// CHECK: 11__Int32x2_t +void f3(int32x2_t) {} +// CHECK: 11__Uint8x8_t +void f4(uint8x8_t) {} +// CHECK: 12__Uint16x4_t +void f5(uint16x4_t) {} +// CHECK: 13__Float16x4_t +void f6(float16x4_t) {} +// CHECK: 13__Float16x8_t +void f7(float16x8_t) {} +// CHECK: 12__Uint32x2_t +void f8(uint32x2_t) {} +// CHECK: 13__Float32x2_t +void f9(float32x2_t) {} +// CHECK: 13__Float32x4_t +void f10(float32x4_t) {} +// CHECK: 11__Poly8x8_t +void f11(poly8x8_t v) {} +// CHECK: 12__Poly16x4_t +void f12(poly16x4_t v) {} +// CHECK:12__Poly8x16_t +void f13(poly8x16_t v) {} +// CHECK:12__Poly16x8_t +void f14(poly16x8_t v) {} +// CHECK: 11__Int8x16_t +void f15(int8x16_t) {} +// CHECK: 11__Int16x8_t +void f16(int16x8_t) {} +// CHECK:11__Int32x4_t +void f17(int32x4_t) {} +// CHECK: 12__Uint8x16_t +void f18(uint8x16_t) {} +// CHECK: 12__Uint16x8_t +void f19(uint16x8_t) {} +// CHECK: 12__Uint32x4_t +void f20(uint32x4_t) {} +// CHECK: 11__Int64x2_t +void f21(int64x2_t) {} +// CHECK: 12__Uint64x2_t +void f22(uint64x2_t) {} +// CHECK: 13__Float64x2_t +void f23(float64x2_t) {} diff --git a/test/CodeGenCXX/aarch64-neon.cpp b/test/CodeGenCXX/aarch64-neon.cpp new file mode 100644 index 0000000..5d2a00b --- /dev/null +++ b/test/CodeGenCXX/aarch64-neon.cpp @@ -0,0 +1,13 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \ +// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s + +// Test whether arm_neon.h can be used in .cpp file. + +#include "arm_neon.h" + +poly64x1_t test_vld1_p64(poly64_t const * ptr) { + // CHECK: test_vld1_p64 + return vld1_p64(ptr); + // CHECK: ld1 {{{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}] +} diff --git a/test/CodeGenCXX/abstract-class-ctors-dtors.cpp b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp index 012c223..793bbde 100644 --- a/test/CodeGenCXX/abstract-class-ctors-dtors.cpp +++ b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp @@ -7,10 +7,10 @@ struct A { ~A(); }; -// CHECK-NOT: define void @_ZN1AC1Ev -// CHECK: define void @_ZN1AC2Ev -// CHECK: define void @_ZN1AD1Ev -// CHECK: define void @_ZN1AD2Ev +// CHECK-NOT-LABEL: define void @_ZN1AC1Ev +// CHECK-LABEL: define void @_ZN1AC2Ev +// CHECK-LABEL: define void @_ZN1AD1Ev +// CHECK-LABEL: define void @_ZN1AD2Ev A::A() { } A::~A() { } diff --git a/test/CodeGenCXX/address-of-fntemplate.cpp b/test/CodeGenCXX/address-of-fntemplate.cpp index 162c6e5..7179452 100644 --- a/test/CodeGenCXX/address-of-fntemplate.cpp +++ b/test/CodeGenCXX/address-of-fntemplate.cpp @@ -9,8 +9,8 @@ void test() { // CHECK: @_Z1fIiEvv void (*p2)() = f<int>; } -// CHECK: define linkonce_odr void @_Z1fIiEvT_ -// CHECK: define linkonce_odr void @_Z1fIiEvv +// CHECK-LABEL: define linkonce_odr void @_Z1fIiEvT_ +// CHECK-LABEL: define linkonce_odr void @_Z1fIiEvv namespace PR6973 { template<typename T> diff --git a/test/CodeGenCXX/alloca-align.cpp b/test/CodeGenCXX/alloca-align.cpp index 99d6ab5..079b55d 100644 --- a/test/CodeGenCXX/alloca-align.cpp +++ b/test/CodeGenCXX/alloca-align.cpp @@ -6,19 +6,19 @@ struct s0 { int TheStores __attribute__((aligned(16))); }; -// CHECK: define void @f0 +// CHECK-LABEL: define void @f0 // CHECK: alloca %struct.s0, align 16 extern "C" void f0() { (void) s0(); } -// CHECK: define void @f1 +// CHECK-LABEL: define void @f1 // CHECK: alloca %struct.s0, align 16 extern "C" void f1() { (void) (struct s0) { 0, 0, 0, 0 }; } -// CHECK: define i32 @f2 +// CHECK-LABEL: define i32 @f2 // CHECK: alloca %struct.s1, align 2 struct s1 { short x; short y; }; extern "C" struct s1 f2(int a, struct s1 *x, struct s1 *y) { diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp index 32e17a3..abc700f 100644 --- a/test/CodeGenCXX/anonymous-namespaces.cpp +++ b/test/CodeGenCXX/anonymous-namespaces.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-llvm %s -o - > %t -// RUN: FileCheck %s -check-prefix=1 < %t -// RUN: FileCheck %s -check-prefix=2 < %t +// RUN: FileCheck %s -check-prefix=CHECK-1 < %t +// RUN: FileCheck %s -check-prefix=CHECK-2 < %t int f(); @@ -28,12 +28,12 @@ namespace { struct E : public virtual EBase { virtual ~E() {} }; }; - // CHECK-1: define internal i32 @_ZN12_GLOBAL__N_13fooEv() + // CHECK-1-LABEL: define internal i32 @_ZN12_GLOBAL__N_13fooEv() int foo() { return 32; } - // CHECK-1: define internal i32 @_ZN12_GLOBAL__N_11A3fooEv() + // CHECK-1-LABEL: define internal i32 @_ZN12_GLOBAL__N_11A3fooEv() namespace A { int foo() { return 45; @@ -58,11 +58,20 @@ namespace test2 { struct C; } - // CHECK-2: define void @_ZN5test24testEv() + // CHECK-2-LABEL: define void @_ZN5test24testEv() // CHECK-2: call void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv() void test() { A::B<C>::foo(); } - // CHECK-2: define internal void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv() + // CHECK-2-LABEL: define internal void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv() } + +namespace { + +int bar() { + extern int a; + return a; +} + +} // namespace diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp index 8dc4f47..98e982d 100644 --- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp +++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -31,7 +31,7 @@ namespace PR7021 { union { long l; }; }; - // CHECK: define void @_ZN6PR70211fENS_1XES0_ + // CHECK-LABEL: define void @_ZN6PR70211fENS_1XES0_ void f(X x, X z) { X x1; @@ -61,7 +61,7 @@ namespace test2 { }; A::A() : b(10) { } - // CHECK: define void @_ZN5test21AC2Ev( + // CHECK-LABEL: define void @_ZN5test21AC2Ev( // CHECK-NOT: } // CHECK: store i32 10 // CHECK: } @@ -79,14 +79,14 @@ namespace PR10512 { }; }; - // CHECK: define void @_ZN7PR105121AC2Ev + // CHECK-LABEL: define void @_ZN7PR105121AC2Ev // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]] // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]] // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]** [[THISADDR]] // CHECK-NEXT: ret void A::A() {} - // CHECK: define void @_ZN7PR105121AC2Ei + // CHECK-LABEL: define void @_ZN7PR105121AC2Ei // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]] // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i32 // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]] @@ -100,7 +100,7 @@ namespace PR10512 { // CHECK-NEXT: ret void A::A(int x) : x(x) { } - // CHECK: define void @_ZN7PR105121AC2El + // CHECK-LABEL: define void @_ZN7PR105121AC2El // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]] // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i64 // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]] @@ -130,7 +130,7 @@ namespace test3 { }; A::A() : callback(0), callback_value(0) {} - // CHECK: define void @_ZN5test31AC2Ev( + // CHECK-LABEL: define void @_ZN5test31AC2Ev( // CHECK: [[THIS:%.*]] = load // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 // CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to diff --git a/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp b/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp index bd275f1..7ac5b58 100644 --- a/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp +++ b/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s -// CHECK: define void @_ZN2B1D0Ev +// CHECK-LABEL: define void @_ZN2B1D0Ev // CHECK: [[T1:%.*]] = load void (%struct.B1*)** getelementptr inbounds (void (%struct.B1*)** bitcast ([5 x i8*]* @_ZTV2B1 to void (%struct.B1*)**), i64 2) // CHECK-NEXT: call void [[T1]](%struct.B1* [[T2:%.*]]) -// CHECK: define void @_Z6DELETEP2B1 +// CHECK-LABEL: define void @_Z6DELETEP2B1 // CHECK: [[T3:%.*]] = load void (%struct.B1*)** getelementptr inbounds (void (%struct.B1*)** bitcast ([5 x i8*]* @_ZTV2B1 to void (%struct.B1*)**), i64 2) // CHECK-NEXT: call void [[T3]](%struct.B1* [[T4:%.*]]) diff --git a/test/CodeGenCXX/apple-kext-linkage.C b/test/CodeGenCXX/apple-kext-linkage.C index 59d228e..e66b038 100644 --- a/test/CodeGenCXX/apple-kext-linkage.C +++ b/test/CodeGenCXX/apple-kext-linkage.C @@ -13,21 +13,21 @@ void foo() { Derived d1; // ok } -// CHECK: define internal i32 @_Z1fj( +// CHECK-LABEL: define internal i32 @_Z1fj( inline unsigned f(unsigned n) { return n == 0 ? 0 : n + f(n-1); } unsigned g(unsigned n) { return f(n); } // rdar://problem/10133200: give explicit instantiations external linkage in kernel mode -// CHECK: define void @_Z3barIiEvv() +// CHECK-LABEL: define void @_Z3barIiEvv() template <typename T> void bar() {} template void bar<int>(); -// CHECK: define internal i32 @_Z5identIiET_S0_( +// CHECK-LABEL: define internal i32 @_Z5identIiET_S0_( template <typename X> X ident(X x) { return x; } int foo(int n) { return ident(n); } -// CHECK: define internal void @_ZN7DerivedD1Ev( -// CHECK: define internal void @_ZN7DerivedD0Ev( -// CHECK: define internal void @_ZN7DeriveddlEPv( +// CHECK-LABEL: define internal void @_ZN7DerivedD1Ev( +// CHECK-LABEL: define internal void @_ZN7DerivedD0Ev( +// CHECK-LABEL: define internal void @_ZN7DeriveddlEPv( diff --git a/test/CodeGenCXX/arm-vaarg.cpp b/test/CodeGenCXX/arm-vaarg.cpp new file mode 100644 index 0000000..9850fb3 --- /dev/null +++ b/test/CodeGenCXX/arm-vaarg.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple armv7-apple-ios -emit-llvm -o - %s | FileCheck %s +struct Empty {}; + +Empty emptyvar; + +int take_args(int a, ...) { + __builtin_va_list l; + __builtin_va_start(l, a); +// CHECK: call void @llvm.va_start + + emptyvar = __builtin_va_arg(l, Empty); +// CHECK: load i8** +// CHECK-NOT: getelementptr +// CHECK: [[EMPTY_PTR:%[a-zA-Z0-9._]+]] = bitcast i8* {{%[a-zA-Z0-9._]+}} to %struct.Empty* + + // It's conceivable that EMPTY_PTR may not actually be a valid pointer + // (e.g. it's at the very bottom of the stack and the next page is + // invalid). This doesn't matter provided it's never loaded (there's no + // well-defined way to tell), but it becomes a problem if we do try to use it. +// CHECK-NOT: load %struct.Empty* [[EMPTY_PTR]] + + int i = __builtin_va_arg(l, int); +// CHECK: load i32* + + __builtin_va_end(l); + return i; +} diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp index 48f2f00..2fb9c49 100644 --- a/test/CodeGenCXX/arm.cpp +++ b/test/CodeGenCXX/arm.cpp @@ -28,7 +28,7 @@ bar baz; // CHECK: call [[BAR:%.*]]* @_ZN3barC1Ev( // CHECK-NEXT: call i32 @atexit(void ()* @__dtor_baz) -// CHECK: define internal void @__dtor_baz() +// CHECK-LABEL: define internal void @__dtor_baz() // CHECK: call [[BAR]]* @_ZN3barD1Ev([[BAR]]* @baz) // Destructors and constructors must return this. @@ -41,7 +41,7 @@ namespace test1 { void bar() { foo(); } }; - // CHECK: define void @_ZN5test14testEv() + // CHECK-LABEL: define void @_ZN5test14testEv() void test() { // CHECK: [[AV:%.*]] = alloca [[A:%.*]], align 1 // CHECK: call [[A]]* @_ZN5test11AC1Ei([[A]]* [[AV]], i32 10) @@ -52,19 +52,19 @@ namespace test1 { a.bar(); } - // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* returned %this, i32 %i) unnamed_addr // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] - // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei( - // CHECK: ret [[A]]* [[THIS2]] + // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AC2Ei( + // CHECK: ret [[A]]* [[THIS1]] - // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* returned %this) unnamed_addr // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] - // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev( - // CHECK: ret [[A]]* [[THIS2]] + // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AD2Ev( + // CHECK: ret [[A]]* [[THIS1]] } // Awkward virtual cases. @@ -107,7 +107,7 @@ namespace test3 { }; void a() { - // CHECK: define void @_ZN5test31aEv() + // CHECK-LABEL: define void @_ZN5test31aEv() // CHECK: call noalias i8* @_Znam(i32 48) // CHECK: store i32 4 // CHECK: store i32 10 @@ -115,7 +115,7 @@ namespace test3 { } void b(int n) { - // CHECK: define void @_ZN5test31bEi( + // CHECK-LABEL: define void @_ZN5test31bEi( // CHECK: [[N:%.*]] = load i32* // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8) @@ -128,7 +128,7 @@ namespace test3 { } void c() { - // CHECK: define void @_ZN5test31cEv() + // CHECK-LABEL: define void @_ZN5test31cEv() // CHECK: call noalias i8* @_Znam(i32 808) // CHECK: store i32 4 // CHECK: store i32 200 @@ -136,7 +136,7 @@ namespace test3 { } void d(int n) { - // CHECK: define void @_ZN5test31dEi( + // CHECK-LABEL: define void @_ZN5test31dEi( // CHECK: [[N:%.*]] = load i32* // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80) // CHECK: [[NE:%.*]] = mul i32 [[N]], 20 @@ -149,7 +149,7 @@ namespace test3 { } void e(A *x) { - // CHECK: define void @_ZN5test31eEPNS_1AE( + // CHECK-LABEL: define void @_ZN5test31eEPNS_1AE( // CHECK: icmp eq {{.*}}, null // CHECK: getelementptr {{.*}}, i64 -8 // CHECK: getelementptr {{.*}}, i64 4 @@ -161,7 +161,7 @@ namespace test3 { } void f(A (*x)[20]) { - // CHECK: define void @_ZN5test31fEPA20_NS_1AE( + // CHECK-LABEL: define void @_ZN5test31fEPA20_NS_1AE( // CHECK: icmp eq {{.*}}, null // CHECK: getelementptr {{.*}}, i64 -8 // CHECK: getelementptr {{.*}}, i64 4 @@ -180,7 +180,7 @@ namespace test4 { }; void a() { - // CHECK: define void @_ZN5test41aEv() + // CHECK-LABEL: define void @_ZN5test41aEv() // CHECK: call noalias i8* @_Znam(i32 48) // CHECK: store i32 4 // CHECK: store i32 10 @@ -188,7 +188,7 @@ namespace test4 { } void b(int n) { - // CHECK: define void @_ZN5test41bEi( + // CHECK-LABEL: define void @_ZN5test41bEi( // CHECK: [[N:%.*]] = load i32* // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8) @@ -200,7 +200,7 @@ namespace test4 { } void c() { - // CHECK: define void @_ZN5test41cEv() + // CHECK-LABEL: define void @_ZN5test41cEv() // CHECK: call noalias i8* @_Znam(i32 808) // CHECK: store i32 4 // CHECK: store i32 200 @@ -208,7 +208,7 @@ namespace test4 { } void d(int n) { - // CHECK: define void @_ZN5test41dEi( + // CHECK-LABEL: define void @_ZN5test41dEi( // CHECK: [[N:%.*]] = load i32* // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80) // CHECK: [[NE:%.*]] = mul i32 [[N]], 20 @@ -221,7 +221,7 @@ namespace test4 { } void e(A *x) { - // CHECK: define void @_ZN5test41eEPNS_1AE( + // CHECK-LABEL: define void @_ZN5test41eEPNS_1AE( // CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8 // CHECK: getelementptr inbounds {{.*}}, i64 4 // CHECK: bitcast @@ -233,7 +233,7 @@ namespace test4 { } void f(A (*x)[20]) { - // CHECK: define void @_ZN5test41fEPA20_NS_1AE( + // CHECK-LABEL: define void @_ZN5test41fEPA20_NS_1AE( // CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8 // CHECK: getelementptr inbounds {{.*}}, i64 4 // CHECK: bitcast @@ -251,7 +251,7 @@ namespace test5 { ~A(); }; - // CHECK: define void @_ZN5test54testEPNS_1AE + // CHECK-LABEL: define void @_ZN5test54testEPNS_1AE void test(A *a) { // CHECK: [[PTR:%.*]] = alloca [[A:%.*]]*, align 4 // CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[PTR]], align 4 @@ -267,7 +267,7 @@ namespace test6 { virtual ~A(); }; - // CHECK: define void @_ZN5test64testEPNS_1AE + // CHECK-LABEL: define void @_ZN5test64testEPNS_1AE void test(A *a) { // CHECK: [[AVAR:%.*]] = alloca [[A:%.*]]*, align 4 // CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[AVAR]], align 4 @@ -290,7 +290,7 @@ namespace test7 { // Static and guard tested at top of file - // CHECK: define void @_ZN5test74testEv() + // CHECK-LABEL: define void @_ZN5test74testEv() void test() { // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test74testEvE1x // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1 @@ -325,7 +325,7 @@ namespace test8 { // Static and guard tested at top of file - // CHECK: define void @_ZN5test84testEv() + // CHECK-LABEL: define void @_ZN5test84testEv() void test() { // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test84testEvE1x // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1 @@ -394,7 +394,7 @@ namespace test9 { void testDelete(A *array) { delete[] array; } -// CHECK: define void @_ZN5test910testDeleteEPNS_1AE( +// CHECK-LABEL: define void @_ZN5test910testDeleteEPNS_1AE( // CHECK: [[BEGIN:%.*]] = load [[TEST9]]** // CHECK-NEXT: [[T0:%.*]] = icmp eq [[TEST9]]* [[BEGIN]], null // CHECK-NEXT: br i1 [[T0]], @@ -413,7 +413,7 @@ namespace test9 { // CHECK: call [[C]]* @_ZN5test21CD1Ev( // CHECK: ret [[C]]* undef - // CHECK: define linkonce_odr void @_ZTv0_n12_N5test21CD0Ev( + // CHECK-LABEL: define linkonce_odr void @_ZTv0_n12_N5test21CD0Ev( // CHECK: call void @_ZN5test21CD0Ev( // CHECK: ret void diff --git a/test/CodeGenCXX/array-construction.cpp b/test/CodeGenCXX/array-construction.cpp index 7b565a4..645ad1d 100644 --- a/test/CodeGenCXX/array-construction.cpp +++ b/test/CodeGenCXX/array-construction.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/array-operator-delete-call.cpp b/test/CodeGenCXX/array-operator-delete-call.cpp index 1b23c4d..8d6f50f 100644 --- a/test/CodeGenCXX/array-operator-delete-call.cpp +++ b/test/CodeGenCXX/array-operator-delete-call.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/atomic.cpp b/test/CodeGenCXX/atomic.cpp index 36bb4ef..653f16d 100644 --- a/test/CodeGenCXX/atomic.cpp +++ b/test/CodeGenCXX/atomic.cpp @@ -5,7 +5,7 @@ namespace PR11411 { void f(); }; - // CHECK: define linkonce_odr void @_ZN7PR114113PtrIiE1fEv + // CHECK-LABEL: define linkonce_odr void @_ZN7PR114113PtrIiE1fEv // CHECK-NOT: ret template<typename _Tp> inline void Ptr<_Tp>::f() { int* _refcount; diff --git a/test/CodeGenCXX/atomicinit.cpp b/test/CodeGenCXX/atomicinit.cpp index 38d012e..ee2e9e4 100644 --- a/test/CodeGenCXX/atomicinit.cpp +++ b/test/CodeGenCXX/atomicinit.cpp @@ -18,7 +18,7 @@ struct B { _Atomic(B) b; -// CHECK: define void @_Z11atomic_initR1Ai +// CHECK-LABEL: define void @_Z11atomic_initR1Ai void atomic_init(A& a, int i) { // CHECK-NOT: atomic // CHECK: tail call void @_ZN1BC1Ei @@ -26,7 +26,7 @@ void atomic_init(A& a, int i) { // CHECK-NEXT: ret void } -// CHECK: define void @_Z16atomic_init_boolPU7_Atomicbb +// CHECK-LABEL: define void @_Z16atomic_init_boolPU7_Atomicbb void atomic_init_bool(_Atomic(bool) *ab, bool b) { // CHECK-NOT: atomic // CHECK: {{zext i1.*to i8}} @@ -40,7 +40,7 @@ struct AtomicBoolMember { AtomicBoolMember(bool b); }; -// CHECK: define void @_ZN16AtomicBoolMemberC2Eb +// CHECK-LABEL: define void @_ZN16AtomicBoolMemberC2Eb // CHECK: {{zext i1.*to i8}} // CHECK-NEXT: store i8 // CHECK-NEXT: ret void diff --git a/test/CodeGenCXX/attr-cleanup.cpp b/test/CodeGenCXX/attr-cleanup.cpp new file mode 100644 index 0000000..ff15b03 --- /dev/null +++ b/test/CodeGenCXX/attr-cleanup.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +namespace N { + void free(void *i) {} +} + +int main(void) { + // CHECK: call void @_ZN1N4freeEPv + void *fp __attribute__((cleanup(N::free))); + return 0; +} diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp index 4748cda..8bcff36 100644 --- a/test/CodeGenCXX/attr.cpp +++ b/test/CodeGenCXX/attr.cpp @@ -26,7 +26,7 @@ void C::bar3() { } void C::bar4() { } // PR6635 -// CHECK: define i32 @_Z5test1v() +// CHECK-LABEL: define i32 @_Z5test1v() int test1() { return 10; } // CHECK at top of file extern "C" int test2() __attribute__((alias("_Z5test1v"))); diff --git a/test/CodeGenCXX/bitfield-layout.cpp b/test/CodeGenCXX/bitfield-layout.cpp index 15f33d2..646300a 100644 --- a/test/CodeGenCXX/bitfield-layout.cpp +++ b/test/CodeGenCXX/bitfield-layout.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP64 %s -// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP32 %s +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix CHECK-LP64 %s +// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix CHECK-LP32 %s // CHECK-LP64: %union.Test1 = type { i32, [4 x i8] } union Test1 { diff --git a/test/CodeGenCXX/bitfield.cpp b/test/CodeGenCXX/bitfield.cpp index 1814aa2..2c454b0 100644 --- a/test/CodeGenCXX/bitfield.cpp +++ b/test/CodeGenCXX/bitfield.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ // RUN: | FileCheck -check-prefix=CHECK-X86-64 %s -// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -verify -emit-llvm -o - %s \ +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm -o - %s \ // RUN: | FileCheck -check-prefix=CHECK-PPC64 %s // // Tests for bitfield access patterns in C++ with special attention to @@ -20,13 +20,13 @@ namespace N0 { unsigned b71 : 2; }; unsigned read00(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read00 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read00 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[and:.*]] = and i64 %[[val]], 16383 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read00 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read00 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 50 @@ -35,14 +35,14 @@ namespace N0 { return s->b00; } unsigned read01(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read01 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read01 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 14 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read01 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read01 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 48 @@ -52,14 +52,14 @@ namespace N0 { return s->b01; } unsigned read20(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read20 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read20 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 16 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read20 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read20 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 42 @@ -69,14 +69,14 @@ namespace N0 { return s->b20; } unsigned read21(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read21 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read21 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 22 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read21 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read21 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 40 @@ -86,14 +86,14 @@ namespace N0 { return s->b21; } unsigned read30(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read30 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read30 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 24 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 1073741823 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read30 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read30 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 10 @@ -103,14 +103,14 @@ namespace N0 { return s->b30; } unsigned read31(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read31 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read31 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 54 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read31 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read31 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 8 @@ -120,14 +120,14 @@ namespace N0 { return s->b31; } unsigned read70(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read70 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read70 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 56 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read70 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read70 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 2 @@ -137,13 +137,13 @@ namespace N0 { return s->b70; } unsigned read71(S* s) { - // CHECK-X86-64: define i32 @_ZN2N06read71 + // CHECK-X86-64-LABEL: define i32 @_ZN2N06read71 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 62 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32 // CHECK-X86-64: ret i32 %[[trunc]] - // CHECK-PPC64: define zeroext i32 @_ZN2N06read71 + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read71 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64* // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]] // CHECK-PPC64: %[[and:.*]] = and i64 %[[val]], 3 @@ -166,13 +166,13 @@ namespace N1 { char c; }; unsigned read(S* s) { - // CHECK-X86-64: define i32 @_ZN2N14read + // CHECK-X86-64-LABEL: define i32 @_ZN2N14read // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-X86-64: %[[val:.*]] = load i8* %[[ptr]] // CHECK-X86-64: %[[and:.*]] = and i8 %[[val]], 1 // CHECK-X86-64: %[[ext:.*]] = zext i8 %[[and]] to i32 // CHECK-X86-64: ret i32 %[[ext]] - // CHECK-PPC64: define zeroext i32 @_ZN2N14read + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N14read // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-PPC64: %[[val:.*]] = load i8* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7 @@ -181,7 +181,7 @@ namespace N1 { return s->b; } void write(S* s, unsigned x) { - // CHECK-X86-64: define void @_ZN2N15write + // CHECK-X86-64-LABEL: define void @_ZN2N15write // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8 // CHECK-X86-64: %[[old:.*]] = load i8* %[[ptr]] @@ -189,7 +189,7 @@ namespace N1 { // CHECK-X86-64: %[[old_and:.*]] = and i8 %[[old]], -2 // CHECK-X86-64: %[[new:.*]] = or i8 %[[old_and]], %[[x_and]] // CHECK-X86-64: store i8 %[[new]], i8* %[[ptr]] - // CHECK-PPC64: define void @_ZN2N15write + // CHECK-PPC64-LABEL: define void @_ZN2N15write // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8 // CHECK-PPC64: %[[old:.*]] = load i8* %[[ptr]] @@ -210,12 +210,12 @@ namespace N2 { void *p; }; unsigned read(S* s) { - // CHECK-X86-64: define i32 @_ZN2N24read + // CHECK-X86-64-LABEL: define i32 @_ZN2N24read // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]] // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215 // CHECK-X86-64: ret i32 %[[and]] - // CHECK-PPC64: define zeroext i32 @_ZN2N24read + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N24read // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8 @@ -223,14 +223,14 @@ namespace N2 { return s->b; } void write(S* s, unsigned x) { - // CHECK-X86-64: define void @_ZN2N25write + // CHECK-X86-64-LABEL: define void @_ZN2N25write // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]] // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]] // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]] - // CHECK-PPC64: define void @_ZN2N25write + // CHECK-PPC64-LABEL: define void @_ZN2N25write // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]] // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 @@ -249,12 +249,12 @@ namespace N3 { unsigned b : 24; }; unsigned read(S* s) { - // CHECK-X86-64: define i32 @_ZN2N34read + // CHECK-X86-64-LABEL: define i32 @_ZN2N34read // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]] // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215 // CHECK-X86-64: ret i32 %[[and]] - // CHECK-PPC64: define zeroext i32 @_ZN2N34read + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N34read // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8 @@ -262,14 +262,14 @@ namespace N3 { return s->b; } void write(S* s, unsigned x) { - // CHECK-X86-64: define void @_ZN2N35write + // CHECK-X86-64-LABEL: define void @_ZN2N35write // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]] // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]] // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]] - // CHECK-PPC64: define void @_ZN2N35write + // CHECK-PPC64-LABEL: define void @_ZN2N35write // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]] // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 @@ -300,13 +300,13 @@ namespace N4 { // FIXME: We should widen this load as long as the function isn't being // instrumented by thread-sanitizer. // - // CHECK-X86-64: define i32 @_ZN2N44read + // CHECK-X86-64-LABEL: define i32 @_ZN2N44read // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24* // CHECK-X86-64: %[[val:.*]] = load i24* %[[ptr]] // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32 // CHECK-X86-64: ret i32 %[[ext]] - // CHECK-PPC64: define zeroext i32 @_ZN2N44read + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N44read // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24* // CHECK-PPC64: %[[val:.*]] = load i24* %[[ptr]] @@ -315,12 +315,12 @@ namespace N4 { return s->b; } void write(Base* s, unsigned x) { - // CHECK-X86-64: define void @_ZN2N45write + // CHECK-X86-64-LABEL: define void @_ZN2N45write // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24* // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24 // CHECK-X86-64: store i24 %[[new]], i24* %[[ptr]] - // CHECK-PPC64: define void @_ZN2N45write + // CHECK-PPC64-LABEL: define void @_ZN2N45write // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24* // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24 @@ -342,12 +342,12 @@ namespace N5 { struct Y { unsigned b : 24; } y; }; unsigned read(U* u) { - // CHECK-X86-64: define i32 @_ZN2N54read + // CHECK-X86-64-LABEL: define i32 @_ZN2N54read // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]] // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215 // CHECK-X86-64: ret i32 %[[and]] - // CHECK-PPC64: define zeroext i32 @_ZN2N54read + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N54read // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]] // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8 @@ -355,14 +355,14 @@ namespace N5 { return u->y.b; } void write(U* u, unsigned x) { - // CHECK-X86-64: define void @_ZN2N55write + // CHECK-X86-64-LABEL: define void @_ZN2N55write // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]] // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]] // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]] - // CHECK-PPC64: define void @_ZN2N55write + // CHECK-PPC64-LABEL: define void @_ZN2N55write // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32* // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]] // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 @@ -387,7 +387,7 @@ namespace N6 { unsigned char b2 : 8; }; unsigned read(S* s) { - // CHECK-X86-64: define i32 @_ZN2N64read + // CHECK-X86-64-LABEL: define i32 @_ZN2N64read // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24* // CHECK-X86-64: %[[val1:.*]] = load i24* %[[ptr1]] // CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32 @@ -396,7 +396,7 @@ namespace N6 { // CHECK-X86-64: %[[ext2:.*]] = zext i8 %[[val2]] to i32 // CHECK-X86-64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]] // CHECK-X86-64: ret i32 %[[add]] - // CHECK-PPC64: define zeroext i32 @_ZN2N64read + // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N64read // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24* // CHECK-PPC64: %[[val1:.*]] = load i24* %[[ptr1]] // CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32 @@ -408,14 +408,14 @@ namespace N6 { return s->b1 + s->b2; } void write(S* s, unsigned x) { - // CHECK-X86-64: define void @_ZN2N65write + // CHECK-X86-64-LABEL: define void @_ZN2N65write // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24* // CHECK-X86-64: %[[new1:.*]] = trunc i32 %{{.*}} to i24 // CHECK-X86-64: store i24 %[[new1]], i24* %[[ptr1]] // CHECK-X86-64: %[[new2:.*]] = trunc i32 %{{.*}} to i8 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1 // CHECK-X86-64: store i8 %[[new2]], i8* %[[ptr2]] - // CHECK-PPC64: define void @_ZN2N65write + // CHECK-PPC64-LABEL: define void @_ZN2N65write // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24* // CHECK-PPC64: %[[new1:.*]] = trunc i32 %{{.*}} to i24 // CHECK-PPC64: store i24 %[[new1]], i24* %[[ptr1]] diff --git a/test/CodeGenCXX/block-byref-cxx-objc.cpp b/test/CodeGenCXX/block-byref-cxx-objc.cpp index 30f1f07..616fd67 100644 --- a/test/CodeGenCXX/block-byref-cxx-objc.cpp +++ b/test/CodeGenCXX/block-byref-cxx-objc.cpp @@ -15,13 +15,13 @@ int main() return 0; } -// CHECK: define internal void @__Block_byref_object_copy_ +// CHECK-LABEL: define internal void @__Block_byref_object_copy_ // CHECK: call {{.*}} @_ZN1AC1ERKS_ -// CHECK: define internal void @__Block_byref_object_dispose_ +// CHECK-LABEL: define internal void @__Block_byref_object_dispose_ // CHECK: call {{.*}} @_ZN1AD1Ev -// CHECK: define internal void @__copy_helper_block_ +// CHECK-LABEL: define internal void @__copy_helper_block_ // CHECK: call void @_Block_object_assign -// CHECK: define internal void @__destroy_helper_block_ +// CHECK-LABEL: define internal void @__destroy_helper_block_ // CHECK: call void @_Block_object_dispose // rdar://problem/11135650 diff --git a/test/CodeGenCXX/block-in-ctor-dtor.cpp b/test/CodeGenCXX/block-in-ctor-dtor.cpp index 4ee6b1c..bd37d44 100644 --- a/test/CodeGenCXX/block-in-ctor-dtor.cpp +++ b/test/CodeGenCXX/block-in-ctor-dtor.cpp @@ -36,13 +36,13 @@ X::~X() { }; -// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke -// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke_ -// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke -// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke_ -// CHECK: define internal void @___ZN1XC1Ev_block_invoke -// CHECK: define internal void @___ZN1XC1Ev_block_invoke_ -// CHECK: define internal void @___ZN1XC2Ev_block_invoke -// CHECK: define internal void @___ZN1XC2Ev_block_invoke_ -// CHECK: define internal void @___ZN1XD2Ev_block_invoke -// CHECK: define internal void @___ZN1XD2Ev_block_invoke_ +// CHECK-LABEL: define internal void @___ZN4ZoneC2Ev_block_invoke +// CHECK-LABEL: define internal void @___ZN4ZoneC2Ev_block_invoke_ +// CHECK-LABEL: define internal void @___ZN4ZoneD2Ev_block_invoke +// CHECK-LABEL: define internal void @___ZN4ZoneD2Ev_block_invoke_ +// CHECK-LABEL: define internal void @___ZN1XC1Ev_block_invoke +// CHECK-LABEL: define internal void @___ZN1XC1Ev_block_invoke_ +// CHECK-LABEL: define internal void @___ZN1XC2Ev_block_invoke +// CHECK-LABEL: define internal void @___ZN1XC2Ev_block_invoke_ +// CHECK-LABEL: define internal void @___ZN1XD2Ev_block_invoke +// CHECK-LABEL: define internal void @___ZN1XD2Ev_block_invoke_ diff --git a/test/CodeGenCXX/blocks-cxx11.cpp b/test/CodeGenCXX/blocks-cxx11.cpp index 3f0380a..9ff5826 100644 --- a/test/CodeGenCXX/blocks-cxx11.cpp +++ b/test/CodeGenCXX/blocks-cxx11.cpp @@ -46,7 +46,7 @@ namespace test_complex_int { void test() { constexpr _Complex int x = 500; takeABlock(^{ takeItByValue(x); }); - // CHECK: store i32 500, + // CHECK: store { i32, i32 } { i32 500, i32 0 }, // CHECK: store i32 500, // CHECK-NEXT: store i32 0, @@ -100,7 +100,7 @@ namespace test_block_in_lambda { }; lambda(); // make sure we emit the invocation function } - // CHECK: define internal void @"_ZZN20test_block_in_lambda4testENS_1AEENK3$_0clEv"( + // CHECK-LABEL: define internal void @"_ZZN20test_block_in_lambda4testENS_1AEENK3$_0clEv"( // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 // CHECK: [[THIS:%.*]] = load [[LAMBDA_T:%.*]]** // CHECK: [[TO_DESTROY:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp index 81eef0e..8a6fdac 100644 --- a/test/CodeGenCXX/blocks.cpp +++ b/test/CodeGenCXX/blocks.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s namespace test0 { - // CHECK: define void @_ZN5test04testEi( + // CHECK-LABEL: define void @_ZN5test04testEi( // CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}( // CHECK: define internal void @___ZN5test04testEi_block_invoke_2{{.*}}( void test(int x) { @@ -13,7 +13,7 @@ extern void (^out)(); namespace test1 { // Capturing const objects doesn't require a local block. - // CHECK: define void @_ZN5test15test1Ev() + // CHECK-LABEL: define void @_ZN5test15test1Ev() // CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out void test1() { const int NumHorsemen = 4; @@ -21,7 +21,7 @@ namespace test1 { } // That applies to structs too... - // CHECK: define void @_ZN5test15test2Ev() + // CHECK-LABEL: define void @_ZN5test15test2Ev() // CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out struct loc { double x, y; }; void test2() { @@ -30,7 +30,7 @@ namespace test1 { } // ...unless they have mutable fields... - // CHECK: define void @_ZN5test15test3Ev() + // CHECK-LABEL: define void @_ZN5test15test3Ev() // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* // CHECK: store void ()* [[T0]], void ()** @out @@ -41,7 +41,7 @@ namespace test1 { } // ...or non-trivial destructors... - // CHECK: define void @_ZN5test15test4Ev() + // CHECK-LABEL: define void @_ZN5test15test4Ev() // CHECK: [[OBJ:%.*]] = alloca // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* @@ -69,22 +69,22 @@ namespace test2 { ~B(); }; - // CHECK: define void @_ZN5test24testEv() + // CHECK-LABEL: define void @_ZN5test24testEv() void test() { __block A a; __block B b; } - // CHECK: define internal void @__Block_byref_object_copy + // CHECK-LABEL: define internal void @__Block_byref_object_copy // CHECK: call void @_ZN5test21AC1ERKS0_( - // CHECK: define internal void @__Block_byref_object_dispose + // CHECK-LABEL: define internal void @__Block_byref_object_dispose // CHECK: call void @_ZN5test21AD1Ev( - // CHECK: define internal void @__Block_byref_object_copy + // CHECK-LABEL: define internal void @__Block_byref_object_copy // CHECK: call void @_ZN5test21BC1ERKS0_( - // CHECK: define internal void @__Block_byref_object_dispose + // CHECK-LABEL: define internal void @__Block_byref_object_dispose // CHECK: call void @_ZN5test21BD1Ev( } @@ -118,8 +118,8 @@ namespace test4 { extern void consume(void(^)()); consume(^{ return foo(A()); }); } - // CHECK: define void @_ZN5test44testEv() - // CHECK: define internal void @___ZN5test44testEv_block_invoke + // CHECK-LABEL: define void @_ZN5test44testEv() + // CHECK-LABEL: define internal void @___ZN5test44testEv_block_invoke // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1 // CHECK-NEXT: store i8* [[BLOCKDESC:%.*]], i8** {{.*}}, align 8 // CHECK-NEXT: load i8* @@ -147,7 +147,7 @@ namespace test5 { doWithBlock(b); } - // CHECK: define void @_ZN5test54testEb( + // CHECK-LABEL: define void @_ZN5test54testEb( // CHECK: [[COND:%.*]] = alloca i8 // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4 // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8 @@ -197,7 +197,7 @@ namespace test6 { bar(); } - // CHECK: define void @_ZN5test64testEv() + // CHECK-LABEL: define void @_ZN5test64testEv() // CHECK: [[TEMP:%.*]] = alloca [[A:%.*]], align 1 // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]]) // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE( diff --git a/test/CodeGenCXX/bool-bitfield.cpp b/test/CodeGenCXX/bool-bitfield.cpp index 06bdf2b..a5a344f 100644 --- a/test/CodeGenCXX/bool-bitfield.cpp +++ b/test/CodeGenCXX/bool-bitfield.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ // RUN: | FileCheck %s // PR14638; make sure this doesn't crash. @@ -9,6 +9,6 @@ void func1(bool b, A& a1) { if ((a1.m_sorted = b)) {} } -// CHECK: define void @_Z5func1bR1A +// CHECK-LABEL: define void @_Z5func1bR1A // CHECK: br i1 // CHECK: ret void diff --git a/test/CodeGenCXX/builtins.cpp b/test/CodeGenCXX/builtins.cpp index c9b0bff..98e2d1a 100644 --- a/test/CodeGenCXX/builtins.cpp +++ b/test/CodeGenCXX/builtins.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s // PR8839 extern "C" char memmove(); @@ -7,3 +7,22 @@ int main() { // CHECK: call {{signext i8|i8}} @memmove() return memmove(); } + +struct S; +// CHECK: define {{.*}} @_Z9addressofbR1SS0_( +S *addressof(bool b, S &s, S &t) { + // CHECK: %[[LVALUE:.*]] = phi + // CHECK: ret {{.*}}* %[[LVALUE]] + return __builtin_addressof(b ? s : t); +} + +extern "C" int __builtin_abs(int); // #1 +long __builtin_abs(long); // #2 +extern "C" int __builtin_abs(int); // #3 + +int x = __builtin_abs(-2); +// CHECK: store i32 2, i32* @x, align 4 + +long y = __builtin_abs(-2l); +// CHECK: [[Y:%.+]] = call i64 @_Z13__builtin_absl(i64 -2) +// CHECK: store i64 [[Y]], i64* @y, align 8 diff --git a/test/CodeGenCXX/c-linkage.cpp b/test/CodeGenCXX/c-linkage.cpp index f6e64d9..1607623 100644 --- a/test/CodeGenCXX/c-linkage.cpp +++ b/test/CodeGenCXX/c-linkage.cpp @@ -10,15 +10,15 @@ extern "C" { } } -// CHECK: define void @_ZN1N1X1fEv +// CHECK-LABEL: define void @_ZN1N1X1fEv extern "C" { static void test2_f() { } - // CHECK: define internal void @_Z7test2_fv + // CHECK-LABEL: define internal void @_Z7test2_fv static void test2_f(int x) { } - // CHECK: define internal void @_Z7test2_fi + // CHECK-LABEL: define internal void @_Z7test2_fi void test2_use() { test2_f(); test2_f(42); diff --git a/test/CodeGenCXX/c99-variable-length-array.cpp b/test/CodeGenCXX/c99-variable-length-array.cpp index d486f9b..2cd8e11 100644 --- a/test/CodeGenCXX/c99-variable-length-array.cpp +++ b/test/CodeGenCXX/c99-variable-length-array.cpp @@ -9,7 +9,7 @@ struct Y { ~Y(); }; -// CHECK: define void @_Z1fiPPKc( +// CHECK-LABEL: define void @_Z1fiPPKc( void f(int argc, const char* argv[]) { // CHECK: call void @_ZN1XC1Ev X x; diff --git a/test/CodeGenCXX/call-arg-zero-temp.cpp b/test/CodeGenCXX/call-arg-zero-temp.cpp index 101e81f..14238f2 100644 --- a/test/CodeGenCXX/call-arg-zero-temp.cpp +++ b/test/CodeGenCXX/call-arg-zero-temp.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/captured-statements.cpp b/test/CodeGenCXX/captured-statements.cpp new file mode 100644 index 0000000..2843c2b --- /dev/null +++ b/test/CodeGenCXX/captured-statements.cpp @@ -0,0 +1,189 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o %t +// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1 +// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2 +// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3 +// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-4 +// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-5 +// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-6 +// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-7 + +struct Foo { + int x; + float y; + ~Foo() {} +}; + +struct TestClass { + int x; + + TestClass() : x(0) {}; + void MemberFunc() { + Foo f; + #pragma clang __debug captured + { + f.y = x; + } + } +}; + +void test1() { + TestClass c; + c.MemberFunc(); + // CHECK-1: %[[Capture:struct\.anon[\.0-9]*]] = type { %struct.Foo*, %struct.TestClass* } + + // CHECK-1: define {{.*}} void @_ZN9TestClass10MemberFuncEv + // CHECK-1: alloca %struct.anon + // CHECK-1: getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 0 + // CHECK-1: store %struct.Foo* %f, %struct.Foo** + // CHECK-1: getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 1 + // CHECK-1: call void @[[HelperName:[A-Za-z0-9_]+]](%[[Capture]]* + // CHECK-1: call {{.*}}FooD1Ev + // CHECK-1: ret +} + +// CHECK-1: define internal void @[[HelperName]] +// CHECK-1: getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 1 +// CHECK-1: getelementptr inbounds %struct.TestClass* {{[^,]*}}, i32 0, i32 0 +// CHECK-1: getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 0 + +void test2(int x) { + int y = [&]() { + #pragma clang __debug captured + { + x++; + } + return x; + }(); + + // CHECK-2-LABEL: define void @_Z5test2i + // CHECK-2: call {{.*}} @[[Lambda:["$\w]+]] + // + // CHECK-2: define internal {{.*}} @[[Lambda]] + // CHECK-2: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]* + // + // CHECK-2: define internal void @[[HelperName]] + // CHECK-2: getelementptr inbounds %[[Capture]]* + // CHECK-2: load i32** + // CHECK-2: load i32* +} + +void test3(int x) { + #pragma clang __debug captured + { + x = [=]() { return x + 1; } (); + } + + // CHECK-3: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* } + + // CHECK-3-LABEL: define void @_Z5test3i + // CHECK-3: store i32* + // CHECK-3: call void @{{.*}}__captured_stmt + // CHECK-3: ret void +} + +void test4() { + #pragma clang __debug captured + { + Foo f; + f.x = 5; + } + // CHECK-4-LABEL: define void @_Z5test4v + // CHECK-4: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]* + // CHECK-4: ret void + // + // CHECK-4: define internal void @[[HelperName]] + // CHECK-4: store i32 5, i32* + // CHECK-4: call {{.*}}FooD1Ev +} + +template <typename T, int id> +void touch(const T &) {} + +template <typename T, unsigned id> +void template_capture_var() { + T x; + #pragma clang __debug captured + { + touch<T, id>(x); + } +} + +template <typename T, int id> +class Val { + T v; +public: + void set() { + #pragma clang __debug captured + { + touch<T, id>(v); + } + } + + template <typename U, int id2> + void foo(U u) { + #pragma clang __debug captured + { + touch<U, id + id2>(u); + } + } +}; + +void test_capture_var() { + // CHECK-5: define {{.*}} void @_Z20template_capture_varIiLj201EEvv + // CHECK-5-NOT: } + // CHECK-5: store i32* + // CHECK-5: call void @__captured_stmt + // CHECK-5-NEXT: ret void + template_capture_var<int, 201>(); + + // CHECK-5: define {{.*}} void @_ZN3ValIfLi202EE3setEv + // CHECK-5-NOT: } + // CHECK-5: store %class.Val* + // CHECK-5: call void @__captured_stmt + // CHECK-5-NEXT: ret void + Val<float, 202> Obj; + Obj.set(); + + // CHECK-5: define {{.*}} void @_ZN3ValIfLi202EE3fooIdLi203EEEvT_ + // CHECK-5-NOT: } + // CHECK-5: store %class.Val* + // CHECK-5: store double + // CHECK-5: call void @__captured_stmt + // CHECK-5-NEXT: ret void + Obj.foo<double, 203>(1.0); +} + +template <typename T> +void template_capture_lambda() { + T x, y; + [=, &y]() { + #pragma clang __debug captured + { + y += x; + } + }(); +} + +void test_capture_lambda() { + // CHECK-6: define {{.*}} void @_ZZ23template_capture_lambdaIiEvvENKUlvE_clEv + // CHECK-6-NOT: } + // CHECK-6: store i32* + // CHECK-6: store i32* + // CHECK-6: call void @__captured_stmt + // CHECK-6-NEXT: ret void + template_capture_lambda<int>(); +} + +inline int test_captured_linkage() { + // CHECK-7: @_ZZ21test_captured_linkagevE1i = linkonce_odr global i32 0 + int j; + #pragma clang __debug captured + { + static int i = 0; + j = ++i; + } + return j; +} +void call_test_captured_linkage() { + test_captured_linkage(); +} diff --git a/test/CodeGenCXX/cast-conversion.cpp b/test/CodeGenCXX/cast-conversion.cpp index d023b9a..5565f65 100644 --- a/test/CodeGenCXX/cast-conversion.cpp +++ b/test/CodeGenCXX/cast-conversion.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s struct A { A(int); diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp index d6d0edfa..338da57 100644 --- a/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/test/CodeGenCXX/catch-undef-behavior.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,bounds -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s struct S { double d; @@ -186,7 +186,7 @@ void bad_downcast_pointer(S *p) { // CHECK: %[[NONNULL:.*]] = icmp ne {{.*}}, null // CHECK: br i1 %[[NONNULL]], - // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64( + // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8( // CHECK: %[[E1:.*]] = icmp uge i64 %[[SIZE]], 24 // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7 // CHECK: %[[E2:.*]] = icmp eq i64 %[[MISALIGN]], 0 @@ -207,7 +207,7 @@ void bad_downcast_pointer(S *p) { void bad_downcast_reference(S &p) { // CHECK: %[[E1:.*]] = icmp ne {{.*}}, null // CHECK-NOT: br i1 - // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64( + // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8( // CHECK: %[[E2:.*]] = icmp uge i64 %[[SIZE]], 24 // CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]] // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7 @@ -321,4 +321,156 @@ char string_index(int n) { return "Hello"[n]; } +class A // align=4 +{ + int a1, a2, a3; +}; + +class B // align=8 +{ + long b1, b2; +}; + +class C : public A, public B // align=16 +{ + alignas(16) int c1; +}; + +// Make sure we check the alignment of the pointer after subtracting any +// offset. The pointer before subtraction doesn't need to be aligned for +// the destination type. + +// CHECK-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b) +void downcast_pointer(B *b) { + (void) static_cast<C*>(b); + // Alignment check from EmitTypeCheck(TCK_DowncastPointer, ...) + // CHECK: [[SUB:%[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16 + // CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C* + // null check goes here + // CHECK: [[FROM_PHI:%[0-9]*]] = phi %class.C* [ [[C]], {{.*}} ], {{.*}} + // Objectsize check goes here + // CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[FROM_PHI]] to i64 + // CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15 + // CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0 + // AND the alignment test with the objectsize test. + // CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]] + // CHECK-NEXT: br i1 [[AND]] +} + +// CHECK-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b) +void downcast_reference(B &b) { + (void) static_cast<C&>(b); + // Alignment check from EmitTypeCheck(TCK_DowncastReference, ...) + // CHECK: [[SUB:%[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16 + // CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C* + // Objectsize check goes here + // CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[C]] to i64 + // CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15 + // CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0 + // AND the alignment test with the objectsize test. + // CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]] + // CHECK-NEXT: br i1 [[AND]] +} + +// CHECK-LABEL: @_Z22indirect_function_callPFviE({{.*}} prefix <{ i32, i8* }> <{ i32 1413876459, i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*) }> +void indirect_function_call(void (*p)(int)) { + // CHECK: [[PTR:%[0-9]*]] = bitcast void (i32)* {{.*}} to <{ i32, i8* }>* + + // Signature check + // CHECK-NEXT: [[SIGPTR:%[0-9]*]] = getelementptr <{ i32, i8* }>* [[PTR]], i32 0, i32 0 + // CHECK-NEXT: [[SIG:%[0-9]*]] = load i32* [[SIGPTR]] + // CHECK-NEXT: [[SIGCMP:%[0-9]*]] = icmp eq i32 [[SIG]], 1413876459 + // CHECK-NEXT: br i1 [[SIGCMP]] + + // RTTI pointer check + // CHECK: [[RTTIPTR:%[0-9]*]] = getelementptr <{ i32, i8* }>* [[PTR]], i32 0, i32 1 + // CHECK-NEXT: [[RTTI:%[0-9]*]] = load i8** [[RTTIPTR]] + // CHECK-NEXT: [[RTTICMP:%[0-9]*]] = icmp eq i8* [[RTTI]], bitcast ({ i8*, i8* }* @_ZTIFviE to i8*) + // CHECK-NEXT: br i1 [[RTTICMP]] + p(42); +} + +namespace CopyValueRepresentation { + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_ + // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S4aSEOS0_ + // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S5C2ERKS0_ + // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S2C2ERKS0_ + // CHECK: __ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S1C2ERKS0_ + // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value + + struct CustomCopy { CustomCopy(); CustomCopy(const CustomCopy&); }; + struct S1 { + CustomCopy CC; + bool b; + }; + void callee1(S1); + void test1() { + S1 s11; + callee1(s11); + S1 s12; + s12 = s11; + } + + static bool some_global_bool; + struct ExprCopy { + ExprCopy(); + ExprCopy(const ExprCopy&, bool b = some_global_bool); + }; + struct S2 { + ExprCopy EC; + bool b; + }; + void callee2(S2); + void test2(void) { + S2 s21; + callee2(s21); + S2 s22; + s22 = s21; + } + + struct CustomAssign { CustomAssign &operator=(const CustomAssign&); }; + struct S3 { + CustomAssign CA; + bool b; + }; + void test3() { + S3 x, y; + x = y; + } + + struct CustomMove { + CustomMove(); + CustomMove(const CustomMove&&); + CustomMove &operator=(const CustomMove&&); + }; + struct S4 { + CustomMove CM; + bool b; + }; + void test4() { + S4 x, y; + x = static_cast<S4&&>(y); + } + + struct EnumCustomCopy { + EnumCustomCopy(); + EnumCustomCopy(const EnumCustomCopy&); + }; + struct S5 { + EnumCustomCopy ECC; + bool b; + }; + void callee5(S5); + void test5() { + S5 s51; + callee5(s51); + S5 s52; + s52 = s51; + } +} + // CHECK: attributes [[NR_NUW]] = { noreturn nounwind } diff --git a/test/CodeGenCXX/catch-undef-behavior2.cpp b/test/CodeGenCXX/catch-undef-behavior2.cpp new file mode 100644 index 0000000..b8b31ca --- /dev/null +++ b/test/CodeGenCXX/catch-undef-behavior2.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,array-bounds,function -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s + +bool GetOptionalBool(bool *value); +bool GetBool(bool default_value) { + // CHECK-LABEL: @_Z7GetBoolb + // CHECK-NOT: select + bool value; + return GetOptionalBool(&value) ? value : default_value; +} diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp index 5df0ea5..f1d8802 100644 --- a/test/CodeGenCXX/compound-literals.cpp +++ b/test/CodeGenCXX/compound-literals.cpp @@ -12,7 +12,7 @@ struct Y { X x; }; -// CHECK: define i32 @_Z1fv() +// CHECK-LABEL: define i32 @_Z1fv() int f() { // CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}}* [[LVALUE]], i32 0, i32 0 @@ -26,7 +26,7 @@ int f() { return ((Y){17, "seventeen"}).i; } -// CHECK: define i32 @_Z1gv() +// CHECK-LABEL: define i32 @_Z1gv() int g() { // CHECK: store [2 x i32]* %{{[a-z0-9.]+}}, [2 x i32]** [[V:%[a-z0-9.]+]] const int (&v)[2] = (int [2]) {1,2}; diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp index cc2eaf5..452f1c3 100644 --- a/test/CodeGenCXX/condition.cpp +++ b/test/CodeGenCXX/condition.cpp @@ -26,7 +26,7 @@ struct Y { X getX(); -// CHECK: define void @_Z11if_destructi( +// CHECK-LABEL: define void @_Z11if_destructi( void if_destruct(int z) { // Verify that the condition variable is destroyed at the end of the // "if" statement. @@ -95,7 +95,7 @@ void switch_destruct(int z) { int foo(); -// CHECK: define void @_Z14while_destructi +// CHECK-LABEL: define void @_Z14while_destructi void while_destruct(int z) { // CHECK: [[Z:%.*]] = alloca i32 // CHECK: [[CLEANUPDEST:%.*]] = alloca i32 @@ -135,7 +135,7 @@ void while_destruct(int z) { // CHECK: ret } -// CHECK: define void @_Z12for_destructi( +// CHECK-LABEL: define void @_Z12for_destructi( void for_destruct(int z) { // CHECK: [[Z:%.*]] = alloca i32 // CHECK: [[CLEANUPDEST:%.*]] = alloca i32 @@ -224,7 +224,7 @@ void for_destruct(int z) { } void do_destruct(int z) { - // CHECK: define void @_Z11do_destruct + // CHECK-LABEL: define void @_Z11do_destruct do { // CHECK: store i32 77 z = 77; diff --git a/test/CodeGenCXX/conditional-gnu-ext.cpp b/test/CodeGenCXX/conditional-gnu-ext.cpp index 104a91d..44ebf98 100644 --- a/test/CodeGenCXX/conditional-gnu-ext.cpp +++ b/test/CodeGenCXX/conditional-gnu-ext.cpp @@ -77,7 +77,7 @@ namespace test3 { }; B test0(B &x) { - // CHECK: define void @_ZN5test35test0ERNS_1BE( + // CHECK-LABEL: define void @_ZN5test35test0ERNS_1BE( // CHECK: [[X:%.*]] = alloca [[B:%.*]]*, // CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]] // CHECK-NEXT: [[T0:%.*]] = load [[B]]** [[X]] @@ -92,7 +92,7 @@ namespace test3 { } B test1() { - // CHECK: define void @_ZN5test35test1Ev( + // CHECK-LABEL: define void @_ZN5test35test1Ev( // CHECK: [[TEMP:%.*]] = alloca [[B]], // CHECK-NEXT: call void @_ZN5test312test1_helperEv([[B]]* sret [[TEMP]]) // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) @@ -109,7 +109,7 @@ namespace test3 { A test2(B &x) { - // CHECK: define void @_ZN5test35test2ERNS_1BE( + // CHECK-LABEL: define void @_ZN5test35test2ERNS_1BE( // CHECK: [[X:%.*]] = alloca [[B]]*, // CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]] // CHECK-NEXT: [[T0:%.*]] = load [[B]]** [[X]] @@ -124,7 +124,7 @@ namespace test3 { } A test3() { - // CHECK: define void @_ZN5test35test3Ev( + // CHECK-LABEL: define void @_ZN5test35test3Ev( // CHECK: [[TEMP:%.*]] = alloca [[B]], // CHECK-NEXT: call void @_ZN5test312test3_helperEv([[B]]* sret [[TEMP]]) // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) diff --git a/test/CodeGenCXX/conditional-temporaries.cpp b/test/CodeGenCXX/conditional-temporaries.cpp index d538287..a3cc2fe 100644 --- a/test/CodeGenCXX/conditional-temporaries.cpp +++ b/test/CodeGenCXX/conditional-temporaries.cpp @@ -36,19 +36,19 @@ Checker c; } -// CHECK: define i32 @_Z12getCtorCallsv() +// CHECK-LABEL: define i32 @_Z12getCtorCallsv() int getCtorCalls() { // CHECK: ret i32 5 return ctorcalls; } -// CHECK: define i32 @_Z12getDtorCallsv() +// CHECK-LABEL: define i32 @_Z12getDtorCallsv() int getDtorCalls() { // CHECK: ret i32 5 return dtorcalls; } -// CHECK: define zeroext i1 @_Z7successv() +// CHECK-LABEL: define zeroext i1 @_Z7successv() bool success() { // CHECK: ret i1 true return ctorcalls == dtorcalls; diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index 833adba..d21e911 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++11 | FileCheck %s +// RUN: not %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++11 | FileCheck %s // FIXME: The padding in all these objects should be zero-initialized. namespace StructUnion { @@ -224,12 +224,50 @@ namespace LiteralReference { constexpr Lit() : n(5) {} int n; }; - // FIXME: This should have static initialization, but we do not implement - // that yet. For now, just check that we don't set the (pointer) value of - // the reference to 5! - // - // CHECK: @_ZN16LiteralReference3litE = global {{.*}} null + + // This creates a non-const temporary and binds a reference to it. + // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 5 }, align 4 + // CHECK: @_ZN16LiteralReference3litE = constant {{.*}} @[[TEMP]], align 8 const Lit &lit = Lit(); + + // This creates a const temporary as part of the reference initialization. + // CHECK: @[[TEMP:.*]] = private constant {{.*}} { i32 5 }, align 4 + // CHECK: @_ZN16LiteralReference4lit2E = constant {{.*}} @[[TEMP]], align 8 + const Lit &lit2 = {}; + + struct A { int &&r1; const int &&r2; }; + struct B { A &&a1; const A &&a2; }; + B b = { { 0, 1 }, { 2, 3 } }; + // CHECK: @[[TEMP0:.*]] = private global i32 0, align 4 + // CHECK: @[[TEMP1:.*]] = private constant i32 1, align 4 + // CHECK: @[[TEMPA1:.*]] = private global {{.*}} { i32* @[[TEMP0]], i32* @[[TEMP1]] }, align 8 + // CHECK: @[[TEMP2:.*]] = private global i32 2, align 4 + // CHECK: @[[TEMP3:.*]] = private constant i32 3, align 4 + // CHECK: @[[TEMPA2:.*]] = private constant {{.*}} { i32* @[[TEMP2]], i32* @[[TEMP3]] }, align 8 + // CHECK: @_ZN16LiteralReference1bE = global {{.*}} { {{.*}}* @[[TEMPA1]], {{.*}}* @[[TEMPA2]] }, align 8 + + struct Subobj { + int a, b, c; + }; + // CHECK: @[[TEMP:.*]] = private global {{.*}} { i32 1, i32 2, i32 3 }, align 4 + // CHECK: @_ZN16LiteralReference2soE = constant {{.*}} (i8* getelementptr {{.*}} @[[TEMP]]{{.*}}, i64 4) + constexpr int &&so = Subobj{ 1, 2, 3 }.b; + + struct Dummy { int padding; }; + struct Derived : Dummy, Subobj { + constexpr Derived() : Dummy{200}, Subobj{4, 5, 6} {} + }; + using ConstDerived = const Derived; + // CHECK: @[[TEMPCOMMA:.*]] = private constant {{.*}} { i32 200, i32 4, i32 5, i32 6 } + // CHECK: @_ZN16LiteralReference5commaE = constant {{.*}} getelementptr {{.*}} @[[TEMPCOMMA]]{{.*}}, i64 8) + constexpr const int &comma = (1, (2, ConstDerived{}).b); + + // CHECK: @[[TEMPDERIVED:.*]] = private global {{.*}} { i32 200, i32 4, i32 5, i32 6 } + // CHECK: @_ZN16LiteralReference4baseE = constant {{.*}} getelementptr {{.*}} @[[TEMPDERIVED]]{{.*}}, i64 4) + constexpr Subobj &&base = Derived{}; + + // CHECK: @_ZN16LiteralReference7derivedE = constant {{.*}} @[[TEMPDERIVED]] + constexpr Derived &derived = static_cast<Derived&>(base); } namespace NonLiteralConstexpr { @@ -330,6 +368,32 @@ namespace PR13273 { extern const S s {}; } +namespace ArrayTemporary { + struct A { const int (&x)[3]; }; + struct B { const A (&x)[2]; }; + // CHECK: @[[A1:_ZGRN14ArrayTemporary1bE.*]] = private constant [3 x i32] [i32 1, i32 2, i32 3] + // CHECK: @[[A2:_ZGRN14ArrayTemporary1bE.*]] = private constant [3 x i32] [i32 4, i32 5, i32 6] + // CHECK: @[[ARR:_ZGRN14ArrayTemporary1bE.*]] = private constant [2 x {{.*}}] [{{.*}} { [3 x i32]* @[[A1]] }, {{.*}} { [3 x i32]* @[[A2]] }] + // CHECK: @[[B:_ZGRN14ArrayTemporary1bE.*]] = private global {{.*}} { [2 x {{.*}}]* @[[ARR]] } + // CHECK: @_ZN14ArrayTemporary1bE = constant {{.*}}* @[[B]] + B &&b = { { { { 1, 2, 3 } }, { { 4, 5, 6 } } } }; +} + +namespace UnemittedTemporaryDecl { + constexpr int &&ref = 0; + extern constexpr int &ref2 = ref; + // CHECK: @_ZGRN22UnemittedTemporaryDecl3refE = private global i32 0 + + // FIXME: This declaration should not be emitted -- it isn't odr-used. + // CHECK: @_ZN22UnemittedTemporaryDecl3refE + + // CHECK: @_ZN22UnemittedTemporaryDecl4ref2E = constant i32* @_ZGRN22UnemittedTemporaryDecl3refE +} + +// CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101 +// CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102 +// CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr constant {{.*}} i32 103 + // Constant initialization tests go before this point, // dynamic initialization tests go after. @@ -356,6 +420,40 @@ namespace PR13273 { // CHECK-NOT: } // CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr4BothD1Ev +// PR12848: Don't emit dynamic initializers for local constexpr variables. +namespace LocalVarInit { + constexpr int f(int n) { return n; } + struct Agg { int k; }; + struct Ctor { constexpr Ctor(int n) : k(n) {} int k; }; + struct Mutable { constexpr Mutable(int n) : k(n) {} mutable int k; }; + + // CHECK: define {{.*}} @_ZN12LocalVarInit6scalarEv + // CHECK-NOT: call + // CHECK: store i32 100, + // CHECK-NOT: call + // CHECK: ret i32 100 + int scalar() { constexpr int a = { f(100) }; return a; } + + // CHECK: define {{.*}} @_ZN12LocalVarInit3aggEv + // CHECK-NOT: call + // CHECK: ret i32 101 + int agg() { constexpr Agg a = { f(101) }; return a.k; } + + // CHECK: define {{.*}} @_ZN12LocalVarInit4ctorEv + // CHECK-NOT: call + // CHECK: ret i32 102 + int ctor() { constexpr Ctor a = { f(102) }; return a.k; } + + // CHECK: define {{.*}} @_ZN12LocalVarInit8mutable_Ev + // CHECK-NOT: call + // CHECK: call {{.*}}memcpy{{.*}} @_ZZN12LocalVarInit8mutable_EvE1a + // CHECK-NOT: call + // Can't fold return value due to 'mutable'. + // CHECK-NOT: ret i32 103 + // CHECK: } + int mutable_() { constexpr Mutable a = { f(103) }; return a.k; } +} + namespace CrossFuncLabelDiff { // Make sure we refuse to constant-fold the variable b. constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); } diff --git a/test/CodeGenCXX/const-init-cxx1y.cpp b/test/CodeGenCXX/const-init-cxx1y.cpp new file mode 100644 index 0000000..978c428 --- /dev/null +++ b/test/CodeGenCXX/const-init-cxx1y.cpp @@ -0,0 +1,48 @@ +// RUN: not %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++1y | FileCheck %s + +struct A { + constexpr A() : n(1) {} + ~A(); + int n; +}; +struct B : A { + A a[3]; + constexpr B() { + ++a[0].n; + a[1].n += 2; + a[2].n = n + a[1].n; + } +}; +B b; + +// CHECK: @b = global {{.*}} i32 1, {{.*}} { i32 2 }, {{.*}} { i32 3 }, {{.*}} { i32 4 } +// CHECK-NOT: _ZN1BC + +namespace ModifyStaticTemporary { + struct A { int &&temporary; int x; }; + constexpr int f(int &r) { r *= 9; return r - 12; } + A a = { 6, f(a.temporary) }; + // CHECK: @_ZGRN21ModifyStaticTemporary1aE = private global i32 54 + // CHECK: @_ZN21ModifyStaticTemporary1aE = global {{.*}} i32* @_ZGRN21ModifyStaticTemporary1aE, i32 42 + + A b = { 7, ++b.temporary }; + // CHECK: @_ZGRN21ModifyStaticTemporary1bE = private global i32 8 + // CHECK: @_ZN21ModifyStaticTemporary1bE = global {{.*}} i32* @_ZGRN21ModifyStaticTemporary1bE, i32 8 + + // Can't emit all of 'c' as a constant here, so emit the initial value of + // 'c.temporary', not the value as modified by the partial evaluation within + // the initialization of 'c.x'. + A c = { 10, (++c.temporary, b.x) }; + // CHECK: @_ZGRN21ModifyStaticTemporary1cE = private global i32 10 + // CHECK: @_ZN21ModifyStaticTemporary1cE = global {{.*}} zeroinitializer +} + +// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b + +// CHECK: define +// CHECK-NOT: @_ZGRN21ModifyStaticTemporary1cE +// CHECK: store {{.*}} @_ZGRN21ModifyStaticTemporary1cE, {{.*}} @_ZN21ModifyStaticTemporary1cE +// CHECK: add +// CHECK: store +// CHECK: load {{.*}} @_ZN21ModifyStaticTemporary1bE +// CHECK: store {{.*}} @_ZN21ModifyStaticTemporary1cE diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp index 201ce8f..05896ff 100644 --- a/test/CodeGenCXX/const-init.cpp +++ b/test/CodeGenCXX/const-init.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s +// RUN: not %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s // CHECK: @a = global i32 10 int a = 10; diff --git a/test/CodeGenCXX/constructor-attr.cpp b/test/CodeGenCXX/constructor-attr.cpp index 691795f..4f6d635 100644 --- a/test/CodeGenCXX/constructor-attr.cpp +++ b/test/CodeGenCXX/constructor-attr.cpp @@ -5,7 +5,7 @@ // PR6521 void bar(); struct Foo { - // CHECK: define linkonce_odr void @_ZN3Foo3fooEv + // CHECK-LABEL: define linkonce_odr void @_ZN3Foo3fooEv static void foo() __attribute__((constructor)) { bar(); } diff --git a/test/CodeGenCXX/constructor-conversion.cpp b/test/CodeGenCXX/constructor-conversion.cpp index f503463..ebb414d 100644 --- a/test/CodeGenCXX/constructor-conversion.cpp +++ b/test/CodeGenCXX/constructor-conversion.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/constructor-default-arg.cpp b/test/CodeGenCXX/constructor-default-arg.cpp index 32086c1..c2cf44c 100644 --- a/test/CodeGenCXX/constructor-default-arg.cpp +++ b/test/CodeGenCXX/constructor-default-arg.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/constructor-destructor-return-this.cpp b/test/CodeGenCXX/constructor-destructor-return-this.cpp index 1ff922d..ea2ea45 100644 --- a/test/CodeGenCXX/constructor-destructor-return-this.cpp +++ b/test/CodeGenCXX/constructor-destructor-return-this.cpp @@ -1,60 +1,116 @@ -//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s +//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-linux | FileCheck --check-prefix=CHECKGEN %s +//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKARM %s +//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-pc-win32 -cxx-abi microsoft -fno-rtti | FileCheck --check-prefix=CHECKMS %s +// FIXME: these tests crash on the bots when run with -triple=x86_64-pc-win32 -// For constructors/desctructors that return 'this', if there exists a callsite -// that returns 'this' and is immediately before the return instruction, make -// sure we are using the return value from the callsite. -// rdar://12818789 +// Make sure we attach the 'returned' attribute to the 'this' parameter of +// constructors and destructors which return this (and only these cases) -// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr -// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev( -// CHECK-NEXT: ret [[A]] [[THIS1]] +class A { +public: + A(); + ~A(); -// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this -// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E( -// CHECK-NEXT: ret [[A]] [[THIS1]] +private: + int x_; +}; -// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr -// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev( -// CHECK-NEXT: ret [[A]] [[THIS1]] +class B : public A { +public: + B(int *i); + ~B(); + +private: + int *i_; +}; -// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr -// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev( -// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]] -// CHECK-NEXT: ret [[A]] [[THIS2]] +B::B(int *i) : i_(i) { } +B::~B() { } -class TimerBase { +// CHECKGEN-LABEL: define void @_ZN1BC1EPi(%class.B* %this, i32* %i) +// CHECKGEN-LABEL: define void @_ZN1BC2EPi(%class.B* %this, i32* %i) +// CHECKGEN-LABEL: define void @_ZN1BD1Ev(%class.B* %this) +// CHECKGEN-LABEL: define void @_ZN1BD2Ev(%class.B* %this) + +// CHECKARM-LABEL: define %class.B* @_ZN1BC1EPi(%class.B* returned %this, i32* %i) +// CHECKARM-LABEL: define %class.B* @_ZN1BC2EPi(%class.B* returned %this, i32* %i) +// CHECKARM-LABEL: define %class.B* @_ZN1BD1Ev(%class.B* returned %this) +// CHECKARM-LABEL: define %class.B* @_ZN1BD2Ev(%class.B* returned %this) + +// CHECKMS-LABEL: define x86_thiscallcc %class.B* @"\01??0B@@QAE@PAH@Z"(%class.B* returned %this, i32* %i) +// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1B@@QAE@XZ"(%class.B* %this) + +class C : public A, public B { public: - TimerBase(); - virtual ~TimerBase(); + C(int *i, char *c); + virtual ~C(); +private: + char *c_; }; -template <typename TimerFiredClass> class Timer : public TimerBase { -public: - typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*); +C::C(int *i, char *c) : B(i), c_(c) { } +C::~C() { } - Timer(TimerFiredClass* o, TimerFiredFunction f) - : m_object(o), m_function(f) { } +// CHECKGEN-LABEL: define void @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c) +// CHECKGEN-LABEL: define void @_ZN1CC2EPiPc(%class.C* %this, i32* %i, i8* %c) +// CHECKGEN-LABEL: define void @_ZN1CD0Ev(%class.C* %this) +// CHECKGEN-LABEL: define void @_ZN1CD1Ev(%class.C* %this) +// CHECKGEN-LABEL: define void @_ZN1CD2Ev(%class.C* %this) -private: - virtual void fired() { (m_object->*m_function)(this); } +// CHECKARM-LABEL: define %class.C* @_ZN1CC1EPiPc(%class.C* returned %this, i32* %i, i8* %c) +// CHECKARM-LABEL: define %class.C* @_ZN1CC2EPiPc(%class.C* returned %this, i32* %i, i8* %c) +// CHECKARM-LABEL: define void @_ZN1CD0Ev(%class.C* %this) +// CHECKARM-LABEL: define %class.C* @_ZN1CD1Ev(%class.C* returned %this) +// CHECKARM-LABEL: define %class.C* @_ZN1CD2Ev(%class.C* returned %this) - TimerFiredClass* m_object; - TimerFiredFunction m_function; -}; +// CHECKMS-LABEL: define x86_thiscallcc %class.C* @"\01??0C@@QAE@PAHPAD@Z"(%class.C* returned %this, i32* %i, i8* %c) +// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1C@@UAE@XZ"(%class.C* %this) -class ObjectCache { +class D : public virtual A { public: - explicit ObjectCache(); - ~ObjectCache(); + D(); + ~D(); +}; -private: - Timer<ObjectCache> m_notificationPostTimer; +D::D() { } +D::~D() { } + +// CHECKGEN-LABEL: define void @_ZN1DC1Ev(%class.D* %this) +// CHECKGEN-LABEL: define void @_ZN1DC2Ev(%class.D* %this, i8** %vtt) +// CHECKGEN-LABEL: define void @_ZN1DD1Ev(%class.D* %this) +// CHECKGEN-LABEL: define void @_ZN1DD2Ev(%class.D* %this, i8** %vtt) + +// CHECKARM-LABEL: define %class.D* @_ZN1DC1Ev(%class.D* returned %this) +// CHECKARM-LABEL: define %class.D* @_ZN1DC2Ev(%class.D* returned %this, i8** %vtt) +// CHECKARM-LABEL: define %class.D* @_ZN1DD1Ev(%class.D* returned %this) +// CHECKARM-LABEL: define %class.D* @_ZN1DD2Ev(%class.D* returned %this, i8** %vtt) + +// CHECKMS-LABEL: define x86_thiscallcc %class.D* @"\01??0D@@QAE@XZ"(%class.D* returned %this, i32 %is_most_derived) +// CHECKMS-LABEL: define x86_thiscallcc void @"\01??1D@@QAE@XZ"(%class.D* %this) + +class E { +public: + E(); + virtual ~E(); }; -inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { } -inline ObjectCache::~ObjectCache() { } +E* gete(); -ObjectCache *test() { - ObjectCache *dd = new ObjectCache(); - return dd; +void test_destructor() { + const E& e1 = E(); + E* e2 = gete(); + e2->~E(); } + +// CHECKARM-LABEL: define void @_Z15test_destructorv() + +// Verify that virtual calls to destructors are not marked with a 'returned' +// this parameter at the call site... +// CHECKARM: [[VFN:%.*]] = getelementptr inbounds %class.E* (%class.E*)** +// CHECKARM: [[THUNK:%.*]] = load %class.E* (%class.E*)** [[VFN]] +// CHECKARM: call %class.E* [[THUNK]](%class.E* % + +// ...but static calls create declarations with 'returned' this +// CHECKARM: {{%.*}} = call %class.E* @_ZN1ED1Ev(%class.E* % + +// CHECKARM: declare %class.E* @_ZN1ED1Ev(%class.E* returned) diff --git a/test/CodeGenCXX/constructor-for-array-members.cpp b/test/CodeGenCXX/constructor-for-array-members.cpp index 7a365cd..7842d9c 100644 --- a/test/CodeGenCXX/constructor-for-array-members.cpp +++ b/test/CodeGenCXX/constructor-for-array-members.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp index b33184e..477a439 100644 --- a/test/CodeGenCXX/constructor-init.cpp +++ b/test/CodeGenCXX/constructor-init.cpp @@ -70,7 +70,7 @@ template <class T> struct A { operator int() {return 0;} }; -// CHECK: define void @_Z1fv() +// CHECK-LABEL: define void @_Z1fv() void f() { // CHECK: call void @_ZN1AIsEC1Ei A<short> a4 = 97; @@ -93,7 +93,7 @@ namespace InitVTable { B(int); }; - // CHECK: define void @_ZN10InitVTable1BC2Ev(%"struct.InitVTable::B"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZN10InitVTable1BC2Ev(%"struct.InitVTable::B"* %this) unnamed_addr // CHECK: [[T0:%.*]] = bitcast [[B:%.*]]* [[THIS:%.*]] to i8*** // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]] // CHECK: [[VTBL:%.*]] = load i32 ([[B]]*)*** {{%.*}} @@ -106,7 +106,7 @@ namespace InitVTable { // CHECK-NEXT: ret void B::B() : A(foo()) {} - // CHECK: define void @_ZN10InitVTable1BC2Ei(%"struct.InitVTable::B"* %this, i32 %x) unnamed_addr + // CHECK-LABEL: define void @_ZN10InitVTable1BC2Ei(%"struct.InitVTable::B"* %this, i32 %x) unnamed_addr // CHECK: [[ARG:%.*]] = add nsw i32 {{%.*}}, 5 // CHECK-NEXT: call void @_ZN10InitVTable1AC2Ei({{.*}}* {{%.*}}, i32 [[ARG]]) // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* {{%.*}} to i8*** @@ -120,7 +120,7 @@ namespace rdar9694300 { int x; }; - // CHECK: define void @_ZN11rdar96943001fEv + // CHECK-LABEL: define void @_ZN11rdar96943001fEv void f() { // CHECK: alloca X x; @@ -163,7 +163,7 @@ template<typename T> struct X; // Make sure that the instantiated constructor initializes start and // end properly. -// CHECK: define linkonce_odr void @_ZN1XIiEC2ERKS0_(%struct.X* %this, %struct.X* %other) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN1XIiEC2ERKS0_(%struct.X* %this, %struct.X* %other) unnamed_addr // CHECK: {{store.*null}} // CHECK: {{store.*null}} // CHECK: ret @@ -200,7 +200,7 @@ namespace PR10720 { // CHECK-PR10720: ret pair2 &operator=(pair2&&) = default; - // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2EOS0_ + // CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107205pair2C2EOS0_ // CHECK-PR10720-NOT: ret // CHECK-PR10720: load // CHECK-PR10720: icmp ult @@ -210,7 +210,7 @@ namespace PR10720 { // CHECK-PR10720: ret void pair2(pair2&&) = default; - // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2ERKS0_ + // CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107205pair2C2ERKS0_ // CHECK-PR10720-NOT: ret // CHECK-PR10720: load // CHECK-PR10720: icmp ult @@ -223,7 +223,7 @@ namespace PR10720 { struct pair : X { // Make the copy constructor non-trivial, so we actually generate it. int second[4]; - // CHECK-PR10720: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_ + // CHECK-PR10720-LABEL: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_ // CHECK-PR10720-NOT: ret // CHECK-PR10720: call void @llvm.memcpy // CHECK-PR10720-NEXT: ret void diff --git a/test/CodeGenCXX/constructor-template.cpp b/test/CodeGenCXX/constructor-template.cpp index fe4687c..0d38d10 100644 --- a/test/CodeGenCXX/constructor-template.cpp +++ b/test/CodeGenCXX/constructor-template.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s // PR4826 struct A { diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp index 9e2da31..f730b9e 100644 --- a/test/CodeGenCXX/constructors.cpp +++ b/test/CodeGenCXX/constructors.cpp @@ -21,18 +21,18 @@ struct A { A::A(struct Undeclared &ref) : mem(0) {} // Check that delegation works. -// CHECK: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK-LABEL: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN1AC2ER10Undeclared( -// CHECK: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK-LABEL: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN6MemberC1Ei( A::A(ValueClass v) : mem(v.y - v.x) {} -// CHECK: define void @_ZN1AC1E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr +// CHECK-LABEL: define void @_ZN1AC1E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr // CHECK: call void @_ZN1AC2E10ValueClass( -// CHECK: define void @_ZN1AC2E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr +// CHECK-LABEL: define void @_ZN1AC2E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr // CHECK: call void @_ZN6MemberC1Ei( @@ -44,10 +44,10 @@ struct B : A { B::B(struct Undeclared &ref) : A(ref), mem(1) {} -// CHECK: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK-LABEL: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN1BC2ER10Undeclared( -// CHECK: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK-LABEL: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr // CHECK: call void @_ZN1AC2ER10Undeclared( // CHECK: call void @_ZN6MemberC1Ei( @@ -64,12 +64,12 @@ struct C : virtual A { }; C::C(int x) : A(ValueClass(x, x+1)), mem(x * x) {} -// CHECK: define void @_ZN1CC1Ei(%struct.C* %this, i32 %x) unnamed_addr +// CHECK-LABEL: define void @_ZN1CC1Ei(%struct.C* %this, i32 %x) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( -// CHECK: define void @_ZN1CC2Ei(%struct.C* %this, i8** %vtt, i32 %x) unnamed_addr +// CHECK-LABEL: define void @_ZN1CC2Ei(%struct.C* %this, i8** %vtt, i32 %x) unnamed_addr // CHECK: call void @_ZN6MemberC1Ei( @@ -83,12 +83,12 @@ struct D : A { D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {} -// CHECK: define void @_ZN1DC1Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr +// CHECK-LABEL: define void @_ZN1DC1Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( -// CHECK: define void @_ZN1DC2Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr +// CHECK-LABEL: define void @_ZN1DC2Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( @@ -109,7 +109,7 @@ namespace test1 { struct A { A(); void *ptr; }; struct B { B(); int x; A a[0]; }; B::B() {} - // CHECK: define void @_ZN5test11BC2Ev( + // CHECK-LABEL: define void @_ZN5test11BC2Ev( // CHECK: [[THIS:%.*]] = load [[B:%.*]]** // CHECK-NEXT: ret void } diff --git a/test/CodeGenCXX/conversion-function.cpp b/test/CodeGenCXX/conversion-function.cpp index 76d9e02..ec098d0 100644 --- a/test/CodeGenCXX/conversion-function.cpp +++ b/test/CodeGenCXX/conversion-function.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s // XFAIL: * extern "C" int printf(...); struct S { diff --git a/test/CodeGenCXX/convert-to-fptr.cpp b/test/CodeGenCXX/convert-to-fptr.cpp index 425f79d..e497acf 100644 --- a/test/CodeGenCXX/convert-to-fptr.cpp +++ b/test/CodeGenCXX/convert-to-fptr.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/copy-assign-synthesis-1.cpp b/test/CodeGenCXX/copy-assign-synthesis-1.cpp index 5d09b54..2ffc7bc 100644 --- a/test/CodeGenCXX/copy-assign-synthesis-1.cpp +++ b/test/CodeGenCXX/copy-assign-synthesis-1.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target -// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s -// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o - | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -emit-llvm %s -o - | \ +// RUN: FileCheck %s extern "C" int printf(...); @@ -93,11 +93,5 @@ int main() { dstY.pr(); } -// CHECK-LP64: .globl __ZN1XaSERKS_ -// CHECK-LP64: .weak_definition __ZN1XaSERKS_ -// CHECK-LP64: __ZN1XaSERKS_: - -// CHECK-LP32: .globl __ZN1XaSERKS_ -// CHECK-LP32: .weak_definition __ZN1XaSERKS_ -// CHECK-LP32: __ZN1XaSERKS_: +// CHECK: define linkonce_odr %struct.X* @_ZN1XaSERKS_ diff --git a/test/CodeGenCXX/copy-assign-synthesis-2.cpp b/test/CodeGenCXX/copy-assign-synthesis-2.cpp index c25e046..18e92f9 100644 --- a/test/CodeGenCXX/copy-assign-synthesis-2.cpp +++ b/test/CodeGenCXX/copy-assign-synthesis-2.cpp @@ -1,4 +1,4 @@ // RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s struct A {}; A& (A::*x)(const A&) = &A::operator=; -// CHECK: define linkonce_odr %struct.A* @_ZN1AaSERKS_ +// CHECK-LABEL: define linkonce_odr %struct.A* @_ZN1AaSERKS_ diff --git a/test/CodeGenCXX/copy-assign-synthesis.cpp b/test/CodeGenCXX/copy-assign-synthesis.cpp index e9fc0c3..9c8ae88 100644 --- a/test/CodeGenCXX/copy-assign-synthesis.cpp +++ b/test/CodeGenCXX/copy-assign-synthesis.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -emit-llvm -o %t %s -// RUN: grep "_ZN1XaSERK1X" %t | count 0 +// RUN: not grep "_ZN1XaSERK1X" %t extern "C" int printf(...); diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp index 4ff8775..727af1b 100644 --- a/test/CodeGenCXX/copy-constructor-elim-2.cpp +++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp @@ -2,7 +2,7 @@ struct A { int x; A(int); ~A(); }; A f() { return A(0); } -// CHECK: define void @_Z1fv +// CHECK-LABEL: define void @_Z1fv // CHECK: call {{.*}} @_ZN1AC1Ei // CHECK-NEXT: ret void @@ -21,7 +21,7 @@ namespace no_elide_base { Derived(const Other &O); }; - // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr + // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* returned %this, %"struct.no_elide_base::Other"* %O) unnamed_addr Derived::Derived(const Other &O) // CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv // CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_ @@ -63,7 +63,7 @@ namespace PR12139 { static A makeA() { A a; a.value = 2; return a; } }; - // CHECK: define i32 @_ZN7PR121394testEv + // CHECK-LABEL: define i32 @_ZN7PR121394testEv int test() { // CHECK: call void @_ZN7PR121391A5makeAEv // CHECK-NEXT: call %"struct.PR12139::A"* @_ZN7PR121391AC1ERKS0_i diff --git a/test/CodeGenCXX/copy-constructor-elim.cpp b/test/CodeGenCXX/copy-constructor-elim.cpp index c883584..ad3a87b 100644 --- a/test/CodeGenCXX/copy-constructor-elim.cpp +++ b/test/CodeGenCXX/copy-constructor-elim.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -emit-llvm -o %t %s -// RUN: grep "_ZN1CC1ERK1C" %t | count 0 -// RUN: grep "_ZN1SC1ERK1S" %t | count 0 +// RUN: not grep "_ZN1CC1ERK1C" %t +// RUN: not grep "_ZN1SC1ERK1S" %t extern "C" int printf(...); diff --git a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp index d028a28..03c6633 100644 --- a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp +++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp @@ -3,5 +3,5 @@ struct A { virtual void a(); }; A x(A& y) { return y; } -// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* {{.*}}%this, %struct.A*) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp index 68f6805..c8b265c 100644 --- a/test/CodeGenCXX/copy-constructor-synthesis.cpp +++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp @@ -21,7 +21,7 @@ struct P { }; -// CHECK: define linkonce_odr void @_ZN1XC1ERKS_(%struct.X* %this, %struct.X*) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN1XC1ERKS_(%struct.X* %this, %struct.X*) unnamed_addr struct X : M, N, P { // ... X() : f1(1.0), d1(2.0), i1(3), name("HELLO"), bf1(0xff), bf2(0xabcd), au_i1(1234), au1_4("MASKED") {} @@ -136,7 +136,33 @@ void f(B b1) { B b2 = b1; } -// CHECK: define linkonce_odr void @_ZN6PR66281BC2ERKS0_(%"struct.PR6628::B"* %this, %"struct.PR6628::B"*) unnamed_addr +// CHECK: define linkonce_odr [[A:%.*]]* @_ZN12rdar138169401AaSERKS0_( +// CHECK: [[THIS:%.*]] = load [[A]]** +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1 +// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16* +// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]** +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1 +// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16* +// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8* +// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false) +// CHECK-NEXT: ret [[A]]* [[THIS]] + +// CHECK-LABEL: define linkonce_odr void @_ZN12rdar138169401AC2ERKS0_( +// CHECK: [[THIS:%.*]] = load [[A]]** +// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[THIS]] to i8*** +// CHECK-NEXT: store i8** getelementptr inbounds ([4 x i8*]* @_ZTVN12rdar138169401AE, i64 0, i64 2), i8*** [[T0]] +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1 +// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16* +// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]** +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1 +// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16* +// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8* +// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false) +// CHECK-NEXT: ret void + +// CHECK-LABEL: define linkonce_odr void @_ZN6PR66281BC2ERKS0_(%"struct.PR6628::B"* %this, %"struct.PR6628::B"*) unnamed_addr // CHECK: call void @_ZN6PR66281TC1Ev // CHECK: call void @_ZN6PR66281TC1Ev // CHECK: call void @_ZN6PR66281AC2ERKS0_RKNS_1TES5_ @@ -154,3 +180,18 @@ void f(B b1) { // CHECK: call void @_ZN6PR66281TD1Ev } +// rdar://13816940 +// Test above because things get weirdly re-ordered. +namespace rdar13816940 { + struct A { + virtual ~A(); + unsigned short a : 1; + unsigned short : 15; + unsigned other; + }; + + void test(A &a) { + A x = a; // force copy constructor into existence + x = a; // also force the copy assignment operator + } +} diff --git a/test/CodeGenCXX/copy-initialization.cpp b/test/CodeGenCXX/copy-initialization.cpp index aecd64e..1a16013 100644 --- a/test/CodeGenCXX/copy-initialization.cpp +++ b/test/CodeGenCXX/copy-initialization.cpp @@ -12,7 +12,7 @@ struct Bar { void f(Foo); -// CHECK: define void @_Z1g3Foo(%struct.Foo* %foo) +// CHECK-LABEL: define void @_Z1g3Foo(%struct.Foo* %foo) void g(Foo foo) { // CHECK: call void @_ZN3BarC1Ev // CHECK: @_ZNK3BarcvRK3FooEv diff --git a/test/CodeGenCXX/crash.cpp b/test/CodeGenCXX/crash.cpp new file mode 100644 index 0000000..073542d --- /dev/null +++ b/test/CodeGenCXX/crash.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only +// CHECK that we don't crash. + +// PR11676's example is ill-formed: +/* +union _XEvent { +}; +void ProcessEvent() { + _XEvent pluginEvent = _XEvent(); +} +*/ + +// Example from PR11665: +void f() { + union U { int field; } u = U(); + (void)U().field; +} + +namespace PR17476 { +struct string { + string(const char *__s); + string &operator+=(const string &__str); +}; + +template <class ELFT> void finalizeDefaultAtomValues() { + auto startEnd = [&](const char * sym)->void { + string start("__"); + start += sym; + } + ; + startEnd("preinit_array"); +} + +void f() { finalizeDefaultAtomValues<int>(); } +} diff --git a/test/CodeGenCXX/ctor-dtor-alias.cpp b/test/CodeGenCXX/ctor-dtor-alias.cpp new file mode 100644 index 0000000..235d165 --- /dev/null +++ b/test/CodeGenCXX/ctor-dtor-alias.cpp @@ -0,0 +1,163 @@ +// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s + +// RUN: %clang_cc1 -cc1 -triple x86_64--netbsd -emit-llvm \ +// RUN: -mconstructor-aliases -O2 %s -o - | FileCheck --check-prefix=CHECK-RAUW %s + +namespace test1 { +// test that we don't produce an alias when the destructor is weak_odr. The +// reason to avoid it that another TU might have no explicit template +// instantiation definition or declaration, causing it to to output only +// one of the destructors as linkonce_odr, producing a different comdat. + +// CHECK-DAG: define weak_odr void @_ZN5test16foobarIvEC2Ev +// CHECK-DAG: define weak_odr void @_ZN5test16foobarIvEC1Ev + +template <typename T> struct foobar { + foobar() {} +}; + +template struct foobar<void>; +} + +namespace test2 { +// test that when the destrucor is linkonce_odr we just replace every use of +// C1 with C2. + +// CHECK-DAG: define linkonce_odr void @_ZN5test26foobarIvEC2Ev( +// CHECK-DAG: call void @_ZN5test26foobarIvEC2Ev +void g(); +template <typename T> struct foobar { + foobar() { g(); } +}; +foobar<void> x; +} + +namespace test3 { +// test that instead of an internal alias we just use the other destructor +// directly. + +// CHECK-DAG: define internal void @_ZN5test312_GLOBAL__N_11AD2Ev( +// CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test312_GLOBAL__N_11AD2Ev +namespace { +struct A { + ~A() {} +}; + +struct B : public A {}; +} + +B x; +} + +namespace test4 { + // Test that we don't produce aliases from B to A. We cannot because we cannot + // guarantee that they will be present in every TU. Instead, we just call + // A's destructor directly. + + // CHECK-DAG: define linkonce_odr void @_ZN5test41AD2Ev( + // CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev + + // test that we don't do this optimization at -O0 so that the debugger can + // see both destructors. + // NOOPT-DAG: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev + // NOOOPT-DAG: define linkonce_odr void @_ZN5test41BD2Ev + struct A { + virtual ~A() {} + }; + struct B : public A{ + ~B() {} + }; + B X; +} + +namespace test5 { + // similar to test4, but with an internal B. + + // CHECK-DAG: define linkonce_odr void @_ZN5test51AD2Ev( + // CHECK-DAG: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev + struct A { + virtual ~A() {} + }; + namespace { + struct B : public A{ + ~B() {} + }; + } + B X; +} + +namespace test6 { + // Test that we use ~A directly, even when ~A is not defined. The symbol for + // ~B would have been internal and still contain a reference to ~A. + struct A { + virtual ~A(); + }; + namespace { + struct B : public A { + ~B() {} + }; + } + B X; + // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test61AD2Ev +} + +namespace test7 { + // Test that we don't produce an alias from ~B to ~A<int> (or crash figuring + // out if we should). + // pr17875. + // CHECK-DAG: define void @_ZN5test71BD2Ev + template <typename> struct A { + ~A() {} + }; + class B : A<int> { + ~B(); + }; + template class A<int>; + B::~B() {} +} + +namespace test8 { + // Test that we replace ~zed with ~bar which is an alias to ~foo. + // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test83barD2Ev + // CHECK-DAG: @_ZN5test83barD2Ev = alias {{.*}} @_ZN5test83fooD2Ev + struct foo { + ~foo(); + }; + foo::~foo() {} + struct bar : public foo { + ~bar(); + }; + bar::~bar() {} + struct zed : public bar {}; + zed foo; +} + +// CHECK-RAUW: @_ZTV1C = linkonce_odr unnamed_addr constant [4 x i8*] [{{[^@]*}}@_ZTI1C {{[^@]*}}@_ZN1CD2Ev {{[^@]*}}@_ZN1CD0Ev {{[^@]*}}] +// r194296 replaced C::~C with B::~B without emitting the later. + +class A { +public: + A(int); + virtual ~A(); +}; + +template <class> +class B : A { +public: + B() + : A(0) { + } + __attribute__((always_inline)) ~B() { + } +}; + +extern template class B<char>; + +class C : B<char> { +}; + +void +fn1() { + new C; +} diff --git a/test/CodeGenCXX/cxx-block-objects.cpp b/test/CodeGenCXX/cxx-block-objects.cpp index b989065..ff868fc 100644 --- a/test/CodeGenCXX/cxx-block-objects.cpp +++ b/test/CodeGenCXX/cxx-block-objects.cpp @@ -25,9 +25,9 @@ main() return 0; } -// CHECK: define internal void @__copy_helper_block_ +// CHECK-LABEL: define internal void @__copy_helper_block_ // CHECK: call void @_ZN1AC1ERKS_ -// CHECK:define internal void @__destroy_helper_block_ +// CHECK-LABEL:define internal void @__destroy_helper_block_ // CHECK: call void @_ZN1AD1Ev diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp index e909f03..c48e61f 100644 --- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp +++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp @@ -87,7 +87,7 @@ namespace PR14588 { virtual void squawk() { other(); } }; - // CHECK: define void @_ZN7PR145883FooC1Ev(%"class.PR14588::Foo"* + // CHECK-LABEL: define void @_ZN7PR145883FooC1Ev(%"class.PR14588::Foo"* // CHECK: call void @_ZN7PR145883FooC1EPKv( // CHECK: invoke void @_ZN7PR145885otherEv() // CHECK: call void @_ZN7PR145883FooD1Ev diff --git a/test/CodeGenCXX/cxx0x-initializer-array.cpp b/test/CodeGenCXX/cxx0x-initializer-array.cpp index 3144e94..49bc86f 100644 --- a/test/CodeGenCXX/cxx0x-initializer-array.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-array.cpp @@ -6,7 +6,7 @@ struct A { int a[1]; }; typedef A x[]; int f() { x{{{1}}}; - // CHECK: define i32 @_Z1fv + // CHECK-LABEL: define i32 @_Z1fv // CHECK: store i32 1 // (It's okay if the output changes here, as long as we don't crash.) return 0; @@ -33,7 +33,7 @@ namespace ValueInitArrayOfMemPtr { S1(); }; - // CHECK: define void @_ZN22ValueInitArrayOfMemPtr1fEi + // CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1fEi void f(int n) { Agg1 a = { n }; // CHECK: store i32 -1, @@ -42,7 +42,7 @@ namespace ValueInitArrayOfMemPtr { // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* bitcast ([3 x i32]* @[[THREE_NULL_MEMPTRS]] to i8*), i32 12, i32 4, i1 false) } - // CHECK: define void @_ZN22ValueInitArrayOfMemPtr1gEv + // CHECK-LABEL: define void @_ZN22ValueInitArrayOfMemPtr1gEv void g() { // CHECK: store i32 -1, f(a{}); @@ -54,7 +54,7 @@ namespace array_dtor { using T = S[3]; void f(const T &); void f(T *); - // CHECK: define void @_ZN10array_dtor1gEv( + // CHECK-LABEL: define void @_ZN10array_dtor1gEv( void g() { // CHECK: %[[ARRAY:.*]] = alloca [3 x // CHECK: br @@ -73,7 +73,7 @@ namespace array_dtor { // CHECK: ret void } - // CHECK: define void @_ZN10array_dtor1hEv( + // CHECK-LABEL: define void @_ZN10array_dtor1hEv( void h() { // CHECK: %[[ARRAY:.*]] = alloca [3 x // CHECK: br @@ -91,7 +91,7 @@ namespace array_dtor { // CHECK: ret void } - // CHECK: define void @_ZN10array_dtor1iEv( + // CHECK-LABEL: define void @_ZN10array_dtor1iEv( void i() { // CHECK: %[[ARRAY:.*]] = alloca [3 x // CHECK: br diff --git a/test/CodeGenCXX/cxx0x-initializer-constructors.cpp b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp index be5b44d..f60536e 100644 --- a/test/CodeGenCXX/cxx0x-initializer-constructors.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp @@ -6,21 +6,21 @@ struct S { }; void fn1() { - // CHECK: define void @_Z3fn1v + // CHECK-LABEL: define void @_Z3fn1v S s { 1 }; // CHECK: alloca %struct.S, align 1 // CHECK: call void @_ZN1SC1Ei(%struct.S* %s, i32 1) } void fn2() { - // CHECK: define void @_Z3fn2v + // CHECK-LABEL: define void @_Z3fn2v S s { 1, 2.0, 3.0 }; // CHECK: alloca %struct.S, align 1 // CHECK: call void @_ZN1SC1Eidd(%struct.S* %s, i32 1, double 2.000000e+00, double 3.000000e+00) } void fn3() { - // CHECK: define void @_Z3fn3v + // CHECK-LABEL: define void @_Z3fn3v S sa[] { { 1 }, { 2 }, { 3 } }; // CHECK: alloca [3 x %struct.S], align 1 // CHECK: call void @_ZN1SC1Ei(%struct.S* %{{.+}}, i32 1) @@ -29,9 +29,25 @@ void fn3() { } void fn4() { - // CHECK: define void @_Z3fn4v + // CHECK-LABEL: define void @_Z3fn4v S sa[] { { 1, 2.0, 3.0 }, { 4, 5.0, 6.0 } }; // CHECK: alloca [2 x %struct.S], align 1 // CHECK: call void @_ZN1SC1Eidd(%struct.S* %{{.+}}, i32 1, double 2.000000e+00, double 3.000000e+00) // CHECK: call void @_ZN1SC1Eidd(%struct.S* %{{.+}}, i32 4, double 5.000000e+00, double 6.000000e+00) } + +namespace TreeTransformBracedInit { + struct S {}; + struct T { T(const S &); T(const T&); ~T(); }; + void x(const T &); + template<typename> void foo(const S &s) { + // Instantiation of this expression used to lose the CXXBindTemporaryExpr + // node and thus not destroy the temporary. + x({s}); + } + template void foo<void>(const S&); + // CHECK: define {{.*}} void @_ZN23TreeTransformBracedInit3fooIvEEvRKNS_1SE( + // CHECK: call void @_ZN23TreeTransformBracedInit1TC1ERKNS_1SE( + // CHECK-NEXT: call void @_ZN23TreeTransformBracedInit1xERKNS_1TE( + // CHECK-NEXT: call void @_ZN23TreeTransformBracedInit1TD1Ev( +} diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp index 14d2f77..091d7b7 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp @@ -1,18 +1,28 @@ -// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - -verify %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-STATIC-BL +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -Dconstexpr= | FileCheck %s --check-prefix=CHECK-DYNAMIC-BL +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -DUSE_END | FileCheck %s --check-prefix=CHECK-STATIC-BE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -DUSE_END -Dconstexpr= | FileCheck %s --check-prefix=CHECK-DYNAMIC-BE namespace std { typedef decltype(sizeof(int)) size_t; - // libc++'s implementation template <class _E> class initializer_list { const _E* __begin_; +#ifdef USE_END + const _E* __end_; +#else size_t __size_; +#endif - initializer_list(const _E* __b, size_t __s) + constexpr initializer_list(const _E* __b, size_t __s) : __begin_(__b), +#ifdef USE_END + __end_(__b + __s) +#else __size_(__s) +#endif {} public: @@ -24,14 +34,99 @@ namespace std { typedef const _E* iterator; typedef const _E* const_iterator; - initializer_list() : __begin_(nullptr), __size_(0) {} +#ifdef USE_END + constexpr initializer_list() : __begin_(nullptr), __end_(nullptr) {} + + size_t size() const {return __end_ - __begin_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __end_;} +#else + constexpr initializer_list() : __begin_(nullptr), __size_(0) {} size_t size() const {return __size_;} const _E* begin() const {return __begin_;} const _E* end() const {return __begin_ + __size_;} +#endif }; } -std::initializer_list<std::initializer_list<int>> pleasefail = { - {1, 2}, {3, 4}, {5, 6} // expected-error {{cannot compile}} +constexpr int a = 2, b = 4, c = 6; +std::initializer_list<std::initializer_list<int>> nested = { + {1, a}, {3, b}, {5, c} }; + +// CHECK-STATIC-BL: @_ZGR6nested = private constant [2 x i32] [i32 1, i32 2], align 4 +// CHECK-STATIC-BL: @_ZGR6nested1 = private constant [2 x i32] [i32 3, i32 4], align 4 +// CHECK-STATIC-BL: @_ZGR6nested2 = private constant [2 x i32] [i32 5, i32 6], align 4 +// CHECK-STATIC-BL: @_ZGR6nested3 = private constant [3 x {{.*}}] [ +// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested, i32 0, i32 0), i64 2 }, +// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i32 0, i32 0), i64 2 }, +// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i32 0, i32 0), i64 2 } +// CHECK-STATIC-BL: ], align 8 +// CHECK-STATIC-BL: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested3, i32 0, i32 0), i64 3 }, align 8 + +// CHECK-DYNAMIC-BL: @nested = global +// CHECK-DYNAMIC-BL: @_ZGR6nested = private global [3 x +// CHECK-DYNAMIC-BL: @_ZGR6nested1 = private global [2 x i32] zeroinitializer +// CHECK-DYNAMIC-BL: @_ZGR6nested2 = private global [2 x i32] zeroinitializer +// CHECK-DYNAMIC-BL: @_ZGR6nested3 = private global [2 x i32] zeroinitializer +// CHECK-DYNAMIC-BL: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0) +// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1) +// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0), +// CHECK-DYMAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8 +// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8 +// CHECK-DYNAMIC-BL: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0) +// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1) +// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0), +// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8 +// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8 +// CHECK-DYNAMIC-BL: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0) +// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1) +// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0), +// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8 +// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 1), align 8 +// CHECK-DYNAMIC-BL: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0), +// CHECK-DYNAMIC-BL: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 0), align 8 +// CHECK-DYNAMIC-BL: store i64 3, i64* getelementptr inbounds ({{.*}}* @nested, i32 0, i32 1), align 8 + +// CHECK-STATIC-BE: @_ZGR6nested = private constant [2 x i32] [i32 1, i32 2], align 4 +// CHECK-STATIC-BE: @_ZGR6nested1 = private constant [2 x i32] [i32 3, i32 4], align 4 +// CHECK-STATIC-BE: @_ZGR6nested2 = private constant [2 x i32] [i32 5, i32 6], align 4 +// CHECK-STATIC-BE: @_ZGR6nested3 = private constant [3 x {{.*}}] [ +// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested, i32 0, i32 0), +// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested to i8*), i64 8) to i32*) } +// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i32 0, i32 0), +// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested1 to i8*), i64 8) to i32*) } +// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i32 0, i32 0), +// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested2 to i8*), i64 8) to i32*) } +// CHECK-STATIC-BE: ], align 8 +// CHECK-STATIC-BE: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested3, i32 0, i32 0), +// CHECK-STATIC-BE: {{.*}} bitcast ({{.*}}* getelementptr (i8* bitcast ([3 x {{.*}}]* @_ZGR6nested3 to i8*), i64 48) to {{.*}}*) } + +// CHECK-DYNAMIC-BE: @nested = global +// CHECK-DYNAMIC-BE: @_ZGR6nested = private global [3 x +// CHECK-DYNAMIC-BE: @_ZGR6nested1 = private global [2 x i32] zeroinitializer +// CHECK-DYNAMIC-BE: @_ZGR6nested2 = private global [2 x i32] zeroinitializer +// CHECK-DYNAMIC-BE: @_ZGR6nested3 = private global [2 x i32] zeroinitializer +// CHECK-DYNAMIC-BE: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0) +// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1) +// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0), +// CHECK-DYMAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8 +// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 1, i64 0), +// CHECK-DYMAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8 +// CHECK-DYNAMIC-BE: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0) +// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1) +// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0), +// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8 +// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 1, i64 0), +// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8 +// CHECK-DYNAMIC-BE: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0) +// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1) +// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0), +// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8 +// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 1, i64 0), +// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 1), align 8 +// CHECK-DYNAMIC-BE: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0), +// CHECK-DYNAMIC-BE: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 0), align 8 +// CHECK-DYNAMIC-BE: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 1, i64 0), +// CHECK-DYNAMIC-BE: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 1), align 8 diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp index 209ee65..8e0d161 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp @@ -32,12 +32,12 @@ namespace std { }; } -// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3] -// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, {{[^)]*}}), i32* +// CHECK: @_ZGR15globalInitList1 = private constant [3 x i32] [i32 1, i32 2, i32 3] +// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZGR15globalInitList1, {{[^)]*}}), i32* std::initializer_list<int> globalInitList1 = {1, 2, 3}; void fn1(int i) { - // CHECK: define void @_Z3fn1i + // CHECK-LABEL: define void @_Z3fn1i // temporary array // CHECK: [[array:%[^ ]+]] = alloca [3 x i32] // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0 @@ -66,7 +66,7 @@ struct destroyme2 { void fn2() { - // CHECK: define void @_Z3fn2v + // CHECK-LABEL: define void @_Z3fn2v void target(std::initializer_list<destroyme1>); // objects should be destroyed before dm2, after call returns target({ destroyme1(), destroyme1() }); @@ -76,7 +76,7 @@ void fn2() { } void fn3() { - // CHECK: define void @_Z3fn3v + // CHECK-LABEL: define void @_Z3fn3v // objects should be destroyed after dm2 auto list = { destroyme1(), destroyme1() }; destroyme2 dm2; diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp index d683493..164cbce 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -47,23 +47,48 @@ struct wantslist1 { ~wantslist1(); }; -// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3] -// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, i32 0, i32 0), i{{32|64}} 3 } +// CHECK: @_ZGR15globalInitList1 = private constant [3 x i32] [i32 1, i32 2, i32 3] +// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZGR15globalInitList1, i32 0, i32 0), i{{32|64}} 3 } std::initializer_list<int> globalInitList1 = {1, 2, 3}; namespace thread_local_global_array { - // CHECK: @_ZN25thread_local_global_arrayL11x__initlistE = internal thread_local global [4 x i32] [i32 1, i32 2, i32 3, i32 4] - // CHECK: @_ZN25thread_local_global_array1xE = thread_local global {{.*}} @_ZN25thread_local_global_arrayL11x__initlistE, {{.*}} i64 4 + // FIXME: We should be able to constant-evaluate this even though the + // initializer is not a constant expression (pointers to thread_local + // objects aren't really a problem). + // + // CHECK: @_ZN25thread_local_global_array1xE = thread_local global + // CHECK: @_ZGRN25thread_local_global_array1xE = private thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4] std::initializer_list<int> thread_local x = { 1, 2, 3, 4 }; } -// CHECK: @_ZL25globalInitList2__initlist = internal global [2 x %{{[^ ]*}}] zeroinitializer -// CHECK: @globalInitList2 = global %{{[^ ]+}} { %[[WITHARG:[^ *]+]]* getelementptr inbounds ([2 x +// CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer +// CHECK: @_ZGR15globalInitList2 = private global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer + +// CHECK: @_ZN15partly_constant1kE = global i32 0, align 4 +// CHECK: @_ZN15partly_constant2ilE = global {{.*}} null, align 8 +// CHECK: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = private global {{.*}} zeroinitializer, align 8 +// CHECK: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = private global [3 x {{.*}}] zeroinitializer, align 8 +// CHECK: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4 +// CHECK: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = private global [2 x i32] zeroinitializer, align 4 +// CHECK: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = private constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4 + // CHECK: appending global -// CHECK: define internal void -// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 0 -// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 1 + + +// thread_local initializer: +// CHECK-LABEL: define internal void +// CHECK: store i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 0), +// CHECK: i32** getelementptr inbounds ({{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8 +// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8 + + +// CHECK-LABEL: define internal void +// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZGR15globalInitList2, i{{32|64}} 0, i{{32|64}} 0 +// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZGR15globalInitList2, i{{32|64}} 0, i{{32|64}} 1 // CHECK: __cxa_atexit +// CHECK: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZGR15globalInitList2, i64 0, i64 0), +// CHECK: %[[WITHARG]]** getelementptr inbounds (%{{.*}}* @globalInitList2, i32 0, i32 0), align 8 +// CHECK: store i64 2, i64* getelementptr inbounds (%{{.*}}* @globalInitList2, i32 0, i32 1), align 8 // CHECK: call void @_ZN10destroyme1D1Ev // CHECK: call void @_ZN10destroyme1D1Ev std::initializer_list<witharg1> globalInitList2 = { @@ -71,7 +96,7 @@ std::initializer_list<witharg1> globalInitList2 = { }; void fn1(int i) { - // CHECK: define void @_Z3fn1i + // CHECK-LABEL: define void @_Z3fn1i // temporary array // CHECK: [[array:%[^ ]+]] = alloca [3 x i32] // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0 @@ -91,7 +116,7 @@ void fn1(int i) { } void fn2() { - // CHECK: define void @_Z3fn2v + // CHECK-LABEL: define void @_Z3fn2v void target(std::initializer_list<destroyme1>); // objects should be destroyed before dm2, after call returns // CHECK: call void @_Z6targetSt16initializer_listI10destroyme1E @@ -102,7 +127,7 @@ void fn2() { } void fn3() { - // CHECK: define void @_Z3fn3v + // CHECK-LABEL: define void @_Z3fn3v // objects should be destroyed after dm2 auto list = { destroyme1(), destroyme1() }; destroyme2 dm2; @@ -111,7 +136,7 @@ void fn3() { } void fn4() { - // CHECK: define void @_Z3fn4v + // CHECK-LABEL: define void @_Z3fn4v void target(std::initializer_list<witharg1>); // objects should be destroyed before dm2, after call returns // CHECK: call void @_ZN8witharg1C1ERK10destroyme1 @@ -124,7 +149,7 @@ void fn4() { } void fn5() { - // CHECK: define void @_Z3fn5v + // CHECK-LABEL: define void @_Z3fn5v // temps should be destroyed before dm2 // objects should be destroyed after dm2 // CHECK: call void @_ZN8witharg1C1ERK10destroyme1 @@ -136,7 +161,7 @@ void fn5() { } void fn6() { - // CHECK: define void @_Z3fn6v + // CHECK-LABEL: define void @_Z3fn6v void target(const wantslist1&); // objects should be destroyed before dm2, after call returns // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E @@ -149,7 +174,7 @@ void fn6() { } void fn7() { - // CHECK: define void @_Z3fn7v + // CHECK-LABEL: define void @_Z3fn7v // temps should be destroyed before dm2 // object should be destroyed after dm2 // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E @@ -161,7 +186,7 @@ void fn7() { } void fn8() { - // CHECK: define void @_Z3fn8v + // CHECK-LABEL: define void @_Z3fn8v void target(std::initializer_list<std::initializer_list<destroyme1>>); // objects should be destroyed before dm2, after call returns // CHECK: call void @_Z6targetSt16initializer_listIS_I10destroyme1EE @@ -175,7 +200,7 @@ void fn8() { } void fn9() { - // CHECK: define void @_Z3fn9v + // CHECK-LABEL: define void @_Z3fn9v // objects should be destroyed after dm2 std::initializer_list<destroyme1> inner; std::initializer_list<std::initializer_list<destroyme1>> list = @@ -193,7 +218,7 @@ struct haslist1 { haslist1(); }; -// CHECK: define void @_ZN8haslist1C2Ev +// CHECK-LABEL: define void @_ZN8haslist1C2Ev haslist1::haslist1() // CHECK: alloca [3 x i32] // CHECK: store i32 1 @@ -210,7 +235,7 @@ struct haslist2 { haslist2(); }; -// CHECK: define void @_ZN8haslist2C2Ev +// CHECK-LABEL: define void @_ZN8haslist2C2Ev haslist2::haslist2() : il{destroyme1(), destroyme1()} { @@ -220,7 +245,7 @@ haslist2::haslist2() } void fn10() { - // CHECK: define void @_Z4fn10v + // CHECK-LABEL: define void @_Z4fn10v // CHECK: alloca [3 x i32] // CHECK: call noalias i8* @_Znw{{[jm]}} // CHECK: store i32 1 @@ -232,7 +257,7 @@ void fn10() { } void fn11() { - // CHECK: define void @_Z4fn11v + // CHECK-LABEL: define void @_Z4fn11v (void) new std::initializer_list<destroyme1> {destroyme1(), destroyme1()}; // CHECK: call void @_ZN10destroyme1D1Ev destroyme2 dm2; @@ -260,7 +285,7 @@ namespace PR12178 { namespace rdar13325066 { struct X { ~X(); }; - // CHECK: define void @_ZN12rdar133250664loopERNS_1XES1_ + // CHECK-LABEL: define void @_ZN12rdar133250664loopERNS_1XES1_ void loop(X &x1, X &x2) { // CHECK: br label // CHECK: br i1 @@ -275,3 +300,134 @@ namespace rdar13325066 { for (X x : { x1, x2 }) { } } } + +namespace dtors { + struct S { + S(); + ~S(); + }; + void z(); + + // CHECK-LABEL: define void @_ZN5dtors1fEv( + void f() { + // CHECK: call void @_ZN5dtors1SC1Ev( + // CHECK: call void @_ZN5dtors1SC1Ev( + std::initializer_list<S>{ S(), S() }; + + // Destruction loop for underlying array. + // CHECK: br label + // CHECK: call void @_ZN5dtors1SD1Ev( + // CHECK: br i1 + + // CHECK: call void @_ZN5dtors1zEv( + z(); + + // CHECK-NOT: call void @_ZN5dtors1SD1Ev( + } + + // CHECK-LABEL: define void @_ZN5dtors1gEv( + void g() { + // CHECK: call void @_ZN5dtors1SC1Ev( + // CHECK: call void @_ZN5dtors1SC1Ev( + auto x = std::initializer_list<S>{ S(), S() }; + + // Destruction loop for underlying array. + // CHECK: br label + // CHECK: call void @_ZN5dtors1SD1Ev( + // CHECK: br i1 + + // CHECK: call void @_ZN5dtors1zEv( + z(); + + // CHECK-NOT: call void @_ZN5dtors1SD1Ev( + } + + // CHECK-LABEL: define void @_ZN5dtors1hEv( + void h() { + // CHECK: call void @_ZN5dtors1SC1Ev( + // CHECK: call void @_ZN5dtors1SC1Ev( + std::initializer_list<S> x = { S(), S() }; + + // CHECK-NOT: call void @_ZN5dtors1SD1Ev( + + // CHECK: call void @_ZN5dtors1zEv( + z(); + + // Destruction loop for underlying array. + // CHECK: br label + // CHECK: call void @_ZN5dtors1SD1Ev( + // CHECK: br i1 + } +} + +namespace partly_constant { + int k; + std::initializer_list<std::initializer_list<int>> &&il = { { 1, 2, 3 }, { 4, k }, { 5, 6, 7, 8 } }; + // First init list. + // CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]], + // CHECK: store i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_FIRST]], i64 0, i64 0), + // CHECK: i32** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 0) + // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 1) + // CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]], + // + // Second init list array (non-constant). + // CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0) + // CHECK: load i32* @_ZN15partly_constant1kE + // CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 1) + // + // Second init list. + // CHECK: store i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0), + // CHECK: i32** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 0) + // CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 1) + // + // Third init list. + // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]], + // CHECK: store i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_THIRD]], i64 0, i64 0), + // CHECK: i32** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 2, i32 0) + // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}* @_ZGRN15partly_constant2ilE4, i64 0, i64 2, i32 1) + // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]], + // + // Outer init list. + // CHECK: store {{.*}}* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0), + // CHECK: {{.*}}** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 0) + // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 1) + // + // 'il' reference. + // CHECK: store {{.*}}* @[[PARTLY_CONSTANT_OUTER]], {{.*}}** @_ZN15partly_constant2ilE, align 8 +} + +namespace nested { + struct A { A(); ~A(); }; + struct B { const A &a; ~B(); }; + struct C { std::initializer_list<B> b; ~C(); }; + void f(); + // CHECK-LABEL: define void @_ZN6nested1gEv( + void g() { + // CHECK: call void @_ZN6nested1AC1Ev( + // CHECK-NOT: call + // CHECK: call void @_ZN6nested1AC1Ev( + // CHECK-NOT: call + const C &c { { { A() }, { A() } } }; + + // CHECK: call void @_ZN6nested1fEv( + // CHECK-NOT: call + f(); + + // CHECK: call void @_ZN6nested1CD1Ev( + // CHECK-NOT: call + + // Destroy B[2] array. + // FIXME: This isn't technically correct: reverse construction order would + // destroy the second B then the second A then the first B then the first A. + // CHECK: call void @_ZN6nested1BD1Ev( + // CHECK-NOT: call + // CHECK: br + + // CHECK-NOT: call + // CHECK: call void @_ZN6nested1AD1Ev( + // CHECK-NOT: call + // CHECK: call void @_ZN6nested1AD1Ev( + // CHECK-NOT: call + // CHECK: } + } +} diff --git a/test/CodeGenCXX/cxx11-exception-spec.cpp b/test/CodeGenCXX/cxx11-exception-spec.cpp index 49ca861..96ea1d7 100644 --- a/test/CodeGenCXX/cxx11-exception-spec.cpp +++ b/test/CodeGenCXX/cxx11-exception-spec.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -verify -fexceptions -fcxx-exceptions -triple x86_64-linux-gnu | FileCheck %s +// RUN: not %clang_cc1 -std=c++11 -emit-llvm %s -o - -verify -fexceptions -fcxx-exceptions -triple x86_64-linux-gnu | FileCheck %s void h(); diff --git a/test/CodeGenCXX/cxx11-initializer-array-new.cpp b/test/CodeGenCXX/cxx11-initializer-array-new.cpp new file mode 100644 index 0000000..23577be --- /dev/null +++ b/test/CodeGenCXX/cxx11-initializer-array-new.cpp @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 %s -emit-llvm -o - | FileCheck %s + +// PR10878 + +struct S { S(); S(int); ~S(); int n; }; + +void *p = new S[2][3]{ { 1, 2, 3 }, { 4, 5, 6 } }; + +// CHECK-LABEL: define +// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 32) +// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64* +// CHECK: store i64 6, i64* %[[COOKIE]] +// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8 +// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S:.*]]* +// +// Explicit initializers: +// +// { 1, 2, 3 } +// +// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]* +// +// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1) +// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2) +// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3) +// +// { 4, 5, 6 } +// +// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1 +// +// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4) +// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5) +// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6) +// +// CHECK-NOT: br i1 +// CHECK-NOT: call +// CHECK: } + +int n; +void *q = new S[n][3]{ { 1, 2, 3 }, { 4, 5, 6 } }; + +// CHECK-LABEL: define +// +// CHECK: load i32* @n +// CHECK: call {{.*}} @llvm.umul.with.overflow.i64(i64 %[[N:.*]], i64 12) +// CHECK: %[[ELTS:.*]] = mul i64 %[[N]], 3 +// CHECK: call {{.*}} @llvm.uadd.with.overflow.i64(i64 %{{.*}}, i64 8) +// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 %{{.*}}) +// +// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64* +// CHECK: store i64 %[[ELTS]], i64* %[[COOKIE]] +// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8 +// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S]]* +// CHECK: %[[END_AS_S:.*]] = getelementptr inbounds %[[S]]* %[[START_AS_S]], i64 %[[ELTS]] +// +// Explicit initializers: +// +// { 1, 2, 3 } +// +// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]* +// +// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1) +// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2) +// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3) +// +// { 4, 5, 6 } +// +// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1 +// +// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4) +// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5) +// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1 +// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6) +// +// CHECK: %[[S_2:.*]] = getelementptr [3 x %[[S]]]* %[[S_1]], i32 1 +// CHECK: %[[S_2_AS_S:.*]] = bitcast [3 x %[[S]]]* %[[S_2]] to %[[S]]* +// CHECK: icmp eq %[[S]]* %[[S_2_AS_S]], %[[END_AS_S]] +// CHECK: br i1 +// +// S[n-2][3] initialization loop: +// +// CHECK: %[[END_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 3 +// CHECK: br label +// +// S[3] initialization loop: +// +// CHECK: call void @_ZN1SC1Ev(%[[S]]* +// CHECK: %[[NEXT_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 1 +// CHECK: icmp eq %[[S]]* %[[NEXT_INNER]], %[[END_INNER]] +// CHECK: br i1 +// +// CHECK: %[[NEXT_OUTER:.*]] = getelementptr %[[S]]* %{{.*}}, i32 1 +// CHECK: icmp eq %[[S]]* %[[NEXT_OUTER]], %[[END_AS_S]] +// CHECK: br i1 +// +// CHECK: } diff --git a/test/CodeGenCXX/cxx11-thread-local-reference.cpp b/test/CodeGenCXX/cxx11-thread-local-reference.cpp index 2ea9acd..7759d41 100644 --- a/test/CodeGenCXX/cxx11-thread-local-reference.cpp +++ b/test/CodeGenCXX/cxx11-thread-local-reference.cpp @@ -13,7 +13,7 @@ int &g() { return r; } // CHECK: call i32* @_Z1fv() // CHECK: store i32* %{{.*}}, i32** @r, align 8 -// CHECK: define i32* @_Z1gv() +// CHECK-LABEL: define i32* @_Z1gv() // CHECK: call i32* @_ZTW1r() // CHECK: ret i32* %{{.*}} @@ -22,5 +22,5 @@ int &g() { return r; } // CHECK: load i32** @r, align 8 // CHECK: ret i32* %{{.*}} -// CHECK: define internal void @__tls_init() +// CHECK-LABEL: define internal void @__tls_init() // CHECK: call void @[[R_INIT]]() diff --git a/test/CodeGenCXX/cxx11-thread-local.cpp b/test/CodeGenCXX/cxx11-thread-local.cpp index a7141d1..509562d 100644 --- a/test/CodeGenCXX/cxx11-thread-local.cpp +++ b/test/CodeGenCXX/cxx11-thread-local.cpp @@ -35,7 +35,7 @@ int e = V<int>::m; // CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global // CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0 -// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global +// CHECK: @_ZGRZ8tls_dtorvE1u = private thread_local global // CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0 @@ -55,7 +55,7 @@ int e = V<int>::m; // CHECK: call i32 @_Z1fv() // CHECK-NEXT: store i32 {{.*}}, i32* @a, align 4 -// CHECK: define i32 @_Z1fv() +// CHECK-LABEL: define i32 @_Z1fv() int f() { // CHECK: %[[GUARD:.*]] = load i8* @_ZGVZ1fvE1n, align 1 // CHECK: %[[NEED_INIT:.*]] = icmp eq i8 %[[GUARD]], 0 @@ -76,7 +76,7 @@ int f() { // CHECK-NEXT: load i32* %{{.*}}, align 4 // CHECK-NEXT: store i32 %{{.*}}, i32* @c, align 4 -// CHECK: define weak_odr hidden i32* @_ZTW1b() +// CHECK-LABEL: define weak_odr hidden i32* @_ZTW1b() // CHECK: br i1 icmp ne (void ()* @_ZTH1b, void ()* null), // not null: // CHECK: call void @_ZTH1b() @@ -97,7 +97,7 @@ int f() { // CHECK-NEXT: load i32* %{{.*}}, align 4 // CHECK-NEXT: store i32 %{{.*}}, i32* @e, align 4 -// CHECK: define weak_odr hidden i32* @_ZTWN1VIiE1mE() +// CHECK-LABEL: define weak_odr hidden i32* @_ZTWN1VIiE1mE() // CHECK: call void @_ZTHN1VIiE1mE() // CHECK: ret i32* @_ZN1VIiE1mE @@ -105,7 +105,7 @@ int f() { struct S { S(); ~S(); }; struct T { ~T(); }; -// CHECK: define void @_Z8tls_dtorv() +// CHECK-LABEL: define void @_Z8tls_dtorv() void tls_dtor() { // CHECK: load i8* @_ZGVZ8tls_dtorvE1s // CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZZ8tls_dtorvE1s) @@ -128,6 +128,13 @@ void tls_dtor() { // CHECK: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*) +// CHECK: define {{.*}} @_Z7PR15991v( +int PR15991() { + thread_local int n; + auto l = [] { return n; }; + return l(); +} + // CHECK: define {{.*}} @[[V_M_INIT:.*]]() // CHECK: load i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*) // CHECK: %[[V_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0 @@ -164,10 +171,10 @@ void tls_dtor() { // CHECK: declare extern_weak void @_ZTH1b() -// CHECK: define internal hidden i32* @_ZTWL1d() +// CHECK-LABEL: define internal hidden i32* @_ZTWL1d() // CHECK: call void @_ZTHL1d() // CHECK: ret i32* @_ZL1d -// CHECK: define weak_odr hidden i32* @_ZTWN1U1mE() +// CHECK-LABEL: define weak_odr hidden i32* @_ZTWN1U1mE() // CHECK: call void @_ZTHN1U1mE() // CHECK: ret i32* @_ZN1U1mE diff --git a/test/CodeGenCXX/cxx1y-deduced-return-type.cpp b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp new file mode 100644 index 0000000..6d15a22 --- /dev/null +++ b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s + +// CHECK: @x = global {{.*}} zeroinitializer + +// CHECK: define {{.*}} @_Z1fv +inline auto f() { + int n = 0; + // CHECK: load i32 + // CHECK: store i32 + // CHECK: ret + return [=] () mutable { return ++n; }; +} + +auto x = f(); + +template<typename T> auto *g(T t) { return t; } +template<typename T> decltype(auto) h(T t) { return t; } + +// CHECK: define {{.*}} @_Z1zv +void z() { + // CHECK: call {{.*}} @_Z1gIPZ1fvEUlvE_EPDaT_( + // CHECK: call {{.*}} @_Z1hIPZ1fvEUlvE_EDcT_( + g(&x); + h(&x); +} + +auto i() { return [] {}; } +// CHECK: define {{.*}} @_Z1jv +auto j() { + // CHECK: call {{.*}} @"_Z1hIZ1ivE3$_0EDcT_"() + h(i()); +} diff --git a/test/CodeGenCXX/cxx1y-init-captures.cpp b/test/CodeGenCXX/cxx1y-init-captures.cpp new file mode 100644 index 0000000..a60269f --- /dev/null +++ b/test/CodeGenCXX/cxx1y-init-captures.cpp @@ -0,0 +1,102 @@ +// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s + +struct S { + S(); + S(S &&); + ~S(); +}; + +void f() { + (void) [s(S{})] {}; +} + +// CHECK-LABEL: define void @_Z1fv( +// CHECK: call void @_ZN1SC1Ev( +// CHECK: call void @"_ZZ1fvEN3$_0D1Ev"( + +// CHECK-LABEL: define internal void @"_ZZ1fvEN3$_0D1Ev"( +// CHECK: @"_ZZ1fvEN3$_0D2Ev"( + +// D2 at end of file. + +void g() { + [a(1), b(2)] { return a + b; } (); +} + +// CHECK-LABEL: define void @_Z1gv( +// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 0 +// CHECK: store i32 1, i32* +// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 1 +// CHECK: store i32 2, i32* +// CHECK: call i32 @"_ZZ1gvENK3$_1clEv"( + +// CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_1clEv"( +// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 0 +// CHECK: load i32* +// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 1 +// CHECK: load i32* +// CHECK: add nsw i32 + +int h(int a) { + // CHECK-LABEL: define i32 @_Z1hi( + // CHECK: %[[A_ADDR:.*]] = alloca i32, + // CHECK: %[[OUTER:.*]] = alloca + // CHECK: store i32 {{.*}}, i32* %[[A_ADDR]], + // + // Initialize init-capture 'b(a)' by reference. + // CHECK: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 0 + // CHECK: store i32* %[[A_ADDR]], i32** {{.*}}, + // + // Initialize init-capture 'c(a)' by copy. + // CHECK: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 1 + // CHECK: load i32* %[[A_ADDR]], + // CHECK: store i32 + // + // CHECK: call i32 @"_ZZ1hiENK3$_2clEv"({{.*}}* %[[OUTER]]) + return [&b(a), c(a)] { + // CHECK-LABEL: define internal i32 @"_ZZ1hiENK3$_2clEv"( + // CHECK: %[[OUTER_ADDR:.*]] = alloca + // CHECK: %[[INNER:.*]] = alloca + // CHECK: store {{.*}}, {{.*}}** %[[OUTER_ADDR]], + // + // Capture outer 'c' by reference. + // CHECK: %[[OUTER:.*]] = load {{.*}}** %[[OUTER_ADDR]] + // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 0 + // CHECK-NEXT: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 1 + // CHECK-NEXT: store i32* % + // + // Capture outer 'b' by copy. + // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 1 + // CHECK-NEXT: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 0 + // CHECK-NEXT: load i32** % + // CHECK-NEXT: load i32* % + // CHECK-NEXT: store i32 + // + // CHECK: call i32 @"_ZZZ1hiENK3$_2clEvENKUlvE_clEv"({{.*}}* %[[INNER]]) + return [=, &c] { + // CHECK-LABEL: define internal i32 @"_ZZZ1hiENK3$_2clEvENKUlvE_clEv"( + // CHECK: %[[INNER_ADDR:.*]] = alloca + // CHECK: store {{.*}}, {{.*}}** %[[INNER_ADDR]], + // CHECK: %[[INNER:.*]] = load {{.*}}** %[[INNER_ADDR]] + // + // Load capture of 'b' + // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 1 + // CHECK: load i32* % + // + // Load capture of 'c' + // CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 0 + // CHECK: load i32** % + // CHECK: load i32* % + // + // CHECK: add nsw i32 + return b + c; + } (); + } (); +} + +// Ensure we can emit code for init-captures in global lambdas too. +auto global_lambda = [a = 0] () mutable { return ++a; }; +int get_incremented() { return global_lambda(); } + +// CHECK-LABEL: define internal void @"_ZZ1fvEN3$_0D2Ev"( +// CHECK: call void @_ZN1SD1Ev( diff --git a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp index ef78c43..ae49a04 100644 --- a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp +++ b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp @@ -25,7 +25,11 @@ A b { 4, "bazquux", .x = 42, .c = 9 }; A c { 1, 0, 'A', f(), { 3 } }; // CHECK: @[[STR_A:.*]] = {{.*}} [7 x i8] c"foobar\00" +// CHECK: @a = global {{.*}} zeroinitializer + +// @b has a constant initializer // CHECK: @[[STR_B:.*]] = {{.*}} [8 x i8] c"bazquux\00" +// CHECK: @b = global {{.*}} i32 4, {{.*}} @[[STR_B]], {{.*}} i8 117, i32 42, {{.*}} i8 9 B x; B y {}; @@ -44,18 +48,9 @@ B z { 1 }; // CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @a, i32 0, i32 3) // CHECK: call void @{{.*}}C1Ev({{.*}} getelementptr inbounds (%struct.A* @a, i32 0, i32 4)) -// Initialization of 'b': +// No dynamic initialization of 'b': -// CHECK: store i32 4, i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0) -// CHECK: store i8* {{.*}} @[[STR_B]]{{.*}}, i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1) -// CHECK: load i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0) -// CHECK: load i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1) -// CHECK: getelementptr inbounds i8* %{{.*}}, {{.*}} %{{.*}} -// CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @b, i32 0, i32 2) -// CHECK-NOT: @_ZN1A1fEv -// CHECK: store i32 42, i32* getelementptr inbounds ({{.*}}* @b, i32 0, i32 3) -// CHECK-NOT: C1Ev -// CHECK: store i8 9, i8* {{.*}} @b, i32 0, i32 4) +// CHECK-NOT: @b // Initialization of 'c': diff --git a/test/CodeGenCXX/cxx1y-sized-deallocation.cpp b/test/CodeGenCXX/cxx1y-sized-deallocation.cpp new file mode 100644 index 0000000..7fd3ece --- /dev/null +++ b/test/CodeGenCXX/cxx1y-sized-deallocation.cpp @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -std=c++1y %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNSIZED + +// CHECK-UNSIZED-NOT: _ZdlPvm +// CHECK-UNSIZED-NOT: _ZdaPvm + +typedef decltype(sizeof(0)) size_t; + +typedef int A; +struct B { int n; }; +struct C { ~C() {} }; +struct D { D(); virtual ~D() {} }; +struct E { + void *operator new(size_t); + void *operator new[](size_t); + void operator delete(void *) noexcept; + void operator delete[](void *) noexcept; +}; +struct F { + void *operator new(size_t); + void *operator new[](size_t); + void operator delete(void *, size_t) noexcept; + void operator delete[](void *, size_t) noexcept; +}; + +template<typename T> T get(); + +template<typename T> +void del() { + ::delete get<T*>(); + ::delete[] get<T*>(); + delete get<T*>(); + delete[] get<T*>(); +} + +template void del<A>(); +template void del<B>(); +template void del<C>(); +template void del<D>(); +template void del<E>(); +template void del<F>(); + +D::D() {} + +// CHECK-LABEL: define weak_odr void @_Z3delIiEvv() +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4) +// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}}) +// +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4) +// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}}) + +// CHECK-LABEL: define linkonce void @_ZdlPvm(i8* +// CHECK: call void @_ZdlPv(i8* %0) + +// CHECK-LABEL: define weak_odr void @_Z3delI1BEvv() +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4) +// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}}) +// +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4) +// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}}) + +// CHECK-LABEL: define weak_odr void @_Z3delI1CEvv() +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1) +// CHECK: mul i64 1, %{{[^ ]*}} +// CHECK: add i64 %{{[^ ]*}}, 8 +// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}}) +// +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1) +// CHECK: mul i64 1, %{{[^ ]*}} +// CHECK: add i64 %{{[^ ]*}}, 8 +// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}}) + +// CHECK-LABEL: define linkonce void @_ZdaPvm(i8* +// CHECK: call void @_ZdaPv(i8* %0) + +// CHECK-LABEL: define weak_odr void @_Z3delI1DEvv() +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8) +// CHECK: mul i64 8, %{{[^ ]*}} +// CHECK: add i64 %{{[^ ]*}}, 8 +// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}}) +// +// CHECK-NOT: Zdl +// CHECK: call void %{{.*}} +// CHECK-NOT: Zdl +// CHECK: mul i64 8, %{{[^ ]*}} +// CHECK: add i64 %{{[^ ]*}}, 8 +// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}}) + +// CHECK-LABEL: define weak_odr void @_Z3delI1EEvv() +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1) +// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}}) +// +// CHECK: call void @_ZN1EdlEPv(i8* %{{[^ ]*}}) +// CHECK: call void @_ZN1EdaEPv(i8* %{{[^ ]*}}) + +// CHECK-LABEL: define weak_odr void @_Z3delI1FEvv() +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1) +// CHECK: mul i64 1, %{{[^ ]*}} +// CHECK: add i64 %{{[^ ]*}}, 8 +// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}}) +// +// CHECK: call void @_ZN1FdlEPvm(i8* %{{[^ ]*}}, i64 1) +// CHECK: mul i64 1, %{{[^ ]*}} +// CHECK: add i64 %{{[^ ]*}}, 8 +// CHECK: call void @_ZN1FdaEPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}}) + + +// CHECK-LABEL: define linkonce_odr void @_ZN1DD0Ev(%{{[^ ]*}}* %this) +// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8) diff --git a/test/CodeGenCXX/cxx1y-variable-template.cpp b/test/CodeGenCXX/cxx1y-variable-template.cpp new file mode 100644 index 0000000..d1e7060 --- /dev/null +++ b/test/CodeGenCXX/cxx1y-variable-template.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s + +// Check that we keep the 'extern' when we instantiate the definition of this +// variable template specialization. +template<typename T> extern const int extern_redecl; +template<typename T> const int extern_redecl = 5; +template const int extern_redecl<int>; + +// CHECK: @_Z13extern_redeclIiE = weak_odr constant + +template<typename T> struct Outer { + template<typename U> struct Inner { + template<typename V> static int arr[]; + }; +}; +Outer<char[100]> outer_int; +int init_arr(); +template<typename T> template<typename U> template<typename V> int Outer<T>::Inner<U>::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() }; +int *p = Outer<char[100]>::Inner<char[20]>::arr<char[3]>; + +// CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global [123 x i32] zeroinitializer +// CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global + +// CHECK: call {{.*}}@_Z8init_arrv diff --git a/test/CodeGenCXX/debug-info-artificial-arg.cpp b/test/CodeGenCXX/debug-info-artificial-arg.cpp index ff0f663..84f496f 100644 --- a/test/CodeGenCXX/debug-info-artificial-arg.cpp +++ b/test/CodeGenCXX/debug-info-artificial-arg.cpp @@ -22,8 +22,8 @@ int main(int argc, char **argv) { A reallyA (500); } -// CHECK: ![[ARTARG:.*]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from A] -// CHECK: ![[CLASSTYPE:.*]] = {{.*}} ; [ DW_TAG_class_type ] [A] -// CHECK: metadata ![[CLASSTYPE]], {{.*}} ; [ DW_TAG_subprogram ] [line 12] [A] -// CHECK: metadata [[FUNCTYPE:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ] +// CHECK: ![[CLASSTYPE:.*]] = {{.*}}, metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A] +// CHECK: ![[ARTARG:.*]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS1A] +// CHECK: metadata !"_ZTS1A", {{.*}} ; [ DW_TAG_subprogram ] [line 12] [A] +// CHECK: metadata [[FUNCTYPE:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] // CHECK: [[FUNCTYPE]] = metadata !{null, metadata ![[ARTARG]], metadata !{{.*}}, metadata !{{.*}}} diff --git a/test/CodeGenCXX/debug-info-class-limited.cpp b/test/CodeGenCXX/debug-info-class-limited.cpp new file mode 100644 index 0000000..a4b9f46 --- /dev/null +++ b/test/CodeGenCXX/debug-info-class-limited.cpp @@ -0,0 +1,52 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s + +namespace PR16214_1 { +// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def] +struct foo { + int i; +}; + +typedef foo bar; + +bar *a; +bar b; +} + +namespace PR14467 { +// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def] +struct foo { +}; + +foo *bar(foo *a) { + foo *b = new foo(*a); + return b; +} +} + +namespace test1 { +// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [decl] +struct foo { +}; + +extern int bar(foo *a); +int baz(foo *a) { + return bar(a); +} +} + +namespace test2 { +// FIXME: if we were a bit fancier, we could realize that the 'foo' type is only +// required because of the 'bar' type which is not required at all (or might +// only be required to be declared) +// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def] +struct foo { +}; + +struct bar { + foo f; +}; + +void func() { + foo *f; +} +} diff --git a/test/CodeGenCXX/debug-info-class-nolimit.cpp b/test/CodeGenCXX/debug-info-class-nolimit.cpp new file mode 100644 index 0000000..ce72bd3 --- /dev/null +++ b/test/CodeGenCXX/debug-info-class-nolimit.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple x86_64-unk-unk -fno-limit-debug-info -o - -emit-llvm -g %s | FileCheck %s + +namespace rdar14101097_1 { // see also PR16214 +// Check that we emit debug info for the definition of a struct if the +// definition is available, even if it's used via a pointer wrapped in a +// typedef. +// CHECK: [ DW_TAG_structure_type ] [foo] {{.*}}[def] +struct foo { +}; + +typedef foo *foop; + +void bar() { + foop f; +} +} + +namespace rdar14101097_2 { +// As above, except trickier because we first encounter only a declaration of +// the type and no debug-info related use after we see the definition of the +// type. +// CHECK: [ DW_TAG_structure_type ] [foo] {{.*}}[def] +struct foo; +void bar() { + foo *f; +} +struct foo { +}; +} + diff --git a/test/CodeGenCXX/debug-info-class.cpp b/test/CodeGenCXX/debug-info-class.cpp index df24926..e1402c9 100644 --- a/test/CodeGenCXX/debug-info-class.cpp +++ b/test/CodeGenCXX/debug-info-class.cpp @@ -12,6 +12,51 @@ class B { public: virtual ~B(); }; + +B::~B() { +} + +struct C { + static int s; + virtual ~C(); +}; + +C::~C() { +} + +struct D { + D(); + virtual ~D(); + void func() { + } +}; + +struct E { + E(); + virtual ~E(); + virtual void func() { + } +}; + +struct F { + struct inner { + }; + static const int i = 2; + virtual ~F(); +}; + +struct G { + virtual void func(); + struct inner { + int j; + }; +}; + +struct H {}; +struct I : virtual H {}; +struct J : I {}; +J j; + struct A { int one; static const int HdrSize = 52; @@ -21,9 +66,17 @@ struct A { } }; +void f1() { + D x; + x.func(); + E y; + int i = F::i; + F::inner z; +} int main(int argc, char **argv) { B b; + G::inner c_i; if (argc) { A a; } @@ -40,9 +93,33 @@ int main(int argc, char **argv) { // CHECK: DW_TAG_structure_type ] [foo] // CHECK: DW_TAG_class_type ] [bar] // CHECK: DW_TAG_union_type ] [baz] -// CHECK: DW_TAG_structure_type ] [A] -// CHECK: HdrSize -// CHECK: DW_TAG_class_type ] [B] +// CHECK: DW_TAG_class_type ] [B] {{.*}} [def] // CHECK: metadata !"_vptr$B", {{.*}}, i32 64, metadata !{{.*}}} ; [ DW_TAG_member ] -// CHECK: ![[EXCEPTLOC]] = metadata !{i32 31, -// CHECK: ![[RETLOC]] = metadata !{i32 30, + +// CHECK: [[C:![0-9]*]] = {{.*}} metadata [[C_MEM:![0-9]*]], i32 0, metadata !"_ZTS1C", null, metadata !"_ZTS1C"} ; [ DW_TAG_structure_type ] [C] {{.*}} [def] +// CHECK: [[C_MEM]] = metadata !{metadata [[C_VPTR:![0-9]*]], metadata [[C_S:![0-9]*]], metadata [[C_DTOR:![0-9]*]]} +// CHECK: [[C_VPTR]] = {{.*}} ; [ DW_TAG_member ] [_vptr$C] {{.*}} [artificial] +// CHECK: [[C_S]] = {{.*}} ; [ DW_TAG_member ] [s] {{.*}} [static] [from int] +// CHECK: [[C_DTOR]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [~C] + +// CHECK: metadata [[D_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS1D"} ; [ DW_TAG_structure_type ] [D] {{.*}} [decl] +// CHECK: [[D_MEM]] = metadata !{metadata [[D_FUNC:![0-9]*]]} +// CHECK: [[D_FUNC]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func] +// CHECK: null, i32 0, null, null, metadata !"_ZTS1E"} ; [ DW_TAG_structure_type ] [E] {{.*}} [decl] +// CHECK: [[F:![0-9]*]] = {{.*}} metadata [[F_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS1F"} ; [ DW_TAG_structure_type ] [F] {{.*}} [decl] +// CHECK: [[F_MEM]] = metadata !{metadata [[F_I:![0-9]*]]} +// CHECK: [[F_I]] = {{.*}} ; [ DW_TAG_member ] [i] + +// CHECK: null, i32 0, null, null, metadata !"_ZTS1G"} ; [ DW_TAG_structure_type ] [G] {{.*}} [decl] +// CHECK: metadata [[G_INNER_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTSN1G5innerE"} ; [ DW_TAG_structure_type ] [inner] [line 50, {{.*}} [def] +// CHECK: [[G_INNER_MEM]] = metadata !{metadata [[G_INNER_I:![0-9]*]]} +// CHECK: [[G_INNER_I]] = {{.*}} ; [ DW_TAG_member ] [j] {{.*}} [from int] + +// CHECK: ; [ DW_TAG_structure_type ] [A] +// CHECK: HdrSize +// CHECK: ; [ DW_TAG_structure_type ] [I] {{.*}} [def] + +// CHECK: [[F_I_DEF:![0-9]*]] = {{.*}}, metadata [[F_I]]} ; [ DW_TAG_variable ] [i] + +// CHECK: ![[EXCEPTLOC]] = metadata !{i32 84, +// CHECK: ![[RETLOC]] = metadata !{i32 83, diff --git a/test/CodeGenCXX/debug-info-cxx1y.cpp b/test/CodeGenCXX/debug-info-cxx1y.cpp new file mode 100644 index 0000000..3cb7e45 --- /dev/null +++ b/test/CodeGenCXX/debug-info-cxx1y.cpp @@ -0,0 +1,7 @@ +// RUN: not %clang_cc1 -emit-llvm-only -std=c++1y -g %s 2>&1 | FileCheck %s + +struct foo { + auto func(); // CHECK: error: debug information for auto is not yet supported +}; + +foo f; diff --git a/test/CodeGenCXX/debug-info-decl-nested.cpp b/test/CodeGenCXX/debug-info-decl-nested.cpp new file mode 100644 index 0000000..f79a8e9 --- /dev/null +++ b/test/CodeGenCXX/debug-info-decl-nested.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -std=c++11 -g -emit-llvm -g -triple x86_64-apple-darwin %s -o %t +// RUN: cat %t | FileCheck %s -check-prefix=CHECK0 +// RUN: cat %t | FileCheck %s -check-prefix=CHECK1 +// RUN: cat %t | FileCheck %s -check-prefix=CHECK2 +// +// This test ensures that we associate a declaration with the +// definition of the constructor for OuterClass. The declaration is +// necessary so the backend can emit the DW_AT_specification attribute +// for the definition. +// +// rdar://problem/13116508 + +class Foo; +class OuterClass +{ + static class InnerClass { + public: + InnerClass(); // Here createContextChain() generates a limited type for OuterClass. + } theInnerClass; +// CHECK0: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [OuterClass] + OuterClass(const Foo *); // line 10 +}; +OuterClass::InnerClass OuterClass::theInnerClass; // This toplevel decl causes InnerClass to be generated. +// CHECK0: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [OuterClass] +OuterClass::OuterClass(const Foo *meta) { } // line 13 + + + + + +class Foo1; +class OuterClass1 +{ + static class InnerClass1 { + public: + InnerClass1(); + } theInnerClass1; +// CHECK1: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+2]]] [private] [Bar] +// CHECK1: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+4]]} ; [ DW_TAG_subprogram ] [line [[@LINE+4]]] [def] [Bar] + void Bar(const Foo1 *); +}; +OuterClass1::InnerClass1 OuterClass1::theInnerClass1; +void OuterClass1::Bar(const Foo1 *meta) { } + + + + + +class Foo2; +class OuterClass2 +{ + static class InnerClass2 { + public: + InnerClass2(); + } theInnerClass2; +// CHECK2: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [~OuterClass2] + ~OuterClass2(); // line 10 +}; +OuterClass2::InnerClass2 OuterClass2::theInnerClass2; +// CHECK2: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [~OuterClass2] +OuterClass2::~OuterClass2() { } diff --git a/test/CodeGenCXX/debug-info-enum-class.cpp b/test/CodeGenCXX/debug-info-enum-class.cpp index 929327b..0f4b09a 100644 --- a/test/CodeGenCXX/debug-info-enum-class.cpp +++ b/test/CodeGenCXX/debug-info-enum-class.cpp @@ -9,10 +9,10 @@ B b; C c; D d; -// CHECK: ; [ DW_TAG_enumeration_type ] [A] [line 3, size 32, align 32, offset 0] [from int] -// CHECK: ; [ DW_TAG_enumeration_type ] [B] [line 4, size 64, align 64, offset 0] [from long unsigned int] -// CHECK: ; [ DW_TAG_enumeration_type ] [C] [line 5, size 32, align 32, offset 0] [from ] -// CHECK: ; [ DW_TAG_enumeration_type ] [D] [line 6, size 16, align 16, offset 0] [fwd] [from ] +// CHECK: ; [ DW_TAG_enumeration_type ] [A] [line 3, size 32, align 32, offset 0] [def] [from int] +// CHECK: ; [ DW_TAG_enumeration_type ] [B] [line 4, size 64, align 64, offset 0] [def] [from long unsigned int] +// CHECK: ; [ DW_TAG_enumeration_type ] [C] [line 5, size 32, align 32, offset 0] [def] [from ] +// CHECK: ; [ DW_TAG_enumeration_type ] [D] [line 6, size 16, align 16, offset 0] [decl] [from ] namespace PR14029 { // Make sure this doesn't crash/assert. diff --git a/test/CodeGenCXX/debug-info-enum.cpp b/test/CodeGenCXX/debug-info-enum.cpp index c08fc35..f0e2608 100644 --- a/test/CodeGenCXX/debug-info-enum.cpp +++ b/test/CodeGenCXX/debug-info-enum.cpp @@ -1,8 +1,36 @@ -// RUN: %clang -fverbose-asm -S -g %s -o - | grep DW_TAG_enumeration_type +// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s -int v; -enum index { MAX }; -void foo(void) -{ - v = MAX; +// CHECK: [[ENUMS:![0-9]*]], {{[^,]*}}, {{[^,]*}}, {{[^,]*}}, {{[^,]*}}, {{[^,]*}}} ; [ DW_TAG_compile_unit ] +// CHECK: [[ENUMS]] = metadata !{metadata [[E1:![0-9]*]], metadata [[E2:![0-9]*]], metadata [[E3:![0-9]*]]} + +namespace test1 { +// CHECK: [[E1]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST1:![0-9]*]], {{.*}}, metadata [[TEST1_ENUMS:![0-9]*]], {{[^,]*}}, null, null, metadata !"_ZTSN5test11eE"} ; [ DW_TAG_enumeration_type ] [e] +// CHECK: [[TEST1]] = {{.*}} ; [ DW_TAG_namespace ] [test1] +// CHECK: [[TEST1_ENUMS]] = metadata !{metadata [[TEST1_E:![0-9]*]]} +// CHECK: [[TEST1_E]] = {{.*}}, metadata !"E", i64 0} ; [ DW_TAG_enumerator ] [E :: 0] +enum e { E }; +void foo() { + int v = E; +} +} + +namespace test2 { +// rdar://8195980 +// CHECK: [[E2]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST2:![0-9]*]], {{.*}}, metadata [[TEST1_ENUMS]], {{[^,]*}}, null, null, metadata !"_ZTSN5test21eE"} ; [ DW_TAG_enumeration_type ] [e] +// CHECK: [[TEST2]] = {{.*}} ; [ DW_TAG_namespace ] [test2] +enum e { E }; +bool func(int i) { + return i == E; +} +} + +namespace test3 { +// CHECK: [[E3]] = metadata !{i32 {{[^,]*}}, {{[^,]*}}, metadata [[TEST3:![0-9]*]], {{.*}}, metadata [[TEST3_ENUMS:![0-9]*]], {{[^,]*}}, null, null, metadata !"_ZTSN5test31eE"} ; [ DW_TAG_enumeration_type ] [e] +// CHECK: [[TEST3]] = {{.*}} ; [ DW_TAG_namespace ] [test3] +// CHECK: [[TEST3_ENUMS]] = metadata !{metadata [[TEST3_E:![0-9]*]]} +// CHECK: [[TEST3_E]] = {{.*}}, metadata !"E", i64 -1} ; [ DW_TAG_enumerator ] [E :: -1] +enum e { E = -1 }; +void func() { + e x; +} } diff --git a/test/CodeGenCXX/debug-info-friend.cpp b/test/CodeGenCXX/debug-info-friend.cpp index c50f281..b103b14 100644 --- a/test/CodeGenCXX/debug-info-friend.cpp +++ b/test/CodeGenCXX/debug-info-friend.cpp @@ -1,11 +1,20 @@ -// RUN: %clang -fverbose-asm -S -g %s -o - | grep DW_TAG_friend +// RUN: %clang -emit-llvm -S -g %s -o - | FileCheck %s class MyFriend; -class SomeClass -{ - friend class MyFriend; +class SomeClass { + friend class MyFriend; + typedef int SomeType; }; -SomeClass sc; +SomeClass *x; +struct MyFriend { + static void func(SomeClass::SomeType) { + } +}; + +// Emitting debug info for friends unnecessarily bloats debug info without any +// known benefit or debugger feature that requires it. Re-enable this is a +// use-case appears. +// CHECK-NOT: DW_TAG_friend diff --git a/test/CodeGenCXX/debug-info-function-context.cpp b/test/CodeGenCXX/debug-info-function-context.cpp new file mode 100644 index 0000000..4ca1c8d --- /dev/null +++ b/test/CodeGenCXX/debug-info-function-context.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-pc-linux-gnu %s -o - | FileCheck %s + +struct C { + void member_function(); + static int static_member_function(); + static int static_member_variable; +}; + +int C::static_member_variable = 0; + +void C::member_function() { static_member_variable = 0; } + +int C::static_member_function() { return static_member_variable; } + +C global_variable; + +int global_function() { return -1; } + +namespace ns { +void global_namespace_function() { global_variable.member_function(); } +int global_namespace_variable = 1; +} + +// Check that the functions that belong to C have C as a context and the +// functions that belong to the namespace have it as a context, and the global +// function has the file as a context. + +// CHECK: metadata !"_ZTS1C", metadata !"member_function"{{.*}} [ DW_TAG_subprogram ] [line 11] [def] [member_function] + +// CHECK: metadata !"_ZTS1C", metadata !"static_member_function"{{.*}} [ DW_TAG_subprogram ] [line 13] [def] [static_member_function] + +// CHECK: metadata !22, metadata !"global_function"{{.*}} [ DW_TAG_subprogram ] [line 17] [def] [global_function] +// CHECK: !22 = {{.*}} [ DW_TAG_file_type ] + +// CHECK: metadata !24, metadata !"global_namespace_function"{{.*}} [ DW_TAG_subprogram ] [line 20] [def] [global_namespace_function] +// CHECK: !24 = {{.*}} [ DW_TAG_namespace ] [ns] [line 19] diff --git a/test/CodeGenCXX/debug-info-gline-tables-only.cpp b/test/CodeGenCXX/debug-info-gline-tables-only.cpp index 8d2e63d..7ecdeb2 100644 --- a/test/CodeGenCXX/debug-info-gline-tables-only.cpp +++ b/test/CodeGenCXX/debug-info-gline-tables-only.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -O0 -gline-tables-only -S -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -gline-tables-only -S -emit-llvm -o - | FileCheck %s // Checks that clang with "-gline-tables-only" doesn't emit debug info // for variables and types. @@ -13,9 +13,17 @@ class E : public C { // CHECK-NOT: DW_TAG_reference type void x(const D& d); }; +struct F { + enum X { }; + void func(X); + virtual ~F(); +}; +F::~F() { +} } // CHECK-NOT: DW_TAG_variable NS::C c; NS::D d; NS::E e; +NS::F f; diff --git a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp index bdaf58c..afa7707 100644 --- a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp +++ b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp @@ -20,8 +20,8 @@ void foo() { // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 12] [local] [def] [__dtor_glob] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_var_init1] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_array_dtor] -// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_] +// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_array] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 16] [local] [def] [__dtor__ZZ3foovE4stat] -// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def] [_GLOBAL__I_a] +// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def]{{$}} -// CHECK-KEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def] [_GLOBAL__D_a] +// CHECK-KEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def]{{$}} diff --git a/test/CodeGenCXX/debug-info-globalinit.cpp b/test/CodeGenCXX/debug-info-globalinit.cpp index b3891c1..30c8bfc 100644 --- a/test/CodeGenCXX/debug-info-globalinit.cpp +++ b/test/CodeGenCXX/debug-info-globalinit.cpp @@ -12,19 +12,27 @@ int test() { static int i = test(); __attribute__((nodebug)) static int j = test(); +static int k = test(); int main(void) {} -// CHECK: define internal void @__cxx_global_var_init() +// CHECK-LABEL: define internal void @__cxx_global_var_init() // CHECK-NOT: __cxx_global_var_init // CHECK: %[[C0:.+]] = call i32 @_Z4testv(), !dbg ![[LINE:.*]] // CHECK-NOT: __cxx_global_var_init // CHECK: store i32 %[[C0]], i32* @_ZL1i, align 4, !dbg // -// CHECK: define internal void @__cxx_global_var_init1() +// CHECK-LABEL: define internal void @__cxx_global_var_init1() // CHECK-NOT: dbg // CHECK: %[[C1:.+]] = call i32 @_Z4testv() // CHECK-NOT: dbg // CHECK: store i32 %[[C1]], i32* @_ZL1j, align 4 +// +// CHECK-LABEL: define internal void @__cxx_global_var_init2() +// CHECK-NOT: __cxx_global_var_init +// CHECK: %[[C2:.+]] = call i32 @_Z4testv(), !dbg ![[LINE2:.*]] +// CHECK-NOT: __cxx_global_var_init +// CHECK: store i32 %[[C2]], i32* @_ZL1k, align 4, !dbg // // CHECK: ![[LINE]] = metadata !{i32 13, i32 +// CHECK: ![[LINE2]] = metadata !{i32 15, i32 diff --git a/test/CodeGenCXX/debug-info-limit-type.cpp b/test/CodeGenCXX/debug-info-limit-type.cpp deleted file mode 100644 index e03024f..0000000 --- a/test/CodeGenCXX/debug-info-limit-type.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s -// XFAIL: * - -class B { -public: - int bb; - void fn2() {} -}; - -class A { -public: - int aa; - void fn1(B b) { b.fn2(); } -}; - -void foo(A *aptr) { -} - -void bar() { - A a; -} - -// B should only be emitted as a forward reference (i32 4). -// CHECK: metadata !"B", metadata !6, i32 3, i32 0, i32 0, i32 0, i32 4} ; [ DW_TAG_class_type ] diff --git a/test/CodeGenCXX/debug-info-limit.cpp b/test/CodeGenCXX/debug-info-limit.cpp deleted file mode 100644 index bca887b..0000000 --- a/test/CodeGenCXX/debug-info-limit.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s - -// TAG_member is used to encode debug info for class constructor. -// CHECK: TAG_member -class A { -public: - int z; -}; - -A *foo (A* x) { - A *a = new A(*x); - return a; -} - diff --git a/test/CodeGenCXX/debug-info-limited.cpp b/test/CodeGenCXX/debug-info-limited.cpp new file mode 100644 index 0000000..54a2424 --- /dev/null +++ b/test/CodeGenCXX/debug-info-limited.cpp @@ -0,0 +1,33 @@ +// RUN: %clang -flimit-debug-info -emit-llvm -g -S %s -o - | FileCheck %s + +// CHECK: ; [ DW_TAG_class_type ] [A] {{.*}} [def] +class A { +public: + int z; +}; + +A *foo (A* x) { + A *a = new A(*x); + return a; +} + +// Verify that we're not emitting a full definition of B in limit debug mode. +// CHECK: ; [ DW_TAG_class_type ] [B] {{.*}} [decl] + +class B { +public: + int y; +}; + +extern int bar(B *b); +int baz(B *b) { + return bar(b); +} + + +// CHECK: ; [ DW_TAG_structure_type ] [C] {{.*}} [decl] + +struct C { +}; + +C (*x)(C); diff --git a/test/CodeGenCXX/debug-info-method.cpp b/test/CodeGenCXX/debug-info-method.cpp index 3ee4d9b..50b3f66 100644 --- a/test/CodeGenCXX/debug-info-method.cpp +++ b/test/CodeGenCXX/debug-info-method.cpp @@ -1,9 +1,10 @@ // RUN: %clang_cc1 -emit-llvm -std=c++11 -g %s -o - | FileCheck %s -// CHECK: ![[THISTYPE:[0-9]+]] = {{.*}} ; [ DW_TAG_pointer_type ] {{.*}} [artificial] [from A] +// CHECK: metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A] // CHECK: metadata !"_ZN1A3fooEiS_3$_0", {{.*}} [protected] +// CHECK: ![[THISTYPE:[0-9]+]] = {{.*}} ; [ DW_TAG_pointer_type ] {{.*}} [artificial] [from _ZTS1A] // CHECK: DW_TAG_ptr_to_member_type // CHECK: {{.*}}metadata ![[MEMFUNTYPE:[0-9]+]], metadata !{{.*}}} ; [ DW_TAG_ptr_to_member_type ] {{.*}} [from ] -// CHECK: ![[MEMFUNTYPE]] = {{.*}}metadata ![[MEMFUNARGS:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ] {{.*}} [from ] +// CHECK: ![[MEMFUNTYPE]] = {{.*}}metadata ![[MEMFUNARGS:[0-9]+]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] {{.*}} [from ] // CHECK: ![[MEMFUNARGS]] = {{.*}}, metadata ![[THISTYPE]], // CHECK: ""{{.*}}DW_TAG_arg_variable // CHECK: ""{{.*}}DW_TAG_arg_variable diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp index 13a7914..a2d7ede 100644 --- a/test/CodeGenCXX/debug-info-namespace.cpp +++ b/test/CodeGenCXX/debug-info-namespace.cpp @@ -1,14 +1,24 @@ -// RUN: %clang -g -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -g -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -g -gline-tables-only -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-GMLT %s +// RUN: %clang -g -fno-limit-debug-info -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-NOLIMIT %s namespace A { #line 1 "foo.cpp" namespace B { int i; +void f1() { } +void f1(int) { } +struct foo; +struct bar { }; +typedef bar baz; } +} +namespace A { using namespace B; } using namespace A; +namespace E = A; int func(bool b) { if (b) { @@ -16,22 +26,52 @@ int func(bool b) { return i; } using namespace A; - return B::i; + using B::foo; + using B::bar; + using B::f1; + using B::i; + using B::baz; + namespace X = A; + namespace Y = X; + return i + X::B::i + Y::B::i; } +// This should work even if 'i' and 'func' were declarations & not definitions, +// but it doesn't yet. + // CHECK: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !""} ; [ DW_TAG_compile_unit ] // CHECK: [[FILE:![0-9]*]] {{.*}}debug-info-namespace.cpp" -// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 9] [def] [func] -// CHECK: [[FILE2:![0-9]*]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp] -// CHECK: [[VAR:![0-9]*]] = {{.*}}, metadata [[NS:![0-9]*]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i] -// CHECK: [[NS]] = {{.*}}, metadata [[FILE2]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1] -// CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 3] -// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]]} -// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 4} ; [ DW_TAG_imported_module ] -// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 7} ; [ DW_TAG_imported_module ] -// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX:![0-9]*]], metadata [[NS]], i32 11} ; [ DW_TAG_imported_module ] -// CHECK: [[LEX]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 10, i32 0, i32 0} ; [ DW_TAG_lexical_block ] -// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 14} ; [ DW_TAG_imported_module ] +// CHECK: [[FOO:![0-9]*]] {{.*}} ; [ DW_TAG_structure_type ] [foo] [line 5, size 0, align 0, offset 0] [decl] [from ] +// CHECK: [[FOOCPP:![0-9]*]] = metadata !{metadata !"foo.cpp", {{.*}} +// CHECK: [[NS:![0-9]*]] = {{.*}}, metadata [[FILE2:![0-9]*]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1] +// CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 5] +// CHECK: [[BAR:![0-9]*]] {{.*}} ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [decl] [from ] +// CHECK: [[F1:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 4] [def] [f1] +// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func] +// CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp] +// CHECK: [[I:![0-9]*]] = {{.*}}, metadata [[NS]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i] +// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]], metadata [[M10:![0-9]*]], metadata [[M11:![0-9]*]], metadata [[M12:![0-9]*]]} +// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 11} ; [ DW_TAG_imported_module ] +// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_module ] +// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 15, metadata !"E"} ; [ DW_TAG_imported_module ] +// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX2:![0-9]*]], metadata [[NS]], i32 19} ; [ DW_TAG_imported_module ] +// CHECK: [[LEX2]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[LEX1:![0-9]+]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ] +// CHECK: [[LEX1]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ] +// CHECK: [[M5]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_module ] +// CHECK: [[M6]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[FOO:![0-9]*]], i32 23} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M7]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAR:![0-9]*]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M8]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[F1]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M9]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ] +// CHECK: [[M10]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAZ:![0-9]*]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ] +// CHECK: [[BAZ]] = metadata !{i32 {{[0-9]*}}, metadata [[FOOCPP]], metadata [[NS]], {{.*}}, metadata !"_ZTSN1A1B3barE"} ; [ DW_TAG_typedef ] [baz] {{.*}} [from _ZTSN1A1B3barE] +// CHECK: [[M11]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}, metadata !"X"} ; [ DW_TAG_imported_module ] +// CHECK: [[M12]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[M11]], i32 {{[0-9]*}}, metadata !"Y"} ; [ DW_TAG_imported_module ] + +// CHECK-GMLT: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !""} ; [ DW_TAG_compile_unit ] +// CHECK-GMLT: [[MODULES]] = metadata !{i32 0} + +// CHECK-NOLIMIT: ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [def] [from ] // FIXME: It is confused on win32 to generate file entry when dosish filename is given. // REQUIRES: shell +// REQUIRES: shell-preserves-root diff --git a/test/CodeGenCXX/debug-info-nullptr.cpp b/test/CodeGenCXX/debug-info-nullptr.cpp index 42e9741..ef9b618 100644 --- a/test/CodeGenCXX/debug-info-nullptr.cpp +++ b/test/CodeGenCXX/debug-info-nullptr.cpp @@ -4,4 +4,4 @@ void foo() { decltype(nullptr) t = 0; } -// CHECK: [ DW_TAG_unspecified_type ] [nullptr_t] +// CHECK: [ DW_TAG_unspecified_type ] [decltype(nullptr)] diff --git a/test/CodeGenCXX/debug-info-pubtypes.cpp b/test/CodeGenCXX/debug-info-pubtypes.cpp index 6ca3da8..6393cdd 100644 --- a/test/CodeGenCXX/debug-info-pubtypes.cpp +++ b/test/CodeGenCXX/debug-info-pubtypes.cpp @@ -1,6 +1,5 @@ // REQUIRES: x86-64-registered-target -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S %s -o %t -// RUN: FileCheck %s < %t +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S -mllvm -generate-dwarf-pub-sections=Enable %s -o - | FileCheck %s // FIXME: This testcase shouldn't rely on assembly emission. //CHECK: Lpubtypes_begin[[SECNUM:[0-9]:]] @@ -10,7 +9,7 @@ class G { public: - void foo(); + void foo(); }; void G::foo() { diff --git a/test/CodeGenCXX/debug-info-same-line.cpp b/test/CodeGenCXX/debug-info-same-line.cpp index ad24503..519e9ee 100644 --- a/test/CodeGenCXX/debug-info-same-line.cpp +++ b/test/CodeGenCXX/debug-info-same-line.cpp @@ -83,6 +83,21 @@ main(int argc, char const *argv[]) // result // CHECK: call void @llvm.dbg.declare +// We want to see a distinct !dbg node. +// CHECK-NOT: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[A_MD]]), !dbg ![[A_DI]] +// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[A_MD]]), !dbg !{{.*}} +// CHECK-NOT: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[B_MD]]), !dbg ![[B_DI]] +// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[B_MD]]), !dbg !{{.*}} +// result +// CHECK: call void @llvm.dbg.declare + +// Again: we want to see a distinct !dbg node. +// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[X_MD:[0-9]+]]), !dbg ![[X_DI:[0-9]+]] +// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[Y_MD:[0-9]+]]), !dbg ![[Y_DI:[0-9]+]] +// result +// CHECK: call void @llvm.dbg.declare + + // CHECK: define {{.*}} @main // CHECK: call {{.*}} @_Z3fooii // CHECK: call {{.*}} @_Z3fooii @@ -96,3 +111,13 @@ main(int argc, char const *argv[]) // CHECK: load {{.*}} !dbg ![[DBG]] // CHECK: call {{.*}} @_Z11strange_maxii(i32 {{.*}}, i32 {{.*}}), !dbg ![[DBG]] // CHECK: call {{.*}} @_Z11strange_maxii(i32 {{.*}}, i32 {{.*}}), !dbg ![[DBG]] + + +// Verify that product() has its own inlined_at location at column 15. +// CHECK-DAG: ![[A_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [a] +// CHECK-DAG: ![[B_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [b] +// CHECK-DAG: ![[X_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [x] +// CHECK-DAG: ![[Y_MD]] = metadata{{.*}}[ DW_TAG_arg_variable ] [y] +// CHECK-DAG: ![[X_DI]] = metadata !{i32 {{[0-9]+}}, i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata ![[PRODUCT:[0-9]+]]} +// CHECK-DAG: [[PRODUCT]] = metadata !{i32 {{.*}}, i32 16, metadata !{{.*}}, null} +// CHECK-DAG: ![[Y_DI]] = metadata !{i32 {{[0-9]+}}, i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata ![[PRODUCT]]} diff --git a/test/CodeGenCXX/debug-info-scope.cpp b/test/CodeGenCXX/debug-info-scope.cpp new file mode 100644 index 0000000..557ee31 --- /dev/null +++ b/test/CodeGenCXX/debug-info-scope.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -g -emit-llvm %s -o -| FileCheck %s +// +// Two variables with the same name in subsequent if staments need to be in separate scopes. +// +// rdar://problem/14024005 +// + +int printf(const char*, ...); + +char *return_char (int input) +{ + if (input%2 == 0) + return "I am even.\n"; + else + return "I am odd.\n"; +} + +int main2() { +// CHECK: [ DW_TAG_auto_variable ] [ptr] [line [[@LINE+2]]] +// CHECK metadata !{i32 {{.*}}, metadata !{{.*}}, i32 [[@LINE+1]], {{.*}}} ; [ DW_TAG_lexical_block ] + if (char *ptr = return_char(1)) { + printf ("%s", ptr); + } +// CHECK: [ DW_TAG_auto_variable ] [ptr] [line [[@LINE+2]]] +// CHECK metadata !{i32 {{.*}}, metadata !{{.*}}, i32 [[@LINE+1]], {{.*}}} ; [ DW_TAG_lexical_block ] + if (char *ptr = return_char(2)) { + printf ("%s", ptr); + } + else printf ("%s", ptr); + + return 0; +} diff --git a/test/CodeGenCXX/debug-info-static-member.cpp b/test/CodeGenCXX/debug-info-static-member.cpp index 774f7b1..1ac235c 100644 --- a/test/CodeGenCXX/debug-info-static-member.cpp +++ b/test/CodeGenCXX/debug-info-static-member.cpp @@ -1,7 +1,9 @@ -// RUN: %clangxx -target x86_64-unknown-unknown -g -O0 %s -emit-llvm -S -o - | FileCheck %s +// RUN: %clangxx -target x86_64-unknown-unknown -g %s -emit-llvm -S -o - | FileCheck %s // PR14471 - +enum X { + Y +}; class C { static int a; @@ -13,6 +15,7 @@ public: static int c; const static int const_c = 18; int d; + static X x_a; }; int C::a = 4; @@ -30,12 +33,15 @@ int main() // why the definition of "a" comes before the declarations while // "b" and "c" come after. -// CHECK: metadata !"a", {{.*}} @_ZN1C1aE, metadata ![[DECL_A:[0-9]+]]} ; [ DW_TAG_variable ] [a] {{.*}} [def] -// CHECK: ![[DECL_A]] = metadata {{.*}} [ DW_TAG_member ] [a] [line {{.*}}, size 0, align 0, offset 0] [private] [static] +// CHECK: metadata !"_ZTS1X"} ; [ DW_TAG_enumeration_type ] [X] +// CHECK: metadata !"_ZTS1C"} ; [ DW_TAG_class_type ] [C] +// CHECK: ![[DECL_A:[0-9]+]] = metadata {{.*}} [ DW_TAG_member ] [a] [line {{.*}}, size 0, align 0, offset 0] [private] [static] // CHECK: metadata !"const_a", {{.*}}, i1 true} ; [ DW_TAG_member ] [const_a] [line {{.*}}, size 0, align 0, offset 0] [private] [static] // CHECK: ![[DECL_B:[0-9]+]] {{.*}} metadata !"b", {{.*}} [ DW_TAG_member ] [b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static] // CHECK: metadata !"const_b", {{.*}}, float 0x{{.*}}} ; [ DW_TAG_member ] [const_b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static] // CHECK: ![[DECL_C:[0-9]+]] {{.*}} metadata !"c", {{.*}} [ DW_TAG_member ] [c] [line {{.*}}, size 0, align 0, offset 0] [static] // CHECK: metadata !"const_c", {{.*}} [ DW_TAG_member ] [const_c] [line {{.*}}, size 0, align 0, offset 0] [static] +// CHECK: metadata !"x_a", {{.*}} [ DW_TAG_member ] [x_a] {{.*}} [static] +// CHECK: metadata !"a", {{.*}} @_ZN1C1aE, metadata ![[DECL_A]]} ; [ DW_TAG_variable ] [a] {{.*}} [def] // CHECK: metadata !"b", {{.*}} @_ZN1C1bE, metadata ![[DECL_B]]} ; [ DW_TAG_variable ] [b] {{.*}} [def] // CHECK: metadata !"c", {{.*}} @_ZN1C1cE, metadata ![[DECL_C]]} ; [ DW_TAG_variable ] [c] {{.*}} [def] diff --git a/test/CodeGenCXX/debug-info-template-limit.cpp b/test/CodeGenCXX/debug-info-template-limit.cpp index afad31b..c3e241e 100644 --- a/test/CodeGenCXX/debug-info-template-limit.cpp +++ b/test/CodeGenCXX/debug-info-template-limit.cpp @@ -1,8 +1,8 @@ // RUN: %clang -flimit-debug-info -emit-llvm -g -S %s -o - | FileCheck %s // Check that this pointer type is TC<int> -// CHECK: ![[LINE:[0-9]+]]} ; [ DW_TAG_pointer_type ]{{.*}}[from TC<int>] -// CHECK-NEXT: ![[LINE]] ={{.*}}"TC<int>" +// CHECK: ![[LINE:[0-9]+]] = {{.*}}"TC<int>", {{.*}} metadata !"_ZTS2TCIiE"} ; [ DW_TAG_class_type ] +// CHECK: metadata !"_ZTS2TCIiE"} ; [ DW_TAG_pointer_type ]{{.*}}[from _ZTS2TCIiE] template<typename T> class TC { diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp index 6be7f9b..9ac1bef 100644 --- a/test/CodeGenCXX/debug-info-template-member.cpp +++ b/test/CodeGenCXX/debug-info-template-member.cpp @@ -1,21 +1,78 @@ // RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s -class MyClass -{ -public: - int add2(int j) - { - return add<2>(j); - } -private: - template <int i> int add(int j) - { - return i + j; - } +struct MyClass { + template <int i> int add(int j) { + return i + j; + } + virtual void func() { + } }; -MyClass m; +int add2(int x) { + return MyClass().add<2>(x); +} + +inline int add3(int x) { + return MyClass().add<3>(x); // even though add<3> is ODR used, don't emit it since we don't codegen it +} + +// CHECK: [[FOO_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo] +// CHECK: [[FOO_MEM]] = metadata !{metadata [[FOO_FUNC:![0-9]*]]} +// CHECK: [[FOO_FUNC]] = {{.*}}, metadata !"_ZN3foo4funcEN5outerIS_E5innerE", i32 {{[0-9]*}}, metadata [[FOO_FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func] +// CHECK: [[FOO_FUNC_TYPE]] = {{.*}}, metadata [[FOO_FUNC_PARAMS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] +// CHECK: [[FOO_FUNC_PARAMS]] = metadata !{null, metadata !{{[0-9]*}}, metadata [[OUTER_FOO_INNER:![0-9]*]]} +// CHECK: [[OUTER_FOO_INNER]] = {{.*}} ; [ DW_TAG_structure_type ] [inner] + +// CHECK: metadata [[VIRT_MEM:![0-9]*]], i32 0, metadata !"_ZTS4virtI4elemE", metadata [[VIRT_TEMP_PARAM:![0-9]*]], metadata !"_ZTS4virtI4elemE"} ; [ DW_TAG_structure_type ] [virt<elem>] {{.*}} [def] +// CHECK: [[VIRT_TEMP_PARAM]] = metadata !{metadata [[VIRT_T:![0-9]*]]} +// CHECK: [[VIRT_T]] = {{.*}}, metadata !"T", metadata !"_ZTS4elem", {{.*}} ; [ DW_TAG_template_type_parameter ] + +// CHECK: [[C:![0-9]*]] = {{.*}}, metadata [[C_MEM:![0-9]*]], i32 0, metadata !"_ZTS7MyClass", null, metadata !"_ZTS7MyClass"} ; [ DW_TAG_structure_type ] [MyClass] +// CHECK: [[C_MEM]] = metadata !{metadata [[C_VPTR:![0-9]*]], metadata [[C_ADD:![0-9]*]], metadata [[C_FUNC:![0-9]*]], metadata [[C_CTOR:![0-9]*]]} +// CHECK: [[C_VPTR]] = {{.*}} ; [ DW_TAG_member ] [_vptr$MyClass] + +// CHECK: [[C_ADD]] = {{.*}} ; [ DW_TAG_subprogram ] [line 4] [add<2>] +// CHECK: [[C_FUNC]] = {{.*}} ; [ DW_TAG_subprogram ] [line 7] [func] +// CHECK: [[C_CTOR]] = {{.*}} ; [ DW_TAG_subprogram ] [line 0] [MyClass] + +// CHECK: [[ELEM:![0-9]*]] = {{.*}}, metadata [[ELEM_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTS4elem"} ; [ DW_TAG_structure_type ] [elem] {{.*}} [def] +// CHECK: [[ELEM_MEM]] = metadata !{metadata [[ELEM_X:![0-9]*]]} +// CHECK: [[ELEM_X]] = {{.*}} ; [ DW_TAG_member ] [x] {{.*}} [static] [from _ZTS4virtI4elemE] + +template<typename T> +struct outer { + struct inner { + int i; + }; +}; + +struct foo { + void func(outer<foo>::inner); +}; + +inline void func() { + // require 'foo' to be complete before the emission of 'inner' so that, when + // constructing the context chain for 'x' we emit the full definition of + // 'foo', which requires the definition of 'inner' again + foo f; +} + +outer<foo>::inner x; + +// CHECK: metadata [[OUTER_FOO_INNER]], i32 {{[0-9]*}}, i32 {{[0-9]*}}, %"struct.outer<foo>::inner"* @x, {{.*}} ; [ DW_TAG_variable ] [x] + +template <typename T> +struct virt { + T* values; + virtual ~virt(); +}; +struct elem { + static virt<elem> x; // ensure that completing 'elem' will require/completing 'virt<elem>' +}; +inline void f1() { + elem e; // ensure 'elem' is required to be complete when it is emitted as a template argument for 'virt<elem>' +}; +void f2() { + virt<elem> d; // emit 'virt<elem>' +} -// CHECK: metadata [[C_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_class_type ] [MyClass] -// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:![0-9]*]], metadata {{.*}}} -// CHECK: [[C_TEMP]] = {{.*}} ; [ DW_TAG_subprogram ] [line 11] [private] [add<2>] diff --git a/test/CodeGenCXX/debug-info-template-quals.cpp b/test/CodeGenCXX/debug-info-template-quals.cpp index 335c8ab..740f7bf 100644 --- a/test/CodeGenCXX/debug-info-template-quals.cpp +++ b/test/CodeGenCXX/debug-info-template-quals.cpp @@ -15,13 +15,13 @@ void foo (const char *c) { str.assign(c, str); } -// CHECK: [[P:.*]] = {{.*}}, metadata [[CON:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ] +// CHECK: [[BS:.*]] = {{.*}} ; [ DW_TAG_structure_type ] [basic_string<char>] [line 4, size 8, align 8, offset 0] [def] [from ] +// CHECK: [[TYPE:![0-9]*]] = metadata !{i32 {{.*}}, metadata [[ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] +// CHECK: [[ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata [[P:![0-9]*]], metadata [[R:.*]]} +// CHECK: [[P]] = {{.*}}, metadata [[CON:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ] // CHECK: [[CON]] = {{.*}}, metadata [[CH:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from char] // CHECK: [[CH]] = {{.*}} ; [ DW_TAG_base_type ] [char] [line 0, size 8, align 8, offset 0, enc DW_ATE_signed_char] -// CHECK: {{.*}} metadata [[TYPE:![0-9]*]], {{.*}}, metadata !{{[0-9]*}}, metadata !{{[0-9]*}}, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign] -// CHECK: [[TYPE]] = metadata !{i32 {{.*}}, metadata [[ARGS:.*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ] -// CHECK: [[ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata [[P]], metadata [[R:.*]]} -// CHECK: [[BS:.*]] = {{.*}} ; [ DW_TAG_structure_type ] [basic_string<char>] [line 4, size 8, align 8, offset 0] [from ] // CHECK: [[R]] = {{.*}}, metadata [[CON2:![0-9]*]]} ; [ DW_TAG_reference_type ] [line 0, size 0, align 0, offset 0] [from ] -// CHECK: [[CON2]] = {{.*}}, metadata [[BS]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from basic_string<char>] +// CHECK: [[CON2]] = {{.*}}, metadata !"_ZTS12basic_stringIcE"} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _ZTS12basic_stringIcE] +// CHECK: {{.*}} metadata [[TYPE]], {{.*}}, metadata !{{[0-9]*}}, metadata !{{[0-9]*}}, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign] diff --git a/test/CodeGenCXX/debug-info-template.cpp b/test/CodeGenCXX/debug-info-template.cpp index 9d52159..f58973b 100644 --- a/test/CodeGenCXX/debug-info-template.cpp +++ b/test/CodeGenCXX/debug-info-template.cpp @@ -1,46 +1,116 @@ -// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s +// RUN: %clang -S -emit-llvm -target x86_64-unknown_unknown -g %s -o - -std=c++11 | FileCheck %s -//CHECK: TC<int> -//CHECK: DW_TAG_template_type_parameter +// CHECK: {{.*}}, i1 false, metadata !"", i32 0, metadata !{{[0-9]]*}}, metadata [[RETAIN:![0-9]*]], {{.*}} ; [ DW_TAG_compile_unit ] +// CHECK: [[EMPTY:![0-9]*]] = metadata !{i32 0} +// CHECK: [[RETAIN]] = metadata !{metadata !{{[0-9]]*}}, metadata [[FOO:![0-9]*]], -template<typename T> -class TC { -public: - TC(const TC &) {} - TC() {} -}; -TC<int> tci; +// CHECK: [[TC:![0-9]*]] = {{.*}}, metadata [[TCARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [TC<unsigned int, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>] +// CHECK: [[TCARGS]] = metadata !{metadata [[TCARG1:![0-9]*]], metadata [[TCARG2:![0-9]*]], metadata [[TCARG3:![0-9]*]], metadata [[TCARG4:![0-9]*]], metadata [[TCARG5:![0-9]*]], metadata [[TCARG6:![0-9]*]], metadata [[TCARG7:![0-9]*]], metadata [[TCARG8:![0-9]*]]} +// +// We seem to be missing file/line/col info on template value parameters - +// metadata supports it but it's not populated. GCC doesn't emit it either, +// perhaps we should just drop it from the metadata. +// +// CHECK: [[TCARG1]] = {{.*}}metadata !"T", metadata [[UINT:![0-9]*]], {{.*}} ; [ DW_TAG_template_type_parameter ] +// CHECK: [[UINT:![0-9]*]] = {{.*}} ; [ DW_TAG_base_type ] [unsigned int] +// CHECK: [[TCARG2]] = {{.*}}metadata !"", metadata [[UINT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCARG3]] = {{.*}}metadata !"x", metadata [[INTPTR:![0-9]*]], i32* @glb, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[INTPTR]] = {{.*}}, metadata [[INT:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from int] +// CHECK: [[INT]] = {{.*}} ; [ DW_TAG_base_type ] [int] +// CHECK: [[TCARG4]] = {{.*}}metadata !"a", metadata [[MEMINTPTR:![0-9]*]], i64 8, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[MEMINTPTR]] = {{.*}}, metadata !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ] {{.*}}[from int] +// +// Currently Clang emits the pointer-to-member-function value, but LLVM doesn't +// use it (GCC doesn't emit a value for pointers to member functions either - so +// it's not clear what, if any, format would be acceptable to GDB) +// +// CHECK: [[TCARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR:![0-9]*]], { i64, i64 } { i64 ptrtoint (void (%struct.foo*)* @_ZN3foo1fEv to i64), i64 0 }, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[MEMFUNPTR]] = {{.*}}, metadata [[FTYPE:![0-9]*]], metadata !"_ZTS3foo"} ; [ DW_TAG_ptr_to_member_type ] +// CHECK: [[FTYPE]] = {{.*}}, metadata [[FARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] +// CHECK: [[FARGS]] = metadata !{null, metadata [[FARG1:![0-9]*]]} +// CHECK: [[FARG1]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS3foo] +// +// CHECK: [[TCARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR:![0-9]*]], void ()* @_Z4funcv, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[FUNPTR]] = {{.*}}, metadata [[FUNTYPE:![0-9]*]]} ; [ DW_TAG_pointer_type ] +// CHECK: [[FUNTYPE]] = {{.*}}, metadata [[FUNARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] +// CHECK: [[FUNARGS]] = metadata !{null} +// CHECK: [[TCARG7]] = {{.*}}metadata !"tmpl", null, metadata !"tmpl_impl", {{.*}} ; [ DW_TAG_GNU_template_template_param ] +// CHECK: [[TCARG8]] = {{.*}}metadata !"Is", null, metadata [[TCARG8_VALS:![0-9]*]], {{.*}} ; [ DW_TAG_GNU_template_parameter_pack ] +// CHECK: [[TCARG8_VALS]] = metadata !{metadata [[TCARG8_1:![0-9]*]], metadata [[TCARG8_2:![0-9]*]], metadata [[TCARG8_3:![0-9]*]]} +// CHECK: [[TCARG8_1]] = {{.*}}metadata !"", metadata [[INT]], i32 1, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCARG8_2]] = {{.*}}metadata !"", metadata [[INT]], i32 2, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCARG8_3]] = {{.*}}metadata !"", metadata [[INT]], i32 3, {{.*}} ; [ DW_TAG_template_value_parameter ] +// +// We could just emit a declaration of 'foo' here, rather than the entire +// definition (same goes for any time we emit a member (function or data) +// pointer type) +// CHECK: [[FOO]] = {{.*}}, metadata !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo] +// CHECK: metadata !"f", metadata !"_ZN3foo1fEv", i32 {{[0-9]*}}, metadata [[FTYPE:![0-9]*]], +// + + +// CHECK: [[TCNESTED:![0-9]*]] = metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"_ZTS2TCIjLj2EXadL_Z3glbEEXadL_ZN3foo1eEEEXadL_ZNS0_1fEvEEXadL_Z4funcvEE9tmpl_implJLi1ELi2ELi3EEE", {{.*}} ; [ DW_TAG_structure_type ] [nested] +// CHECK: [[TCNT:![0-9]*]] = {{.*}}, metadata [[TCNARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [TC<int, -3, nullptr, nullptr, nullptr, nullptr, tmpl_impl>] +// CHECK: [[TCNARGS]] = metadata !{metadata [[TCNARG1:![0-9]*]], metadata [[TCNARG2:![0-9]*]], metadata [[TCNARG3:![0-9]*]], metadata [[TCNARG4:![0-9]*]], metadata [[TCNARG5:![0-9]*]], metadata [[TCNARG6:![0-9]*]], metadata [[TCARG7:![0-9]*]], metadata [[TCNARG8:![0-9]*]]} +// CHECK: [[TCNARG1]] = {{.*}}metadata !"T", metadata [[INT]], {{.*}} ; [ DW_TAG_template_type_parameter ] +// CHECK: [[TCNARG2]] = {{.*}}metadata !"", metadata [[INT]], i32 -3, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCNARG3]] = {{.*}}metadata !"x", metadata [[INTPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ] + +// The interesting null pointer: -1 for member data pointers (since they are +// just an offset in an object, they can be zero and non-null for the first +// member) + +// CHECK: [[TCNARG4]] = {{.*}}metadata !"a", metadata [[MEMINTPTR]], i64 -1, {{.*}} ; [ DW_TAG_template_value_parameter ] +// +// In some future iteration we could possibly emit the value of a null member +// function pointer as '{ i64, i64 } zeroinitializer' as it may be handled +// naturally from the LLVM CodeGen side once we decide how to handle non-null +// member function pointers. For now, it's simpler just to emit the 'i8 0'. +// +// CHECK: [[TCNARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCNARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[TCNARG8]] = {{.*}}metadata !"Is", null, metadata [[EMPTY]], {{.*}} ; [ DW_TAG_GNU_template_parameter_pack ] + +// CHECK: metadata [[PTOARGS:![0-9]*]], metadata !"{{.*}}"} ; [ DW_TAG_structure_type ] [PaddingAtEndTemplate<&PaddedObj>] +// CHECK: [[PTOARGS]] = metadata !{metadata [[PTOARG1:![0-9]*]]} +// CHECK: [[PTOARG1]] = {{.*}}metadata !"", metadata [[CONST_PADDINGATEND_PTR:![0-9]*]], { i32, i8, [3 x i8] }* @PaddedObj, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[CONST_PADDINGATEND_PTR]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from _ZTS12PaddingAtEnd] -//CHECK: TU<2> -//CHECK: DW_TAG_template_value_parameter -template<unsigned > -class TU { - int b; +// CHECK: metadata [[TCNESTED]], i32 0, i32 1, %"struct.TC<unsigned int, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>::nested"* @tci, null} ; [ DW_TAG_variable ] [tci] + +// CHECK: metadata [[TCNT:![0-9]*]], i32 0, i32 1, %struct.TC* @tcn, null} ; [ DW_TAG_variable ] [tcn] +struct foo { + char pad[8]; // make the member pointer to 'e' a bit more interesting (nonzero) + int e; + void f(); +}; + +template<typename T, T, int *x, int foo::*a, void (foo::*b)(), void (*f)(), template<typename> class tmpl, int ...Is> +struct TC { + struct nested { + }; }; -TU<2> u2; +int glb; +void func(); -// PR9600 -template<typename T> class vector {}; -class Foo; -typedef vector<Foo*> FooVector[3]; -struct Test { - virtual void foo(FooVector *); +template<typename> +struct tmpl_impl { }; -static Test test; -// PR9608 -template <int i> struct TheTemplate { - struct Empty2 {}; - typedef const Empty2 DependentType[i]; - TheTemplate() {} -}; +TC<unsigned, 2, &glb, &foo::e, &foo::f, &func, tmpl_impl, 1, 2, 3>::nested tci; +TC<int, -3, nullptr, nullptr, nullptr, nullptr, tmpl_impl> tcn; -class TheTemplateTest : public TheTemplate<42> { - TheTemplateTest(); - void method(const TheTemplate<42>::DependentType *) {} -}; +struct PaddingAtEnd { + int i; + char c; +}; + +PaddingAtEnd PaddedObj = {}; -TheTemplateTest::TheTemplateTest() : TheTemplate<42>() {} +template <const PaddingAtEnd *> +struct PaddingAtEndTemplate { +}; +PaddingAtEndTemplate<&PaddedObj> PaddedTemplateObj; diff --git a/test/CodeGenCXX/debug-info-thunk.cpp b/test/CodeGenCXX/debug-info-thunk.cpp index 394ebd8..2a50895 100644 --- a/test/CodeGenCXX/debug-info-thunk.cpp +++ b/test/CodeGenCXX/debug-info-thunk.cpp @@ -14,4 +14,4 @@ struct C : A, B { void C::f() { } -// CHECK: [ DW_TAG_subprogram ] [line 15] [def] [_ZThn{{4|8}}_N1C1fEv] +// CHECK: metadata !"_ZThn{{4|8}}_N1C1fEv", i32 15, {{.*}} ; [ DW_TAG_subprogram ] [line 15] [def]{{$}} diff --git a/test/CodeGenCXX/debug-info-union-template.cpp b/test/CodeGenCXX/debug-info-union-template.cpp index f5e6e14..570520d 100644 --- a/test/CodeGenCXX/debug-info-union-template.cpp +++ b/test/CodeGenCXX/debug-info-union-template.cpp @@ -10,6 +10,6 @@ namespace PR15637 { Value<float> f; } -// CHECK: {{.*}}, metadata !"Value<float>", {{.*}}, null, metadata [[TTPARAM:.*]]} ; [ DW_TAG_union_type ] [Value<float>] +// CHECK: {{.*}}, metadata !"Value<float>", {{.*}}, null, metadata [[TTPARAM:.*]], metadata !"_ZTSN7PR156375ValueIfEE"} ; [ DW_TAG_union_type ] [Value<float>] // CHECK: [[TTPARAM]] = metadata !{metadata [[PARAMS:.*]]} // CHECK: [[PARAMS]] = metadata !{{{.*}}metadata !"T",{{.*}}} ; [ DW_TAG_template_type_parameter ] diff --git a/test/CodeGenCXX/debug-info-uuid.cpp b/test/CodeGenCXX/debug-info-uuid.cpp new file mode 100644 index 0000000..a57e2f0 --- /dev/null +++ b/test/CodeGenCXX/debug-info-uuid.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-pc-win32 -cxx-abi microsoft -g %s -o - -std=c++11 | FileCheck %s +// RUN: not %clang_cc1 -emit-llvm -fms-extensions -triple=x86_64-unknown-unknown -g %s -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=CHECK-ITANIUM + +// CHECK: metadata [[TGIARGS:![0-9]*]], null} ; [ DW_TAG_structure_type ] [tmpl_guid<&__uuidof(uuid)>] +// CHECK: [[TGIARGS]] = metadata !{metadata [[TGIARG1:![0-9]*]]} +// CHECK: [[TGIARG1]] = {{.*}}metadata !"", metadata [[CONST_GUID_PTR:![0-9]*]], { i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab, {{.*}} ; [ DW_TAG_template_value_parameter ] +// CHECK: [[CONST_GUID_PTR]] = {{.*}}, metadata [[CONST_GUID:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ] +// CHECK: [[CONST_GUID]] = {{.*}}, metadata [[GUID:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from _GUID] +// CHECK: [[GUID]] = {{.*}} ; [ DW_TAG_structure_type ] [_GUID] + +// CHECK-ITANIUM: error: cannot yet mangle expression type CXXUuidofExpr + +struct _GUID; +template <const _GUID *> +struct tmpl_guid { +}; + +struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ab}")) uuid; +tmpl_guid<&__uuidof(uuid)> tgi; diff --git a/test/CodeGenCXX/debug-info-zero-length-arrays.cpp b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp index fb47022..1017965 100644 --- a/test/CodeGenCXX/debug-info-zero-length-arrays.cpp +++ b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp @@ -7,6 +7,6 @@ class A { A a; // CHECK: metadata [[ARRAY_TYPE:![0-9]*]]} ; [ DW_TAG_member ] [x] -// CHECK: metadata [[ELEM_TYPE:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_array_type ] [line 0, size 0, align 32, offset 0] [from int] +// CHECK: metadata [[ELEM_TYPE:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 32, offset 0] [from int] // CHECK: [[ELEM_TYPE]] = metadata !{metadata [[SUBRANGE:.*]]} // CHECK: [[SUBRANGE]] = metadata !{i32 786465, i64 0, i64 -1} ; [ DW_TAG_subrange_type ] [unbounded] diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp index 33b5278..93a4fe3 100644 --- a/test/CodeGenCXX/debug-info.cpp +++ b/test/CodeGenCXX/debug-info.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm-only -g %s +// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -g %s -o - | FileCheck %s template<typename T> struct Identity { typedef T Type; }; @@ -67,3 +67,54 @@ class Cls { Cls obj; } + +namespace pr14763 { +struct foo { + foo(const foo&); +}; + +foo func(foo f) { + return f; // reference 'f' for now because otherwise we hit another bug +} + +// CHECK: [[FOO:![0-9]*]] = metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata [[PR14763:![0-9]*]], {{.*}} ; [ DW_TAG_structure_type ] [foo] +// CHECK: [[PR14763]] = {{.*}} ; [ DW_TAG_namespace ] [pr14763] +// CHECK: [[INCTYPE:![0-9]*]] = {{.*}} ; [ DW_TAG_structure_type ] [incomplete]{{.*}} [decl] +// CHECK: metadata [[A_MEM:![0-9]*]], i32 0, null, null, metadata !"_ZTSN7pr162141aE"} ; [ DW_TAG_structure_type ] [a] +// CHECK: [[A_MEM]] = metadata !{metadata [[A_I:![0-9]*]]} +// CHECK: [[A_I]] = {{.*}} ; [ DW_TAG_member ] [i] {{.*}} [from int] +// CHECK: ; [ DW_TAG_structure_type ] [b] {{.*}}[decl] + +// CHECK: [[FUNC:![0-9]*]] = {{.*}} metadata !"_ZN7pr147634funcENS_3fooE", i32 {{[0-9]*}}, metadata [[FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func] +} + +namespace pr9608 { // also pr9600 +struct incomplete; +incomplete (*x)[3]; +// CHECK: metadata [[INCARRAYPTR:![0-9]*]], i32 0, i32 1, [3 x i8]** @_ZN6pr96081xE, null} ; [ DW_TAG_variable ] [x] +// CHECK: [[INCARRAYPTR]] = {{.*}}metadata [[INCARRAY:![0-9]*]]} ; [ DW_TAG_pointer_type ] +// CHECK: [[INCARRAY]] = {{.*}}metadata !"_ZTSN6pr960810incompleteE", metadata {{![0-9]*}}, i32 0, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 0, offset 0] [from _ZTSN6pr960810incompleteE] +} + +// For some reason the argument for PR14763 ended up all the way down here +// CHECK: = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], {{.*}}, metadata [[FOO]], i32 8192, i32 0} ; [ DW_TAG_arg_variable ] [f] + +namespace pr16214 { +struct a { + int i; +}; + +typedef a at; + +struct b { +}; + +typedef b bt; + +void func() { + at a_inst; + bt *b_ptr_inst; + const bt *b_cnst_ptr_inst; +} + +} diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp index 39c9a44..0b087360 100644 --- a/test/CodeGenCXX/debug-lambda-expressions.cpp +++ b/test/CodeGenCXX/debug-lambda-expressions.cpp @@ -12,7 +12,7 @@ int b(int x) { return [x]{return x;}(); } int c(int x) { return [&x]{return x;}(); } struct D { D(); D(const D&); int x; }; -int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } +int d(int x) { D y[10]; return [x,y] { return y[x].x; }(); } // Randomness for file. -- 6 // CHECK: [[FILE:.*]] = {{.*}} [ DW_TAG_file_type ] [{{.*}}debug-lambda-expressions.cpp] @@ -30,42 +30,38 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } // CHECK: [[D_FUNC:.*]] = {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE:.*]]] [def] [d] // Back to D. -- 24 -// CHECK: [[LAM_D:.*]] = {{.*}}, metadata [[D_FUNC]], {{.*}}, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[D_LINE]], -// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]], metadata [[DES_LAM_D:.*]]} +// CHECK: [[LAM_D:.*]] = {{.*}}, metadata [[D_FUNC]], {{.*}}, metadata [[LAM_D_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[D_LINE]], +// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]]} // CHECK: [[CAP_D_X]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [x] [line [[D_LINE]], // CHECK: [[CAP_D_Y]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [y] [line [[D_LINE]], // CHECK: [[CON_LAM_D]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [operator()] -// CHECK: [[DES_LAM_D]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [~] // Back to C. -- 55 -// CHECK: [[LAM_C:.*]] = {{.*}}, metadata [[C_FUNC]], {{.*}}, metadata [[LAM_C_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[C_LINE]], -// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]], metadata [[DES_LAM_C:.*]]} +// CHECK: [[LAM_C:.*]] = {{.*}}, metadata [[C_FUNC]], {{.*}}, metadata [[LAM_C_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[C_LINE]], +// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]]} // Ignoring the member type for now. // CHECK: [[CAP_C]] = {{.*}}, metadata [[LAM_C]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[C_LINE]], // CHECK: [[CON_LAM_C]] = {{.*}}, metadata [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [operator()] -// CHECK: [[DES_LAM_C]] = {{.*}}, metadata [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [~] // Back to B. -- 67 -// CHECK: [[LAM_B:.*]] = {{.*}}, metadata [[B_FUNC]], {{.*}}, metadata [[LAM_B_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[B_LINE]], -// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]], metadata [[DES_LAM_B:.*]]} +// CHECK: [[LAM_B:.*]] = {{.*}}, metadata [[B_FUNC]], {{.*}}, metadata [[LAM_B_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[B_LINE]], +// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]]} // CHECK: [[CAP_B]] = {{.*}}, metadata [[LAM_B]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[B_LINE]], // CHECK: [[CON_LAM_B]] = {{.*}}, metadata [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [operator()] -// CHECK: [[DES_LAM_B]] = {{.*}}, metadata [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [~] // Back to A. -- 78 -// CHECK: [[LAM_A:.*]] = {{.*}}, metadata [[A_FUNC]], {{.*}}, metadata [[LAM_A_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[A_LINE]], -// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]], metadata [[DES_LAM_A:.*]]} +// CHECK: [[LAM_A:.*]] = {{.*}}, metadata [[A_FUNC]], {{.*}}, metadata [[LAM_A_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[A_LINE]], +// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]]} // CHECK: [[CON_LAM_A]] = {{.*}}, metadata [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [operator()] -// CHECK: [[DES_LAM_A]] = {{.*}}, metadata [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [~] // CVAR: // CHECK: {{.*}} metadata [[CVAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [cvar] [line [[CVAR_LINE:[0-9]*]]] -// CHECK: [[CVAR_T]] = {{.*}}, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[CVAR_LINE]], -// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}} +// CHECK: [[CVAR_T]] = {{.*}}, metadata ![[CVAR_ARGS:.*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[CVAR_LINE]], +// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}} // VAR: // CHECK: {{.*}} metadata [[VAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [var] [line [[VAR_LINE:[0-9]*]]] -// CHECK: [[VAR_T]] = {{.*}}, metadata [[VAR_ARGS:![0-9]*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[VAR_LINE]], -// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}} +// CHECK: [[VAR_T]] = {{.*}}, metadata [[VAR_ARGS:![0-9]*]], i32 0, null, null, null} ; [ DW_TAG_class_type ] [line [[VAR_LINE]], +// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}} diff --git a/test/CodeGenCXX/decl-ref-init.cpp b/test/CodeGenCXX/decl-ref-init.cpp index a066fbb..1a82ee2 100644 --- a/test/CodeGenCXX/decl-ref-init.cpp +++ b/test/CodeGenCXX/decl-ref-init.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s struct A {}; diff --git a/test/CodeGenCXX/default-arg-temps.cpp b/test/CodeGenCXX/default-arg-temps.cpp index 3d741d5..4375600 100644 --- a/test/CodeGenCXX/default-arg-temps.cpp +++ b/test/CodeGenCXX/default-arg-temps.cpp @@ -13,7 +13,7 @@ public: X(const X&, const T& t = T()); }; -// CHECK: define void @_Z1gv() +// CHECK-LABEL: define void @_Z1gv() void g() { // CHECK: call void @_ZN1TC1Ev([[T:%.*]]* [[AGG1:%.*]]) // CHECK-NEXT: call void @_Z1fRK1T([[T]]* [[AGG1]]) @@ -41,7 +41,7 @@ void g() { class obj{ int a; float b; double d; }; -// CHECK: define void @_Z1hv() +// CHECK-LABEL: define void @_Z1hv() void h() { // CHECK: call void @llvm.memset.p0i8.i64( obj o = obj(); @@ -61,7 +61,7 @@ namespace test1 { C c; A a; - // CHECK: define linkonce_odr void @_ZN5test11DC2Ev(%"struct.test1::D"* %this) unnamed_addr + // CHECK-LABEL: define linkonce_odr void @_ZN5test11DC2Ev(%"struct.test1::D"* %this) unnamed_addr // CHECK: call void @_ZN5test11BC1Ev( // CHECK-NEXT: call void @_ZN5test11CC1ERKNS_1BE( // CHECK-NEXT: call void @_ZN5test11BD1Ev( diff --git a/test/CodeGenCXX/default-arguments.cpp b/test/CodeGenCXX/default-arguments.cpp index 206d4d6..83cae3a 100644 --- a/test/CodeGenCXX/default-arguments.cpp +++ b/test/CodeGenCXX/default-arguments.cpp @@ -26,7 +26,7 @@ struct B { B(const A1& = A1(), const A2& = A2()); }; -// CHECK: define void @_Z2f1v() +// CHECK-LABEL: define void @_Z2f1v() void f1() { // CHECK: call void @_ZN2A1C1Ev( @@ -42,10 +42,10 @@ struct C { C(); }; -// CHECK: define void @_ZN1CC1Ev(%struct.C* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1CC1Ev(%struct.C* %this) unnamed_addr // CHECK: call void @_ZN1CC2Ev( -// CHECK: define void @_ZN1CC2Ev(%struct.C* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1CC2Ev(%struct.C* %this) unnamed_addr // CHECK: call void @_ZN2A1C1Ev( // CHECK: call void @_ZN2A2C1Ev( // CHECK: call void @_ZN1BC1ERK2A1RK2A2( @@ -53,7 +53,7 @@ struct C { // CHECK: call void @_ZN2A1D1Ev C::C() { } -// CHECK: define void @_Z2f3v() +// CHECK-LABEL: define void @_Z2f3v() void f3() { // CHECK: call void @_ZN2A1C1Ev( // CHECK: call void @_ZN2A2C1Ev( diff --git a/test/CodeGenCXX/default-constructor-for-members.cpp b/test/CodeGenCXX/default-constructor-for-members.cpp index 714811f..6065b49 100644 --- a/test/CodeGenCXX/default-constructor-for-members.cpp +++ b/test/CodeGenCXX/default-constructor-for-members.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/default-constructor-template-member.cpp b/test/CodeGenCXX/default-constructor-template-member.cpp index 0dd64df..2156964 100644 --- a/test/CodeGenCXX/default-constructor-template-member.cpp +++ b/test/CodeGenCXX/default-constructor-template-member.cpp @@ -5,6 +5,7 @@ struct B { A<int> x; }; void a() { B b; } + // CHECK: call {{.*}} @_ZN1BC1Ev -// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* {{.*}}%this) unnamed_addr // CHECK: call {{.*}} @_ZN1AIiEC1Ev diff --git a/test/CodeGenCXX/deferred-global-init.cpp b/test/CodeGenCXX/deferred-global-init.cpp index 24c8c67..deb458f 100644 --- a/test/CodeGenCXX/deferred-global-init.cpp +++ b/test/CodeGenCXX/deferred-global-init.cpp @@ -7,10 +7,10 @@ void* bar() { return a; } // CHECK: @_ZL1a = internal global i8* null -// CHECK: define internal void @__cxx_global_var_init +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: load i8** @foo // CHECK: ret void -// CHECK: define internal void @_GLOBAL__I_a +// CHECK-LABEL: define internal void @_GLOBAL__I_a // CHECK: call void @__cxx_global_var_init() // CHECK: ret void diff --git a/test/CodeGenCXX/delayed-template-parsing.cpp b/test/CodeGenCXX/delayed-template-parsing.cpp new file mode 100644 index 0000000..fa177d4 --- /dev/null +++ b/test/CodeGenCXX/delayed-template-parsing.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s + +namespace ClassScopeSpecialization { + struct Type { + template <int i> + void Foo() {} + template <> + void Foo<0>() {} + }; + + void call() { + Type T; +// CHECK: call {{.*}} @"\01??$Foo@$0A@@Type@ClassScopeSpecialization@@QAEXXZ" +// X64: call {{.*}} @"\01??$Foo@$0A@@Type@ClassScopeSpecialization@@QEAAXXZ" + T.Foo<0>(); + } +} diff --git a/test/CodeGenCXX/delete-two-arg.cpp b/test/CodeGenCXX/delete-two-arg.cpp index b82e9ba..f8e6bff 100644 --- a/test/CodeGenCXX/delete-two-arg.cpp +++ b/test/CodeGenCXX/delete-two-arg.cpp @@ -1,11 +1,11 @@ -// RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -o - -emit-llvm -verify | FileCheck %s +// RUN: not %clang_cc1 -triple i686-pc-linux-gnu %s -o - -emit-llvm -verify | FileCheck %s typedef __typeof(sizeof(int)) size_t; namespace test1 { struct A { void operator delete(void*,size_t); int x; }; - // CHECK: define void @_ZN5test11aEPNS_1AE( + // CHECK-LABEL: define void @_ZN5test11aEPNS_1AE( void a(A *x) { // CHECK: load // CHECK-NEXT: icmp eq {{.*}}, null @@ -35,7 +35,7 @@ namespace test2 { return ::new A[10]; } - // CHECK: define void @_ZN5test24testEPNS_1AE( + // CHECK-LABEL: define void @_ZN5test24testEPNS_1AE( void test(A *p) { // CHECK: [[P:%.*]] = alloca [[A]]*, align 4 // CHECK-NEXT: store [[A]]* {{%.*}}, [[A]]** [[P]], align 4 @@ -60,7 +60,7 @@ namespace test3 { }; struct B : A {}; - // CHECK: define void @_ZN5test34testEv() + // CHECK-LABEL: define void @_ZN5test34testEv() void test() { // CHECK: call noalias i8* @_Znaj(i32 24) // CHECK-NEXT: bitcast diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp index 1299b29..cdd5a89 100644 --- a/test/CodeGenCXX/delete.cpp +++ b/test/CodeGenCXX/delete.cpp @@ -19,7 +19,7 @@ struct T { int a; }; -// CHECK: define void @_Z2t4P1T +// CHECK-LABEL: define void @_Z2t4P1T void t4(T *t) { // CHECK: call void @_ZN1TD1Ev // CHECK-NEXT: bitcast @@ -46,7 +46,7 @@ namespace test0 { ~A() {} }; - // CHECK: define void @_ZN5test04testEPNS_1AE( + // CHECK-LABEL: define void @_ZN5test04testEPNS_1AE( void test(A *a) { // CHECK: call void @_ZN5test01AD1Ev // CHECK-NEXT: bitcast @@ -54,8 +54,8 @@ namespace test0 { delete a; } - // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%"struct.test0::A"* %this) unnamed_addr - // CHECK: define linkonce_odr void @_ZN5test01AdlEPv + // CHECK-LABEL: define linkonce_odr void @_ZN5test01AD1Ev(%"struct.test0::A"* %this) unnamed_addr + // CHECK-LABEL: define linkonce_odr void @_ZN5test01AdlEPv } namespace test1 { @@ -64,7 +64,7 @@ namespace test1 { ~A(); }; - // CHECK: define void @_ZN5test14testEPA10_A20_NS_1AE( + // CHECK-LABEL: define void @_ZN5test14testEPA10_A20_NS_1AE( void test(A (*arr)[10][20]) { delete [] arr; // CHECK: icmp eq [10 x [20 x [[A:%.*]]]]* [[PTR:%.*]], null @@ -88,7 +88,7 @@ namespace test1 { } namespace test2 { - // CHECK: define void @_ZN5test21fEPb + // CHECK-LABEL: define void @_ZN5test21fEPb void f(bool *b) { // CHECK: call void @_ZdlPv(i8* delete b; @@ -111,7 +111,7 @@ namespace test4 { void operator delete (void *); }; - // CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE + // CHECK-LABEL: define void @_ZN5test421global_delete_virtualEPNS_1XE void global_delete_virtual(X *xp) { // Load the offset-to-top from the vtable and apply it. // This has to be done first because the dtor can mess it up. @@ -136,7 +136,7 @@ namespace test4 { namespace test5 { struct Incomplete; - // CHECK: define void @_ZN5test523array_delete_incompleteEPNS_10IncompleteES1_ + // CHECK-LABEL: define void @_ZN5test523array_delete_incompleteEPNS_10IncompleteES1_ void array_delete_incomplete(Incomplete *p1, Incomplete *p2) { // CHECK: call void @_ZdlPv delete p1; @@ -145,4 +145,4 @@ namespace test5 { } } -// CHECK: attributes [[NUW]] = { nounwind{{.*}} } +// CHECK: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}} diff --git a/test/CodeGenCXX/derived-to-base-conv.cpp b/test/CodeGenCXX/derived-to-base-conv.cpp index 9b15c68..675c50c 100644 --- a/test/CodeGenCXX/derived-to-base-conv.cpp +++ b/test/CodeGenCXX/derived-to-base-conv.cpp @@ -31,7 +31,7 @@ struct X { void test0_helper(A); void test0(X x) { test0_helper(x); - // CHECK: define void @_Z5test01X( + // CHECK-LABEL: define void @_Z5test01X( // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align // CHECK-NEXT: [[T0:%.*]] = call [[B:%.*]]* @_ZN1XcvR1BEv( // CHECK-NEXT: [[T1:%.*]] = bitcast [[B]]* [[T0]] to [[A]]* @@ -60,7 +60,7 @@ struct Derived : Base { void test1_helper(Base); void test1(Derived bb) { - // CHECK: define void @_Z5test17Derived( + // CHECK-LABEL: define void @_Z5test17Derived( // CHECK-NOT: call {{.*}} @_ZN4BasecvR7DerivedEv( // CHECK: call void @_ZN4BaseC1ERKS_( // CHECK-NOT: call {{.*}} @_ZN4BasecvR7DerivedEv( @@ -75,7 +75,7 @@ class Test2a {}; class Test2b final : public virtual Test2a {}; void test2(Test2b &x) { Test2a &y = x; - // CHECK: define void @_Z5test2R6Test2b( + // CHECK-LABEL: define void @_Z5test2R6Test2b( // CHECK: [[X:%.*]] = alloca [[B:%.*]]*, align 8 // CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]]*, align 8 // CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]], align 8 diff --git a/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp index 0e15302..f2ecfc1 100644 --- a/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp +++ b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp @@ -9,7 +9,7 @@ struct D final : virtual C { virtual void f(); }; -// CHECK: define %struct.B* @_Z1fR1D +// CHECK-LABEL: define %struct.B* @_Z1fR1D B &f(D &d) { // CHECK-NOT: load i8** return d; diff --git a/test/CodeGenCXX/destructor-exception-spec.cpp b/test/CodeGenCXX/destructor-exception-spec.cpp index 579daef..e111ba0 100644 --- a/test/CodeGenCXX/destructor-exception-spec.cpp +++ b/test/CodeGenCXX/destructor-exception-spec.cpp @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -emit-llvm-only %s -std=c++11 +// RUN: %clang_cc1 -emit-llvm-only -fno-use-cxa-atexit %s -std=c++11 +// RUN: %clang_cc1 -cxx-abi microsoft -fno-rtti -emit-llvm-only %s -std=c++11 // PR13479: don't crash with -fno-exceptions. namespace { diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index 7dc188b..799cca2 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -1,14 +1,10 @@ -// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions -O1 -disable-llvm-optzns | FileCheck %s -// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev -// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev -// CHECK: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev -// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev -// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev - -// CHECK: @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev -// CHECK: @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev -// CHECK: @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev +// CHECK-DAG: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev +// CHECK-DAG: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK-DAG: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK-DAG: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK-DAG: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev struct A { int a; @@ -40,13 +36,13 @@ namespace PR7526 { struct allocator_derived : allocator { }; - // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZN6PR75263fooEv() + // CHECK: call void {{.*}} @_ZN6PR75269allocatorD2Ev + + // CHECK-LABEL: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr // CHECK: call void @__cxa_call_unexpected allocator::~allocator() throw() { foo(); } - // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR7526::allocator_derived"* %this) unnamed_addr - // CHECK-NOT: call void @__cxa_call_unexpected - // CHECK: } void foo() { allocator_derived ad; } @@ -93,7 +89,7 @@ namespace test0 { // complete destructor alias tested above -// CHECK: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr // CHECK: invoke void @_ZN5test06MemberD1Ev // CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] // CHECK: invoke void @_ZN5test04BaseD2Ev @@ -106,7 +102,7 @@ namespace test0 { B::~B() try { } catch (int i) {} // It will suppress the delegation optimization here, though. -// CHECK: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr // CHECK: invoke void @_ZN5test06MemberD1Ev // CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] // CHECK: invoke void @_ZN5test04BaseD2Ev @@ -114,7 +110,7 @@ namespace test0 { // CHECK: invoke void @_ZN5test05VBaseD2Ev // CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]] -// CHECK: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr +// CHECK-LABEL: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr // CHECK: invoke void @_ZN5test06MemberD1Ev // CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] // CHECK: invoke void @_ZN5test04BaseD2Ev @@ -142,24 +138,24 @@ namespace test1 { O::~O() {} // alias tested above struct P : NonEmpty, A { ~P(); }; - P::~P() {} // CHECK: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr + P::~P() {} // CHECK-LABEL: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr struct Q : A, B { ~Q(); }; - Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr + Q::~Q() {} // CHECK-LABEL: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr struct R : A { ~R(); }; - R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr + R::~R() { A a; } // CHECK-LABEL: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr struct S : A { ~S(); int x; }; S::~S() {} // alias tested above struct T : A { ~T(); B x; }; - T::~T() {} // CHECK: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr + T::~T() {} // CHECK-LABEL: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr // The VTT parameter prevents this. We could still make this work // for calling conventions that are safe against extra parameters. struct U : A, virtual B { ~U(); }; - U::~U() {} // CHECK: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr + U::~U() {} // CHECK-LABEL: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr } // PR6471 @@ -168,7 +164,7 @@ namespace test2 { struct B : A { ~B(); }; B::~B() {} - // CHECK: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr // CHECK: call void @_ZN5test21AD2Ev } @@ -184,18 +180,12 @@ namespace test3 { void test() { new D; // Force emission of D's vtable } - - // Checked at top of file: - // @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev - - // More checks at end of file. - } namespace test4 { struct A { ~A(); }; - // CHECK: define void @_ZN5test43fooEv() + // CHECK-LABEL: define void @_ZN5test43fooEv() // CHECK: call void @_ZN5test41AD1Ev // CHECK: ret void void foo() { @@ -208,7 +198,7 @@ namespace test4 { return; } - // CHECK: define void @_ZN5test43barEi( + // CHECK-LABEL: define void @_ZN5test43barEi( // CHECK: [[X:%.*]] = alloca i32 // CHECK-NEXT: [[A:%.*]] = alloca // CHECK: br label @@ -233,7 +223,7 @@ namespace test4 { namespace test5 { struct A { ~A(); }; - // CHECK: define void @_ZN5test53fooEv() + // CHECK-LABEL: define void @_ZN5test53fooEv() // CHECK: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align // CHECK-NEXT: [[EXN:%.*]] = alloca i8* // CHECK-NEXT: [[SEL:%.*]] = alloca i32 @@ -272,7 +262,7 @@ namespace test6 { }; C::C() { opaque(); } - // CHECK: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr // CHECK: call void @_ZN5test61BILj2EEC2Ev // CHECK: invoke void @_ZN5test61BILj3EEC2Ev // CHECK: invoke void @_ZN5test61BILj0EEC2Ev @@ -282,7 +272,7 @@ namespace test6 { // FIXME: way too much EH cleanup code follows C::~C() { opaque(); } - // CHECK: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr // CHECK: invoke void @_ZN5test61CD2Ev // CHECK: invoke void @_ZN5test61BILj3EED2Ev // CHECK: call void @_ZN5test61BILj2EED2Ev @@ -290,7 +280,7 @@ namespace test6 { // CHECK: invoke void @_ZN5test61BILj3EED2Ev // CHECK: invoke void @_ZN5test61BILj2EED2Ev - // CHECK: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr + // CHECK-LABEL: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr // CHECK: invoke void @_ZN5test66opaqueEv // CHECK: invoke void @_ZN5test61AD1Ev // CHECK: invoke void @_ZN5test61AD1Ev @@ -318,7 +308,7 @@ namespace test7 { }; // Verify that this doesn't get emitted as an alias - // CHECK: define void @_ZN5test71BD2Ev( + // CHECK-LABEL: define void @_ZN5test71BD2Ev( // CHECK: invoke void @_ZN5test71DD1Ev( // CHECK: call void @_ZN5test71AD2Ev( B::~B() {} @@ -338,7 +328,7 @@ namespace test8 { l: die(); } - // CHECK: define void @_ZN5test84testEv() + // CHECK-LABEL: define void @_ZN5test84testEv() // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 1 // CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]], align 1 // CHECK: call void @_ZN5test81AC1Ev([[A]]* [[X]]) @@ -366,10 +356,26 @@ namespace test9 { // CHECK: call void @_ZN5test92f2Ev() } +namespace test10 { + // We used to crash trying to replace _ZN6test106OptionD1Ev with + // _ZN6test106OptionD2Ev twice. + struct Option { + virtual ~Option() {} + }; + template <class DataType> class opt : public Option {}; + template class opt<int>; + // CHECK-LABEL: define zeroext i1 @_ZN6test1016handleOccurrenceEv( + bool handleOccurrence() { + // CHECK: call void @_ZN6test106OptionD2Ev( + Option x; + return true; + } +} + // Checks from test3: - // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr - // CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev( + // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr + // CHECK: invoke void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev // CHECK: call void @_ZdlPv({{.*}}) [[NUW:#[0-9]+]] // CHECK: ret void // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) @@ -377,21 +383,22 @@ namespace test9 { // CHECK: call void @_ZdlPv({{.*}}) [[NUW]] // CHECK: resume { i8*, i32 } - // Checked at top of file: - // @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev - // @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev - - // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev( + // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev( // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 - // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev( + // CHECK: call void {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev // CHECK: ret void - // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev( + // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev( // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 // CHECK: call void @_ZN5test312_GLOBAL__N_11DD0Ev( // CHECK: ret void - // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr + // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11CD2Ev( + // CHECK: ret void + + // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr // CHECK: invoke void @_ZN5test31BD2Ev( // CHECK: call void @_ZN5test31AD2Ev( // CHECK: ret void @@ -399,8 +406,8 @@ namespace test9 { // CHECK: declare void @_ZN5test31BD2Ev( // CHECK: declare void @_ZN5test31AD2Ev( - // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr - // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev( + // CHECK-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr + // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev( // CHECK: call void @_ZdlPv({{.*}}) [[NUW]] // CHECK: ret void // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) @@ -408,14 +415,9 @@ namespace test9 { // CHECK: call void @_ZdlPv({{.*}}) [[NUW]] // CHECK: resume { i8*, i32 } - // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( - // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 - // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev( - // CHECK: ret void - - // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev( + // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev( // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev( // CHECK: ret void - // CHECK: attributes [[NUW]] = { nounwind{{.*}} } + // CHECK: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}} diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp index 40f3cad..11026e8 100644 --- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp +++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp @@ -5,7 +5,7 @@ namespace Test1 { virtual int f() final; }; - // CHECK: define i32 @_ZN5Test11fEPNS_1AE + // CHECK-LABEL: define i32 @_ZN5Test11fEPNS_1AE int f(A *a) { // CHECK: call i32 @_ZN5Test11A1fEv return a->f(); @@ -17,7 +17,7 @@ namespace Test2 { virtual int f(); }; - // CHECK: define i32 @_ZN5Test21fEPNS_1AE + // CHECK-LABEL: define i32 @_ZN5Test21fEPNS_1AE int f(A *a) { // CHECK: call i32 @_ZN5Test21A1fEv return a->f(); @@ -31,19 +31,19 @@ namespace Test3 { struct B final : A { }; - // CHECK: define i32 @_ZN5Test31fEPNS_1BE + // CHECK-LABEL: define i32 @_ZN5Test31fEPNS_1BE int f(B *b) { // CHECK: call i32 @_ZN5Test31A1fEv return b->f(); } - // CHECK: define i32 @_ZN5Test31fERNS_1BE + // CHECK-LABEL: define i32 @_ZN5Test31fERNS_1BE int f(B &b) { // CHECK: call i32 @_ZN5Test31A1fEv return b.f(); } - // CHECK: define i32 @_ZN5Test31fEPv + // CHECK-LABEL: define i32 @_ZN5Test31fEPv int f(void *v) { // CHECK: call i32 @_ZN5Test31A1fEv return static_cast<B*>(v)->f(); @@ -59,7 +59,7 @@ namespace Test4 { virtual void f(); }; - // CHECK: define void @_ZN5Test41fEPNS_1BE + // CHECK-LABEL: define void @_ZN5Test41fEPNS_1BE void f(B* d) { // CHECK: call void @_ZN5Test41B1fEv static_cast<A*>(d)->f(); @@ -78,7 +78,7 @@ namespace Test5 { struct C final : B { }; - // CHECK: define void @_ZN5Test51fEPNS_1CE + // CHECK-LABEL: define void @_ZN5Test51fEPNS_1CE void f(C* d) { // FIXME: It should be possible to devirtualize this case, but that is // not implemented yet. @@ -105,7 +105,7 @@ namespace Test6 { struct D final : public C, public B { }; - // CHECK: define void @_ZN5Test61fEPNS_1DE + // CHECK-LABEL: define void @_ZN5Test61fEPNS_1DE void f(D* d) { // CHECK: call void @_ZN5Test61DD1Ev static_cast<A*>(d)->~A(); @@ -126,7 +126,7 @@ namespace Test7 { virtual int f() {return z;} }; - // CHECK: define i32 @_ZN5Test71fEPNS_3zedE + // CHECK-LABEL: define i32 @_ZN5Test71fEPNS_3zedE int f(zed *z) { // CHECK: alloca // CHECK-NEXT: store @@ -144,7 +144,7 @@ namespace Test8 { virtual int foo() { return b; } }; struct C final : A, B { }; - // CHECK: define i32 @_ZN5Test84testEPNS_1CE + // CHECK-LABEL: define i32 @_ZN5Test84testEPNS_1CE int test(C *c) { // CHECK: %[[THIS:.*]] = phi // CHECK-NEXT: call i32 @_ZN5Test81B3fooEv(%"struct.Test8::B"* %[[THIS]]) diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp index 52f1cd3..911ddee 100644 --- a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp +++ b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp @@ -79,7 +79,7 @@ namespace test3 { struct D : public B { }; void f(D d) { - // CHECK: define void @_ZN5test31fENS_1DE + // CHECK-LABEL: define void @_ZN5test31fENS_1DE d.B::~B(); } } diff --git a/test/CodeGenCXX/dynamic_cast-no-rtti.cpp b/test/CodeGenCXX/dynamic_cast-no-rtti.cpp new file mode 100644 index 0000000..0e26de5 --- /dev/null +++ b/test/CodeGenCXX/dynamic_cast-no-rtti.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -emit-llvm %s -verify -fno-rtti -o - | FileCheck %s +// expected-no-diagnostics + +struct A { + virtual ~A(){}; +}; + +struct B : public A { + B() : A() {} +}; + +// An upcast can be resolved statically and can be used with -fno-rtti, iff it +// does not use runtime support. +A *upcast(B *b) { + return dynamic_cast<A *>(b); +// CHECK-LABEL: define %struct.A* @_Z6upcastP1B +// CHECK-NOT: call i8* @__dynamic_cast +} + +// A NoOp dynamic_cast can be used with -fno-rtti iff it does not use +// runtime support. +B *samecast(B *b) { + return dynamic_cast<B *>(b); +// CHECK-LABEL: define %struct.B* @_Z8samecastP1B +// CHECK-NOT: call i8* @__dynamic_cast +} diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp index 70887f7..2a61e61 100644 --- a/test/CodeGenCXX/eh.cpp +++ b/test/CodeGenCXX/eh.cpp @@ -9,7 +9,7 @@ void test1() { throw d1; } -// CHECK: define void @_Z5test1v() +// CHECK-LABEL: define void @_Z5test1v() // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] // CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8* @@ -29,7 +29,7 @@ void test2() { throw d2; } -// CHECK: define void @_Z5test2v() +// CHECK-LABEL: define void @_Z5test2v() // CHECK: [[EXNVAR:%.*]] = alloca i8* // CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32 // CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16) @@ -51,7 +51,7 @@ void test3() { throw (volatile test3_D *)0; } -// CHECK: define void @_Z5test3v() +// CHECK-LABEL: define void @_Z5test3v() // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]** // CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]] @@ -63,7 +63,7 @@ void test4() { throw; } -// CHECK: define void @_Z5test4v() +// CHECK-LABEL: define void @_Z5test4v() // CHECK: call void @__cxa_rethrow() [[NR]] // CHECK-NEXT: unreachable @@ -79,7 +79,7 @@ namespace test5 { void test() { try { throw A(); } catch (A &x) {} } -// CHECK: define void @_ZN5test54testEv() +// CHECK-LABEL: define void @_ZN5test54testEv() // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1) // CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]* // CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]]) @@ -101,7 +101,7 @@ namespace test6 { // PR7127 namespace test7 { -// CHECK: define i32 @_ZN5test73fooEv() +// CHECK-LABEL: define i32 @_ZN5test73fooEv() int foo() { // CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8* // CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32 @@ -160,7 +160,7 @@ namespace test8 { struct A { A(const A&); ~A(); }; void bar(); - // CHECK: define void @_ZN5test83fooEv() + // CHECK-LABEL: define void @_ZN5test83fooEv() void foo() { try { // CHECK: invoke void @_ZN5test83barEv() @@ -184,11 +184,11 @@ namespace test9 { struct A { A(); }; - // CHECK: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr // CHECK: call void @_ZN5test91AC2Ev // CHECK-NEXT: ret void - // CHECK: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr A::A() try { // CHECK: invoke void @_ZN5test96opaqueEv() opaque(); @@ -210,7 +210,7 @@ namespace test10 { struct A { ~A(); }; struct B { int x; }; - // CHECK: define void @_ZN6test103fooEv() + // CHECK-LABEL: define void @_ZN6test103fooEv() void foo() { A a; // force a cleanup context @@ -244,7 +244,7 @@ namespace test10 { namespace test11 { void opaque(); - // CHECK: define void @_ZN6test113fooEv() + // CHECK-LABEL: define void @_ZN6test113fooEv() void foo() { try { // CHECK: invoke void @_ZN6test116opaqueEv() @@ -261,7 +261,7 @@ namespace test11 { struct A {}; - // CHECK: define void @_ZN6test113barEv() + // CHECK-LABEL: define void @_ZN6test113barEv() void bar() { try { // CHECK: [[EXNSLOT:%.*]] = alloca i8* @@ -286,7 +286,7 @@ namespace test12 { struct A { ~A() noexcept(false); }; bool opaque(const A&); - // CHECK: define void @_ZN6test124testEv() + // CHECK-LABEL: define void @_ZN6test124testEv() void test() { // CHECK: [[X:%.*]] = alloca [[A:%.*]], // CHECK: [[EHCLEANUPDEST:%.*]] = alloca i32 @@ -371,7 +371,7 @@ namespace test15 { bool opaque(int); - // CHECK: define void @_ZN6test153fooEv() + // CHECK-LABEL: define void @_ZN6test153fooEv() void foo() { A a; @@ -405,7 +405,7 @@ namespace test16 { void foo(); bool cond(); - // CHECK: define void @_ZN6test163barEv() + // CHECK-LABEL: define void @_ZN6test163barEv() void bar() { // CHECK: [[EXN_SAVE:%.*]] = alloca i8* // CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1 diff --git a/test/CodeGenCXX/empty-classes.cpp b/test/CodeGenCXX/empty-classes.cpp index 1ce1dad..8491480 100644 --- a/test/CodeGenCXX/empty-classes.cpp +++ b/test/CodeGenCXX/empty-classes.cpp @@ -29,7 +29,7 @@ struct D : A, Empty { #define CHECK(x) if (!(x)) return __LINE__ // PR7012 -// CHECK: define i32 @_Z1fv() +// CHECK-LABEL: define i32 @_Z1fv() int f() { B b1; diff --git a/test/CodeGenCXX/empty-nontrivially-copyable.cpp b/test/CodeGenCXX/empty-nontrivially-copyable.cpp new file mode 100644 index 0000000..9ee3281 --- /dev/null +++ b/test/CodeGenCXX/empty-nontrivially-copyable.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple armv7-apple-ios -x c++ -emit-llvm -o - %s | FileCheck %s + +// According to the Itanium ABI (3.1.1), types with non-trivial copy +// constructors passed by value should be passed indirectly, with the caller +// creating a temporary. + +struct Empty; + +struct Empty { + Empty(const Empty &e); + bool check(); +}; + +bool foo(Empty e) { +// CHECK: @_Z3foo5Empty(%struct.Empty* %e) +// CHECK: call {{.*}} @_ZN5Empty5checkEv(%struct.Empty* %e) + return e.check(); +} + +void caller(Empty &e) { +// CHECK: @_Z6callerR5Empty(%struct.Empty* %e) +// CHECK: call {{.*}} @_ZN5EmptyC1ERKS_(%struct.Empty* [[NEWTMP:%.*]], %struct.Empty* +// CHECK: call {{.*}} @_Z3foo5Empty(%struct.Empty* [[NEWTMP]]) + foo(e); +} diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp index f6f5079..d37e610 100644 --- a/test/CodeGenCXX/exceptions.cpp +++ b/test/CodeGenCXX/exceptions.cpp @@ -269,7 +269,7 @@ namespace test5 { void foo(); - // CHECK: define void @_ZN5test54testEv() + // CHECK-LABEL: define void @_ZN5test54testEv() // CHECK: [[EXNSLOT:%.*]] = alloca i8* // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 // CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1 @@ -403,7 +403,7 @@ namespace test8 { void test() { throw makeA(); } - // CHECK: define void @_ZN5test84testEv + // CHECK-LABEL: define void @_ZN5test84testEv } // Make sure we generate the correct code for the delete[] call which @@ -432,14 +432,14 @@ namespace test10 { struct A { ~A(); }; A::~A() try { cleanup(); } catch (...) { return; } - // CHECK: define void @_ZN6test101AD1Ev( + // CHECK-LABEL: define void @_ZN6test101AD1Ev( // CHECK: invoke void @_ZN6test107cleanupEv() // CHECK-NOT: rethrow // CHECK: ret void struct B { ~B(); }; B::~B() try { cleanup(); } catch (...) {} - // CHECK: define void @_ZN6test101BD1Ev( + // CHECK-LABEL: define void @_ZN6test101BD1Ev( // CHECK: invoke void @_ZN6test107cleanupEv() // CHECK: call i8* @__cxa_begin_catch // CHECK-NEXT: invoke void @__cxa_rethrow() @@ -447,7 +447,7 @@ namespace test10 { struct C { ~C(); }; C::~C() try { cleanup(); } catch (...) { if (suppress) return; } - // CHECK: define void @_ZN6test101CD1Ev( + // CHECK-LABEL: define void @_ZN6test101CD1Ev( // CHECK: invoke void @_ZN6test107cleanupEv() // CHECK: call i8* @__cxa_begin_catch // CHECK-NEXT: load i8* @_ZN6test108suppressE, align 1 @@ -477,7 +477,7 @@ namespace test11 { C::C() { throw 0; } - // CHECK: define void @_ZN6test111CC2Ev( + // CHECK-LABEL: define void @_ZN6test111CC2Ev( // CHECK: [[THIS:%.*]] = load [[C:%.*]]** {{%.*}} // Construct single. // CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[C]]* [[THIS]], i32 0, i32 0 diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp index 8daf3c6..6a4fd82 100644 --- a/test/CodeGenCXX/explicit-instantiation.cpp +++ b/test/CodeGenCXX/explicit-instantiation.cpp @@ -13,7 +13,7 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const { return t + u; } -// CHECK: define weak_odr i32 @_ZNK4plusIillEclERKiRKl +// CHECK-LABEL: define weak_odr i32 @_ZNK4plusIillEclERKiRKl template struct plus<int, long, long>; // Check that we emit definitions from explicit instantiations even when they @@ -27,16 +27,16 @@ template <typename T> struct S { }; }; -// CHECK: define weak_odr void @_ZN1SIiE1fEv +// CHECK-LABEL: define weak_odr void @_ZN1SIiE1fEv template void S<int>::f(); -// CHECK: define weak_odr void @_ZN1SIiE1gEv +// CHECK-LABEL: define weak_odr void @_ZN1SIiE1gEv template void S<int>::g(); // See the check line at the top of the file. template int S<int>::i; -// CHECK: define weak_odr void @_ZN1SIiE2S21hEv +// CHECK-LABEL: define weak_odr void @_ZN1SIiE2S21hEv template void S<int>::S2::h(); template <typename T> void S<T>::f() {} diff --git a/test/CodeGenCXX/fastcall.cpp b/test/CodeGenCXX/fastcall.cpp index c0a9106..0326ce5 100644 --- a/test/CodeGenCXX/fastcall.cpp +++ b/test/CodeGenCXX/fastcall.cpp @@ -2,7 +2,7 @@ void __attribute__((fastcall)) foo1(int &y); void bar1(int &y) { - // CHECK: define void @_Z4bar1Ri + // CHECK-LABEL: define void @_Z4bar1Ri // CHECK: call x86_fastcallcc void @_Z4foo1Ri(i32* inreg % foo1(y); } @@ -14,7 +14,7 @@ struct S1 { void __attribute__((fastcall)) foo2(S1 a, int b); void bar2(S1 a, int b) { - // CHECK: define void @_Z4bar22S1i + // CHECK-LABEL: define void @_Z4bar22S1i // CHECK: call x86_fastcallcc void @_Z4foo22S1i(%struct.S1* inreg %{{.*}}, i32 inreg % foo2(a, b); } diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp index 926fe44..8124129 100644 --- a/test/CodeGenCXX/for-range.cpp +++ b/test/CodeGenCXX/for-range.cpp @@ -32,7 +32,7 @@ B *end(C&); extern B array[5]; -// CHECK: define void @_Z9for_arrayv( +// CHECK-LABEL: define void @_Z9for_arrayv( void for_array() { // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]]) A a; @@ -40,7 +40,7 @@ void for_array() { // CHECK-NOT: 5begin // CHECK-NOT: 3end // CHECK: getelementptr {{.*}}, i32 0 - // CHECK: getelementptr {{.*}}, i64 1, i64 0 + // CHECK: getelementptr {{.*}}, i64 5 // CHECK: br label %[[COND:.*]] // CHECK: [[COND]]: @@ -61,7 +61,7 @@ void for_array() { // CHECK: ret void } -// CHECK: define void @_Z9for_rangev( +// CHECK-LABEL: define void @_Z9for_rangev( void for_range() { // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]]) A a; @@ -93,7 +93,7 @@ void for_range() { // CHECK: ret void } -// CHECK: define void @_Z16for_member_rangev( +// CHECK-LABEL: define void @_Z16for_member_rangev( void for_member_range() { // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]]) A a; diff --git a/test/CodeGenCXX/forward-enum.cpp b/test/CodeGenCXX/forward-enum.cpp index c1169e0..685e4f3 100644 --- a/test/CodeGenCXX/forward-enum.cpp +++ b/test/CodeGenCXX/forward-enum.cpp @@ -3,7 +3,7 @@ enum MyEnum : char; void bar(MyEnum value) { } -// CHECK: define void @_Z3foo6MyEnum +// CHECK-LABEL: define void @_Z3foo6MyEnum void foo(MyEnum value) { // CHECK: call void @_Z3bar6MyEnum(i8 signext diff --git a/test/CodeGenCXX/fp16-mangle.cpp b/test/CodeGenCXX/fp16-mangle.cpp index 4a056d6..bd5a319 100644 --- a/test/CodeGenCXX/fp16-mangle.cpp +++ b/test/CodeGenCXX/fp16-mangle.cpp @@ -4,9 +4,9 @@ template <typename T, typename U> struct S { static int i; }; template <> int S<__fp16, __fp16>::i = 3; -// CHECK: define void @_Z1fPDh(i16* %x) +// CHECK-LABEL: define void @_Z1fPDh(i16* %x) void f (__fp16 *x) { } -// CHECK: define void @_Z1gPDhS_(i16* %x, i16* %y) +// CHECK-LABEL: define void @_Z1gPDhS_(i16* %x, i16* %y) void g (__fp16 *x, __fp16 *y) { } diff --git a/test/CodeGenCXX/function-template-explicit-specialization.cpp b/test/CodeGenCXX/function-template-explicit-specialization.cpp index 21f0127..5d26dcd 100644 --- a/test/CodeGenCXX/function-template-explicit-specialization.cpp +++ b/test/CodeGenCXX/function-template-explicit-specialization.cpp @@ -3,11 +3,11 @@ template<typename T> void a(T); template<> void a(int) {} -// CHECK: define void @_Z1aIiEvT_ +// CHECK-LABEL: define void @_Z1aIiEvT_ namespace X { template<typename T> void b(T); template<> void b(int) {} } -// CHECK: define void @_ZN1X1bIiEEvT_ +// CHECK-LABEL: define void @_ZN1X1bIiEEvT_ diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp index 087d655..6ebc139 100644 --- a/test/CodeGenCXX/global-array-destruction.cpp +++ b/test/CodeGenCXX/global-array-destruction.cpp @@ -56,7 +56,7 @@ using U = T[2][3]; U &&u = U{ {{1.0, 2}, {3.0, 4}, {5.0, 6}}, {{7.0, 8}, {9.0, 10}, {11.0, 12}} }; // CHECK: call {{.*}} @__cxa_atexit -// CHECK: getelementptr inbounds ([2 x [3 x {{.*}}]]* @_ZGR1u, i64 1, i64 0, i64 0) +// CHECK: getelementptr inbounds ({{.*}}* getelementptr inbounds ([2 x [3 x {{.*}}]]* @_ZGR1u, i32 0, i32 0, i32 0), i64 6) // CHECK: call void @_ZN1TD1Ev // CHECK: icmp eq {{.*}} @_ZGR1u // CHECK: br i1 {{.*}} diff --git a/test/CodeGenCXX/global-block-literal-helpers.cpp b/test/CodeGenCXX/global-block-literal-helpers.cpp index 350ea54..762b5d9 100644 --- a/test/CodeGenCXX/global-block-literal-helpers.cpp +++ b/test/CodeGenCXX/global-block-literal-helpers.cpp @@ -5,23 +5,23 @@ namespace N { typedef void (^BL)(); int func(BL, BL, BL); -// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke( -// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke_2( -// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke_3 +// CHECK-LABEL: define internal void @_ZN1N8ArrBlockE_block_invoke( +// CHECK-LABEL: define internal void @_ZN1N8ArrBlockE_block_invoke_2( +// CHECK-LABEL: define internal void @_ZN1N8ArrBlockE_block_invoke_3 BL ArrBlock [] = { ^{}, ^{}, ^{} }; -// CHECK: define internal void @_ZN1N4ivalE_block_invoke_4( -// CHECK: define internal void @_ZN1N4ivalE_block_invoke_5( -// CHECK: define internal void @_ZN1N4ivalE_block_invoke_6( +// CHECK-LABEL: define internal void @_ZN1N4ivalE_block_invoke_4( +// CHECK-LABEL: define internal void @_ZN1N4ivalE_block_invoke_5( +// CHECK-LABEL: define internal void @_ZN1N4ivalE_block_invoke_6( int ival = func(^{}, ^{}, ^{}); -// CHECK: define internal void @_ZN1N9gvarlobalE_block_invoke_7( +// CHECK-LABEL: define internal void @_ZN1N9gvarlobalE_block_invoke_7( void (^gvarlobal)(void) = ^{}; struct S { BL field = ^{}; }; -// CHECK: define internal void @_ZN1N3blfE_block_invoke_8( +// CHECK-LABEL: define internal void @_ZN1N3blfE_block_invoke_8( S blf; }; diff --git a/test/CodeGenCXX/global-dtor-no-atexit.cpp b/test/CodeGenCXX/global-dtor-no-atexit.cpp index 7c4b6aa..9d35e84 100644 --- a/test/CodeGenCXX/global-dtor-no-atexit.cpp +++ b/test/CodeGenCXX/global-dtor-no-atexit.cpp @@ -22,7 +22,7 @@ public: A a, b; // PR9593 -// CHECK: define void @_Z4funcv() +// CHECK-LABEL: define void @_Z4funcv() // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a1) // CHECK: call void @_ZN1AC1Ev([[A]]* @_ZZ4funcvE2a1) // CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a1) diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp index 426cf9c..69631c2 100644 --- a/test/CodeGenCXX/global-init.cpp +++ b/test/CodeGenCXX/global-init.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -fexceptions %s -o - |FileCheck %s -// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - |FileCheck -check-prefix NOEXC %s +// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - |FileCheck -check-prefix CHECK-NOEXC %s struct A { A(); @@ -45,7 +45,7 @@ namespace test1 { const int y = x - 1; // This gets deferred. const int z = ~y; // This also gets deferred, but gets "undeferred" before y. int test() { return z; } -// CHECK: define i32 @_ZN5test14testEv() +// CHECK-LABEL: define i32 @_ZN5test14testEv() // All of these initializers end up delayed, so we check them later. } diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp index 77b6166..904f95f 100644 --- a/test/CodeGenCXX/goto.cpp +++ b/test/CodeGenCXX/goto.cpp @@ -5,7 +5,7 @@ namespace test0 { struct A { A(); ~A(); }; struct V { V(const A &a = A()); ~V(); }; - // CHECK: define linkonce_odr i32 @_ZN5test04testILi0EEEii + // CHECK-LABEL: define linkonce_odr i32 @_ZN5test04testILi0EEEii template<int X> int test(int x) { // CHECK: [[RET:%.*]] = alloca i32 // CHECK-NEXT: [[X:%.*]] = alloca i32 diff --git a/test/CodeGenCXX/implicit-copy-assign-operator.cpp b/test/CodeGenCXX/implicit-copy-assign-operator.cpp index 79586fb..2674021 100644 --- a/test/CodeGenCXX/implicit-copy-assign-operator.cpp +++ b/test/CodeGenCXX/implicit-copy-assign-operator.cpp @@ -40,7 +40,7 @@ void test_D(D d1, D d2) { d1 = d2; } -// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_ +// CHECK-LABEL: define linkonce_odr %struct.D* @_ZN1DaSERS_ // CHECK: {{call.*_ZN1AaSERS_}} // CHECK: {{call.*_ZN1BaSERS_}} // CHECK: {{call.*_ZN1CaSERKS_}} diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp index 24e84d5..bb04318 100644 --- a/test/CodeGenCXX/implicit-copy-constructor.cpp +++ b/test/CodeGenCXX/implicit-copy-constructor.cpp @@ -40,7 +40,7 @@ void f(D d) { D d2(d); } -// CHECK: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr // CHECK: call void @_ZN1AC1Ev // CHECK: call void @_ZN1CC2ERS_1A // CHECK: call void @_ZN1AD1Ev diff --git a/test/CodeGenCXX/implicit-instantiation-1.cpp b/test/CodeGenCXX/implicit-instantiation-1.cpp index 0c826e4..bf6a141 100644 --- a/test/CodeGenCXX/implicit-instantiation-1.cpp +++ b/test/CodeGenCXX/implicit-instantiation-1.cpp @@ -20,7 +20,7 @@ void foo(X<int> &xi, X<float> *xfp, int i, float f) { // RUN: grep "linkonce_odr.*_ZN1XIfE1fEf" %t | count 1 xfp->f(f); - // RUN: grep "linkonce_odr.*_ZN1XIfE1hEf" %t | count 0 + // RUN: not grep "linkonce_odr.*_ZN1XIfE1hEf" %t } diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp index 0f39784..c99a20c 100644 --- a/test/CodeGenCXX/inheriting-constructor.cpp +++ b/test/CodeGenCXX/inheriting-constructor.cpp @@ -11,18 +11,18 @@ struct C { template<typename T> C(T); }; struct D : C { using C::C; }; D d(123); -// CHECK: define void @_ZN1BD0Ev -// CHECK: define void @_ZN1BD1Ev -// CHECK: define void @_ZN1BD2Ev +// CHECK-LABEL: define void @_ZN1BD0Ev +// CHECK-LABEL: define void @_ZN1BD1Ev +// CHECK-LABEL: define void @_ZN1BD2Ev -// CHECK: define linkonce_odr void @_ZN1BC1Ei( +// CHECK-LABEL: define linkonce_odr void @_ZN1BC1Ei( // CHECK: call void @_ZN1BC2Ei( -// CHECK: define linkonce_odr void @_ZN1DC1IiEET_( +// CHECK-LABEL: define linkonce_odr void @_ZN1DC1IiEET_( // CHECK: call void @_ZN1DC2IiEET_( -// CHECK: define linkonce_odr void @_ZN1DC2IiEET_( +// CHECK-LABEL: define linkonce_odr void @_ZN1DC2IiEET_( // CHECK: call void @_ZN1CC2IiEET_( -// CHECK: define linkonce_odr void @_ZN1BC2Ei( +// CHECK-LABEL: define linkonce_odr void @_ZN1BC2Ei( // CHECK: call void @_ZN1AC2Ei( diff --git a/test/CodeGenCXX/init-invariant.cpp b/test/CodeGenCXX/init-invariant.cpp index 9eb1989..45816b2 100644 --- a/test/CodeGenCXX/init-invariant.cpp +++ b/test/CodeGenCXX/init-invariant.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O0 -o - | FileCheck %s --check-prefix=CHECK-O0 +// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-O0 // RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O1 -o - | FileCheck %s // Check that we add an llvm.invariant.start to mark when a global becomes @@ -54,7 +54,7 @@ void e() { // CHECK: store {{.*}}, i32* @d // CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @d to i8*)) -// CHECK: define void @_Z1ev( +// CHECK-LABEL: define void @_Z1ev( // CHECK: call void @_ZN1AC1Ev(%struct.A* @_ZZ1evE1a) // CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @_ZZ1evE1a to i8*)) // CHECK-NOT: llvm.invariant.end diff --git a/test/CodeGenCXX/inline-functions.cpp b/test/CodeGenCXX/inline-functions.cpp index 8c011de..9f8e536 100644 --- a/test/CodeGenCXX/inline-functions.cpp +++ b/test/CodeGenCXX/inline-functions.cpp @@ -5,7 +5,7 @@ struct A { inline void f(); }; -// CHECK-NOT: define void @_ZN1A1fEv +// CHECK-NOT-LABEL: define void @_ZN1A1fEv void A::f() { } template<typename> struct B { }; @@ -19,13 +19,13 @@ void B<char>::f() { } // We need a final CHECK line here. -// CHECK: define void @_Z1fv +// CHECK-LABEL: define void @_Z1fv void f() { } // <rdar://problem/8740363> inline void f1(int); -// CHECK: define linkonce_odr void @_Z2f1i +// CHECK-LABEL: define linkonce_odr void @_Z2f1i void f1(int) { } void test_f1() { f1(17); } @@ -38,7 +38,7 @@ namespace test1 { void g() {} }; - // CHECK: define linkonce_odr void @_ZN5test11C4funcEv( + // CHECK-LABEL: define linkonce_odr void @_ZN5test11C4funcEv( class C { public: @@ -65,5 +65,5 @@ namespace test2 { A a; f(a); } - // CHECK: define linkonce_odr void @_ZN5test21fERKNS_1AE + // CHECK-LABEL: define linkonce_odr void @_ZN5test21fERKNS_1AE } diff --git a/test/CodeGenCXX/instantiate-temporaries.cpp b/test/CodeGenCXX/instantiate-temporaries.cpp index 29cfc07..c08ea78 100644 --- a/test/CodeGenCXX/instantiate-temporaries.cpp +++ b/test/CodeGenCXX/instantiate-temporaries.cpp @@ -18,7 +18,7 @@ void call() { Y().get(); } -// CHECK: define weak_odr void @_Z4callIiEvv +// CHECK-LABEL: define weak_odr void @_Z4callIiEvv // CHECK: call void @_ZN1Y3getEv // CHECK-NEXT: call void @_ZN1XD1Ev // CHECK-NEXT: ret void @@ -29,7 +29,7 @@ void compound_literal() { (X2){}; } -// CHECK: define weak_odr void @_Z16compound_literalIiEvv +// CHECK-LABEL: define weak_odr void @_Z16compound_literalIiEvv // CHECK: call void @_ZN1XC1Ev // CHECK-NEXT: call void @_ZN2X2D1Ev // CHECK-NEXT: ret void diff --git a/test/CodeGenCXX/invalid.cpp b/test/CodeGenCXX/invalid.cpp new file mode 100644 index 0000000..d346246 --- /dev/null +++ b/test/CodeGenCXX/invalid.cpp @@ -0,0 +1,11 @@ +// RUN: not %clang_cc1 -g -emit-llvm %s + +// Don't attempt to codegen invalid code that would lead to a crash + +// PR16933 +struct A; +A *x; +struct A { + B y; +}; +A y; diff --git a/test/CodeGenCXX/lambda-expressions-inside-auto-functions.cpp b/test/CodeGenCXX/lambda-expressions-inside-auto-functions.cpp new file mode 100644 index 0000000..0083f08 --- /dev/null +++ b/test/CodeGenCXX/lambda-expressions-inside-auto-functions.cpp @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++1y | FileCheck %s + +// CHECK-LABEL: define void @_ZN19non_inline_function3fooEv +// CHECK-LABEL: define internal void @"_ZZN19non_inline_function3fooEvENK3$_0clEi"(%class.anon +// CHECK-LABEL: define internal signext i8 @"_ZZZN19non_inline_function3fooEvENK3$_0clEiENKUlcE_clEc"(%class.anon +// CHECK-LABEL: define linkonce_odr void @_ZN19non_inline_function4foo2IiEEDav() +namespace non_inline_function { +auto foo() { + auto L = [](int a) { + return [](char b) { + return b; + }; + }; + L(3)('a'); + return L; +} + +template<typename T> +auto foo2() { + return [](const T&) { return 42; }; +} + +auto use = foo2<int>(); + +} +//CHECK-LABEL: define linkonce_odr void @_ZN22inline_member_function1X3fooEv(%"struct.inline_member_function::X"* %this) +//CHECK-LABEL: define linkonce_odr void @_ZZN22inline_member_function1X3fooEvENKUliE_clEi(%class.anon +//CHECK-LABEL: define linkonce_odr signext i8 @_ZZZN22inline_member_function1X3fooEvENKUliE_clEiENKUlcE_clEc(%class.anon + +namespace inline_member_function { +struct X { +auto foo() { + auto L = [](int a) { + return [](char b) { + return b; + }; + }; + return L; +} +}; + +auto run1 = X{}.foo()(3)('a'); + +template<typename S> +struct A { + template<typename T> static auto default_lambda() { + return [](const T&) { return 42; }; + } + + template<class U = decltype(default_lambda<S>())> + U func(U u = default_lambda<S>()) { return u; } + + template<class T> auto foo() { return [](const T&) { return 42; }; } +}; +//CHECK-LABEL: define linkonce_odr i32 @_ZZN22inline_member_function1AIdE14default_lambdaIdEEDavENKUlRKdE_clES5_(%class.anon +int run2 = A<double>{}.func()(3.14); + +//CHECK-LABEL: define linkonce_odr i32 @_ZZN22inline_member_function1AIcE14default_lambdaIcEEDavENKUlRKcE_clES5_(%class.anon +int run3 = A<char>{}.func()('a'); +} // end inline_member_function + + +// CHECK-LABEL: define linkonce_odr void @_ZN15inline_function3fooEv() +// CHECK: define linkonce_odr void @_ZZN15inline_function3fooEvENKUliE_clEi(%class.anon +// CHECK: define linkonce_odr signext i8 @_ZZZN15inline_function3fooEvENKUliE_clEiENKUlcE_clEc(%class.anon +namespace inline_function { +inline auto foo() { + auto L = [](int a) { + return [](char b) { + return b; + }; + }; + return L; +} +auto use = foo()(3)('a'); +} + diff --git a/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp b/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp new file mode 100644 index 0000000..accc5d2 --- /dev/null +++ b/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s + +// CHECK-LABEL: define void @_ZN19non_inline_function3fooEv() +// CHECK-LABEL: define internal void @"_ZZN19non_inline_function3fooEvENK3$_0clEi"(%class.anon +// CHECK-LABEL: define internal signext i8 @"_ZZZN19non_inline_function3fooEvENK3$_0clEiENKUlcE_clEc"(%class.anon +namespace non_inline_function { +void foo() { + auto L = [](int a) { + return [](char b) { + return b; + }; + }; + L(3)('a'); +} +} + +namespace non_template { + struct L { + int t = ([](int a) { return [](int b) { return b; };})(2)(3); + }; + L l; +} + +namespace lambdas_in_NSDMIs_template_class { +template<class T> +struct L { + T t2 = ([](int a) { return [](int b) { return b; };})(T{})(T{}); +}; +L<int> l; +} + +// CHECK-LABEL: define linkonce_odr i32 @_ZN15inline_function3fooEv +// CHECK: define linkonce_odr void @_ZZN15inline_function3fooEvENKUliE_clEi +// CHECK: define linkonce_odr signext i8 @_ZZZN15inline_function3fooEvENKUliE_clEiENKUlcE_clEc +namespace inline_function { +inline int foo() { + auto L = [](int a) { + return [](char b) { + return b; + }; + }; + L(3)('a'); +} +int use = foo(); +} +// CHECK: define linkonce_odr void @_ZNK32lambdas_in_NSDMIs_template_class1LIiEUliE_clEi(%class.anon +// CHECK: define linkonce_odr i32 @_ZZNK32lambdas_in_NSDMIs_template_class1LIiEUliE_clEiENKUliE_clEi(%class.anon + +// CHECK: define linkonce_odr void @_ZNK12non_template1L1tMUliE_clEi(%class.anon +// CHECK: define linkonce_odr i32 @_ZZNK12non_template1L1tMUliE_clEiENKUliE_clEi(%class.anon diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp index 68ae68f..2f9a4f2 100644 --- a/test/CodeGenCXX/lambda-expressions.cpp +++ b/test/CodeGenCXX/lambda-expressions.cpp @@ -11,27 +11,27 @@ void *use = &used; extern "C" auto cvar = []{}; int a() { return []{ return 1; }(); } -// CHECK: define i32 @_Z1av +// CHECK-LABEL: define i32 @_Z1av // CHECK: call i32 @"_ZZ1avENK3$_0clEv" -// CHECK: define internal i32 @"_ZZ1avENK3$_0clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_0clEv" // CHECK: ret i32 1 int b(int x) { return [x]{return x;}(); } -// CHECK: define i32 @_Z1bi +// CHECK-LABEL: define i32 @_Z1bi // CHECK: store i32 // CHECK: load i32* // CHECK: store i32 // CHECK: call i32 @"_ZZ1biENK3$_1clEv" -// CHECK: define internal i32 @"_ZZ1biENK3$_1clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_1clEv" // CHECK: load i32* // CHECK: ret i32 int c(int x) { return [&x]{return x;}(); } -// CHECK: define i32 @_Z1ci +// CHECK-LABEL: define i32 @_Z1ci // CHECK: store i32 // CHECK: store i32* // CHECK: call i32 @"_ZZ1ciENK3$_2clEv" -// CHECK: define internal i32 @"_ZZ1ciENK3$_2clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_2clEv" // CHECK: load i32** // CHECK: load i32* // CHECK: ret i32 @@ -39,32 +39,32 @@ int c(int x) { return [&x]{return x;}(); } struct D { D(); D(const D&); int x; }; int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } -// CHECK: define i32 @_Z1di +// CHECK-LABEL: define i32 @_Z1di // CHECK: call void @_ZN1DC1Ev // CHECK: icmp ult i64 %{{.*}}, 10 // CHECK: call void @_ZN1DC1ERKS_ // CHECK: call i32 @"_ZZ1diENK3$_3clEv" -// CHECK: define internal i32 @"_ZZ1diENK3$_3clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_3clEv" // CHECK: load i32* // CHECK: load i32* // CHECK: ret i32 struct E { E(); E(const E&); ~E(); int x; }; int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); } -// CHECK: define i32 @_Z1e1ES_b +// CHECK-LABEL: define i32 @_Z1e1ES_b // CHECK: call void @_ZN1EC1ERKS_ // CHECK: invoke void @_ZN1EC1ERKS_ // CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv" // CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" // CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" -// CHECK: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv" +// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv" // CHECK: trunc i8 // CHECK: load i32* // CHECK: ret i32 void f() { - // CHECK: define void @_Z1fv() + // CHECK-LABEL: define void @_Z1fv() // CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv" // CHECK-NEXT: store i32 (i32, i32)* // CHECK-NEXT: ret void @@ -74,7 +74,7 @@ void f() { static int k; int g() { int &r = k; - // CHECK: define internal i32 @"_ZZ1gvENK3$_6clEv"( + // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_6clEv"( // CHECK-NOT: } // CHECK: load i32* @_ZL1k, return [] { return r; } (); @@ -100,7 +100,7 @@ void h() { A (*h)() = [] { return A(); }; } -// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii" +// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_58__invokeEii" // CHECK: store i32 // CHECK-NEXT: store i32 // CHECK-NEXT: load i32* @@ -108,7 +108,7 @@ void h() { // CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii" // CHECK-NEXT: ret i32 -// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev" +// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev" // <rdar://problem/12778708> struct XXX {}; diff --git a/test/CodeGenCXX/linetable-cleanup.cpp b/test/CodeGenCXX/linetable-cleanup.cpp index 4077af6..96b8572 100644 --- a/test/CodeGenCXX/linetable-cleanup.cpp +++ b/test/CodeGenCXX/linetable-cleanup.cpp @@ -1,12 +1,18 @@ // RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s -// Check the line numbers for cleanup code with EH in combinatin with +// Check the line numbers for cleanup code with EH in combination with // simple return expressions. // CHECK: define {{.*}}foo // CHECK: call void @_ZN1CD1Ev(%class.C* {{.*}}), !dbg ![[CLEANUP:[0-9]+]] // CHECK: ret i32 0, !dbg ![[RET:[0-9]+]] +// CHECK: define {{.*}}bar +// CHECK: ret void, !dbg ![[RETBAR:[0-9]+]] + +// CHECK: define {{.*}}baz +// CHECK: ret void, !dbg ![[RETBAZ:[0-9]+]] + class C { public: ~C() {} @@ -22,3 +28,31 @@ int foo() return 0; // CHECK: ![[RET]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} } + +void bar() +{ + if (!foo()) + // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} + return; + + if (foo()) { + C c; + c.i = foo(); + } + // Clang creates only a single ret instruction. Make sure it is at a useful line. + // CHECK: ![[RETBAR]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} +} + +void baz() +{ + if (!foo()) + // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} + return; + + if (foo()) { + // no cleanup + // CHECK: {{.*}} = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} + return; + } + // CHECK: ![[RETBAZ]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} +} diff --git a/test/CodeGenCXX/linkage.cpp b/test/CodeGenCXX/linkage.cpp new file mode 100644 index 0000000..19f1b20 --- /dev/null +++ b/test/CodeGenCXX/linkage.cpp @@ -0,0 +1,222 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -O1 -disable-llvm-optzns %s -o - | FileCheck %s + +namespace test1 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test11fIZNS_1gEvE1SEEvT_( + template <typename T> void f(T) {} + inline void *g() { + struct S { + } s; + return reinterpret_cast<void *>(f<S>); + } + void *h() { return g(); } +} + +namespace test2 { + // CHECK-DAG-LABEL: define internal void @_ZN5test21fIZNS_L1gEvE1SEEvT_( + template <typename T> void f(T) {} + static inline void *g() { + struct S { + } s; + return reinterpret_cast<void *>(f<S>); + } + void *h() { return g(); } +} + +namespace test3 { + // CHECK-DAG-LABEL: define internal void @_ZN5test31fIZNS_1gEvE1SEEvT_( + template <typename T> void f(T) {} + void *g() { + struct S { + } s; + return reinterpret_cast<void *>(f<S>); + } + void *h() { return g(); } +} + +namespace test4 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test41fIZNS_1gILi1EEEPvvE1SEEvT_( + template <typename T> void f(T) {} + template <int N> inline void *g() { + struct S { + } s; + return reinterpret_cast<void *>(f<S>); + } + extern template void *g<1>(); + template void *g<1>(); +} + +namespace test5 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test51fIZNS_1gILi1EEEPvvE1SEEvT_( + template <typename T> void f(T) {} + template <int N> inline void *g() { + struct S { + } s; + return reinterpret_cast<void *>(f<S>); + } + extern template void *g<1>(); + void *h() { return g<1>(); } +} + +namespace test6 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test61fIZZNS_1gEvEN1S1hEvE1TEEvv( + template <typename T> void f() {} + + inline void *g() { + struct S { + void *h() { + struct T { + }; + return (void *)f<T>; + } + } s; + return s.h(); + } + + void *h() { return g(); } +} + +namespace test7 { + // CHECK-DAG-LABEL: define internal void @_ZN5test71fIZZNS_1gEvEN1S1hEvE1TEEvv( + template <typename T> void f() {} + + void *g() { + struct S { + void *h() { + struct T { + }; + return (void *)f<T>; + } + } s; + return s.h(); + } + + void *h() { return g(); } +} + +namespace test8 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test81fIZNS_1gEvE1SEEvT_( + template <typename T> void f(T) {} + inline void *g() { + enum S { + }; + return reinterpret_cast<void *>(f<S>); + } + void *h() { return g(); } +} + +namespace test9 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN5test91fIPZNS_1gEvE1SEEvT_( + template <typename T> void f(T) {} + inline void *g() { + struct S { + } s; + return reinterpret_cast<void *>(f<S*>); + } + void *h() { return g(); } +} + +namespace test10 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test101fIPFZNS_1gEvE1SvEEEvT_( + template <typename T> void f(T) {} + inline void *g() { + struct S { + } s; + typedef S(*ftype)(); + return reinterpret_cast<void *>(f<ftype>); + } + void *h() { return g(); } +} + +namespace test11 { + // CHECK-DAG-LABEL: define internal void @_ZN6test111fIPFZNS_1gEvE1SPNS_12_GLOBAL__N_11IEEEEvT_( + namespace { + struct I { + }; + } + + template <typename T> void f(T) {} + inline void *g() { + struct S { + }; + typedef S(*ftype)(I * x); + return reinterpret_cast<void *>(f<ftype>); + } + void *h() { return g(); } +} + +namespace test12 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test123fooIZNS_3barIZNS_3zedEvE2S2EEPvvE2S1EEvv + template <typename T> void foo() {} + template <typename T> inline void *bar() { + enum S1 { + }; + return reinterpret_cast<void *>(foo<S1>); + } + inline void *zed() { + enum S2 { + }; + return reinterpret_cast<void *>(bar<S2>); + } + void *h() { return zed(); } +} + +namespace test13 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZZN6test133fooEvEN1S3barEv( + inline void *foo() { + struct S { + static void bar() {} + }; + return (void *)S::bar; + } + void *zed() { return foo(); } +} + +namespace test14 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test143fooIZNS_1fEvE1SE3barILPS1_0EEEvv( + template <typename T> struct foo { + template <T *P> static void bar() {} + static void *g() { return (void *)bar<nullptr>; } + }; + inline void *f() { + struct S { + }; + return foo<S>::g(); + } + void h() { f(); } +} + +namespace test15 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test153zedIZNS_3fooIiEEPvvE3barEEvv( + template <class T> void zed() {} + template <class T> void *foo() { + class bar { + }; + return reinterpret_cast<void *>(zed<bar>); + } + void test() { foo<int>(); } +} + +namespace test16 { + // CHECK-DAG-LABEL: define linkonce_odr void @_ZN6test163zedIZNS_3fooIiE3barEvE1SEEvv( + template <class T> void zed() {} + template <class T> struct foo { + static void *bar(); + }; + template <class T> void *foo<T>::bar() { + class S { + }; + return reinterpret_cast<void *>(zed<S>); + } + void *test() { return foo<int>::bar(); } +} + +namespace test17 { + // CHECK-DAG: @_ZZN6test173fooILi42EEEPivE3bar = linkonce_odr + // CHECK-DAG-LABEL: define weak_odr i32* @_ZN6test173fooILi42EEEPiv( + template<int I> + int *foo() { + static int bar; + return &bar; + } + template int *foo<42>(); +} diff --git a/test/CodeGenCXX/lpad-linetable.cpp b/test/CodeGenCXX/lpad-linetable.cpp new file mode 100644 index 0000000..dba2ad6 --- /dev/null +++ b/test/CodeGenCXX/lpad-linetable.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s +// The landing pad should have the line number of the closing brace of the function. +// rdar://problem/13888152 +// CHECK: ret i32 +// CHECK: landingpad {{.*}} +// CHECK-NEXT: !dbg ![[LPAD:[0-9]+]] +// CHECK: ![[LPAD]] = metadata !{i32 24, i32 0, metadata !{{.*}}, null} + +# 1 "/usr/include/c++/4.2.1/vector" 1 3 +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +namespace std { + template<typename _Tp> + class allocator + { + public: + template<typename _Tp1> + struct rebind + { typedef allocator<_Tp1> other; }; + ~allocator() throw() { } + }; + template<typename _Tp, typename _Alloc> + struct _Vector_base + { + typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type; + struct _Vector_impl + { + _Vector_impl(_Tp_alloc_type const& __a) { } + }; + typedef _Alloc allocator_type; + _Vector_base(const allocator_type& __a) + : _M_impl(__a) + { } + ~_Vector_base() { } + _Vector_impl _M_impl; + }; + template<typename _Tp, typename _Alloc = std::allocator<_Tp> > + class vector + : protected _Vector_base<_Tp, _Alloc> + { + typedef _Vector_base<_Tp, _Alloc> _Base; + public: + typedef _Tp value_type; + typedef size_t size_type; + typedef _Alloc allocator_type; + vector(const allocator_type& __a = allocator_type()) + : _Base(__a) + { } + size_type + push_back(const value_type& __x) + {} + }; +} +# 10 "main.cpp" 2 + + + + +int main (int argc, char const *argv[], char const *envp[]) +{ // 15 + std::vector<long> longs; + std::vector<short> shorts; + for (int i=0; i<12; i++) + { + longs.push_back(i); + shorts.push_back(i); + } + return 0; // 23 +} // 24 diff --git a/test/CodeGenCXX/lvalue-bitcasts.cpp b/test/CodeGenCXX/lvalue-bitcasts.cpp index 8c5fa4a..86355b2 100644 --- a/test/CodeGenCXX/lvalue-bitcasts.cpp +++ b/test/CodeGenCXX/lvalue-bitcasts.cpp @@ -3,7 +3,7 @@ struct X { int i; float f; }; struct Y { X x; }; -// CHECK: define void @_Z21reinterpret_cast_testRiRfR1X +// CHECK-LABEL: define void @_Z21reinterpret_cast_testRiRfR1X void reinterpret_cast_test(int &ir, float &fr, X &xr) { // CHECK: load float** // CHECK: bitcast float* @@ -48,7 +48,7 @@ void reinterpret_cast_test(int &ir, float &fr, X &xr) { // CHECK: ret void } -// CHECK: define void @_Z6c_castRiRfR1X +// CHECK-LABEL: define void @_Z6c_castRiRfR1X void c_cast(int &ir, float &fr, X &xr) { // CHECK: load float** // CHECK: bitcast float* @@ -93,7 +93,7 @@ void c_cast(int &ir, float &fr, X &xr) { // CHECK: ret void } -// CHECK: define void @_Z15functional_castRiRfR1X +// CHECK-LABEL: define void @_Z15functional_castRiRfR1X void functional_cast(int &ir, float &fr, X &xr) { typedef int &intref; typedef float &floatref; diff --git a/test/CodeGenCXX/mangle-98.cpp b/test/CodeGenCXX/mangle-98.cpp index a9ab6ca..a329caf 100644 --- a/test/CodeGenCXX/mangle-98.cpp +++ b/test/CodeGenCXX/mangle-98.cpp @@ -2,11 +2,11 @@ template <bool B> struct S3 {}; -// CHECK: define void @_Z1f2S3ILb1EE +// CHECK-LABEL: define void @_Z1f2S3ILb1EE void f(S3<true>) {} -// CHECK: define void @_Z1f2S3ILb0EE +// CHECK-LABEL: define void @_Z1f2S3ILb0EE void f(S3<false>) {} -// CHECK: define void @_Z2f22S3ILb1EE +// CHECK-LABEL: define void @_Z2f22S3ILb1EE void f2(S3<100>) {} diff --git a/test/CodeGenCXX/mangle-address-space.cpp b/test/CodeGenCXX/mangle-address-space.cpp index ff23c20..4a4a1f3 100644 --- a/test/CodeGenCXX/mangle-address-space.cpp +++ b/test/CodeGenCXX/mangle-address-space.cpp @@ -1,12 +1,12 @@ // RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s -// CHECK: define void @_Z2f0Pc +// CHECK-LABEL: define void @_Z2f0Pc void f0(char *p) { } -// CHECK: define void @_Z2f0PU3AS1c +// CHECK-LABEL: define void @_Z2f0PU3AS1c void f0(char __attribute__((address_space(1))) *p) { } struct OpaqueType; typedef OpaqueType __attribute__((address_space(100))) * OpaqueTypePtr; -// CHECK: define void @_Z2f0PU5AS10010OpaqueType +// CHECK-LABEL: define void @_Z2f0PU5AS10010OpaqueType void f0(OpaqueTypePtr) { } diff --git a/test/CodeGenCXX/mangle-alias-template.cpp b/test/CodeGenCXX/mangle-alias-template.cpp index 5ace0b0..b6719c5 100644 --- a/test/CodeGenCXX/mangle-alias-template.cpp +++ b/test/CodeGenCXX/mangle-alias-template.cpp @@ -15,7 +15,7 @@ template<typename,typename,typename> struct S {}; template<typename T, typename U> using U = S<T, int, U>; template<typename...Ts> void h(U<Ts...>, Ts...); -// CHECK: define void @_Z1zv( +// CHECK-LABEL: define void @_Z1zv( void z() { vector<int> VI; f(VI); diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp index 2d7a883..e935f51 100644 --- a/test/CodeGenCXX/mangle-exprs.cpp +++ b/test/CodeGenCXX/mangle-exprs.cpp @@ -70,22 +70,22 @@ namespace Casts { template <int N> T<N> f() { return T<N>(); } - // CHECK: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE + // CHECK-LABEL: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE template void implicit<4>(void*); - // CHECK: define weak_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK-LABEL: define weak_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void cstyle<4>(void*); - // CHECK: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK-LABEL: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void functional<4>(void*); - // CHECK: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK-LABEL: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void static_<4>(void*); - // CHECK: define weak_odr void @_ZN5Casts1fILi6EEENS_1TIXT_EEEv + // CHECK-LABEL: define weak_odr void @_ZN5Casts1fILi6EEENS_1TIXT_EEEv template T<6> f<6>(); - // CHECK: define weak_odr void @_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE( + // CHECK-LABEL: define weak_odr void @_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE( template void auto_<int>(int*); - // CHECK: define weak_odr void @_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE( + // CHECK-LABEL: define weak_odr void @_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE( template void scalar_<int>(int); } @@ -93,10 +93,10 @@ namespace test1 { short foo(short); int foo(int); - // CHECK: define linkonce_odr signext i16 @_ZN5test11aIsEEDTcl3foocvT__EEES1_( + // CHECK-LABEL: define linkonce_odr signext i16 @_ZN5test11aIsEEDTcl3foocvT__EEES1_( template <class T> auto a(T t) -> decltype(foo(T())) { return foo(t); } - // CHECK: define linkonce_odr signext i16 @_ZN5test11bIsEEDTcp3foocvT__EEES1_( + // CHECK-LABEL: define linkonce_odr signext i16 @_ZN5test11bIsEEDTcp3foocvT__EEES1_( template <class T> auto b(T t) -> decltype((foo)(T())) { return (foo)(t); } void test(short s) { @@ -124,7 +124,7 @@ namespace test2 { float baz(float(*)()); void fred(float(*)(), float); - // CHECK: define void @_ZN5test211instantiateEv + // CHECK-LABEL: define void @_ZN5test211instantiateEv void instantiate() { // CHECK: call void @_ZN5test21aIPFfvEEEvT_DTclfL0p_EE( a(foo, 0.0f); @@ -156,7 +156,7 @@ namespace test3 { int *member; }; - // CHECK: define void @_ZN5test311instantiateEv + // CHECK-LABEL: define void @_ZN5test311instantiateEv void instantiate() { X x; int *ip; diff --git a/test/CodeGenCXX/mangle-extreme.cpp b/test/CodeGenCXX/mangle-extreme.cpp index ef2d466..9fa678a 100644 --- a/test/CodeGenCXX/mangle-extreme.cpp +++ b/test/CodeGenCXX/mangle-extreme.cpp @@ -2,7 +2,7 @@ struct X { }; -// CHECK: define void @_Z1fPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP1XS13_S12_S11_S10_SZ_SY_SX_SW_SV_SU_ST_SS_SR_SQ_SP_SO_SN_SM_SL_SK_SJ_SI_SH_SG_SF_SE_SD_SC_SB_SA_S9_S8_S7_S6_S5_S4_S3_S2_S1_S0_S_( +// CHECK-LABEL: define void @_Z1fPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP1XS13_S12_S11_S10_SZ_SY_SX_SW_SV_SU_ST_SS_SR_SQ_SP_SO_SN_SM_SL_SK_SJ_SI_SH_SG_SF_SE_SD_SC_SB_SA_S9_S8_S7_S6_S5_S4_S3_S2_S1_S0_S_( void f(X****************************************, X****************************************, X***************************************, diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp index 0bd5ad2..659b437 100644 --- a/test/CodeGenCXX/mangle-lambdas.cpp +++ b/test/CodeGenCXX/mangle-lambdas.cpp @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s // CHECK: @_ZZNK7PR12917IJiiEE1nMUlvE_clEvE1n = linkonce_odr global i32 0 -// CHECK: @_ZZN7PR12917IJicdEEC1EicdEd_N1nE = linkonce_odr global i32 0 -// CHECK: @_ZZN7PR12917IJicdEEC1EicdEd0_N1nE = linkonce_odr global i32 0 -// CHECK: @_ZZN7PR12917IJicdEEC1EicdEd1_N1nE = linkonce_odr global i32 0 +// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd_NKUlvE_clEvE1n = linkonce_odr global i32 0 +// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd0_NKUlvE_clEvE1n = linkonce_odr global i32 0 +// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd1_NKUlvE_clEvE1n = linkonce_odr global i32 0 -// CHECK: define linkonce_odr void @_Z11inline_funci +// CHECK-LABEL: define linkonce_odr void @_Z11inline_funci inline void inline_func(int n) { // CHECK: call i32 @_ZZ11inline_funciENKUlvE_clEv int i = []{ return 1; }(); @@ -41,7 +41,7 @@ struct S { void S::g(int i = []{return 1;}(), int j = []{return 2; }()) {} -// CHECK: define void @_Z6test_S1S +// CHECK-LABEL: define void @_Z6test_S1S void test_S(S s) { // CHECK: call i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv // CHECK-NEXT: call i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv @@ -63,15 +63,15 @@ void test_S(S s) { } // Check the linkage of the lambda call operators used in test_S. -// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv // CHECK: ret i32 1 -// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv // CHECK: ret i32 2 -// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZZN1S1fEiiEd_NKUlvE_clEv // CHECK: ret i32 3 -// CHECK: define internal i32 @"_ZNK1S3$_0clEv" +// CHECK-LABEL: define internal i32 @"_ZNK1S3$_0clEv" // CHECK: ret i32 1 -// CHECK: define internal i32 @"_ZNK1S3$_1clEv" +// CHECK-LABEL: define internal i32 @"_ZNK1S3$_1clEv" // CHECK: ret i32 2 template<typename T> @@ -81,7 +81,7 @@ struct ST { T = []{return T(3);}()); }; -// CHECK: define void @_Z7test_ST2STIdE +// CHECK-LABEL: define void @_Z7test_ST2STIdE void test_ST(ST<double> st) { // CHECK: call double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv // CHECK-NEXT: call double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv @@ -94,11 +94,11 @@ void test_ST(ST<double> st) { } // Check the linkage of the lambda call operators used in test_ST. -// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv // CHECK: ret double 1 -// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv +// CHECK-LABEL: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv // CHECK: ret double 2 -// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr double @_ZZN2STIdE1fEddEd_NKUlvE_clEv // CHECK: ret double 3 template<typename T> @@ -106,6 +106,7 @@ struct StaticMembers { static T x; static T y; static T z; + static int (*f)(); }; template<typename T> int accept_lambda(T); @@ -119,39 +120,47 @@ T StaticMembers<T>::y = []{return 3;}(); template<typename T> T StaticMembers<T>::z = accept_lambda([]{return 4;}); -// CHECK: define internal void @__cxx_global_var_init() +template<typename T> +int (*StaticMembers<T>::f)() = []{return 5;}; + +// CHECK-LABEL: define internal void @__cxx_global_var_init() // CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv // CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv // CHECK-NEXT: add nsw -// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv // CHECK: ret i32 1 -// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv // CHECK: ret i32 2 template float StaticMembers<float>::x; -// CHECK: define internal void @__cxx_global_var_init1() +// CHECK-LABEL: define internal void @__cxx_global_var_init1() // CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv -// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv // CHECK: ret i32 3 template float StaticMembers<float>::y; -// CHECK: define internal void @__cxx_global_var_init2() +// CHECK-LABEL: define internal void @__cxx_global_var_init2() // CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_ // CHECK: declare i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_() template float StaticMembers<float>::z; -// CHECK: define internal void @__cxx_global_var_init3 +// CHECK-LABEL: define internal void @__cxx_global_var_init3() +// CHECK: call {{.*}} @_ZNK13StaticMembersIfE1fMUlvE_cvPFivEEv +// CHECK-LABEL: define linkonce_odr i32 ()* @_ZNK13StaticMembersIfE1fMUlvE_cvPFivEEv +template int (*StaticMembers<float>::f)(); + +// CHECK-LABEL: define internal void @__cxx_global_var_init4 // CHECK: call i32 @"_ZNK13StaticMembersIdE3$_2clEv" -// CHECK: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv" +// CHECK-LABEL: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv" // CHECK: ret i32 42 template<> double StaticMembers<double>::z = []{return 42; }(); template<typename T> void func_template(T = []{ return T(); }()); -// CHECK: define void @_Z17use_func_templatev() +// CHECK-LABEL: define void @_Z17use_func_templatev() void use_func_template() { - // CHECK: call i32 @"_ZZ13func_templateIiEvT_ENKS_IiE3$_3clEv" + // CHECK: call i32 @"_ZZ13func_templateIiEvT_ENK3$_3clEv" func_template<int>(); } @@ -183,7 +192,7 @@ namespace PR12123 { }; void B::h() { f(); } } -// CHECK: define linkonce_odr %"struct.PR12123::A"* @_ZZN7PR121231B1fERKSt9type_infoEd_NKUlvE_clEv +// CHECK-LABEL: define linkonce_odr %"struct.PR12123::A"* @_ZZN7PR121231B1fERKSt9type_infoEd_NKUlvE_clEv namespace PR12808 { template <typename> struct B { @@ -196,11 +205,11 @@ namespace PR12808 { void f() { b<int>(1); } - // CHECK: define linkonce_odr void @_ZZN7PR128081bIiEEviENKS0_IiEUlvE_clEv - // CHECK: define linkonce_odr i32 @_ZZZN7PR128081bIiEEviENKS0_IiEUlvE_clEvENKUlvE_clEv + // CHECK-LABEL: define linkonce_odr void @_ZZN7PR128081bIiEEviENKUlvE_clEv + // CHECK-LABEL: define linkonce_odr i32 @_ZZZN7PR128081bIiEEviENKUlvE_clEvENKUlvE_clEv } -// CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_ +// CHECK-LABEL: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_ struct Members { int x = [] { return 1; }() + [] { return 2; }(); @@ -208,7 +217,7 @@ struct Members { }; void test_Members() { - // CHECK: define linkonce_odr void @_ZN7MembersC2Ev + // CHECK-LABEL: define linkonce_odr void @_ZN7MembersC2Ev // CHECK: call i32 @_ZNK7Members1xMUlvE_clEv // CHECK-NEXT: call i32 @_ZNK7Members1xMUlvE0_clE // CHECK-NEXT: add nsw i32 @@ -232,21 +241,21 @@ void test_NestedInstantiation() { } // Check the linkage of the lambdas used in test_Members. -// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv // CHECK: ret i32 1 -// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE0_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZNK7Members1xMUlvE0_clEv // CHECK: ret i32 2 -// CHECK: define linkonce_odr i32 @_ZNK7Members1yMUlvE_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZNK7Members1yMUlvE_clEv // CHECK: ret i32 3 // Check linkage of the various lambdas. -// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE_clEv // CHECK: ret i32 1 -// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE0_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE0_clEv // CHECK: ret i32 -// CHECK: define linkonce_odr double @_ZZ11inline_funciENKUlvE1_clEv +// CHECK-LABEL: define linkonce_odr double @_ZZ11inline_funciENKUlvE1_clEv // CHECK: ret double -// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUliE_clEi +// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUliE_clEi // CHECK: ret i32 -// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE2_clEv +// CHECK-LABEL: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE2_clEv // CHECK: ret i32 17 diff --git a/test/CodeGenCXX/mangle-local-class-names.cpp b/test/CodeGenCXX/mangle-local-class-names.cpp index 3321460..8b950fc 100644 --- a/test/CodeGenCXX/mangle-local-class-names.cpp +++ b/test/CodeGenCXX/mangle-local-class-names.cpp @@ -55,3 +55,33 @@ void GORF (float IVAR1) } } +// CHECK: @_ZZ12OmittingCodefEN4SSSSC1E_0RKf +inline void OmittingCode(float x) { + if (0) { + struct SSSS { + float bv; + SSSS(const float& from): bv(from) { } + }; + + SSSS VAR1(x); + } + + struct SSSS { + float bv; + SSSS(const float& from): bv(from) { } + }; + + SSSS VAR2(x); +} +void CallOmittingCode() { OmittingCode(1); } + +// CHECK: @_ZZ15LocalAnonStructvENUt0_1gEv +inline void LocalAnonStruct() { + if (0) { + struct { void f() {} } x; + x.f(); + } + struct { void g() {} } y; + y.g(); +} +void CallLocalAnonStruct() { LocalAnonStruct(); } diff --git a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp index d03ba52..50a2383 100644 --- a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp @@ -1,123 +1,240 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix=X64 %s void foo(const unsigned int) {} // CHECK: "\01?foo@@YAXI@Z" +// X64: "\01?foo@@YAXI@Z" void foo(const double) {} // CHECK: "\01?foo@@YAXN@Z" +// X64: "\01?foo@@YAXN@Z" void bar(const volatile double) {} // CHECK: "\01?bar@@YAXN@Z" +// X64: "\01?bar@@YAXN@Z" void foo_pad(char * x) {} // CHECK: "\01?foo_pad@@YAXPAD@Z" +// X64: "\01?foo_pad@@YAXPEAD@Z" void foo_pbd(const char * x) {} // CHECK: "\01?foo_pbd@@YAXPBD@Z" +// X64: "\01?foo_pbd@@YAXPEBD@Z" void foo_pcd(volatile char * x) {} // CHECK: "\01?foo_pcd@@YAXPCD@Z" +// X64: "\01?foo_pcd@@YAXPECD@Z" void foo_qad(char * const x) {} // CHECK: "\01?foo_qad@@YAXQAD@Z" +// X64: "\01?foo_qad@@YAXQEAD@Z" void foo_rad(char * volatile x) {} // CHECK: "\01?foo_rad@@YAXRAD@Z" +// X64: "\01?foo_rad@@YAXREAD@Z" void foo_sad(char * const volatile x) {} // CHECK: "\01?foo_sad@@YAXSAD@Z" +// X64: "\01?foo_sad@@YAXSEAD@Z" void foo_papad(char ** x) {} // CHECK: "\01?foo_papad@@YAXPAPAD@Z" +// X64: "\01?foo_papad@@YAXPEAPEAD@Z" void foo_papbd(char const ** x) {} // CHECK: "\01?foo_papbd@@YAXPAPBD@Z" +// X64: "\01?foo_papbd@@YAXPEAPEBD@Z" void foo_papcd(char volatile ** x) {} // CHECK: "\01?foo_papcd@@YAXPAPCD@Z" +// X64: "\01?foo_papcd@@YAXPEAPECD@Z" void foo_pbqad(char * const* x) {} // CHECK: "\01?foo_pbqad@@YAXPBQAD@Z" +// X64: "\01?foo_pbqad@@YAXPEBQEAD@Z" void foo_pcrad(char * volatile* x) {} // CHECK: "\01?foo_pcrad@@YAXPCRAD@Z" +// X64: "\01?foo_pcrad@@YAXPECREAD@Z" void foo_qapad(char ** const x) {} // CHECK: "\01?foo_qapad@@YAXQAPAD@Z" +// X64: "\01?foo_qapad@@YAXQEAPEAD@Z" void foo_rapad(char ** volatile x) {} // CHECK: "\01?foo_rapad@@YAXRAPAD@Z" +// X64: "\01?foo_rapad@@YAXREAPEAD@Z" void foo_pbqbd(const char * const* x) {} // CHECK: "\01?foo_pbqbd@@YAXPBQBD@Z" +// X64: "\01?foo_pbqbd@@YAXPEBQEBD@Z" void foo_pbqcd(volatile char * const* x) {} // CHECK: "\01?foo_pbqcd@@YAXPBQCD@Z" +// X64: "\01?foo_pbqcd@@YAXPEBQECD@Z" void foo_pcrbd(const char * volatile* x) {} // CHECK: "\01?foo_pcrbd@@YAXPCRBD@Z" +// X64: "\01?foo_pcrbd@@YAXPECREBD@Z" void foo_pcrcd(volatile char * volatile* x) {} // CHECK: "\01?foo_pcrcd@@YAXPCRCD@Z" +// X64: "\01?foo_pcrcd@@YAXPECRECD@Z" void foo_aad(char &x) {} // CHECK: "\01?foo_aad@@YAXAAD@Z" +// X64: "\01?foo_aad@@YAXAEAD@Z" void foo_abd(const char &x) {} // CHECK: "\01?foo_abd@@YAXABD@Z" +// X64: "\01?foo_abd@@YAXAEBD@Z" void foo_aapad(char *&x) {} // CHECK: "\01?foo_aapad@@YAXAAPAD@Z" +// X64: "\01?foo_aapad@@YAXAEAPEAD@Z" void foo_aapbd(const char *&x) {} // CHECK: "\01?foo_aapbd@@YAXAAPBD@Z" +// X64: "\01?foo_aapbd@@YAXAEAPEBD@Z" void foo_abqad(char * const &x) {} // CHECK: "\01?foo_abqad@@YAXABQAD@Z" +// X64: "\01?foo_abqad@@YAXAEBQEAD@Z" void foo_abqbd(const char * const &x) {} // CHECK: "\01?foo_abqbd@@YAXABQBD@Z" +// X64: "\01?foo_abqbd@@YAXAEBQEBD@Z" void foo_aay144h(int (&x)[5][5]) {} // CHECK: "\01?foo_aay144h@@YAXAAY144H@Z" +// X64: "\01?foo_aay144h@@YAXAEAY144H@Z" void foo_aay144cbh(const int (&x)[5][5]) {} // CHECK: "\01?foo_aay144cbh@@YAXAAY144$$CBH@Z" +// X64: "\01?foo_aay144cbh@@YAXAEAY144$$CBH@Z" void foo_qay144h(int (&&x)[5][5]) {} // CHECK: "\01?foo_qay144h@@YAX$$QAY144H@Z" +// X64: "\01?foo_qay144h@@YAX$$QEAY144H@Z" void foo_qay144cbh(const int (&&x)[5][5]) {} // CHECK: "\01?foo_qay144cbh@@YAX$$QAY144$$CBH@Z" +// X64: "\01?foo_qay144cbh@@YAX$$QEAY144$$CBH@Z" void foo_p6ahxz(int x()) {} // CHECK: "\01?foo_p6ahxz@@YAXP6AHXZ@Z" +// X64: "\01?foo_p6ahxz@@YAXP6AHXZ@Z" void foo_a6ahxz(int (&x)()) {} // CHECK: "\01?foo_a6ahxz@@YAXA6AHXZ@Z" +// X64: "\01?foo_a6ahxz@@YAXA6AHXZ@Z" void foo_q6ahxz(int (&&x)()) {} // CHECK: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z" +// X64: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z" void foo_qay04h(int x[5][5]) {} // CHECK: "\01?foo_qay04h@@YAXQAY04H@Z" +// X64: "\01?foo_qay04h@@YAXQEAY04H@Z" void foo_qay04cbh(const int x[5][5]) {} // CHECK: "\01?foo_qay04cbh@@YAXQAY04$$CBH@Z" +// X64: "\01?foo_qay04cbh@@YAXQEAY04$$CBH@Z" typedef double Vector[3]; void foo(Vector*) {} // CHECK: "\01?foo@@YAXPAY02N@Z" +// X64: "\01?foo@@YAXPEAY02N@Z" void foo(Vector) {} // CHECK: "\01?foo@@YAXQAN@Z" +// X64: "\01?foo@@YAXQEAN@Z" void foo_const(const Vector) {} // CHECK: "\01?foo_const@@YAXQBN@Z" +// X64: "\01?foo_const@@YAXQEBN@Z" void foo_volatile(volatile Vector) {} // CHECK: "\01?foo_volatile@@YAXQCN@Z" +// X64: "\01?foo_volatile@@YAXQECN@Z" void foo(Vector*, const Vector, const double) {} // CHECK: "\01?foo@@YAXPAY02NQBNN@Z" +// X64: "\01?foo@@YAXPEAY02NQEBNN@Z" + +typedef void (*ConstFunPtr)(int *const d); +void foo_fnptrconst(ConstFunPtr f) { } +// CHECK: "\01?foo_fnptrconst@@YAXP6AXQAH@Z@Z" +// X64: "\01?foo_fnptrconst@@YAXP6AXQEAH@Z@Z" + +typedef void (*ArrayFunPtr)(int d[1]); +void foo_fnptrarray(ArrayFunPtr f) { } +// CHECK: "\01?foo_fnptrarray@@YAXP6AXQAH@Z@Z" +// X64: "\01?foo_fnptrarray@@YAXP6AXQEAH@Z@Z" + +void foo_fnptrbackref1(ArrayFunPtr f1, ArrayFunPtr f2) { } +// CHECK: "\01?foo_fnptrbackref1@@YAXP6AXQAH@Z1@Z" +// X64: "\01?foo_fnptrbackref1@@YAXP6AXQEAH@Z1@Z" + +void foo_fnptrbackref2(ArrayFunPtr f1, ConstFunPtr f2) { } +// CHECK: "\01?foo_fnptrbackref2@@YAXP6AXQAH@Z1@Z" +// X64: "\01?foo_fnptrbackref2@@YAXP6AXQEAH@Z1@Z" + +typedef void (*NormalFunPtr)(int *d); +void foo_fnptrbackref3(ArrayFunPtr f1, NormalFunPtr f2) { } +// CHECK: "\01?foo_fnptrbackref3@@YAXP6AXQAH@Z1@Z" +// X64: "\01?foo_fnptrbackref3@@YAXP6AXQEAH@Z1@Z" + +void foo_fnptrbackref4(NormalFunPtr f1, ArrayFunPtr f2) { } +// CHECK: "\01?foo_fnptrbackref4@@YAXP6AXPAH@Z1@Z" +// X64: "\01?foo_fnptrbackref4@@YAXP6AXPEAH@Z1@Z" + +ArrayFunPtr ret_fnptrarray() { return 0; } +// CHECK: "\01?ret_fnptrarray@@YAP6AXQAH@ZXZ" +// X64: "\01?ret_fnptrarray@@YAP6AXQEAH@ZXZ" + +// Test that we mangle the forward decl when we have a redeclaration with a +// slightly different type. +void mangle_fwd(char * const x); +void mangle_fwd(char * x) {} +// CHECK: "\01?mangle_fwd@@YAXQAD@Z" +// X64: "\01?mangle_fwd@@YAXQEAD@Z" + +void mangle_no_fwd(char * x) {} +// CHECK: "\01?mangle_no_fwd@@YAXPAD@Z" +// X64: "\01?mangle_no_fwd@@YAXPEAD@Z" + +// The first argument gets mangled as-if it were written "int *const" +// The second arg should not form a backref because it isn't qualified +void mangle_no_backref0(int[], int *) {} +// CHECK: "\01?mangle_no_backref0@@YAXQAHPAH@Z" +// X64: "\01?mangle_no_backref0@@YAXQEAHPEAH@Z" + +void mangle_no_backref1(int[], int *const) {} +// CHECK: "\01?mangle_no_backref1@@YAXQAHQAH@Z" +// X64: "\01?mangle_no_backref1@@YAXQEAHQEAH@Z" + +typedef void fun_type(void); +typedef void (*ptr_to_fun_type)(void); + +// Pointer to function types don't backref with function types +void mangle_no_backref2(fun_type, ptr_to_fun_type) {} +// CHECK: "\01?mangle_no_backref2@@YAXP6AXXZP6AXXZ@Z" +// X64: "\01?mangle_no_backref2@@YAXP6AXXZP6AXXZ@Z" + +void mangle_yes_backref0(int[], int []) {} +// CHECK: "\01?mangle_yes_backref0@@YAXQAH0@Z" +// X64: "\01?mangle_yes_backref0@@YAXQEAH0@Z" + +void mangle_yes_backref1(int *const, int *const) {} +// CHECK: "\01?mangle_yes_backref1@@YAXQAH0@Z" +// X64: "\01?mangle_yes_backref1@@YAXQEAH0@Z" + +void mangle_yes_backref2(fun_type *const[], ptr_to_fun_type const[]) {} +// CHECK: "\01?mangle_yes_backref2@@YAXQBQ6AXXZ0@Z" +// X64: "\01?mangle_yes_backref2@@YAXQEBQ6AXXZ0@Z" + +void mangle_yes_backref3(ptr_to_fun_type *const, void (**const)(void)) {} +// CHECK: "\01?mangle_yes_backref3@@YAXQAP6AXXZ0@Z" +// X64: "\01?mangle_yes_backref3@@YAXQEAP6AXXZ0@Z" diff --git a/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp index fbc6492..e10cc8e 100644 --- a/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp +++ b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp @@ -107,7 +107,7 @@ void call_l_foo(L* l) { l->foo(I<A>()); } void foo(I<A> x) {} // CHECK: "\01?foo@PR13207@@YAXV?$I@VA@PR13207@@@1@@Z" void foo2(I<A> x, I<A> y) { } -// CHECK "\01?foo2@PR13207@@YAXV?$I@VA@PR13207@@@1@0@Z" +// CHECK: "\01?foo2@PR13207@@YAXV?$I@VA@PR13207@@@1@0@Z" void bar(J<A,B> x) {} // CHECK: "\01?bar@PR13207@@YAXV?$J@VA@PR13207@@VB@2@@1@@Z" void spam(K<A,B,C> x) {} @@ -163,3 +163,31 @@ void foobar(NC::Y<NB::Y<NA::Y<NA::X> > > x) {} // CHECK: "\01?foobar@NC@PR13207@@YAXV?$Y@V?$Y@V?$Y@VX@NA@PR13207@@@NA@PR13207@@@NB@PR13207@@@12@@Z" } } + +// Function template names are not considered for backreferencing, but normal +// function names are. +namespace fn_space { +struct RetVal { int hash; }; +template <typename T> +RetVal fun_tmpl(const T &t) { return RetVal(); } +RetVal fun_normal(int t) { return RetVal(); } +void fun_instantiate() { + fun_normal(1); + fun_tmpl(1); +} +// CHECK: "\01?fun_normal@fn_space@@YA?AURetVal@1@H@Z" +// CHECK: "\01??$fun_tmpl@H@fn_space@@YA?AURetVal@0@ABH@Z" + +template <typename T, RetVal (*F)(T)> +RetVal fun_tmpl_recurse(T t) { + if (!t) + return RetVal(); + return F(t - 1); +} +RetVal ident(int x) { return RetVal(); } +void fun_instantiate2() { + fun_tmpl_recurse<int, fun_tmpl_recurse<int, ident> >(10); +} +// CHECK: "\01??$fun_tmpl_recurse@H$1??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@1@H@Z@fn_space@@YA?AURetVal@0@H@Z" +// CHECK: "\01??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@0@H@Z" +} diff --git a/test/CodeGenCXX/mangle-ms-back-references.cpp b/test/CodeGenCXX/mangle-ms-back-references.cpp index 5f93590..4f17326 100644 --- a/test/CodeGenCXX/mangle-ms-back-references.cpp +++ b/test/CodeGenCXX/mangle-ms-back-references.cpp @@ -61,3 +61,8 @@ void h2(void (*f_ptr)(void *), void *arg) {} PInt3Func h3(PInt3Func x, PInt3Func y, int* z) { return 0; } // CHECK: "\01?h3@@YAP6APAHPAH0@ZP6APAH00@Z10@Z" + +namespace foo { +void foo() { } +// CHECK: "\01?foo@0@YAXXZ" +} diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp index 10e6824..514f573 100644 --- a/test/CodeGenCXX/mangle-ms-templates.cpp +++ b/test/CodeGenCXX/mangle-ms-templates.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -cxx-abi microsoft -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s template<typename T> class Class { @@ -23,6 +24,18 @@ class IntTemplate { IntTemplate() {} }; +template<long long param> +class LongLongTemplate { + public: + LongLongTemplate() {} +}; + +template<unsigned long long param> +class UnsignedLongLongTemplate { + public: + UnsignedLongLongTemplate() {} +}; + template<> class BoolTemplate<true> { public: @@ -33,65 +46,113 @@ class BoolTemplate<true> { void template_mangling() { Class<Typename> c1; // CHECK: call {{.*}} @"\01??0?$Class@VTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@VTypename@@@@QEAA@XZ" Class<const Typename> c1_const; // CHECK: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QEAA@XZ" Class<volatile Typename> c1_volatile; // CHECK: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QEAA@XZ" Class<const volatile Typename> c1_cv; // CHECK: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QEAA@XZ" Class<Nested<Typename> > c2; // CHECK: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QEAA@XZ" Class<int * const> c_intpc; // CHECK: call {{.*}} @"\01??0?$Class@QAH@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@QEAH@@QEAA@XZ" Class<int()> c_ft; // CHECK: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QEAA@XZ" Class<int[]> c_inti; // CHECK: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QEAA@XZ" Class<int[5]> c_int5; // CHECK: call {{.*}} @"\01??0?$Class@$$BY04H@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY04H@@QEAA@XZ" Class<const int[5]> c_intc5; // CHECK: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QEAA@XZ" Class<int * const[5]> c_intpc5; // CHECK: call {{.*}} @"\01??0?$Class@$$BY04QAH@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$Class@$$BY04QEAH@@QEAA@XZ" BoolTemplate<false> _false; // CHECK: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QEAA@XZ" BoolTemplate<true> _true; // PR13158 _true.Foo(1); // CHECK: call {{.*}} @"\01??0?$BoolTemplate@$00@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$BoolTemplate@$00@@QEAA@XZ" // CHECK: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QAEXH@Z" +// X64: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QEAAXH@Z" IntTemplate<0> zero; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0A@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0A@@@QEAA@XZ" IntTemplate<5> five; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$04@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$04@@QEAA@XZ" IntTemplate<11> eleven; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QEAA@XZ" IntTemplate<256> _256; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0BAA@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0BAA@@@QEAA@XZ" IntTemplate<513> _513; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0CAB@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0CAB@@@QEAA@XZ" IntTemplate<1026> _1026; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0EAC@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0EAC@@@QEAA@XZ" IntTemplate<65535> ffff; // CHECK: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QEAA@XZ" + + IntTemplate<-1> neg_1; +// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?0@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0?0@@QEAA@XZ" + IntTemplate<-9> neg_9; +// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?8@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0?8@@QEAA@XZ" + IntTemplate<-10> neg_10; +// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?9@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0?9@@QEAA@XZ" + IntTemplate<-11> neg_11; +// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0?L@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$IntTemplate@$0?L@@@QEAA@XZ" + + LongLongTemplate<-9223372036854775807LL-1LL> int64_min; +// CHECK: call {{.*}} @"\01??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QEAA@XZ" + LongLongTemplate<9223372036854775807LL> int64_max; +// CHECK: call {{.*}} @"\01??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QEAA@XZ" + UnsignedLongLongTemplate<18446744073709551615ULL> uint64_max; +// CHECK: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QEAA@XZ" + UnsignedLongLongTemplate<(unsigned long long)-1> uint64_neg_1; +// CHECK: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QAE@XZ" +// X64: call {{.*}} @"\01??0?$UnsignedLongLongTemplate@$0?0@@QEAA@XZ" } namespace space { template<class T> const T& foo(const T& l) { return l; } } // CHECK: "\01??$foo@H@space@@YAABHABH@Z" +// X64: "\01??$foo@H@space@@YAAEBHAEBH@Z" void use() { space::foo(42); @@ -108,4 +169,96 @@ void FunctionPointerTemplate() { void spam() { FunctionPointerTemplate<spam>(); // CHECK: "\01??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ" +// X64: "\01??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ" +} + +// Unlike Itanium, there is no character code to indicate an argument pack. +// Tested with MSVC 2013, the first version which supports variadic templates. + +template <typename ...Ts> void variadic_fn_template(const Ts &...args) { } +void variadic_fn_instantiate() { + variadic_fn_template(0, 1, 3, 4); + variadic_fn_template(0, 1, 'a', "b"); +} +// CHECK: "\01??$variadic_fn_template@HHHH@@YAXABH000@Z" +// CHECK: "\01??$variadic_fn_template@HHD$$BY01D@@YAXABH0ABDAAY01$$CBD@Z" + +template <typename ...Ts> +struct VariadicClass { + VariadicClass() { } + int x; +}; +void variadic_class_instantiate() { + VariadicClass<int, char, bool> a; + VariadicClass<bool, char, int> b; +} +// CHECK: call {{.*}} @"\01??0?$VariadicClass@HD_N@@QAE@XZ" +// CHECK: call {{.*}} @"\01??0?$VariadicClass@_NDH@@QAE@XZ" + +template <typename T> +struct Second {}; + +template <typename T, template <class> class> +struct Type {}; + +template <template <class> class T> +struct Type2 {}; + +template <template <class> class T, bool B> +struct Thing; + +template <template <class> class T> +struct Thing<T, false> { }; + +template <template <class> class T> +struct Thing<T, true> { }; + +void template_template_fun(Type<Thing<Second, true>, Second>) { } +// CHECK: "\01?template_template_fun@@YAXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z" + +template <typename T> +void template_template_specialization(); + +template <> +void template_template_specialization<void (Type<Thing<Second, true>, Second>)>() { +} +// CHECK: "\01??$template_template_specialization@$$A6AXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z@@YAXXZ" + +// PR16788 +template <decltype(nullptr)> struct S1 {}; +void f(S1<nullptr>) {} +// CHECK: "\01?f@@YAXU?$S1@$0A@@@@Z" + +struct record { + int first; + int second; +}; +template <const record &> +struct type1 { +}; +extern const record inst; +void recref(type1<inst>) {} +// CHECK: "\01?recref@@YAXU?$type1@$E?inst@@3Urecord@@B@@@Z" + +struct _GUID {}; +struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid; + +template <typename T, const _GUID *G = &__uuidof(T)> +struct UUIDType1 {}; + +template <typename T, const _GUID &G = __uuidof(T)> +struct UUIDType2 {}; + +void fun(UUIDType1<uuid> a) {} +// CHECK: "\01?fun@@YAXU?$UUIDType1@Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z" +void fun(UUIDType2<uuid> b) {} +// CHECK: "\01?fun@@YAXU?$UUIDType2@Uuuid@@$E?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z" + +template <typename T> struct TypeWithFriendDefinition { + friend void FunctionDefinedWithInjectedName(TypeWithFriendDefinition<T>) {} +}; +// CHECK: call {{.*}} @"\01?FunctionDefinedWithInjectedName@@YAXU?$TypeWithFriendDefinition@H@@@Z" +void CallFunctionDefinedWithInjectedName() { + FunctionDefinedWithInjectedName(TypeWithFriendDefinition<int>()); } +// CHECK: @"\01?FunctionDefinedWithInjectedName@@YAXU?$TypeWithFriendDefinition@H@@@Z" diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp index 1b98a84..68ec2b3 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -1,57 +1,51 @@ -// RUN: %clang_cc1 -fms-extensions -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s -// RUN: %clang_cc1 -fms-compatibility -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s - -// CHECK: @"\01?a@@3HA" -// CHECK: @"\01?b@N@@3HA" -// CHECK: @"\01?anonymous@?A@N@@3HA" -// CHECK: @c -// CHECK: @"\01?d@foo@@0FB" -// CHECK: @"\01?e@foo@@1JC" -// CHECK: @"\01?f@foo@@2DD" -// CHECK: @"\01?g@bar@@2HA" -// CHECK: @"\01?h1@@3QAHA" -// CHECK: @"\01?h2@@3QBHB" -// CHECK: @"\01?i@@3PAY0BE@HA" -// CHECK: @"\01?j@@3P6GHCE@ZA" -// CHECK: @"\01?k@@3PTfoo@@DA" -// CHECK: @"\01?l@@3P8foo@@AEHH@ZA" -// CHECK: @"\01?color1@@3PANA" -// CHECK: @"\01?color2@@3QBNB" -// CHECK: @"\01?color3@@3QAY02$$CBNA" -// CHECK: @"\01?color4@@3QAY02$$CBNA" +// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -std=c++11 | FileCheck %s +// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 -std=c++11| FileCheck -check-prefix X64 %s int a; +// CHECK-DAG: @"\01?a@@3HA" namespace N { int b; +// CHECK-DAG: @"\01?b@N@@3HA" namespace { int anonymous; +// CHECK-DAG: @"\01?anonymous@?A@N@@3HA" } } static int c; +// CHECK-DAG: @c + int _c(void) {return N::anonymous + c;} -// CHECK: @"\01?_c@@YAHXZ" +// CHECK-DAG: @"\01?_c@@YAHXZ" +// X64-DAG: @"\01?_c@@YAHXZ" class foo { static const short d; +// CHECK-DAG: @"\01?d@foo@@0FB" protected: static volatile long e; +// CHECK-DAG: @"\01?e@foo@@1JC" public: static const volatile char f; +// CHECK-DAG: @"\01?f@foo@@2DD" int operator+(int a); foo(){} -//CHECK: @"\01??0foo@@QAE@XZ" +// CHECK-DAG: @"\01??0foo@@QAE@XZ" +// X64-DAG: @"\01??0foo@@QEAA@XZ" ~foo(){} -//CHECK: @"\01??1foo@@QAE@XZ" +// CHECK-DAG: @"\01??1foo@@QAE@XZ" +// X64-DAG: @"\01??1foo@@QEAA@XZ foo(int i){} -//CHECK: @"\01??0foo@@QAE@H@Z" +// CHECK-DAG: @"\01??0foo@@QAE@H@Z" +// X64-DAG: @"\01??0foo@@QEAA@H@Z" foo(char *q){} -//CHECK: @"\01??0foo@@QAE@PAD@Z" +// CHECK-DAG: @"\01??0foo@@QAE@PAD@Z" +// X64-DAG: @"\01??0foo@@QEAA@PEAD@Z" static foo* static_method() { return 0; } @@ -76,13 +70,16 @@ enum quux { }; foo bar() { return foo(); } -//CHECK: @"\01?bar@@YA?AVfoo@@XZ" +// CHECK-DAG: @"\01?bar@@YA?AVfoo@@XZ" +// X64-DAG: @"\01?bar@@YA?AVfoo@@XZ" int foo::operator+(int a) { -//CHECK: @"\01??Hfoo@@QAEHH@Z" +// CHECK-DAG: @"\01??Hfoo@@QAEHH@Z" +// X64-DAG: @"\01??Hfoo@@QEAAHH@Z" foo::static_method(); -//CHECK: @"\01?static_method@foo@@SAPAV1@XZ" +// CHECK-DAG: @"\01?static_method@foo@@SAPAV1@XZ" +// X64-DAG: @"\01?static_method@foo@@SAPEAV1@XZ" bar(); return a; } @@ -92,106 +89,278 @@ volatile long foo::e; const volatile char foo::f = 'C'; int bar::g; +// CHECK-DAG: @"\01?g@bar@@2HA" extern int * const h1 = &a; +// CHECK-DAG: @"\01?h1@@3QAHA" extern const int * const h2 = &a; +// CHECK-DAG: @"\01?h2@@3QBHB" int i[10][20]; +// CHECK-DAG: @"\01?i@@3PAY0BE@HA" int (__stdcall *j)(signed char, unsigned char); +// CHECK-DAG: @"\01?j@@3P6GHCE@ZA" const volatile char foo2::*k; +// CHECK-DAG: @"\01?k@@3PTfoo@@DT1@" +// X64-DAG: @"\01?k@@3PETfoo@@DET1@" int (foo2::*l)(int); +// CHECK-DAG: @"\01?l@@3P8foo@@AEHH@ZQ1@" // Static functions are mangled, too. // Also make sure calling conventions, arglists, and throw specs work. static void __stdcall alpha(float a, double b) throw() {} bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) { -// CHECK: @"\01?beta@@YI_N_J_W@Z" +// CHECK-DAG: @"\01?beta@@YI_N_J_W@Z" +// X64-DAG: @"\01?beta@@YA_N_J_W@Z" alpha(0.f, 0.0); return false; } -// CHECK: @"\01?alpha@@YGXMN@Z" -// X64: @"\01?alpha@@YAXMN@Z" +// CHECK-DAG: @"\01?alpha@@YGXMN@Z" +// X64-DAG: @"\01?alpha@@YAXMN@Z" // Make sure tag-type mangling works. void gamma(class foo, struct bar, union baz, enum quux) {} -// CHECK: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z" +// CHECK-DAG: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z" +// X64-DAG: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z" // Make sure pointer/reference-type mangling works. void delta(int * const a, const long &) {} -// CHECK: @"\01?delta@@YAXQAHABJ@Z" +// CHECK-DAG: @"\01?delta@@YAXQAHABJ@Z" +// X64-DAG: @"\01?delta@@YAXQEAHAEBJ@Z" // Array mangling. void epsilon(int a[][10][20]) {} -// CHECK: @"\01?epsilon@@YAXQAY19BE@H@Z" +// CHECK-DAG: @"\01?epsilon@@YAXQAY19BE@H@Z" +// X64-DAG: @"\01?epsilon@@YAXQEAY19BE@H@Z" void zeta(int (*)(int, int)) {} -// CHECK: @"\01?zeta@@YAXP6AHHH@Z@Z" +// CHECK-DAG: @"\01?zeta@@YAXP6AHHH@Z@Z" +// X64-DAG: @"\01?zeta@@YAXP6AHHH@Z@Z" // Blocks mangling (Clang extension). A block should be mangled slightly // differently from a similar function pointer. void eta(int (^)(int, int)) {} -// CHECK: @"\01?eta@@YAXP_EAHHH@Z@Z" +// CHECK-DAG: @"\01?eta@@YAXP_EAHHH@Z@Z" typedef int theta_arg(int,int); void theta(theta_arg^ block) {} -// CHECK: @"\01?theta@@YAXP_EAHHH@Z@Z" +// CHECK-DAG: @"\01?theta@@YAXP_EAHHH@Z@Z" void operator_new_delete() { char *ptr = new char; -// CHECK: @"\01??2@YAPAXI@Z" +// CHECK-DAG: @"\01??2@YAPAXI@Z" delete ptr; -// CHECK: @"\01??3@YAXPAX@Z" +// CHECK-DAG: @"\01??3@YAXPAX@Z" char *array = new char[42]; -// CHECK: @"\01??_U@YAPAXI@Z" +// CHECK-DAG: @"\01??_U@YAPAXI@Z" delete [] array; -// CHECK: @"\01??_V@YAXPAX@Z" +// CHECK-DAG: @"\01??_V@YAXPAX@Z" } // PR13022 void (redundant_parens)(); void redundant_parens_use() { redundant_parens(); } -// CHECK: @"\01?redundant_parens@@YAXXZ" +// CHECK-DAG: @"\01?redundant_parens@@YAXXZ" +// X64-DAG: @"\01?redundant_parens@@YAXXZ" // PR13047 typedef double RGB[3]; RGB color1; +// CHECK-DAG: @"\01?color1@@3PANA" extern const RGB color2 = {}; +// CHECK-DAG: @"\01?color2@@3QBNB" extern RGB const color3[5] = {}; +// CHECK-DAG: @"\01?color3@@3QAY02$$CBNA" extern RGB const ((color4)[5]) = {}; +// CHECK-DAG: @"\01?color4@@3QAY02$$CBNA" + +struct B; +volatile int B::* volatile memptr1; +// X64-DAG: @"\01?memptr1@@3RESB@@HES1@" +volatile int B::* memptr2; +// X64-DAG: @"\01?memptr2@@3PESB@@HES1@" +int B::* volatile memptr3; +// X64-DAG: @"\01?memptr3@@3REQB@@HEQ1@" +typedef int (*fun)(); +volatile fun B::* volatile funmemptr1; +// X64-DAG: @"\01?funmemptr1@@3RESB@@R6AHXZES1@" +volatile fun B::* funmemptr2; +// X64-DAG: @"\01?funmemptr2@@3PESB@@R6AHXZES1@" +fun B::* volatile funmemptr3; +// X64-DAG: @"\01?funmemptr3@@3REQB@@P6AHXZEQ1@" +void (B::* volatile memptrtofun1)(); +// X64-DAG: @"\01?memptrtofun1@@3R8B@@EAAXXZEQ1@" +const void (B::* memptrtofun2)(); +// X64-DAG: @"\01?memptrtofun2@@3P8B@@EAAXXZEQ1@" +volatile void (B::* memptrtofun3)(); +// X64-DAG: @"\01?memptrtofun3@@3P8B@@EAAXXZEQ1@" +int (B::* volatile memptrtofun4)(); +// X64-DAG: @"\01?memptrtofun4@@3R8B@@EAAHXZEQ1@" +volatile int (B::* memptrtofun5)(); +// X64-DAG: @"\01?memptrtofun5@@3P8B@@EAA?CHXZEQ1@" +const int (B::* memptrtofun6)(); +// X64-DAG: @"\01?memptrtofun6@@3P8B@@EAA?BHXZEQ1@" +fun (B::* volatile memptrtofun7)(); +// X64-DAG: @"\01?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1@" +volatile fun (B::* memptrtofun8)(); +// X64-DAG: @"\01?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1@" +const fun (B::* memptrtofun9)(); +// X64-DAG: @"\01?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1@" // PR12603 enum E {}; -// CHECK: "\01?fooE@@YA?AW4E@@XZ" +// CHECK-DAG: "\01?fooE@@YA?AW4E@@XZ" +// X64-DAG: "\01?fooE@@YA?AW4E@@XZ" E fooE() { return E(); } class X {}; -// CHECK: "\01?fooX@@YA?AVX@@XZ" +// CHECK-DAG: "\01?fooX@@YA?AVX@@XZ" +// X64-DAG: "\01?fooX@@YA?AVX@@XZ" X fooX() { return X(); } namespace PR13182 { extern char s0[]; - // CHECK: @"\01?s0@PR13182@@3PADA" + // CHECK-DAG: @"\01?s0@PR13182@@3PADA" extern char s1[42]; - // CHECK: @"\01?s1@PR13182@@3PADA" + // CHECK-DAG: @"\01?s1@PR13182@@3PADA" extern const char s2[]; - // CHECK: @"\01?s2@PR13182@@3QBDB" + // CHECK-DAG: @"\01?s2@PR13182@@3QBDB" extern const char s3[42]; - // CHECK: @"\01?s3@PR13182@@3QBDB" + // CHECK-DAG: @"\01?s3@PR13182@@3QBDB" extern volatile char s4[]; - // CHECK: @"\01?s4@PR13182@@3RCDC" + // CHECK-DAG: @"\01?s4@PR13182@@3RCDC" extern const volatile char s5[]; - // CHECK: @"\01?s5@PR13182@@3SDDD" + // CHECK-DAG: @"\01?s5@PR13182@@3SDDD" extern const char* const* s6; - // CHECK: @"\01?s6@PR13182@@3PBQBDB" + // CHECK-DAG: @"\01?s6@PR13182@@3PBQBDB" char foo() { return s0[0] + s1[0] + s2[0] + s3[0] + s4[0] + s5[0] + s6[0][0]; } } + +extern "C" inline void extern_c_func() { + static int local; +// CHECK-DAG: @"\01?local@?1??extern_c_func@@9@4HA" +// X64-DAG: @"\01?local@?1??extern_c_func@@9@4HA" +} + +void call_extern_c_func() { + extern_c_func(); +} + +int main() { return 0; } +// CHECK-DAG: @main +// X64-DAG: @main + +int wmain() { return 0; } +// CHECK-DAG: @wmain +// X64-DAG: @wmain + +int WinMain() { return 0; } +// CHECK-DAG: @WinMain +// X64-DAG: @WinMain + +int wWinMain() { return 0; } +// CHECK-DAG: @wWinMain +// X64-DAG: @wWinMain + +int DllMain() { return 0; } +// CHECK-DAG: @DllMain +// X64-DAG: @DllMain + +inline int inline_function_with_local_type() { + static struct { + int a_field; + } static_variable_in_inline_function = { 20 }, second_static = { 40 }; + // CHECK: @"\01?static_variable_in_inline_function@?1??inline_function_with_local_type@@YAHXZ@4U<unnamed-type-static_variable_in_inline_function>@?1??1@YAHXZ@A" + + return static_variable_in_inline_function.a_field + second_static.a_field; +} + +int call_inline_function_with_local_type() { + return inline_function_with_local_type(); +} + +template <typename T> +inline int templated_inline_function_with_local_type() { + static struct { + int a_field; + } static_variable_in_templated_inline_function = { 20 }, + second_static = { 40 }; + // CHECK: @"\01?static_variable_in_templated_inline_function@?1???$templated_inline_function_with_local_type@H@@YAHXZ@4U<unnamed-type-static_variable_in_templated_inline_function>@?1???$templated_inline_function_with_local_type@H@@YAHXZ@A" + + return static_variable_in_templated_inline_function.a_field + + second_static.a_field; +} + +int call_templated_inline_function_with_local_type() { + return templated_inline_function_with_local_type<int>(); +} + +// PR17371 +struct OverloadedNewDelete { + // __cdecl + void *operator new(__SIZE_TYPE__); + void *operator new[](__SIZE_TYPE__); + void operator delete(void *); + void operator delete[](void *); + // __thiscall + int operator+(int); +}; + +void *OverloadedNewDelete::operator new(__SIZE_TYPE__ s) { return 0; } +void *OverloadedNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; } +void OverloadedNewDelete::operator delete(void *) { } +void OverloadedNewDelete::operator delete[](void *) { } +int OverloadedNewDelete::operator+(int x) { return x; }; + +// CHECK-DAG: ??2OverloadedNewDelete@@SAPAXI@Z +// CHECK-DAG: ??_UOverloadedNewDelete@@SAPAXI@Z +// CHECK-DAG: ??3OverloadedNewDelete@@SAXPAX@Z +// CHECK-DAG: ??_VOverloadedNewDelete@@SAXPAX@Z +// CHECK-DAG: ??HOverloadedNewDelete@@QAEHH@Z + +// X64-DAG: ??2OverloadedNewDelete@@SAPEAX_K@Z +// X64-DAG: ??_UOverloadedNewDelete@@SAPEAX_K@Z +// X64-DAG: ??3OverloadedNewDelete@@SAXPEAX@Z +// X64-DAG: ??_VOverloadedNewDelete@@SAXPEAX@Z +// X64-DAG: ??HOverloadedNewDelete@@QEAAHH@Z + +// Indirecting the function type through a typedef will require a calling +// convention adjustment before building the method decl. + +typedef void *__thiscall OperatorNewType(__SIZE_TYPE__); +typedef void __thiscall OperatorDeleteType(void *); + +struct TypedefNewDelete { + OperatorNewType operator new; + OperatorNewType operator new[]; + OperatorDeleteType operator delete; + OperatorDeleteType operator delete[]; +}; + +void *TypedefNewDelete::operator new(__SIZE_TYPE__ s) { return 0; } +void *TypedefNewDelete::operator new[](__SIZE_TYPE__ s) { return 0; } +void TypedefNewDelete::operator delete(void *) { } +void TypedefNewDelete::operator delete[](void *) { } + +// CHECK-DAG: ??2TypedefNewDelete@@SAPAXI@Z +// CHECK-DAG: ??_UTypedefNewDelete@@SAPAXI@Z +// CHECK-DAG: ??3TypedefNewDelete@@SAXPAX@Z +// CHECK-DAG: ??_VTypedefNewDelete@@SAXPAX@Z + +namespace PR18022 { + +struct { } a; +decltype(a) fun(decltype(a) x, decltype(a)) { return x; } +// CHECK-DAG: ?fun@PR18022@@YA?AU<unnamed-type-a>@1@U21@0@Z + +} diff --git a/test/CodeGenCXX/mangle-neon-vectors.cpp b/test/CodeGenCXX/mangle-neon-vectors.cpp index 3723deb..249ec2e 100644 --- a/test/CodeGenCXX/mangle-neon-vectors.cpp +++ b/test/CodeGenCXX/mangle-neon-vectors.cpp @@ -1,6 +1,7 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple arm-none-linux-gnueabi -target-feature +neon %s -emit-llvm -o - | FileCheck %s typedef float float32_t; +typedef __fp16 float16_t; typedef signed char poly8_t; typedef short poly16_t; typedef unsigned long long uint64_t; @@ -11,8 +12,10 @@ typedef __attribute__((neon_vector_type(1))) uint64_t uint64x1_t; typedef __attribute__((neon_vector_type(2))) uint64_t uint64x2_t; typedef __attribute__((neon_vector_type(2))) float32_t float32x2_t; typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t; -typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t; -typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t; +typedef __attribute__((neon_vector_type(4))) float16_t float16x4_t; +typedef __attribute__((neon_vector_type(8))) float16_t float16x8_t; +typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t; +typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t; // CHECK: 16__simd64_int32_t void f1(int32x2_t v) { } @@ -26,7 +29,11 @@ void f4(uint64x2_t v) { } void f5(float32x2_t v) { } // CHECK: 19__simd128_float32_t void f6(float32x4_t v) { } +// CHECK: 18__simd64_float16_t +void f7(float16x4_t v) {} +// CHECK: 19__simd128_float16_t +void f8(float16x8_t v) {} // CHECK: 17__simd128_poly8_t -void f7(poly8x16_t v) { } +void f9(poly8x16_t v) {} // CHECK: 18__simd128_poly16_t -void f8(poly16x8_t v) { } +void f10(poly16x8_t v) {} diff --git a/test/CodeGenCXX/mangle-nullptr-arg.cpp b/test/CodeGenCXX/mangle-nullptr-arg.cpp index 07bf52f..b55ea6d 100644 --- a/test/CodeGenCXX/mangle-nullptr-arg.cpp +++ b/test/CodeGenCXX/mangle-nullptr-arg.cpp @@ -2,15 +2,15 @@ template<int *ip> struct IP {}; -// CHECK: define void @_Z5test12IPILPi0EE +// CHECK-LABEL: define void @_Z5test12IPILPi0EE void test1(IP<nullptr>) {} struct X{ }; template<int X::*pm> struct PM {}; -// CHECK: define void @_Z5test22PMILM1Xi0EE +// CHECK-LABEL: define void @_Z5test22PMILM1Xi0EE void test2(PM<nullptr>) { } -// CHECK: define void @_Z5test316DependentTypePtrIPiLS0_0EE +// CHECK-LABEL: define void @_Z5test316DependentTypePtrIPiLS0_0EE template<typename T, T x> struct DependentTypePtr {}; void test3(DependentTypePtr<int*,nullptr>) { } diff --git a/test/CodeGenCXX/mangle-ref-qualifiers.cpp b/test/CodeGenCXX/mangle-ref-qualifiers.cpp index ce2af50..4552c93 100644 --- a/test/CodeGenCXX/mangle-ref-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ref-qualifiers.cpp @@ -5,17 +5,17 @@ struct X { int h() const &&; }; -// CHECK: define i32 @_ZNR1X1fEv +// CHECK-LABEL: define i32 @_ZNR1X1fEv int X::f() & { return 0; } -// CHECK: define i32 @_ZNO1X1gEv +// CHECK-LABEL: define i32 @_ZNO1X1gEv int X::g() && { return 0; } -// CHECK: define i32 @_ZNKO1X1hEv +// CHECK-LABEL: define i32 @_ZNKO1X1hEv int X::h() const && { return 0; } -// CHECK: define void @_Z1fM1XFivREMS_FivOEMS_KFivOE +// CHECK-LABEL: define void @_Z1fM1XFivREMS_FivOEMS_KFivOE void f(int (X::*)() &, int (X::*)() &&, int (X::*)() const&&) { } -// CHECK: define void @_Z1g1AIFivEES_IFivREES_IFivOEES_IKFivEES_IKFivREES_IKFivOEES_IVKFivEES_IVKFivREES_IVKFivOEE() +// CHECK-LABEL: define void @_Z1g1AIFivEES_IFivREES_IFivOEES_IKFivEES_IKFivREES_IKFivOEES_IVKFivEES_IVKFivREES_IVKFivOEE() template <class T> struct A {}; void g(A<int()>, A<int()&>, A<int()&&>, A<int() const>, A<int() const &>, A<int() const &&>, diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp index 04e3e84..6277c7a 100644 --- a/test/CodeGenCXX/mangle-subst-std.cpp +++ b/test/CodeGenCXX/mangle-subst-std.cpp @@ -15,8 +15,8 @@ namespace std { struct A { A(); }; - // CHECK: define void @_ZNSt1AC1Ev(%"struct.std::A"* %this) unnamed_addr - // CHECK: define void @_ZNSt1AC2Ev(%"struct.std::A"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZNSt1AC1Ev(%"struct.std::A"* %this) unnamed_addr + // CHECK-LABEL: define void @_ZNSt1AC2Ev(%"struct.std::A"* %this) unnamed_addr A::A() { } }; @@ -24,14 +24,14 @@ namespace std { template<typename> struct allocator { }; } -// CHECK: define void @_Z1fSaIcESaIiE +// CHECK-LABEL: define void @_Z1fSaIcESaIiE void f(std::allocator<char>, std::allocator<int>) { } namespace std { template<typename, typename, typename> struct basic_string { }; } -// CHECK: define void @_Z1fSbIcciE +// CHECK-LABEL: define void @_Z1fSbIcciE void f(std::basic_string<char, char, int>) { } namespace std { @@ -90,7 +90,7 @@ namespace std } // Make sure we don't treat the following like std::string -// CHECK: define void @_Z1f12basic_stringIcSt11char_traitsIcESaIcEE +// CHECK-LABEL: define void @_Z1f12basic_stringIcSt11char_traitsIcESaIcEE template<typename, typename, typename> struct basic_string { }; typedef basic_string<char, std::char_traits<char>, std::allocator<char> > not_string; void f(not_string) { } @@ -106,7 +106,7 @@ namespace N { namespace std { struct A { void f(); }; - // CHECK: define void @_ZN1N3std1A1fEv + // CHECK-LABEL: define void @_ZN1N3std1A1fEv void A::f() { } } } diff --git a/test/CodeGenCXX/mangle-subst.cpp b/test/CodeGenCXX/mangle-subst.cpp index d83a081..30360aea 100644 --- a/test/CodeGenCXX/mangle-subst.cpp +++ b/test/CodeGenCXX/mangle-subst.cpp @@ -2,19 +2,19 @@ struct X {}; -// CHECK: define void @_Z1f1XS_( +// CHECK-LABEL: define void @_Z1f1XS_( void f(X, X) { } -// CHECK: define void @_Z1fR1XS0_( +// CHECK-LABEL: define void @_Z1fR1XS0_( void f(X&, X&) { } -// CHECK: define void @_Z1fRK1XS1_( +// CHECK-LABEL: define void @_Z1fRK1XS1_( void f(const X&, const X&) { } typedef void T(); struct S {}; -// CHECK: define void @_Z1fPFvvEM1SFvvE( +// CHECK-LABEL: define void @_Z1fPFvvEM1SFvvE( void f(T*, T (S::*)) {} namespace A { @@ -22,14 +22,14 @@ namespace A { struct B { }; }; -// CHECK: define void @_Z1fN1A1AENS_1BE( +// CHECK-LABEL: define void @_Z1fN1A1AENS_1BE( void f(A::A a, A::B b) { } struct C { struct D { }; }; -// CHECK: define void @_Z1fN1C1DERS_PS_S1_( +// CHECK-LABEL: define void @_Z1fN1C1DERS_PS_S1_( void f(C::D, C&, C*, C&) { } template<typename T> diff --git a/test/CodeGenCXX/mangle-system-header.cpp b/test/CodeGenCXX/mangle-system-header.cpp index 6716b58..3ab5f96 100644 --- a/test/CodeGenCXX/mangle-system-header.cpp +++ b/test/CodeGenCXX/mangle-system-header.cpp @@ -3,9 +3,9 @@ // PR5420 # 1 "fake_system_header.h" 1 3 4 -// CHECK: define void @_ZdlPvS_( +// CHECK-LABEL: define void @_ZdlPvS_( void operator delete (void*, void*) {} // PR6217 -// CHECK: define void @_Z3barv() +// CHECK-LABEL: define void @_Z3barv() void bar() { } diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp index 15a85c7..3b7f302 100644 --- a/test/CodeGenCXX/mangle-template.cpp +++ b/test/CodeGenCXX/mangle-template.cpp @@ -82,7 +82,7 @@ namespace test7 { X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { } }; - // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr + // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE( template X<int>::X(double*, float*); } @@ -101,7 +101,7 @@ namespace test8 { template<typename T> void f(int_c<meta<T>::type::value>) { } - // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE + // CHECK-LABEL: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE( template void f<int>(int_c<sizeof(int)>); } @@ -160,13 +160,13 @@ namespace test12 { const int n = 10; template<typename T, T v> void test() {} void use() { - // CHECK: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv( + // CHECK-LABEL: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv( test<int(), &f>(); - // CHECK: define internal void @_ZN6test124testIRFivELZNS_L1fEvEEEvv( + // CHECK-LABEL: define internal void @_ZN6test124testIRFivELZNS_L1fEvEEEvv( test<int(&)(), f>(); - // CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv( + // CHECK-LABEL: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv( test<const int*, &n>(); - // CHECK: define internal void @_ZN6test124testIRKiLZNS_L1nEEEEvv( + // CHECK-LABEL: define internal void @_ZN6test124testIRKiLZNS_L1nEEEEvv( test<const int&, n>(); } } diff --git a/test/CodeGenCXX/mangle-unnamed.cpp b/test/CodeGenCXX/mangle-unnamed.cpp index 53f381c..a62bdd5 100644 --- a/test/CodeGenCXX/mangle-unnamed.cpp +++ b/test/CodeGenCXX/mangle-unnamed.cpp @@ -80,7 +80,7 @@ template <class T> struct Test8 { template <class T> void make_test8(T value) { Test8<T> t(value); } void test8() { make_test8(T8); } -// CHECK: define internal void @"_ZNV3$_35test9Ev"( +// CHECK-LABEL: define internal void @"_ZNV3$_35test9Ev"( typedef volatile struct { void test9() volatile {} } Test9; @@ -89,4 +89,4 @@ void test9() { a.test9(); } -// CHECK: define internal void @"_ZN5Test8I3$_2EC1ES0_"( +// CHECK-LABEL: define internal void @"_ZN5Test8I3$_2EC1ES0_"( diff --git a/test/CodeGenCXX/mangle-valist.cpp b/test/CodeGenCXX/mangle-valist.cpp index 73fd58e..0fcc1db 100644 --- a/test/CodeGenCXX/mangle-valist.cpp +++ b/test/CodeGenCXX/mangle-valist.cpp @@ -15,30 +15,30 @@ void Test2::test2(const char *fmt, va_list ap) { // RUN: %clang_cc1 %s -emit-llvm -o - \ // RUN: -triple armv7-unknown-linux \ -// RUN: | FileCheck -check-prefix=MANGLE-ARM-AAPCS %s +// RUN: | FileCheck -check-prefix=CHECK-MANGLE-ARM-AAPCS %s // CHECK-MANGLE-ARM-AAPCS: @_ZN5test15test1EPKcSt9__va_list // CHECK-MANGLE-ARM-AAPCS: @_ZN5Test25test2EPKcSt9__va_list // RUN: %clang_cc1 %s -emit-llvm -o - \ // RUN: -triple armv7-unknown-linux -target-abi apcs-gnu \ -// RUN: | FileCheck -check-prefix=MANGLE-ARM-APCS %s +// RUN: | FileCheck -check-prefix=CHECK-MANGLE-ARM-APCS %s // CHECK-MANGLE-ARM-APCS: @_ZN5test15test1EPKcPv // CHECK-MANGLE-ARM-APCS: @_ZN5Test25test2EPKcPv // RUN: %clang_cc1 %s -emit-llvm -o - \ // RUN: -triple mipsel-unknown-linux \ -// RUN: | FileCheck -check-prefix=MANGLE-MIPSEL %s +// RUN: | FileCheck -check-prefix=CHECK-MANGLE-MIPSEL %s // CHECK-MANGLE-MIPSEL: @_ZN5test15test1EPKcPv // CHECK-MANGLE-MIPSEL: @_ZN5Test25test2EPKcPv // RUN: %clang_cc1 %s -emit-llvm -o - \ // RUN: -triple i686-unknown-linux \ -// RUN: | FileCheck -check-prefix=MANGLE-X86 %s +// RUN: | FileCheck -check-prefix=CHECK-MANGLE-X86 %s // CHECK-MANGLE-X86: @_ZN5test15test1EPKcPc // CHECK-MANGLE-X86: @_ZN5Test25test2EPKcPc // RUN: %clang_cc1 %s -emit-llvm -o - \ // RUN: -triple x86_64-unknown-linux \ -// RUN: | FileCheck -check-prefix=MANGLE-X86-64 %s +// RUN: | FileCheck -check-prefix=CHECK-MANGLE-X86-64 %s // CHECK-MANGLE-X86-64: @_ZN5test15test1EPKcP13__va_list_tag // CHECK-MANGLE-X86-64: @_ZN5Test25test2EPKcP13__va_list_tag diff --git a/test/CodeGenCXX/mangle-variadic-templates.cpp b/test/CodeGenCXX/mangle-variadic-templates.cpp index b5bdae2..264cc11 100644 --- a/test/CodeGenCXX/mangle-variadic-templates.cpp +++ b/test/CodeGenCXX/mangle-variadic-templates.cpp @@ -9,59 +9,59 @@ template<typename ...Types> struct tuple { }; template<int ...Values> struct int_tuple { }; template<template<typename> class ...Templates> struct template_tuple { }; -// CHECK: define weak_odr void @_Z2f0IJEEv1XIXsZT_EJDpRT_EE +// CHECK-LABEL: define weak_odr void @_Z2f0IJEEv1XIXsZT_EJDpRT_EE template<typename ...Types> void f0(X<sizeof...(Types), Types&...>) { } template void f0(X<0>); -// CHECK: define weak_odr void @_Z2f0IJifdEEv1XIXsZT_EJDpRT_EE +// CHECK-LABEL: define weak_odr void @_Z2f0IJifdEEv1XIXsZT_EJDpRT_EE template void f0<int, float, double>(X<3, int&, float&, double&>); // Mangling for template argument packs template<typename ...Types> void f1() {} -// CHECK: define weak_odr void @_Z2f1IJEEvv +// CHECK-LABEL: define weak_odr void @_Z2f1IJEEvv template void f1<>(); -// CHECK: define weak_odr void @_Z2f1IJiEEvv +// CHECK-LABEL: define weak_odr void @_Z2f1IJiEEvv template void f1<int>(); -// CHECK: define weak_odr void @_Z2f1IJifEEvv +// CHECK-LABEL: define weak_odr void @_Z2f1IJifEEvv template void f1<int, float>(); // Mangling function parameter packs template<typename ...Types> void f2(Types...) {} -// CHECK: define weak_odr void @_Z2f2IJEEvDpT_ +// CHECK-LABEL: define weak_odr void @_Z2f2IJEEvDpT_ template void f2<>(); -// CHECK: define weak_odr void @_Z2f2IJiEEvDpT_ +// CHECK-LABEL: define weak_odr void @_Z2f2IJiEEvDpT_ template void f2<int>(int); -// CHECK: define weak_odr void @_Z2f2IJifEEvDpT_ +// CHECK-LABEL: define weak_odr void @_Z2f2IJifEEvDpT_ template void f2<int, float>(int, float); // Mangling non-trivial function parameter packs template<typename ...Types> void f3(const Types *...) {} -// CHECK: define weak_odr void @_Z2f3IJEEvDpPKT_ +// CHECK-LABEL: define weak_odr void @_Z2f3IJEEvDpPKT_ template void f3<>(); -// CHECK: define weak_odr void @_Z2f3IJiEEvDpPKT_ +// CHECK-LABEL: define weak_odr void @_Z2f3IJiEEvDpPKT_ template void f3<int>(const int*); -// CHECK: define weak_odr void @_Z2f3IJifEEvDpPKT_ +// CHECK-LABEL: define weak_odr void @_Z2f3IJifEEvDpPKT_ template void f3<int, float>(const int*, const float*); // Mangling of type pack expansions in a template argument template<typename ...Types> tuple<Types...> f4() {} -// CHECK: define weak_odr void @_Z2f4IJifdEE5tupleIJDpT_EEv +// CHECK-LABEL: define weak_odr void @_Z2f4IJifdEE5tupleIJDpT_EEv template tuple<int, float, double> f4(); // Mangling of type pack expansions in a function type template<typename R, typename ...ArgTypes> identity<R(ArgTypes...)> f5() {} -// CHECK: define weak_odr void @_Z2f5IiJifdEE8identityIFT_DpT0_EEv +// CHECK-LABEL: define weak_odr void @_Z2f5IiJifdEE8identityIFT_DpT0_EEv template identity<int(int, float, double)> f5(); // Mangling of non-type template argument expansions template<int ...Values> int_tuple<Values...> f6() {} -// CHECK: define weak_odr void @_Z2f6IJLi1ELi2ELi3EEE9int_tupleIJXspT_EEEv +// CHECK-LABEL: define weak_odr void @_Z2f6IJLi1ELi2ELi3EEE9int_tupleIJXspT_EEEv template int_tuple<1, 2, 3> f6(); // Mangling of template template argument expansions template<template<typename> class ...Templates> template_tuple<Templates...> f7() {} -// CHECK: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv +// CHECK-LABEL: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv template template_tuple<identity, add_reference> f7(); diff --git a/test/CodeGenCXX/mangle-windows.cpp b/test/CodeGenCXX/mangle-windows.cpp new file mode 100644 index 0000000..c087616 --- /dev/null +++ b/test/CodeGenCXX/mangle-windows.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft \ +// RUN: -triple=i386-pc-win32 | FileCheck --check-prefix=WIN %s +// +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | \ +// RUN: FileCheck --check-prefix=ITANIUM %s + +void __stdcall f1(void) {} +// WIN: define x86_stdcallcc void @"\01?f1@@YGXXZ" +// ITANIUM: define x86_stdcallcc void @"\01__Z2f1v@0" + +void __fastcall f2(void) {} +// WIN: define x86_fastcallcc void @"\01?f2@@YIXXZ" +// ITANIUM: define x86_fastcallcc void @"\01@_Z2f2v@0" + +extern "C" void __stdcall f3(void) {} +// WIN: define x86_stdcallcc void @"\01_f3@0" +// ITANIUM: define x86_stdcallcc void @"\01_f3@0" + +extern "C" void __fastcall f4(void) {} +// WIN: define x86_fastcallcc void @"\01@f4@0" +// ITANIUM: define x86_fastcallcc void @"\01@f4@0" + +struct Foo { + void __stdcall foo(); + static void __stdcall bar(); +}; + +void Foo::foo() {} +// WIN: define x86_stdcallcc void @"\01?foo@Foo@@QAGXXZ" +// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3fooEv@4" + +void Foo::bar() {} +// WIN: define x86_stdcallcc void @"\01?bar@Foo@@SGXXZ" +// ITANIUM: define x86_stdcallcc void @"\01__ZN3Foo3barEv@0" + +// Mostly a test that we don't crash and that the names start with a \01. +// gcc on mingw produces __Zpp@4 +// cl produces _++@4 +extern "C" void __stdcall operator++(Foo &x) { +} +// WIN: define x86_stdcallcc void @"\01??E@YGXAAUFoo@@@Z" +// ITANIUM: define x86_stdcallcc void @"\01__ZppR3Foo@4" diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index e7955a8..d836f36 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -9,37 +9,37 @@ struct Y { }; // CHECK: @_ZGVZN1N1gEvE1a = internal global //CHECK: @pr5966_i = external global -//CHECK: @_ZL8pr5966_i = internal global +//CHECK: @_ZL8pr5966_j = internal global -// CHECK: define zeroext i1 @_ZplRK1YRA100_P1X +// CHECK-LABEL: define zeroext i1 @_ZplRK1YRA100_P1X bool operator+(const Y&, X* (&xs)[100]) { return false; } -// CHECK: define void @_Z1f1s +// CHECK-LABEL: define void @_Z1f1s typedef struct { int a; } s; void f(s) { } -// CHECK: define void @_Z1f1e +// CHECK-LABEL: define void @_Z1f1e typedef enum { foo } e; void f(e) { } -// CHECK: define void @_Z1f1u +// CHECK-LABEL: define void @_Z1f1u typedef union { int a; } u; void f(u) { } -// CHECK: define void @_Z1f1x +// CHECK-LABEL: define void @_Z1f1x typedef struct { int a; } x,y; void f(y) { } -// CHECK: define void @_Z1fv +// CHECK-LABEL: define void @_Z1fv void f() { } -// CHECK: define void @_ZN1N1fEv +// CHECK-LABEL: define void @_ZN1N1fEv namespace N { void f() { } } -// CHECK: define void @_ZN1N1N1fEv +// CHECK-LABEL: define void @_ZN1N1N1fEv namespace N { namespace N { void f() { } } } -// CHECK: define void @unmangled_function +// CHECK-LABEL: define void @unmangled_function extern "C" { namespace N { void unmangled_function() { } } } extern "C" { namespace N { int unmangled_variable = 10; } } @@ -50,41 +50,41 @@ namespace N { int f(int, int) { static int b; return b; } } namespace N { int h(); void g() { static int a = h(); } } -// CHECK: define void @_Z1fno +// CHECK-LABEL: define void @_Z1fno void f(__int128_t, __uint128_t) { } template <typename T> struct S1 {}; -// CHECK: define void @_Z1f2S1IiE +// CHECK-LABEL: define void @_Z1f2S1IiE void f(S1<int>) {} -// CHECK: define void @_Z1f2S1IdE +// CHECK-LABEL: define void @_Z1f2S1IdE void f(S1<double>) {} template <int N> struct S2 {}; -// CHECK: define void @_Z1f2S2ILi100EE +// CHECK-LABEL: define void @_Z1f2S2ILi100EE void f(S2<100>) {} -// CHECK: define void @_Z1f2S2ILin100EE +// CHECK-LABEL: define void @_Z1f2S2ILin100EE void f(S2<-100>) {} template <bool B> struct S3 {}; -// CHECK: define void @_Z1f2S3ILb1EE +// CHECK-LABEL: define void @_Z1f2S3ILb1EE void f(S3<true>) {} -// CHECK: define void @_Z1f2S3ILb0EE +// CHECK-LABEL: define void @_Z1f2S3ILb0EE void f(S3<false>) {} struct S; -// CHECK: define void @_Z1fM1SKFvvE +// CHECK-LABEL: define void @_Z1fM1SKFvvE void f(void (S::*)() const) {} -// CHECK: define void @_Z1fM1SFvvE +// CHECK-LABEL: define void @_Z1fM1SFvvE void f(void (S::*)()) {} -// CHECK: define void @_Z1fi +// CHECK-LABEL: define void @_Z1fi void f(const int) { } template<typename T, typename U> void ft1(U u, T t) { } @@ -238,7 +238,7 @@ template<bool, typename> struct __enable_if {}; template<typename T> struct __enable_if<true, T> { typedef T __type; }; template<typename T> -// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv +// CHECK-LABEL: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv typename __enable_if<!__is_scalar_type<T>::__value, void>::__type __fill_a() { }; void f() { __fill_a<int>(); } @@ -247,26 +247,26 @@ void f() { __fill_a<int>(); } namespace Expressions { // Unary operators. -// CHECK: define weak_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i +// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i template <int i> void f1(int (*)[(-i) + 2]) { }; template void f1<1>(int (*)[1]); -// CHECK: define weak_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i +// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i template <int i> void f2(int (*)[+i]) { }; template void f2<1>(int (*)[1]); // Binary operators. -// CHECK: define weak_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i +// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i template <int i> void f3(int (*)[i+i]) { }; template void f3<1>(int (*)[2]); -// CHECK: define weak_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i +// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i template <int i> void f4(int (*)[2 + i+i]) { }; template void f4<1>(int (*)[4]); // The ternary operator. -// CHECK: define weak_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i +// CHECK-LABEL: define weak_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i template <bool b> void f4(int (*)[b ? 1 : 2]) { }; template void f4<true>(int (*)[1]); } @@ -280,13 +280,13 @@ struct Ops { void *v; }; -// CHECK: define %struct.Ops* @_ZN3OpsplERKS_ +// CHECK-LABEL: define %struct.Ops* @_ZN3OpsplERKS_ Ops& Ops::operator+(const Ops&) { return *this; } -// CHECK: define %struct.Ops* @_ZN3OpsmiERKS_ +// CHECK-LABEL: define %struct.Ops* @_ZN3OpsmiERKS_ Ops& Ops::operator-(const Ops&) { return *this; } -// CHECK: define %struct.Ops* @_ZN3OpsanERKS_ +// CHECK-LABEL: define %struct.Ops* @_ZN3OpsanERKS_ Ops& Ops::operator&(const Ops&) { return *this; } -// CHECK: define %struct.Ops* @_ZN3OpsmlERKS_ +// CHECK-LABEL: define %struct.Ops* @_ZN3OpsmlERKS_ Ops& Ops::operator*(const Ops&) { return *this; } // PR5861 @@ -302,11 +302,11 @@ template<typename T, typename = Policy<P, true> > class Alloc T *allocate(int, const void*) { return 0; } }; -// CHECK: define weak_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv +// CHECK-LABEL: define weak_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv template class Alloc<char>; } -// CHECK: define void @_Z1fU13block_pointerFiiiE +// CHECK-LABEL: define void @_Z1fU13block_pointerFiiiE void f(int (^)(int, int)) { } void pr5966_foo() { @@ -314,10 +314,10 @@ void pr5966_foo() { pr5966_i = 0; } -static int pr5966_i; +static int pr5966_j; void pr5966_bar() { - pr5966_i = 0; + pr5966_j = 0; } namespace test0 { @@ -330,29 +330,29 @@ namespace test0 { char buffer[1]; f(0.0, buffer); } - // CHECK: define void @_ZN5test05test0Ev() - // CHECK: define linkonce_odr void @_ZN5test01fIdEEvT_RAszcl3ovlcvS1__EE_c( + // CHECK-LABEL: define void @_ZN5test05test0Ev() + // CHECK-LABEL: define linkonce_odr void @_ZN5test01fIdEEvT_RAszcl3ovlcvS1__EE_c( void test1() { char buffer[sizeof(int)]; f(1, buffer); } - // CHECK: define void @_ZN5test05test1Ev() - // CHECK: define linkonce_odr void @_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c( + // CHECK-LABEL: define void @_ZN5test05test1Ev() + // CHECK-LABEL: define linkonce_odr void @_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c( template <class T> void g(char (&buffer)[sizeof(T() + 5.0f)]) {} void test2() { char buffer[sizeof(float)]; g<float>(buffer); } - // CHECK: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c( + // CHECK-LABEL: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c( template <class T> void h(char (&buffer)[sizeof(T() + 5.0)]) {} void test3() { char buffer[sizeof(double)]; h<float>(buffer); } - // CHECK: define linkonce_odr void @_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c( + // CHECK-LABEL: define linkonce_odr void @_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c( template <class T> void j(char (&buffer)[sizeof(T().buffer)]) {} struct A { double buffer[128]; }; @@ -360,25 +360,25 @@ namespace test0 { char buffer[1024]; j<A>(buffer); } - // CHECK: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c( + // CHECK-LABEL: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c( template <class T> void k(char (&buffer)[sizeof(T() + 0.0f)]) {} void test5() { char buffer[sizeof(float)]; k<float>(buffer); } - // CHECK: define linkonce_odr void @_ZN5test01kIfEEvRAszplcvT__ELf00000000E_c( + // CHECK-LABEL: define linkonce_odr void @_ZN5test01kIfEEvRAszplcvT__ELf00000000E_c( } namespace test1 { template<typename T> struct X { }; template<template<class> class Y, typename T> void f(Y<T>) { } - // CHECK: define weak_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E + // CHECK-LABEL: define weak_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E template void f(X<int>); } -// CHECK: define internal void @_ZL27functionWithInternalLinkagev() +// CHECK-LABEL: define internal void @_ZL27functionWithInternalLinkagev() static void functionWithInternalLinkage() { } void g() { functionWithInternalLinkage(); } @@ -392,7 +392,7 @@ namespace test2 { return read_member(obj); } - // CHECK: define linkonce_odr i32 @_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_( + // CHECK-LABEL: define linkonce_odr i32 @_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_( } // rdar://problem/9280586 @@ -402,16 +402,16 @@ namespace test3 { struct Path2 : AmbiguousBase { double p; }; struct Derived : Path1, Path2 { }; - // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E2abERS2_( + // CHECK-LABEL: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E2abERS2_( template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; } - // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E2abERS2_( + // CHECK-LABEL: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E2abERS2_( template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; } - // CHECK: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E1pERS2_( + // CHECK-LABEL: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E1pERS2_( template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; } - // CHECK: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E1pERS2_( + // CHECK-LABEL: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E1pERS2_( template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; } Derived obj; @@ -423,7 +423,7 @@ namespace test3 { } } -// CHECK: define void @_ZN5test41gEPNS_3zedIXadL_ZNS_3foo3barEEEEE +// CHECK-LABEL: define void @_ZN5test41gEPNS_3zedIXadL_ZNS_3foo3barEEEEE namespace test4 { struct foo { int bar; }; template <int (foo::*)> @@ -431,7 +431,7 @@ namespace test4 { void g(zed<&foo::bar>*) {} } -// CHECK: define void @_ZN5test51gEPNS_3zedIXadL_ZNS_3foo3barEEEEE +// CHECK-LABEL: define void @_ZN5test51gEPNS_3zedIXadL_ZNS_3foo3barEEEEE namespace test5 { struct foo { static int bar; }; template <int *> @@ -439,7 +439,7 @@ namespace test5 { void g(zed<&foo::bar>*) {} } -// CHECK: define void @_ZN5test61gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE +// CHECK-LABEL: define void @_ZN5test61gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE namespace test6 { struct foo { int bar(); }; template <int (foo::*)()> @@ -447,7 +447,7 @@ namespace test6 { void g(zed<&foo::bar>*) {} } -// CHECK: define void @_ZN5test71gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE +// CHECK-LABEL: define void @_ZN5test71gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE namespace test7 { struct foo { static int bar(); }; template <int (*f)()> @@ -455,7 +455,7 @@ namespace test7 { void g(zed<&foo::bar>*) {} } -// CHECK: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv +// CHECK-LABEL: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv namespace test8 { template <int &counter> class A { void inc() { counter++; } }; class B { public: static int value; }; @@ -482,7 +482,7 @@ namespace test10 { template <char P1> struct S {}; template <char P2> void f(struct S<false ? 'a' : P2> ) {} - // CHECK: define weak_odr void @_ZN6test101fILc3EEEvNS_1SIXquLb0ELc97ET_EEE( + // CHECK-LABEL: define weak_odr void @_ZN6test101fILc3EEEvNS_1SIXquLb0ELc97ET_EEE( template void f<(char) 3>(struct S<3>); } @@ -512,7 +512,7 @@ namespace test13 { template <template<class> class T> void foo(const A<T> &a) {} - // CHECK: define weak_odr void @_ZN6test133fooINS_1BEEEvRKNS_1AIT_EE( + // CHECK-LABEL: define weak_odr void @_ZN6test133fooINS_1BEEEvRKNS_1AIT_EE( template void foo(const A<B> &a); } @@ -521,7 +521,7 @@ namespace test14 { struct S { static int a(), x; }; - // CHECK: define i32 @_ZN6test141S1aEv + // CHECK-LABEL: define i32 @_ZN6test141S1aEv // CHECK: load i32* @_ZN6test141S1xE int S::a() { return S::x; } } @@ -534,7 +534,7 @@ namespace test15 { template <int I> void f(S<I + e>) {} - // CHECK: define weak_odr void @_ZN6test151fILi7EEEvNS_1SIXplT_LNS_1EE3EEEE( + // CHECK-LABEL: define weak_odr void @_ZN6test151fILi7EEEvNS_1SIXplT_LNS_1EE3EEEE( template void f<7>(S<7 + e>); } @@ -548,7 +548,7 @@ namespace test17 { template <class T> A<sizeof(T::foo())> func(void); - // CHECK: define void @_ZN6test174testEv() + // CHECK-LABEL: define void @_ZN6test174testEv() // CHECK: call {{.*}} @_ZN6test174funcINS_1BEEENS_1AIXszclsrT_3fooEEEEv() void test() { func<B>(); @@ -577,10 +577,10 @@ namespace test18 { template <typename T> void f(S<&T::operator&>) {} template void f<A>(S<&A::operator&>); - // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_plEEE - // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_miEEE - // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_mlEEE - // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_anEEE + // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_plEEE + // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_miEEE + // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_mlEEE + // CHECK-LABEL: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_anEEE } // rdar://problem/8332117 @@ -599,13 +599,13 @@ namespace test19 { template <typename T> void g (S<&T::operator int>) {} template <typename T> void g (S<&T::template operator- <double> >) {} - // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_1fIiEEEE( + // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_1fIiEEEE( template void g<A>(S<&A::f<int> >); - // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_plEEE( + // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_plEEE( template void g<A>(S<&A::operator+>); - // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_cviEEE( + // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_cviEEE( template void g<A>(S<&A::operator int>); - // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_miIdEEEE( + // CHECK-LABEL: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_miIdEEEE( template void g<A>(S<&A::operator-<double> >); } @@ -613,23 +613,23 @@ namespace test20 { template <class T> T *f(const T&); template <class T> T *f(T*); - // CHECK: define weak_odr void @_ZN6test205test0IiEEvDTcl1fIPT_ELi0EEE( + // CHECK-LABEL: define weak_odr void @_ZN6test205test0IiEEvDTcl1fIPT_ELi0EEE( template <class T> void test0(decltype(f<T*>(0))) {} template void test0<int>(decltype(f<int*>(0))); - // CHECK: define weak_odr void @_ZN6test205test1IiEEvDTcl1fIEcvT__EEE( + // CHECK-LABEL: define weak_odr void @_ZN6test205test1IiEEvDTcl1fIEcvT__EEE( template <class T> void test1(decltype(f<>(T()))) {} template void test1<int>(decltype(f<>(int()))); } // rdar:// 8620510 namespace test21 { - // CHECK: define void @_ZN6test2112vla_arg_funcEiPA_i( + // CHECK-LABEL: define void @_ZN6test2112vla_arg_funcEiPA_i( void vla_arg_func(int X, int a[X][X]) {} } namespace test22 { - // CHECK: define void @_ZN6test221fEDn( + // CHECK-LABEL: define void @_ZN6test221fEDn( void f(decltype(nullptr)) { } } @@ -637,12 +637,12 @@ namespace test22 { namespace test23 { typedef void * const vpc; - // CHECK: define void @_ZN6test231fERA10_KPv( + // CHECK-LABEL: define void @_ZN6test231fERA10_KPv( void f(vpc (&)[10]) {} typedef vpc vpca5[5]; void f(vpca5 volatile (&)[10]) {} - // CHECK: define void @_ZN6test231fERA10_A5_VKPv( + // CHECK-LABEL: define void @_ZN6test231fERA10_A5_VKPv( } namespace test24 { @@ -652,10 +652,10 @@ namespace test24 { foo(); } - static char foo() {} + static char bar() {} void test1() { - // CHECK: call signext i8 @_ZN6test24L3fooEv() - foo(); + // CHECK: call signext i8 @_ZN6test24L3barEv() + bar(); } } @@ -757,11 +757,11 @@ namespace test31 { // instantiation-dependent mangling of decltype void g(int); template<class T> auto f3(T p)->decltype(g(p)) {} - // CHECK: define weak_odr i32 @_ZN6test312f1IiEEiT_( + // CHECK-LABEL: define weak_odr i32 @_ZN6test312f1IiEEiT_( template int f1(int); - // CHECK: define weak_odr i32 @_ZN6test312f2IiEEDtfp_ET_ + // CHECK-LABEL: define weak_odr i32 @_ZN6test312f2IiEEDtfp_ET_ template int f2(int); - // CHECK: define weak_odr void @_ZN6test312f3IiEEDTcl1gfp_EET_ + // CHECK-LABEL: define weak_odr void @_ZN6test312f3IiEEDTcl1gfp_EET_ template void f3(int); } @@ -802,14 +802,14 @@ namespace test34 { template<typename T> void f(decltype(sizeof(decltype(T() + T())))) {} - // CHECK: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE + // CHECK-LABEL: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE template void f<int>(decltype(sizeof(1))); // Mangling for non-instantiation-dependent sizeof expressions. template<unsigned N> void f2(int (&)[N + sizeof(int*)]) {} - // CHECK: define weak_odr void @_ZN6test342f2ILj4EEEvRAplT_Lm8E_i + // CHECK-LABEL: define weak_odr void @_ZN6test342f2ILj4EEEvRAplT_Lm8E_i template void f2<4>(int (&)[4 + sizeof(int*)]); // Mangling for non-instantiation-dependent sizeof expressions @@ -817,7 +817,7 @@ namespace test34 { template<unsigned long long N> void f3(int (&)[N + sizeof(int*)]) {} - // CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i + // CHECK-LABEL: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i template void f3<4>(int (&)[4 + sizeof(int*)]); // Mangling for instantiation-dependent sizeof() expressions as @@ -826,7 +826,7 @@ namespace test34 { template<typename T> void f4(::test34::A<sizeof(sizeof(decltype(T() + T())))>) { } - // CHECK: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE + // CHECK-LABEL: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE template void f4<int>(A<sizeof(sizeof(int))>); } @@ -839,7 +839,7 @@ namespace test35 { template<typename T> void f1(decltype(sizeof(&T::template operator+<int>))) {} - // CHECK: define weak_odr void @_ZN6test352f1INS_1AEEEvDTszadsrT_plIiEE + // CHECK-LABEL: define weak_odr void @_ZN6test352f1INS_1AEEEvDTszadsrT_plIiEE template void f1<A>(__SIZE_TYPE__); } @@ -864,14 +864,90 @@ namespace test37 { }; template<typename T> void func(T) { } void test() { - // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt_EEEvT_ + // CHECK-LABEL: define linkonce_odr void @_ZN6test374funcINS_3fooUt_EEEvT_ func(foo().a); - // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt0_EEEvT_ + // CHECK-LABEL: define linkonce_odr void @_ZN6test374funcINS_3fooUt0_EEEvT_ func(*foo::c()); - // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt1_EEEvT_ + // CHECK-LABEL: define linkonce_odr void @_ZN6test374funcINS_3fooUt1_EEEvT_ func(foo().d); } } -// CHECK: define void @_Z6ASfuncPU3AS3i +// CHECK-LABEL: define void @_Z6ASfuncPU3AS3i void ASfunc(__attribute__((address_space(3))) int* x) {} + +namespace test38 { + // CHECK-LABEL: define linkonce_odr void @_ZN6test384funcINS_3fooUt_EEEvT_ + typedef struct { + struct { + } a; + } foo; + + template <typename T> void func(T) {} + void test() { func(foo().a); } +} + +namespace test39 { + // CHECK-LABEL: define internal void @"_ZN6test394funcINS_3$_03$_1EEEvT_" + typedef struct { + struct {} a; + } *foo; + template<typename T> void func(T) {} + void test(foo x) { + func(x->a); + } +} + +namespace test40 { + // CHECK: i32* @_ZZN6test401fEvE1a_0 + void h(int&); + inline void f() { + if (0) { + static int a; + } + static int a; + h(a); + }; + void g() { f(); } +} + +namespace test41 { + // CHECK: define linkonce_odr void @_ZN6test414funcINS_1XEEEvNS_3fooILi20ES1_EE + template <int i, class T> struct foo { + template <class T2 = T> friend void func(foo x) {} + }; + + struct X {}; + + void g() { func(foo<20, X>()); } +} + +namespace test42 { + // CHECK: define linkonce_odr void @_ZN6test424funcINS_1XEEEvNS_3fooILi20ES1_EE + template <int i, template <class> class T> struct foo { + template <template <class> class T2 = T> friend void func(foo x) {} + }; + + template <class V> struct X { + }; + + void g() { func(foo<20, X>()); } +} + +namespace test43 { + // CHECK-LABEL: define void @_ZN6test431gEPNS_3zedIXadL_ZNS_3fooUt_3barEEEEE + struct foo { union { int bar; }; }; + template <int (foo::*)> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} + +namespace test44 { + struct foo { void bar() __restrict { }; } obj; + + void f() { + obj.bar(); + } + // CHECK-LABEL: define linkonce_odr void @_ZN6test443foo3barEv(%"struct.test44::foo"* %this) +} diff --git a/test/CodeGenCXX/member-expressions.cpp b/test/CodeGenCXX/member-expressions.cpp index d9fb394..4850272 100644 --- a/test/CodeGenCXX/member-expressions.cpp +++ b/test/CodeGenCXX/member-expressions.cpp @@ -58,7 +58,7 @@ namespace test4 { extern C *c_ptr; - // CHECK: define i32 @_ZN5test44testEv() + // CHECK-LABEL: define i32 @_ZN5test44testEv() int test() { // CHECK: load {{.*}} @_ZN5test45c_ptrE // CHECK-NEXT: bitcast diff --git a/test/CodeGenCXX/member-function-pointer-calls.cpp b/test/CodeGenCXX/member-function-pointer-calls.cpp index f8960aa..99162eb 100644 --- a/test/CodeGenCXX/member-function-pointer-calls.cpp +++ b/test/CodeGenCXX/member-function-pointer-calls.cpp @@ -8,14 +8,14 @@ int f(A* a, int (A::*fp)()) { return (a->*fp)(); } -// CHECK: define i32 @_Z2g1v() +// CHECK-LABEL: define i32 @_Z2g1v() // CHECK: ret i32 1 int g1() { A a; return f(&a, &A::vf1); } -// CHECK: define i32 @_Z2g2v() +// CHECK-LABEL: define i32 @_Z2g2v() // CHECK: ret i32 2 int g2() { A a; diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 84b54b6..fb06fa7 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -4,6 +4,9 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-unknown-unknown | FileCheck -check-prefix GLOBAL-LP32 %s // RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix GLOBAL-ARM %s +// PNaCl uses the same representation of method pointers as ARM. +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=le32-unknown-nacl | FileCheck -check-prefix GLOBAL-ARM %s + struct A { int a; void f(); virtual void vf1(); virtual void vf2(); }; struct B { int b; virtual void g(); }; struct C : B, A { }; @@ -226,7 +229,7 @@ namespace test9 { fooptr p; }; - // CODE-LP64: define void @_ZN5test94testEv( + // CODE-LP64-LABEL: define void @_ZN5test94testEv( // CODE-LP64: alloca i32 // CODE-LP64-NEXT: ret void void test() { diff --git a/test/CodeGenCXX/member-functions.cpp b/test/CodeGenCXX/member-functions.cpp index 75b354c..1773c67 100644 --- a/test/CodeGenCXX/member-functions.cpp +++ b/test/CodeGenCXX/member-functions.cpp @@ -5,11 +5,11 @@ struct C { void g(int, ...); }; -// CHECK: define void @_ZN1C1fEv +// CHECK-LABEL: define void @_ZN1C1fEv void C::f() { } -// CHECK: define void @_Z5test1v +// CHECK-LABEL: define void @_Z5test1v void test1() { C c; @@ -34,7 +34,7 @@ struct S { virtual void v() {} }; -// CHECK: define void @_ZN1S1fEv +// CHECK-LABEL: define void @_ZN1S1fEv void S::f() { } @@ -51,13 +51,13 @@ void test2() { // CHECK: define linkonce_odr void @_ZN1SC1Ev{{.*}} unnamed_addr // S::f_inline1() -// CHECK: define linkonce_odr void @_ZN1S9f_inline1Ev +// CHECK-LABEL: define linkonce_odr void @_ZN1S9f_inline1Ev // S::f_inline2() -// CHECK: define linkonce_odr void @_ZN1S9f_inline2Ev +// CHECK-LABEL: define linkonce_odr void @_ZN1S9f_inline2Ev // S::g() -// CHECK: define linkonce_odr void @_ZN1S1gEv +// CHECK-LABEL: define linkonce_odr void @_ZN1S1gEv // S::~S() // CHECK: define linkonce_odr void @_ZN1SD1Ev{{.*}} unnamed_addr @@ -66,7 +66,7 @@ struct T { T operator+(const T&); }; -// CHECK: define void @_Z5test3v +// CHECK-LABEL: define void @_Z5test3v void test3() { T t1, t2; diff --git a/test/CodeGenCXX/member-init-anon-union.cpp b/test/CodeGenCXX/member-init-anon-union.cpp index 4db31f0..bfe1667 100644 --- a/test/CodeGenCXX/member-init-anon-union.cpp +++ b/test/CodeGenCXX/member-init-anon-union.cpp @@ -11,7 +11,7 @@ static union { int f() { return a; } -// CHECK: define internal void @__cxx_global_var_init +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK-NOT: } // CHECK: call {{.*}}@"[[CONSTRUCT_GLOBAL:.*]]C1Ev" diff --git a/test/CodeGenCXX/member-initializers.cpp b/test/CodeGenCXX/member-initializers.cpp index c22b99d..c98e6bf 100644 --- a/test/CodeGenCXX/member-initializers.cpp +++ b/test/CodeGenCXX/member-initializers.cpp @@ -12,7 +12,7 @@ struct B : A { int i; }; -// CHECK: define i32 @_Z1fv() #0 +// CHECK-LABEL: define i32 @_Z1fv() #0 int f() { B b; diff --git a/test/CodeGenCXX/member-templates.cpp b/test/CodeGenCXX/member-templates.cpp index 7e4bdca..c72dd6e 100644 --- a/test/CodeGenCXX/member-templates.cpp +++ b/test/CodeGenCXX/member-templates.cpp @@ -15,8 +15,8 @@ struct B { template<typename T> B::B(T) {} -// CHECK: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) unnamed_addr -// CHECK: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) unnamed_addr +// CHECK-LABEL: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) unnamed_addr +// CHECK-LABEL: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) unnamed_addr template B::B(int); template<typename T> diff --git a/test/CodeGenCXX/microsoft-abi-alignment-fail.cpp b/test/CodeGenCXX/microsoft-abi-alignment-fail.cpp new file mode 100644 index 0000000..7407efe --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-alignment-fail.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i686-pc-win32 -o - %s 2>/dev/null | FileCheck %s +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 -o - %s 2>/dev/null | FileCheck %s -check-prefix CHECK-X64 + +struct B { char a; }; +struct A : virtual B {} a; + +// The <> indicate that the pointer is packed, which is required to support +// microsoft layout in 32 bit mode, but not 64 bit mode. +// CHECK: %struct.A = type <{ i32*, %struct.B }>
+// CHECK-X64: %struct.A = type { i32*, %struct.B }
diff --git a/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp new file mode 100644 index 0000000..92db9a7 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct A { + constexpr A(int x) : x(x) {} + virtual void f(); + int x; +}; + +A a(42); +// CHECK: @"\01?a@@3UA@@A" = global { [1 x i8*]*, i32 } { [1 x i8*]* @"\01??_7A@@6B@", i32 42 }, align 4 + +struct B { + constexpr B(int y) : y(y) {} + virtual void g(); + int y; +}; + +struct C : A, B { + constexpr C() : A(777), B(13) {} +}; + +C c; +// CHECK: @"\01?c@@3UC@@A" = global { [1 x i8*]*, i32, [1 x i8*]*, i32 } { [1 x i8*]* @"\01??_7C@@6BA@@@", i32 777, [1 x i8*]* @"\01??_7C@@6BB@@@", i32 13 } diff --git a/test/CodeGenCXX/microsoft-abi-default-cc.cpp b/test/CodeGenCXX/microsoft-abi-default-cc.cpp index 7f2fc0a..d7fba99 100644 --- a/test/CodeGenCXX/microsoft-abi-default-cc.cpp +++ b/test/CodeGenCXX/microsoft-abi-default-cc.cpp @@ -12,13 +12,13 @@ void foo(); void __cdecl foo(); void __cdecl foo() {} -// GCABI: define void @_Z3foov() +// GCABI-LABEL: define void @_Z3foov() // MSABI: define void @"\01?foo@@YAXXZ" void __cdecl bar(); void bar(); void bar() {} -// GCABI: define void @_Z3barv() +// GCABI-LABEL: define void @_Z3barv() // MSABI: define void @"\01?bar@@YAXXZ" // Test that it's OK to mark either the method declaration or method definition @@ -33,15 +33,15 @@ public: }; void METHOD_CC A::baz() {} -// GCABI: define void @_ZN1A3bazEv +// GCABI-LABEL: define void @_ZN1A3bazEv // MSABI: define x86_thiscallcc void @"\01?baz@A@@QAEXXZ" void A::qux() {} -// GCABI: define void @_ZN1A3quxEv +// GCABI-LABEL: define void @_ZN1A3quxEv // MSABI: define x86_thiscallcc void @"\01?qux@A@@QAEXXZ" void __cdecl static_baz() {} -// GCABI: define void @_Z10static_bazv +// GCABI-LABEL: define void @_Z10static_bazv // MSABI: define void @"\01?static_baz@@YAXXZ" void static_qux() {} -// GCABI: define void @_Z10static_quxv +// GCABI-LABEL: define void @_Z10static_quxv // MSABI: define void @"\01?static_qux@@YAXXZ" diff --git a/test/CodeGenCXX/microsoft-abi-exceptions.cpp b/test/CodeGenCXX/microsoft-abi-exceptions.cpp new file mode 100644 index 0000000..7757ea0 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-exceptions.cpp @@ -0,0 +1,157 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fexceptions -fno-rtti | FileCheck -check-prefix WIN32 %s + +struct A { + A(); + ~A(); + int a; +}; + +A getA(); + +int TakesTwo(A a, A b); +void HasEHCleanup() { + TakesTwo(getA(), getA()); +} + +// With exceptions, we need to clean up at least one of these temporaries. +// WIN32: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} { +// First one doesn't have any cleanups, no need for invoke. +// WIN32: call void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) +// If this call throws, we have to cleanup the first temporary. +// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) +// If this call throws, we already popped our cleanups +// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// WIN32: ret void +// +// There should be one dtor call for unwinding from the second getA. +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: } + +void TakeRef(const A &a); +int HasDeactivatedCleanups() { + return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())); +} + +// WIN32: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} { +// WIN32: %[[isactive:.*]] = alloca i1 +// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]]) +// WIN32: store i1 true, i1* %[[isactive]] +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: store i1 false, i1* %[[isactive]] +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// Destroy the two const ref temporaries. +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: ret i32 +// +// Conditionally destroy arg1. +// WIN32: %[[cond:.*]] = load i1* %[[isactive]] +// WIN32: br i1 %[[cond]] +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) +// WIN32: } + +// Test putting the cleanups inside a conditional. +int CouldThrow(); +int HasConditionalCleanup(bool cond) { + return (cond ? TakesTwo(A(), A()) : CouldThrow()); +} + +// WIN32: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} { +// WIN32: store i1 false +// WIN32: br i1 +// No cleanups, so we call and then activate a cleanup if it succeeds. +// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]]) +// WIN32: store i1 true +// Now we have a cleanup for the first aggregate, so we invoke. +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}}) +// Now we have no cleanups because TakeTwo will destruct both args. +// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// Still no cleanups, so call. +// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"() +// Somewhere in the landing pad for our single invoke, call the dtor. +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) +// WIN32: } + +// Now test both. +int HasConditionalDeactivatedCleanups(bool cond) { + return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow()); +} + +// WIN32: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { +// WIN32: %[[arg1:.*]] = alloca %struct.A, align 4 +// WIN32: alloca i1 +// WIN32: %[[arg1_cond:.*]] = alloca i1 +// Start all four cleanups as deactivated. +// WIN32: store i1 false +// WIN32: store i1 false +// WIN32: store i1 false +// WIN32: store i1 false +// WIN32: br i1 +// True condition. +// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: store i1 true +// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]]) +// WIN32: store i1 true, i1* %[[arg1_cond]] +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: store i1 true +// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: store i1 true +// WIN32: store i1 false, i1* %[[arg1_cond]] +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// False condition. +// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"() +// Two normal cleanups for TakeRef args. +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: ret i32 +// +// Somewhere in the landing pad soup, we conditionally destroy arg1. +// WIN32: %[[isactive:.*]] = load i1* %[[arg1_cond]] +// WIN32: br i1 %[[isactive]] +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) +// WIN32: } + +namespace crash_on_partial_destroy { +struct A { + virtual ~A(); +}; + +struct B : virtual A { + // Has an implicit destructor. +}; + +struct C : B { + C(); +}; + +void foo(); +// We used to crash when emitting this. +C::C() { foo(); } + +// Verify that we don't bother with a vbtable lookup when adjusting the this +// pointer to call a base destructor from a constructor while unwinding. +// WIN32-LABEL: define {{.*}} @"\01??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} { +// WIN32: landingpad +// +// We shouldn't do any vbptr loads, just constant GEPs. +// WIN32-NOT: load +// WIN32: getelementptr i8* %{{.*}}, i32 4 +// WIN32-NOT: load +// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"* +// WIN32: invoke x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ" +// +// WIN32-NOT: load +// WIN32: bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8* +// WIN32-NOT: load +// WIN32: getelementptr inbounds i8* %{{.*}}, i64 4 +// WIN32-NOT: load +// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"* +// WIN32: invoke x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ" +// WIN32: } +} diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp index 3fffc9d..c0dcd3c 100755 --- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -1,16 +1,20 @@ // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// FIXME: Test x86_64 member pointers when codegen no longer asserts on records +// with virtual bases. struct B1 { void foo(); int b; }; struct B2 { + int b2; void foo(); }; struct Single : B1 { void foo(); }; struct Multiple : B1, B2 { + int m; void foo(); }; struct Virtual : virtual B1 { @@ -34,9 +38,11 @@ struct Polymorphic { // offset. struct NonZeroVBPtr : POD, Virtual { int n; + void foo(); }; struct Unspecified; +struct UnspecSingle; // Check that we can lower the LLVM types and get the null initializers right. int Single ::*s_d_memptr; @@ -45,29 +51,95 @@ int Multiple ::*m_d_memptr; int Virtual ::*v_d_memptr; int NonZeroVBPtr::*n_d_memptr; int Unspecified::*u_d_memptr; -// CHECK: @"\01?s_d_memptr@@3PQSingle@@HA" = global i32 -1, align 4 -// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HA" = global i32 0, align 4 -// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HA" = global i32 -1, align 4 -// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HA" = global { i32, i32 } +int UnspecSingle::*us_d_memptr; +// CHECK: @"\01?s_d_memptr@@3PQSingle@@HQ1@" = global i32 -1, align 4 +// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HQ1@" = global i32 0, align 4 +// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HQ1@" = global i32 -1, align 4 +// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HQ1@" = global { i32, i32 } // CHECK: { i32 0, i32 -1 }, align 4 -// CHECK: @"\01?n_d_memptr@@3PQNonZeroVBPtr@@HA" = global { i32, i32 } +// CHECK: @"\01?n_d_memptr@@3PQNonZeroVBPtr@@HQ1@" = global { i32, i32 } // CHECK: { i32 0, i32 -1 }, align 4 -// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HA" = global { i32, i32, i32 } +// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HQ1@" = global { i32, i32, i32 } +// CHECK: { i32 0, i32 0, i32 -1 }, align 4 +// CHECK: @"\01?us_d_memptr@@3PQUnspecSingle@@HQ1@" = global { i32, i32, i32 } // CHECK: { i32 0, i32 0, i32 -1 }, align 4 void (Single ::*s_f_memptr)(); void (Multiple::*m_f_memptr)(); void (Virtual ::*v_f_memptr)(); -// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZA" = global i8* null, align 4 -// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4 -// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4 +// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZQ1@" = global i8* null, align 4 +// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZQ1@" = global { i8*, i32 } zeroinitializer, align 4 +// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } zeroinitializer, align 4 // We can define Unspecified after locking in the inheritance model. -struct Unspecified : Virtual { +struct Unspecified : Multiple, Virtual { void foo(); int u; }; +struct UnspecSingle { + void foo(); +}; + +// Test memptr emission in a constant expression. +namespace Const { +void (Single ::*s_f_mp)() = &Single::foo; +void (Multiple ::*m_f_mp)() = &B2::foo; +void (Virtual ::*v_f_mp)() = &Virtual::foo; +void (Unspecified::*u_f_mp)() = &Unspecified::foo; +void (UnspecSingle::*us_f_mp)() = &UnspecSingle::foo; +// CHECK: @"\01?s_f_mp@Const@@3P8Single@@AEXXZQ2@" = +// CHECK: global i8* bitcast ({{.*}} @"\01?foo@Single@@QAEXXZ" to i8*), align 4 +// CHECK: @"\01?m_f_mp@Const@@3P8Multiple@@AEXXZQ2@" = +// CHECK: global { i8*, i32 } { i8* bitcast ({{.*}} @"\01?foo@B2@@QAEXXZ" to i8*), i32 4 }, align 4 +// CHECK: @"\01?v_f_mp@Const@@3P8Virtual@@AEXXZQ2@" = +// CHECK: global { i8*, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, align 4 +// CHECK: @"\01?u_f_mp@Const@@3P8Unspecified@@AEXXZQ2@" = +// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 }, align 4 +// CHECK: @"\01?us_f_mp@Const@@3P8UnspecSingle@@AEXXZQ2@" = +// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@UnspecSingle@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, align 4 +} + +namespace CastParam { +// This exercises ConstExprEmitter instead of ValueDecl::evaluateValue. The +// extra reinterpret_cast for the parameter type requires more careful folding. +// FIXME: Or does it? If reinterpret_casts are no-ops, we should be able to +// strip them in evaluateValue() and just proceed as normal with an APValue. +struct A { + int a; + void foo(A *p); +}; +struct B { int b; }; +struct C : B, A { int c; }; + +void (A::*ptr1)(void *) = (void (A::*)(void *)) &A::foo; +// CHECK: @"\01?ptr1@CastParam@@3P8A@1@AEXPAX@ZQ21@" = +// CHECK: global i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), align 4 + +// Try a reinterpret_cast followed by a memptr conversion. +void (C::*ptr2)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) &A::foo; +// CHECK: @"\01?ptr2@CastParam@@3P8C@1@AEXPAX@ZQ21@" = +// CHECK: global { i8*, i32 } { i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), i32 4 }, align 4 + +void (C::*ptr3)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) (void (A::*)(A *)) 0; +// CHECK: @"\01?ptr3@CastParam@@3P8C@1@AEXPAX@ZQ21@" = +// CHECK: global { i8*, i32 } zeroinitializer, align 4 + +struct D : C { + virtual void isPolymorphic(); + int d; +}; + +// Try a cast that changes the inheritance model. Null for D is 0, but null for +// C is -1. We need the cast to long in order to hit the non-APValue path. +int C::*ptr4 = (int C::*) (int D::*) (long D::*) 0; +// CHECK: @"\01?ptr4@CastParam@@3PQC@1@HQ21@" = global i32 -1, align 4 + +// MSVC rejects this but we accept it. +int C::*ptr5 = (int C::*) (long D::*) 0; +// CHECK: @"\01?ptr5@CastParam@@3PQC@1@HQ21@" = global i32 -1, align 4 +} + struct UnspecWithVBPtr; int UnspecWithVBPtr::*forceUnspecWithVBPtr; struct UnspecWithVBPtr : B1, virtual B2 { @@ -82,7 +154,7 @@ void EmitNonVirtualMemberPointers() { void (Virtual ::*v_f_memptr)() = &Virtual::foo; void (Unspecified::*u_f_memptr)() = &Unspecified::foo; void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo; -// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() #0 { +// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() {{.*}} { // CHECK: alloca i8*, align 4 // CHECK: alloca { i8*, i32 }, align 4 // CHECK: alloca { i8*, i32, i32 }, align 4 @@ -95,7 +167,7 @@ void EmitNonVirtualMemberPointers() { // CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, // CHECK: { i8*, i32, i32 }* %{{.*}}, align 4 // CHECK: store { i8*, i32, i32, i32 } -// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 }, // CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4 // CHECK: store { i8*, i32, i32, i32 } // CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@UnspecWithVBPtr@@QAEXXZ" to i8*), @@ -112,7 +184,7 @@ void podMemPtrs() { if (memptr) memptr = 0; // Check that member pointers use the right offsets and that null is -1. -// CHECK: define void @"\01?podMemPtrs@@YAXXZ"() #0 { +// CHECK: define void @"\01?podMemPtrs@@YAXXZ"() {{.*}} { // CHECK: %[[memptr:.*]] = alloca i32, align 4 // CHECK-NEXT: store i32 0, i32* %[[memptr]], align 4 // CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4 @@ -132,7 +204,7 @@ void polymorphicMemPtrs() { memptr = 0; // Member pointers for polymorphic classes include the vtable slot in their // offset and use 0 to represent null. -// CHECK: define void @"\01?polymorphicMemPtrs@@YAXXZ"() #0 { +// CHECK: define void @"\01?polymorphicMemPtrs@@YAXXZ"() {{.*}} { // CHECK: %[[memptr:.*]] = alloca i32, align 4 // CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4 // CHECK-NEXT: store i32 8, i32* %[[memptr]], align 4 @@ -233,7 +305,7 @@ int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) { void callMemberPointerSingle(Single *o, void (Single::*memptr)()) { (o->*memptr)(); // Just look for an indirect thiscall. -// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} #0 { +// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} {{.*}} { // CHECK: call x86_thiscallcc void %{{.*}}(%{{.*}} %{{.*}}) // CHECK: ret void // CHECK: } @@ -241,7 +313,7 @@ void callMemberPointerSingle(Single *o, void (Single::*memptr)()) { void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) { (o->*memptr)(); -// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} #0 { +// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} { // CHECK: %[[memptr0:.*]] = extractvalue { i8*, i32 } %{{.*}}, 0 // CHECK: %[[memptr1:.*]] = extractvalue { i8*, i32 } %{{.*}}, 1 // CHECK: %[[this_adjusted:.*]] = getelementptr inbounds i8* %{{.*}}, i32 %[[memptr1]] @@ -255,7 +327,7 @@ void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) { void callMemberPointerVirtualBase(Virtual *o, void (Virtual::*memptr)()) { (o->*memptr)(); // This shares a lot with virtual data member pointers. -// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} #0 { +// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} { // CHECK: %[[memptr0:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 0 // CHECK: %[[memptr1:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 1 // CHECK: %[[memptr2:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 2 @@ -361,3 +433,107 @@ bool unspecDataMemptrEq(int Unspecified::*l, int Unspecified::*r) { // CHECK: ret i1 // CHECK: } } + +void (Multiple::*convertB2FuncToMultiple(void (B2::*mp)()))() { + return mp; +// CHECK: define i64 @"\01?convertB2FuncToMultiple@@YAP8Multiple@@AEXXZP8B2@@AEXXZ@Z"{{.*}} { +// CHECK: store +// CHECK: %[[mp:.*]] = load i8** %{{.*}}, align 4 +// CHECK: icmp ne i8* %[[mp]], null +// CHECK: br i1 %{{.*}} label %{{.*}}, label %{{.*}} +// +// memptr.convert: ; preds = %entry +// CHECK: insertvalue { i8*, i32 } undef, i8* %[[mp]], 0 +// CHECK: insertvalue { i8*, i32 } %{{.*}}, i32 4, 1 +// CHECK: br label +// +// memptr.converted: ; preds = %memptr.convert, %entry +// CHECK: phi { i8*, i32 } [ zeroinitializer, %{{.*}} ], [ {{.*}} ] +// CHECK: } +} + +void (B2::*convertMultipleFuncToB2(void (Multiple::*mp)()))() { +// FIXME: cl emits warning C4407 on this code because of the representation +// change. We might want to do the same. + return static_cast<void (B2::*)()>(mp); +// FIXME: We should return i8* instead of i32 here. The ptrtoint cast prevents +// LLVM from optimizing away the branch. This is likely a bug in +// lib/CodeGen/TargetInfo.cpp with how we classify memptr types for returns. +// +// CHECK: define i32 @"\01?convertMultipleFuncToB2@@YAP8B2@@AEXXZP8Multiple@@AEXXZ@Z"{{.*}} { +// CHECK: store +// CHECK: %[[src:.*]] = load { i8*, i32 }* %{{.*}}, align 4 +// CHECK: extractvalue { i8*, i32 } %[[src]], 0 +// CHECK: icmp ne i8* %{{.*}}, null +// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} +// +// memptr.convert: ; preds = %entry +// CHECK: %[[fp:.*]] = extractvalue { i8*, i32 } %[[src]], 0 +// CHECK: br label +// +// memptr.converted: ; preds = %memptr.convert, %entry +// CHECK: phi i8* [ null, %{{.*}} ], [ %[[fp]], %{{.*}} ] +// CHECK: } +} + +namespace Test1 { + +struct A { int a; }; +struct B { int b; }; +struct C : virtual A { int c; }; +struct D : B, C { int d; }; + +void (D::*convertCToD(void (C::*mp)()))() { + return mp; +// CHECK: define void @"\01?convertCToD@Test1@@YAP8D@1@AEXXZP8C@1@AEXXZ@Z"{{.*}} { +// CHECK: store +// CHECK: load { i8*, i32, i32 }* %{{.*}}, align 4 +// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 0 +// CHECK: icmp ne i8* %{{.*}}, null +// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} +// +// memptr.convert: ; preds = %entry +// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 0 +// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 1 +// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 2 +// CHECK: %[[adj:.*]] = add nsw i32 %{{.*}}, 4 +// CHECK: insertvalue { i8*, i32, i32 } undef, i8* {{.*}}, 0 +// CHECK: insertvalue { i8*, i32, i32 } {{.*}}, i32 %[[adj]], 1 +// CHECK: insertvalue { i8*, i32, i32 } {{.*}}, i32 {{.*}}, 2 +// CHECK: br label +// +// memptr.converted: ; preds = %memptr.convert, %entry +// CHECK: phi { i8*, i32, i32 } [ { i8* null, i32 0, i32 -1 }, {{.*}} ], [ {{.*}} ] +// CHECK: } +} + +} + +namespace Test2 { +// Test that we dynamically convert between different null reps. + +struct A { int a; }; +struct B : A { int b; }; +struct C : A { + int c; + virtual void hasVfPtr(); +}; + +int A::*reinterpret(int B::*mp) { + return reinterpret_cast<int A::*>(mp); +// CHECK: define i32 @"\01?reinterpret@Test2@@YAPQA@1@HPQB@1@H@Z"{{.*}} { +// CHECK-NOT: select +// CHECK: ret i32 +// CHECK: } +} + +int A::*reinterpret(int C::*mp) { + return reinterpret_cast<int A::*>(mp); +// CHECK: define i32 @"\01?reinterpret@Test2@@YAPQA@1@HPQC@1@H@Z"{{.*}} { +// CHECK: %[[mp:.*]] = load i32* +// CHECK: %[[cmp:.*]] = icmp ne i32 %[[mp]], 0 +// CHECK: select i1 %[[cmp]], i32 %[[mp]], i32 -1 +// CHECK: } +} + +} diff --git a/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp new file mode 100644 index 0000000..802f0ca --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp @@ -0,0 +1,201 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct Left { + virtual void left(); +}; + +struct Right { + virtual void right(); +}; + +struct ChildNoOverride : Left, Right { +}; + +struct ChildOverride : Left, Right { + virtual void left(); + virtual void right(); +}; + +extern "C" void foo(void *); + +void call_left_no_override(ChildNoOverride *child) { +// CHECK: define void @"\01?call_left_no_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride + + child->left(); +// Only need to cast 'this' to Left*. +// CHECK: %[[LEFT:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to %struct.Left* +// CHECK: %[[VFPTR:.*]] = bitcast %struct.Left* %[[LEFT]] to void (%struct.Left*)*** +// CHECK: %[[VFTABLE:.*]] = load void (%struct.Left*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Left*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Left*)** %[[VFUN]] +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Left* %[[LEFT]]) +// CHECK: ret +} + +void ChildOverride::left() { +// CHECK: define x86_thiscallcc void @"\01?left@ChildOverride@@UAEXXZ"(%struct.ChildOverride* %[[THIS:.*]]) +// +// No need to adjust 'this' as the ChildOverride's layout begins with Left. +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4 +// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4 + + foo(this); +// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]] +// CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8* +// CHECK: call void @foo(i8* %[[THIS_i8]]) +// CHECK: ret +} + +void call_left_override(ChildOverride *child) { +// CHECK: define void @"\01?call_left_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride + + child->left(); +// CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to void (%struct.ChildOverride*)*** +// CHECK: %[[VFTABLE:.*]] = load void (%struct.ChildOverride*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.ChildOverride*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.ChildOverride*)** %[[VFUN]] +// +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.ChildOverride* %[[CHILD]]) +// CHECK: ret +} + +void call_right_no_override(ChildNoOverride *child) { +// CHECK: define void @"\01?call_right_no_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride + + child->right(); +// When calling a right base's virtual method, one needs to adjust 'this' at +// the caller site. +// +// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to i8* +// CHECK: %[[RIGHT_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4 +// CHECK: %[[RIGHT:.*]] = bitcast i8* %[[RIGHT_i8]] to %struct.Right* +// +// CHECK: %[[VFPTR:.*]] = bitcast %struct.Right* %[[RIGHT]] to void (%struct.Right*)*** +// CHECK: %[[VFTABLE:.*]] = load void (%struct.Right*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Right*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Right*)** %[[VFUN]] +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Right* %[[RIGHT]]) +// CHECK: ret +} + +void ChildOverride::right() { +// CHECK: define x86_thiscallcc void @"\01?right@ChildOverride@@UAEXXZ"(i8* +// +// ChildOverride::right gets 'this' cast to Right* in ECX (i.e. this+4) so we +// need to adjust 'this' before use. +// +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4 +// CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ECX:.*]], i32 -4 +// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.ChildOverride* +// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4 + + foo(this); +// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]] +// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8* +// CHECK: call void @foo(i8* %[[THIS_PARAM]]) +// CHECK: ret +} + +void call_right_override(ChildOverride *child) { +// CHECK: define void @"\01?call_right_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride + + child->right(); +// When calling a right child's virtual method, one needs to adjust 'this' at +// the caller site. +// +// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8* +// +// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4 +// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to void (i8*)*** +// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]] +// +// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8* +// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4 +// +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[RIGHT]]) +// CHECK: ret +} + +struct GrandchildOverride : ChildOverride { + virtual void right(); +}; + +void GrandchildOverride::right() { +// CHECK: define x86_thiscallcc void @"\01?right@GrandchildOverride@@UAEXXZ"(i8* +// +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.GrandchildOverride*, align 4 +// CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ECX:.*]], i32 -4 +// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.GrandchildOverride* +// CHECK: store %struct.GrandchildOverride* %[[THIS]], %struct.GrandchildOverride** %[[THIS_ADDR]], align 4 + + foo(this); +// CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride** %[[THIS_ADDR]] +// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8* +// CHECK: call void @foo(i8* %[[THIS_PARAM]]) +// CHECK: ret +} + +void call_grandchild_right(GrandchildOverride *obj) { + // Just make sure we don't crash. + obj->right(); +} + +void emit_ctors() { + Left l; + // CHECK: define {{.*}} @"\01??0Left@@QAE@XZ" + // CHECK-NOT: getelementptr + // CHECK: store [1 x i8*]* @"\01??_7Left@@6B@" + // CHECK: ret + + Right r; + // CHECK: define {{.*}} @"\01??0Right@@QAE@XZ" + // CHECK-NOT: getelementptr + // CHECK: store [1 x i8*]* @"\01??_7Right@@6B@" + // CHECK: ret + + ChildOverride co; + // CHECK: define {{.*}} @"\01??0ChildOverride@@QAE@XZ" + // CHECK: %[[THIS:.*]] = load %struct.ChildOverride** + // CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8* + // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4 + // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: ret + + GrandchildOverride gc; + // CHECK: define {{.*}} @"\01??0GrandchildOverride@@QAE@XZ" + // CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride** + // CHECK: %[[VFPTR:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8* + // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4 + // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: ret +} + +struct LeftWithNonVirtualDtor { + virtual void left(); + ~LeftWithNonVirtualDtor(); +}; + +struct AsymmetricChild : LeftWithNonVirtualDtor, Right { + virtual ~AsymmetricChild(); +}; + +void call_asymmetric_child_complete_dtor() { + // CHECK-LABEL: define void @"\01?call_asymmetric_child_complete_dtor@@YAXXZ" + AsymmetricChild obj; + // CHECK: call x86_thiscallcc %struct.AsymmetricChild* @"\01??0AsymmetricChild@@QAE@XZ"(%struct.AsymmetricChild* %[[OBJ:.*]]) + // CHECK-NOT: getelementptr + // CHECK: call x86_thiscallcc void @"\01??1AsymmetricChild@@UAE@XZ"(%struct.AsymmetricChild* %[[OBJ]]) + // CHECK: ret +} diff --git a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp index 060c172..d0750e6 100644 --- a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp +++ b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-linux | FileCheck -check-prefix LINUX %s -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -cxx-abi microsoft | FileCheck -check-prefix WIN32 %s -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 -cxx-abi microsoft | FileCheck -check-prefix WIN64 %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fno-rtti | FileCheck -check-prefix WIN32 %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fno-rtti | FileCheck -check-prefix WIN64 %s struct Empty {}; @@ -22,6 +22,12 @@ struct SmallWithCtor { int x; }; +struct SmallWithDtor { + SmallWithDtor(); + ~SmallWithDtor(); + int x; +}; + struct SmallWithVftable { int x; virtual void foo(); @@ -43,70 +49,108 @@ struct Big { // Returning structs that fit into a register. Small small_return() { return Small(); } -// LINUX: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result) // WIN32: define i32 @"\01?small_return@@YA?AUSmall@@XZ"() // WIN64: define i32 @"\01?small_return@@YA?AUSmall@@XZ"() Medium medium_return() { return Medium(); } -// LINUX: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result) // WIN32: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"() // WIN64: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"() // Returning structs that fit into a register but are not POD. SmallCpp11NotCpp03Pod small_non_pod_return() { return SmallCpp11NotCpp03Pod(); } -// LINUX: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) // WIN32: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) // WIN64: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) SmallWithCtor small_with_ctor_return() { return SmallWithCtor(); } -// LINUX: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result) // WIN32: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) // WIN64: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) SmallWithVftable small_with_vftable_return() { return SmallWithVftable(); } -// LINUX: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result) // WIN32: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) // WIN64: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) MediumWithCopyCtor medium_with_copy_ctor_return() { return MediumWithCopyCtor(); } -// LINUX: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result) // WIN32: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) // WIN64: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) // Returning a large struct that doesn't fit into a register. Big big_return() { return Big(); } -// LINUX: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result) // WIN32: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) // WIN64: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) void small_arg(Small s) {} -// LINUX: define void @_Z9small_arg5Small(%struct.Small* byval align 4 %s) +// LINUX-LABEL: define void @_Z9small_arg5Small(%struct.Small* byval align 4 %s) // WIN32: define void @"\01?small_arg@@YAXUSmall@@@Z"(%struct.Small* byval align 4 %s) // WIN64: define void @"\01?small_arg@@YAXUSmall@@@Z"(i32 %s.coerce) void medium_arg(Medium s) {} -// LINUX: define void @_Z10medium_arg6Medium(%struct.Medium* byval align 4 %s) +// LINUX-LABEL: define void @_Z10medium_arg6Medium(%struct.Medium* byval align 4 %s) // WIN32: define void @"\01?medium_arg@@YAXUMedium@@@Z"(%struct.Medium* byval align 4 %s) // WIN64: define void @"\01?medium_arg@@YAXUMedium@@@Z"(i64 %s.coerce) void small_arg_with_ctor(SmallWithCtor s) {} -// LINUX: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s) +// LINUX-LABEL: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s) // WIN32: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(%struct.SmallWithCtor* byval align 4 %s) // WIN64: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.coerce) +// Test that dtors are invoked in the callee. +void small_arg_with_dtor(SmallWithDtor s) {} +// WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval align 4 %s) {{.*}} { +// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"(%struct.SmallWithDtor* %s) +// WIN32: } +// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval %s) {{.*}} { +// WIN64: call void @"\01??1SmallWithDtor@@QEAA@XZ"(%struct.SmallWithDtor* %s) +// WIN64: } + +// Test that references aren't destroyed in the callee. +void ref_small_arg_with_dtor(const SmallWithDtor &s) { } +// WIN32: define void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} { +// WIN32-NOT: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ" +// WIN32: } + +// Test that temporaries passed by reference are destroyed in the caller. +void temporary_ref_with_dtor() { + ref_small_arg_with_dtor(SmallWithDtor()); +} +// WIN32: define void @"\01?temporary_ref_with_dtor@@YAXXZ"() {{.*}} { +// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ" +// WIN32: call void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z" +// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ" +// WIN32: } + +void takes_two_by_val_with_dtor(SmallWithDtor a, SmallWithDtor b); +void eh_cleanup_arg_with_dtor() { + takes_two_by_val_with_dtor(SmallWithDtor(), SmallWithDtor()); +} +// When exceptions are off, we don't have any cleanups. See +// microsoft-abi-exceptions.cpp for these cleanups. +// WIN32: define void @"\01?eh_cleanup_arg_with_dtor@@YAXXZ"() {{.*}} { +// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ" +// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ" +// WIN32: call void @"\01?takes_two_by_val_with_dtor@@YAXUSmallWithDtor@@0@Z" +// WIN32-NOT: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ" +// WIN32: } + void small_arg_with_vftable(SmallWithVftable s) {} -// LINUX: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s) +// LINUX-LABEL: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s) // WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval align 4 %s) // WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval %s) void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {} -// LINUX: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s) +// LINUX-LABEL: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s) // WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval align 4 %s) // WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval %s) void big_arg(Big s) {} -// LINUX: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s) +// LINUX-LABEL: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s) // WIN32: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* byval align 4 %s) // WIN64: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* %s) @@ -167,3 +211,19 @@ void use_class() { c.thiscall_method_arg(SmallWithCtor()); c.thiscall_method_arg(Big()); } + +struct X { + X(); + ~X(); +}; +void g(X) { +} +// WIN32: define void @"\01?g@@YAXUX@@@Z"(%struct.X* byval align 4) {{.*}} { +// WIN32: call x86_thiscallcc void @"\01??1X@@QAE@XZ"(%struct.X* %0) +// WIN32: } +void f() { + g(X()); +} +// WIN32: define void @"\01?f@@YAXXZ"() {{.*}} { +// WIN32-NOT: call {{.*}} @"\01??1X@@QAE@XZ" +// WIN32: } diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp index 35e343b..c0b9722 100644 --- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp +++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -1,19 +1,85 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()* }] +// CHECK: [{ i32, void ()* } { i32 65535, void ()* @"\01??__Efoo@?$B@H@@YAXXZ" }, +// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] struct S { - S() {} - ~S() {} -} s; + S(); + ~S(); +}; -// CHECK: define internal void [[INIT_s:@.*global_var.*]] [[NUW:#[0-9]+]] +S s; + +// CHECK: define internal void @"\01??__Es@@YAXXZ"() [[NUW:#[0-9]+]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A") +// CHECK: call i32 @atexit(void ()* @"\01??__Fs@@YAXXZ") // CHECK: ret void -// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() [[NUW]] { +// CHECK: define internal void @"\01??__Fs@@YAXXZ"() [[NUW]] { // CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ" // CHECK: ret void +void StaticLocal() { + static S TheS; +} +// CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: ret + +void MultipleStatics() { + static S S1; + static S S2; + static S S3; + static S S4; + static S S5; + static S S6; + static S S7; + static S S8; + static S S9; + static S S10; + static S S11; + static S S12; + static S S13; + static S S14; + static S S15; + static S S16; + static S S17; + static S S18; + static S S19; + static S S20; + static S S21; + static S S22; + static S S23; + static S S24; + static S S25; + static S S26; + static S S27; + static S S28; + static S S29; + static S S30; + static S S31; + static S S32; + static S S33; + static S S34; + static S S35; +} +// CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: and i32 {{.*}}, 8 +// CHECK: and i32 {{.*}}, 16 +// ... +// CHECK: and i32 {{.*}}, -2147483648 +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA1" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: ret + // Force WeakODRLinkage by using templates class A { public: @@ -29,26 +95,60 @@ class B { template<typename T> A B<T>::foo; +inline S &UnreachableStatic() { + if (0) { + static S s; // bit 1 + return s; + } + static S s; // bit 2 + return s; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?UnreachableStatic@@YAAAUS@@XZ"() +// CHECK: and i32 {{.*}}, 2 +// CHECK: or i32 {{.*}}, 2 +// CHECK: ret + +inline S &getS() { + static S TheS; + return TheS; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?getS@@YAAAUS@@XZ" +// CHECK: load i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: and i32 {{.*}}, 1 +// CHECK: icmp ne i32 {{.*}}, 0 +// CHECK: br i1 +// init: +// CHECK: or i32 {{.*}}, 1 +// CHECK: store i32 {{.*}}, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"(%struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A") +// CHECK: call i32 @atexit(void ()* @"\01??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ") +// CHECK: br label +// init.end: +// CHECK: ret %struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A" + void force_usage() { + UnreachableStatic(); + getS(); (void)B<int>::foo; // (void) - force usage } -// CHECK: define internal void [[INIT_foo:@.*global_var.*]] [[NUW]] +// CHECK: define internal void @"\01??__Efoo@?$B@H@@YAXXZ"() [[NUW]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]]) +// CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B@H@@YAXXZ") // CHECK: ret void // CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" // CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ" -// CHECK: define internal void [[FOO_DTOR]] +// CHECK: define internal void @"\01??__Ffoo@?$B@H@@YAXXZ" // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo // CHECK: ret void // CHECK: define internal void @_GLOBAL__I_a() [[NUW]] { -// CHECK: call void [[INIT_s]] -// CHECK: call void [[INIT_foo]] +// CHECK: call void @"\01??__Es@@YAXXZ"() // CHECK: ret void // CHECK: attributes [[NUW]] = { nounwind } diff --git a/test/CodeGenCXX/microsoft-abi-structors-alias.cpp b/test/CodeGenCXX/microsoft-abi-structors-alias.cpp new file mode 100644 index 0000000..d54520f --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-structors-alias.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti -mconstructor-aliases | FileCheck %s + +namespace test1 { +template <typename T> class A { + ~A() {} +}; +template class A<char>; +// CHECK: define weak_odr x86_thiscallcc void @"\01??1?$A@D@test1@@AAE@XZ" +} diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp index 864540d..c2f1395 100644 --- a/test/CodeGenCXX/microsoft-abi-structors.cpp +++ b/test/CodeGenCXX/microsoft-abi-structors.cpp @@ -1,27 +1,31 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t 2>&1 +// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t // RUN: FileCheck %s < %t -// Using a different check prefix as the inline destructors might be placed -// anywhere in the output. -// RUN: FileCheck --check-prefix=DTORS %s < %t +// vftables are emitted very late, so do another pass to try to keep the checks +// in source order. +// RUN: FileCheck --check-prefix DTORS %s < %t +// +// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -cxx-abi microsoft -triple=x86_64-pc-win32 -fno-rtti | FileCheck --check-prefix DTORS-X64 %s namespace basic { class A { public: A() { } - ~A() { } + ~A(); }; void no_constructor_destructor_infinite_recursion() { A a; -// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %this) +// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* returned %this) // CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4 // CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4 // CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]] // CHECK-NEXT: ret %"class.basic::A"* [[T1]] // CHECK-NEXT: } +} +A::~A() { // Make sure that the destructor doesn't call itself: // CHECK: define {{.*}} @"\01??1A@basic@@QAE@XZ" // CHECK-NOT: call void @"\01??1A@basic@@QAE@XZ" @@ -34,33 +38,29 @@ struct B { // Tests that we can define constructors outside the class (PR12784). B::B() { - // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %this) + // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* returned %this) // CHECK: ret } struct C { virtual ~C() { -// Complete destructor first: -// DTORS: define {{.*}} x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %this) - -// Then, the scalar deleting destructor (used in the vtable): -// FIXME: add a test that verifies that the out-of-line scalar deleting -// destructor is linkonce_odr too. -// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i1 zeroext %should_call_delete) -// DTORS: %[[FROMBOOL:[0-9a-z]+]] = zext i1 %should_call_delete to i8 -// DTORS-NEXT: store i8 %[[FROMBOOL]], i8* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 1 -// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i8* %[[SHOULD_DELETE_VAR]] +// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i32 %should_call_delete) +// DTORS: store i32 %should_call_delete, i32* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4 +// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32* %[[SHOULD_DELETE_VAR]] // DTORS: call x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %[[THIS:[0-9a-z]+]]) -// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i8 %[[SHOULD_DELETE_VALUE]], 0 +// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i32 %[[SHOULD_DELETE_VALUE]], 0 // DTORS-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]] // // DTORS: [[CALL_DELETE_LABEL]] // DTORS-NEXT: %[[THIS_AS_VOID:[0-9a-z]+]] = bitcast %"struct.basic::C"* %[[THIS]] to i8* -// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[THIS_AS_VOID]]) [[NUW:#[0-9]+]] +// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[THIS_AS_VOID]]) // DTORS-NEXT: br label %[[CONTINUE_LABEL]] // // DTORS: [[CONTINUE_LABEL]] // DTORS-NEXT: ret void + +// Check that we do the mangling correctly on x64. +// DTORS-X64: @"\01??_GC@basic@@UEAAPEAXI@Z" } virtual void foo(); }; @@ -71,19 +71,19 @@ void C::foo() {} void check_vftable_offset() { C c; // The vftable pointer should point at the beginning of the vftable. -// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to i8*** -// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7C@basic@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]] +// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to [2 x i8*]** +// CHECK: store [2 x i8*]* @"\01??_7C@basic@@6B@", [2 x i8*]** [[THIS_PTR]] } void call_complete_dtor(C *obj_ptr) { // CHECK: define void @"\01?call_complete_dtor@basic@@YAXPAUC@1@@Z"(%"struct.basic::C"* %obj_ptr) obj_ptr->~C(); // CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4 -// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)*** -// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]] -// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0 -// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]] -// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext false) +// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)*** +// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]] +// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0 +// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]] +// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0) // CHECK-NEXT: ret void } @@ -94,11 +94,11 @@ void call_deleting_dtor(C *obj_ptr) { // CHECK: br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]] // CHECK: [[DELETE_NOTNULL]] -// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)*** -// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]] -// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0 -// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]] -// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext true) +// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)*** +// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]] +// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0 +// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]] +// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 1) // CHECK: ret void } @@ -119,8 +119,6 @@ struct D { void use_D() { D c; } -// DTORS: attributes [[NUW]] = { nounwind{{.*}} } - } // end namespace basic @@ -136,7 +134,7 @@ struct B : A { }; B::B() { - // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %this) + // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* returned %this) // CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}}) // CHECK: ret } @@ -146,7 +144,7 @@ struct C : virtual A { }; C::C() { - // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived) + // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* returned %this, i32 %is_most_derived) // TODO: make sure this works in the Release build too; // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] @@ -154,12 +152,19 @@ C::C() { // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] // // CHECK: [[INIT_VBASES]] - // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to %"struct.constructors::A"* + // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::C"* %{{.*}} to i8* + // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0 + // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]** + // CHECK-NEXT: store [2 x i32]* @"\01??_8C@constructors@@7B@", [2 x i32]** %[[vbptr]] + // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to i8* + // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4 + // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"* // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}}) // CHECK-NEXT: br label %[[SKIP_VBASES]] // // CHECK: [[SKIP_VBASES]] - // CHECK: @"\01??_7C@constructors@@6B@" + // Class C does not define or override methods, so shouldn't change the vfptr. + // CHECK-NOT: @"\01??_7C@constructors@@6B@" // CHECK: ret } @@ -175,14 +180,20 @@ struct D : C { }; D::D() { - // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr + // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* returned %this, i32 %is_most_derived) unnamed_addr // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0 // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] // // CHECK: [[INIT_VBASES]] - // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to %"struct.constructors::A"* + // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::D"* %{{.*}} to i8* + // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0 + // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]** + // CHECK-NEXT: store [2 x i32]* @"\01??_8D@constructors@@7B@", [2 x i32]** %[[vbptr]] + // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to i8* + // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4 + // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"* // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}}) // CHECK-NEXT: br label %[[SKIP_VBASES]] // @@ -196,14 +207,23 @@ struct E : virtual C { }; E::E() { - // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr + // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* returned %this, i32 %is_most_derived) unnamed_addr // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0 // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] // // CHECK: [[INIT_VBASES]] - // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to %"struct.constructors::A"* + // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::E"* %{{.*}} to i8* + // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0 + // CHECK-NEXT: %[[vbptr_E:.*]] = bitcast i8* %[[offs]] to [3 x i32]** + // CHECK-NEXT: store [3 x i32]* @"\01??_8E@constructors@@7B01@@", [3 x i32]** %[[vbptr_E]] + // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 4 + // CHECK-NEXT: %[[vbptr_C:.*]] = bitcast i8* %[[offs]] to [2 x i32]** + // CHECK-NEXT: store [2 x i32]* @"\01??_8E@constructors@@7BC@1@@", [2 x i32]** %[[vbptr_C]] + // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to i8* + // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4 + // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"* // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}}) // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %{{.*}}, i32 0) // CHECK-NEXT: br label %[[SKIP_VBASES]] @@ -212,4 +232,70 @@ E::E() { // CHECK: ret } +// PR16735 - even abstract classes should have a constructor emitted. +struct F { + F(); + virtual void f() = 0; +}; + +F::F() {} +// CHECK: define x86_thiscallcc %"struct.constructors::F"* @"\01??0F@constructors@@QAE@XZ" + } // end namespace constructors + +namespace dtors { + +struct A { + ~A(); +}; + +void call_nv_complete(A *a) { + a->~A(); +// CHECK: define void @"\01?call_nv_complete@dtors@@YAXPAUA@1@@Z" +// CHECK: call x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ" +// CHECK: ret +} + +// CHECK: declare x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ" + +// Now try some virtual bases, where we need the complete dtor. + +struct B : virtual A { ~B(); }; +struct C : virtual A { ~C(); }; +struct D : B, C { ~D(); }; + +void call_vbase_complete(D *d) { + d->~D(); +// CHECK: define void @"\01?call_vbase_complete@dtors@@YAXPAUD@1@@Z" +// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}}) +// CHECK: ret +} + +// The complete dtor should call the base dtors for D and the vbase A (once). +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ" +// CHECK-NOT: call +// CHECK: call x86_thiscallcc void @"\01??1D@dtors@@QAE@XZ" +// CHECK-NOT: call +// CHECK: call x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ" +// CHECK-NOT: call +// CHECK: ret + +void destroy_d_complete() { + D d; +// CHECK: define void @"\01?destroy_d_complete@dtors@@YAXXZ" +// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}}) +// CHECK: ret +} + +// FIXME: Clang manually inlines the deletion, so we don't get a call to the +// deleting dtor (_G). The only way to call deleting dtors currently is through +// a vftable. +void call_nv_deleting_dtor(D *d) { + delete d; +// CHECK: define void @"\01?call_nv_deleting_dtor@dtors@@YAXPAUD@1@@Z" +// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}}) +// CHECK: call void @"\01??3@YAXPAX@Z" +// CHECK: ret +} + +} diff --git a/test/CodeGenCXX/microsoft-abi-thunks.cpp b/test/CodeGenCXX/microsoft-abi-thunks.cpp new file mode 100644 index 0000000..f1bc385 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-thunks.cpp @@ -0,0 +1,154 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 >%t 2>&1 +// RUN: FileCheck --check-prefix=MANGLING %s < %t +// RUN: FileCheck --check-prefix=XMANGLING %s < %t +// RUN: FileCheck --check-prefix=CODEGEN %s < %t +// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 2>&1 | FileCheck --check-prefix=MANGLING-X64 %s + +void foo(void *); + +struct A { + virtual ~A(); + virtual void public_f(); + // Make sure we don't emit unneeded thunks: + // XMANGLING-NOT: @"\01?public_f@A@@QAEXXZ" + protected: + virtual void protected_f(); + private: + virtual void private_f(); +}; + +struct B { + virtual ~B(); + virtual void public_f(); + protected: + virtual void protected_f(); + private: + virtual void private_f(); +}; + + +struct C : A, B { + C(); + + virtual ~C(); + // MANGLING-DAG: @"\01??1C@@UAE@XZ" + // MANGLING-DAG: @"\01??_GC@@UAEPAXI@Z" + // MANGLING-DAG: @"\01??_EC@@W3AEPAXI@Z" + // MANGLING-X64-DAG: @"\01??1C@@UEAA@XZ" + // MANGLING-X64-DAG: @"\01??_GC@@UEAAPEAXI@Z" + // MANGLING-X64-DAG: @"\01??_EC@@W7EAAPEAXI@Z" + + // Overrides public_f() of two subobjects with distinct vfptrs, thus needs a thunk. + virtual void public_f(); + // MANGLING-DAG: @"\01?public_f@C@@UAEXXZ" + // MANGLING-DAG: @"\01?public_f@C@@W3AEXXZ" + // MANGLING-X64-DAG: @"\01?public_f@C@@UEAAXXZ" + // MANGLING-X64-DAG: @"\01?public_f@C@@W7EAAXXZ" + protected: + virtual void protected_f(); + // MANGLING-DAG: @"\01?protected_f@C@@MAEXXZ" + // MANGLING-DAG: @"\01?protected_f@C@@O3AEXXZ" + // MANGLING-X64-DAG: @"\01?protected_f@C@@MEAAXXZ" + // MANGLING-X64-DAG: @"\01?protected_f@C@@O7EAAXXZ" + + private: + virtual void private_f(); + // MANGLING-DAG: @"\01?private_f@C@@EAEXXZ" + // MANGLING-DAG: @"\01?private_f@C@@G3AEXXZ" + // MANGLING-X64-DAG: @"\01?private_f@C@@EEAAXXZ" + // MANGLING-X64-DAG: @"\01?private_f@C@@G7EAAXXZ" +}; + +C::C() {} // Emits vftable and forces thunk generation. + +// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete) +// CODEGEN: getelementptr i8* {{.*}}, i32 -4 +// FIXME: should actually call _EC, not _GC. +// CODEGEN: call x86_thiscallcc void @"\01??_GC@@UAEPAXI@Z" +// CODEGEN: ret + +// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C* +// CODEGEN: getelementptr i8* {{.*}}, i32 -4 +// CODEGEN: call x86_thiscallcc void @"\01?public_f@C@@UAEXXZ"(%struct.C* +// CODEGEN: ret + +void zoo(C* obj) { + delete obj; +} + +struct D { + virtual B* goo(); +}; + +struct E : D { + E(); + virtual C* goo(); + // MANGLING-DAG: @"\01?goo@E@@UAEPAUC@@XZ" + // MANGLING-DAG: @"\01?goo@E@@QAEPAUB@@XZ" + // MANGLING-X64-DAG: @"\01?goo@E@@UEAAPEAUC@@XZ" + // MANGLING-X64-DAG: @"\01?goo@E@@QEAAPEAUB@@XZ" +}; + +E::E() {} // Emits vftable and forces thunk generation. + +// CODEGEN-LABEL: define weak x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ" +// CODEGEN: call x86_thiscallcc %struct.C* @"\01?goo@E@@UAEPAUC@@XZ" +// CODEGEN: getelementptr inbounds i8* {{.*}}, i32 4 +// CODEGEN: ret + +struct F : virtual A, virtual B { + virtual void own_method(); + virtual ~F(); +}; + +F f; // Just make sure we don't crash, e.g. mangling the complete dtor. + +struct G : C { }; + +struct H : E { + virtual G* goo(); + // MANGLING-DAG: @"\01?goo@H@@UAEPAUG@@XZ" + // MANGLING-DAG: @"\01?goo@H@@QAEPAUB@@XZ" + // MANGLING-DAG: @"\01?goo@H@@QAEPAUC@@XZ" + // MANGLING-X64-DAG: @"\01?goo@H@@UEAAPEAUG@@XZ" + // MANGLING-X64-DAG: @"\01?goo@H@@QEAAPEAUB@@XZ" + // MANGLING-X64-DAG: @"\01?goo@H@@QEAAPEAUC@@XZ" +}; + +H h; + +struct I : D { + I(); + virtual F* goo(); +}; + +I::I() {} // Emits vftable and forces thunk generation. + +// CODEGEN-LABEL: define weak x86_thiscallcc %struct.{{[BF]}}* @"\01?goo@I@@QAEPAUB@@XZ" +// CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"\01?goo@I@@UAEPAUF@@XZ" +// CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8* +// CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[ORIG_RET_i8]], i32 4 +// CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8** +// CODEGEN: %[[VBTABLE:.*]] = load i8** %[[VBPTR]] +// CODEGEN: %[[VBASE_OFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 8 +// CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = bitcast i8* %[[VBASE_OFFSET_PTR_i8]] to i32* +// CODEGEN: %[[VBASE_OFFSET:.*]] = load i32* %[[VBASE_OFFSET_PTR]] +// CODEGEN: %[[RES_i8:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]] +// CODEGEN: %[[RES:.*]] = bitcast i8* %[[RES_i8]] to %struct.F* +// CODEGEN: phi %struct.F* {{.*}} %[[RES]] +// CODEGEN: ret %struct.{{[BF]}}* + +namespace CrashOnThunksForAttributedType { +// We used to crash on this because the type of foo is an AttributedType, not +// FunctionType, and we had to look through the sugar. +struct A { + virtual void __stdcall foo(); +}; +struct B { + virtual void __stdcall foo(); +}; +struct C : A, B { + virtual void __stdcall foo(); +}; +C c; +} diff --git a/test/CodeGenCXX/microsoft-abi-vbtables.cpp b/test/CodeGenCXX/microsoft-abi-vbtables.cpp new file mode 100644 index 0000000..6de556b --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-vbtables.cpp @@ -0,0 +1,479 @@ +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o - | FileCheck %s + +// See microsoft-abi-structors.cpp for constructor codegen tests. + +namespace Test1 { +// Classic diamond, fully virtual. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual A { int c; }; +struct D : virtual B, virtual C { int d; }; +D d; // Force vbtable emission. + +// Layout should be: +// D: vbptr D +// int d +// A: int a +// B: vbptr B +// int b +// C: vbptr C +// int c + +// CHECK-DAG: @"\01??_8D@Test1@@7B01@@" = linkonce_odr unnamed_addr constant [4 x i32] [i32 0, i32 8, i32 12, i32 20] +// CHECK-DAG: @"\01??_8D@Test1@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 -4] +// CHECK-DAG: @"\01??_8D@Test1@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 -12] +// CHECK-DAG: @"\01??_8C@Test1@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +// CHECK-DAG: @"\01??_8B@Test1@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +} + +namespace Test2 { +// Classic diamond, only A is virtual. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual A { int c; }; +struct D : B, C { int d; }; +D d; // Force vbtable emission. + +// Layout should be: +// B: vbptr B +// int b +// C: vbptr C +// int c +// D: int d +// A: int a + +// CHECK-DAG: @"\01??_8D@Test2@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 20] +// CHECK-DAG: @"\01??_8D@Test2@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 12] +// CHECK-DAG: @"\01??_8C@Test2@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +// CHECK-DAG: @"\01??_8B@Test2@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +} + +namespace Test3 { +struct A { int a; }; +struct B { int b; }; +struct C : virtual A, virtual B { int c; }; +C c; + +// CHECK-DAG: @"\01??_8C@Test3@@7B@" = {{.*}} [3 x i32] [i32 0, i32 8, i32 12] +} + +namespace Test4 { +// Test reusing a vbptr from a non-virtual base. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : B, virtual A { int c; }; +C c; // Force vbtable emission. + +// CHECK-DAG: @"\01??_8C@Test4@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12] +// CHECK-DAG: @"\01??_8B@Test4@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +} + +namespace Test5 { +// Test multiple base subobjects of the same type when that type has a virtual +// base. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : B { int c; }; +struct D : B, C { int d; }; +D d; // Force vbtable emission. + +// CHECK-DAG: @"\01??_8D@Test5@@7BB@1@@" +// CHECK-DAG: @"\01??_8D@Test5@@7BC@1@@" +// CHECK-DAG: @"\01??_8C@Test5@@7B@" +// CHECK-DAG: @"\01??_8B@Test5@@7B@" +} + +namespace Test6 { +// Test that we skip unneeded base path component names. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : B { int c; }; +struct D : B, C { int d; }; +struct E : D { int e; }; +struct F : E, B, C { int f; }; +struct G : F, virtual E { int g; }; +G g; + +// CHECK-DAG: @"\01??_8G@Test6@@7BB@1@E@1@F@1@@" = +// CHECK-DAG: @"\01??_8G@Test6@@7BC@1@E@1@F@1@@" = +// CHECK-DAG: @"\01??_8G@Test6@@7BB@1@F@1@@" = +// CHECK-DAG: @"\01??_8G@Test6@@7BC@1@F@1@@" = +// CHECK-DAG: @"\01??_8G@Test6@@7BB@1@E@1@@" = +// CHECK-DAG: @"\01??_8G@Test6@@7BC@1@E@1@@" = +// CHECK-DAG: @"\01??_8F@Test6@@7BB@1@E@1@@" = {{.*}} [2 x i32] [i32 0, i32 52] +// CHECK-DAG: @"\01??_8F@Test6@@7BC@1@E@1@@" = {{.*}} [2 x i32] [i32 0, i32 44] +// CHECK-DAG: @"\01??_8F@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 24] +// CHECK-DAG: @"\01??_8F@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 16] +// CHECK-DAG: @"\01??_8C@Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12] +// CHECK-DAG: @"\01??_8B@Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +// CHECK-DAG: @"\01??_8E@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 28] +// CHECK-DAG: @"\01??_8E@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 20] +// CHECK-DAG: @"\01??_8D@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 24] +// CHECK-DAG: @"\01??_8D@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 16] +} + +namespace Test7 { +// Test a non-virtual base which reuses the vbptr of another base. +struct A { int a; }; +struct B { int b; }; +struct C { int c; }; +struct D : virtual A { int d; }; +struct E : B, D, virtual A, virtual C { int e; }; +E o; + +// CHECK-DAG: @"\01??_8E@Test7@@7B@" = {{.*}} [3 x i32] [i32 0, i32 12, i32 16] +// CHECK-DAG: @"\01??_8D@Test7@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +} + +namespace Test8 { +// Test a virtual base which reuses the vbptr of another base. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : B { int c; }; +struct D : virtual C { int d; }; +D o; + +// CHECK-DAG: @"\01??_8D@Test8@@7B01@@" = {{.*}} [3 x i32] [i32 0, i32 8, i32 12] +// CHECK-DAG: @"\01??_8D@Test8@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 -4] +// CHECK-DAG: @"\01??_8C@Test8@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12] +// CHECK-DAG: @"\01??_8B@Test8@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8] +} + +namespace Test9 { +// D has to add to B's vbtable because D has more morally virtual bases than B. +// D then takes B's vbptr and the vbtable is named for D, not B. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual B { int c; }; +struct BB : B { int bb; }; // Indirection =/ +struct D : BB, C { int d; }; +struct E : virtual D { }; +E e; + +// CHECK-DAG: @"\01??_8E@Test9@@7B01@@" = +// CHECK-DAG: @"\01??_8E@Test9@@7BD@1@@" = +// CHECK-DAG: @"\01??_8E@Test9@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test9@@7BB@1@@" = +// CHECK-DAG: @"\01??_8D@Test9@@7B@" = +// CHECK-DAG: @"\01??_8D@Test9@@7BC@1@@" = +// CHECK-DAG: @"\01??_8D@Test9@@7BB@1@@" = +// CHECK-DAG: @"\01??_8C@Test9@@7B01@@" = +// CHECK-DAG: @"\01??_8C@Test9@@7BB@1@@" = +// CHECK-DAG: @"\01??_8BB@Test9@@7B@" = +// CHECK-DAG: @"\01??_8B@Test9@@7B@" = +} + +namespace Test10 { +struct A { int a; }; +struct B { int b; }; +struct C : virtual A { int c; }; +struct D : B, C { int d; }; +D d; + +// CHECK-DAG: @"\01??_8D@Test10@@7B@" = +// CHECK-DAG: @"\01??_8C@Test10@@7B@" = + +} + +namespace Test11 { +// Typical diamond with an extra single inheritance indirection for B and C. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual A { int c; }; +struct D : B { int d; }; +struct E : C { int e; }; +struct F : D, E { int f; }; +F f; + +// CHECK-DAG: @"\01??_8F@Test11@@7BD@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 28] +// CHECK-DAG: @"\01??_8F@Test11@@7BE@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16] +// CHECK-DAG: @"\01??_8E@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12] +// CHECK-DAG: @"\01??_8C@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +// CHECK-DAG: @"\01??_8D@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12] +// CHECK-DAG: @"\01??_8B@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] + +} + +namespace Test12 { +// Another vbptr inside a virtual base. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual B { int c; }; +struct D : C, B { int d; }; +struct E : D, C, B { int e; }; +E e; + +// CHECK-DAG: @"\01??_8E@Test12@@7BC@1@D@1@@" = +// CHECK-DAG: @"\01??_8E@Test12@@7BB@1@D@1@@" = +// CHECK-DAG: @"\01??_8E@Test12@@7BD@1@@" = +// CHECK-DAG: @"\01??_8E@Test12@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test12@@7BB@1@@" = +// CHECK-DAG: @"\01??_8C@Test12@@7B01@@" = +// CHECK-DAG: @"\01??_8C@Test12@@7BB@1@@" = +// CHECK-DAG: @"\01??_8D@Test12@@7BC@1@@" = +// CHECK-DAG: @"\01??_8D@Test12@@7BB@1@@" = +// CHECK-DAG: @"\01??_8D@Test12@@7B@" = +// CHECK-DAG: @"\01??_8B@Test12@@7B@" = +} + +namespace Test13 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual B { int c; }; +struct D : virtual C { int d; }; +struct E : D, C, B { int e; }; +E e; + +// CHECK-DAG: @"\01??_8E@Test13@@7BD@1@@" = +// CHECK-DAG: @"\01??_8E@Test13@@7BC@1@D@1@@" = +// CHECK-DAG: @"\01??_8E@Test13@@7BB@1@D@1@@" = +// CHECK-DAG: @"\01??_8E@Test13@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test13@@7BB@1@@" = +// CHECK-DAG: @"\01??_8D@Test13@@7B@" = +// CHECK-DAG: @"\01??_8D@Test13@@7BC@1@@" = +// CHECK-DAG: @"\01??_8D@Test13@@7BB@1@@" = +// CHECK-DAG: @"\01??_8C@Test13@@7B01@@" = +// CHECK-DAG: @"\01??_8C@Test13@@7BB@1@@" = +// CHECK-DAG: @"\01??_8B@Test13@@7B@" = +} + +namespace Test14 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual B { int c; }; +struct D : virtual C { int d; }; +struct E : D, virtual C, virtual B { int e; }; +E e; + +// CHECK-DAG: @"\01??_8E@Test14@@7B@" = +// CHECK-DAG: @"\01??_8E@Test14@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test14@@7BB@1@@" = +// CHECK-DAG: @"\01??_8D@Test14@@7B@" = +// CHECK-DAG: @"\01??_8D@Test14@@7BC@1@@" = +// CHECK-DAG: @"\01??_8D@Test14@@7BB@1@@" = +// CHECK-DAG: @"\01??_8C@Test14@@7B01@@" = +// CHECK-DAG: @"\01??_8C@Test14@@7BB@1@@" = +// CHECK-DAG: @"\01??_8B@Test14@@7B@" = +} + +namespace Test15 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual A { int c; }; +struct D : virtual B { int d; }; +struct E : D, C, B { int e; }; +E e; + +// CHECK-DAG: @"\01??_8E@Test15@@7BD@1@@" = +// CHECK-DAG: @"\01??_8E@Test15@@7BB@1@D@1@@" = +// CHECK-DAG: @"\01??_8E@Test15@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test15@@7BB@1@@" = +// CHECK-DAG: @"\01??_8C@Test15@@7B@" = +// CHECK-DAG: @"\01??_8D@Test15@@7B01@@" = +// CHECK-DAG: @"\01??_8D@Test15@@7BB@1@@" = +// CHECK-DAG: @"\01??_8B@Test15@@7B@" = +} + +namespace Test16 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual B { int c; }; // ambig +struct D : virtual C { int d; }; +struct E : virtual D { int e; }; // ambig +struct F : E, D, C, B { int f; }; // ambig +F f; + +// CHECK-DAG: @"\01??_8F@Test16@@7BE@1@@" = +// CHECK-DAG: @"\01??_8F@Test16@@7BD@1@E@1@@" = +// CHECK-DAG: @"\01??_8F@Test16@@7BC@1@E@1@@" = +// CHECK-DAG: @"\01??_8F@Test16@@7BB@1@E@1@@" = +// CHECK-DAG: @"\01??_8F@Test16@@7BD@1@@" = +// CHECK-DAG: @"\01??_8F@Test16@@7BC@1@@" = +// CHECK-DAG: @"\01??_8F@Test16@@7BB@1@@" = +// CHECK-DAG: @"\01??_8E@Test16@@7B01@@" = +// CHECK-DAG: @"\01??_8E@Test16@@7BD@1@@" = +// CHECK-DAG: @"\01??_8E@Test16@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test16@@7BB@1@@" = +// CHECK-DAG: @"\01??_8D@Test16@@7B@" = +// CHECK-DAG: @"\01??_8D@Test16@@7BC@1@@" = +// CHECK-DAG: @"\01??_8D@Test16@@7BB@1@@" = +// CHECK-DAG: @"\01??_8C@Test16@@7B01@@" = +// CHECK-DAG: @"\01??_8C@Test16@@7BB@1@@" = +// CHECK-DAG: @"\01??_8B@Test16@@7B@" = +} + +namespace Test17 { +// This test case has an interesting alternating pattern of using "vbtable of B" +// and "vbtable of C for C". This may be the key to the underlying algorithm. +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual B { int c; }; // ambig +struct D : virtual C { int d; }; +struct E : virtual D { int e; }; // ambig +struct F : virtual E { int f; }; +struct G : virtual F { int g; }; // ambig +struct H : virtual G { int h; }; +struct I : virtual H { int i; }; // ambig +struct J : virtual I { int j; }; +struct K : virtual J { int k; }; // ambig +K k; + +// CHECK-DAG: @"\01??_8K@Test17@@7B01@@" = +// CHECK-DAG: @"\01??_8J@Test17@@7B@" = +// CHECK-DAG: @"\01??_8I@Test17@@7B01@@" = +// CHECK-DAG: @"\01??_8H@Test17@@7B@" = +// CHECK-DAG: @"\01??_8G@Test17@@7B01@@" = +// CHECK-DAG: @"\01??_8F@Test17@@7B@" = +// CHECK-DAG: @"\01??_8E@Test17@@7B01@@" = +// CHECK-DAG: @"\01??_8D@Test17@@7B@" = +// CHECK-DAG: @"\01??_8C@Test17@@7B01@@" = +// CHECK-DAG: @"\01??_8B@Test17@@7B@" = +} + +namespace Test18 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : B { int c; }; +struct D : C, B { int d; }; +struct E : D, C, B { int e; }; +E e; + +// CHECK-DAG: @"\01??_8E@Test18@@7BC@1@D@1@@" = +// CHECK-DAG: @"\01??_8E@Test18@@7BB@1@D@1@@" = +// CHECK-DAG: @"\01??_8E@Test18@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test18@@7BB@1@@" = +// CHECK-DAG: @"\01??_8B@Test18@@7B@" = +// CHECK-DAG: @"\01??_8C@Test18@@7B@" = +// CHECK-DAG: @"\01??_8D@Test18@@7BC@1@@" = +// CHECK-DAG: @"\01??_8D@Test18@@7BB@1@@" = +} + +namespace Test19 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : virtual B { int c; }; +struct D : virtual C, virtual B { int d; }; +struct E : virtual D, virtual C, virtual B { int e; }; +E e; + +// CHECK-DAG: @"\01??_8E@Test19@@7B01@@" = +// CHECK-DAG: @"\01??_8E@Test19@@7BD@1@@" = +// CHECK-DAG: @"\01??_8E@Test19@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test19@@7BB@1@@" = +// CHECK-DAG: @"\01??_8D@Test19@@7B@" = +// CHECK-DAG: @"\01??_8D@Test19@@7BC@1@@" = +// CHECK-DAG: @"\01??_8D@Test19@@7BB@1@@" = +// CHECK-DAG: @"\01??_8C@Test19@@7B01@@" = +// CHECK-DAG: @"\01??_8C@Test19@@7BB@1@@" = +// CHECK-DAG: @"\01??_8B@Test19@@7B@" = +} + +namespace Test20 { +// E has no direct vbases, but it adds to C's vbtable anyway. +struct A { int a; }; +struct B { int b; }; +struct C : virtual A { int c; }; +struct D : virtual B { int d; }; +struct E : C, D { int e; }; +E f; + +// CHECK-DAG: @"\01??_8E@Test20@@7BC@1@@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 20, i32 24] +// CHECK-DAG: @"\01??_8E@Test20@@7BD@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16] +// CHECK-DAG: @"\01??_8D@Test20@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +// CHECK-DAG: @"\01??_8C@Test20@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +} + +namespace Test21 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C : B { int c; }; +struct D : B { int d; }; +struct E : C, D { int e; }; +struct F : virtual E { int f; }; +struct G : E { int g; }; +struct H : F, G { int h; }; +H h; + +// CHECK-DAG: @"\01??_8H@Test21@@7B@" = +// CHECK-DAG: @"\01??_8H@Test21@@7BC@1@F@1@@" = +// CHECK-DAG: @"\01??_8H@Test21@@7BD@1@F@1@@" = +// CHECK-DAG: @"\01??_8H@Test21@@7BC@1@G@1@@" = +// CHECK-DAG: @"\01??_8H@Test21@@7BD@1@G@1@@" = +// CHECK-DAG: @"\01??_8G@Test21@@7BC@1@@" = +// CHECK-DAG: @"\01??_8G@Test21@@7BD@1@@" = +// CHECK-DAG: @"\01??_8F@Test21@@7B@" = +// CHECK-DAG: @"\01??_8F@Test21@@7BC@1@@" = +// CHECK-DAG: @"\01??_8F@Test21@@7BD@1@@" = +// CHECK-DAG: @"\01??_8E@Test21@@7BC@1@@" = +// CHECK-DAG: @"\01??_8E@Test21@@7BD@1@@" = +// CHECK-DAG: @"\01??_8D@Test21@@7B@" = +// CHECK-DAG: @"\01??_8B@Test21@@7B@" = +// CHECK-DAG: @"\01??_8C@Test21@@7B@" = +} + +namespace Test22 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C { int c; }; +struct D : B, virtual C { int d; }; +D d; + +// CHECK-DAG: @"\01??_8D@Test22@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 12, i32 16] +// CHECK-DAG: @"\01??_8B@Test22@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +} + +namespace Test23 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C { int c; }; +// Note the unusual order of bases. It forces C to be laid out before A. +struct D : virtual C, B { int d; }; +D d; + +// CHECK-DAG: @"\01??_8D@Test23@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 16, i32 12] +// CHECK-DAG: @"\01??_8B@Test23@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +} + +namespace Test24 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C { int c; }; +struct D : virtual C, B { + virtual void f(); // Issues a vfptr, but the vbptr is still shared with B. + int d; +}; +D d; + +// CHECK-DAG: @"\01??_8D@Test24@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 16, i32 12] +// CHECK-DAG: @"\01??_8B@Test24@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +} + +namespace Test25 { +struct A { int a; }; +struct B : virtual A { + virtual void f(); // Issues a vfptr. + int b; +}; +struct C { int c; }; +struct D : virtual C, B { int d; }; +D d; + +// CHECK-DAG: @"\01??_8D@Test25@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 -4, i32 16, i32 12] +// CHECK-DAG: @"\01??_8B@Test25@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 -4, i32 8] +} + +namespace Test26 { +struct A { int a; }; +struct B { int b; }; +struct C { int c; }; +struct D : virtual A { int d; }; +struct E : virtual B { + virtual void foo(); // Issues a vfptr. + int e; +}; +struct F: virtual C, D, E { int f; }; +F f; +// F reuses the D's vbptr, even though D is laid out after E. +// CHECK-DAG: @"\01??_8F@Test26@@7BD@1@@" = linkonce_odr unnamed_addr constant [4 x i32] [i32 0, i32 16, i32 12, i32 20] +// CHECK-DAG: @"\01??_8F@Test26@@7BE@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 -4, i32 28] +} diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp new file mode 100644 index 0000000..8e23ade --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance-vtordisps.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o - | FileCheck %s + +// For now, just make sure x86_64 doesn't crash. +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=x86_64-pc-win32 -emit-llvm -o %t + +struct A { + virtual void f(); +}; + +struct B { + virtual void f(); +}; + +struct C : A, B {}; + +struct D : virtual C { + D(); + ~D(); + virtual void f(); + void g(); + int xxx; +}; + +D::D() {} // Forces vftable emission. + +// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@D@@$4PPPPPPPM@A@AEXXZ" +// CHECK: %[[ECX:.*]] = load %struct.D** %{{.*}} +// CHECK: %[[ECX_i8:.*]] = bitcast %struct.D* %[[ECX]] to i8* +// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -4 +// CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_PTR_i8]] to i32* +// CHECK: %[[VTORDISP:.*]] = load i32* %[[VTORDISP_PTR]] +// CHECK: %[[VTORDISP_NEG:.*]] = sub i32 0, %[[VTORDISP]] +// CHECK: %[[ADJUSTED_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 %[[VTORDISP_NEG]] +// CHECK: call x86_thiscallcc void @"\01?f@D@@UAEXXZ"(i8* %[[ADJUSTED_i8]]) +// CHECK: ret void + +// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@D@@$4PPPPPPPI@3AEXXZ" +// CHECK: %[[ECX:.*]] = load %struct.D** %{{.*}} +// CHECK: %[[ECX_i8:.*]] = bitcast %struct.D* %[[ECX]] to i8* +// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -8 +// CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_PTR_i8]] to i32* +// CHECK: %[[VTORDISP:.*]] = load i32* %[[VTORDISP_PTR]] +// CHECK: %[[VTORDISP_NEG:.*]] = sub i32 0, %[[VTORDISP]] +// CHECK: %[[VTORDISP_ADJUSTED_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 %[[VTORDISP_NEG]] +// CHECK: %[[ADJUSTED_i8:.*]] = getelementptr i8* %[[VTORDISP_ADJUSTED_i8]], i32 -4 +// CHECK: call x86_thiscallcc void @"\01?f@D@@UAEXXZ"(i8* %[[ADJUSTED_i8]]) +// CHECK: ret void + +struct E : virtual A { + virtual void f(); + ~E(); +}; + +struct F { + virtual void z(); +}; + +struct G : virtual F, virtual E { + int ggg; + G(); + ~G(); +}; + +G::G() {} // Forces vftable emission. + +// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@E@@$R4BA@M@PPPPPPPM@7AEXXZ"(i8*) +// CHECK: %[[ECX:.*]] = load %struct.E** %{{.*}} +// CHECK: %[[ECX_i8:.*]] = bitcast %struct.E* %[[ECX]] to i8* +// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -4 +// CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_PTR_i8]] to i32* +// CHECK: %[[VTORDISP:.*]] = load i32* %[[VTORDISP_PTR]] +// CHECK: %[[VTORDISP_NEG:.*]] = sub i32 0, %[[VTORDISP]] +// CHECK: %[[VTORDISP_ADJUSTED_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 %[[VTORDISP_NEG]] +// CHECK: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[VTORDISP_ADJUSTED_i8]], i32 -16 +// CHECK: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR]] +// CHECK: %[[VBOFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 12 +// CHECK: %[[VBOFFSET_PTR:.*]] = bitcast i8* %[[VBOFFSET_PTR_i8]] to i32* +// CHECK: %[[VBASE_OFFSET:.*]] = load i32* %[[VBOFFSET_PTR]] +// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]] +// CHECK: %[[ARG_i8:.*]] = getelementptr i8* %[[VBASE]], i32 8 +// CHECK: call x86_thiscallcc void @"\01?f@E@@UAEXXZ"(i8* %[[ARG_i8]]) +// CHECK: ret void diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp new file mode 100644 index 0000000..7c223ca --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp @@ -0,0 +1,314 @@ +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t +// RUN: FileCheck %s < %t +// RUN: FileCheck --check-prefix=CHECK2 %s < %t + +// For now, just make sure x86_64 doesn't crash. +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=x86_64-pc-win32 -emit-llvm -o %t + +struct VBase { + virtual ~VBase(); + virtual void foo(); + virtual void bar(); + int field; +}; + +struct B : virtual VBase { + B(); + virtual ~B(); + virtual void foo(); + virtual void bar(); +}; + +B::B() { + // CHECK-LABEL: define x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ" + // CHECK: %[[THIS:.*]] = load %struct.B** + // CHECK: br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] + + // Don't check the INIT_VBASES case as it's covered by the ctor tests. + + // CHECK: %[[SKIP_VBASES]] + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0 + // ... + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}} + // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]** + // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]] + + // Initialize vtorDisp: + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0 + // ... + // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}} + // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8 + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %[[VBASE_OFFSET]] + // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8* %[[VBASE_i8]], i32 -4 + // CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_i8]] to i32* + // CHECK: store i32 %[[VTORDISP_VAL]], i32* %[[VTORDISP_PTR]] + + // CHECK: ret +} + +B::~B() { + // CHECK-LABEL: define x86_thiscallcc void @"\01??1B@@UAE@XZ" + // Adjust the this parameter: + // CHECK: %[[THIS_PARAM_i8:.*]] = bitcast %struct.B* {{.*}} to i8* + // CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[THIS_PARAM_i8]], i32 -8 + // CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B* + // CHECK: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4 + // CHECK: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]] + + // Restore the vfptr that could have been changed by a subclass. + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0 + // ... + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}} + // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]** + // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]] + + // Initialize vtorDisp: + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0 + // ... + // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}} + // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8 + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %[[VBASE_OFFSET]] + // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8* %[[VBASE_i8]], i32 -4 + // CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_i8]] to i32* + // CHECK: store i32 %[[VTORDISP_VAL]], i32* %[[VTORDISP_PTR]] + + foo(); // Avoid the "trivial destructor" optimization. + + // CHECK: ret + + // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* + // CHECK2: %[[THIS:.*]] = load %struct.B** {{.*}} + // CHECK2: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK2: %[[B_i8:.*]] = getelementptr i8* %[[THIS_i8]], i32 8 + // CHECK2: %[[B:.*]] = bitcast i8* %[[B_i8]] to %struct.B* + // CHECK2: call x86_thiscallcc void @"\01??1B@@UAE@XZ"(%struct.B* %[[B]]) + // CHECK2: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK2: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i64 8 + // CHECK2: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.VBase* + // CHECK2: call x86_thiscallcc void @"\01??1VBase@@UAE@XZ"(%struct.VBase* %[[VBASE]]) + // CHECK2: ret + + // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_GB@@UAEPAXI@Z" + // CHECK2: %[[THIS_PARAM_i8:.*]] = bitcast %struct.B* {{.*}} to i8* + // CHECK2: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[THIS_PARAM_i8:.*]], i32 -8 + // CHECK2: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B* + // CHECK2: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4 + // CHECK2: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]] + // CHECK2: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[THIS]]) + // ... + // CHECK2: ret +} + +void B::foo() { +// CHECK-LABEL: define x86_thiscallcc void @"\01?foo@B@@UAEXXZ"(i8* +// +// B::foo gets 'this' cast to VBase* in ECX (i.e. this+8) so we +// need to adjust 'this' before use. +// +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.B*, align 4 +// CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ECX:.*]], i32 -8 +// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B* +// CHECK: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR]], align 4 + + field = 42; +// CHECK: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]] +// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8* +// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 %[[VBOFFSET]] +// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.VBase* +// CHECK: %[[FIELD:.*]] = getelementptr inbounds %struct.VBase* %[[VBASE]], i32 0, i32 1 +// CHECK: store i32 42, i32* %[[FIELD]], align 4 +// +// CHECK: ret void +} + +void call_vbase_bar(B *obj) { +// CHECK-LABEL: define void @"\01?call_vbase_bar@@YAXPAUB@@@Z"(%struct.B* %obj) +// CHECK: %[[OBJ:.*]] = load %struct.B + + obj->bar(); +// When calling a vbase's virtual method, one needs to adjust 'this' +// at the caller site. +// +// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (i8*)*** +// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 2 +// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]] +// +// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[VBASE]]) +// +// CHECK: ret void +} + +void delete_B(B *obj) { +// CHECK-LABEL: define void @"\01?delete_B@@YAXPAUB@@@Z"(%struct.B* %obj) +// CHECK: %[[OBJ:.*]] = load %struct.B + + delete obj; +// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (%struct.B*, i32)*** +// CHECK: %[[VFTABLE:.*]] = load void (%struct.B*, i32)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.B*, i32)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.B*, i32)** %[[VFUN]] +// +// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.B* +// +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.B* %[[VBASE]], i32 1) +// CHECK: ret void +} + +void call_complete_dtor() { + // CHECK-LABEL: define void @"\01?call_complete_dtor@@YAXXZ" + B b; + // CHECK: call x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"(%struct.B* %[[B:.*]], i32 1) + // CHECK-NOT: getelementptr + // CHECK: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[B]]) + // CHECK: ret +} + +struct C : B { + C(); + // has an implicit vdtor. +}; + +// Used to crash on an assertion. +C::C() { +// CHECK-LABEL: define x86_thiscallcc %struct.C* @"\01??0C@@QAE@XZ" +} + +namespace multiple_vbases { +struct A { + virtual void a(); +}; + +struct B { + virtual void b(); +}; + +struct C { + virtual void c(); +}; + +struct D : virtual A, virtual B, virtual C { + virtual void a(); + virtual void b(); + virtual void c(); + D(); +}; + +D::D() { + // CHECK-LABEL: define x86_thiscallcc %"struct.multiple_vbases::D"* @"\01??0D@multiple_vbases@@QAE@XZ" + // Just make sure we emit 3 vtordisps after initializing vfptrs. + // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BA@1@@", [1 x i8*]** %{{.*}} + // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BB@1@@", [1 x i8*]** %{{.*}} + // CHECK: store [1 x i8*]* @"\01??_7D@multiple_vbases@@6BC@1@@", [1 x i8*]** %{{.*}} + // ... + // CHECK: store i32 %{{.*}}, i32* %{{.*}} + // CHECK: store i32 %{{.*}}, i32* %{{.*}} + // CHECK: store i32 %{{.*}}, i32* %{{.*}} + // CHECK: ret +} +} + +namespace diamond { +struct A { + A(); + virtual ~A(); +}; + +struct B : virtual A { + B(); + ~B(); +}; + +struct C : virtual A { + C(); + ~C(); + int c1, c2, c3; +}; + +struct Z { + int z; +}; + +struct D : virtual Z, B, C { + D(); + ~D(); +} d; + +D::~D() { + // CHECK-LABEL: define x86_thiscallcc void @"\01??1D@diamond@@UAE@XZ"(%"struct.diamond::D"*) + // CHECK: %[[ARG_i8:.*]] = bitcast %"struct.diamond::D"* %{{.*}} to i8* + // CHECK: %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[ARG_i8]], i32 -24 + // CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %"struct.diamond::D"* + // CHECK: store %"struct.diamond::D"* %[[THIS]], %"struct.diamond::D"** %[[THIS_VAL:.*]], align 4 + // CHECK: %[[THIS:.*]] = load %"struct.diamond::D"** %[[THIS_VAL]] + // CHECK: %[[D_i8:.*]] = bitcast %"struct.diamond::D"* %[[THIS]] to i8* + // CHECK: %[[C_i8:.*]] = getelementptr inbounds i8* %[[D_i8]], i64 4 + // CHECK: %[[C:.*]] = bitcast i8* %[[C_i8]] to %"struct.diamond::C"* + // CHECK: %[[C_i8:.*]] = bitcast %"struct.diamond::C"* %[[C]] to i8* + // CHECK: %[[ARG_i8:.*]] = getelementptr i8* %{{.*}}, i32 16 + // FIXME: We might consider changing the dtor this parameter type to i8*. + // CHECK: %[[ARG:.*]] = bitcast i8* %[[ARG_i8]] to %"struct.diamond::C"* + // CHECK: call x86_thiscallcc void @"\01??1C@diamond@@UAE@XZ"(%"struct.diamond::C"* %[[ARG]]) + + // CHECK: %[[B:.*]] = bitcast %"struct.diamond::D"* %[[THIS]] to %"struct.diamond::B"* + // CHECK: %[[B_i8:.*]] = bitcast %"struct.diamond::B"* %[[B]] to i8* + // CHECK: %[[ARG_i8:.*]] = getelementptr i8* %[[B_i8]], i32 4 + // CHECK: %[[ARG:.*]] = bitcast i8* %[[ARG_i8]] to %"struct.diamond::B"* + // CHECK: call x86_thiscallcc void @"\01??1B@diamond@@UAE@XZ"(%"struct.diamond::B"* %[[ARG]]) + // CHECK: ret void +} + +} diff --git a/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp new file mode 100644 index 0000000..51a04c8 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK32 +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK64 + +struct S { + int x, y, z; +}; + +struct C { + virtual void foo(); + virtual int bar(int, double); + virtual S baz(int); +}; + +namespace { +struct D { + virtual void foo(); +}; +} + +void f() { + void (C::*ptr)(); + ptr = &C::foo; + ptr = &C::foo; // Don't crash trying to define the thunk twice :) + + int (C::*ptr2)(int, double); + ptr2 = &C::bar; + + S (C::*ptr3)(int); + ptr3 = &C::baz; + + void (D::*ptr4)(); + ptr4 = &D::foo; + +// CHECK32-LABEL: define void @"\01?f@@YAXXZ"() +// CHECK32: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr +// CHECK32: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2 +// CHECK32: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3 +// CHECK32: store i8* bitcast (void (%"struct.<anonymous namespace>::D"*)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4 +// CHECK32: } +// +// CHECK64-LABEL: define void @"\01?f@@YAXXZ"() +// CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr +// CHECK64: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2 +// CHECK64: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3 +// CHECK64: store i8* bitcast (void (%"struct.<anonymous namespace>::D"*)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr +// CHECK64: } +} + + +// Thunk for calling the 1st virtual function in C with no parameters. +// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this) unnamed_addr +// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0 +// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]] +// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}}) +// CHECK32: ret void +// CHECK32: } +// +// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this) unnamed_addr +// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0 +// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]] +// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}) +// CHECK64: ret void +// CHECK64: } + +// Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int. +// CHECK32-LABEL: define linkonce_odr x86_thiscallcc i32 @"\01??_9C@@$B3AE"(%struct.C* %this, i32, double) unnamed_addr +// CHECK32: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1 +// CHECK32: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]] +// CHECK32: [[CALL:%.*]] = call x86_thiscallcc i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}}) +// CHECK32: ret i32 [[CALL]] +// CHECK32: } +// +// CHECK64-LABEL: define linkonce_odr i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double) unnamed_addr +// CHECK64: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1 +// CHECK64: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]] +// CHECK64: [[CALL:%.*]] = call i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}}) +// CHECK64: ret i32 [[CALL]] +// CHECK64: } + +// Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct. +// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr +// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2 +// CHECK32: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]] +// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}}) +// CHECK32: ret void +// CHECK32: } +// +// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr +// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2 +// CHECK64: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]] +// CHECK64: call void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}}) +// CHECK64: ret void +// CHECK64: } + +// Thunk for calling the virtual function in internal class D. +// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"struct.<anonymous namespace>::D"* %this) unnamed_addr +// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.<anonymous namespace>::D"*)** %{{.*}}, i64 0 +// CHECK32: [[CALLEE:%.*]] = load void (%"struct.<anonymous namespace>::D"*)** [[VPTR]] +// CHECK32: call x86_thiscallcc void [[CALLEE]](%"struct.<anonymous namespace>::D"* %{{.*}}) +// CHECK32: ret void +// CHECK32: } +// +// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"struct.<anonymous namespace>::D"* %this) unnamed_addr +// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.<anonymous namespace>::D"*)** %{{.*}}, i64 0 +// CHECK64: [[CALLEE:%.*]] = load void (%"struct.<anonymous namespace>::D"*)** [[VPTR]] +// CHECK64: call void [[CALLEE]](%"struct.<anonymous namespace>::D"* %{{.*}}) +// CHECK64: ret void +// CHECK64: } diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp new file mode 100644 index 0000000..d93dee1 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp @@ -0,0 +1,579 @@ +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t + +// RUN: FileCheck --check-prefix=NO-THUNKS-Test1 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test2 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test3 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test4 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test5 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test6 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test7 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test8 %s < %t +// RUN: FileCheck --check-prefix=NO-THUNKS-Test9 %s < %t +// RUN: FileCheck --check-prefix=PURE-VIRTUAL-Test1 %s < %t +// RUN: FileCheck --check-prefix=THIS-THUNKS-Test1 %s < %t +// RUN: FileCheck --check-prefix=THIS-THUNKS-Test2 %s < %t +// RUN: FileCheck --check-prefix=THIS-THUNKS-Test3 %s < %t +// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test3 %s < %t +// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test5 %s < %t +// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test6 %s < %t +// RUN: FileCheck --check-prefix=VDTOR-THUNKS-Test7 %s < %t +// RUN: FileCheck --check-prefix=RET-THUNKS-Test1 %s < %t +// RUN: FileCheck --check-prefix=RET-THUNKS-Test2 %s < %t +// RUN: FileCheck --check-prefix=RET-THUNKS-Test3 %s < %t +// RUN: FileCheck --check-prefix=RET-THUNKS-Test4 %s < %t +// RUN: FileCheck --check-prefix=RET-THUNKS-Test5 %s < %t +// RUN: FileCheck --check-prefix=RET-THUNKS-Test6 %s < %t + +// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll + +struct Empty { + // Doesn't have a vftable! +}; + +struct A { + virtual void f(); +}; + +struct B { + virtual void g(); + // Add an extra virtual method so it's easier to check for the absence of thunks. + virtual void h(); +}; + +struct C { + virtual void g(); // Might "collide" with B::g if both are bases of some class. +}; + + +namespace no_thunks { + +struct Test1: A, B { + // NO-THUNKS-Test1: VFTable for 'A' in 'no_thunks::Test1' (1 entries) + // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f() + + // NO-THUNKS-Test1: VFTable for 'B' in 'no_thunks::Test1' (2 entries) + // NO-THUNKS-Test1-NEXT: 0 | void B::g() + // NO-THUNKS-Test1-NEXT: 1 | void B::h() + + // NO-THUNKS-Test1: VFTable indices for 'no_thunks::Test1' (1 entries) + // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f() + + // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BB@@@" + + // Overrides only the left child's method (A::f), needs no thunks. + virtual void f(); +}; + +Test1 t1; + +struct Test2: A, B { + // NO-THUNKS-Test2: VFTable for 'A' in 'no_thunks::Test2' (1 entries) + // NO-THUNKS-Test2-NEXT: 0 | void A::f() + + // NO-THUNKS-Test2: VFTable for 'B' in 'no_thunks::Test2' (2 entries) + // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g() + // NO-THUNKS-Test2-NEXT: 1 | void B::h() + + // NO-THUNKS-Test2: VFTable indices for 'no_thunks::Test2' (1 entries). + // NO-THUNKS-Test2-NEXT: via vfptr at offset 4 + // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g() + + // Overrides only the right child's method (B::g), needs this adjustment but + // not thunks. + virtual void g(); +}; + +Test2 t2; + +struct Test3: A, B { + // NO-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test3' (2 entries) + // NO-THUNKS-Test3-NEXT: 0 | void A::f() + // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i() + + // NO-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test3' (2 entries) + // NO-THUNKS-Test3-NEXT: 0 | void B::g() + // NO-THUNKS-Test3-NEXT: 1 | void B::h() + + // NO-THUNKS-Test3: VFTable indices for 'no_thunks::Test3' (1 entries). + // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i() + + // Only adds a new method. + virtual void i(); +}; + +Test3 t3; + +// Only the right base has a vftable, so it's laid out before the left one! +struct Test4 : Empty, A { + // NO-THUNKS-Test4: VFTable for 'A' in 'no_thunks::Test4' (1 entries) + // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f() + + // NO-THUNKS-Test4: VFTable indices for 'no_thunks::Test4' (1 entries). + // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f() + + // MANGLING-DAG: @"\01??_7Test4@no_thunks@@6B@" + + virtual void f(); +}; + +Test4 t4; + +// 2-level structure with repeating subobject types, but no thunks needed. +struct Test5: Test1, Test2 { + // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries) + // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test1::f() + // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z() + + // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries) + // NO-THUNKS-Test5-NEXT: 0 | void B::g() + // NO-THUNKS-Test5-NEXT: 1 | void B::h() + + // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test5' (1 entries) + // NO-THUNKS-Test5-NEXT: 0 | void A::f() + + // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test5' (2 entries) + // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test2::g() + // NO-THUNKS-Test5-NEXT: 1 | void B::h() + + // NO-THUNKS-Test5: VFTable indices for 'no_thunks::Test5' (1 entries). + // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z() + + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test1@1@@" + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test2@1@@" + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test1@1@@" + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test2@1@@" + + virtual void z(); +}; + +Test5 t5; + +struct Test6: Test1 { + // NO-THUNKS-Test6: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test6' (1 entries). + // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f() + + // NO-THUNKS-Test6: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test6' (2 entries). + // NO-THUNKS-Test6-NEXT: 0 | void B::g() + // NO-THUNKS-Test6-NEXT: 1 | void B::h() + + // NO-THUNKS-Test6: VFTable indices for 'no_thunks::Test6' (1 entries). + // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f() + + // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BB@@@" + + // Overrides both no_thunks::Test1::f and A::f. + virtual void f(); +}; + +Test6 t6; + +struct Test7: Test2 { + // NO-THUNKS-Test7: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test7' (1 entries). + // NO-THUNKS-Test7-NEXT: 0 | void A::f() + + // NO-THUNKS-Test7: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test7' (2 entries). + // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g() + // NO-THUNKS-Test7-NEXT: 1 | void B::h() + + // NO-THUNKS-Test7: VFTable indices for 'no_thunks::Test7' (1 entries). + // NO-THUNKS-Test7-NEXT: via vfptr at offset 4 + // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g() + + // Overrides both no_thunks::Test2::g and B::g. + virtual void g(); +}; + +Test7 t7; + +struct Test8: Test3 { + // NO-THUNKS-Test8: VFTable for 'A' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries). + // NO-THUNKS-Test8-NEXT: 0 | void A::f() + // NO-THUNKS-Test8-NEXT: 1 | void no_thunks::Test3::i() + + // NO-THUNKS-Test8: VFTable for 'B' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries). + // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g() + // NO-THUNKS-Test8-NEXT: 1 | void B::h() + + // NO-THUNKS-Test8: VFTable indices for 'no_thunks::Test8' (1 entries). + // NO-THUNKS-Test8-NEXT: via vfptr at offset 4 + // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g() + + // Overrides grandparent's B::g. + virtual void g(); +}; + +Test8 t8; + +struct D : A { + virtual void g(); +}; + +// Repeating subobject. +struct Test9: A, D { + // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::Test9' (2 entries). + // NO-THUNKS-Test9-NEXT: 0 | void A::f() + // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h() + + // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::D' in 'no_thunks::Test9' (2 entries). + // NO-THUNKS-Test9-NEXT: 0 | void A::f() + // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::D::g() + + // NO-THUNKS-Test9: VFTable indices for 'no_thunks::Test9' (1 entries). + // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h() + + // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BD@1@@" + + virtual void h(); +}; + +Test9 t9; +} + +namespace pure_virtual { +struct D { + virtual void g() = 0; + virtual void h(); +}; + + +struct Test1: A, D { + // PURE-VIRTUAL-Test1: VFTable for 'A' in 'pure_virtual::Test1' (1 entries) + // PURE-VIRTUAL-Test1-NEXT: 0 | void A::f() + + // PURE-VIRTUAL-Test1: VFTable for 'pure_virtual::D' in 'pure_virtual::Test1' (2 entries) + // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g() + // PURE-VIRTUAL-Test1-NEXT: 1 | void pure_virtual::D::h() + + // PURE-VIRTUAL-Test1: VFTable indices for 'pure_virtual::Test1' (1 entries). + // PURE-VIRTUAL-Test1-NEXT: via vfptr at offset 4 + // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g() + + // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BD@1@@" + + // Overrides only the right child's method (pure_virtual::D::g), needs this adjustment but + // not thunks. + virtual void g(); +}; + +Test1 t1; +} + +namespace this_adjustment { + +// Overrides methods of two bases at the same time, thus needing thunks. +struct Test1 : B, C { + // THIS-THUNKS-Test1: VFTable for 'B' in 'this_adjustment::Test1' (2 entries). + // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g() + // THIS-THUNKS-Test1-NEXT: 1 | void B::h() + + // THIS-THUNKS-Test1: VFTable for 'C' in 'this_adjustment::Test1' (1 entries). + // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g() + // THIS-THUNKS-Test1-NEXT: [this adjustment: -4 non-virtual] + + // THIS-THUNKS-Test1: Thunks for 'void this_adjustment::Test1::g()' (1 entry). + // THIS-THUNKS-Test1-NEXT: 0 | [this adjustment: -4 non-virtual] + + // THIS-THUNKS-Test1: VFTable indices for 'this_adjustment::Test1' (1 entries). + // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g() + + // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BB@@@" + // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BC@@@" + + virtual void g(); +}; + +Test1 t1; + +struct Test2 : A, B, C { + // THIS-THUNKS-Test2: VFTable for 'A' in 'this_adjustment::Test2' (1 entries). + // THIS-THUNKS-Test2-NEXT: 0 | void A::f() + + // THIS-THUNKS-Test2: VFTable for 'B' in 'this_adjustment::Test2' (2 entries). + // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g() + // THIS-THUNKS-Test2-NEXT: 1 | void B::h() + + // THIS-THUNKS-Test2: VFTable for 'C' in 'this_adjustment::Test2' (1 entries). + // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g() + // THIS-THUNKS-Test2-NEXT: [this adjustment: -4 non-virtual] + + // THIS-THUNKS-Test2: Thunks for 'void this_adjustment::Test2::g()' (1 entry). + // THIS-THUNKS-Test2-NEXT: 0 | [this adjustment: -4 non-virtual] + + // THIS-THUNKS-Test2: VFTable indices for 'this_adjustment::Test2' (1 entries). + // THIS-THUNKS-Test2-NEXT: via vfptr at offset 4 + // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g() + + // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BB@@@" + // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BC@@@" + + virtual void g(); +}; + +Test2 t2; + +// Overrides methods of two bases at the same time, thus needing thunks. +struct Test3: no_thunks::Test1, no_thunks::Test2 { + // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test1' in 'this_adjustment::Test3' (1 entries). + // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f() + + // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test1' in 'this_adjustment::Test3' (2 entries). + // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g() + // THIS-THUNKS-Test3-NEXT: 1 | void B::h() + + // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test2' in 'this_adjustment::Test3' (1 entries). + // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f() + // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual] + + // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::f()' (1 entry). + // THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual] + + // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test2' in 'this_adjustment::Test3' (2 entries). + // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g() + // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual] + // THIS-THUNKS-Test3-NEXT: 1 | void B::h() + + // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::g()' (1 entry). + // THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual] + + // THIS-THUNKS-Test3: VFTable indices for 'this_adjustment::Test3' (2 entries). + // THIS-THUNKS-Test3-NEXT: via vfptr at offset 0 + // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f() + // THIS-THUNKS-Test3-NEXT: via vfptr at offset 4 + // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g() + + virtual void f(); + virtual void g(); +}; + +Test3 t3; +} + +namespace vdtor { +struct Test1 { + virtual ~Test1(); + virtual void z1(); +}; + +struct Test2 { + virtual ~Test2(); +}; + +struct Test3 : Test1, Test2 { + // VDTOR-THUNKS-Test3: VFTable for 'vdtor::Test1' in 'vdtor::Test3' (2 entries). + // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting] + // VDTOR-THUNKS-Test3-NEXT: 1 | void vdtor::Test1::z1() + + // VDTOR-THUNKS-Test3: VFTable for 'vdtor::Test2' in 'vdtor::Test3' (1 entries). + // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting] + // VDTOR-THUNKS-Test3-NEXT: [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test3: Thunks for 'vdtor::Test3::~Test3()' (1 entry). + // VDTOR-THUNKS-Test3-NEXT: 0 | [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test3: VFTable indices for 'vdtor::Test3' (1 entries). + // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting] + virtual ~Test3(); +}; + +Test3 t3; + +struct Test4 { + // No virtual destructor here! + virtual void z4(); +}; + +struct Test5 : Test4, Test2 { + // Implicit virtual dtor here! + + // VDTOR-THUNKS-Test5: VFTable for 'vdtor::Test4' in 'vdtor::Test5' (1 entries). + // VDTOR-THUNKS-Test5-NEXT: 0 | void vdtor::Test4::z4() + + // VDTOR-THUNKS-Test5: VFTable for 'vdtor::Test2' in 'vdtor::Test5' (1 entries). + // VDTOR-THUNKS-Test5-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting] + // VDTOR-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test5: Thunks for 'vdtor::Test5::~Test5()' (1 entry). + // VDTOR-THUNKS-Test5-NEXT: 0 | [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test5: VFTable indices for 'vdtor::Test5' (1 entries). + // VDTOR-THUNKS-Test5-NEXT: -- accessible via vfptr at offset 4 -- + // VDTOR-THUNKS-Test5-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting] +}; + +Test5 t5; + +struct Test6 : Test4, Test2 { + // Implicit virtual dtor here! + + // VDTOR-THUNKS-Test6: VFTable for 'vdtor::Test4' in 'vdtor::Test6' (1 entries). + // VDTOR-THUNKS-Test6-NEXT: 0 | void vdtor::Test4::z4() + + // VDTOR-THUNKS-Test6: VFTable for 'vdtor::Test2' in 'vdtor::Test6' (1 entries). + // VDTOR-THUNKS-Test6-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting] + // VDTOR-THUNKS-Test6-NEXT: [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test6: Thunks for 'vdtor::Test6::~Test6()' (1 entry). + // VDTOR-THUNKS-Test6-NEXT: 0 | [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test6: VFTable indices for 'vdtor::Test6' (1 entries). + // VDTOR-THUNKS-Test6-NEXT: -- accessible via vfptr at offset 4 -- + // VDTOR-THUNKS-Test6-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting] +}; + +Test6 t6; + +struct Test7 : Test5 { + // VDTOR-THUNKS-Test7: VFTable for 'vdtor::Test4' in 'vdtor::Test5' in 'vdtor::Test7' (1 entries). + // VDTOR-THUNKS-Test7-NEXT: 0 | void vdtor::Test4::z4() + + // VDTOR-THUNKS-Test7: VFTable for 'vdtor::Test2' in 'vdtor::Test5' in 'vdtor::Test7' (1 entries). + // VDTOR-THUNKS-Test7-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting] + // VDTOR-THUNKS-Test7-NEXT: [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test7: Thunks for 'vdtor::Test7::~Test7()' (1 entry). + // VDTOR-THUNKS-Test7-NEXT: 0 | [this adjustment: -4 non-virtual] + + // VDTOR-THUNKS-Test7: VFTable indices for 'vdtor::Test7' (1 entries). + // VDTOR-THUNKS-Test7-NEXT: -- accessible via vfptr at offset 4 -- + // VDTOR-THUNKS-Test7-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting] + virtual ~Test7(); +}; + +Test7 t7; + +} + +namespace return_adjustment { + +struct Ret1 { + virtual C* foo(); + virtual void z(); +}; + +struct Test1 : Ret1 { + // RET-THUNKS-Test1: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' (3 entries). + // RET-THUNKS-Test1-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test1::foo() + // RET-THUNKS-Test1-NEXT: [return adjustment: 4 non-virtual] + // RET-THUNKS-Test1-NEXT: 1 | void return_adjustment::Ret1::z() + // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo() + + // RET-THUNKS-Test1: VFTable indices for 'return_adjustment::Test1' (1 entries). + // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo() + + // MANGLING-DAG: @"\01??_7Test1@return_adjustment@@6B@" + + virtual this_adjustment::Test1* foo(); +}; + +Test1 t1; + +struct Ret2 : B, this_adjustment::Test1 { }; + +struct Test2 : Test1 { + // RET-THUNKS-Test2: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test2' (4 entries). + // RET-THUNKS-Test2-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test2::foo() + // RET-THUNKS-Test2-NEXT: [return adjustment: 8 non-virtual] + // RET-THUNKS-Test2-NEXT: 1 | void return_adjustment::Ret1::z() + // RET-THUNKS-Test2-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test2::foo() + // RET-THUNKS-Test2-NEXT: [return adjustment: 4 non-virtual] + // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo() + + // RET-THUNKS-Test2: VFTable indices for 'return_adjustment::Test2' (1 entries). + // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo() + + virtual Ret2* foo(); +}; + +Test2 t2; + +struct Test3: B, Ret1 { + // RET-THUNKS-Test3: VFTable for 'B' in 'return_adjustment::Test3' (2 entries). + // RET-THUNKS-Test3-NEXT: 0 | void B::g() + // RET-THUNKS-Test3-NEXT: 1 | void B::h() + + // RET-THUNKS-Test3: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' (3 entries). + // RET-THUNKS-Test3-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test3::foo() + // RET-THUNKS-Test3-NEXT: [return adjustment: 4 non-virtual] + // RET-THUNKS-Test3-NEXT: 1 | void return_adjustment::Ret1::z() + // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo() + + // RET-THUNKS-Test3: VFTable indices for 'return_adjustment::Test3' (1 entries). + // RET-THUNKS-Test3-NEXT: via vfptr at offset 4 + // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo() + + virtual this_adjustment::Test1* foo(); +}; + +Test3 t3; + +struct Test4 : Test3 { + // RET-THUNKS-Test4: VFTable for 'B' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (2 entries). + // RET-THUNKS-Test4-NEXT: 0 | void B::g() + // RET-THUNKS-Test4-NEXT: 1 | void B::h() + + // RET-THUNKS-Test4: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (4 entries). + // RET-THUNKS-Test4-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test4::foo() + // RET-THUNKS-Test4-NEXT: [return adjustment: 8 non-virtual] + // RET-THUNKS-Test4-NEXT: 1 | void return_adjustment::Ret1::z() + // RET-THUNKS-Test4-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test4::foo() + // RET-THUNKS-Test4-NEXT: [return adjustment: 4 non-virtual] + // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo() + + // RET-THUNKS-Test4: VFTable indices for 'return_adjustment::Test4' (1 entries). + // RET-THUNKS-Test4-NEXT: -- accessible via vfptr at offset 4 -- + // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo() + + virtual Ret2* foo(); +}; + +Test4 t4; + +struct Test5 : Ret1, Test1 { + // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test5' (3 entries). + // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo() + // RET-THUNKS-Test5-NEXT: [return adjustment: 8 non-virtual] + // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z() + // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo() + + // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test5' (4 entries). + // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo() + // RET-THUNKS-Test5-NEXT: [return adjustment: 8 non-virtual] + // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual] + // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z() + // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo() + // RET-THUNKS-Test5-NEXT: [return adjustment: 4 non-virtual] + // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual] + // RET-THUNKS-Test5-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test5::foo() + // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual] + + // RET-THUNKS-Test5: VFTable indices for 'return_adjustment::Test5' (1 entries). + // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo() + + virtual Ret2* foo(); +}; + +Test5 t5; + +struct Ret3 : this_adjustment::Test1 { }; + +struct Test6 : Test1 { + virtual Ret3* foo(); + // RET-THUNKS-Test6: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test6' (4 entries). + // RET-THUNKS-Test6-NEXT: 0 | return_adjustment::Ret3 *return_adjustment::Test6::foo() + // RET-THUNKS-Test6-NEXT: [return adjustment: 4 non-virtual] + // RET-THUNKS-Test6-NEXT: 1 | void return_adjustment::Ret1::z() + // RET-THUNKS-Test6-NEXT: 2 | return_adjustment::Ret3 *return_adjustment::Test6::foo() + // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo() + + // RET-THUNKS-Test6: VFTable indices for 'return_adjustment::Test6' (1 entries). + // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo() +}; + +Test6 t6; + +} diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp index 5d430db..6fe12b0 100644 --- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o - > %t 2>&1 -// RUN: FileCheck --check-prefix=EMITS-VTABLE %s < %t +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o %t.ll > %t +// RUN: FileCheck --check-prefix=EMITS-VFTABLE %s < %t.ll +// RUN: FileCheck --check-prefix=NO-VFTABLE %s < %t.ll // RUN: FileCheck --check-prefix=CHECK-A %s < %t // RUN: FileCheck --check-prefix=CHECK-B %s < %t // RUN: FileCheck --check-prefix=CHECK-C %s < %t @@ -7,107 +8,245 @@ // RUN: FileCheck --check-prefix=CHECK-E %s < %t // RUN: FileCheck --check-prefix=CHECK-F %s < %t // RUN: FileCheck --check-prefix=CHECK-G %s < %t +// RUN: FileCheck --check-prefix=CHECK-I %s < %t +// RUN: FileCheck --check-prefix=CHECK-J %s < %t +// RUN: FileCheck --check-prefix=CHECK-K %s < %t +// RUN: FileCheck --check-prefix=CHECK-L %s < %t +// RUN: FileCheck --check-prefix=CHECK-M %s < %t +// RUN: FileCheck --check-prefix=CHECK-N %s < %t struct A { - // CHECK-A: Vtable for 'A' (3 entries) + // CHECK-A: VFTable for 'A' (3 entries) // CHECK-A-NEXT: 0 | void A::f() // CHECK-A-NEXT: 1 | void A::g() // CHECK-A-NEXT: 2 | void A::h() - // EMITS-VTABLE: @"\01??_7A@@6B@" = unnamed_addr constant [3 x i8*] + // CHECK-A: VFTable indices for 'A' (3 entries) + // CHECK-A-NEXT: 0 | void A::f() + // CHECK-A-NEXT: 1 | void A::g() + // CHECK-A-NEXT: 2 | void A::h() + virtual void f(); virtual void g(); virtual void h(); int ia; }; -void A::f() {} +A a; +// EMITS-VFTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*] struct B : A { - // CHECK-B: Vtable for 'B' (5 entries) + // CHECK-B: VFTable for 'A' in 'B' (5 entries) // CHECK-B-NEXT: 0 | void B::f() // CHECK-B-NEXT: 1 | void A::g() // CHECK-B-NEXT: 2 | void A::h() // CHECK-B-NEXT: 3 | void B::i() // CHECK-B-NEXT: 4 | void B::j() - // EMITS-VTABLE: @"\01??_7B@@6B@" = unnamed_addr constant [5 x i8*] + // CHECK-B: VFTable indices for 'B' (3 entries) + // CHECK-B-NEXT: 0 | void B::f() + // CHECK-B-NEXT: 3 | void B::i() + // CHECK-B-NEXT: 4 | void B::j() + virtual void f(); // overrides A::f() virtual void i(); virtual void j(); }; -void B::f() {} +B b; +// EMITS-VFTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] struct C { - // CHECK-C: Vtable for 'C' (2 entries) + // CHECK-C: VFTable for 'C' (2 entries) // CHECK-C-NEXT: 0 | C::~C() [scalar deleting] // CHECK-C-NEXT: 1 | void C::f() - // CHECK-C: VTable indices for 'C' (2 entries). + // CHECK-C: VFTable indices for 'C' (2 entries). // CHECK-C-NEXT: 0 | C::~C() [scalar deleting] // CHECK-C-NEXT: 1 | void C::f() - // Never used, so doesn't emit a vtable. - virtual ~C(); + virtual ~C(); virtual void f(); }; void C::f() {} +// NO-VFTABLE-NOT: @"\01??_7C@@6B@" struct D { - // CHECK-D: Vtable for 'D' (2 entries) + // CHECK-D: VFTable for 'D' (2 entries) + // CHECK-D-NEXT: 0 | void D::f() + // CHECK-D-NEXT: 1 | D::~D() [scalar deleting] + // CHECK-D: VFTable indices for 'D' (2 entries) // CHECK-D-NEXT: 0 | void D::f() // CHECK-D-NEXT: 1 | D::~D() [scalar deleting] - // EMITS-VTABLE: @"\01??_7D@@6B@" = unnamed_addr constant [2 x i8*] - virtual void f(); + virtual void f(); virtual ~D(); }; -void D::f() {} +D d; +// EMITS-VFTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*] struct E : A { - // CHECK-E: Vtable for 'E' (5 entries) + // CHECK-E: VFTable for 'A' in 'E' (5 entries) // CHECK-E-NEXT: 0 | void A::f() // CHECK-E-NEXT: 1 | void A::g() // CHECK-E-NEXT: 2 | void A::h() // CHECK-E-NEXT: 3 | E::~E() [scalar deleting] // CHECK-E-NEXT: 4 | void E::i() - // CHECK-E: VTable indices for 'E' (2 entries). + // CHECK-E: VFTable indices for 'E' (2 entries). // CHECK-E-NEXT: 3 | E::~E() [scalar deleting] // CHECK-E-NEXT: 4 | void E::i() - // Never used, so doesn't emit a vtable. + // ~E would be the key method, but it isn't used, and MS ABI has no key + // methods. virtual ~E(); virtual void i(); }; void E::i() {} +// NO-VFTABLE-NOT: @"\01??_7E@@6B@" struct F : A { - // CHECK-F: Vtable for 'F' (5 entries) + // CHECK-F: VFTable for 'A' in 'F' (5 entries) // CHECK-F-NEXT: 0 | void A::f() // CHECK-F-NEXT: 1 | void A::g() // CHECK-F-NEXT: 2 | void A::h() // CHECK-F-NEXT: 3 | void F::i() // CHECK-F-NEXT: 4 | F::~F() [scalar deleting] - // CHECK-F: VTable indices for 'F' (2 entries). + // CHECK-F: VFTable indices for 'F' (2 entries). // CHECK-F-NEXT: 3 | void F::i() // CHECK-F-NEXT: 4 | F::~F() [scalar deleting] - // EMITS-VTABLE: @"\01??_7F@@6B@" = unnamed_addr constant [5 x i8*] + virtual void i(); virtual ~F(); }; -void F::i() {} +F f; +// EMITS-VFTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] struct G : E { - // CHECK-G: Vtable for 'G' (6 entries) + // CHECK-G: VFTable for 'A' in 'E' in 'G' (6 entries) // CHECK-G-NEXT: 0 | void G::f() // CHECK-G-NEXT: 1 | void A::g() // CHECK-G-NEXT: 2 | void A::h() // CHECK-G-NEXT: 3 | G::~G() [scalar deleting] // CHECK-G-NEXT: 4 | void E::i() // CHECK-G-NEXT: 5 | void G::j() - // CHECK-G: VTable indices for 'G' (3 entries). + // CHECK-G: VFTable indices for 'G' (3 entries). // CHECK-G-NEXT: 0 | void G::f() // CHECK-G-NEXT: 3 | G::~G() [scalar deleting] // CHECK-G-NEXT: 5 | void G::j() - // Never used, so doesn't emit a vtable. + virtual void f(); // overrides A::f() virtual ~G(); virtual void j(); }; void G::j() {} +// NO-VFTABLE-NOT: @"\01??_7G@@6B@" + +// Test that the usual Itanium-style key method does not emit a vtable. +struct H { + virtual void f(); +}; +void H::f() {} +// NO-VFTABLE-NOT: @"\01??_7H@@6B@" + +struct Empty { }; + +struct I : Empty { + // CHECK-I: VFTable for 'I' (2 entries) + // CHECK-I-NEXT: 0 | void I::f() + // CHECK-I-NEXT: 1 | void I::g() + virtual void f(); + virtual void g(); +}; + +I i; + +struct J { + // CHECK-J: VFTable for 'J' (6 entries) + // CHECK-J-NEXT: 0 | void J::foo(long) + // CHECK-J-NEXT: 1 | void J::foo(int) + // CHECK-J-NEXT: 2 | void J::foo(short) + // CHECK-J-NEXT: 3 | void J::bar(long) + // CHECK-J-NEXT: 4 | void J::bar(int) + // CHECK-J-NEXT: 5 | void J::bar(short) + virtual void foo(short); + virtual void bar(short); + virtual void foo(int); + virtual void bar(int); + virtual void foo(long); + virtual void bar(long); +}; + +J j; + +struct K : J { + // CHECK-K: VFTable for 'J' in 'K' (9 entries) + // CHECK-K-NEXT: 0 | void J::foo(long) + // CHECK-K-NEXT: 1 | void J::foo(int) + // CHECK-K-NEXT: 2 | void J::foo(short) + // CHECK-K-NEXT: 3 | void J::bar(long) + // CHECK-K-NEXT: 4 | void J::bar(int) + // CHECK-K-NEXT: 5 | void J::bar(short) + // CHECK-K-NEXT: 6 | void K::bar(double) + // CHECK-K-NEXT: 7 | void K::bar(float) + // CHECK-K-NEXT: 8 | void K::foo(float) + virtual void bar(float); + virtual void foo(float); + virtual void bar(double); +}; + +K k; + +struct L : J { + // CHECK-L: VFTable for 'J' in 'L' (9 entries) + // CHECK-L-NEXT: 0 | void J::foo(long) + // CHECK-L-NEXT: 1 | void L::foo(int) + // CHECK-L-NEXT: 2 | void J::foo(short) + // CHECK-L-NEXT: 3 | void J::bar(long) + // CHECK-L-NEXT: 4 | void J::bar(int) + // CHECK-L-NEXT: 5 | void J::bar(short) + // CHECK-L-NEXT: 6 | void L::foo(float) + // CHECK-L-NEXT: 7 | void L::bar(double) + // CHECK-L-NEXT: 8 | void L::bar(float) + + // This case is interesting. Since the J::foo(int) override is the first method in + // the class, foo(float) precedes the bar(double) and bar(float) in the vftable. + virtual void foo(int); + virtual void bar(float); + virtual void foo(float); + virtual void bar(double); +}; + +L l; + +struct M : J { + // CHECK-M: VFTable for 'J' in 'M' (11 entries) + // CHECK-M-NEXT: 0 | void J::foo(long) + // CHECK-M-NEXT: 1 | void M::foo(int) + // CHECK-M-NEXT: 2 | void J::foo(short) + // CHECK-M-NEXT: 3 | void J::bar(long) + // CHECK-M-NEXT: 4 | void J::bar(int) + // CHECK-M-NEXT: 5 | void J::bar(short) + // CHECK-M-NEXT: 6 | void M::foo(float) + // CHECK-M-NEXT: 7 | void M::spam(long) + // CHECK-M-NEXT: 8 | void M::spam(int) + // CHECK-M-NEXT: 9 | void M::bar(double) + // CHECK-M-NEXT: 10 | void M::bar(float) + + virtual void foo(int); + virtual void spam(int); + virtual void bar(float); + virtual void bar(double); + virtual void foo(float); + virtual void spam(long); +}; + +M m; + +struct N { + // CHECK-N: VFTable for 'N' (4 entries) + // CHECK-N-NEXT: 0 | void N::operator+(int) + // CHECK-N-NEXT: 1 | void N::operator+(short) + // CHECK-N-NEXT: 2 | void N::operator*(int) + // CHECK-N-NEXT: 3 | void N::operator*(short) + virtual void operator+(short); + virtual void operator*(short); + virtual void operator+(int); + virtual void operator*(int); +}; + +N n; diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp new file mode 100644 index 0000000..3fef0e4 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp @@ -0,0 +1,324 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm -fdump-vtable-layouts %s -o %t.ll -cxx-abi microsoft -triple=i386-pc-win32 >%t +// RUN: FileCheck --check-prefix=VTABLE-SIMPLE-A %s < %t +// RUN: FileCheck --check-prefix=VTABLE-SIMPLE-B %s < %t +// RUN: FileCheck --check-prefix=VTABLE-SIMPLE-C %s < %t +// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-A %s < %t +// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-B %s < %t +// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-C %s < %t +// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-E %s < %t +// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-F %s < %t +// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-G %s < %t +// RUN: FileCheck --check-prefix=VTABLE-EXTENDED-H %s < %t +// RUN: FileCheck --check-prefix=VTABLE-PR17738-A %s < %t +// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll + +// For now, just make sure x86_64 doesn't crash. +// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -fdump-vtable-layouts %s -cxx-abi microsoft -triple=x86_64-pc-win32 >/dev/null + +struct V1 { + virtual void f(); + virtual ~V1(); +}; + +struct V2 { + virtual void f(); + virtual ~V2(); + int v; +}; + +struct Z { + virtual void g(); + virtual ~Z(); + int x; +}; + +struct V3 : Z, V2 { +}; + +struct V4 : Z, V1, V2 { + int y; +}; + +void use_somewhere_else(void*); + +namespace simple { +// In case of a single-layer virtual inheritance, the "this" adjustment is done +// staically: +// struct A { +// virtual void f(); // Expects "(A*)this" in ECX +// }; +// struct B : virtual A { +// virtual void f(); // Expects "(char*)(B*)this + 12" in ECX +// virtual ~B(); // Might call f() +// }; +// +// If a class overrides a virtual function of its base and has a non-trivial +// ctor/dtor that call(s) the virtual function (or may escape "this" to some +// code that might call it), a virtual adjustment might be needed in case the +// current class layout and the most derived class layout are different. +// This is done using vtordisp thunks. +// +// A simple vtordisp{A,B} thunk for Method@Class is something like: +// sub ecx, [ecx+A] // apply the vtordisp adjustment +// sub ecx, B // apply the subobject adjustment, if needed. +// jmp Method@Class + +struct A : virtual V1 { + // VTABLE-SIMPLE-A: VFTable for 'V1' in 'simple::A' (2 entries). + // VTABLE-SIMPLE-A-NEXT: 0 | void simple::A::f() + // VTABLE-SIMPLE-A-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual] + // VTABLE-SIMPLE-A-NEXT: 1 | simple::A::~A() [scalar deleting] + // VTABLE-SIMPLE-A-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual] + + virtual void f(); + // MANGLING-DAG: @"\01?f@A@simple@@$4PPPPPPPM@A@AEXXZ" + + virtual ~A(); + // MANGLING-DAG: @"\01??_EA@simple@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +A a; + +struct B : virtual V3 { + // VTABLE-SIMPLE-B: VFTable for 'Z' in 'V3' in 'simple::B' (2 entries). + // VTABLE-SIMPLE-B-NEXT: 0 | void Z::g() + // VTABLE-SIMPLE-B-NEXT: 1 | simple::B::~B() [scalar deleting] + // VTABLE-SIMPLE-B-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual] + + // VTABLE-SIMPLE-B: VFTable for 'V2' in 'V3' in 'simple::B' (2 entries). + // VTABLE-SIMPLE-B-NEXT: 0 | void simple::B::f() + // VTABLE-SIMPLE-B-NEXT: [this adjustment: vtordisp at -12, 0 non-virtual] + // VTABLE-SIMPLE-B-NEXT: 1 | simple::B::~B() [scalar deleting] + // VTABLE-SIMPLE-B-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual] + + // FIXME: The vtordisp thunk should only get emitted for a constructor + // if "this" leaves scope. + B() { use_somewhere_else(this); } + + virtual void f(); + // MANGLING-DAG: @"\01?f@B@simple@@$4PPPPPPPE@A@AEXXZ" + + // Has an implicit destructor. + // MANGLING-DAG: @"\01??_EB@simple@@$4PPPPPPPE@7AEPAXI@Z" + // MANGLING-DAG: @"\01??_EB@simple@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +B b; + +struct C : virtual V4 { + // VTABLE-SIMPLE-C: VFTable for 'Z' in 'V4' in 'simple::C' (2 entries). + // VTABLE-SIMPLE-C-NEXT: 0 | void Z::g() + // VTABLE-SIMPLE-C-NEXT: 1 | simple::C::~C() [scalar deleting] + // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual] + + // VTABLE-SIMPLE-C: VFTable for 'V1' in 'V4' in 'simple::C' (2 entries). + // VTABLE-SIMPLE-C-NEXT: 0 | void simple::C::f() + // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -12, 0 non-virtual] + // VTABLE-SIMPLE-C-NEXT: 1 | simple::C::~C() [scalar deleting] + // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual] + + // VTABLE-SIMPLE-C: VFTable for 'V2' in 'V4' in 'simple::C' (2 entries). + // VTABLE-SIMPLE-C-NEXT: 0 | void simple::C::f() + // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -16, -4 non-virtual] + // VTABLE-SIMPLE-C-NEXT: 1 | simple::C::~C() [scalar deleting] + // VTABLE-SIMPLE-C-NEXT: [this adjustment: vtordisp at -16, -12 non-virtual] + + int x; + virtual void f(); + // MANGLING-DAG: @"\01?f@C@simple@@$4PPPPPPPA@3AEXXZ" + // MANGLING-DAG: @"\01?f@C@simple@@$4PPPPPPPE@A@AEXXZ" + virtual ~C(); + // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPA@M@AEPAXI@Z" + // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPE@7AEPAXI@Z" + // MANGLING-DAG: @"\01??_EC@simple@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +C c; +} + +namespace extended { +// If a virtual function requires vtordisp adjustment and the final overrider +// is defined in another vitual base of the most derived class, +// we need to know two vbase offsets. +// In this case, we should use the extended form of vtordisp thunks, called +// vtordispex thunks. +// +// vtordispex{A,B,C,D} thunk for Method@Class is something like: +// sub ecx, [ecx+C] // apply the vtordisp adjustment +// sub ecx, A // jump to the vbtable of the most derived class +// mov eax, [ecx] // load the vbtable address +// add ecx, [eax+B] // lookup the final overrider's vbase offset +// add ecx, D // apphy the subobject offset if needed +// jmp Method@Class + +struct A : virtual simple::A { + // VTABLE-EXTENDED-A: VFTable for 'V1' in 'simple::A' in 'extended::A' (2 entries). + // VTABLE-EXTENDED-A-NEXT: 0 | void simple::A::f() + // VTABLE-EXTENDED-A-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left, + // VTABLE-EXTENDED-A-NEXT: vboffset at 8 in the vbtable, 8 non-virtual] + // VTABLE-EXTENDED-A-NEXT: 1 | extended::A::~A() [scalar deleting] + // VTABLE-EXTENDED-A-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual] + + // `vtordispex{8,8,4294967292,8}' + // MANGLING-DAG: @"\01?f@A@simple@@$R477PPPPPPPM@7AEXXZ" + + virtual ~A(); + // vtordisp{4294967292,0} + // MANGLING-DAG: @"\01??_EA@extended@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +A a; + +struct B : virtual simple::A { + // This class has an implicit dtor. Vdtors don't require vtordispex thunks + // as the most derived class always has an implicit dtor, + // which is a final overrider. + + // VTABLE-EXTENDED-B: VFTable for 'V1' in 'simple::A' in 'extended::B' (2 entries). + // ... + // VTABLE-EXTENDED-B: 1 | extended::B::~B() [scalar deleting] + // VTABLE-EXTENDED-B-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual] + + // vtordisp{4294967292,0} + // MANGLING-DAG: @"\01??_EB@extended@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +B b; + +struct C : virtual simple::A { + // VTABLE-EXTENDED-C: VFTable for 'V1' in 'simple::A' in 'extended::C' (2 entries). + // VTABLE-EXTENDED-C-NEXT: 0 | void simple::A::f() + // VTABLE-EXTENDED-C-NEXT: [this adjustment: vtordisp at -4, vbptr at 12 to the left, + // VTABLE-EXTENDED-C-NEXT: vboffset at 8 in the vbtable, 8 non-virtual] + + // `vtordispex{12,8,4294967292,8}' + // MANGLING-DAG: @"\01?f@A@simple@@$R4M@7PPPPPPPM@7AEXXZ" + int x; + virtual ~C(); + // MANGLING-DAG: @"\01??_EC@extended@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +C c; + +struct D : virtual V2 { + virtual void f(); + virtual ~D(); + int x; +}; + +struct E : virtual D { + // VTABLE-EXTENDED-E: VFTable for 'V2' in 'extended::D' in 'extended::E' (2 entries). + // VTABLE-EXTENDED-E-NEXT: 0 | void extended::D::f() + // VTABLE-EXTENDED-E-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left, + // VTABLE-EXTENDED-E-NEXT: vboffset at 8 in the vbtable, 12 non-virtual] + + // `vtordispex{8,8,4294967292,12}' + // MANGLING-DAG: @"\01?f@D@extended@@$R477PPPPPPPM@M@AEXXZ" + + virtual ~E(); + // MANGLING-DAG: @"\01??_EE@extended@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +E e; + +struct F : virtual Z, virtual D { + // VTABLE-EXTENDED-F: VFTable for 'V2' in 'extended::D' in 'extended::F' (2 entries). + // VTABLE-EXTENDED-F-NEXT: 0 | void extended::D::f() + // VTABLE-EXTENDED-F-NEXT: [this adjustment: vtordisp at -4, vbptr at 20 to the left, + // VTABLE-EXTENDED-F-NEXT: vboffset at 12 in the vbtable, 12 non-virtual] + + // `vtordispex{20,12,4294967292,12}' + // MANGLING-DAG: @"\01?f@D@extended@@$R4BE@M@PPPPPPPM@M@AEXXZ" + int x; + virtual ~F(); + // MANGLING-DAG: @"\01??_EF@extended@@$4PPPPPPPM@M@AEPAXI@Z" +}; + +F f; + +struct G : virtual simple::A { + // VTABLE-EXTENDED-G: VFTable for 'extended::G' (1 entries). + // VTABLE-EXTENDED-G-NEXT: 0 | void extended::G::g() + + // VTABLE-EXTENDED-G: VFTable for 'V1' in 'simple::A' in 'extended::G' (2 entries). + // VTABLE-EXTENDED-G-NEXT: 0 | void simple::A::f() + // VTABLE-EXTENDED-G-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left, + // VTABLE-EXTENDED-G-NEXT: vboffset at 8 in the vbtable, 8 non-virtual] + // VTABLE-EXTENDED-G-NEXT: 1 | extended::G::~G() [scalar deleting] + // VTABLE-EXTENDED-G-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual] + + // Emits a G's own vfptr, thus moving the vbptr in the layout. + virtual void g(); + + virtual ~G(); + // vtordisp{4294967292,0} + // MANGLING-DAG: @"\01??_EG@extended@@$4PPPPPPPM@A@AEPAXI@Z" +}; + +G g; + +struct H : Z, A { + // VTABLE-EXTENDED-H: VFTable for 'Z' in 'extended::H' (2 entries). + // VTABLE-EXTENDED-H-NEXT: 0 | void Z::g() + // VTABLE-EXTENDED-H-NEXT: 1 | extended::H::~H() [scalar deleting] + + // VTABLE-EXTENDED-H: VFTable for 'V1' in 'simple::A' in 'extended::A' in 'extended::H' (2 entries). + // VTABLE-EXTENDED-H-NEXT: 0 | void simple::A::f() + // VTABLE-EXTENDED-H-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left, + // VTABLE-EXTENDED-H-NEXT: vboffset at 8 in the vbtable, 8 non-virtual] + + // MANGLING-DAG: @"\01?f@A@simple@@$R477PPPPPPPM@7AEXXZ" + // MANGLING-DAG: @"\01??_EH@extended@@$4PPPPPPPM@BA@AEPAXI@Z" +}; + +H h; +} + +namespace pr17738 { +// These classes should have vtordispex thunks but MSVS CL miscompiles them. +// Just do the right thing. + +struct A : virtual simple::B { + // VTABLE-PR17738-A: VFTable for 'V2' in 'V3' in 'simple::B' in 'pr17738::A' (2 entries). + // VTABLE-PR17738-A-NEXT: 0 | void simple::B::f() + // VTABLE-PR17738-A-NEXT: [this adjustment: vtordisp at -12, vbptr at 20 to the left, + // VTABLE-PR17738-A-NEXT: vboffset at 8 in the vbtable, 16 non-virtual] + + // MANGLING-DAG: @"\01?f@B@simple@@$R4BE@7PPPPPPPE@BA@AEXXZ" + int a; + virtual ~A(); +}; + +A a; +} + +namespace access { +struct A { + virtual ~A(); +protected: + virtual void prot(); +private: + virtual void priv(); +}; + +struct B : virtual A { + virtual ~B(); +protected: + virtual void prot(); + // MANGLING-DAG: @"\01?prot@B@access@@$2PPPPPPPM@A@AEXXZ" +private: + virtual void priv(); + // MANGLING-DAG: @"\01?priv@B@access@@$0PPPPPPPM@A@AEXXZ" +}; + +B b; + +struct C : virtual B { + virtual ~C(); + + // MANGLING-DAG: @"\01?prot@B@access@@$R277PPPPPPPM@7AEXXZ" + // MANGLING-DAG: @"\01?priv@B@access@@$R077PPPPPPPM@7AEXXZ" +}; + +C c; +} diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp new file mode 100644 index 0000000..b58a0b1 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp @@ -0,0 +1,575 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -cxx-abi microsoft -triple=i386-pc-win32 >%t + +// RUN: FileCheck --check-prefix=VTABLE-C %s < %t +// RUN: FileCheck --check-prefix=VTABLE-D %s < %t +// RUN: FileCheck --check-prefix=TEST1 %s < %t +// RUN: FileCheck --check-prefix=TEST2 %s < %t +// RUN: FileCheck --check-prefix=TEST3 %s < %t +// RUN: FileCheck --check-prefix=TEST4 %s < %t +// RUN: FileCheck --check-prefix=TEST5 %s < %t +// RUN: FileCheck --check-prefix=TEST6 %s < %t +// RUN: FileCheck --check-prefix=TEST7 %s < %t +// RUN: FileCheck --check-prefix=TEST8-X %s < %t +// RUN: FileCheck --check-prefix=TEST8-Z %s < %t +// RUN: FileCheck --check-prefix=TEST9-Y %s < %t +// RUN: FileCheck --check-prefix=TEST9-Z %s < %t +// RUN: FileCheck --check-prefix=TEST9-W %s < %t +// RUN: FileCheck --check-prefix=TEST9-T %s < %t +// RUN: FileCheck --check-prefix=TEST10 %s < %t +// RUN: FileCheck --check-prefix=VDTORS-Y %s < %t +// RUN: FileCheck --check-prefix=VDTORS-U %s < %t +// RUN: FileCheck --check-prefix=VDTORS-V %s < %t +// RUN: FileCheck --check-prefix=VDTORS-P %s < %t +// RUN: FileCheck --check-prefix=RET-W %s < %t +// RUN: FileCheck --check-prefix=RET-T %s < %t +// RUN: FileCheck --check-prefix=RET-V %s < %t + +// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll + +struct Empty { }; + +struct A { + virtual void f(); + virtual void z(); // Useful to check there are no thunks for f() when appropriate. +}; + +struct B { + virtual void g(); +}; + +struct C: virtual A { + // VTABLE-C: VFTable for 'A' in 'C' (2 entries) + // VTABLE-C-NEXT: 0 | void C::f() + // VTABLE-C-NEXT: 1 | void A::z() + + // VTABLE-C: VFTable indices for 'C' (1 entries) + // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0 + // VTABLE-C-NEXT: 0 | void C::f() + + // MANGLING-DAG: @"\01??_7C@@6B@" + + virtual void f(); +}; + +C c; + +struct D: virtual A { + // VTABLE-D: VFTable for 'D' (1 entries). + // VTABLE-D-NEXT: 0 | void D::h() + + // VTABLE-D: VFTable for 'A' in 'D' (2 entries). + // VTABLE-D-NEXT: 0 | void D::f() + // VTABLE-D-NEXT: 1 | void A::z() + + // VTABLE-D: VFTable indices for 'D' (2 entries). + // VTABLE-D-NEXT: via vfptr at offset 0 + // VTABLE-D-NEXT: 0 | void D::h() + // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0 + // VTABLE-D-NEXT: 0 | void D::f() + + // MANGLING-DAG: @"\01??_7D@@6B0@@" + // MANGLING-DAG: @"\01??_7D@@6BA@@@" + + virtual void f(); + virtual void h(); +}; + +void D::h() {} +D d; + +namespace Test1 { + +struct X { int x; }; + +// X and A get reordered in the layout since X doesn't have a vfptr while A has. +struct Y : X, A { }; +// MANGLING-DAG: @"\01??_7Y@Test1@@6B@" + +struct Z : virtual Y { + // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). + // TEST1-NEXT: 0 | void A::f() + // TEST1-NEXT: 1 | void A::z() + + // TEST1-NOT: VFTable indices for 'Test1::Z' + + // MANGLING-DAG: @"\01??_7Z@Test1@@6B@" +}; + +Z z; +} + +namespace Test2 { + +struct X: virtual A, virtual B { + // TEST2: VFTable for 'Test2::X' (1 entries). + // TEST2-NEXT: 0 | void Test2::X::h() + + // TEST2: VFTable for 'A' in 'Test2::X' (2 entries). + // TEST2-NEXT: 0 | void A::f() + // TEST2-NEXT: 1 | void A::z() + + // TEST2: VFTable for 'B' in 'Test2::X' (1 entries). + // TEST2-NEXT: 0 | void B::g() + + // TEST2: VFTable indices for 'Test2::X' (1 entries). + // TEST2-NEXT: 0 | void Test2::X::h() + + // MANGLING-DAG: @"\01??_7X@Test2@@6B01@@" + // MANGLING-DAG: @"\01??_7X@Test2@@6BA@@@" + // MANGLING-DAG: @"\01??_7X@Test2@@6BB@@@" + + virtual void h(); +}; + +X x; +} + +namespace Test3 { + +struct X : virtual A { + // MANGLING-DAG: @"\01??_7X@Test3@@6B@" +}; + +struct Y: virtual X { + // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). + // TEST3-NEXT: 0 | void A::f() + // TEST3-NEXT: 1 | void A::z() + + // TEST3-NOT: VFTable indices for 'Test3::Y' + + // MANGLING-DAG: @"\01??_7Y@Test3@@6B@" +}; + +Y y; +} + +namespace Test4 { + +struct X: virtual C { + // This one's interesting. C::f expects (A*) to be passed as 'this' and does + // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk + // should pass a pointer to the end of X in order + // for ECX-=4 to point at the C part. + + // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). + // TEST4-NEXT: 0 | void C::f() + // TEST4-NEXT: [this adjustment: 8 non-virtual] + // TEST4-NEXT: 1 | void A::z() + + // TEST4-NOT: VFTable indices for 'Test4::X' + + // MANGLING-DAG: @"\01??_7X@Test4@@6B@" + + // Also check the mangling of the thunk. + // MANGLING-DAG: define weak x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ" +}; + +X x; +} + +namespace Test5 { + +// New methods are added to the base's vftable. +struct X : A { + // MANGLING-DAG: @"\01??_7X@Test5@@6B@" + virtual void g(); +}; + +struct Y : virtual X { + // TEST5: VFTable for 'Test5::Y' (1 entries). + // TEST5-NEXT: 0 | void Test5::Y::h() + + // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). + // TEST5-NEXT: 0 | void A::f() + // TEST5-NEXT: 1 | void A::z() + // TEST5-NEXT: 2 | void Test5::X::g() + + // TEST5: VFTable indices for 'Test5::Y' (1 entries). + // TEST5-NEXT: 0 | void Test5::Y::h() + + // MANGLING-DAG: @"\01??_7Y@Test5@@6B01@@" + // MANGLING-DAG: @"\01??_7Y@Test5@@6BX@1@@" + + virtual void h(); +}; + +Y y; +} + +namespace Test6 { + +struct X : A, virtual Empty { + // TEST6: VFTable for 'A' in 'Test6::X' (2 entries). + // TEST6-NEXT: 0 | void A::f() + // TEST6-NEXT: 1 | void A::z() + + // TEST6-NOT: VFTable indices for 'Test6::X' + + // MANGLING-DAG: @"\01??_7X@Test6@@6B@" +}; + +X x; +} + +namespace Test7 { + +struct X : C { + // MANGLING-DAG: @"\01??_7X@Test7@@6B@" +}; + +struct Y : virtual X { + // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). + // TEST7-NEXT: 0 | void C::f() + // TEST7-NEXT: [this adjustment: 8 non-virtual] + // TEST7-NEXT: 1 | void A::z() + + // TEST7: Thunks for 'void C::f()' (1 entry). + // TEST7-NEXT: 0 | [this adjustment: 8 non-virtual] + + // TEST7-NOT: VFTable indices for 'Test7::Y' + + // MANGLING-DAG: @"\01??_7Y@Test7@@6B@" +}; + +Y y; +} + +namespace Test8 { + +// This is a typical diamond inheritance with a shared 'A' vbase. +struct X : D, C { + // TEST8-X: VFTable for 'D' in 'Test8::X' (1 entries). + // TEST8-X-NEXT: 0 | void D::h() + + // TEST8-X: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). + // TEST8-X-NEXT: 0 | void Test8::X::f() + // TEST8-X-NEXT: 1 | void A::z() + + // TEST8-X: VFTable indices for 'Test8::X' (1 entries). + // TEST8-X-NEXT: via vbtable index 1, vfptr at offset 0 + // TEST8-X-NEXT: 0 | void Test8::X::f() + + // MANGLING-DAG: @"\01??_7X@Test8@@6BA@@@" + // MANGLING-DAG: @"\01??_7X@Test8@@6BD@@@" + + virtual void f(); +}; + +X x; + +// Another diamond inheritance which led to AST crashes. +struct Y : virtual A {}; + +class Z : Y, C { + // TEST8-Z: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). + // TEST8-Z-NEXT: 0 | void Test8::Z::f() + // TEST8-Z-NEXT: 1 | void A::z() + + // TEST8-Z: VFTable indices for 'Test8::Z' (1 entries). + // TEST8-Z-NEXT: via vbtable index 1, vfptr at offset 0 + // TEST8-Z-NEXT: 0 | void Test8::Z::f() + virtual void f(); +}; +Z z; +} + +namespace Test9 { + +struct X : A { }; + +struct Y : virtual X { + // TEST9-Y: VFTable for 'Test9::Y' (1 entries). + // TEST9-Y-NEXT: 0 | void Test9::Y::h() + + // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). + // TEST9-Y-NEXT: 0 | void A::f() + // TEST9-Y-NEXT: 1 | void A::z() + + // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries). + // TEST9-Y-NEXT: 0 | void Test9::Y::h() + + // MANGLING-DAG: @"\01??_7Y@Test9@@6B01@@" + // MANGLING-DAG: @"\01??_7Y@Test9@@6BX@1@@" + + virtual void h(); +}; + +Y y; + +struct Z : Y, virtual B { + // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries). + // TEST9-Z-NEXT: 0 | void Test9::Y::h() + + // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). + // TEST9-Z-NEXT: 0 | void A::f() + // TEST9-Z-NEXT: 1 | void A::z() + + // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries). + // TEST9-Z-NEXT: 0 | void B::g() + + // TEST9-Z-NOT: VFTable indices for 'Test9::Z' + + // MANGLING-DAG: @"\01??_7Z@Test9@@6BX@1@@" + // MANGLING-DAG: @"\01??_7Z@Test9@@6BY@1@@" + + // FIXME this one is wrong: + // INCORRECT MANGLING-DAG: @"\01??_7Z@Test9@@6BB@@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7Z@Test9@@6B@" +}; + +Z z; + +struct W : Z, D, virtual A, virtual B { + // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entries). + // TEST9-W-NEXT: 0 | void Test9::Y::h() + + // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). + // TEST9-W-NEXT: 0 | void A::f() + // TEST9-W-NEXT: 1 | void A::z() + + // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries). + // TEST9-W-NEXT: 0 | void B::g() + + // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries). + // TEST9-W-NEXT: 0 | void D::h() + + // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). + // TEST9-W-NEXT: 0 | void D::f() + // TEST9-W-NEXT: [this adjustment: -8 non-virtual] + // TEST9-W-NEXT: 1 | void A::z() + + // TEST9-W: Thunks for 'void D::f()' (1 entry). + // TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual] + + // TEST9-W-NOT: VFTable indices for 'Test9::W' + + // MANGLING-DAG: @"\01??_7W@Test9@@6BA@@@" + // MANGLING-DAG: @"\01??_7W@Test9@@6BD@@@" + // MANGLING-DAG: @"\01??_7W@Test9@@6BX@1@@" + + // FIXME: these two are wrong: + // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BB@@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6B@" + // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@Z@1@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6BY@1@@" +}; + +W w; + +struct T : Z, D, virtual A, virtual B { + // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entries). + // TEST9-T-NEXT: 0 | void Test9::T::h() + + // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). + // TEST9-T-NEXT: 0 | void Test9::T::f() + // TEST9-T-NEXT: 1 | void Test9::T::z() + + // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries). + // TEST9-T-NEXT: 0 | void Test9::T::g() + + // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries). + // TEST9-T-NEXT: 0 | void Test9::T::h() + // TEST9-T-NEXT: [this adjustment: -8 non-virtual] + + // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry). + // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] + + // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). + // TEST9-T-NEXT: 0 | void Test9::T::f() + // TEST9-T-NEXT: [this adjustment: -8 non-virtual] + // TEST9-T-NEXT: 1 | void Test9::T::z() + // TEST9-T-NEXT: [this adjustment: -8 non-virtual] + + // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry). + // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] + + // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry). + // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] + + // TEST9-T: VFTable indices for 'Test9::T' (4 entries). + // TEST9-T-NEXT: via vfptr at offset 0 + // TEST9-T-NEXT: 0 | void Test9::T::h() + // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0 + // TEST9-T-NEXT: 0 | void Test9::T::f() + // TEST9-T-NEXT: 1 | void Test9::T::z() + // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0 + // TEST9-T-NEXT: 0 | void Test9::T::g() + + // MANGLING-DAG: @"\01??_7T@Test9@@6BA@@@" + // MANGLING-DAG: @"\01??_7T@Test9@@6BD@@@" + // MANGLING-DAG: @"\01??_7T@Test9@@6BX@1@@" + + // FIXME: these two are wrong: + // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BB@@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6B@" + // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@Z@1@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6BY@1@@" + + virtual void f(); + virtual void g(); + virtual void h(); + virtual void z(); +}; + +T t; +} + +namespace Test10 { +struct X : virtual C, virtual A { + // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). + // TEST10-NEXT: 0 | void Test10::X::f() + // TEST10-NEXT: 1 | void A::z() + + // TEST10: VFTable indices for 'Test10::X' (1 entries). + // TEST10-NEXT: via vbtable index 1, vfptr at offset 0 + // TEST10-NEXT: 0 | void Test10::X::f() + virtual void f(); +}; + +void X::f() {} +X x; +} + +namespace vdtors { +struct X { + virtual ~X(); + virtual void zzz(); +}; + +struct Y : virtual X { + // VDTORS-Y: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). + // VDTORS-Y-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] + // VDTORS-Y-NEXT: 1 | void vdtors::X::zzz() + + // VDTORS-Y-NOT: Thunks for 'vdtors::Y::~Y()' + virtual ~Y(); +}; + +Y y; + +struct Z { + virtual void z(); +}; + +struct W : Z, X { + // Implicit virtual dtor. +}; + +struct U : virtual W { + // VDTORS-U: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entries). + // VDTORS-U-NEXT: 0 | void vdtors::Z::z() + + // VDTORS-U: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). + // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] + // VDTORS-U-NEXT: [this adjustment: -4 non-virtual] + // VDTORS-U-NEXT: 1 | void vdtors::X::zzz() + + // VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry). + // VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual] + + // VDTORS-U: VFTable indices for 'vdtors::U' (1 entries). + // VDTORS-U-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- + // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] + virtual ~U(); +}; + +U u; + +struct V : virtual W { + // VDTORS-V: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entries). + // VDTORS-V-NEXT: 0 | void vdtors::Z::z() + + // VDTORS-V: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). + // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] + // VDTORS-V-NEXT: [this adjustment: -4 non-virtual] + // VDTORS-V-NEXT: 1 | void vdtors::X::zzz() + + // VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry). + // VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual] + + // VDTORS-V: VFTable indices for 'vdtors::V' (1 entries). + // VDTORS-V-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- + // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] +}; + +V v; + +struct T : virtual X { + virtual ~T(); +}; + +struct P : T, Y { + // VDTORS-P: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). + // VDTORS-P-NEXT: 0 | vdtors::P::~P() [scalar deleting] + // VDTORS-P-NEXT: 1 | void vdtors::X::zzz() + + // VDTORS-P-NOT: Thunks for 'vdtors::P::~P()' + virtual ~P(); +}; + +P p; + +} + +namespace return_adjustment { + +struct X : virtual A { + virtual void f(); +}; + +struct Y : virtual A, virtual X { + virtual void f(); +}; + +struct Z { + virtual A* foo(); +}; + +struct W : Z { + // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). + // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() + // RET-W-NEXT: [return adjustment: vbase #1, 0 non-virtual] + // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() + + // RET-W: VFTable indices for 'return_adjustment::W' (1 entries). + // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() + + virtual X* foo(); +}; + +W y; + +struct T : W { + // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). + // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() + // RET-T-NEXT: [return adjustment: vbase #1, 0 non-virtual] + // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() + // RET-T-NEXT: [return adjustment: vbase #2, 0 non-virtual] + // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() + + // RET-T: VFTable indices for 'return_adjustment::T' (1 entries). + // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() + + virtual Y* foo(); +}; + +T t; + +struct U : virtual A { + virtual void g(); // adds a vfptr +}; + +struct V : Z { + // RET-V: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). + // RET-V-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() + // RET-V-NEXT: [return adjustment: vbptr at offset 4, vbase #1, 0 non-virtual] + // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() + + // RET-V: VFTable indices for 'return_adjustment::V' (1 entries). + // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() + + virtual U* foo(); +}; + +V v; +} diff --git a/test/CodeGenCXX/microsoft-interface.cpp b/test/CodeGenCXX/microsoft-interface.cpp index 0b44bab..419075a 100644 --- a/test/CodeGenCXX/microsoft-interface.cpp +++ b/test/CodeGenCXX/microsoft-interface.cpp @@ -19,25 +19,25 @@ int fn() { // CHECK: @_ZTV1S = linkonce_odr unnamed_addr constant [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1S to i8*), i8* bitcast (i32 (%struct.S*)* @_ZN1S4testEv to i8*)] -// CHECK: define i32 @_Z2fnv() +// CHECK-LABEL: define i32 @_Z2fnv() // CHECK: call void @_ZN1SC1Ev(%struct.S* %s) // CHECK: %{{[.0-9A-Z_a-z]+}} = call i32 @_ZN1S4testEv(%struct.S* %s) -// CHECK: define linkonce_odr void @_ZN1SC1Ev(%struct.S* %this) +// CHECK-LABEL: define linkonce_odr void @_ZN1SC1Ev(%struct.S* %this) // CHECK: call void @_ZN1SC2Ev(%struct.S* %{{[.0-9A-Z_a-z]+}}) -// CHECK: define linkonce_odr i32 @_ZN1S4testEv(%struct.S* %this) +// CHECK-LABEL: define linkonce_odr i32 @_ZN1S4testEv(%struct.S* %this) // CHECK: %{{[.0-9A-Z_a-z]+}} = call i32 @_ZN1I4testEv(%__interface.I* %{{[.0-9A-Z_a-z]+}}) -// CHECK: define linkonce_odr i32 @_ZN1I4testEv(%__interface.I* %this) +// CHECK-LABEL: define linkonce_odr i32 @_ZN1I4testEv(%__interface.I* %this) // CHECK: ret i32 1 -// CHECK: define linkonce_odr void @_ZN1SC2Ev(%struct.S* %this) +// CHECK-LABEL: define linkonce_odr void @_ZN1SC2Ev(%struct.S* %this) // CHECK: call void @_ZN1IC2Ev(%__interface.I* %{{[.0-9A-Z_a-z]+}}) // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1S, i64 0, i64 2), i8*** %{{[.0-9A-Z_a-z]+}} -// CHECK: define linkonce_odr void @_ZN1IC2Ev(%__interface.I* %this) +// CHECK-LABEL: define linkonce_odr void @_ZN1IC2Ev(%__interface.I* %this) // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1I, i64 0, i64 2), i8*** %{{[.0-9A-Z_a-z]+}} -// CHECK-NOT: define linkonce_odr %__interface.I* @_ZN1IaSERKS_(%__interface.I* %this, %__interface.I*) -// CHECK-NOT: define linkonce_odr %__interface.I* @_ZN1IaSEOS_(%__interface.I* %this, %__interface.I*) +// CHECK-NOT-LABEL: define linkonce_odr %__interface.I* @_ZN1IaSERKS_(%__interface.I* %this, %__interface.I*) +// CHECK-NOT-LABEL: define linkonce_odr %__interface.I* @_ZN1IaSEOS_(%__interface.I* %this, %__interface.I*) diff --git a/test/CodeGenCXX/microsoft-new.cpp b/test/CodeGenCXX/microsoft-new.cpp new file mode 100644 index 0000000..48e93d4 --- /dev/null +++ b/test/CodeGenCXX/microsoft-new.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple i686-pc-win32 -fms-compatibility %s -emit-llvm -o - | FileCheck %s
+
+#include <stddef.h>
+
+struct arbitrary_t {} arbitrary;
+void *operator new(size_t size, arbitrary_t);
+
+struct arbitrary2_t {} arbitrary2;
+void *operator new[](size_t size, arbitrary2_t);
+
+namespace PR13164 {
+ void f() {
+ // MSVC will fall back on the non-array operator new.
+ void *a;
+ int *p = new(arbitrary) int[4];
+ // CHECK: call i8* @_Znwj11arbitrary_t(i32 16, %struct.arbitrary_t*
+ }
+
+ struct S {
+ void *operator new[](size_t size, arbitrary_t);
+ };
+
+ void g() {
+ S *s = new(arbitrary) S[2];
+ // CHECK: call i8* @_ZN7PR131641SnaEj11arbitrary_t(i32 2, %struct.arbitrary_t*
+ S *s1 = new(arbitrary) S;
+ // CHECK: call i8* @_Znwj11arbitrary_t(i32 1, %struct.arbitrary_t*
+ }
+
+ struct T {
+ void *operator new(size_t size, arbitrary2_t);
+ };
+
+ void h() {
+ // This should still call the global operator new[].
+ T *t = new(arbitrary2) T[2];
+ // CHECK: call i8* @_Znaj12arbitrary2_t(i32 2, %struct.arbitrary2_t*
+ }
+}
diff --git a/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp b/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp deleted file mode 100644 index 4f68aa3..0000000 --- a/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-macosx10.8.0 -fms-extensions -verify - -typedef struct _GUID -{ - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8]; -} GUID; - -struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S { }; - -GUID g = __uuidof(S); // expected-error {{__uuidof codegen is not supported on this architecture}} diff --git a/test/CodeGenCXX/microsoft-uuidof.cpp b/test/CodeGenCXX/microsoft-uuidof.cpp index 8eeb449..ab3d9b6 100644 --- a/test/CodeGenCXX/microsoft-uuidof.cpp +++ b/test/CodeGenCXX/microsoft-uuidof.cpp @@ -1,72 +1,112 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -triple=i386-pc-win32 -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DWRONG_GUID -triple=i386-pc-win32 -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-WRONG-GUID -typedef struct _GUID -{ +#ifdef DEFINE_GUID +struct _GUID { +#ifdef WRONG_GUID + unsigned int SomethingWentWrong; +#else unsigned long Data1; unsigned short Data2; unsigned short Data3; unsigned char Data4[8]; -} GUID; +#endif +}; +#endif +typedef struct _GUID GUID; -struct __declspec(uuid("12345678-1234-1234-1234-1234567890ab")) S1 { } s1; +struct __declspec(uuid("12345678-1234-1234-1234-1234567890aB")) S1 { } s1; struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S2 { }; +struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly; + +#ifdef DEFINE_GUID +// Make sure we can properly generate code when the UUID has curly braces on it. +GUID thing = __uuidof(Curly); +// CHECK-DEFINE-GUID: @thing = global %struct._GUID zeroinitializer, align 4 +// CHECK-DEFINE-WRONG-GUID: @thing = global %struct._GUID zeroinitializer, align 4 // This gets initialized in a static initializer. -// CHECK: @g = global %struct._GUID zeroinitializer, align 4 +// CHECK-DEFINE-GUID: @g = global %struct._GUID zeroinitializer, align 4 +// CHECK-DEFINE-WRONG-GUID: @g = global %struct._GUID zeroinitializer, align 4 GUID g = __uuidof(S1); +#endif // First global use of __uuidof(S1) forces the creation of the global. -// CHECK: @__uuid_12345678-1234-1234-1234-1234567890ab = private unnamed_addr constant %struct._GUID { i32 305419896, i16 4660, i16 4660, [8 x i8] c"\124\124Vx\90\AB" } -// CHECK: @gr = constant %struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab, align 4 +// CHECK: @_GUID_12345678_1234_1234_1234_1234567890ab = linkonce_odr constant { i32, i16, i16, [8 x i8] } { i32 305419896, i16 4660, i16 4660, [8 x i8] c"\124\124Vx\90\AB" } +// CHECK: @gr = constant %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to %struct._GUID*), align 4 const GUID& gr = __uuidof(S1); -// CHECK: @gp = global %struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab, align 4 +// CHECK: @gp = global %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to %struct._GUID*), align 4 const GUID* gp = &__uuidof(S1); +// CHECK: @cp = global %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to %struct._GUID*), align 4 +const GUID* cp = &__uuidof(Curly); + // Special case: _uuidof(0) -// CHECK: @zeroiid = constant %struct._GUID* @__uuid_00000000-0000-0000-0000-000000000000, align 4 +// CHECK: @zeroiid = constant %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_00000000_0000_0000_0000_000000000000 to %struct._GUID*), align 4 const GUID& zeroiid = __uuidof(0); // __uuidof(S2) hasn't been used globally yet, so it's emitted when it's used // in a function and is emitted at the end of the globals section. -// CHECK: @__uuid_87654321-4321-4321-4321-ba0987654321 = private unnamed_addr constant %struct._GUID { i32 -2023406815, i16 17185, i16 17185, [8 x i8] c"C!\BA\09\87eC!" } +// CHECK: @_GUID_87654321_4321_4321_4321_ba0987654321 = linkonce_odr constant { i32, i16, i16, [8 x i8] } { i32 -2023406815, i16 17185, i16 17185, [8 x i8] c"C!\BA\09\87eC!" } + +// The static initializer for thing. +// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @thing to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 16, i32 4, i1 false) +// CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @thing to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ac to i8*), i32 4, i32 4, i1 false) // The static initializer for g. -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false) +// CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false) +// CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast (%struct._GUID* @g to i8*), i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false) +#ifdef DEFINE_GUID void fun() { - // CHECK: %s1_1 = alloca %struct._GUID, align 4 - // CHECK: %s1_2 = alloca %struct._GUID, align 4 - // CHECK: %s1_3 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-GUID: %s1_1 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-WRONG-GUID: %s1_1 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-GUID: %s1_2 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-WRONG-GUID: %s1_2 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-GUID: %s1_3 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-WRONG-GUID: %s1_3 = alloca %struct._GUID, align 4 - // CHECK: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8* - // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false) + // CHECK-DEFINE-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8* + // CHECK-DEFINE-WRONG-GUID: [[U1:%.+]] = bitcast %struct._GUID* %s1_1 to i8* + // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false) + // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U1]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false) GUID s1_1 = __uuidof(S1); - // CHECK: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8* - // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false) + // CHECK-DEFINE-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8* + // CHECK-DEFINE-WRONG-GUID: [[U2:%.+]] = bitcast %struct._GUID* %s1_2 to i8* + // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false) + // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U2]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false) GUID s1_2 = __uuidof(S1); - // CHECK: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8* - // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast (%struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab to i8*), i32 16, i32 4, i1 false) + // CHECK-DEFINE-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8* + // CHECK-DEFINE-WRONG-GUID: [[U3:%.+]] = bitcast %struct._GUID* %s1_3 to i8* + // CHECK-DEFINE-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 16, i32 4, i1 false) + // CHECK-DEFINE-WRONG-GUID: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[U3]], i8* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_12345678_1234_1234_1234_1234567890ab to i8*), i32 4, i32 4, i1 false) GUID s1_3 = __uuidof(s1); } +#endif void gun() { - // CHECK: %s2_1 = alloca %struct._GUID, align 4 - // CHECK: %s2_2 = alloca %struct._GUID, align 4 +#ifdef DEFINE_GUID + // CHECK-DEFINE-GUID: %s2_1 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-WRONG-GUID: %s2_1 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-GUID: %s2_2 = alloca %struct._GUID, align 4 + // CHECK-DEFINE-WRONG-GUID: %s2_2 = alloca %struct._GUID, align 4 + GUID s2_1 = __uuidof(S2); + GUID s2_2 = __uuidof(S2); +#endif // CHECK: %r = alloca %struct._GUID*, align 4 // CHECK: %p = alloca %struct._GUID*, align 4 // CHECK: %zeroiid = alloca %struct._GUID*, align 4 - GUID s2_1 = __uuidof(S2); - GUID s2_2 = __uuidof(S2); - // CHECK: store %struct._GUID* @__uuid_87654321-4321-4321-4321-ba0987654321, %struct._GUID** %r, align 4 + // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_87654321_4321_4321_4321_ba0987654321 to %struct._GUID*), %struct._GUID** %r, align 4 const GUID& r = __uuidof(S2); - // CHECK: store %struct._GUID* @__uuid_87654321-4321-4321-4321-ba0987654321, %struct._GUID** %p, align 4 + // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_87654321_4321_4321_4321_ba0987654321 to %struct._GUID*), %struct._GUID** %p, align 4 const GUID* p = &__uuidof(S2); // Special case _uuidof(0), local scope version. - // CHECK: store %struct._GUID* @__uuid_00000000-0000-0000-0000-000000000000, %struct._GUID** %zeroiid, align 4 + // CHECK: store %struct._GUID* bitcast ({ i32, i16, i16, [8 x i8] }* @_GUID_00000000_0000_0000_0000_000000000000 to %struct._GUID*), %struct._GUID** %zeroiid, align 4 const GUID& zeroiid = __uuidof(0); } diff --git a/test/CodeGenCXX/move-assignment.cpp b/test/CodeGenCXX/move-assignment.cpp new file mode 100644 index 0000000..3653eab --- /dev/null +++ b/test/CodeGenCXX/move-assignment.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -emit-llvm -std=c++11 -o - %s -triple x86_64-pc-linux-gnu | FileCheck %s + +struct A { + A &operator=(A&&); +}; + +struct B { + A a; + int i; + bool b; + char c; + long l; + float f; +}; + +void test1() { + B b1, b2; + b1 = static_cast<B&&>(b2); +} + +// CHECK-LABEL: define {{.*}} @_ZN1BaSEOS_ +// CHECK: call {{.*}} @_ZN1AaSEOS_ +// CHECK-NOT: store +// CHECK: call {{.*}}memcpy{{.*}}, i64 24 +// CHECK-NOT: store +// CHECK: ret diff --git a/test/CodeGenCXX/ms-integer-static-data-members.cpp b/test/CodeGenCXX/ms-integer-static-data-members.cpp new file mode 100644 index 0000000..00beaa6 --- /dev/null +++ b/test/CodeGenCXX/ms-integer-static-data-members.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s +// RUN: %clang_cc1 -DINLINE_INIT -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-INLINE +// RUN: %clang_cc1 -DREAL_DEFINITION -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-OUTOFLINE +// RUN: %clang_cc1 -DINLINE_INIT -DREAL_DEFINITION -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-INLINE + +struct S { + // For MS ABI, we emit a linkonce_odr definition here, even though it's really just a declaration. +#ifdef INLINE_INIT + static const int x = 5; +#else + static const int x; +#endif +}; + +const int *f() { + return &S::x; +}; + +#ifdef REAL_DEFINITION +#ifdef INLINE_INIT +const int S::x; +#else +const int S::x = 5; +#endif +#endif + + +// Inline initialization. +// CHECK-INLINE: @"\01?x@S@@2HB" = linkonce_odr constant i32 5, align 4 + +// Out-of-line initialization. +// CHECK-OUTOFLINE: @"\01?x@S@@2HB" = constant i32 5, align 4 + +// No initialization. +// CHECK: @"\01?x@S@@2HB" = external constant i32 diff --git a/test/CodeGenCXX/new-alias.cpp b/test/CodeGenCXX/new-alias.cpp new file mode 100644 index 0000000..7ddc1f9 --- /dev/null +++ b/test/CodeGenCXX/new-alias.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -std=c++11 -o - %s | FileCheck %s + +using size_t = decltype(sizeof(0)); + +extern "C" char *something(long long x) { +} + +// CHECK: @_Znwm = alias i8* (i64)* @something +void *operator new(size_t) __attribute__((alias("something"))); + +// PR16715: don't assert here. +// CHECK: call noalias i8* @_Znwm(i64 4){{$}} +int *pr16715 = new int; diff --git a/test/CodeGenCXX/new-array-init-exceptions.cpp b/test/CodeGenCXX/new-array-init-exceptions.cpp index 5d9cc9fa..5cfb757 100644 --- a/test/CodeGenCXX/new-array-init-exceptions.cpp +++ b/test/CodeGenCXX/new-array-init-exceptions.cpp @@ -7,7 +7,7 @@ struct Throws { ~Throws(); }; -// CHECK: define void @_Z7cleanupi +// CHECK-LABEL: define void @_Z7cleanupi void cleanup(int n) { // CHECK: invoke void @_ZN6ThrowsC1Ei // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD:[^ ]+]] @@ -25,7 +25,7 @@ void cleanup(int n) { } -// CHECK: define void @_Z7cleanupv +// CHECK-LABEL: define void @_Z7cleanupv void cleanup() { // CHECK: invoke void @_ZN6ThrowsC1Ei // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2:[^ ]+]] diff --git a/test/CodeGenCXX/new-array-init.cpp b/test/CodeGenCXX/new-array-init.cpp index 231df24..0e925c0 100644 --- a/test/CodeGenCXX/new-array-init.cpp +++ b/test/CodeGenCXX/new-array-init.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s -// CHECK: define void @_Z2fni +// CHECK-LABEL: define void @_Z2fni void fn(int n) { // CHECK: icmp ult i{{32|64}} %{{[^ ]+}}, 3 // CHECK: store i32 1 @@ -11,21 +11,21 @@ void fn(int n) { new int[n] { 1, 2, 3 }; } -// CHECK: define void @_Z15const_underflowv +// CHECK-LABEL: define void @_Z15const_underflowv void const_underflow() { // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3 // CHECK: call noalias i8* @_Zna{{.}}(i{{32|64}} -1) new int[2] { 1, 2, 3 }; } -// CHECK: define void @_Z11const_exactv +// CHECK-LABEL: define void @_Z11const_exactv void const_exact() { // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3 // CHECK-NOT: icmp eq i32* new int[3] { 1, 2, 3 }; } -// CHECK: define void @_Z16const_sufficientv +// CHECK-LABEL: define void @_Z16const_sufficientv void const_sufficient() { // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3 new int[4] { 1, 2, 3 }; diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp index e052390..91da77a 100644 --- a/test/CodeGenCXX/new.cpp +++ b/test/CodeGenCXX/new.cpp @@ -2,9 +2,24 @@ typedef __typeof__(sizeof(0)) size_t; +// Ensure that this declaration doesn't cause operator new to lose its +// 'noalias' attribute. +void *operator new[](size_t); + void t1() { - int* a = new int; + delete new int; + delete [] new int [3]; +} + +// CHECK: declare noalias i8* @_Znwm(i64) [[ATTR_NOBUILTIN:#[^ ]*]] +// CHECK: declare void @_ZdlPv(i8*) [[ATTR_NOBUILTIN_NOUNWIND:#[^ ]*]] +// CHECK: declare noalias i8* @_Znam(i64) [[ATTR_NOBUILTIN]] +// CHECK: declare void @_ZdaPv(i8*) [[ATTR_NOBUILTIN_NOUNWIND]] + +namespace std { + struct nothrow_t {}; } +std::nothrow_t nothrow; // Declare the reserved placement operators. void *operator new(size_t, void*) throw(); @@ -12,6 +27,13 @@ void operator delete(void*, void*) throw(); void *operator new[](size_t, void*) throw(); void operator delete[](void*, void*) throw(); +// Declare the replaceable global allocation operators. +void *operator new(size_t, const std::nothrow_t &) throw(); +void *operator new[](size_t, const std::nothrow_t &) throw(); +void operator delete(void *, const std::nothrow_t &) throw(); +void operator delete[](void *, const std::nothrow_t &) throw(); + + void t2(int* a) { int* b = new (a) int; } @@ -77,10 +99,6 @@ void t8(int n) { new U[n]; } -// noalias -// CHECK: declare noalias i8* @_Znam -void *operator new[](size_t); - void t9() { bool b; @@ -98,7 +116,7 @@ A* t10() { return new(1, 2, 3.45, 100) A; } -// CHECK: define void @_Z3t11i +// CHECK-LABEL: define void @_Z3t11i struct B { int a; }; struct Bmemptr { int Bmemptr::* memptr; int a; }; @@ -122,7 +140,7 @@ void t11(int n) { struct Empty { }; // We don't need to initialize an empty class. -// CHECK: define void @_Z3t12v +// CHECK-LABEL: define void @_Z3t12v void t12() { // CHECK: call noalias i8* @_Znam // CHECK-NOT: br @@ -136,7 +154,7 @@ void t12() { } // Zero-initialization -// CHECK: define void @_Z3t13i +// CHECK-LABEL: define void @_Z3t13i void t13(int n) { // CHECK: call noalias i8* @_Znwm // CHECK: store i32 0, i32* @@ -171,7 +189,7 @@ void f() { namespace test15 { struct A { A(); ~A(); }; - // CHECK: define void @_ZN6test155test0EPv( + // CHECK-LABEL: define void @_ZN6test155test0EPv( // CHECK: [[P:%.*]] = load i8* // CHECK-NEXT: icmp eq i8* [[P]], null // CHECK-NEXT: br i1 @@ -181,7 +199,7 @@ namespace test15 { new (p) A(); } - // CHECK: define void @_ZN6test155test1EPv( + // CHECK-LABEL: define void @_ZN6test155test1EPv( // CHECK: [[P:%.*]] = load i8** // CHECK-NEXT: icmp eq i8* [[P]], null // CHECK-NEXT: br i1 @@ -199,7 +217,7 @@ namespace test15 { // TODO: it's okay if all these size calculations get dropped. // FIXME: maybe we should try to throw on overflow? - // CHECK: define void @_ZN6test155test2EPvi( + // CHECK-LABEL: define void @_ZN6test155test2EPvi( // CHECK: [[N:%.*]] = load i32* // CHECK-NEXT: [[T0:%.*]] = sext i32 [[N]] to i64 // CHECK-NEXT: [[T1:%.*]] = icmp slt i64 [[T0]], 0 @@ -220,7 +238,7 @@ namespace test15 { } namespace PR10197 { - // CHECK: define weak_odr void @_ZN7PR101971fIiEEvv() + // CHECK-LABEL: define weak_odr void @_ZN7PR101971fIiEEvv() template<typename T> void f() { // CHECK: [[CALL:%.*]] = call noalias i8* @_Znwm @@ -235,7 +253,7 @@ namespace PR10197 { namespace PR11523 { class MyClass; typedef int MyClass::* NewTy; - // CHECK: define i64* @_ZN7PR115231fEv + // CHECK-LABEL: define i64* @_ZN7PR115231fEv // CHECK: store i64 -1 NewTy* f() { return new NewTy[2](); } } @@ -254,9 +272,69 @@ namespace PR11757 { namespace PR13380 { struct A { A() {} }; struct B : public A { int x; }; - // CHECK: define i8* @_ZN7PR133801fEv + // CHECK-LABEL: define i8* @_ZN7PR133801fEv // CHECK: call noalias i8* @_Znam( // CHECK: call void @llvm.memset.p0i8 // CHECK-NEXT: call void @_ZN7PR133801BC1Ev void* f() { return new B[2](); } } + +struct MyPlacementType {} mpt; +void *operator new(size_t, MyPlacementType); + +namespace N3664 { + struct S { S() throw(int); }; + + // CHECK-LABEL-LABEL: define void @_ZN5N36641fEv + void f() { + // CHECK: call noalias i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW:#[^ ]*]] + int *p = new int; + // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE:#[^ ]*]] + delete p; + + // CHECK: call noalias i8* @_Znam(i64 12) [[ATTR_BUILTIN_NEW]] + int *q = new int[3]; + // CHECK: call void @_ZdaPv({{.*}}) [[ATTR_BUILTIN_DELETE]] + delete [] p; + + // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}}) [[ATTR_BUILTIN_NOTHROW_NEW:#[^ ]*]] + (void) new (nothrow) S[3]; + + // CHECK: call i8* @_Znwm15MyPlacementType(i64 4){{$}} + (void) new (mpt) int; + } + + // FIXME: Can we mark this noalias? + // CHECK: declare i8* @_ZnamRKSt9nothrow_t(i64, {{.*}}) [[ATTR_NOBUILTIN_NOUNWIND]] + + // CHECK-LABEL-LABEL: define void @_ZN5N36641gEv + void g() { + // It's OK for there to be attributes here, so long as we don't have a + // 'builtin' attribute. + // CHECK: call noalias i8* @_Znwm(i64 4){{$}} + int *p = (int*)operator new(4); + // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_NOUNWIND:#[^ ]*]] + operator delete(p); + + // CHECK: call noalias i8* @_Znam(i64 12){{$}} + int *q = (int*)operator new[](12); + // CHECK: call void @_ZdaPv({{.*}}) [[ATTR_NOUNWIND]] + operator delete [](p); + + // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}}) [[ATTR_NOUNWIND]] + (void) operator new[](3, nothrow); + } +} + +// CHECK-DAG: attributes [[ATTR_NOBUILTIN]] = {{[{].*}} nobuiltin {{.*[}]}} +// CHECK-DAG: attributes [[ATTR_NOBUILTIN_NOUNWIND]] = {{[{].*}} nobuiltin nounwind {{.*[}]}} + +// CHECK: attributes [[ATTR_NOUNWIND]] = +// CHECK-NOT: builtin +// CHECK-NOT: attributes +// CHECK: nounwind +// CHECK-NOT: builtin +// CHECK: attributes + +// CHECK-DAG: attributes [[ATTR_BUILTIN_NEW]] = {{[{].*}} builtin {{.*[}]}} +// CHECK-DAG: attributes [[ATTR_BUILTIN_DELETE]] = {{[{].*}} builtin {{.*[}]}} diff --git a/test/CodeGenCXX/no-opt-volatile-memcpy.cpp b/test/CodeGenCXX/no-opt-volatile-memcpy.cpp index e542e4a..d1e2e1d 100644 --- a/test/CodeGenCXX/no-opt-volatile-memcpy.cpp +++ b/test/CodeGenCXX/no-opt-volatile-memcpy.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -O0 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s // rdar://11861085 struct s { @@ -14,7 +14,7 @@ void foo (void) { gs = gs; ls = gs; } -// CHECK: define void @_Z3foov() +// CHECK-LABEL: define void @_Z3foov() // CHECK: %[[LS:.*]] = alloca %struct.s, align 4 // CHECK-NEXT: %[[ZERO:.*]] = bitcast %struct.s* %[[LS]] to i8* // CHECK-NEXT: %[[ONE:.*]] = bitcast %struct.s* %[[LS]] to i8* @@ -34,7 +34,7 @@ void fee (void) { s = s; s.y = gs; } -// CHECK: define void @_Z3feev() +// CHECK-LABEL: define void @_Z3feev() // CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true) // CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true) @@ -46,5 +46,5 @@ d gd; void gorf(void) { gd = gd; } -// CHECK: define void @_Z4gorfv() +// CHECK-LABEL: define void @_Z4gorfv() // CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.d* @gd, i32 0, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.d* @gd, i32 0, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true) diff --git a/test/CodeGenCXX/noexcept.cpp b/test/CodeGenCXX/noexcept.cpp new file mode 100644 index 0000000..dd4cfda --- /dev/null +++ b/test/CodeGenCXX/noexcept.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions -std=c++11 | FileCheck %s + +// rdar://11904428 +// Ensure that we call __cxa_begin_catch before calling +// std::terminate in a noexcept function. +namespace test0 { + void foo(); + + struct A { + A(); + ~A(); + }; + + void test() noexcept { + A a; + foo(); + } +} +// CHECK-LABEL: define void @_ZN5test04testEv() +// CHECK: [[EXN:%.*]] = alloca i8* +// This goes to the terminate lpad. +// CHECK: invoke void @_ZN5test01AC1Ev( +// This goes to the cleanup-and-then-terminate lpad. +// CHECK: invoke void @_ZN5test03fooEv() +// Destructors don't throw by default in C++11. +// CHECK: call void @_ZN5test01AD1Ev( +// Cleanup lpad. +// CHECK: [[T0:%.*]] = landingpad +// CHECK-NEXT: catch i8* null +// CHECK-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0 +// CHECK-NEXT: store i8* [[T1]], i8** [[EXN]] +// (Calling this destructor is not technically required.) +// CHECK: call void @_ZN5test01AD1Ev( +// CHECK-NEXT: br label +// The terminate landing pad jumps in here for some reason. +// CHECK: [[T0:%.*]] = landingpad +// CHECK-NEXT: catch i8* null +// CHECK-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0 +// CHECK-NEXT: call void @__clang_call_terminate(i8* [[T1]]) +// CHECK-NEXT: unreachable +// The terminate handler chained to by the cleanup lpad. +// CHECK: [[T0:%.*]] = load i8** [[EXN]] +// CHECK-NEXT: call void @__clang_call_terminate(i8* [[T0]]) +// CHECK-NEXT: unreachable + +// CHECK-LABEL: define linkonce_odr hidden void @__clang_call_terminate( +// CHECK: call i8* @__cxa_begin_catch( +// CHECK-NEXT: call void @_ZSt9terminatev() +// CHECK-NEXT: unreachable diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp index 747ab6d..b83dd72 100644 --- a/test/CodeGenCXX/nrvo.cpp +++ b/test/CodeGenCXX/nrvo.cpp @@ -9,8 +9,8 @@ public: ~X(); }; -// CHECK: define void @_Z5test0v -// CHECK-EH: define void @_Z5test0v +// CHECK-LABEL: define void @_Z5test0v +// CHECK-EH-LABEL: define void @_Z5test0v X test0() { X x; // CHECK: call {{.*}} @_ZN1XC1Ev @@ -21,8 +21,8 @@ X test0() { return x; } -// CHECK: define void @_Z5test1b( -// CHECK-EH: define void @_Z5test1b( +// CHECK-LABEL: define void @_Z5test1b( +// CHECK-EH-LABEL: define void @_Z5test1b( X test1(bool B) { // CHECK: tail call {{.*}} @_ZN1XC1Ev // CHECK-NEXT: ret void @@ -34,8 +34,8 @@ X test1(bool B) { // CHECK-EH-NEXT: ret void } -// CHECK: define void @_Z5test2b -// CHECK-EH: define void @_Z5test2b +// CHECK-LABEL: define void @_Z5test2b +// CHECK-EH-LABEL: define void @_Z5test2b X test2(bool B) { // No NRVO. @@ -120,7 +120,7 @@ X test3(bool B) { extern "C" void exit(int) throw(); -// CHECK: define void @_Z5test4b +// CHECK-LABEL: define void @_Z5test4b X test4(bool B) { { // CHECK: tail call {{.*}} @_ZN1XC1Ev @@ -135,7 +135,7 @@ X test4(bool B) { } #ifdef __EXCEPTIONS -// CHECK-EH: define void @_Z5test5 +// CHECK-EH-LABEL: define void @_Z5test5 void may_throw(); X test5() { try { @@ -150,7 +150,7 @@ X test5() { #endif // rdar://problem/10430868 -// CHECK: define void @_Z5test6v +// CHECK-LABEL: define void @_Z5test6v X test6() { X a __attribute__((aligned(8))); return a; diff --git a/test/CodeGenCXX/override-layout.cpp b/test/CodeGenCXX/override-layout.cpp index aba4c91..418c4ff 100644 --- a/test/CodeGenCXX/override-layout.cpp +++ b/test/CodeGenCXX/override-layout.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fdump-record-layouts-simple %s 2> %t.layouts -// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before 2>&1 -// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1 +// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.layouts +// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before +// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after // RUN: diff -u %t.before %t.after // RUN: FileCheck %s < %t.after diff --git a/test/CodeGenCXX/partial-destruction.cpp b/test/CodeGenCXX/partial-destruction.cpp index f232a15..22daebe 100644 --- a/test/CodeGenCXX/partial-destruction.cpp +++ b/test/CodeGenCXX/partial-destruction.cpp @@ -11,7 +11,7 @@ namespace test0 { A as[10] = { 5, 7 }; opaque(); } - // CHECK: define void @_ZN5test04testEv() + // CHECK-LABEL: define void @_ZN5test04testEv() // CHECK: [[AS:%.*]] = alloca [10 x [[A:%.*]]], align // CHECK-NEXT: [[ENDVAR:%.*]] = alloca [[A]]* // CHECK-NEXT: [[EXN:%.*]] = alloca i8* @@ -98,7 +98,7 @@ namespace test1 { void test() { B v = { 5, 6, 7, 8 }; } - // CHECK: define void @_ZN5test14testEv() + // CHECK-LABEL: define void @_ZN5test14testEv() // CHECK: [[V:%.*]] = alloca [[B:%.*]], align 4 // CHECK-NEXT: alloca i8* // CHECK-NEXT: alloca i32 @@ -128,7 +128,7 @@ namespace test2 { void test() { A v[4][7]; - // CHECK: define void @_ZN5test24testEv() + // CHECK-LABEL: define void @_ZN5test24testEv() // CHECK: [[V:%.*]] = alloca [4 x [7 x [[A:%.*]]]], align 1 // CHECK-NEXT: alloca i8* // CHECK-NEXT: alloca i32 diff --git a/test/CodeGenCXX/pod-member-memcpys.cpp b/test/CodeGenCXX/pod-member-memcpys.cpp index 534d5d1..5c79568 100644 --- a/test/CodeGenCXX/pod-member-memcpys.cpp +++ b/test/CodeGenCXX/pod-member-memcpys.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++03 -fexceptions -fcxx-exceptions -O1 -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -std=c++03 -O0 -o - %s | FileCheck --check-prefix=CHECK-2 %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++03 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -std=c++03 -o - %s | FileCheck --check-prefix=CHECK-2 %s struct POD { int w, x, y, z; @@ -108,61 +108,61 @@ CALL_AO(InnerClassMember) CALL_AO(PackedMembers) // Basic copy-assignment: -// CHECK: define linkonce_odr %struct.Basic* @_ZN5BasicaSERKS_(%struct.Basic* %this, %struct.Basic*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: ret %struct.Basic* %this +// CHECK-LABEL: define linkonce_odr %struct.Basic* @_ZN5BasicaSERKS_(%struct.Basic* %this, %struct.Basic*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: ret %struct.Basic* // PODMember copy-assignment: -// CHECK: define linkonce_odr %struct.PODMember* @_ZN9PODMemberaSERKS_(%struct.PODMember* %this, %struct.PODMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: ret %struct.PODMember* %this +// CHECK-LABEL: define linkonce_odr %struct.PODMember* @_ZN9PODMemberaSERKS_(%struct.PODMember* %this, %struct.PODMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: ret %struct.PODMember* // PODLikeMember copy-assignment: -// CHECK: define linkonce_odr %struct.PODLikeMember* @_ZN13PODLikeMemberaSERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: ret %struct.PODLikeMember* %this +// CHECK-LABEL: define linkonce_odr %struct.PODLikeMember* @_ZN13PODLikeMemberaSERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: ret %struct.PODLikeMember* // ArrayMember copy-assignment: -// CHECK: define linkonce_odr %struct.ArrayMember* @_ZN11ArrayMemberaSERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) -// CHECK: ret %struct.ArrayMember* %this +// CHECK-LABEL: define linkonce_odr %struct.ArrayMember* @_ZN11ArrayMemberaSERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) +// CHECK: ret %struct.ArrayMember* // VolatileMember copy-assignment: -// CHECK: define linkonce_odr %struct.VolatileMember* @_ZN14VolatileMemberaSERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK-LABEL: define linkonce_odr %struct.VolatileMember* @_ZN14VolatileMemberaSERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) // CHECK: load volatile i32* {{.*}}, align 4 // CHECK: store volatile i32 {{.*}}, align 4 -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: ret %struct.VolatileMember* %this +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: ret %struct.VolatileMember* // BitfieldMember copy-assignment: -// CHECK: define linkonce_odr %struct.BitfieldMember* @_ZN14BitfieldMemberaSERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}}) -// CHECK: ret %struct.BitfieldMember* %this +// CHECK-LABEL: define linkonce_odr %struct.BitfieldMember* @_ZN14BitfieldMemberaSERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}}) +// CHECK: ret %struct.BitfieldMember* // InnerClass copy-assignment: -// CHECK: define linkonce_odr %struct.InnerClassMember* @_ZN16InnerClassMemberaSERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: ret %struct.InnerClassMember* %this +// CHECK-LABEL: define linkonce_odr %struct.InnerClassMember* @_ZN16InnerClassMemberaSERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: ret %struct.InnerClassMember* // PackedMembers copy-assignment: -// CHECK: define linkonce_odr %struct.PackedMembers* @_ZN13PackedMembersaSERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*) -// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}}) -// CHECK: ret %struct.PackedMembers* %this +// CHECK-LABEL: define linkonce_odr %struct.PackedMembers* @_ZN13PackedMembersaSERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*) +// CHECK: call %struct.NonPOD* @_ZN6NonPODaSERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}}) +// CHECK: ret %struct.PackedMembers* // COPY-CONSTRUCTORS: @@ -184,73 +184,73 @@ CALL_CC(PODMember) CALL_CC(Basic) // Basic copy-constructor: -// CHECK: define linkonce_odr void @_ZN5BasicC2ERKS_(%struct.Basic* %this, %struct.Basic*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN5BasicC2ERKS_(%struct.Basic* %this, %struct.Basic*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) // CHECK: ret void // PODMember copy-constructor: -// CHECK: define linkonce_odr void @_ZN9PODMemberC2ERKS_(%struct.PODMember* %this, %struct.PODMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN9PODMemberC2ERKS_(%struct.PODMember* %this, %struct.PODMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) // CHECK: ret void // PODLikeMember copy-constructor: -// CHECK: define linkonce_odr void @_ZN13PODLikeMemberC2ERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN13PODLikeMemberC2ERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) // CHECK: invoke void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) // CHECK: ret void // CHECK: landingpad // CHECK: invoke void @_ZN7PODLikeD1Ev // ArrayMember copy-constructor: -// CHECK: define linkonce_odr void @_ZN11ArrayMemberC2ERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN11ArrayMemberC2ERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}}) // CHECK: ret void // VolatileMember copy-constructor: -// CHECK: define linkonce_odr void @_ZN14VolatileMemberC2ERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN14VolatileMemberC2ERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) // CHECK: load volatile i32* {{.*}}, align 4 // CHECK: store volatile i32 {{.*}}, align 4 -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) // CHECK: ret void // BitfieldMember copy-constructor: -// CHECK: define linkonce_odr void @_ZN14BitfieldMemberC2ERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN14BitfieldMemberC2ERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}}) // CHECK: ret void // InnerClass copy-constructor: -// CHECK: define linkonce_odr void @_ZN16InnerClassMemberC2ERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN16InnerClassMemberC2ERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}}) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}}) // CHECK: ret void // ReferenceMember copy-constructor: -// CHECK: define linkonce_odr void @_ZN15ReferenceMemberC2ERKS_(%struct.ReferenceMember* %this, %struct.ReferenceMember*) -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}}) -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN15ReferenceMemberC2ERKS_(%struct.ReferenceMember* %this, %struct.ReferenceMember*) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}}) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}}) // CHECK: ret void // BitfieldMember2 copy-constructor: -// CHECK-2: define linkonce_odr void @_ZN15BitfieldMember2C2ERKS_(%struct.BitfieldMember2* %this, %struct.BitfieldMember2*) +// CHECK-2-LABEL: define linkonce_odr void @_ZN15BitfieldMember2C2ERKS_(%struct.BitfieldMember2* %this, %struct.BitfieldMember2*) // CHECK-2: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4, i1 false) // CHECK-2: call void @_ZN6NonPODC1ERKS_ // CHECK-2: ret void // PackedMembers copy-assignment: -// CHECK: define linkonce_odr void @_ZN13PackedMembersC2ERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*) -// CHECK: tail call void @_ZN6NonPODC1ERKS_ -// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}}) +// CHECK-LABEL: define linkonce_odr void @_ZN13PackedMembersC2ERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*) +// CHECK: call void @_ZN6NonPODC1ERKS_ +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}}) // CHECK: ret void diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp index 7335c97..f0199c8 100644 --- a/test/CodeGenCXX/pointers-to-data-members.cpp +++ b/test/CodeGenCXX/pointers-to-data-members.cpp @@ -124,7 +124,7 @@ struct A { A(); }; -// CHECK: define void @_ZN9ValueInit1AC2Ev(%"struct.ValueInit::A"* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN9ValueInit1AC2Ev(%"struct.ValueInit::A"* %this) unnamed_addr // CHECK: store i64 -1, i64* // CHECK: ret void A::A() : a() {} @@ -202,7 +202,7 @@ namespace BoolPtrToMember { bool member; }; - // CHECK: define i8* @_ZN15BoolPtrToMember1fERNS_1XEMS0_b + // CHECK-LABEL: define i8* @_ZN15BoolPtrToMember1fERNS_1XEMS0_b bool &f(X &x, bool X::*member) { // CHECK: {{bitcast.* to i8\*}} // CHECK-NEXT: getelementptr inbounds i8* @@ -249,7 +249,7 @@ namespace PR13097 { }; A f(); X g() { return f().*&A::x; } - // CHECK: define void @_ZN7PR130971gEv + // CHECK-LABEL: define void @_ZN7PR130971gEv // CHECK: call void @_ZN7PR130971fEv // CHECK-NOT: memcpy // CHECK: call void @_ZN7PR130971XC1ERKS0_ diff --git a/test/CodeGenCXX/pr11676.cpp b/test/CodeGenCXX/pr11676.cpp deleted file mode 100644 index 896751a..0000000 --- a/test/CodeGenCXX/pr11676.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only -// CHECK that we don't crash. - -// PR11676's example is ill-formed: -/* -union _XEvent { -}; -void ProcessEvent() { - _XEvent pluginEvent = _XEvent(); -} -*/ - -// Example from PR11665: -void f() { - union U { int field; } u = U(); - (void)U().field; -} diff --git a/test/CodeGenCXX/pr11797.cpp b/test/CodeGenCXX/pr11797.cpp index 05221ac..1098372 100644 --- a/test/CodeGenCXX/pr11797.cpp +++ b/test/CodeGenCXX/pr11797.cpp @@ -5,4 +5,4 @@ namespace std __attribute__ ((__visibility__ ("default"))) {} void foo() { } #pragma GCC visibility pop -// CHECK: define void @_Z3foov() +// CHECK-LABEL: define void @_Z3foov() diff --git a/test/CodeGenCXX/pr12251.cpp b/test/CodeGenCXX/pr12251.cpp index f3f2ec4..bb1c82d 100644 --- a/test/CodeGenCXX/pr12251.cpp +++ b/test/CodeGenCXX/pr12251.cpp @@ -4,97 +4,97 @@ bool f(bool *x) { return *x; } -// CHECK: define zeroext i1 @_Z1fPb -// CHECK: load i8* %{{.*}}, align 1, !range !0 +// CHECK-LABEL: define zeroext i1 @_Z1fPb +// CHECK: load i8* %{{[^ ]*}}, align 1, !range [[RANGE_i8_0_2:![^ ]*]] // Only enum-tests follow. Ensure that after the bool test, no further range // metadata shows up when strict enums are disabled. -// NO-STRICT-ENUMS: define zeroext i1 @_Z1fPb -// NO-STRICT-ENUMS: load i8* %{{.*}}, align 1, !range !0 +// NO-STRICT-ENUMS-LABEL: define zeroext i1 @_Z1fPb +// NO-STRICT-ENUMS: load i8* %{{[^ ]*}}, align 1, !range // NO-STRICT-ENUMS-NOT: !range enum e1 { }; e1 g1(e1 *x) { return *x; } -// CHECK: define i32 @_Z2g1P2e1 -// CHECK: load i32* %x, align 4, !range !1 +// CHECK-LABEL: define i32 @_Z2g1P2e1 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_1:![^ ]*]] enum e2 { e2_a = 0 }; e2 g2(e2 *x) { return *x; } -// CHECK: define i32 @_Z2g2P2e2 -// CHECK: load i32* %x, align 4, !range !1 +// CHECK-LABEL: define i32 @_Z2g2P2e2 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_1]] enum e3 { e3_a = 16 }; e3 g3(e3 *x) { return *x; } -// CHECK: define i32 @_Z2g3P2e3 -// CHECK: load i32* %x, align 4, !range !2 +// CHECK-LABEL: define i32 @_Z2g3P2e3 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_32:![^ ]*]] enum e4 { e4_a = -16}; e4 g4(e4 *x) { return *x; } -// CHECK: define i32 @_Z2g4P2e4 -// CHECK: load i32* %x, align 4, !range !3 +// CHECK-LABEL: define i32 @_Z2g4P2e4 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m16_16:![^ ]*]] enum e5 { e5_a = -16, e5_b = 16}; e5 g5(e5 *x) { return *x; } -// CHECK: define i32 @_Z2g5P2e5 -// CHECK: load i32* %x, align 4, !range !4 +// CHECK-LABEL: define i32 @_Z2g5P2e5 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m32_32:![^ ]*]] enum e6 { e6_a = -1 }; e6 g6(e6 *x) { return *x; } -// CHECK: define i32 @_Z2g6P2e6 -// CHECK: load i32* %x, align 4, !range !5 +// CHECK-LABEL: define i32 @_Z2g6P2e6 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m1_1:![^ ]*]] enum e7 { e7_a = -16, e7_b = 2}; e7 g7(e7 *x) { return *x; } -// CHECK: define i32 @_Z2g7P2e7 -// CHECK: load i32* %x, align 4, !range !3 +// CHECK-LABEL: define i32 @_Z2g7P2e7 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m16_16]] enum e8 { e8_a = -17}; e8 g8(e8 *x) { return *x; } -// CHECK: define i32 @_Z2g8P2e8 -// CHECK: load i32* %x, align 4, !range !4 +// CHECK-LABEL: define i32 @_Z2g8P2e8 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m32_32:![^ ]*]] enum e9 { e9_a = 17}; e9 g9(e9 *x) { return *x; } -// CHECK: define i32 @_Z2g9P2e9 -// CHECK: load i32* %x, align 4, !range !2 +// CHECK-LABEL: define i32 @_Z2g9P2e9 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_0_32]] enum e10 { e10_a = -16, e10_b = 32}; e10 g10(e10 *x) { return *x; } -// CHECK: define i32 @_Z3g10P3e10 -// CHECK: load i32* %x, align 4, !range !6 +// CHECK-LABEL: define i32 @_Z3g10P3e10 +// CHECK: load i32* %x, align 4, !range [[RANGE_i32_m64_64:![^ ]*]] enum e11 {e11_a = 4294967296 }; enum e11 g11(enum e11 *x) { return *x; } -// CHECK: define i64 @_Z3g11P3e11 -// CHECK: load i64* %x, align {{[84]}}, !range !7 +// CHECK-LABEL: define i64 @_Z3g11P3e11 +// CHECK: load i64* %x, align {{[84]}}, !range [[RANGE_i64_0_2pow33:![^ ]*]] enum e12 {e12_a = 9223372036854775808U }; enum e12 g12(enum e12 *x) { return *x; } -// CHECK: define i64 @_Z3g12P3e12 +// CHECK-LABEL: define i64 @_Z3g12P3e12 // CHECK: load i64* %x, align {{[84]}} // CHECK-NOT: range // CHECK: ret @@ -103,7 +103,7 @@ enum e13 : char {e13_a = -1 }; e13 g13(e13 *x) { return *x; } -// CHECK: define signext i8 @_Z3g13P3e13 +// CHECK-LABEL: define signext i8 @_Z3g13P3e13 // CHECK: load i8* %x, align 1 // CHECK-NOT: range // CHECK: ret @@ -112,7 +112,7 @@ enum class e14 {e14_a = 1}; e14 g14(e14 *x) { return *x; } -// CHECK: define i32 @_Z3g14P3e14 +// CHECK-LABEL: define i32 @_Z3g14P3e14 // CHECK: load i32* %x, align 4 // CHECK-NOT: range // CHECK: ret @@ -121,7 +121,7 @@ enum e15 { e15_a = 2147483648 }; e15 g15(e15 *x) { return *x; } -// CHECK: define i32 @_Z3g15P3e15 +// CHECK-LABEL: define i32 @_Z3g15P3e15 // CHECK: load i32* %x, align 4 // CHECK-NOT: range // CHECK: ret @@ -130,17 +130,17 @@ enum e16 { e16_a = -2147483648 }; e16 g16(e16 *x) { return *x; } -// CHECK: define i32 @_Z3g16P3e16 +// CHECK-LABEL: define i32 @_Z3g16P3e16 // CHECK: load i32* %x, align 4 // CHECK-NOT: range // CHECK: ret -// CHECK: !0 = metadata !{i8 0, i8 2} -// CHECK: !1 = metadata !{i32 0, i32 1} -// CHECK: !2 = metadata !{i32 0, i32 32} -// CHECK: !3 = metadata !{i32 -16, i32 16} -// CHECK: !4 = metadata !{i32 -32, i32 32} -// CHECK: !5 = metadata !{i32 -1, i32 1} -// CHECK: !6 = metadata !{i32 -64, i32 64} -// CHECK: !7 = metadata !{i64 0, i64 8589934592} +// CHECK: [[RANGE_i8_0_2]] = metadata !{i8 0, i8 2} +// CHECK: [[RANGE_i32_0_1]] = metadata !{i32 0, i32 1} +// CHECK: [[RANGE_i32_0_32]] = metadata !{i32 0, i32 32} +// CHECK: [[RANGE_i32_m16_16]] = metadata !{i32 -16, i32 16} +// CHECK: [[RANGE_i32_m32_32]] = metadata !{i32 -32, i32 32} +// CHECK: [[RANGE_i32_m1_1]] = metadata !{i32 -1, i32 1} +// CHECK: [[RANGE_i32_m64_64]] = metadata !{i32 -64, i32 64} +// CHECK: [[RANGE_i64_0_2pow33]] = metadata !{i64 0, i64 8589934592} diff --git a/test/CodeGenCXX/pr13396.cpp b/test/CodeGenCXX/pr13396.cpp index 7d4e2ce..3d582c5 100644 --- a/test/CodeGenCXX/pr13396.cpp +++ b/test/CodeGenCXX/pr13396.cpp @@ -7,13 +7,13 @@ struct foo { }; foo::foo() { - // CHECK: define void @_ZN3fooC1Ev(%struct.foo* inreg %this) - // CHECK: define void @_ZN3fooC2Ev(%struct.foo* inreg %this) + // CHECK-LABEL: define void @_ZN3fooC1Ev(%struct.foo* inreg %this) + // CHECK-LABEL: define void @_ZN3fooC2Ev(%struct.foo* inreg %this) } foo::~foo() { - // CHECK: define void @_ZN3fooD1Ev(%struct.foo* inreg %this) - // CHECK: define void @_ZN3fooD2Ev(%struct.foo* inreg %this) + // CHECK-LABEL: define void @_ZN3fooD1Ev(%struct.foo* inreg %this) + // CHECK-LABEL: define void @_ZN3fooD2Ev(%struct.foo* inreg %this) } void dummy() { @@ -21,6 +21,6 @@ void dummy() { // older clangs accept: // template foo::foo(int x); foo x(10); - // CHECK: define linkonce_odr void @_ZN3fooC1IiEET_(%struct.foo* inreg %this, i32 inreg %x) - // CHECK: define linkonce_odr void @_ZN3fooC2IiEET_(%struct.foo* inreg %this, i32 inreg %x) + // CHECK-LABEL: define linkonce_odr void @_ZN3fooC1IiEET_(%struct.foo* inreg %this, i32 inreg %x) + // CHECK-LABEL: define linkonce_odr void @_ZN3fooC2IiEET_(%struct.foo* inreg %this, i32 inreg %x) } diff --git a/test/CodeGenCXX/pr9130.cpp b/test/CodeGenCXX/pr9130.cpp index b28f394..e726e5a 100644 --- a/test/CodeGenCXX/pr9130.cpp +++ b/test/CodeGenCXX/pr9130.cpp @@ -11,4 +11,4 @@ class nsVorbisState : public nsOggCodecState { nsVorbisState::~nsVorbisState() { } -// CHECK: define linkonce_odr i32 @_ZN15nsOggCodecState9StartTimeEv +// CHECK-LABEL: define linkonce_odr i32 @_ZN15nsOggCodecState9StartTimeEv diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp index 0d267ff..c2d54e1 100644 --- a/test/CodeGenCXX/pr9965.cpp +++ b/test/CodeGenCXX/pr9965.cpp @@ -8,7 +8,7 @@ struct X : A // default constructor is not trivial }; X<int> x; -// CHECK: define internal void @__cxx_global_var_init() +// CHECK-LABEL: define internal void @__cxx_global_var_init() // CHECK: call {{.*}} @_ZN1XIiEC1Ev // CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC1Ev // CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC2Ev diff --git a/test/CodeGenCXX/pragma-visibility.cpp b/test/CodeGenCXX/pragma-visibility.cpp index 0640d42..c0ba904 100644 --- a/test/CodeGenCXX/pragma-visibility.cpp +++ b/test/CodeGenCXX/pragma-visibility.cpp @@ -28,8 +28,8 @@ template<> int x4<int>::y = 10; template<int x> int f() { return x; } extern "C" int g() { return f<3>(); } #pragma GCC visibility pop -// CHECK: define hidden i32 @g() -// CHECK: define linkonce_odr hidden i32 @_Z1fILi3EEiv() +// CHECK-LABEL: define hidden i32 @g() +// CHECK-LABEL: define linkonce_odr hidden i32 @_Z1fILi3EEiv() #pragma GCC visibility push(hidden) template<class T> struct x5 { @@ -37,19 +37,19 @@ template<class T> struct x5 { }; #pragma GCC visibility pop template<> void x5<int>::y() {} -// CHECK: define hidden void @_ZN2x5IiE1yEv +// CHECK-LABEL: define hidden void @_ZN2x5IiE1yEv #pragma GCC visibility push(hidden) namespace n __attribute((visibility("default"))) { void f() {} - // CHECK: define void @_ZN1n1fEv + // CHECK-LABEL: define void @_ZN1n1fEv } #pragma GCC visibility pop namespace n __attribute((visibility("default"))) { #pragma GCC visibility push(hidden) void g() {} - // CHECK: define hidden void @_ZN1n1gEv + // CHECK-LABEL: define hidden void @_ZN1n1gEv #pragma GCC visibility pop } @@ -69,6 +69,6 @@ namespace test2 { bar<foo>::f(); bar<int>::f(); } - // CHECK: define linkonce_odr hidden void @_ZN5test23barINS_3fooEE1fEv - // CHECK: define linkonce_odr void @_ZN5test23barIiE1fEv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN5test23barINS_3fooEE1fEv + // CHECK-LABEL: define linkonce_odr void @_ZN5test23barIiE1fEv } diff --git a/test/CodeGenCXX/pragma-weak.cpp b/test/CodeGenCXX/pragma-weak.cpp index ed537ff..c033079 100644 --- a/test/CodeGenCXX/pragma-weak.cpp +++ b/test/CodeGenCXX/pragma-weak.cpp @@ -10,22 +10,22 @@ int zex; #pragma weak foo struct S { void foo(); }; void S::foo() {} -// CHECK: define void @_ZN1S3fooEv( +// CHECK-LABEL: define void @_ZN1S3fooEv( #pragma weak zed namespace bar { void zed() {} } -// CHECK: define void @_ZN3bar3zedEv( +// CHECK-LABEL: define void @_ZN3bar3zedEv( #pragma weak bah void bah() {} -// CHECK: define void @_Z3bahv( +// CHECK-LABEL: define void @_Z3bahv( #pragma weak baz extern "C" void baz() {} -// CHECK: define weak void @baz( +// CHECK-LABEL: define weak void @baz( #pragma weak _Z3baxv void bax() {} // GCC produces a weak symbol for this one, but it doesn't look like a good // idea to expose the mangling to the pragma unless we really have to. -// CHECK: define void @_Z3baxv( +// CHECK-LABEL: define void @_Z3baxv( diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp index 24ead8f..9062ee0 100644 --- a/test/CodeGenCXX/predefined-expr.cpp +++ b/test/CodeGenCXX/predefined-expr.cpp @@ -9,6 +9,8 @@ // CHECK: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00" // CHECK: private unnamed_addr constant [122 x i8] c"static void ClassWithTemplateTemplateParam<char, NS::ClassTemplate>::staticMember() [T = char, Param = NS::ClassTemplate]\00" // CHECK: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00" +// CHECK: private unnamed_addr constant [51 x i8] c"void functionTemplateWithCapturedStmt(T) [T = int]\00" +// CHECK: private unnamed_addr constant [76 x i8] c"auto functionTemplateWithLambda(int)::<anonymous class>::operator()() const\00" // CHECK: private unnamed_addr constant [65 x i8] c"void functionTemplateWithUnnamedTemplateParameter(T) [T = float]\00" // CHECK: private unnamed_addr constant [60 x i8] c"void functionTemplateExplicitSpecialization(T) [T = double]\00" @@ -376,6 +378,23 @@ void functionTemplateWithUnnamedTemplateParameter(T t) } template <typename T> +void functionTemplateWithLambda(T t) +{ + []() { + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } (); +} + +template <typename T> +void functionTemplateWithCapturedStmt(T t) +{ + #pragma clang __debug captured + { + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +} + +template <typename T> class OuterClass { public: @@ -500,6 +519,9 @@ int main() { functionTemplateExplicitSpecialization(0.0); functionTemplateWithUnnamedTemplateParameter<int, float>(0.0f); + functionTemplateWithLambda<int>(0); + functionTemplateWithCapturedStmt<int>(0); + OuterClass<int *>::MiddleClass::InnerClass<float> omi; omi.memberFunction(0, 0.0f); diff --git a/test/CodeGenCXX/ptr-to-member-function.cpp b/test/CodeGenCXX/ptr-to-member-function.cpp index 3989c03..914a90a 100644 --- a/test/CodeGenCXX/ptr-to-member-function.cpp +++ b/test/CodeGenCXX/ptr-to-member-function.cpp @@ -1,8 +1,8 @@ // REQUIRES: x86-registered-target,x86-64-registered-target // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s -// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s // RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s -// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// RUN: FileCheck -check-prefix CHECK-LP32 --input-file=%t-32.s %s // 13.3.3.2 Ranking implicit conversion sequences extern "C" int printf(...); diff --git a/test/CodeGenCXX/reference-cast.cpp b/test/CodeGenCXX/reference-cast.cpp index f157ae9..60ea393 100644 --- a/test/CodeGenCXX/reference-cast.cpp +++ b/test/CodeGenCXX/reference-cast.cpp @@ -15,7 +15,7 @@ const int &lvalue_noop_cast() { return 17; } -// CHECK: define i16* @_Z20lvalue_integral_castv() +// CHECK-LABEL: define i16* @_Z20lvalue_integral_castv() const short &lvalue_integral_cast() { if (i == 0) // CHECK: store i16 17, i16* @@ -27,7 +27,7 @@ const short &lvalue_integral_cast() { return 17; } -// CHECK: define i16* @_Z29lvalue_floating_integral_castv() +// CHECK-LABEL: define i16* @_Z29lvalue_floating_integral_castv() const short &lvalue_floating_integral_cast() { if (i == 0) // CHECK: store i16 17, i16* @@ -39,7 +39,7 @@ const short &lvalue_floating_integral_cast() { return 17.5; } -// CHECK: define float* @_Z29lvalue_integral_floating_castv() +// CHECK-LABEL: define float* @_Z29lvalue_integral_floating_castv() const float &lvalue_integral_floating_cast() { if (i == 0) // CHECK: store float 1.700000e+{{0*}}1, float* @@ -51,7 +51,7 @@ const float &lvalue_integral_floating_cast() { return 17; } -// CHECK: define float* @_Z20lvalue_floating_castv() +// CHECK-LABEL: define float* @_Z20lvalue_floating_castv() const float &lvalue_floating_cast() { if (i == 0) // CHECK: store float 1.700000e+{{0*}}1, float* @@ -65,7 +65,7 @@ const float &lvalue_floating_cast() { int get_int(); -// CHECK: define i8* @_Z24lvalue_integer_bool_castv() +// CHECK-LABEL: define i8* @_Z24lvalue_integer_bool_castv() const bool &lvalue_integer_bool_cast() { if (i == 0) // CHECK: call i32 @_Z7get_intv() @@ -82,7 +82,7 @@ const bool &lvalue_integer_bool_cast() { float get_float(); -// CHECK: define i8* @_Z25lvalue_floating_bool_castv() +// CHECK-LABEL: define i8* @_Z25lvalue_floating_bool_castv() const bool &lvalue_floating_bool_cast() { if (i == 0) // CHECK: call float @_Z9get_floatv() @@ -107,7 +107,7 @@ typedef int (X::*pmf)(int); pm get_pointer_to_member_data(); pmf get_pointer_to_member_function(); -// CHECK: define i8* @_Z26lvalue_ptrmem_to_bool_castv() +// CHECK-LABEL: define i8* @_Z26lvalue_ptrmem_to_bool_castv() const bool &lvalue_ptrmem_to_bool_cast() { if (i == 0) // CHECK: call i64 @_Z26get_pointer_to_member_datav() @@ -125,7 +125,7 @@ const bool &lvalue_ptrmem_to_bool_cast() { return get_pointer_to_member_data(); } -// CHECK: define i8* @_Z27lvalue_ptrmem_to_bool_cast2v +// CHECK-LABEL: define i8* @_Z27lvalue_ptrmem_to_bool_cast2v const bool &lvalue_ptrmem_to_bool_cast2() { if (i == 0) // CHECK: {{call.*_Z30get_pointer_to_member_functionv}} @@ -169,7 +169,7 @@ const _Complex float &f1() { return get_complex_double(); } -// CHECK: define i32 @_Z7pr10592RKi(i32* +// CHECK-LABEL: define i32 @_Z7pr10592RKi(i32* unsigned pr10592(const int &v) { // CHECK: [[VADDR:%[a-zA-Z0-9.]+]] = alloca i32* // CHECK-NEXT: [[REFTMP:%[a-zA-Z0-9.]+]] = alloca i32 @@ -189,7 +189,7 @@ namespace PR10650 { unsigned long long test(Helper *obj) { return static_cast<const unsigned long long&>(obj->id()); } - // CHECK: define i64 @_ZN7PR106504testEPNS_6HelperE + // CHECK-LABEL: define i64 @_ZN7PR106504testEPNS_6HelperE // CHECK: store i64 } diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index df5a336..ec7a3d5 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s +// RUN: not %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s void t1() { - // CHECK: define void @_Z2t1v + // CHECK-LABEL: define void @_Z2t1v // CHECK: [[REFLOAD:%.*]] = load i32** @a, align 8 // CHECK: load i32* [[REFLOAD]], align 4 extern int& a; @@ -8,7 +8,7 @@ void t1() { } void t2(int& a) { - // CHECK: define void @_Z2t2Ri + // CHECK-LABEL: define void @_Z2t2Ri // CHECK: [[REFLOAD2:%.*]] = load i32** {{.*}}, align 8 // CHECK: load i32* [[REFLOAD2]], align 4 int b = a; @@ -189,7 +189,7 @@ namespace N2 { P getP(); - // CHECK: define void @_ZN2N21fEi + // CHECK-LABEL: define void @_ZN2N21fEi // CHECK: call void @_ZN2N24getPEv // CHECK: getelementptr inbounds // CHECK: store i32 17 @@ -218,7 +218,7 @@ namespace N2 { Z getZ(); - // CHECK: define void @_ZN2N21gEi + // CHECK-LABEL: define void @_ZN2N21gEi // CHECK: call void @_ZN2N24getZEv // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} @@ -240,7 +240,7 @@ struct A { ~A(); }; -// CHECK: define internal void @__cxx_global_var_init +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: call void @_ZN2N31AC1Ei(%"struct.N3::A"* @_ZGRN2N35sA123E, i32 123) // CHECK: call i32 @__cxa_atexit // CHECK: ret void @@ -255,7 +255,7 @@ struct A { }; void f() { - // CHECK: define void @_ZN2N41fEv + // CHECK-LABEL: define void @_ZN2N41fEv // CHECK: call void @_ZN2N41AC1Ev(%"struct.N4::A"* @_ZGRZN2N41fEvE2ar) // CHECK: call i32 @__cxa_atexit // CHECK: ret void @@ -279,7 +279,7 @@ void h() { // PR9565 namespace PR9565 { struct a { int a : 10, b : 10; }; - // CHECK: define void @_ZN6PR95651fEv() + // CHECK-LABEL: define void @_ZN6PR95651fEv() void f() { // CHECK: call void @llvm.memcpy a x = { 0, 0 }; @@ -306,7 +306,7 @@ namespace PR9565 { namespace N6 { extern struct x {char& x;}y; int a() { return y.x; } - // CHECK: define i32 @_ZN2N61aEv + // CHECK-LABEL: define i32 @_ZN2N61aEv // CHECK: [[REFLOAD3:%.*]] = load i8** getelementptr inbounds (%"struct.N6::x"* @_ZN2N61yE, i32 0, i32 0), align 8 // CHECK: load i8* [[REFLOAD3]], align 1 } diff --git a/test/CodeGenCXX/return.cpp b/test/CodeGenCXX/return.cpp index 43d40ae..1975055 100644 --- a/test/CodeGenCXX/return.cpp +++ b/test/CodeGenCXX/return.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -emit-llvm -O -o - %s | FileCheck %s --check-prefix=CHECK-OPT // CHECK: @_Z9no_return diff --git a/test/CodeGenCXX/rtti-layout.cpp b/test/CodeGenCXX/rtti-layout.cpp index 7128c4e..0db2577 100644 --- a/test/CodeGenCXX/rtti-layout.cpp +++ b/test/CodeGenCXX/rtti-layout.cpp @@ -101,7 +101,7 @@ struct B { static int (B::*d)[10]; }; -// CHECK: define i32 @_Z1fv() +// CHECK-LABEL: define i32 @_Z1fv() int f() { // Vectors should be treated as fundamental types. typedef short __v4hi __attribute__ ((__vector_size__ (8))); diff --git a/test/CodeGenCXX/runtimecc.cpp b/test/CodeGenCXX/runtimecc.cpp index 66d3f41..646c61e 100644 --- a/test/CodeGenCXX/runtimecc.cpp +++ b/test/CodeGenCXX/runtimecc.cpp @@ -20,7 +20,7 @@ namespace test0 { }; A global; -// CHECK: define internal arm_aapcscc void @__cxx_global_var_init() +// CHECK-LABEL: define internal arm_aapcscc void @__cxx_global_var_init() // CHECK: call arm_aapcscc [[A]]* @_ZN5test01AC1Ev([[A]]* @_ZN5test06globalE) // CHECK-NEXT: call arm_aapcscc i32 @__cxa_atexit(void (i8*)* bitcast ([[A]]* ([[A]]*)* @_ZN5test01AD1Ev to void (i8*)*), i8* bitcast ([[A]]* @_ZN5test06globalE to i8*), i8* @__dso_handle) [[NOUNWIND:#[0-9]+]] // CHECK-NEXT: ret void @@ -33,7 +33,7 @@ namespace test1 { throw 0; } -// CHECK: define arm_aapcscc void @_ZN5test14testEv() +// CHECK-LABEL: define arm_aapcscc void @_ZN5test14testEv() // CHECK: [[T0:%.*]] = call arm_aapcscc i8* @__cxa_allocate_exception(i32 4) [[NOUNWIND]] // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32* // CHECK-NEXT: store i32 0, i32* [[T1]] @@ -45,7 +45,7 @@ namespace test1 { // CHECK: declare arm_aapcscc void @__cxa_throw(i8*, i8*, i8*) -// CHECK: define internal arm_aapcscc void @_GLOBAL__I_a() +// CHECK-LABEL: define internal arm_aapcscc void @_GLOBAL__I_a() // CHECK: call arm_aapcscc void @__cxx_global_var_init() diff --git a/test/CodeGenCXX/rvalue-references.cpp b/test/CodeGenCXX/rvalue-references.cpp index b8d47dc..2e0fa82 100644 --- a/test/CodeGenCXX/rvalue-references.cpp +++ b/test/CodeGenCXX/rvalue-references.cpp @@ -7,7 +7,7 @@ struct B : Spacer, A { }; B &getB(); -// CHECK: define %struct.A* @_Z4getAv() +// CHECK-LABEL: define %struct.A* @_Z4getAv() // CHECK: call %struct.B* @_Z4getBv() // CHECK-NEXT: bitcast %struct.B* // CHECK-NEXT: getelementptr inbounds i8* @@ -19,17 +19,17 @@ int &getIntLValue(); int &&getIntXValue(); int getIntPRValue(); -// CHECK: define i32* @_Z2f0v() +// CHECK-LABEL: define i32* @_Z2f0v() // CHECK: call i32* @_Z12getIntLValuev() // CHECK-NEXT: ret i32* int &&f0() { return static_cast<int&&>(getIntLValue()); } -// CHECK: define i32* @_Z2f1v() +// CHECK-LABEL: define i32* @_Z2f1v() // CHECK: call i32* @_Z12getIntXValuev() // CHECK-NEXT: ret i32* int &&f1() { return static_cast<int&&>(getIntXValue()); } -// CHECK: define i32* @_Z2f2v +// CHECK-LABEL: define i32* @_Z2f2v // CHECK: call i32 @_Z13getIntPRValuev() // CHECK-NEXT: store i32 {{.*}}, i32* // CHECK-NEXT: ret i32* @@ -59,7 +59,7 @@ public: C test(); -// CHECK: define void @_Z15elide_copy_initv +// CHECK-LABEL: define void @_Z15elide_copy_initv void elide_copy_init() { ok = false; // CHECK: call void @_Z4testv @@ -68,7 +68,7 @@ void elide_copy_init() { // CHECK-NEXT: ret void } -// CHECK: define void @_Z16test_move_returnv +// CHECK-LABEL: define void @_Z16test_move_returnv C test_move_return() { // CHECK: call void @_ZN1CC1Ei C a1(3); @@ -94,7 +94,7 @@ namespace test1 { B(int i); }; - // CHECK: define void @_ZN5test11BC2Ei( + // CHECK-LABEL: define void @_ZN5test11BC2Ei( // CHECK: [[T0:%.*]] = call i32* @_ZN5test14moveERi( // CHECK-NEXT: [[T1:%.*]] = load i32* [[T0]] // CHECK-NEXT: call void @_ZN5test11AC1Ei({{.*}}, i32 [[T1]]) diff --git a/test/CodeGenCXX/scoped-enums.cpp b/test/CodeGenCXX/scoped-enums.cpp index c20faaa..159172d 100644 --- a/test/CodeGenCXX/scoped-enums.cpp +++ b/test/CodeGenCXX/scoped-enums.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s // PR9923 enum class Color { red, blue, green }; @@ -15,3 +15,10 @@ void h(Colour); void i() { h(Colour::grey); } + +enum struct PR17103 : int { a = -1, b = 1 }; +bool cmp(PR17103 x, PR17103 y) { return x < y; } + +// CHECK-LABEL: @_Z3cmp7PR17103S_( +// CHECK-NOT: } +// CHECK: icmp slt diff --git a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp index 84697be..29926b9 100644 --- a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp +++ b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp @@ -10,7 +10,7 @@ struct A { ~A(); }; -// CHECK: define void @_ZN5Test11AD2Ev +// CHECK-LABEL: define void @_ZN5Test11AD2Ev // CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test11AE, i64 0, i64 2), i8*** A::~A() { @@ -26,7 +26,7 @@ struct A { ~A(); }; -// CHECK: define void @_ZN5Test21AD2Ev +// CHECK-LABEL: define void @_ZN5Test21AD2Ev // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test21AE, i64 0, i64 2), i8*** A::~A() { f(); @@ -49,7 +49,7 @@ struct A { Field field; }; -// CHECK: define void @_ZN5Test31AD2Ev +// CHECK-LABEL: define void @_ZN5Test31AD2Ev // CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test31AE, i64 0, i64 2), i8*** A::~A() { @@ -75,7 +75,7 @@ struct A { Field field; }; -// CHECK: define void @_ZN5Test41AD2Ev +// CHECK-LABEL: define void @_ZN5Test41AD2Ev // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test41AE, i64 0, i64 2), i8*** A::~A() { @@ -99,7 +99,7 @@ struct A { Field field; }; -// CHECK: define void @_ZN5Test51AD2Ev +// CHECK-LABEL: define void @_ZN5Test51AD2Ev // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test51AE, i64 0, i64 2), i8*** A::~A() { @@ -127,7 +127,7 @@ struct A { Field field; }; -// CHECK: define void @_ZN5Test61AD2Ev +// CHECK-LABEL: define void @_ZN5Test61AD2Ev // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test61AE, i64 0, i64 2), i8*** A::~A() { @@ -153,7 +153,7 @@ struct A { Field field; }; -// CHECK: define void @_ZN5Test71AD2Ev +// CHECK-LABEL: define void @_ZN5Test71AD2Ev // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test71AE, i64 0, i64 2), i8*** A::~A() { @@ -179,7 +179,7 @@ struct A { Field field; }; -// CHECK: define void @_ZN5Test81AD2Ev +// CHECK-LABEL: define void @_ZN5Test81AD2Ev // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test81AE, i64 0, i64 2), i8*** A::~A() { diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp index 4ad339d..eea9794 100644 --- a/test/CodeGenCXX/static-data-member.cpp +++ b/test/CodeGenCXX/static-data-member.cpp @@ -42,7 +42,7 @@ namespace test2 { template struct A<int>; } - // CHECK: define internal void @__cxx_global_var_init() + // CHECK-LABEL: define internal void @__cxx_global_var_init() // CHECK: [[TMP:%.*]] = call i32 @_ZN5test23fooEv() // CHECK-NEXT: store i32 [[TMP]], i32* @_ZN5test212_GLOBAL__N_11AIiE1xE, align 4 // CHECK-NEXT: ret void @@ -60,7 +60,7 @@ namespace test3 { template <class T> int A<T>::x = foo(); template struct A<int>; - // CHECK: define internal void @__cxx_global_var_init1() + // CHECK-LABEL: define internal void @__cxx_global_var_init1() // CHECK: [[GUARDBYTE:%.*]] = load i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*) // CHECK-NEXT: [[UNINITIALIZED:%.*]] = icmp eq i8 [[GUARDBYTE]], 0 // CHECK-NEXT: br i1 [[UNINITIALIZED]] @@ -79,7 +79,7 @@ namespace test4 { }; int f(A *a) { - // CHECK: define i32 @_ZN5test41fEPNS_1AE + // CHECK-LABEL: define i32 @_ZN5test41fEPNS_1AE // CHECK: ret i32 76 return a->n; } diff --git a/test/CodeGenCXX/static-init-1.cpp b/test/CodeGenCXX/static-init-1.cpp index a926c0a..09bf7bf 100644 --- a/test/CodeGenCXX/static-init-1.cpp +++ b/test/CodeGenCXX/static-init-1.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t -// RUN: grep "call i32 @_Z5func1i" %t | count 3 +// RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-llvm %s -o - | FileCheck %s extern "C" int printf(...); @@ -9,15 +8,18 @@ int func2(int c) { return printf("loading the func2(%d)\n", c); }; int func1(int c) { return printf("loading the func1(%d)\n", c); } static int loader_1 = func1(++count); +// CHECK: call i32 @_Z5func1i int loader_2 = func2(++count); static int loader_3 = func1(++count); - +// CHECK: call i32 @_Z5func1i int main() {} int loader_4 = func2(++count); static int loader_5 = func1(++count); int loader_6 = func2(++count); +// CHECK: call i32 @_Z5func1i +// CHECK-NOT: call i32 @_Z5func1i diff --git a/test/CodeGenCXX/static-init-4.cpp b/test/CodeGenCXX/static-init-4.cpp new file mode 100644 index 0000000..a4bb987 --- /dev/null +++ b/test/CodeGenCXX/static-init-4.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s -triple x86_64-linux-gnu | FileCheck %s + +typedef __attribute__((vector_size(4*4))) float float32x4_t; +union QDSUnion { float32x4_t q; float s[4]; }; +constexpr float32x4_t a = {1,2,3,4}; +QDSUnion t = {{(a)}}; +// CHECK: @t = global %union.QDSUnion { <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00> } diff --git a/test/CodeGenCXX/static-init-pnacl.cpp b/test/CodeGenCXX/static-init-pnacl.cpp new file mode 100644 index 0000000..de35ec3 --- /dev/null +++ b/test/CodeGenCXX/static-init-pnacl.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-llvm -triple=le32-unknown-nacl -o - %s | FileCheck %s + +int f(); + +// Test that PNaCl uses the Itanium/x86 ABI in which the static +// variable's guard variable is tested via "load i8 and compare with +// zero" rather than the ARM ABI which uses "load i32 and test the +// bottom bit". +void g() { + static int a = f(); +} +// CHECK: [[LOAD:%.*]] = load atomic i8* bitcast (i64* @_ZGVZ1gvE1a to i8*) acquire +// CHECK-NEXT: [[GUARD:%.*]] = icmp eq i8 [[LOAD]], 0 +// CHECK-NEXT: br i1 [[GUARD]] diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp index 74278f7..f522775 100644 --- a/test/CodeGenCXX/static-init.cpp +++ b/test/CodeGenCXX/static-init.cpp @@ -54,7 +54,7 @@ namespace test0 { } namespace test1 { - // CHECK: define internal i32 @_ZN5test1L6getvarEi( + // CHECK-LABEL: define internal i32 @_ZN5test1L6getvarEi( static inline int getvar(int index) { static const int var[] = { 1, 0, 2, 4 }; return var[index]; @@ -68,7 +68,7 @@ char base_req[] = { "foo" }; unsigned char base_req_uchar[] = { "bar" }; namespace union_static_local { - // CHECK: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv + // CHECK-LABEL: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv // CHECK: call void @_ZN18union_static_local1fEPNS_1xE(%"union.union_static_local::x"* bitcast ({ [2 x i8*] }* @_ZZN18union_static_local4testEvE3foo to %"union.union_static_local::x"*)) union x { long double y; const char *x[2]; }; void f(union x*); @@ -103,14 +103,14 @@ namespace test2 { B::B() { static int x = foo(); } - // CHECK: define void @_ZN5test21BC1Ev + // CHECK-LABEL: define void @_ZN5test21BC1Ev // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x, // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x) - // CHECK: define void @_ZN5test21BC2Ev + // CHECK-LABEL: define void @_ZN5test21BC2Ev // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() @@ -122,10 +122,10 @@ namespace test2 { B::~B() { static int y = foo(); } - // CHECK: define void @_ZN5test21BD1Ev( + // CHECK-LABEL: define void @_ZN5test21BD1Ev( // CHECK: call void @_ZN5test21BD2Ev( - // CHECK: define void @_ZN5test21BD2Ev( + // CHECK-LABEL: define void @_ZN5test21BD2Ev( // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BD1EvE1y to i8*) acquire, // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BD1EvE1y) // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() @@ -149,6 +149,6 @@ namespace test3 { union U { char x; int i; }; static U u = { 'a' }; } - // CHECK: define void @_ZN5test31BC1Ev( - // CHECK: define void @_ZN5test31BC2Ev( + // CHECK-LABEL: define void @_ZN5test31BC1Ev( + // CHECK-LABEL: define void @_ZN5test31BC2Ev( } diff --git a/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp index 94fd9aa..50772bf 100644 --- a/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp +++ b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp @@ -1,6 +1,10 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s // CHECK: ; ModuleID -template<typename> struct A { static int a; }; + +extern "C" int foo(); + +template<typename T> struct A { static int a; }; +template<typename T> int A<T>::a = foo(); // CHECK-NOT: @_ZN1AIcE1aE template<> int A<char>::a; @@ -8,4 +12,85 @@ template<> int A<char>::a; // CHECK: @_ZN1AIbE1aE = global i32 10 template<> int A<bool>::a = 10; +// CHECK: @llvm.global_ctors = appending global [7 x { i32, void ()* }] +// CHECK: [{ i32, void ()* } { i32 65535, void ()* @[[unordered1:[^ ]*]] }, +// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered2:[^ ]*]] }, +// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered3:[^ ]*]] }, +// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered4:[^ ]*]] }, +// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered5:[^ ]*]] }, +// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered6:[^ ]*]] }, +// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] + +template int A<short>::a; // Unordered +int b = foo(); +int c = foo(); +int d = A<void>::a; // Unordered + +// An explicit specialization is ordered, and goes in __GLOBAL_I_a. +template<> struct A<int> { static int a; }; +int A<int>::a = foo(); + +template<typename T> struct S { static T x; static T y; }; +template<> int S<int>::x = foo(); +template<> int S<int>::y = S<int>::x; + +template<typename T> T x = foo(); +template short x<short>; // Unordered +template<> int x<int> = foo(); +int e = x<char>; // Unordered + +namespace ns { +template <typename T> struct a { + static int i; +}; +template<typename T> int a<T>::i = foo(); +template struct a<int>; + +struct b { + template <typename T> static T i; +}; +template<typename T> T b::i = foo(); +template int b::i<int>; +} +// CHECK: define internal void @[[unordered1]] +// CHECK: call i32 @foo() +// CHECK: store {{.*}} @_ZN1AIsE1aE +// CHECK: ret + +// CHECK: define internal void @[[unordered2]] +// CHECK: call i32 @foo() +// CHECK: store {{.*}} @_Z1xIsE +// CHECK: ret + +// CHECK: define internal void @[[unordered3]] +// CHECK: call i32 @foo() +// CHECK: store {{.*}} @_ZN2ns1aIiE1iE +// CHECK: ret + +// CHECK: define internal void @[[unordered4]] +// CHECK: call i32 @foo() +// CHECK: store {{.*}} @_ZN2ns1b1iIiEE +// CHECK: ret + +// CHECK: define internal void @[[unordered5]] +// CHECK: call i32 @foo() +// CHECK: store {{.*}} @_ZN1AIvE1aE +// CHECK: ret + +// CHECK: define internal void @[[unordered6]] +// CHECK: call i32 @foo() +// CHECK: store {{.*}} @_Z1xIcE +// CHECK: ret +// CHECK: define internal void @_GLOBAL__I_a() +// We call unique stubs for every ordered dynamic initializer in the TU. +// CHECK: call +// CHECK: call +// CHECK: call +// CHECK: call +// CHECK: call +// CHECK: call +// CHECK: call +// CHECK: call +// CHECK-NOT: call +// CHECK: ret diff --git a/test/CodeGenCXX/stmtexpr.cpp b/test/CodeGenCXX/stmtexpr.cpp index 1f0e4ac..5d4d6bc 100644 --- a/test/CodeGenCXX/stmtexpr.cpp +++ b/test/CodeGenCXX/stmtexpr.cpp @@ -73,3 +73,10 @@ int* foo5() { return (({ a; })); } +// <rdar://problem/14074868> +// Make sure this doesn't crash. +int foo5(bool b) { + int y = 0; + y = ({ A a(1); if (b) goto G; a.i; }); + G: return y; +} diff --git a/test/CodeGenCXX/template-anonymous-types.cpp b/test/CodeGenCXX/template-anonymous-types.cpp index 3df487a..f4d6549 100644 --- a/test/CodeGenCXX/template-anonymous-types.cpp +++ b/test/CodeGenCXX/template-anonymous-types.cpp @@ -19,19 +19,19 @@ template <typename T> int f(T t) { void test() { // Look for two instantiations, one for FOO's // type and one for BAR's. - // CHECK: define linkonce_odr i32 @_Z1fIN1SUt_EEiT_(i32 %t) + // CHECK-LABEL: define linkonce_odr i32 @_Z1fIN1SUt_EEiT_(i32 %t) (void)f(S::FOO); - // CHECK: define linkonce_odr i32 @_Z1fIN1SUt0_EEiT_(i32 %t) + // CHECK-LABEL: define linkonce_odr i32 @_Z1fIN1SUt0_EEiT_(i32 %t) (void)f(S::BAR); // Now check for the class template instantiations. Annoyingly, they are in // reverse order. // // BAR's instantiation of X: - // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt0_EE1fEv(%struct.X* %this) - // CHECK: define linkonce_odr void @_ZN1XIN1SUt0_EEC2ES1_(%struct.X* %this, i32 %t) unnamed_addr + // CHECK-LABEL: define linkonce_odr i32 @_ZN1XIN1SUt0_EE1fEv(%struct.X* %this) + // CHECK-LABEL: define linkonce_odr void @_ZN1XIN1SUt0_EEC2ES1_(%struct.X* %this, i32 %t) unnamed_addr // // FOO's instantiation of X: - // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt_EE1fEv(%struct.X.0* %this) - // CHECK: define linkonce_odr void @_ZN1XIN1SUt_EEC2ES1_(%struct.X.0* %this, i32 %t) unnamed_addr + // CHECK-LABEL: define linkonce_odr i32 @_ZN1XIN1SUt_EE1fEv(%struct.X.0* %this) + // CHECK-LABEL: define linkonce_odr void @_ZN1XIN1SUt_EEC2ES1_(%struct.X.0* %this, i32 %t) unnamed_addr } diff --git a/test/CodeGenCXX/template-dependent-bind-temporary.cpp b/test/CodeGenCXX/template-dependent-bind-temporary.cpp index cc1ce86..ca980c3 100644 --- a/test/CodeGenCXX/template-dependent-bind-temporary.cpp +++ b/test/CodeGenCXX/template-dependent-bind-temporary.cpp @@ -18,7 +18,7 @@ void IntToString(T a) } int main() { -// CHECK: define linkonce_odr void @_Z11IntToStringIcEvT_( +// CHECK-LABEL: define linkonce_odr void @_Z11IntToStringIcEvT_( IntToString('a'); } diff --git a/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp b/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp index 2c62b60..de86f10 100644 --- a/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp +++ b/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp @@ -2,8 +2,8 @@ // Verify that symbols are hidden. // CHECK: @_ZN1CIiE5Inner6Inner26StaticE = weak_odr hidden global -// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner1fEv -// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner6Inner21gEv +// CHECK-LABEL: define weak_odr hidden void @_ZN1CIiE5Inner1fEv +// CHECK-LABEL: define weak_odr hidden void @_ZN1CIiE5Inner6Inner21gEv template<typename T> struct C { diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp index b90716b..80283a1 100644 --- a/test/CodeGenCXX/template-instantiation.cpp +++ b/test/CodeGenCXX/template-instantiation.cpp @@ -13,16 +13,16 @@ // CHECK-NOT: _ZTVN5test31SIiEE // CHECK-NOT: _ZTSN5test31SIiEE -// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* %this) unnamed_addr -// CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_( -// CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd( - -// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi1EEE() -// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi2EEE() -// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi3EEE() -// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi1EEE() -// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi2EEE() -// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi3EEE() +// CHECK-LABEL: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* %this) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_( +// CHECK-LABEL: define available_externally void @_ZN5test21CIiE6zedbarEd( + +// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi1EEE() +// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi2EEE() +// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi3EEE() +// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi1EEE() +// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi2EEE() +// CHECK-LABEL: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi3EEE() // CHECK: declare void @_ZN7PR106662h1ENS_1SILi1EEE() // CHECK: declare void @_ZN7PR106662h1ENS_1SILi2EEE() // CHECK: declare void @_ZN7PR106662h1ENS_1SILi3EEE() diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp index 3acd12e..a84affa 100644 --- a/test/CodeGenCXX/template-linkage.cpp +++ b/test/CodeGenCXX/template-linkage.cpp @@ -9,19 +9,19 @@ template<typename T> struct A { // Explicit instantiations have external linkage. -// CHECK: define weak_odr void @_ZN1AIiE1gEv( +// CHECK-LABEL: define weak_odr void @_ZN1AIiE1gEv( template void A<int>::g(); -// CHECK: define weak_odr void @_ZN1AIfE1fEf( -// CHECK: define weak_odr void @_ZN1AIfE1gEv( +// CHECK-LABEL: define weak_odr void @_ZN1AIfE1fEf( +// CHECK-LABEL: define weak_odr void @_ZN1AIfE1gEv( // FIXME: This should also emit the vtable. template struct A<float>; -// CHECK: define weak_odr void @_Z1fIiEvT_ +// CHECK-LABEL: define weak_odr void @_Z1fIiEvT_ template <typename T> void f(T) { } template void f<int>(int); -// CHECK: define weak_odr void @_Z1gIiEvT_ +// CHECK-LABEL: define weak_odr void @_Z1gIiEvT_ template <typename T> inline void g(T) { } template void g<int>(int); @@ -40,7 +40,7 @@ template<typename T> void X1<T>::blarg() { } extern template struct X0<char>; extern template struct X1<char>; -// CHECK: define linkonce_odr void @_ZN2X1IcED1Ev(%struct.X1* %this) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN2X1IcED1Ev(%struct.X1* %this) unnamed_addr void test_X1() { X1<char> i1c; } diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp index a369c2e..e8a7a1f 100644 --- a/test/CodeGenCXX/temporaries.cpp +++ b/test/CodeGenCXX/temporaries.cpp @@ -1,4 +1,32 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 | FileCheck %s + +namespace PR16263 { + const unsigned int n = 1234; + extern const int &r = (const int&)n; + // CHECK: @_ZGRN7PR162631rE = private constant i32 1234, + // CHECK: @_ZN7PR162631rE = constant i32* @_ZGRN7PR162631rE, + + extern const int &s = reinterpret_cast<const int&>(n); + // CHECK: @_ZN7PR16263L1nE = internal constant i32 1234, align 4 + // CHECK: @_ZN7PR162631sE = constant i32* @_ZN7PR16263L1nE, align 8 + + struct A { int n; }; + struct B { int n; }; + struct C : A, B {}; + extern const A &&a = (A&&)(A&&)(C&&)(C{}); + // CHECK: @_ZGRN7PR162631aE = private global {{.*}} zeroinitializer, + // CHECK: @_ZN7PR162631aE = constant {{.*}} bitcast ({{.*}}* @_ZGRN7PR162631aE to + + extern const int &&t = ((B&&)C{}).n; + // CHECK: @_ZGRN7PR162631tE = private global {{.*}} zeroinitializer, + // CHECK: @_ZN7PR162631tE = constant i32* {{.*}}* @_ZGRN7PR162631tE {{.*}} 4 + + struct D { double d; C c; }; + extern const int &&u = (123, static_cast<B&&>(0, ((D&&)D{}).*&D::c).n); + // CHECK: @_ZGRN7PR162631uE = private global {{.*}} zeroinitializer + // CHECK: @_ZN7PR162631uE = constant i32* {{.*}} @_ZGRN7PR162631uE {{.*}} 12 +} + struct A { A(); ~A(); @@ -226,7 +254,7 @@ namespace PR5867 { }; void f(S, int); - // CHECK: define void @_ZN6PR58671gEv + // CHECK-LABEL: define void @_ZN6PR58671gEv void g() { // CHECK: call void @_ZN6PR58671SC1Ev // CHECK-NEXT: call void @_ZN6PR58671fENS_1SEi @@ -235,7 +263,7 @@ namespace PR5867 { (f)(S(), 0); } - // CHECK: define linkonce_odr void @_ZN6PR58672g2IiEEvT_ + // CHECK-LABEL: define linkonce_odr void @_ZN6PR58672g2IiEEvT_ template<typename T> void g2(T) { // CHECK: call void @_ZN6PR58671SC1Ev @@ -256,7 +284,7 @@ namespace PR6199 { struct B { operator A(); }; - // CHECK: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_ + // CHECK-LABEL: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_ template<typename T> A f2(T) { B b; // CHECK: call void @_ZN6PR61991BcvNS_1AEEv @@ -278,7 +306,7 @@ struct A { int& f(int); -// CHECK: define void @_ZN3T121gEv +// CHECK-LABEL: define void @_ZN3T121gEv void g() { // CHECK: call void @_ZN3T121AC1Ev // CHECK-NEXT: call i32 @_ZN3T121A1fEv( @@ -325,7 +353,7 @@ namespace PR7556 { struct A { ~A(); }; struct B { int i; ~B(); }; struct C { int C::*pm; ~C(); }; - // CHECK: define void @_ZN6PR75563fooEv() + // CHECK-LABEL: define void @_ZN6PR75563fooEv() void foo() { // CHECK: call void @_ZN6PR75561AD1Ev A(); @@ -350,7 +378,7 @@ namespace Elision { A fooA(); void takeA(A a); - // CHECK: define void @_ZN7Elision5test0Ev() + // CHECK-LABEL: define void @_ZN7Elision5test0Ev() void test0() { // CHECK: [[I:%.*]] = alloca [[A:%.*]], align 8 // CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8 @@ -378,7 +406,7 @@ namespace Elision { } - // CHECK: define void @_ZN7Elision5test1EbNS_1AE( + // CHECK-LABEL: define void @_ZN7Elision5test1EbNS_1AE( void test1(bool c, A x) { // CHECK: [[I:%.*]] = alloca [[A]], align 8 // CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8 @@ -417,7 +445,7 @@ namespace Elision { // CHECK: ret void } - // CHECK: define void @_ZN7Elision5test4Ev() + // CHECK-LABEL: define void @_ZN7Elision5test4Ev() void test4() { // CHECK: [[X:%.*]] = alloca [[A]], align 8 // CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16 @@ -493,7 +521,7 @@ namespace Elision { namespace PR8623 { struct A { A(int); ~A(); }; - // CHECK: define void @_ZN6PR86233fooEb( + // CHECK-LABEL: define void @_ZN6PR86233fooEb( void foo(bool b) { // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1 // CHECK-NEXT: [[LCONS:%.*]] = alloca i1 @@ -523,7 +551,7 @@ namespace PR8623 { namespace PR11365 { struct A { A(); ~A(); }; - // CHECK: define void @_ZN7PR113653fooEv( + // CHECK-LABEL: define void @_ZN7PR113653fooEv( void foo() { // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [3 x [[A:%.*]]]* {{.*}}, i32 0, i32 0 // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 3 @@ -542,7 +570,7 @@ namespace AssignmentOp { struct A { ~A(); }; struct B { A operator=(const B&); }; struct C : B { B b1, b2; }; - // CHECK: define void @_ZN12AssignmentOp1fE + // CHECK-LABEL: define void @_ZN12AssignmentOp1fE void f(C &c1, const C &c2) { // CHECK: call {{.*}} @_ZN12AssignmentOp1CaSERKS0_( c1 = c2; @@ -558,3 +586,194 @@ namespace AssignmentOp { // CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS // CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev( } + +namespace BindToSubobject { + struct A { + A(); + ~A(); + int a; + }; + + void f(), g(); + + // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1aE) + // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1aE to i8*), i8* @__dso_handle) + // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1aE, i32 0, i32 0), i32** @_ZN15BindToSubobject1aE, align 8 + int &&a = A().a; + + // CHECK: call void @_ZN15BindToSubobject1fEv() + // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1bE) + // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1bE to i8*), i8* @__dso_handle) + // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1bE, i32 0, i32 0), i32** @_ZN15BindToSubobject1bE, align 8 + int &&b = (f(), A().a); + + int A::*h(); + + // CHECK: call void @_ZN15BindToSubobject1fEv() + // CHECK: call void @_ZN15BindToSubobject1gEv() + // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1cE) + // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle) + // CHECK: call {{.*}} @_ZN15BindToSubobject1hE + // CHECK: getelementptr + // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1cE, align 8 + int &&c = (f(), (g(), A().*h())); + + struct B { + int padding; + A a; + }; + + // CHECK: call void @_ZN15BindToSubobject1BC1Ev({{.*}} @_ZGRN15BindToSubobject1dE) + // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle) + // CHECK: call {{.*}} @_ZN15BindToSubobject1hE + // CHECK: getelementptr {{.*}} getelementptr + // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1dE, align 8 + int &&d = (B().a).*h(); +} + +namespace Bitfield { + struct S { int a : 5; ~S(); }; + + // Do not lifetime extend the S() temporary here. + // CHECK: alloca + // CHECK: call {{.*}}memset + // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE + // CHECK: call void @_ZN8Bitfield1SD1 + // CHECK: store i32* @_ZGRN8Bitfield1rE, i32** @_ZN8Bitfield1rE, align 8 + int &&r = S().a; +} + +namespace Vector { + typedef __attribute__((vector_size(16))) int vi4a; + typedef __attribute__((ext_vector_type(4))) int vi4b; + struct S { + vi4a v; + vi4b w; + }; + // CHECK: alloca + // CHECK: extractelement + // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE + // CHECK: store i32* @_ZGRN6Vector1rE, i32** @_ZN6Vector1rE, + int &&r = S().v[1]; + + // CHECK: alloca + // CHECK: extractelement + // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE + // CHECK: store i32* @_ZGRN6Vector1sE, i32** @_ZN6Vector1sE, + int &&s = S().w[1]; + // FIXME PR16204: The following code leads to an assertion in Sema. + //int &&s = S().w.y; +} + +namespace ImplicitTemporaryCleanup { + struct A { A(int); ~A(); }; + void g(); + + // CHECK-LABEL: define void @_ZN24ImplicitTemporaryCleanup1fEv( + void f() { + // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1AC1Ei( + A &&a = 0; + + // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1gEv( + g(); + + // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1AD1Ev( + } +} + +namespace MultipleExtension { + struct A { A(); ~A(); }; + struct B { B(); ~B(); }; + struct C { C(); ~C(); }; + struct D { D(); ~D(); int n; C c; }; + struct E { const A &a; B b; const C &c; ~E(); }; + + E &&e1 = { A(), B(), D().c }; + + // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e1E.*]]) + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]] + // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]], i32 0, i32 0) + + // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 1)) + + // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e1E.*]]) + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]] + // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 2) + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[TEMPE]] + // CHECK: store {{.*}} @[[TEMPE]], %"struct.MultipleExtension::E"** @_ZN17MultipleExtension2e1E, align 8 + + E e2 = { A(), B(), D().c }; + + // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e2E.*]]) + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]] + // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[E:_ZN17MultipleExtension2e2E]], i32 0, i32 0) + + // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 1)) + + // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e2E.*]]) + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]] + // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 2) + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[E]] + + + void g(); + // CHECK: define void @[[NS:_ZN17MultipleExtension]]1fEv( + void f() { + E &&e1 = { A(), B(), D().c }; + // CHECK: %[[TEMPE1_A:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1:.*]], i32 0, i32 0 + // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA1:.*]]) + // CHECK: store {{.*}} %[[TEMPA1]], {{.*}} %[[TEMPE1_A]] + // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 1 + // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE1_B]]) + // CHECK: %[[TEMPE1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 2 + // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD1:.*]]) + // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i32 0, i32 1 + // CHECK: store {{.*}} %[[TEMPD1_C]], {{.*}} %[[TEMPE1_C]] + // CHECK: store {{.*}} %[[TEMPE1]], {{.*}} %[[E1:.*]] + + g(); + // CHECK: call void @[[NS]]1gEv() + + E e2 = { A(), B(), D().c }; + // CHECK: %[[TEMPE2_A:.*]] = getelementptr inbounds {{.*}} %[[E2:.*]], i32 0, i32 0 + // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA2:.*]]) + // CHECK: store {{.*}} %[[TEMPA2]], {{.*}} %[[TEMPE2_A]] + // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 1 + // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE2_B]]) + // CHECK: %[[TEMPE2_C:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 2 + // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD2:.*]]) + // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i32 0, i32 1 + // CHECK: store {{.*}} %[[TEMPD2_C]], {{.*}}* %[[TEMPE2_C]] + + g(); + // CHECK: call void @[[NS]]1gEv() + + // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[E2]]) + // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD2]]) + // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA2]]) + // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[TEMPE1]]) + // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD1]]) + // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA1]]) + } +} + +namespace PR14130 { + struct S { S(int); }; + struct U { S &&s; }; + U v { { 0 } }; + // CHECK: call void @_ZN7PR141301SC1Ei({{.*}} @_ZGRN7PR141301vE, i32 0) + // CHECK: store {{.*}} @_ZGRN7PR141301vE, {{.*}} @_ZN7PR141301vE +} + +namespace Ctor { + struct A { A(); ~A(); }; + void f(); + struct B { + A &&a; + B() : a{} { f(); } + } b; + // CHECK: define {{.*}}void @_ZN4Ctor1BC1Ev( + // CHECK: call void @_ZN4Ctor1AC1Ev( + // CHECK: call void @_ZN4Ctor1fEv( + // CHECK: call void @_ZN4Ctor1AD1Ev( +} diff --git a/test/CodeGenCXX/thiscall-struct-return.cpp b/test/CodeGenCXX/thiscall-struct-return.cpp index ff53125..a6be5aa 100644 --- a/test/CodeGenCXX/thiscall-struct-return.cpp +++ b/test/CodeGenCXX/thiscall-struct-return.cpp @@ -1,7 +1,7 @@ // For MSVC ABI compatibility, all structures returned by value using the // thiscall calling convention must use the hidden parameter. // -// RUN: %clang_cc1 -triple i386-PC-Win32 %s -fms-compatibility -O0 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple i386-PC-Win32 %s -fms-compatibility -emit-llvm -o - | FileCheck %s // This structure would normally be returned via EAX struct S { @@ -29,7 +29,7 @@ public: } }; -// CHECK: define void @_Z4testv() +// CHECK-LABEL: define void @_Z4testv() void test( void ) { // CHECK: call void @_ZN1CC1Ev(%class.C* [[C:%.+]]) C c; diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp index 769d120..70decc9 100644 --- a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp +++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp @@ -7,7 +7,7 @@ struct X { struct Y { }; -// CHECK: define void @_Z1fv +// CHECK-LABEL: define void @_Z1fv void f() { // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x) // CHECK: invoke void @_ZN1XC1Ev diff --git a/test/CodeGenCXX/throw-expression-cleanup.cpp b/test/CodeGenCXX/throw-expression-cleanup.cpp index e1ecd38..9944e16 100644 --- a/test/CodeGenCXX/throw-expression-cleanup.cpp +++ b/test/CodeGenCXX/throw-expression-cleanup.cpp @@ -14,7 +14,7 @@ void f() { } catch (...) { } } -// CHECK: define void @_Z1fv +// CHECK-LABEL: define void @_Z1fv // CHECK: call void @_ZN5ErrorC1ERK1X // CHECK: invoke void @__cxa_throw // CHECK: landingpad diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp index ba8a868..d9bf8fd 100644 --- a/test/CodeGenCXX/throw-expressions.cpp +++ b/test/CodeGenCXX/throw-expressions.cpp @@ -23,7 +23,31 @@ int test4() { int test5(bool x, bool y, int z) { return (x ? throw 1 : y) ? z : throw 2; } -// CHECK: define i32 @_Z5test5bbi( +// CHECK-LABEL: define i32 @_Z5test5bbi( +// CHECK: br i1 +// +// x.true: +// CHECK: call void @__cxa_throw( +// CHECK-NEXT: unreachable +// +// x.false: +// CHECK: br i1 +// +// y.true: +// CHECK: load i32* +// CHECK: br label +// +// y.false: +// CHECK: call void @__cxa_throw( +// CHECK-NEXT: unreachable +// +// end: +// CHECK: ret i32 + +int test6(bool x, bool y, int z) { + return (x ? throw 1 : y) ? z : (throw 2); +} +// CHECK-LABEL: define i32 @_Z5test6bbi( // CHECK: br i1 // // x.true: diff --git a/test/CodeGenCXX/thunks-available-externally.cpp b/test/CodeGenCXX/thunks-available-externally.cpp index dfdb786..01e4947 100644 --- a/test/CodeGenCXX/thunks-available-externally.cpp +++ b/test/CodeGenCXX/thunks-available-externally.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm-only -O3 // Check that we don't assert on this case. namespace Test1 { @@ -58,15 +58,6 @@ static void f(B* b) { b->f(); } -// CHECK: define void @_ZN5Test21fEv() -// CHECK: call void @_ZN5Test21C1fEv -// CHECK: ret void -// CHECK: define available_externally void @_ZThn16_N5Test21C1fEv -void f() { - C c; - f(&c); -} - } // Test that we don't assert. diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp index 6e58830..defb706 100644 --- a/test/CodeGenCXX/thunks.cpp +++ b/test/CodeGenCXX/thunks.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=HIDDEN %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - -O1 -disable-llvm-optzns | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=CHECK-HIDDEN %s namespace Test1 { @@ -19,7 +20,7 @@ struct C : A, B { virtual void f(); }; -// CHECK: define void @_ZThn8_N5Test11C1fEv( +// CHECK-LABEL: define void @_ZThn8_N5Test11C1fEv( void C::f() { } } @@ -37,7 +38,7 @@ struct B : virtual A { virtual void f(); }; -// CHECK: define void @_ZTv0_n24_N5Test21B1fEv( +// CHECK-LABEL: define void @_ZTv0_n24_N5Test21B1fEv( void B::f() { } } @@ -82,7 +83,7 @@ struct __attribute__((visibility("protected"))) C : A, B { virtual void f(); }; -// CHECK: define protected void @_ZThn8_N5Test41C1fEv( +// CHECK-LABEL: define protected void @_ZThn8_N5Test41C1fEv( void C::f() { } } @@ -165,7 +166,7 @@ namespace Test6 { virtual X f(); }; - // CHECK: define void @_ZThn16_N5Test66Thunks1fEv + // CHECK-LABEL: define void @_ZThn16_N5Test66Thunks1fEv // CHECK-NOT: memcpy // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}} // CHECK: ret void @@ -211,7 +212,7 @@ namespace Test7 { void D::baz(X, X&, _Complex float, Small, Small&, Large) { } - // CHECK: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE( + // CHECK-LABEL: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE( // CHECK-NOT: memcpy // CHECK: ret void void testD() { D d; } @@ -226,7 +227,7 @@ namespace Test8 { // CHECK: define void @_ZN5Test81C6helperENS_6NonPODE([[NONPODTYPE:%.*]]* void C::helper(NonPOD var) {} - // CHECK: define void @_ZThn8_N5Test81C3barENS_6NonPODE( + // CHECK-LABEL: define void @_ZThn8_N5Test81C3barENS_6NonPODE( // CHECK-NOT: load [[NONPODTYPE]]* // CHECK-NOT: memcpy // CHECK: ret void @@ -250,8 +251,8 @@ namespace Test10 { struct B { virtual void foo(); }; struct C : A, B { void foo() {} }; - // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test101C3fooEv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv + // CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv void test() { C c; @@ -342,10 +343,31 @@ namespace Test14 { // CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) unnamed_addr [[NUW:#[0-9]+]] } +// Varargs non-covariant thunk test. +// PR18098 +namespace Test15 { + struct A { + virtual ~A(); + }; + struct B { + virtual void f(int x, ...); + }; + struct C : A, B { + virtual void c(); + virtual void f(int x, ...); + }; + void C::c() {} + + // C::c + // CHECK: declare void @_ZN6Test151C1fEiz + // non-virtual thunk to C::f + // CHECK: declare void @_ZThn8_N6Test151C1fEiz +} + /**** The following has to go at the end of the file ****/ // This is from Test5: -// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv -// CHECK: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv( +// CHECK-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv +// CHECK-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv( // CHECK: attributes [[NUW]] = { nounwind uwtable{{.*}} } diff --git a/test/CodeGenCXX/type_visibility.cpp b/test/CodeGenCXX/type_visibility.cpp index 5c45611..11e5091 100644 --- a/test/CodeGenCXX/type_visibility.cpp +++ b/test/CodeGenCXX/type_visibility.cpp @@ -26,11 +26,11 @@ namespace temp0 { }; template struct B<A>; - // FUNS: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv( + // FUNS-LABEL: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv( // VARS: @_ZTVN5temp01BINS_1AEEE = weak_odr unnamed_addr constant // VARS: @_ZTSN5temp01BINS_1AEEE = weak_odr constant // VARS: @_ZTIN5temp01BINS_1AEEE = weak_odr unnamed_addr constant - // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv( + // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv( // VARS-HIDDEN: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTSN5temp01BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTIN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant @@ -43,11 +43,11 @@ namespace temp1 { }; template struct B<A>; - // FUNS: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv( + // FUNS-LABEL: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv( // VARS: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant // VARS: @_ZTSN5temp11BINS_1AEEE = weak_odr constant // VARS: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant - // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv( + // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv( // VARS-HIDDEN: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant // VARS-HIDDEN: @_ZTSN5temp11BINS_1AEEE = weak_odr constant // VARS-HIDDEN: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant @@ -60,11 +60,11 @@ namespace temp2 { }; template struct B<A>; - // FUNS: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv( + // FUNS-LABEL: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv( // VARS: @_ZTVN5temp21BINS_1AEEE = weak_odr unnamed_addr constant // VARS: @_ZTSN5temp21BINS_1AEEE = weak_odr constant // VARS: @_ZTIN5temp21BINS_1AEEE = weak_odr unnamed_addr constant - // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv( + // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv( // VARS-HIDDEN: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTSN5temp21BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTIN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant @@ -77,11 +77,11 @@ namespace temp3 { }; template struct B<A>; - // FUNS: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( + // FUNS-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( // VARS: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant // VARS: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant - // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( + // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( // VARS-HIDDEN: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant @@ -94,11 +94,11 @@ namespace temp4 { }; template struct B<A>; - // FUNS: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv( + // FUNS-LABEL: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv( // VARS: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant // VARS: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant - // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv( + // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv( // VARS-HIDDEN: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant @@ -110,11 +110,11 @@ namespace type0 { }; void A::foo() {} - // FUNS: define void @_ZN5type01A3fooEv( + // FUNS-LABEL: define void @_ZN5type01A3fooEv( // VARS: @_ZTVN5type01AE = unnamed_addr constant // VARS: @_ZTSN5type01AE = constant // VARS: @_ZTIN5type01AE = unnamed_addr constant - // FUNS-HIDDEN: define hidden void @_ZN5type01A3fooEv( + // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type01A3fooEv( // VARS-HIDDEN: @_ZTVN5type01AE = unnamed_addr constant // VARS-HIDDEN: @_ZTSN5type01AE = constant // VARS-HIDDEN: @_ZTIN5type01AE = unnamed_addr constant @@ -126,11 +126,11 @@ namespace type1 { }; void A::foo() {} - // FUNS: define hidden void @_ZN5type11A3fooEv( + // FUNS-LABEL: define hidden void @_ZN5type11A3fooEv( // VARS: @_ZTVN5type11AE = unnamed_addr constant // VARS: @_ZTSN5type11AE = constant // VARS: @_ZTIN5type11AE = unnamed_addr constant - // FUNS-HIDDEN: define hidden void @_ZN5type11A3fooEv( + // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type11A3fooEv( // VARS-HIDDEN: @_ZTVN5type11AE = unnamed_addr constant // VARS-HIDDEN: @_ZTSN5type11AE = constant // VARS-HIDDEN: @_ZTIN5type11AE = unnamed_addr constant @@ -142,11 +142,11 @@ namespace type2 { }; void A::foo() {} - // FUNS: define void @_ZN5type21A3fooEv( + // FUNS-LABEL: define void @_ZN5type21A3fooEv( // VARS: @_ZTVN5type21AE = hidden unnamed_addr constant // VARS: @_ZTSN5type21AE = hidden constant // VARS: @_ZTIN5type21AE = hidden unnamed_addr constant - // FUNS-HIDDEN: define hidden void @_ZN5type21A3fooEv( + // FUNS-HIDDEN-LABEL: define hidden void @_ZN5type21A3fooEv( // VARS-HIDDEN: @_ZTVN5type21AE = hidden unnamed_addr constant // VARS-HIDDEN: @_ZTSN5type21AE = hidden constant // VARS-HIDDEN: @_ZTIN5type21AE = hidden unnamed_addr constant @@ -158,11 +158,11 @@ namespace type3 { }; void A::foo() {} - // FUNS: define void @_ZN5type31A3fooEv( + // FUNS-LABEL: define void @_ZN5type31A3fooEv( // VARS: @_ZTVN5type31AE = hidden unnamed_addr constant // VARS: @_ZTSN5type31AE = hidden constant // VARS: @_ZTIN5type31AE = hidden unnamed_addr constant - // FUNS-HIDDEN: define void @_ZN5type31A3fooEv( + // FUNS-HIDDEN-LABEL: define void @_ZN5type31A3fooEv( // VARS-HIDDEN: @_ZTVN5type31AE = hidden unnamed_addr constant // VARS-HIDDEN: @_ZTSN5type31AE = hidden constant // VARS-HIDDEN: @_ZTIN5type31AE = hidden unnamed_addr constant diff --git a/test/CodeGenCXX/typeid.cpp b/test/CodeGenCXX/typeid.cpp index a1bc967..9d21290 100644 --- a/test/CodeGenCXX/typeid.cpp +++ b/test/CodeGenCXX/typeid.cpp @@ -27,7 +27,10 @@ extern A &a; // CHECK: @_ZN5Test14a_tiE = global const std::type_info &a_ti = typeid(a); -// CHECK: define i8* @_ZN5Test11fEv +// CHECK: @_ZN5Test18A10_c_tiE = constant %"class.std::type_info"* bitcast ({ i8*, i8* }* @_ZTIA10_c to %"class.std::type_info"*), align 8 +const std::type_info &A10_c_ti = typeid(char const[10]); + +// CHECK-LABEL: define i8* @_ZN5Test11fEv const char *f() { try { // CHECK: br i1 diff --git a/test/CodeGenCXX/unknown-anytype.cpp b/test/CodeGenCXX/unknown-anytype.cpp index 902cc8d..aacb849 100644 --- a/test/CodeGenCXX/unknown-anytype.cpp +++ b/test/CodeGenCXX/unknown-anytype.cpp @@ -1,33 +1,45 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o %t %s +// RUN: FileCheck -check-prefix COMMON %s < %t +// RUN: FileCheck -check-prefix X86_64 %s < %t +// RUN: %clang_cc1 -triple i386-apple-darwin10 -funknown-anytype -emit-llvm -o %t %s +// RUN: FileCheck -check-prefix COMMON %s < %t +// RUN: FileCheck -check-prefix I386 %s < %t + +// x86-64 is the special case here because of its variadic convention. +// We want to ensure that it always uses a variadic convention even if +// other platforms do not. +// rdar://13731520 int test0() { extern __unknown_anytype test0_any; - // CHECK: load i32* @test0_any + // COMMON: load i32* @test0_any return (int) test0_any; } int test1() { extern __unknown_anytype test1_any(); - // CHECK: call i32 @_Z9test1_anyv() + // COMMON: call i32 @_Z9test1_anyv() return (int) test1_any(); } extern "C" __unknown_anytype test2_any(...); float test2() { - // CHECK: call float (...)* @test2_any(double {{[^,]+}}) + // X86_64: call float (double, ...)* @test2_any(double {{[^,]+}}) + // I386: call float (double, ...)* @test2_any(double {{[^,]+}}) return (float) test2_any(0.5f); } extern "C" __unknown_anytype test2a_any(...); float test2a() { - // CHECK: call float (...)* @test2a_any(float {{[^,]+}}) + // X86_64: call float (float, ...)* @test2a_any(float {{[^,]+}}) + // I386: call float (float, ...)* @test2a_any(float {{[^,]+}}) return (float) test2a_any((float) 0.5f); } float test3() { extern __unknown_anytype test3_any; - // CHECK: [[FN:%.*]] = load float (i32)** @test3_any, - // CHECK: call float [[FN]](i32 5) + // COMMON: [[FN:%.*]] = load float (i32)** @test3_any, + // COMMON: call float [[FN]](i32 5) return ((float(*)(int)) test3_any)(5); } @@ -36,22 +48,22 @@ namespace test4 { extern __unknown_anytype test4_any2; int test() { - // CHECK: load i32* @_ZN5test410test4_any1E - // CHECK: load i8* @_ZN5test410test4_any2E + // COMMON: load i32* @_ZN5test410test4_any1E + // COMMON: load i8* @_ZN5test410test4_any2E return (int) test4_any1 + (char) test4_any2; } } extern "C" __unknown_anytype test5_any(); void test5() { - // CHECK: call void @test5_any() + // COMMON: call void @test5_any() return (void) test5_any(); } extern "C" __unknown_anytype test6_any(float *); long test6() { - // CHECK: call i64 @test6_any(float* null) - return (long) test6_any(0); + // COMMON: call i64 @test6_any(float* null) + return (long long) test6_any(0); } struct Test7 { @@ -59,7 +71,7 @@ struct Test7 { }; extern "C" __unknown_anytype test7_any(int); Test7 test7() { - // CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5) + // COMMON: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5) return (Test7) test7_any(5); } @@ -71,29 +83,35 @@ struct Test8 { }; void Test8::test() { float f; - // CHECK: call i32 @_ZN5Test83fooEv( + // COMMON: call i32 @_ZN5Test83fooEv( f = (int) foo(); - // CHECK: call i32 @_ZN5Test83fooEi( + // COMMON: call i32 @_ZN5Test83fooEi( f = (int) foo(5); - // CHECK: call i32 @_ZN5Test83fooEv( + // COMMON: call i32 @_ZN5Test83fooEv( f = (float) this->foo(); - // CHECK: call i32 @_ZN5Test83fooEi( + // COMMON: call i32 @_ZN5Test83fooEi( f = (float) this->foo(5); } void test8(Test8 *p) { double d; - // CHECK: call i32 @_ZN5Test83fooEv( + // COMMON: call i32 @_ZN5Test83fooEv( d = (double) p->foo(); - // CHECK: call i32 @_ZN5Test83fooEi( + // COMMON: call i32 @_ZN5Test83fooEi( d = (double) p->foo(5); - // CHECK: call i32 @_ZN5Test83fooEv( + // COMMON: call i32 @_ZN5Test83fooEv( d = (bool) (*p).foo(); - // CHECK: call i32 @_ZN5Test83fooEi( + // COMMON: call i32 @_ZN5Test83fooEi( d = (bool) (*p).foo(5); } extern "C" __unknown_anytype test9_foo; void *test9() { - // CHECK: ret i8* bitcast (i32* @test9_foo to i8*) + // COMMON: ret i8* bitcast (i32* @test9_foo to i8*) return (int*) &test9_foo; } + +// Don't explode on this. +extern "C" __unknown_anytype test10_any(...); +void test10() { + (void) test10_any(), (void) test10_any(); +} diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp index 60dca99..fad459b 100644 --- a/test/CodeGenCXX/value-init.cpp +++ b/test/CodeGenCXX/value-init.cpp @@ -74,7 +74,7 @@ namespace ptrmem { int S::*mem2; }; - // CHECK: define i32 @_ZN6ptrmem4testEPNS_1SE + // CHECK-LABEL: define i32 @_ZN6ptrmem4testEPNS_1SE int test(S *s) { // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 // CHECK: getelementptr @@ -99,7 +99,7 @@ struct Test2 { struct Test3 : public Test { }; -// CHECK: define void @_ZN6PR98011fEv +// CHECK-LABEL: define void @_ZN6PR98011fEv void f() { // CHECK-NOT: call void @llvm.memset.p0i8.i64 // CHECK: call void @_ZN6PR98014TestC1Ei @@ -131,7 +131,7 @@ void f() { namespace zeroinit { struct S { int i; }; - // CHECK: define i32 @_ZN8zeroinit4testEv() + // CHECK-LABEL: define i32 @_ZN8zeroinit4testEv() int test() { // CHECK: call void @llvm.memset.p0i8.i64 // CHECK: ret i32 0 @@ -148,7 +148,7 @@ namespace zeroinit { void f(); }; - // CHECK: define void @_ZN8zeroinit9testX0_X1Ev + // CHECK-LABEL: define void @_ZN8zeroinit9testX0_X1Ev void testX0_X1() { // CHECK: call void @llvm.memset.p0i8.i64 // CHECK-NEXT: call void @_ZN8zeroinit2X1C1Ev @@ -169,7 +169,7 @@ namespace zeroinit { }; - // CHECK: define void @_ZN8zeroinit9testX0_X3Ev + // CHECK-LABEL: define void @_ZN8zeroinit9testX0_X3Ev void testX0_X3() { // CHECK-NOT: call void @llvm.memset // CHECK: call void @_ZN8zeroinit2X3IiEC1Ev @@ -201,7 +201,7 @@ namespace test6 { void test() { A arr[10][20] = { 5 }; }; - // CHECK: define void @_ZN5test64testEv() + // CHECK-LABEL: define void @_ZN5test64testEv() // CHECK: [[ARR:%.*]] = alloca [10 x [20 x [[A:%.*]]]], // CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[ARR]], i64 0, i64 0 @@ -243,7 +243,7 @@ namespace PR11124 { struct B : virtual A { int b; }; struct C : B { C(); }; C::C() : A(3), B() {} - // CHECK: define void @_ZN7PR111241CC1Ev + // CHECK-LABEL: define void @_ZN7PR111241CC1Ev // CHECK: call void @llvm.memset.p0i8.i64(i8* {{.*}}, i8 0, i64 12, i32 8, i1 false) // CHECK-NEXT: call void @_ZN7PR111241BC2Ev // Make sure C::C doesn't overwrite parts of A while it is zero-initializing B @@ -251,18 +251,18 @@ namespace PR11124 { struct B2 : virtual A { int B::*b; }; struct C2 : B2 { C2(); }; C2::C2() : A(3), B2() {} - // CHECK: define void @_ZN7PR111242C2C1Ev + // CHECK-LABEL: define void @_ZN7PR111242C2C1Ev // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* {{.*}}, i64 16, i32 8, i1 false) // CHECK-NEXT: call void @_ZN7PR111242B2C2Ev } // Ensure we produce an i1 here, and don't assert. -// CHECK: define void @_Z9r170806_bv( +// CHECK-LABEL: define void @_Z9r170806_bv( // CHECK: call void @_Z9r170806_ab(i1 zeroext false) void r170806_a(bool b = bool()); void r170806_b() { r170806_a(); } -// CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr // CHECK: call void @llvm.memset.p0i8.i64 // CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev // CHECK-NEXT: ret void diff --git a/test/CodeGenCXX/vararg-conversion-ctor.cpp b/test/CodeGenCXX/vararg-conversion-ctor.cpp index a49b1db..e496f6d 100644 --- a/test/CodeGenCXX/vararg-conversion-ctor.cpp +++ b/test/CodeGenCXX/vararg-conversion-ctor.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o %t-64.ll -// RUN: FileCheck -check-prefix LPLL64 --input-file=%t-64.ll %s +// RUN: FileCheck -check-prefix CHECK-LPLL64 --input-file=%t-64.ll %s extern "C" int printf(...); diff --git a/test/CodeGenCXX/vararg-non-pod.cpp b/test/CodeGenCXX/vararg-non-pod.cpp index 6c6f459..9497179 100644 --- a/test/CodeGenCXX/vararg-non-pod.cpp +++ b/test/CodeGenCXX/vararg-non-pod.cpp @@ -8,7 +8,7 @@ struct X { void vararg(...); -// CHECK: define void @_Z4test1X +// CHECK-LABEL: define void @_Z4test1X void test(X x) { // CHECK: call void @llvm.trap() vararg(x); diff --git a/test/CodeGenCXX/varargs.cpp b/test/CodeGenCXX/varargs.cpp index af34336..31bbee98 100644 --- a/test/CodeGenCXX/varargs.cpp +++ b/test/CodeGenCXX/varargs.cpp @@ -7,7 +7,7 @@ namespace test0 { // though there is no way to do a va_begin. Otherwise, the optimizer // will warn about 'dropped arguments' at the call site. - // CHECK: define i32 @_ZN5test05test1Ez(...) + // CHECK-LABEL: define i32 @_ZN5test05test1Ez(...) int test1(...) { return -1; } @@ -30,7 +30,7 @@ namespace test1 { A x; foo(x); } - // CHECK: define void @_ZN5test14testEv() + // CHECK-LABEL: define void @_ZN5test14testEv() // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 4 // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]], align 4 // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i8* diff --git a/test/CodeGenCXX/variadic-templates.cpp b/test/CodeGenCXX/variadic-templates.cpp index c56bec3..4974b65 100644 --- a/test/CodeGenCXX/variadic-templates.cpp +++ b/test/CodeGenCXX/variadic-templates.cpp @@ -5,7 +5,7 @@ int get_num_types(Types...) { return sizeof...(Types); } -// CHECK: define weak_odr i32 @_Z13get_num_typesIJifdEEiDpT_ +// CHECK-LABEL: define weak_odr i32 @_Z13get_num_typesIJifdEEiDpT_ // CHECK: ret i32 3 template int get_num_types(int, float, double); @@ -13,7 +13,7 @@ template int get_num_types(int, float, double); namespace test1 { template <class... T> void foo() { int values[sizeof...(T)+1] = { T::value... }; - // CHECK: define linkonce_odr void @_ZN5test13fooIJEEEvv() + // CHECK-LABEL: define linkonce_odr void @_ZN5test13fooIJEEEvv() // CHECK: alloca [1 x i32], align 4 } diff --git a/test/CodeGenCXX/virt-dtor-gen.cpp b/test/CodeGenCXX/virt-dtor-gen.cpp index 1a6c583..78a0b81 100644 --- a/test/CodeGenCXX/virt-dtor-gen.cpp +++ b/test/CodeGenCXX/virt-dtor-gen.cpp @@ -7,4 +7,4 @@ class Foo { }; Foo::~Foo() {} -// CHECK: define void @_ZN3FooD0Ev(%class.Foo* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN3FooD0Ev(%class.Foo* %this) unnamed_addr diff --git a/test/CodeGenCXX/virtual-base-cast.cpp b/test/CodeGenCXX/virtual-base-cast.cpp index f469636..40e68f6 100644 --- a/test/CodeGenCXX/virtual-base-cast.cpp +++ b/test/CodeGenCXX/virtual-base-cast.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple i686-pc-linux-gnu | FileCheck %s +// RUN: %clang_cc1 -cxx-abi microsoft -emit-llvm %s -o - -triple i686-pc-win32 | FileCheck -check-prefix MSVC %s struct A { int a; virtual int aa(); }; struct B { int b; virtual int bb(); }; @@ -17,6 +18,16 @@ A* a() { return x; } // CHECK: load i32* [[CASTVBASEOFFSETPTRA]] // CHECK: } +// MSVC: @"\01?a@@YAPAUA@@XZ"() [[NUW:#[0-9]+]] { +// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0 +// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8** +// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]] +// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 4 +// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32* +// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]] +// MSVC: add nsw i32 0, %[[offset]] +// MSVC: } + B* b() { return x; } // CHECK: @_Z1bv() [[NUW]] // CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -20 @@ -24,6 +35,18 @@ B* b() { return x; } // CHECK: load i32* [[CASTVBASEOFFSETPTRA]] // CHECK: } +// Same as 'a' except we use a different vbtable offset. +// MSVC: @"\01?b@@YAPAUB@@XZ"() [[NUW:#[0-9]+]] { +// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0 +// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8** +// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]] +// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 8 +// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32* +// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]] +// MSVC: add nsw i32 0, %[[offset]] +// MSVC: } + + BB* c() { return x; } // CHECK: @_Z1cv() [[NUW]] // CHECK: [[VBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -24 @@ -32,4 +55,35 @@ BB* c() { return x; } // CHECK: add i32 [[VBASEOFFSETC]], 8 // CHECK: } +// Same as 'a' except we use a different vbtable offset. +// MSVC: @"\01?c@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] { +// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0 +// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8** +// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]] +// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16 +// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32* +// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]] +// MSVC: add nsw i32 0, %[[offset]] +// MSVC: } + +// Put the vbptr at a non-zero offset inside a non-virtual base. +struct E { int e; }; +struct F : E, D { int f; }; + +F* y; + +BB* d() { return y; } + +// Same as 'c' except the vbptr offset is 4, changing the initial GEP and the +// final add. +// MSVC: @"\01?d@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] { +// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 4 +// MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8** +// MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]] +// MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16 +// MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32* +// MSVC: %[[offset:.*]] = load i32* %[[entry_i32]] +// MSVC: add nsw i32 4, %[[offset]] +// MSVC: } + // CHECK: attributes [[NUW]] = { nounwind{{.*}} } diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp index 2424d21..5014eaf 100644 --- a/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -18,34 +18,34 @@ int main() { // basic_iostream's complete dtor calls its base dtor, then its // virtual base's dtor. -// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr // CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev // CHECK: call {{.*}} @_ZN9basic_iosD2Ev // basic_iostream's base dtor calls its non-virtual base dtor. -// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* {{.*}}%this, i8** %vtt) unnamed_addr // CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: } -// basic_iostream's deleting dtor calls its complete dtor, then -// operator delete(). -// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr -// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev -// CHECK: call {{.*}} @_ZdlPv - // basic_istream's complete dtor calls the base dtor, // then its virtual base's base dtor. -// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr // CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: call {{.*}} @_ZN9basic_iosD2Ev // basic_istream's deleting dtor calls the complete dtor, then // operator delete(). -// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr // CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev // CHECK: call {{.*}} @_ZdlPv +// basic_iostream's deleting dtor calls its complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr +// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev +// CHECK: call {{.*}} @_ZdlPv + // basic_istream's base dtor is a no-op. -// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* {{.*}}%this, i8** %vtt) unnamed_addr // CHECK-NOT: call // CHECK: } diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp index c9f13f8..2878e95 100644 --- a/test/CodeGenCXX/virtual-bases.cpp +++ b/test/CodeGenCXX/virtual-bases.cpp @@ -5,23 +5,23 @@ struct A { }; // CHECK: @_ZN1AC1Ev = alias {{.*}} @_ZN1AC2Ev -// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr A::A() { } struct B : virtual A { B(); }; -// CHECK: define void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr -// CHECK: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) unnamed_addr +// CHECK-LABEL: define void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) unnamed_addr B::B() { } struct C : virtual A { C(bool); }; -// CHECK: define void @_ZN1CC1Eb(%struct.C* %this, i1 zeroext) unnamed_addr -// CHECK: define void @_ZN1CC2Eb(%struct.C* %this, i8** %vtt, i1 zeroext) unnamed_addr +// CHECK-LABEL: define void @_ZN1CC1Eb(%struct.C* %this, i1 zeroext) unnamed_addr +// CHECK-LABEL: define void @_ZN1CC2Eb(%struct.C* %this, i8** %vtt, i1 zeroext) unnamed_addr C::C(bool) { } // PR6251 @@ -39,7 +39,7 @@ struct D : B, C { D(); }; -// CHECK: define void @_ZN6PR62511DC1Ev(%"struct.PR6251::D"* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN6PR62511DC1Ev(%"struct.PR6251::D"* %this) unnamed_addr // CHECK: call void @_ZN6PR62511AIcEC2Ev // CHECK-NOT: call void @_ZN6PR62511AIcEC2Ev // CHECK: ret void diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp index 7ef50b2..ae3704f 100644 --- a/test/CodeGenCXX/virtual-destructor-calls.cpp +++ b/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s struct Member { ~Member(); @@ -21,12 +21,12 @@ struct B : A { // CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev // Deleting dtor: defers to the complete dtor. -// CHECK: define void @_ZN1BD0Ev(%struct.B* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1BD0Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN1BD1Ev // CHECK: call void @_ZdlPv // Base dtor: actually calls A's base dtor. -// CHECK: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN6MemberD1Ev // CHECK: call void @_ZN1AD2Ev @@ -41,7 +41,7 @@ C::~C() { } // Complete dtor: just an alias (checked above). // Deleting dtor: defers to the complete dtor. -// CHECK: define void @_ZN1CD0Ev(%struct.C* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1CD0Ev(%struct.C* %this) unnamed_addr // CHECK: call void @_ZN1CD1Ev // CHECK: call void @_ZdlPv diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp index afa658f..624c89d 100644 --- a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp +++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp @@ -9,7 +9,7 @@ struct B { void B::f() { } -// CHECK: define i32 @_ZN1D1gEv(%struct.D* %this) +// CHECK-LABEL: define i32 @_ZN1D1gEv(%struct.D* %this) // CHECK: declare void @_ZN1B1gEv() struct C; diff --git a/test/CodeGenCXX/visibility-hidden-extern-templates.cpp b/test/CodeGenCXX/visibility-hidden-extern-templates.cpp index 7629b77..549e674 100644 --- a/test/CodeGenCXX/visibility-hidden-extern-templates.cpp +++ b/test/CodeGenCXX/visibility-hidden-extern-templates.cpp @@ -14,13 +14,13 @@ extern template struct X<char>; // <rdar://problem/8109763> void test_X(X<int> xi, X<char> xc) { - // CHECK: define weak_odr hidden void @_ZN1XIiE1fEv + // CHECK-LABEL: define weak_odr hidden void @_ZN1XIiE1fEv xi.f(); - // CHECK: define weak_odr hidden void @_ZN1XIiE1gEv + // CHECK-LABEL: define weak_odr hidden void @_ZN1XIiE1gEv xi.g(); // CHECK: declare void @_ZN1XIcE1fEv xc.f(); - // CHECK: define available_externally void @_ZN1XIcE1gEv + // CHECK-LABEL: define available_externally void @_ZN1XIcE1gEv xc.g(); } diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp index e5bc743..7c0757b 100644 --- a/test/CodeGenCXX/visibility-inlines-hidden.cpp +++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp @@ -37,31 +37,31 @@ struct __attribute__((visibility("default"))) X2 { extern template struct X1<float>; void use(X0 *x0, X1<int> *x1, X2 *x2, X1<float> *x3) { - // CHECK: define linkonce_odr void @_ZN2X02f1Ev + // CHECK-LABEL: define linkonce_odr void @_ZN2X02f1Ev x0->f1(); - // CHECK: define linkonce_odr hidden void @_ZN2X02f2Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f2Ev x0->f2(); - // CHECK: define linkonce_odr hidden void @_ZN2X02f3Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f3Ev x0->f3(); - // CHECK: define linkonce_odr hidden void @_ZN2X02f5Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f5Ev X0::f5(); - // CHECK: define linkonce_odr hidden void @_ZN2X02f6Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X02f6Ev x0->X0::f6(); - // CHECK: define linkonce_odr void @_ZN2X1IiE2f1Ev + // CHECK-LABEL: define linkonce_odr void @_ZN2X1IiE2f1Ev x1->f1(); - // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f2Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f2Ev x1->f2(); - // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f3Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f3Ev x1->f3(); - // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f4Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f4Ev x1->f4(); - // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f5Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f5Ev X1<int>::f5(); - // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f6Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X1IiE2f6Ev x1->X1::f6(); - // CHECK: define linkonce_odr hidden void @_ZN2X22f2Ev + // CHECK-LABEL: define linkonce_odr hidden void @_ZN2X22f2Ev x2->f2(); - // CHECK: define available_externally void @_ZN2X1IfE2f2Ev + // CHECK-LABEL: define available_externally void @_ZN2X1IfE2f2Ev x3->f2(); } @@ -95,7 +95,7 @@ namespace test2 { ns::foo<arg>(); } - // CHECK: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv() + // CHECK-LABEL: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv() } namespace PR11642 { @@ -106,7 +106,7 @@ namespace PR11642 { }; extern template class Foo<int>; template class Foo<int>; - // CHECK: define weak_odr i32 @_ZN7PR116423FooIiE3fooEi + // CHECK-LABEL: define weak_odr i32 @_ZN7PR116423FooIiE3fooEi } // Test that clang implements the new gcc behaviour for inline functions. @@ -122,9 +122,9 @@ namespace test3 { foo(); zed<int>(); } - // CHECK: define weak_odr void @_ZN5test33zedIfEEvv - // CHECK: define linkonce_odr hidden void @_ZN5test33fooEv - // CHECK: define linkonce_odr hidden void @_ZN5test33zedIiEEvv + // CHECK-LABEL: define weak_odr void @_ZN5test33zedIfEEvv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN5test33fooEv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN5test33zedIiEEvv } namespace test4 { @@ -133,7 +133,7 @@ namespace test4 { void bar() { foo(); } - // CHECK: define available_externally void @_ZN5test43fooE + // CHECK-LABEL: define available_externally void @_ZN5test43fooE } namespace test5 { diff --git a/test/CodeGenCXX/visibility-ms-compat.cpp b/test/CodeGenCXX/visibility-ms-compat.cpp index 58a8fed..25446cd 100644 --- a/test/CodeGenCXX/visibility-ms-compat.cpp +++ b/test/CodeGenCXX/visibility-ms-compat.cpp @@ -22,7 +22,7 @@ namespace test0 { }; void A::foo() { bar(); } - // CHECK: define hidden void @_ZN5test01A3fooEv() + // CHECK-LABEL: define hidden void @_ZN5test01A3fooEv() // CHECK: declare void @_ZN5test01A3barEv() const std::type_info &ti = typeid(A); @@ -38,7 +38,7 @@ namespace test1 { }; void A::foo() { bar(); } - // CHECK: define hidden void @_ZN5test11A3fooEv() + // CHECK-LABEL: define hidden void @_ZN5test11A3fooEv() // CHECK: declare hidden void @_ZN5test11A3barEv() const std::type_info &ti = typeid(A); @@ -54,7 +54,7 @@ namespace test2 { }; void A::foo() { bar(); } - // CHECK: define void @_ZN5test21A3fooEv() + // CHECK-LABEL: define void @_ZN5test21A3fooEv() // CHECK: declare void @_ZN5test21A3barEv() const std::type_info &ti = typeid(A); @@ -71,7 +71,7 @@ namespace test3 { }; template void B<A>::foo(); - // CHECK: define weak_odr hidden void @_ZN5test31BINS_1AEE3fooEv() + // CHECK-LABEL: define weak_odr hidden void @_ZN5test31BINS_1AEE3fooEv() // CHECK: declare void @_ZN5test31BINS_1AEE3barEv() const std::type_info &ti = typeid(B<A>); @@ -87,7 +87,7 @@ namespace test4 { }; template void B<A>::foo(); - // CHECK: define weak_odr void @_ZN5test41BINS_1AEE3fooEv() + // CHECK-LABEL: define weak_odr void @_ZN5test41BINS_1AEE3fooEv() // CHECK: declare void @_ZN5test41BINS_1AEE3barEv() const std::type_info &ti = typeid(B<A>); @@ -103,7 +103,7 @@ namespace test5 { }; template void B<A>::foo(); - // CHECK: define weak_odr hidden void @_ZN5test51BINS_1AEE3fooEv() + // CHECK-LABEL: define weak_odr hidden void @_ZN5test51BINS_1AEE3fooEv() // CHECK: declare hidden void @_ZN5test51BINS_1AEE3barEv() const std::type_info &ti = typeid(B<A>); diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp index 87add44..1c4d5bb 100644 --- a/test/CodeGenCXX/visibility.cpp +++ b/test/CodeGenCXX/visibility.cpp @@ -139,12 +139,16 @@ namespace test27 { // CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64 // CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global // CHECK-HIDDEN: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr hidden global i64 +// CHECK: @_ZZN6test681fC1EvE4test = linkonce_odr global +// CHECK: @_ZGVZN6test681fC1EvE4test = linkonce_odr global +// CHECK-HIDDEN: @_ZZN6test681fC1EvE4test = linkonce_odr hidden global +// CHECK-HIDDEN: @_ZGVZN6test681fC1EvE4test = linkonce_odr hidden global // CHECK-HIDDEN: @_ZTVN6Test161AIcEE = external unnamed_addr constant // CHECK-HIDDEN: @_ZTTN6Test161AIcEE = external unnamed_addr constant // CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden unnamed_addr constant namespace Test1 { - // CHECK: define hidden void @_ZN5Test11fEv + // CHECK-LABEL: define hidden void @_ZN5Test11fEv void HIDDEN f() { } } @@ -155,7 +159,7 @@ namespace Test2 { }; // A::f is a member function of a hidden class. - // CHECK: define hidden void @_ZN5Test21A1fEv + // CHECK-LABEL: define hidden void @_ZN5Test21A1fEv void A::f() { } } @@ -167,7 +171,7 @@ namespace Test3 { }; // B is a nested class where its parent class is hidden. - // CHECK: define hidden void @_ZN5Test31A1B1fEv + // CHECK-LABEL: define hidden void @_ZN5Test31A1B1fEv void A::B::f() { } } @@ -175,7 +179,7 @@ namespace Test4 HIDDEN { int VariableInHiddenNamespace = 10; // Test4::g is in a hidden namespace. - // CHECK: define hidden void @_ZN5Test41gEv + // CHECK-LABEL: define hidden void @_ZN5Test41gEv void g() { } struct DEFAULT A { @@ -183,7 +187,7 @@ namespace Test4 HIDDEN { }; // A has default visibility. - // CHECK: define void @_ZN5Test41A1fEv + // CHECK-LABEL: define void @_ZN5Test41A1fEv void A::f() { } } @@ -191,13 +195,13 @@ namespace Test5 { namespace NS HIDDEN { // f is in NS which is hidden. - // CHECK: define hidden void @_ZN5Test52NS1fEv() + // CHECK-LABEL: define hidden void @_ZN5Test52NS1fEv() void f() { } } namespace NS { // g is in NS, but this NS decl is not hidden. - // CHECK: define void @_ZN5Test52NS1gEv + // CHECK-LABEL: define void @_ZN5Test52NS1gEv void g() { } } } @@ -231,7 +235,7 @@ namespace Test7 { class B : public A {}; B b; // top of file - // CHECK: define linkonce_odr hidden void @_ZN5Test74ArefILZNS_1aEEE3fooEv() + // CHECK-LABEL: define linkonce_odr hidden void @_ZN5Test74ArefILZNS_1aEEE3fooEv() void test() { Aref<a>::foo(); } @@ -240,7 +244,7 @@ namespace Test7 { namespace Test8 { void foo(); void bar() {} - // CHECK-HIDDEN: define hidden void @_ZN5Test83barEv() + // CHECK-HIDDEN-LABEL: define hidden void @_ZN5Test83barEv() // CHECK-HIDDEN: declare void @_ZN5Test83fooEv() void test() { @@ -256,8 +260,8 @@ namespace Test9 { void DEFAULT test9_fun(struct A *a) { } struct A DEFAULT test9_var; // above } - // CHECK: define void @test9_fun( - // CHECK-HIDDEN: define void @test9_fun( + // CHECK-LABEL: define void @test9_fun( + // CHECK-HIDDEN-LABEL: define void @test9_fun( void test() { A a = test9_var; @@ -273,8 +277,8 @@ namespace Test10 { void foo(A*); }; - // CHECK: define void @_ZN6Test101B3fooEPNS_1AE( - // CHECK-HIDDEN: define void @_ZN6Test101B3fooEPNS_1AE( + // CHECK-LABEL: define void @_ZN6Test101B3fooEPNS_1AE( + // CHECK-HIDDEN-LABEL: define void @_ZN6Test101B3fooEPNS_1AE( void B::foo(A*) {} } @@ -291,10 +295,10 @@ namespace Test11 { a.bar(); } - // CHECK: define linkonce_odr void @_ZN6Test111A3fooEv( - // CHECK: define linkonce_odr void @_ZN6Test111A3barEv( - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6Test111A3fooEv( - // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test111A3barEv( + // CHECK-LABEL: define linkonce_odr void @_ZN6Test111A3fooEv( + // CHECK-LABEL: define linkonce_odr void @_ZN6Test111A3barEv( + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6Test111A3fooEv( + // CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6Test111A3barEv( } // Tested at top of file. @@ -481,7 +485,7 @@ namespace Test20 { static void test1(); }; - // CHECK: define hidden void @_ZN6Test201AILj0EE5test0Ev() + // CHECK-LABEL: define hidden void @_ZN6Test201AILj0EE5test0Ev() void A<0>::test0() {} // CHECK: declare hidden void @_ZN6Test201AILj0EE5test1Ev() @@ -495,7 +499,7 @@ namespace Test20 { static void test3(); }; - // CHECK: define void @_ZN6Test201AILj1EE5test2Ev() + // CHECK-LABEL: define void @_ZN6Test201AILj1EE5test2Ev() void A<1>::test2() {} // CHECK: declare void @_ZN6Test201AILj1EE5test3Ev() @@ -511,7 +515,7 @@ namespace Test20 { static void test5(); }; - // CHECK: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev() + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev() void test4() { B<A<2> >::test4(); } @@ -529,7 +533,7 @@ namespace test21 { DEFAULT void foo() {} }; - // CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv( + // CHECK-LABEL: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv( template void A<en>::foo(); } @@ -556,13 +560,13 @@ namespace test22 { B<A2>::bar(); } // CHECK: declare void @_ZN6test221BINS_2A1EE3fooEv() - // CHECK: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK-LABEL: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() // CHECK: declare void @_ZN6test221BINS_2A2EE3fooEv() - // CHECK: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv() + // CHECK-LABEL: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv() // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A1EE3fooEv() - // CHECK-HIDDEN: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv() - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv() + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv() } namespace PR10113 { @@ -573,14 +577,14 @@ namespace PR10113 { }; } template class foo::bar<char>; - // CHECK: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv - // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv + // CHECK-LABEL: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv struct zed { }; template class foo::bar<zed>; - // CHECK: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN7PR101133foo3barINS_3zedEE3zedEv + // CHECK-LABEL: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN7PR101133foo3barINS_3zedEE3zedEv } namespace PR11690 { @@ -589,13 +593,13 @@ namespace PR11690 { } }; template class DEFAULT Class<char>; - // CHECK: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv - // CHECK-HIDDEN: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv + // CHECK-LABEL: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv template<class T> void Method() {} template DEFAULT void Method<char>(); - // CHECK: define weak_odr void @_ZN7PR116906MethodIcEEvv - // CHECK-HIDDEN: define weak_odr void @_ZN7PR116906MethodIcEEvv + // CHECK-LABEL: define weak_odr void @_ZN7PR116906MethodIcEEvv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN7PR116906MethodIcEEvv } namespace PR11690_2 { @@ -610,8 +614,8 @@ namespace PR11690_2 { struct baz { }; template class foo::zed<baz>; - // CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv + // CHECK-LABEL: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv } namespace test23 { @@ -629,8 +633,8 @@ namespace test23 { X<A> y; y.f(); } - // CHECK: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv + // CHECK-LABEL: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv } namespace PR12001 { @@ -643,8 +647,8 @@ namespace PR12001 { void f() { Bind(Version()); } - // CHECK: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_ - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_ + // CHECK-LABEL: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_ + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_ } namespace test24 { @@ -659,8 +663,8 @@ namespace test24 { S s; s.mem<A>(); } - // CHECK: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv + // CHECK-LABEL: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv } namespace test26 { @@ -672,8 +676,8 @@ namespace test26 { template<> void C<int>::f() { } - // CHECK: define void @_ZN6test261CIiE1fEv - // CHECK-HIDDEN: define void @_ZN6test261CIiE1fEv + // CHECK-LABEL: define void @_ZN6test261CIiE1fEv + // CHECK-HIDDEN-LABEL: define void @_ZN6test261CIiE1fEv } namespace test31 { @@ -697,8 +701,8 @@ namespace test32 { }; void A::B::baz() { } - // CHECK: define void @_ZN6test321A1B3bazEv - // CHECK-HIDDEN: define void @_ZN6test321A1B3bazEv + // CHECK-LABEL: define void @_ZN6test321A1B3bazEv + // CHECK-HIDDEN-LABEL: define void @_ZN6test321A1B3bazEv } namespace test33 { @@ -709,8 +713,8 @@ namespace test33 { struct HIDDEN zed { }; template class DEFAULT foo<zed>; - // CHECK: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv - // CHECK-HIDDEN: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv + // CHECK-LABEL: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv } namespace test34 { @@ -719,8 +723,8 @@ namespace test34 { template<class T> void bar() {} template DEFAULT void bar<foo>(); - // CHECK: define weak_odr void @_ZN6test343barINS_3fooEEEvv - // CHECK-HIDDEN: define weak_odr void @_ZN6test343barINS_3fooEEEvv + // CHECK-LABEL: define weak_odr void @_ZN6test343barINS_3fooEEEvv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test343barINS_3fooEEEvv } namespace test35 { @@ -737,8 +741,8 @@ namespace test35 { template class foo<zed>; class DEFAULT zed { }; - // CHECK: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test353fooINS_3zedEE3barEv + // CHECK-LABEL: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test353fooINS_3zedEE3barEv } namespace test36 { @@ -749,8 +753,8 @@ namespace test36 { class DEFAULT S1 {}; struct HIDDEN S2 {}; template class foo<S1, S2>; - // CHECK: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv + // CHECK-LABEL: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv } namespace test37 { @@ -759,8 +763,8 @@ namespace test37 { template<class T> DEFAULT void bar() {} template DEFAULT void bar<foo>(); - // CHECK: define weak_odr void @_ZN6test373barINS_3fooEEEvv - // CHECK-HIDDEN: define weak_odr void @_ZN6test373barINS_3fooEEEvv + // CHECK-LABEL: define weak_odr void @_ZN6test373barINS_3fooEEEvv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test373barINS_3fooEEEvv } namespace test38 { @@ -771,8 +775,8 @@ namespace test38 { struct HIDDEN zed { }; template class foo<zed>; - // CHECK: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv + // CHECK-LABEL: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv } namespace test39 { @@ -790,19 +794,19 @@ namespace test39 { template void A<hidden_t>::B<hidden_t>::temp<default_t>(); template void A<hidden_t>::B<hidden_t>::temp<hidden_t>(); - // CHECK: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv - // CHECK: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv - // CHECK: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv + // CHECK-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv + // CHECK-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv + // CHECK-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv // GCC produces a default for this one. Why? - // CHECK: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv + // CHECK-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv - // CHECK-HIDDEN: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv - // CHECK-HIDDEN: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv // GCC produces a default for this one. Why? - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv } namespace test42 { @@ -817,8 +821,8 @@ namespace test42 { }; void bar<foo>::zed() { } - // CHECK: define void @_ZN6test423barINS_3fooEE3zedEv - // CHECK-HIDDEN: define void @_ZN6test423barINS_3fooEE3zedEv + // CHECK-LABEL: define void @_ZN6test423barINS_3fooEE3zedEv + // CHECK-HIDDEN-LABEL: define void @_ZN6test423barINS_3fooEE3zedEv } namespace test43 { @@ -830,8 +834,8 @@ namespace test43 { template <> DEFAULT void bar<foo>() { } - // CHECK: define void @_ZN6test433barINS_3fooEEEvv - // CHECK-HIDDEN: define void @_ZN6test433barINS_3fooEEEvv + // CHECK-LABEL: define void @_ZN6test433barINS_3fooEEEvv + // CHECK-HIDDEN-LABEL: define void @_ZN6test433barINS_3fooEEEvv } namespace test44 { @@ -844,8 +848,8 @@ namespace test44 { } template struct DEFAULT foo<bar>; foo<bar> x; - // CHECK: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev - // CHECK-HIDDEN: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev + // CHECK-LABEL: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev + // CHECK-HIDDEN-LABEL: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev } namespace test45 { @@ -861,8 +865,8 @@ namespace test45 { } template struct DEFAULT foo<int>::bar<zed>; foo<int>::bar<zed> x; - // CHECK: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev - // CHECK-HIDDEN: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev + // CHECK-LABEL: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev + // CHECK-HIDDEN-LABEL: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev } namespace test46 { @@ -876,8 +880,8 @@ namespace test46 { void zed() { foo<bar>(); } - // CHECK: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv - // CHECK-HIDDEN: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv + // CHECK-LABEL: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv + // CHECK-HIDDEN-LABEL: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv } namespace test47 { @@ -893,8 +897,8 @@ namespace test47 { void baz() { foo::bar<zed>(); } - // CHECK: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv - // CHECK-HIDDEN: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv + // CHECK-LABEL: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv + // CHECK-HIDDEN-LABEL: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv } namespace test49 { @@ -914,8 +918,8 @@ namespace test49 { }; template void bar::zed<&x>(); - // CHECK: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv + // CHECK-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv } namespace test50 { @@ -932,8 +936,8 @@ namespace test50 { } }; template void bar<&x>::zed(); - // CHECK: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv + // CHECK-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv } namespace test51 { @@ -948,8 +952,8 @@ namespace test51 { void DEFAULT zed() { } template void zed<&x>(); - // CHECK: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv - // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv + // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv + // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv } namespace test52 { @@ -967,8 +971,8 @@ namespace test52 { void f() { zed<nullptr>(); } - // CHECK: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv - // CHECK-HIDDEN: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv + // CHECK-LABEL: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv + // CHECK-HIDDEN-LABEL: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv } namespace test53 { @@ -1070,8 +1074,8 @@ namespace test58 { bar<foo>::zed(); } #pragma GCC visibility pop - // CHECK: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv } namespace test59 { @@ -1082,12 +1086,12 @@ namespace test59 { void test() {} void use() { test<&g, &f>(); - // CHECK: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv test<&f, &g>(); - // CHECK: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv } } @@ -1100,12 +1104,12 @@ namespace test60 { void test() {} void use() { test<a, b>(); - // CHECK: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv test<b, a>(); - // CHECK: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv - // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv } } @@ -1167,8 +1171,8 @@ namespace test63 { A::foo<E0>(); A::B<E0>::foo(); } - // CHECK: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv() - // CHECK: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv() + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv() + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv() } // Don't ignore the visibility of template arguments just because we @@ -1180,7 +1184,7 @@ namespace test64 { }; template class B<A>; - // CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv() + // CHECK-LABEL: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv() } namespace test65 { @@ -1196,23 +1200,23 @@ namespace test65 { static void foo() {} }; - // CHECK: define void @_ZN6test651BINS_1AEE4funcEv() + // CHECK-LABEL: define void @_ZN6test651BINS_1AEE4funcEv() template <> DEFAULT void B<A>::func() {} - // CHECK: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv() + // CHECK-LABEL: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv() template <> template <> DEFAULT void B<A>::funcT2<A>() {} - // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv() - // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv() + // CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv() + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv() template <> template <class T> DEFAULT void B<A>::funcT1() {} - // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv() + // CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv() template <> struct DEFAULT B<A>::Inner { static void foo() {} }; - // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv() - // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv() + // CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv() + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv() template <> template <class U> struct DEFAULT B<A>::InnerT { static void foo() {} }; @@ -1236,8 +1240,8 @@ namespace test66 { class foo; class DEFAULT foo; template struct barT<foo>; - // CHECK: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv - // CHECK-HIDDEN: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv + // CHECK-LABEL: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv template <int* I> struct DEFAULT barI { @@ -1246,8 +1250,8 @@ namespace test66 { extern int I; extern int I DEFAULT; template struct barI<&I>; - // CHECK: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv - // CHECK-HIDDEN: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv + // CHECK-LABEL: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv typedef void (*fType)(void); template<fType F> @@ -1257,8 +1261,8 @@ namespace test66 { void F(); void F() DEFAULT; template struct barF<F>; - // CHECK: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv - // CHECK-HIDDEN: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv + // CHECK-LABEL: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv } namespace test67 { @@ -1274,6 +1278,34 @@ namespace test67 { class DEFAULT foo; template struct bar<foo>; - // CHECK: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv - // CHECK-HIDDEN: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv + // CHECK-LABEL: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv +} + +namespace test68 { + class A { public: ~A(); }; + class f { + public: + f() { + static A test; + } + }; + void g() { + f a; + } + // Check lines at top of file. +} + +namespace test69 { + // PR18174 + namespace foo { + void f(); + } + namespace foo { + void f() {}; + } + namespace foo __attribute__((visibility("hidden"))) { + } + // CHECK-LABEL: define void @_ZN6test693foo1fEv + // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv } diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp index b523c76..b22f21c 100644 --- a/test/CodeGenCXX/vla.cpp +++ b/test/CodeGenCXX/vla.cpp @@ -16,7 +16,7 @@ int f() { // rdar://problem/9506377 void test0(void *array, int n) { - // CHECK: define void @_Z5test0Pvi( + // CHECK-LABEL: define void @_Z5test0Pvi( // CHECK: [[ARRAY:%.*]] = alloca i8*, align 8 // CHECK-NEXT: [[N:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[REF:%.*]] = alloca i16*, align 8 diff --git a/test/CodeGenCXX/volatile.cpp b/test/CodeGenCXX/volatile.cpp index 6ebb2f1..38c8829 100644 --- a/test/CodeGenCXX/volatile.cpp +++ b/test/CodeGenCXX/volatile.cpp @@ -11,7 +11,7 @@ namespace test0 { volatile A *array; - // CHECK: define void @_ZN5test04testENS_1AE( + // CHECK-LABEL: define void @_ZN5test04testENS_1AE( void test(A t) { // CHECK: [[ARR:%.*]] = load [[A:%.*]]** @_ZN5test05arrayE, align 8 // CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [[A]]* [[ARR]], i64 0 @@ -24,7 +24,7 @@ namespace test0 { namespace test1 { volatile int *x; - // CHECK: define void @_ZN5test14testEv() + // CHECK-LABEL: define void @_ZN5test14testEv() void test() { // CHECK: [[TMP:%.*]] = load i32** @_ZN5test11xE, align 8 // CHECK-NEXT: ret void diff --git a/test/CodeGenCXX/vtable-available-externally.cpp b/test/CodeGenCXX/vtable-available-externally.cpp index 693b36a..282bd2a 100644 --- a/test/CodeGenCXX/vtable-available-externally.cpp +++ b/test/CodeGenCXX/vtable-available-externally.cpp @@ -1,19 +1,11 @@ -// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o %t +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t // RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t // RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t // RUN: FileCheck --check-prefix=CHECK-TEST5 %s < %t -// RUN: FileCheck --check-prefix=CHECK-TEST7 %s < %t #include <typeinfo> -// Test1::A's key function (f) is not defined in this translation -// unit, but in order to devirtualize calls, we emit the v-table with -// available_externally linkage. -// -// There's no real reason to do this to the RTTI, though. - -// CHECK-TEST1: @_ZTVN5Test11AE = available_externally -// CHECK-TEST1: @_ZTIN5Test11AE = external constant i8* +// CHECK-TEST1: @_ZTVN5Test11AE = external unnamed_addr constant namespace Test1 { struct A { @@ -28,7 +20,7 @@ void f(A* a) { a->f(); }; -// CHECK: define void @_ZN5Test11gEv +// CHECK-LABEL: define void @_ZN5Test11gEv // CHECK: call void @_ZN5Test11A1fEv void g() { A a; @@ -106,7 +98,7 @@ void f() { } // PR9130, test that we emit a definition of A::f. -// CHECK-TEST5: define linkonce_odr void @_ZN5Test51A1fEv +// CHECK-TEST5-LABEL: define linkonce_odr void @_ZN5Test51A1fEv namespace Test5 { struct A { @@ -159,14 +151,4 @@ struct c11 : c10, c1{ struct c28 : virtual c11{ void f6 (); }; - -// CHECK-TEST7: define void @_ZN5Test79check_c28Ev -// CHECK-TEST7: call void @_ZN5Test73c282f6Ev -// CHECK-TEST7: ret void -void check_c28 () { - c28 obj; - c11 *ptr = &obj; - ptr->f6 (); -} - } diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp index 1e831d2..ca5384d 100644 --- a/test/CodeGenCXX/vtable-layout.cpp +++ b/test/CodeGenCXX/vtable-layout.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1 +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t // RUN: FileCheck --check-prefix=CHECK-1 %s < %t // RUN: FileCheck --check-prefix=CHECK-2 %s < %t // RUN: FileCheck --check-prefix=CHECK-3 %s < %t @@ -44,6 +44,7 @@ // RUN: FileCheck --check-prefix=CHECK-43 %s < %t // RUN: FileCheck --check-prefix=CHECK-44 %s < %t // RUN: FileCheck --check-prefix=CHECK-45 %s < %t +// RUN: FileCheck --check-prefix=CHECK-46 %s < %t // For now, just verify this doesn't crash. namespace test0 { @@ -61,6 +62,9 @@ namespace Test1 { // CHECK-1-NEXT: 1 | Test1::A RTTI // CHECK-1-NEXT: -- (Test1::A, 0) vtable address -- // CHECK-1-NEXT: 2 | void Test1::A::f() +// +// CHECK-1: VTable indices for 'Test1::A' (1 entries). +// CHECK-1-NEXT: 0 | void Test1::A::f() struct A { virtual void f(); }; @@ -82,6 +86,15 @@ namespace Test2 { // CHECK-2-NEXT: 6 | Test2::A::~A() [deleting] // CHECK-2-NEXT: 7 | void Test2::A::h() // CHECK-2-NEXT: 8 | Test2::A &Test2::A::operator=(const Test2::A &) +// +// CHECK-2: VTable indices for 'Test2::A' (7 entries). +// CHECK-2-NEXT: 0 | void Test2::A::f() +// CHECK-2-NEXT: 1 | void Test2::A::f() const +// CHECK-2-NEXT: 2 | Test2::A *Test2::A::g(int) +// CHECK-2-NEXT: 3 | Test2::A::~A() [complete] +// CHECK-2-NEXT: 4 | Test2::A::~A() [deleting] +// CHECK-2-NEXT: 5 | void Test2::A::h() +// CHECK-2-NEXT: 6 | Test2::A &Test2::A::operator=(const Test2::A &) struct A { virtual void f(); virtual void f() const; @@ -103,6 +116,12 @@ void A::f() { } // CHECK-3-NEXT: 3 | void Test2::B::g() [pure] // CHECK-3-NEXT: 4 | Test2::B::~B() [complete] [pure] // CHECK-3-NEXT: 5 | Test2::B::~B() [deleting] [pure] +// +// CHECK-3: VTable indices for 'Test2::B' (4 entries). +// CHECK-3-NEXT: 0 | void Test2::B::f() +// CHECK-3-NEXT: 1 | void Test2::B::g() +// CHECK-3-NEXT: 2 | Test2::B::~B() [complete] +// CHECK-3-NEXT: 3 | Test2::B::~B() [deleting] struct B { virtual void f(); virtual void g() = 0; @@ -123,6 +142,9 @@ namespace Test3 { // CHECK-4-NEXT: 1 | Test3::A RTTI // CHECK-4-NEXT: -- (Test3::A, 0) vtable address -- // CHECK-4-NEXT: 2 | void Test3::A::f() +// +// CHECK-4: VTable indices for 'Test3::A' (1 entries). +// CHECK-4-NEXT: 0 | void Test3::A::f() struct A { virtual void f(); }; @@ -135,6 +157,10 @@ void A::f() { } // CHECK-5-NEXT: -- (Test3::B, 0) vtable address -- // CHECK-5-NEXT: 2 | void Test3::B::f() // CHECK-5-NEXT: 3 | void Test3::B::g() +// +// CHECK-5: VTable indices for 'Test3::B' (2 entries). +// CHECK-5-NEXT: 0 | void Test3::B::f() +// CHECK-5-NEXT: 1 | void Test3::B::g() struct B : A { virtual void f(); virtual void g(); @@ -149,6 +175,10 @@ void B::f() { } // CHECK-6-NEXT: 2 | void Test3::A::f() // CHECK-6-NEXT: 3 | void Test3::C::g() // CHECK-6-NEXT: 4 | void Test3::C::h() +// +// CHECK-6: VTable indices for 'Test3::C' (2 entries). +// CHECK-6-NEXT: 1 | void Test3::C::g() +// CHECK-6-NEXT: 2 | void Test3::C::h() struct C : A { virtual void g(); virtual void h(); @@ -164,6 +194,11 @@ void C::g() { } // CHECK-7-NEXT: 2 | void Test3::D::f() // CHECK-7-NEXT: 3 | void Test3::D::g() // CHECK-7-NEXT: 4 | void Test3::D::h() +// +// CHECK-7: VTable indices for 'Test3::D' (3 entries). +// CHECK-7-NEXT: 0 | void Test3::D::f() +// CHECK-7-NEXT: 1 | void Test3::D::g() +// CHECK-7-NEXT: 2 | void Test3::D::h() struct D : B { virtual void f(); virtual void g(); @@ -193,7 +228,9 @@ struct A { // CHECK-8-NEXT: 2 | Test4::R3 *Test4::B::f() // CHECK-8-NEXT: [return adjustment: 4 non-virtual] // CHECK-8-NEXT: 3 | Test4::R3 *Test4::B::f() - +// +// CHECK-8: VTable indices for 'Test4::B' (1 entries). +// CHECK-8-NEXT: 1 | Test4::R3 *Test4::B::f() struct B : A { virtual R3 *f(); }; @@ -215,6 +252,9 @@ struct C { // CHECK-9-NEXT: 2 | Test4::V2 *Test4::D::f() // CHECK-9-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] // CHECK-9-NEXT: 3 | Test4::V2 *Test4::D::f() +// +// CHECK-9: VTable indices for 'Test4::D' (1 entries). +// CHECK-9-NEXT: 1 | Test4::V2 *Test4::D::f() struct D : C { virtual V2 *f(); }; @@ -231,7 +271,9 @@ struct V3 : virtual R3 { int r3; }; // CHECK-10-NEXT: 2 | Test4::V3 *Test4::E::f() // CHECK-10-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset] // CHECK-10-NEXT: 3 | Test4::V3 *Test4::E::f() - +// +// CHECK-10: VTable indices for 'Test4::E' (1 entries). +// CHECK-10-NEXT: 1 | Test4::V3 *Test4::E::f() struct E : A { virtual V3 *f(); }; @@ -247,6 +289,10 @@ V3 *E::f() { return 0;} // CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f() [pure] // CHECK-11-NEXT: 3 | void Test4::F::g() // CHECK-11-NEXT: 4 | Test4::R3 *Test4::F::f() [pure] +// +// CHECK-11: VTable indices for 'Test4::F' (2 entries). +// CHECK-11-NEXT: 1 | void Test4::F::g() +// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f() struct F : A { virtual void g(); virtual R3 *f() = 0; @@ -289,6 +335,9 @@ struct B2 : A { // CHECK-12-NEXT: -- (Test5::B2, 16) vtable address -- // CHECK-12-NEXT: 7 | void Test5::A::f() // CHECK-12-NEXT: 8 | void Test5::B2::g() +// +// CHECK-12: VTable indices for 'Test5::C' (1 entries). +// CHECK-12-NEXT: 2 | void Test5::C::h() struct C : B1, B2 { virtual void h(); }; @@ -319,6 +368,9 @@ struct A2 { // CHECK-13-NEXT: -- (Test6::A2, 16) vtable address -- // CHECK-13-NEXT: 5 | void Test6::C::f() // CHECK-13-NEXT: [this adjustment: -16 non-virtual] +// +// CHECK-13: VTable indices for 'Test6::C' (1 entries). +// CHECK-13-NEXT: 0 | void Test6::C::f() struct C : A1, A2 { virtual void f(); }; @@ -360,6 +412,9 @@ struct C { virtual void c(); }; // CHECK-14-NEXT: -- (Test7::B2, 24) vtable address -- // CHECK-14-NEXT: 9 | void Test7::D::f() // CHECK-14-NEXT: [this adjustment: -24 non-virtual] +// +// CHECK-14: VTable indices for 'Test7::D' (1 entries). +// CHECK-14-NEXT: 1 | void Test7::D::f() struct D : C, B1, B2 { virtual void f(); }; @@ -379,7 +434,10 @@ struct A { }; // CHECK-15-NEXT: 1 | Test8::B RTTI // CHECK-15-NEXT: -- (Test8::B, 0) vtable address -- // CHECK-15-NEXT: 2 | void Test8::B::f() -struct B : A { +// +// CHECK-15: VTable indices for 'Test8::B' (1 entries). +// CHECK-15-NEXT: 0 | void Test8::B::f() +struct B : A { virtual void f(); }; void B::f() { } @@ -400,6 +458,9 @@ struct A2 { int a2; }; // CHECK-16-NEXT: 3 | Test9::B RTTI // CHECK-16-NEXT: -- (Test9::B, 0) vtable address -- // CHECK-16-NEXT: 4 | void Test9::B::f() +// +// CHECK-16: VTable indices for 'Test9::B' (1 entries). +// CHECK-16-NEXT: 0 | void Test9::B::f() struct B : virtual A1, virtual A2 { int b; @@ -430,6 +491,9 @@ struct A2 { virtual void a2(); }; // CHECK-17-NEXT: 5 | Test10::C RTTI // CHECK-17-NEXT: -- (Test10::A2, 8) vtable address -- // CHECK-17-NEXT: 6 | void Test10::A2::a2() +// +// CHECK-17: VTable indices for 'Test10::C' (1 entries). +// CHECK-17-NEXT: 1 | void Test10::C::f() struct B : A1, A2 { int b; }; @@ -461,6 +525,9 @@ struct B : A1, virtual A2 { // CHECK-18-NEXT: 5 | vbase_offset (16) // CHECK-18-NEXT: 6 | offset_to_top (-8) // CHECK-18-NEXT: 7 | Test11::C RTTI +// +// CHECK-18: VTable indices for 'Test11::C' (1 entries). +// CHECK-18-NEXT: 0 | void Test11::C::f() struct C : virtual B { virtual void f(); }; @@ -498,6 +565,10 @@ namespace Test12 { // CHECK-19-NEXT: 17 | Test12::B RTTI // CHECK-19-NEXT: -- (Test12::A3, 40) vtable address -- // CHECK-19-NEXT: 18 | void Test12::A3::a3() +// +// CHECK-19: VTable indices for 'Test12::B' (2 entries). +// CHECK-19-NEXT: 0 | void Test12::B::f() +// CHECK-19-NEXT: 1 | void Test12::B::a() struct A1 { virtual void a1(); int a; @@ -548,6 +619,9 @@ struct B : virtual A { // CHECK-20-NEXT: -- (Test13::B, 0) vtable address -- // CHECK-20-NEXT: -- (Test13::C, 0) vtable address -- // CHECK-20-NEXT: 5 | void Test13::C::f() +// +// CHECK-20: VTable indices for 'Test13::C' (1 entries). +// CHECK-20-NEXT: 0 | void Test13::C::f() struct C : virtual B, virtual A { virtual void f(); }; @@ -577,6 +651,9 @@ struct C : virtual B { }; // CHECK-21-NEXT: -- (Test14::C, 0) vtable address -- // CHECK-21-NEXT: -- (Test14::D, 0) vtable address -- // CHECK-21-NEXT: 4 | void Test14::D::f() +// +// CHECK-21: VTable indices for 'Test14::D' (1 entries). +// CHECK-21-NEXT: 0 | void Test14::D::f() struct D : C, virtual B { virtual void f(); }; @@ -608,6 +685,9 @@ struct C : virtual B { }; // CHECK-22-NEXT: -- (Test15::B, 8) vtable address -- // CHECK-22-NEXT: -- (Test15::C, 8) vtable address -- // CHECK-22-NEXT: 10 | void Test15::B::b() +// +// CHECK-22: VTable indices for 'Test15::D' (1 entries). +// CHECK-22-NEXT: 1 | void Test15::D::f() struct D : A, virtual B, virtual C { virtual void f(); }; @@ -648,6 +728,11 @@ struct C : A, B { virtual ~C(); }; // CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] // CHECK-23-NEXT: 14 | Test16::D::~D() [deleting] // CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] +// +// CHECK-23: VTable indices for 'Test16::D' (3 entries). +// CHECK-23-NEXT: 0 | void Test16::D::f() +// CHECK-23-NEXT: 1 | Test16::D::~D() [complete] +// CHECK-23-NEXT: 2 | Test16::D::~D() [deleting] struct D : virtual C { virtual void f(); }; @@ -683,6 +768,9 @@ struct D : virtual B, virtual C { virtual void f(); }; // CHECK-24-NEXT: -- (Test17::C, 8) vtable address -- // CHECK-24-NEXT: 12 | void Test17::E::f() // CHECK-24-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// +// CHECK-24: VTable indices for 'Test17::E' (1 entries). +// CHECK-24-NEXT: 0 | void Test17::E::f() class E : virtual D { virtual void f(); }; @@ -741,6 +829,10 @@ struct C : A, B { // CHECK-25-NEXT: 22 | void Test18::D::f() // CHECK-25-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset] // CHECK-25-NEXT: 23 | [unused] void Test18::C::g() +// +// CHECK-25: VTable indices for 'Test18::D' (2 entries). +// CHECK-25-NEXT: 0 | void Test18::D::f() +// CHECK-25-NEXT: 2 | void Test18::D::h() // CHECK-25: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries). // CHECK-25-NEXT: 0 | vbase_offset (0) @@ -848,6 +940,9 @@ struct C { // CHECK-26-NEXT: -- (Test19::A, 24) vtable address -- // CHECK-26-NEXT: 12 | void Test19::D::f() // CHECK-26-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// +// CHECK-26: VTable indices for 'Test19::D' (1 entries). +// CHECK-26-NEXT: 1 | void Test19::D::f() struct D : C, B, virtual A { virtual void f(); }; @@ -880,7 +975,11 @@ struct B : A { }; // CHECK-27-NEXT: -- (Test20::B, 8) vtable address -- // CHECK-27-NEXT: 7 | void Test20::C::f() [pure] // CHECK-27-NEXT: 8 | void Test20::A::g() -struct C : A, B { +// +// CHECK-27: VTable indices for 'Test20::C' (2 entries). +// CHECK-27-NEXT: 0 | void Test20::C::f() +// CHECK-27-NEXT: 2 | void Test20::C::h() +struct C : A, B { virtual void f() = 0; virtual void h(); }; @@ -931,6 +1030,9 @@ class E : virtual C { }; // CHECK-28-NEXT: Test21::C | -48 // CHECK-28-NEXT: Test21::D | -56 // CHECK-28-NEXT: Test21::E | -64 +// +// CHECK-28: VTable indices for 'Test21::F' (1 entries). +// CHECK-28-NEXT: 0 | void Test21::F::f() class F : virtual D, virtual E { virtual void f(); }; @@ -960,6 +1062,9 @@ struct V2 : virtual V1 { // CHECK-29-NEXT: 6 | offset_to_top (-16) // CHECK-29-NEXT: 7 | Test22::C RTTI // CHECK-29-NEXT: -- (Test22::V2, 16) vtable address -- +// +// CHECK-29: VTable indices for 'Test22::C' (1 entries). +// CHECK-29-NEXT: 0 | void Test22::C::f() // CHECK-29: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries). // CHECK-29-NEXT: 0 | vbase_offset (-4) @@ -1052,6 +1157,9 @@ struct C : virtual A { }; // CHECK-31-NEXT: 8 | Test24::D RTTI // CHECK-31-NEXT: -- (Test24::C, 8) vtable address -- // CHECK-31-NEXT: 9 | [unused] void Test24::D::f() +// +// CHECK-31: VTable indices for 'Test24::D' (1 entries). +// CHECK-31-NEXT: 0 | void Test24::D::f() // CHECK-31: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries). // CHECK-31-NEXT: 0 | vbase_offset (0) @@ -1108,6 +1216,9 @@ struct B : virtual V { }; // CHECK-32-NEXT: 9 | Test25::C RTTI // CHECK-32-NEXT: -- (Test25::B, 8) vtable address -- // CHECK-32-NEXT: 10 | [unused] void Test25::V::f() +// +// CHECK-32: VTable indices for 'Test25::C' (1 entries). +// CHECK-32-NEXT: 1 | void Test25::C::g() // CHECK-32: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries). // CHECK-32-NEXT: 0 | vbase_offset (0) @@ -1174,6 +1285,9 @@ struct C : virtual A { // CHECK-33-NEXT: -- (Test26::C, 8) vtable address -- // CHECK-33-NEXT: 13 | void Test26::A::a() // CHECK-33-NEXT: 14 | void Test26::C::b() +// +// CHECK-33: VTable indices for 'Test26::D' (1 entries). +// CHECK-33-NEXT: 1 | void Test26::D::d() // CHECK-33: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries). // CHECK-33-NEXT: 0 | vcall_offset (0) @@ -1232,6 +1346,9 @@ struct D : A, virtual B, C { // CHECK-34-NEXT: 11 | Test27::E RTTI // CHECK-34-NEXT: -- (Test27::B, 16) vtable address -- // CHECK-34-NEXT: 12 | void Test27::B::b() +// +// CHECK-34: VTable indices for 'Test27::E' (1 entries). +// CHECK-34-NEXT: 2 | void Test27::E::e() // CHECK-34: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries). // CHECK-34-NEXT: 0 | vbase_offset (16) @@ -1293,6 +1410,9 @@ struct D : virtual C { // CHECK-35-NEXT: 12 | Test28::E RTTI // CHECK-35-NEXT: -- (Test28::B, 16) vtable address -- // CHECK-35-NEXT: 13 | void Test28::B::b() +// +// CHECK-35: VTable indices for 'Test28::E' (1 entries). +// CHECK-35-NEXT : 0 | void Test28::E::e() // CHECK-35: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries). // CHECK-35-NEXT: 0 | vbase_offset (8) @@ -1342,6 +1462,9 @@ struct A { // CHECK-36-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] // CHECK-36-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] // CHECK-36-NEXT: 5 | Test29::V2 *Test29::B::f() +// +// CHECK-36: VTable indices for 'Test29::B' (1 entries). +// CHECK-36-NEXT: 1 | Test29::V2 *Test29::B::f() struct B : virtual A { virtual V2 *f(); }; @@ -1403,6 +1526,9 @@ struct C : A, virtual B { // CHECK-37-NEXT: -- (Test31::C, 8) vtable address -- // CHECK-37-NEXT: 10 | void Test31::D::f() // CHECK-37-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// +// CHECK-37: VTable indices for 'Test31::D' (1 entries). +// CHECK-37-NEXT: 0 | void Test31::D::f() struct D : virtual C { virtual void f(); }; @@ -1494,6 +1620,9 @@ struct E : A, D { // CHECK-39-NEXT: 28 | Test33::F RTTI // CHECK-39-NEXT: -- (Test33::B, 24) vtable address -- // CHECK-39-NEXT: 29 | void Test33::B::b() +// +// CHECK-39: VTable indices for 'Test33::F' (1 entries). +// CHECK-39-NEXT: 1 | void Test33::F::f() struct F : virtual E, A { virtual void f(); }; @@ -1631,12 +1760,15 @@ struct G : virtual E { }; // CHECK-41-NEXT: 29 | void Test35::C::c() // CHECK-41-NEXT: 30 | void Test35::D::d() // CHECK-41-NEXT: 31 | void Test35::E::e() - +// // CHECK-41: Virtual base offset offsets for 'Test35::H' (4 entries). // CHECK-41-NEXT: Test35::A | -32 // CHECK-41-NEXT: Test35::B | -24 // CHECK-41-NEXT: Test35::D | -56 // CHECK-41-NEXT: Test35::E | -64 +// +// CHECK-41: VTable indices for 'Test35::H' (1 entries). +// CHECK-41-NEXT: 2 | void Test35::H::h() struct H : F, G { virtual void h(); }; @@ -1676,6 +1808,9 @@ struct C : virtual A { // CHECK-42-NEXT: -- (Test36::B, 8) vtable address -- // CHECK-42-NEXT: 11 | void Test36::C::f() // CHECK-42-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// +// CHECK-42: VTable indices for 'Test36::D' (1 entries). +// CHECK-42-NEXT: 1 | void Test36::D::g() struct D : virtual B, C { virtual void g(); }; @@ -1721,6 +1856,10 @@ namespace Test38 { // CHECK-44-NEXT: -- (Test38::B, 0) vtable address -- // CHECK-44-NEXT: 5 | void *Test38::B::foo() // CHECK-44-NEXT: 6 | const void *Test38::B::foo() const + // + // CHECK-44: VTable indices for 'Test38::B' (2 entries). + // CHECK-44-NEXT: 0 | void *Test38::B::foo() + // CHECK-44-NEXT: 1 | const void *Test38::B::foo() const class B : virtual public A { void *foo(); const void *foo() const; @@ -1741,6 +1880,9 @@ namespace Test39 { // CHECK-45-NEXT: -- (Test39::B, 0) vtable address -- // CHECK-45-NEXT: 2 | void Test39::A::foo() [deleted] // CHECK-45-NEXT: 3 | void Test39::B::foo2() + // + // CHECK-45: VTable indices for 'Test39::B' (1 entries). + // CHECK-45-NEXT: 1 | void Test39::B::foo2() struct B: A { virtual void foo2(); }; @@ -1748,3 +1890,37 @@ namespace Test39 { void B::foo2() { } } + +namespace Test40 { + struct A { + virtual void foo() = 0; + }; + + struct B : public A { + virtual void foo(); + }; + + struct C: public B { + // CHECK-46: VTable indices for 'Test40::C' (8 entries). + // CHECK-46-NEXT: 1 | int Test40::C::f(int) + // CHECK-46-NEXT: 2 | int Test40::C::f() + // CHECK-46-NEXT: 3 | int Test40::C::g(int) + // CHECK-46-NEXT: 4 | int Test40::C::g() + // CHECK-46-NEXT: 5 | int Test40::C::h(int) + // CHECK-46-NEXT: 6 | int Test40::C::h() + // CHECK-46-NEXT: 7 | int Test40::C::i(int) + // CHECK-46-NEXT: 8 | int Test40::C::i() + virtual int f(int); + virtual int f(); + virtual int g(int); + virtual int g(); + virtual int h(int); + virtual int h(); + virtual int i(int); + virtual int i(); + }; + + class D : C {}; + + D d; +} diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp index b945e56..c17e333 100644 --- a/test/CodeGenCXX/vtable-linkage.cpp +++ b/test/CodeGenCXX/vtable-linkage.cpp @@ -1,24 +1,9 @@ // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -disable-llvm-optzns -O3 -emit-llvm -o %t.opt -// RUN: FileCheck --check-prefix=CHECK-1 %s < %t -// RUN: FileCheck --check-prefix=CHECK-2 %s < %t -// RUN: FileCheck --check-prefix=CHECK-2-HIDDEN %s < %t.hidden -// RUN: FileCheck --check-prefix=CHECK-3 %s < %t -// RUN: FileCheck --check-prefix=CHECK-4 %s < %t -// RUN: FileCheck --check-prefix=CHECK-5 %s < %t -// RUN: FileCheck --check-prefix=CHECK-5-HIDDEN %s < %t.hidden -// RUN: FileCheck --check-prefix=CHECK-6 %s < %t -// RUN: FileCheck --check-prefix=CHECK-6-HIDDEN %s < %t.hidden -// RUN: FileCheck --check-prefix=CHECK-7 %s < %t -// RUN: FileCheck --check-prefix=CHECK-8 %s < %t -// RUN: FileCheck --check-prefix=CHECK-9 %s < %t -// RUN: FileCheck --check-prefix=CHECK-9-OPT %s < %t.opt -// RUN: FileCheck --check-prefix=CHECK-10 %s < %t -// RUN: FileCheck --check-prefix=CHECK-10-OPT %s < %t.opt -// RUN: FileCheck --check-prefix=CHECK-11 %s < %t -// RUN: FileCheck --check-prefix=CHECK-12 %s < %t -// RUN: FileCheck --check-prefix=CHECK-13 %s < %t +// RUN: FileCheck --check-prefix=CHECK %s < %t +// RUN: FileCheck --check-prefix=CHECK-HIDDEN %s < %t.hidden +// RUN: FileCheck --check-prefix=CHECK-OPT %s < %t.opt namespace { struct A { @@ -102,96 +87,94 @@ void use_F() { // B has a key function that is not defined in this translation unit so its vtable // has external linkage. -// CHECK-1: @_ZTV1B = external unnamed_addr constant +// CHECK-DAG: @_ZTV1B = external unnamed_addr constant // C has no key function, so its vtable should have weak_odr linkage // and hidden visibility (rdar://problem/7523229). -// CHECK-2: @_ZTV1C = linkonce_odr unnamed_addr constant -// CHECK-2: @_ZTS1C = linkonce_odr constant -// CHECK-2: @_ZTI1C = linkonce_odr unnamed_addr constant -// CHECK-2: @_ZTT1C = linkonce_odr unnamed_addr constant -// CHECK-2-HIDDEN: @_ZTV1C = linkonce_odr hidden unnamed_addr constant -// CHECK-2-HIDDEN: @_ZTS1C = linkonce_odr constant -// CHECK-2-HIDDEN: @_ZTI1C = linkonce_odr hidden unnamed_addr constant -// CHECK-2-HIDDEN: @_ZTT1C = linkonce_odr hidden unnamed_addr constant +// CHECK-DAG: @_ZTV1C = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTS1C = linkonce_odr constant +// CHECK-DAG: @_ZTI1C = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTT1C = linkonce_odr unnamed_addr constant +// CHECK-HIDDEN-DAG: @_ZTV1C = linkonce_odr hidden unnamed_addr constant +// CHECK-HIDDEN-DAG: @_ZTS1C = linkonce_odr constant +// CHECK-HIDDEN-DAG: @_ZTI1C = linkonce_odr hidden unnamed_addr constant +// CHECK-HIDDEN-DAG: @_ZTT1C = linkonce_odr hidden unnamed_addr constant // D has a key function that is defined in this translation unit so its vtable is // defined in the translation unit. -// CHECK-3: @_ZTV1D = unnamed_addr constant -// CHECK-3: @_ZTS1D = constant -// CHECK-3: @_ZTI1D = unnamed_addr constant +// CHECK-DAG: @_ZTV1D = unnamed_addr constant +// CHECK-DAG: @_ZTS1D = constant +// CHECK-DAG: @_ZTI1D = unnamed_addr constant // E<char> is an explicit specialization with a key function defined // in this translation unit, so its vtable should have external // linkage. -// CHECK-4: @_ZTV1EIcE = unnamed_addr constant -// CHECK-4: @_ZTS1EIcE = constant -// CHECK-4: @_ZTI1EIcE = unnamed_addr constant +// CHECK-DAG: @_ZTV1EIcE = unnamed_addr constant +// CHECK-DAG: @_ZTS1EIcE = constant +// CHECK-DAG: @_ZTI1EIcE = unnamed_addr constant // E<short> is an explicit template instantiation with a key function // defined in this translation unit, so its vtable should have // weak_odr linkage. -// CHECK-5: @_ZTV1EIsE = weak_odr unnamed_addr constant -// CHECK-5: @_ZTS1EIsE = weak_odr constant -// CHECK-5: @_ZTI1EIsE = weak_odr unnamed_addr constant -// CHECK-5-HIDDEN: @_ZTV1EIsE = weak_odr unnamed_addr constant -// CHECK-5-HIDDEN: @_ZTS1EIsE = weak_odr constant -// CHECK-5-HIDDEN: @_ZTI1EIsE = weak_odr unnamed_addr constant +// CHECK-DAG: @_ZTV1EIsE = weak_odr unnamed_addr constant +// CHECK-DAG: @_ZTS1EIsE = weak_odr constant +// CHECK-DAG: @_ZTI1EIsE = weak_odr unnamed_addr constant +// CHECK-HIDDEN-DAG: @_ZTV1EIsE = weak_odr unnamed_addr constant +// CHECK-HIDDEN-DAG: @_ZTS1EIsE = weak_odr constant +// CHECK-HIDDEN-DAG: @_ZTI1EIsE = weak_odr unnamed_addr constant // F<short> is an explicit template instantiation without a key // function, so its vtable should have weak_odr linkage -// CHECK-6: @_ZTV1FIsE = weak_odr unnamed_addr constant -// CHECK-6: @_ZTS1FIsE = weak_odr constant -// CHECK-6: @_ZTI1FIsE = weak_odr unnamed_addr constant -// CHECK-6-HIDDEN: @_ZTV1FIsE = weak_odr unnamed_addr constant -// CHECK-6-HIDDEN: @_ZTS1FIsE = weak_odr constant -// CHECK-6-HIDDEN: @_ZTI1FIsE = weak_odr unnamed_addr constant +// CHECK-DAG: @_ZTV1FIsE = weak_odr unnamed_addr constant +// CHECK-DAG: @_ZTS1FIsE = weak_odr constant +// CHECK-DAG: @_ZTI1FIsE = weak_odr unnamed_addr constant +// CHECK-HIDDEN-DAG: @_ZTV1FIsE = weak_odr unnamed_addr constant +// CHECK-HIDDEN-DAG: @_ZTS1FIsE = weak_odr constant +// CHECK-HIDDEN-DAG: @_ZTI1FIsE = weak_odr unnamed_addr constant // E<long> is an implicit template instantiation with a key function // defined in this translation unit, so its vtable should have // linkonce_odr linkage. -// CHECK-7: @_ZTV1EIlE = linkonce_odr unnamed_addr constant -// CHECK-7: @_ZTS1EIlE = linkonce_odr constant -// CHECK-7: @_ZTI1EIlE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTV1EIlE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTS1EIlE = linkonce_odr constant +// CHECK-DAG: @_ZTI1EIlE = linkonce_odr unnamed_addr constant // F<long> is an implicit template instantiation with no key function, // so its vtable should have linkonce_odr linkage. -// CHECK-8: @_ZTV1FIlE = linkonce_odr unnamed_addr constant -// CHECK-8: @_ZTS1FIlE = linkonce_odr constant -// CHECK-8: @_ZTI1FIlE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTV1FIlE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTS1FIlE = linkonce_odr constant +// CHECK-DAG: @_ZTI1FIlE = linkonce_odr unnamed_addr constant // F<int> is an explicit template instantiation declaration without a // key function, so its vtable should have external linkage. -// CHECK-9: @_ZTV1FIiE = external unnamed_addr constant -// CHECK-9-OPT: @_ZTV1FIiE = available_externally unnamed_addr constant +// CHECK-DAG: @_ZTV1FIiE = external unnamed_addr constant +// CHECK-OPT-DAG: @_ZTV1FIiE = external unnamed_addr constant // E<int> is an explicit template instantiation declaration. It has a // key function that is not instantiated, so we should only reference // its vtable, not define it. -// CHECK-10: @_ZTV1EIiE = external unnamed_addr constant -// CHECK-10-OPT: @_ZTV1EIiE = available_externally unnamed_addr constant +// CHECK-DAG: @_ZTV1EIiE = external unnamed_addr constant +// CHECK-OPT-DAG: @_ZTV1EIiE = external unnamed_addr constant // The anonymous struct for e has no linkage, so the vtable should have // internal linkage. -// CHECK-11: @"_ZTV3$_0" = internal unnamed_addr constant -// CHECK-11: @"_ZTS3$_0" = internal constant -// CHECK-11: @"_ZTI3$_0" = internal unnamed_addr constant +// CHECK-DAG: @"_ZTV3$_0" = internal unnamed_addr constant +// CHECK-DAG: @"_ZTS3$_0" = internal constant +// CHECK-DAG: @"_ZTI3$_0" = internal unnamed_addr constant // The A vtable should have internal linkage since it is inside an anonymous // namespace. -// CHECK-12: @_ZTVN12_GLOBAL__N_11AE = internal unnamed_addr constant -// CHECK-12: @_ZTSN12_GLOBAL__N_11AE = internal constant -// CHECK-12: @_ZTIN12_GLOBAL__N_11AE = internal unnamed_addr constant +// CHECK-DAG: @_ZTVN12_GLOBAL__N_11AE = internal unnamed_addr constant +// CHECK-DAG: @_ZTSN12_GLOBAL__N_11AE = internal constant +// CHECK-DAG: @_ZTIN12_GLOBAL__N_11AE = internal unnamed_addr constant // F<char> is an explicit specialization without a key function, so // its vtable should have linkonce_odr linkage. -// CHECK-13: @_ZTV1FIcE = linkonce_odr unnamed_addr constant -// CHECK-13: @_ZTS1FIcE = linkonce_odr constant -// CHECK-13: @_ZTI1FIcE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTV1FIcE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTS1FIcE = linkonce_odr constant +// CHECK-DAG: @_ZTI1FIcE = linkonce_odr unnamed_addr constant -// RUN: FileCheck --check-prefix=CHECK-G %s < %t -// -// CHECK-G: @_ZTV1GIiE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTV1GIiE = linkonce_odr unnamed_addr constant template <typename T> class G { public: @@ -205,11 +188,9 @@ template <typename T> void G<T>::f0() {} void G_f0() { new G<int>(); } -// RUN: FileCheck --check-prefix=CHECK-H %s < %t - // H<int> has a key function without a body but it's a template instantiation // so its VTable must be emitted. -// CHECK-H: @_ZTV1HIiE = linkonce_odr unnamed_addr constant +// CHECK-DAG: @_ZTV1HIiE = linkonce_odr unnamed_addr constant template <typename T> class H { public: @@ -220,21 +201,15 @@ void use_H() { H<int> h; } -// RUN: FileCheck --check-prefix=CHECK-I %s < %t -// RUN: FileCheck --check-prefix=CHECK-I-OPT %s < %t.opt - // I<int> has an explicit instantiation declaration and needs a VTT and -// construction vtables. We emit the VTT available_externally, but point it at -// internal construction vtables because there is no way to form a reference to -// the real construction vtables. +// construction vtables. -// CHECK-I: @_ZTV1IIiE = external unnamed_addr constant -// CHECK-I: @_ZTT1IIiE = external unnamed_addr constant -// CHECK-I-NOT: @_ZTC1IIiE +// CHECK-DAG: @_ZTV1IIiE = external unnamed_addr constant +// CHECK-DAG: @_ZTT1IIiE = external unnamed_addr constant +// CHECK-NOT: @_ZTC1IIiE // -// CHECK-I-OPT: @_ZTV1IIiE = available_externally unnamed_addr constant -// CHECK-I-OPT: @_ZTT1IIiE = available_externally unnamed_addr constant {{.*}} @_ZTC1IIiE0_6VBase2 -// CHECK-I-OPT: @_ZTC1IIiE0_6VBase2 = internal unnamed_addr constant +// CHECK-OPT-DAG: @_ZTV1IIiE = external unnamed_addr constant +// CHECK-OPT-DAG: @_ZTT1IIiE = external unnamed_addr constant struct VBase1 { virtual void f(); }; struct VBase2 : virtual VBase1 {}; template<typename T> struct I : VBase2 {}; diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp index 9b1eaa5..85e08d8 100644 --- a/test/CodeGenCXX/vtable-pointer-initialization.cpp +++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp @@ -19,14 +19,14 @@ struct A : Base { Field field; }; -// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr // CHECK: call void @_ZN4BaseC2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldC1Ev( // CHECK: ret void A::A() { } -// CHECK: define void @_ZN1AD2Ev(%struct.A* %this) unnamed_addr +// CHECK-LABEL: define void @_ZN1AD2Ev(%struct.A* %this) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( @@ -41,16 +41,16 @@ struct B : Base { void f() { B b; } -// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN1BC2Ev( -// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( // CHECK: ret void -// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr +// CHECK-LABEL: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN4BaseC2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldC1Ev diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp index 4404de0..2c7234e 100644 --- a/test/CodeGenCXX/x86_32-arguments.cpp +++ b/test/CodeGenCXX/x86_32-arguments.cpp @@ -6,9 +6,9 @@ struct S { short s; }; -// CHECK: define void @_Z1fv(%struct.S* noalias sret % +// CHECK-LABEL: define void @_Z1fv(%struct.S* noalias sret % S f() { return S(); } -// CHECK: define void @_Z1f1S(%struct.S*) +// CHECK-LABEL: define void @_Z1f1S(%struct.S*) void f(S) { } // Non-trivial dtors, should both be passed indirectly. @@ -18,10 +18,10 @@ public: double c; }; -// CHECK: define void @_Z1gv(%class.C* noalias sret % +// CHECK-LABEL: define void @_Z1gv(%class.C* noalias sret % C g() { return C(); } -// CHECK: define void @_Z1f1C(%class.C*) +// CHECK-LABEL: define void @_Z1f1C(%class.C*) void f(C) { } @@ -29,7 +29,7 @@ void f(C) { } // PR7058 - Missing byval on MI thunk definition. -// CHECK: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite +// CHECK-LABEL: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite // ... // CHECK: %struct.CallSite* byval align 4 %CS) struct CallSite { @@ -57,38 +57,38 @@ void BasicAliasAnalysis::getModRefInfo(CallSite CS) { // // PR7098. -// CHECK: define i64 @_Z2f0v() +// CHECK-LABEL: define i64 @_Z2f0v() struct s0_0 { int x; }; struct s0_1 : s0_0 { int* y; }; s0_1 f0() { return s0_1(); } -// CHECK: define i32 @_Z2f1v() +// CHECK-LABEL: define i32 @_Z2f1v() struct s1_0 { int x; }; struct s1_1 : s1_0 { }; s1_1 f1() { return s1_1(); } -// CHECK: define double @_Z2f2v() +// CHECK-LABEL: define double @_Z2f2v() struct s2_0 { double x; }; struct s2_1 : s2_0 { }; s2_1 f2() { return s2_1(); } -// CHECK: define double @_Z2f3v() +// CHECK-LABEL: define double @_Z2f3v() struct s3_0 { }; struct s3_1 { double x; }; struct s3_2 : s3_0, s3_1 { }; s3_2 f3() { return s3_2(); } -// CHECK: define i64 @_Z2f4v() +// CHECK-LABEL: define i64 @_Z2f4v() struct s4_0 { float x; }; struct s4_1 { float x; }; struct s4_2 : s4_0, s4_1 { }; s4_2 f4() { return s4_2(); } -// CHECK: define i32* @_Z2f5v() +// CHECK-LABEL: define i32* @_Z2f5v() struct s5 { s5(); int &x; }; s5 f5() { return s5(); } -// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a) +// CHECK-LABEL: define i32 @_Z4f6_0M2s6i(i32 %a) // CHECK: define i64 @_Z4f6_1M2s6FivE({ i32, i32 }* byval align 4) // FIXME: It would be nice to avoid byval on the previous case. struct s6 {}; @@ -97,19 +97,19 @@ typedef int (s6::*s6_mfp)(); s6_mdp f6_0(s6_mdp a) { return a; } s6_mfp f6_1(s6_mfp a) { return a; } -// CHECK: define double @_Z2f7v() +// CHECK-LABEL: define double @_Z2f7v() struct s7_0 { unsigned : 0; }; struct s7_1 { double x; }; struct s7 : s7_0, s7_1 { }; s7 f7() { return s7(); } -// CHECK: define void @_Z2f8v(%struct.s8* noalias sret %agg.result) +// CHECK-LABEL: define void @_Z2f8v(%struct.s8* noalias sret %agg.result) struct s8_0 { }; struct s8_1 { double x; }; struct s8 { s8_0 a; s8_1 b; }; s8 f8() { return s8(); } -// CHECK: define void @_Z2f9v(%struct.s9* noalias sret %agg.result) +// CHECK-LABEL: define void @_Z2f9v(%struct.s9* noalias sret %agg.result) struct s9_0 { unsigned : 0; }; struct s9_1 { double x; }; struct s9 { s9_0 a; s9_1 b; }; diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp index 6721803..2172e08 100644 --- a/test/CodeGenCXX/x86_64-arguments.cpp +++ b/test/CodeGenCXX/x86_64-arguments.cpp @@ -3,28 +3,28 @@ // Basic base class test. struct f0_s0 { unsigned a; }; struct f0_s1 : public f0_s0 { void *b; }; -// CHECK: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1) +// CHECK-LABEL: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1) void f0(f0_s1 a0) { } // Check with two eight-bytes in base class. struct f1_s0 { unsigned a; unsigned b; float c; }; struct f1_s1 : public f1_s0 { float d;}; -// CHECK: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1) +// CHECK-LABEL: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1) void f1(f1_s1 a0) { } // Check with two eight-bytes in base class and merge. struct f2_s0 { unsigned a; unsigned b; float c; }; struct f2_s1 : public f2_s0 { char d;}; -// CHECK: define void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1) +// CHECK-LABEL: define void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1) void f2(f2_s1 a0) { } // PR5831 -// CHECK: define void @_Z2f34s3_1(i64 %x.coerce) +// CHECK-LABEL: define void @_Z2f34s3_1(i64 %x.coerce) struct s3_0 {}; struct s3_1 { struct s3_0 a; long b; }; void f3(struct s3_1 x) {} -// CHECK: define i64 @_Z4f4_0M2s4i(i64 %a) +// CHECK-LABEL: define i64 @_Z4f4_0M2s4i(i64 %a) // CHECK: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1) struct s4 {}; typedef int s4::* s4_mdp; @@ -41,7 +41,7 @@ struct StringRef { void AddKeyword(StringRef, int x); void foo() { - // CHECK: define void @_ZN6PR75233fooEv() + // CHECK-LABEL: define void @_ZN6PR75233fooEv() // CHECK: call void @_ZN6PR752310AddKeywordENS_9StringRefEi(i8* {{.*}}, i32 4) AddKeyword(StringRef(), 4); } @@ -54,7 +54,7 @@ namespace PR7742 { // Also rdar://8250764 struct c2 : public s2 {}; - // CHECK: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P) + // CHECK-LABEL: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P) c2 foo(c2 *P) { return c2(); } @@ -72,7 +72,7 @@ namespace PR5179 { B1 b1; }; - // CHECK: define i8* @_ZN6PR51793barENS_2B2E(i32* %b2.coerce) + // CHECK-LABEL: define i8* @_ZN6PR51793barENS_2B2E(i32* %b2.coerce) const void *bar(B2 b2) { return b2.b1.pa; } @@ -114,7 +114,7 @@ namespace test6 { int test(outer x) { return x.x + x.f; } - // CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1) + // CHECK-LABEL: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1) } namespace test7 { |