diff options
author | dim <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
commit | 554bcb69c2d785a011a30e7db87a36a87fe7db10 (patch) | |
tree | 9abb1a658a297776086f4e0dfa6ca533de02104e /test/CodeGenCXX | |
parent | bb67ca86b31f67faee50bd10c3b036d65751745a (diff) | |
download | FreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.zip FreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.tar.gz |
Vendor import of clang trunk r161861:
http://llvm.org/svn/llvm-project/cfe/trunk@161861
Diffstat (limited to 'test/CodeGenCXX')
72 files changed, 2443 insertions, 247 deletions
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp index a12ae53..8dc4f47 100644 --- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp +++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -179,3 +179,13 @@ namespace PR9683 { }; QueueEntry QE; } + +namespace PR13154 { + struct IndirectReferenceField { + struct { + float &x; + }; + IndirectReferenceField(float &x); + }; + IndirectReferenceField::IndirectReferenceField(float &xx) : x(xx) {} +} diff --git a/test/CodeGenCXX/block-in-ctor-dtor.cpp b/test/CodeGenCXX/block-in-ctor-dtor.cpp index e4389a4..4ee6b1c 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 @___ZN4ZoneC2Ev_block_invoke_ -// CHECK: define internal void @___ZN4ZoneD2Ev_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 @___ZN1XC1Ev_block_invoke_ +// CHECK: define internal void @___ZN1XC2Ev_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: define internal void @___ZN1XD2Ev_block_invoke_ diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp index eb54478..1500c0d 100644 --- a/test/CodeGenCXX/blocks.cpp +++ b/test/CodeGenCXX/blocks.cpp @@ -2,8 +2,8 @@ namespace test0 { // CHECK: define void @_ZN5test04testEi( - // CHECK: define internal void @__test_block_invoke_{{.*}}( - // CHECK: define internal void @__block_global_{{.*}}( + // CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}( + // CHECK: define internal void @___ZN5test04testEi_block_invoke_2{{.*}}( void test(int x) { ^{ ^{ (void) x; }; }; } @@ -119,7 +119,7 @@ namespace test4 { consume(^{ return foo(A()); }); } // CHECK: define void @_ZN5test44testEv() - // CHECK: define internal void @__test_block_invoke + // CHECK: define internal void @___ZN5test44testEv_block_invoke // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1 // CHECK-NEXT: bitcast i8* // CHECK-NEXT: call void @_ZN5test41AC1Ev([[A]]* [[TMP]]) diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp index dac0a0a..21e1a2b 100644 --- a/test/CodeGenCXX/class-layout.cpp +++ b/test/CodeGenCXX/class-layout.cpp @@ -77,3 +77,17 @@ namespace Test6 { class E : public B {}; E *e; } + +// <rdar://problem/11324125>: Make sure this doesn't crash. (It's okay +// if we start rejecting it at some point.) +namespace Test7 { + #pragma pack (1) + class A {}; + // CHECK: %"class.Test7::B" = type <{ i32 (...)**, %"class.Test7::A" }> + class B { + virtual ~B(); + A a; + }; + B* b; + #pragma pack () +} diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index 62a345a..db1bb41 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -49,6 +49,17 @@ namespace StructUnion { // CHECK: @_ZN11StructUnion1fE = global {{.*}} { i32 5 } D f; + + union E { + int a; + void *b = &f; + }; + + // CHECK: @_ZN11StructUnion1gE = global {{.*}} @_ZN11StructUnion1fE + E g; + + // CHECK: @_ZN11StructUnion1hE = global {{.*}} @_ZN11StructUnion1fE + E h = E(); } namespace BaseClass { @@ -110,6 +121,13 @@ namespace Array { }; // CHECK: @_ZN5Array1eE = constant {{.*}} { [4 x i8] c"foo\00", [4 x i8] c"x\00\00\00" } extern constexpr E e = E(); + + // PR13290 + struct F { constexpr F() : n(4) {} int n; }; + // CHECK: @_ZN5Array2f1E = global {{.*}} zeroinitializer + F f1[1][1][0] = { }; + // CHECK: @_ZN5Array2f2E = global {{.* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4 .* i32 4}} + F f2[2][2][2] = { }; } namespace MemberPtr { @@ -298,6 +316,20 @@ namespace VirtualMembers { static nsMemoryImpl sGlobalMemory; } +namespace PR13273 { + struct U { + int t; + U() = default; + }; + + struct S : U { + S() = default; + }; + + // CHECK: @_ZN7PR132731sE = {{.*}} zeroinitializer + extern const S s {}; +} + // Constant initialization tests go before this point, // dynamic initialization tests go after. diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp index 9f808f6..b33184e 100644 --- a/test/CodeGenCXX/constructor-init.cpp +++ b/test/CodeGenCXX/constructor-init.cpp @@ -131,6 +131,26 @@ namespace rdar9694300 { } } +// Check that we emit a zero initialization step for list-value-initialization +// which calls a trivial default constructor. +namespace PR13273 { + struct U { + int t; + U() = default; + }; + + struct S : U { + S() = default; + }; + + // CHECK: define {{.*}}@_ZN7PR132731fEv( + int f() { + // CHECK-NOT: } + // CHECK: llvm.memset{{.*}}i8 0 + return (new S{})->t; + } +} + template<typename T> struct X { X(const X &); diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp index f5684d9..ad6492f 100644 --- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp +++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp @@ -54,3 +54,14 @@ delegator::delegator(char) delegator::delegator(int) : delegator() {} + +namespace PR12890 { + class X { + int x; + X() = default; + X(int); + }; + X::X(int) : X() {} +} +// CHECK: define {{.*}} @_ZN7PR128901XC1Ei(%"class.PR12890::X"* %this, i32) +// CHECK: call void @llvm.memset.p0i8.{{i32|i64}}(i8* {{.*}}, i8 0, {{i32|i64}} 4, i32 4, i1 false) diff --git a/test/CodeGenCXX/cxx0x-initializer-constructors.cpp b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp new file mode 100644 index 0000000..48fbe85 --- /dev/null +++ b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s + +struct S { + S(int x) { } + S(int x, double y, double z) { } +}; + +void fn1() { + // CHECK: 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 + 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 + S sa[] { { 1 }, { 2 }, { 3 } }; + // CHECK: alloca [3 x %struct.S], align 1 + // CHECK: call void @_ZN1SC1Ei(%struct.S* %{{.+}}, i32 1) + // CHECK: call void @_ZN1SC1Ei(%struct.S* %{{.+}}, i32 2) + // CHECK: call void @_ZN1SC1Ei(%struct.S* %{{.+}}, i32 3) +} + +void fn4() { + // CHECK: 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) +} diff --git a/test/CodeGenCXX/cxx0x-initializer-references.cpp b/test/CodeGenCXX/cxx0x-initializer-references.cpp index 4c847b8..660b018 100644 --- a/test/CodeGenCXX/cxx0x-initializer-references.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-references.cpp @@ -28,6 +28,10 @@ namespace reference { // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** % A &ra1a = {a}; + using T = A&; + // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** % + A &ra1b = T{a}; + // CHECK-NEXT: ret } diff --git a/test/CodeGenCXX/cxx11-initializer-aggregate.cpp b/test/CodeGenCXX/cxx11-initializer-aggregate.cpp new file mode 100644 index 0000000..acc7782 --- /dev/null +++ b/test/CodeGenCXX/cxx11-initializer-aggregate.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s -triple x86_64-linux-gnu | FileCheck %s + +struct A { int a, b; int f(); }; + +// CHECK: define {{.*}}@_Z3fn1i( +int fn1(int x) { + // CHECK: %[[INITLIST:.*]] = alloca %struct.A + // CHECK: %[[A:.*]] = getelementptr inbounds %struct.A* %[[INITLIST]], i32 0, i32 0 + // CHECK: store i32 %{{.*}}, i32* %[[A]], align 4 + // CHECK: %[[B:.*]] = getelementptr inbounds %struct.A* %[[INITLIST]], i32 0, i32 1 + // CHECK: store i32 5, i32* %[[B]], align 4 + // CHECK: call i32 @_ZN1A1fEv(%struct.A* %[[INITLIST]]) + return A{x, 5}.f(); +} + +struct B { int &r; int &f() { return r; } }; + +// CHECK: define {{.*}}@_Z3fn2Ri( +int &fn2(int &v) { + // CHECK: %[[INITLIST2:.*]] = alloca %struct.B, align 8 + // CHECK: %[[R:.*]] = getelementptr inbounds %struct.B* %[[INITLIST2:.*]], i32 0, i32 0 + // CHECK: store i32* %{{.*}}, i32** %[[R]], align 8 + // CHECK: call i32* @_ZN1B1fEv(%struct.B* %[[INITLIST2:.*]]) + return B{v}.f(); +} diff --git a/test/CodeGenCXX/cxx11-vtable-key-function.cpp b/test/CodeGenCXX/cxx11-vtable-key-function.cpp new file mode 100644 index 0000000..cd2ab59 --- /dev/null +++ b/test/CodeGenCXX/cxx11-vtable-key-function.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -std=c++11 | FileCheck %s +// PR13424 + +namespace Test1 { +struct X { + virtual ~X(); // Key function. + virtual void f(); // Not a key function. +}; + +X::~X() = default; + +// Verify that the vtable is emitted. +// CHECK: @_ZTVN5Test11XE = unnamed_addr constant +} + +namespace Test2 { +struct X { + virtual ~X() = default; // Not a key function. + virtual void f(); // Key function. +}; + +void X::f() {} + +// Verify that the vtable is emitted. +// CHECK: @_ZTVN5Test21XE = unnamed_addr constant +} + +namespace Test3 { +struct X { + virtual ~X() = delete; // Not a key function. + virtual void f(); // Key function. +}; + +void X::f() {} + +// Verify that the vtable is emitted. +// CHECK: @_ZTVN5Test31XE = unnamed_addr constant +} diff --git a/test/CodeGenCXX/debug-info-artificial-arg.cpp b/test/CodeGenCXX/debug-info-artificial-arg.cpp index 92d1b16..35e5f27 100644 --- a/test/CodeGenCXX/debug-info-artificial-arg.cpp +++ b/test/CodeGenCXX/debug-info-artificial-arg.cpp @@ -23,8 +23,8 @@ int main(int argc, char **argv) { } // FIXME: The numbers are truly awful. -// CHECK: !18 = metadata !{i32 {{.*}}, i32 0, metadata !"", i32 0, i32 0, i64 64, i64 64, i64 0, i32 64, metadata !19} ; [ DW_TAG_pointer_type ] -// CHECK: !19 = metadata !{i32 {{.*}}, null, metadata !"A", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !20, i32 0, metadata !19, null} ; [ DW_TAG_class_type ] -// CHECK: metadata !19, metadata !"A", metadata !"A", metadata !"", metadata !6, i32 12, metadata !45, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !47, i32 12} ; [ DW_TAG_subprogram ] -// CHECK: metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !46, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] -// CHECK: !46 = metadata !{null, metadata !18, metadata !9, metadata !34} +// CHECK: !16 = metadata !{i32 {{.*}}, i32 0, metadata !"", i32 0, i32 0, i64 64, i64 64, i64 0, i32 64, metadata !17} ; [ DW_TAG_pointer_type ] +// CHECK: !17 = metadata !{i32 {{.*}}, null, metadata !"A", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !18, i32 0, metadata !17, null} ; [ DW_TAG_class_type ] +// CHECK: metadata !17, metadata !"A", metadata !"A", metadata !"", metadata !6, i32 12, metadata !43, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !45, i32 12} ; [ DW_TAG_subprogram ] +// CHECK: metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !44, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] +// CHECK: !44 = metadata !{null, metadata !16, metadata !9, metadata !32} diff --git a/test/CodeGenCXX/debug-info-cxx0x.cpp b/test/CodeGenCXX/debug-info-cxx0x.cpp index 37ccdb0..9d30375 100644 --- a/test/CodeGenCXX/debug-info-cxx0x.cpp +++ b/test/CodeGenCXX/debug-info-cxx0x.cpp @@ -6,3 +6,13 @@ namespace PR9414 { return x; } } + +// Don't crash. +namespace PR13570 { + template<typename T, typename U> struct P {}; + template<typename T> struct A { + template<typename U> static P<T,U> isa(U); + decltype(isa(int())) f() {} + }; + template struct A<int>; +} diff --git a/test/CodeGenCXX/debug-info-determinism.cpp b/test/CodeGenCXX/debug-info-determinism.cpp new file mode 100644 index 0000000..a96a14e --- /dev/null +++ b/test/CodeGenCXX/debug-info-determinism.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -S -emit-llvm -g -o %t1.ll %s +// RUN: %clang_cc1 -S -emit-llvm -g -o %t2.ll %s +// RUN: diff %t1.ll %t2.ll + +template <int N> struct C { + template <int M> int f() { + int arr[M] = {}; + return arr[M/2] + C<M/2>().template f<M-1>(); + } +}; +template <> template <> int C<0>::f<0>() { return 0; } +template <> template <> int C<0>::f<1>() { return 0; } +template <> template <> int C<1>::f<0>() { return 0; } +template <> template <> int C<1>::f<1>() { return 0; } + +int x = C<0>().f<64>(); diff --git a/test/CodeGenCXX/debug-info-enum-class.cpp b/test/CodeGenCXX/debug-info-enum-class.cpp new file mode 100644 index 0000000..6f88439 --- /dev/null +++ b/test/CodeGenCXX/debug-info-enum-class.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -std=c++11 %s -o - | FileCheck %s + +enum class A { A1=1 }; // underlying type is int by default +enum class B: unsigned long { B1=1 }; // underlying type is unsigned long +enum C { C1 = 1 }; +enum D : short; // enum forward declaration +A a; +B b; +C c; +D d; + +// CHECK: metadata !{i32 {{.*}}, null, metadata !"A", metadata !4, i32 3, i64 32, i64 32, i32 0, i32 0, metadata !5, metadata !6, i32 0, i32 0} ; [ DW_TAG_enumeration_type ] +// CHECK: metadata !{i32 {{.*}}, null, metadata !"B", metadata !4, i32 4, i64 64, i64 64, i32 0, i32 0, metadata !9, metadata !10, i32 0, i32 0} ; [ DW_TAG_enumeration_type ] +// CHECK: metadata !{i32 {{.*}}, null, metadata !"C", metadata !4, i32 5, i64 32, i64 32, i32 0, i32 0, null, metadata !13, i32 0, i32 0} ; [ DW_TAG_enumeration_type ] +// CHECK: metadata !{i32 {{.*}}, null, metadata !"D", metadata !4, i32 6, i64 16, i64 16, i32 0, i32 4, null, metadata !16, i32 0, i32 0} ; [ DW_TAG_enumeration_type ] diff --git a/test/CodeGenCXX/debug-info-flex-member.cpp b/test/CodeGenCXX/debug-info-flex-member.cpp new file mode 100644 index 0000000..b6aa6da --- /dev/null +++ b/test/CodeGenCXX/debug-info-flex-member.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +// CHECK: metadata !{i32 {{.*}}, i64 1, i64 0} ; [ DW_TAG_subrange_type ] + +struct StructName { + int member[]; +}; + +struct StructName SN; diff --git a/test/CodeGenCXX/debug-info-fwd-ref.cpp b/test/CodeGenCXX/debug-info-fwd-ref.cpp index 5480c6b..e7f2ed1 100644 --- a/test/CodeGenCXX/debug-info-fwd-ref.cpp +++ b/test/CodeGenCXX/debug-info-fwd-ref.cpp @@ -19,8 +19,8 @@ int main(int argc, char** argv) { // Make sure we have two DW_TAG_class_types for baz and bar and no forward // references. // FIXME: These should be struct types to match the declaration. -// CHECK: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !20, i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 32, i64 32, i32 0, i32 0, null, metadata !23, i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 9, i64 0, i64 0, i32 0, i32 4, i32 0, null, i32 0, i32 0} ; [ DW_TAG_class_type ] +// CHECK: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !18, i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 32, i64 32, i32 0, i32 0, null, metadata !21, i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 0, i64 0, i32 0, i32 4, i32 0, null, i32 0, i32 0} ; [ DW_TAG_class_type ] // CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 0, i64 0, i32 0, i32 4, null, null, i32 0, null, null} ; [ DW_TAG_class_type ] diff --git a/test/CodeGenCXX/debug-info-gline-tables-only.cpp b/test/CodeGenCXX/debug-info-gline-tables-only.cpp new file mode 100644 index 0000000..8d2e63d --- /dev/null +++ b/test/CodeGenCXX/debug-info-gline-tables-only.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 %s -O0 -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. + +// CHECK-NOT: DW_TAG_namespace +namespace NS { +// CHECK-NOT: DW_TAG_class_type +// CHECK-NOT: DW_TAG_friend +class C { friend class D; }; +class D {}; +// CHECK-NOT: DW_TAG_inheritance +class E : public C { + // CHECK-NOT: DW_TAG_reference type + void x(const D& d); +}; +} + +// CHECK-NOT: DW_TAG_variable +NS::C c; +NS::D d; +NS::E e; diff --git a/test/CodeGenCXX/debug-info-globalinit.cpp b/test/CodeGenCXX/debug-info-globalinit.cpp new file mode 100644 index 0000000..ff50fac --- /dev/null +++ b/test/CodeGenCXX/debug-info-globalinit.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -std=c++11 -g | FileCheck %s + +void crash() { + volatile char *ptr = 0; + char x = *ptr; +} + +int test() { + crash(); + return 1; +} + +static int i = test(); +__attribute__((nodebug)) static int j = test(); + +int main(void) {} + +// CHECK: 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-NOT: dbg +// CHECK: %[[C1:.+]] = call i32 @_Z4testv() +// CHECK-NOT: dbg +// CHECK: store i32 %[[C1]], i32* @_ZL1j, align 4 +// +// CHECK: ![[LINE]] = metadata !{i32 13, i32 16 diff --git a/test/CodeGenCXX/debug-info-nullptr.cpp b/test/CodeGenCXX/debug-info-nullptr.cpp index 5540a92..4cc7e54 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: !13 = metadata !{i32 {{.*}}, null, metadata !"nullptr_t", null, i32 0, i64 0, i64 0, i64 0, i32 0, i32 0} ; [ DW_TAG_unspecified_type ] +// CHECK: metadata !{i32 {{.*}}, null, metadata !"nullptr_t", null, i32 0, i64 0, i64 0, i64 0, i32 0, i32 0} ; [ DW_TAG_unspecified_type ] diff --git a/test/CodeGenCXX/debug-info-rvalue-ref.cpp b/test/CodeGenCXX/debug-info-rvalue-ref.cpp new file mode 100644 index 0000000..b633c5c --- /dev/null +++ b/test/CodeGenCXX/debug-info-rvalue-ref.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +extern "C" { +extern int printf(const char * format, ...); +} +void foo (int &&i) +{ + printf("%d\n", i); +} + +// CHECK: metadata !{i32 {{.*}}, null, null, null, i32 0, i64 0, i64 0, i64 0, i32 0, metadata !10} ; [ DW_TAG_rvalue_reference_type ] diff --git a/test/CodeGenCXX/debug-info-static-fns.cpp b/test/CodeGenCXX/debug-info-static-fns.cpp index 485d28a..ee46f25 100644 --- a/test/CodeGenCXX/debug-info-static-fns.cpp +++ b/test/CodeGenCXX/debug-info-static-fns.cpp @@ -7,4 +7,4 @@ namespace A { } // Verify that a is present and mangled. -// CHECK: metadata !{i32 786478, i32 0, metadata !6, metadata !"a", metadata !"a", metadata !"_ZN1AL1aEi", metadata !7, i32 4, metadata !8, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_ZN1AL1aEi, null, null, metadata !14, i32 4} ; [ DW_TAG_subprogram ] +// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !6, metadata !"a", metadata !"a", metadata !"_ZN1AL1aEi", metadata !7, i32 4, metadata !8, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_ZN1AL1aEi, null, null, metadata !1, i32 4} ; [ DW_TAG_subprogram ] diff --git a/test/CodeGenCXX/debug-info-template-array.cpp b/test/CodeGenCXX/debug-info-template-array.cpp new file mode 100644 index 0000000..305327b --- /dev/null +++ b/test/CodeGenCXX/debug-info-template-array.cpp @@ -0,0 +1,14 @@ +// RUN: %clang -emit-llvm -g -S %s -o - +// PR13531 +template <typename> +struct unique_ptr { + unique_ptr() {} +}; + +template <unsigned> +struct Vertex {}; + +void crash() // Asserts +{ + unique_ptr<Vertex<2>[]> v = unique_ptr<Vertex<2>[]>(); +} diff --git a/test/CodeGenCXX/debug-info-template-limit.cpp b/test/CodeGenCXX/debug-info-template-limit.cpp index 796a80f..afad31b 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: !10} ; [ DW_TAG_pointer_type -// CHECK-NEXT: !10 ={{.*}}"TC<int>" +// CHECK: ![[LINE:[0-9]+]]} ; [ DW_TAG_pointer_type ]{{.*}}[from TC<int>] +// CHECK-NEXT: ![[LINE]] ={{.*}}"TC<int>" template<typename T> class TC { @@ -12,4 +12,3 @@ public: }; TC<int> tci; - diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp index 6208c80..f21718d 100644 --- a/test/CodeGenCXX/debug-info-template-member.cpp +++ b/test/CodeGenCXX/debug-info-template-member.cpp @@ -17,5 +17,5 @@ private: MyClass m; // CHECK: metadata !{i32 {{.*}}, null, metadata !"MyClass", metadata {{.*}}, i32 {{.*}}, i64 8, i64 8, i32 0, i32 0, null, metadata [[C_MEM:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:.*]], metadata {{.*}}} +// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:.*]]} // CHECK: [[C_TEMP]] = metadata !{i32 {{.*}}, i32 0, metadata {{.*}}, metadata !"add<2>", metadata !"add<2>", metadata !"_ZN7MyClass3addILi2EEEii", metadata {{.*}} diff --git a/test/CodeGenCXX/debug-info-template-quals.cpp b/test/CodeGenCXX/debug-info-template-quals.cpp new file mode 100644 index 0000000..e5a9082 --- /dev/null +++ b/test/CodeGenCXX/debug-info-template-quals.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +template<typename _CharT> +struct basic_string { + + basic_string& + assign(const _CharT* __s) + { + return *this; + } +}; + +void foo (const char *c) { + basic_string<char> str; + str.assign(c); +} + +// CHECK: [[P:.*]] = metadata !{i32 {{.*}}, metadata [[CON:.*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ] +// CHECK: [[CON]] = metadata !{i32 {{.*}}, metadata [[CH:.*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from char] +// CHECK: [[CH]] = metadata !{i32 {{.*}}, metadata !"char", {{.*}}} ; [ DW_TAG_base_type ] [char] [line 0, size 8, align 8, offset 0, enc DW_ATE_signed_char] +// CHECK: metadata !{i32 {{.*}}, metadata !"_ZN12basic_stringIcE6assignEPKc", metadata !6, i32 7, metadata [[TYPE:.*]], i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, %struct.basic_string* (%struct.basic_string*, i8*)* @_ZN12basic_stringIcE6assignEPKc, null, metadata !18, metadata !1, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign] +// CHECK: [[TYPE]] = metadata !{i32 {{.*}}, null, metadata [[ARGS:.*]], i32 0, i32 0} +// CHECK: [[ARGS]] = metadata !{metadata !15, metadata !23, metadata [[P]]} diff --git a/test/CodeGenCXX/debug-info-union.cpp b/test/CodeGenCXX/debug-info-union.cpp new file mode 100644 index 0000000..588fa20 --- /dev/null +++ b/test/CodeGenCXX/debug-info-union.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -std=c++11 %s -o - | FileCheck %s + +union E { + int a; + float b; + int bb() { return a;} + float aa() { return b;} + E() { a = 0; } +}; + +E e; + +// CHECK: metadata !{i32 {{.*}}, null, metadata !"E", metadata !{{.*}}, i32 3, i64 32, i64 32, i64 0, i32 0, null, metadata !{{.*}}, i32 0, null} ; [ DW_TAG_union_type ] +// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"bb", metadata !"bb", metadata !"_ZN1E2bbEv", metadata !{{.*}}, i32 6, metadata !{{.*}}, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !{{.*}}, i32 6} ; [ DW_TAG_subprogram ] +// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"aa", metadata !"aa", metadata !"_ZN1E2aaEv", metadata !{{.*}}, i32 7, metadata !{{.*}}, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !{{.*}}, i32 7} ; [ DW_TAG_subprogram ] +// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"E", metadata !"E", metadata !"", metadata !{{.*}}, i32 8, metadata !{{.*}}, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !{{.*}}, i32 8} ; [ DW_TAG_subprogram ] diff --git a/test/CodeGenCXX/debug-info-user-def.cpp b/test/CodeGenCXX/debug-info-user-def.cpp new file mode 100644 index 0000000..ecd3878 --- /dev/null +++ b/test/CodeGenCXX/debug-info-user-def.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -std=c++11 %s -o - | FileCheck %s + +class A { +}; + +template <typename T> class B { + T t; +}; + +A a; +B<int> b; + +// Check that no subprograms are emitted into debug info. +// CHECK-NOT: [ DW_TAG_subprogram ] diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp index 859a71b..1c82399 100644 --- a/test/CodeGenCXX/debug-lambda-expressions.cpp +++ b/test/CodeGenCXX/debug-lambda-expressions.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 -g | FileCheck %s auto var = [](int i) { return i+1; }; +void *use = &var; extern "C" auto cvar = []{}; @@ -13,59 +14,56 @@ 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; }(); } - -// A: 5 -// CHECK: [[A_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE:.*]], metadata !"a", metadata !"a", metadata !"_Z1av", metadata {{.*}}, i32 [[A_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @_Z1av, null, null, {{.*}} [ DW_TAG_subprogram ] - // Randomness for file. -- 6 -// CHECK: [[FILE]] = metadata !{i32 {{.*}}, metadata !{{.*}}debug-lambda-expressions.cpp{{.*}}; [ DW_TAG_file_type ] +// CHECK: [[FILE:.*]] = metadata !{i32 {{.*}}, metadata !{{.*}}debug-lambda-expressions.cpp{{.*}}; [ DW_TAG_file_type ] + +// A: 10 +// CHECK: [[A_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"a", metadata !"a", metadata !"_Z1av", metadata {{.*}}, i32 [[A_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @_Z1av, null, null, {{.*}} [ DW_TAG_subprogram ] -// B: 12 +// B: 14 // CHECK: [[B_FUNC:.*]] = metadata !{i32 786478, i32 0, metadata [[FILE]], metadata !"b", metadata !"b", metadata !"_Z1bi", metadata [[FILE]], i32 [[B_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1bi, null, null, {{.*}} ; [ DW_TAG_subprogram ] // C: 17 // CHECK: [[C_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"c", metadata !"c", metadata !"_Z1ci", metadata [[FILE]], i32 [[C_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1ci, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ] -// D: 20 +// D: 18 // CHECK: [[D_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"d", metadata !"d", metadata !"_Z1di", metadata [[FILE]], i32 [[D_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1di, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ] -// Back to D. -- 120 +// Back to D. -- 24 // CHECK: [[LAM_D:.*]] = metadata !{i32 {{.*}}, metadata [[D_FUNC]], metadata !"", metadata [[FILE]], i32 [[D_LINE]], i64 352, i64 32, i32 0, i32 0, null, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]], metadata [[DES_LAM_D:.*]]} -// CHECK: [[CAP_D_X]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"x", metadata [[FILE]], i32 14, i64 32, i64 32, i64 0, i32 1, metadata {{.*}} ; [ DW_TAG_member ] -// CHECK: [[CAP_D_Y]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"y", metadata [[FILE]], i32 14, i64 320, i64 32, i64 32, i32 1, metadata {{.*}} ; [ DW_TAG_member ] +// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]]} +// CHECK: [[CAP_D_X]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"x", metadata [[FILE]], i32 [[D_LINE]], i64 32, i64 32, i64 0, i32 1, metadata {{.*}} ; [ DW_TAG_member ] +// CHECK: [[CAP_D_Y]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"y", metadata [[FILE]], i32 [[D_LINE]], i64 320, i64 32, i64 32, i32 1, metadata {{.*}} ; [ DW_TAG_member ] // CHECK: [[CON_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] -// CHECK: [[DES_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] -// Back to C. -- 159 +// Back to C. -- 55 // CHECK: [[LAM_C:.*]] = metadata !{i32 {{.*}}, metadata [[C_FUNC]], metadata !"", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i32 0, i32 0, null, metadata [[LAM_C_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]], metadata [[DES_LAM_C:.*]]} +// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]]} // Ignoring the member type for now. // CHECK: [[CAP_C]] = metadata !{i32 {{.*}}, metadata [[LAM_C]], metadata !"x", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ] // CHECK: [[CON_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] -// CHECK: [[DES_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] -// Back to B. -- 179 +// Back to B. -- 67 // CHECK: [[LAM_B:.*]] = metadata !{i32 {{.*}}, metadata [[B_FUNC]], metadata !"", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i32 0, i32 0, null, metadata [[LAM_B_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]], metadata [[DES_LAM_B:.*]]} +// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]]} // CHECK: [[CAP_B]] = metadata !{i32 {{.*}}, metadata [[LAM_B]], metadata !"x", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ] // CHECK: [[CON_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] -// CHECK: [[DES_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] -// Back to A. -- 204 + +// Back to A. -- 78 // CHECK: [[LAM_A:.*]] = metadata !{i32 {{.*}}, metadata [[A_FUNC]], metadata !"", metadata [[FILE]], i32 [[A_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata [[LAM_A_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]], metadata [[DES_LAM_A:.*]]} +// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]]} // CHECK: [[CON_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] -// CHECK: [[DES_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] -// VAR: -// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ] -// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}} // CVAR: // CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"cvar", metadata !"cvar", metadata !"", metadata [[FILE]], i32 [[CVAR_LINE:.*]], metadata ![[CVAR_T:.*]], i32 0, i32 1, %class.anon.0* @cvar} ; [ DW_TAG_variable ] // CHECK: [[CVAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[CVAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] -// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}} +// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}} + +// VAR: +// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ] +// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}} diff --git a/test/CodeGenCXX/derived-to-base-conv.cpp b/test/CodeGenCXX/derived-to-base-conv.cpp index 8c51809..9b15c68 100644 --- a/test/CodeGenCXX/derived-to-base-conv.cpp +++ b/test/CodeGenCXX/derived-to-base-conv.cpp @@ -1,85 +1,86 @@ -// 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 - -extern "C" int printf(...); -extern "C" void exit(int); +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o - | FileCheck %s struct A { - A (const A&) { printf("A::A(const A&)\n"); } - A() {}; - ~A() { printf("A::~A()\n"); } + A(const A&); + A(); + ~A(); }; struct B : public A { - B() {}; - B(const B& Other) : A(Other) { printf("B::B(const B&)\n"); } - ~B() { printf("B::~B()\n"); } + B(); + B(const B& Other); + ~B(); }; struct C : public B { - C() {}; - C(const C& Other) : B(Other) { printf("C::C(const C&)\n"); } - ~C() { printf("C::~C()\n"); } + C(); + C(const C& Other); + ~C(); }; struct X { - operator B&() {printf("X::operator B&()\n"); return b; } - operator C&() {printf("X::operator C&()\n"); return c; } - X (const X&) { printf("X::X(const X&)\n"); } - X () { printf("X::X()\n"); } - ~X () { printf("X::~X()\n"); } - B b; - C c; + operator B&(); + operator C&(); + X(const X&); + X(); + ~X(); + B b; + C c; }; -void f(A) { - printf("f(A)\n"); -} - - -void func(X x) -{ - f (x); -} - -int main() -{ - X x; - func(x); +void test0_helper(A); +void test0(X x) { + test0_helper(x); + // CHECK: define void @_Z5test01X( + // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align + // CHECK-NEXT: [[T0:%.*]] = call [[B:%.*]]* @_ZN1XcvR1BEv( + // CHECK-NEXT: [[T1:%.*]] = bitcast [[B]]* [[T0]] to [[A]]* + // CHECK-NEXT: call void @_ZN1AC1ERKS_([[A]]* [[TMP]], [[A]]* [[T1]]) + // CHECK-NEXT: call void @_Z12test0_helper1A([[A]]* [[TMP]]) + // CHECK-NEXT: call void @_ZN1AD1Ev([[A]]* [[TMP]]) + // CHECK-NEXT: ret void } struct Base; struct Root { - operator Base&() { exit(1); } + operator Base&(); }; struct Derived; struct Base : Root { - Base(const Base&) { printf("Base::(const Base&)\n"); } - Base() { printf("Base::Base()\n"); } - operator Derived&() { exit(1); } + Base(const Base &); + Base(); + operator Derived &(); }; struct Derived : Base { }; -void foo(Base) {} - -void test(Derived bb) -{ - // CHECK-LP64-NOT: callq __ZN4BasecvR7DerivedEv - // CHECK-LP32-NOT: callq L__ZN4BasecvR7DerivedEv - foo(bb); +void test1_helper(Base); +void test1(Derived bb) { + // CHECK: define void @_Z5test17Derived( + // CHECK-NOT: call {{.*}} @_ZN4BasecvR7DerivedEv( + // CHECK: call void @_ZN4BaseC1ERKS_( + // CHECK-NOT: call {{.*}} @_ZN4BasecvR7DerivedEv( + // CHECK: call void @_Z12test1_helper4Base( + test1_helper(bb); } -// CHECK-LP64: callq __ZN1XcvR1BEv -// CHECK-LP64: callq __ZN1AC1ERKS_ - -// CHECK-LP32: calll L__ZN1XcvR1BEv -// CHECK-LP32: calll L__ZN1AC1ERKS_ - +// Don't crash after devirtualizing a derived-to-base conversion +// to an empty base allocated at offset zero. +// rdar://problem/11993704 +class Test2a {}; +class Test2b final : public virtual Test2a {}; +void test2(Test2b &x) { + Test2a &y = x; + // CHECK: define void @_Z5test2R6Test2b( + // CHECK: [[X:%.*]] = alloca [[B:%.*]]*, align 8 + // CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]]*, align 8 + // CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]], align 8 + // CHECK-NEXT: [[T0:%.*]] = load [[B]]** [[X]], align 8 + // CHECK-NEXT: [[T1:%.*]] = bitcast [[B]]* [[T0]] to [[A]]* + // CHECK-NEXT: store [[A]]* [[T1]], [[A]]** [[Y]], align 8 + // CHECK-NEXT: ret void +} diff --git a/test/CodeGenCXX/destructor-debug-info.cpp b/test/CodeGenCXX/destructor-debug-info.cpp index 9e32275..385c86d 100644 --- a/test/CodeGenCXX/destructor-debug-info.cpp +++ b/test/CodeGenCXX/destructor-debug-info.cpp @@ -1,6 +1,5 @@ -// RUN: %clang_cc1 -g -S -emit-llvm -o %t %s -// RUN: grep "i32 20, i32 3, metadata" %t | count 1 -// Check there is a line number entry for line 20 where b1 is destructed. +// RUN: %clang_cc1 -g -S -emit-llvm %s -o - | FileCheck %s + class A { int a; }; class B { public: @@ -19,3 +18,5 @@ void foo() { fn (b1); } } +// Check there is a line number entry for line 19 where b1 is destructed. +// CHECK: i32 19, i32 3, metadata diff --git a/test/CodeGenCXX/destructor-exception-spec.cpp b/test/CodeGenCXX/destructor-exception-spec.cpp new file mode 100644 index 0000000..579daef --- /dev/null +++ b/test/CodeGenCXX/destructor-exception-spec.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm-only %s -std=c++11 + +// PR13479: don't crash with -fno-exceptions. +namespace { + struct SchedulePostRATDList { + virtual ~SchedulePostRATDList(); + }; + + SchedulePostRATDList::~SchedulePostRATDList() {} + + SchedulePostRATDList Scheduler; +} diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index d9962e6..d665445 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -350,6 +350,22 @@ namespace test8 { // CHECK: unreachable } +// PR12710 +namespace test9 { + struct ArgType { + ~ArgType(); + }; + template<typename T> + void f1(const ArgType& = ArgType()); + void f2(); + void bar() { + f1<int>(); + f2(); + } + // CHECK: call void @_ZN5test97ArgTypeD1Ev(%"struct.test9::ArgType"* % + // CHECK: call void @_ZN5test92f2Ev() +} + // Checks from test3: // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp index 3de75ed..634bf84 100644 --- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp +++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - | FileCheck %s namespace Test1 { struct A { @@ -49,3 +49,140 @@ namespace Test3 { return static_cast<B*>(v)->f(); } } + +namespace Test4 { + struct A { + virtual void f(); + }; + + struct B final : A { + virtual void f(); + }; + + // CHECK: define void @_ZN5Test41fEPNS_1BE + void f(B* d) { + // CHECK: call void @_ZN5Test41B1fEv + static_cast<A*>(d)->f(); + } +} + +namespace Test5 { + struct A { + virtual void f(); + }; + + struct B : A { + virtual void f(); + }; + + struct C final : B { + }; + + // CHECK: define void @_ZN5Test51fEPNS_1CE + void f(C* d) { + // FIXME: It should be possible to devirtualize this case, but that is + // not implemented yet. + // CHECK: getelementptr + // CHECK-NEXT: %[[FUNC:.*]] = load + // CHECK-NEXT: call void %[[FUNC]] + static_cast<A*>(d)->f(); + } +} + +namespace Test6 { + struct A { + virtual ~A(); + }; + + struct B : public A { + virtual ~B(); + }; + + struct C { + virtual ~C(); + }; + + struct D final : public C, public B { + }; + + // CHECK: define void @_ZN5Test61fEPNS_1DE + void f(D* d) { + // CHECK: call void @_ZN5Test61DD1Ev + static_cast<A*>(d)->~A(); + } +} + +namespace Test7 { + struct foo { + virtual void g() {} + }; + + struct bar { + virtual int f() { return 0; } + }; + + struct zed final : public foo, public bar { + int z; + virtual int f() {return z;} + }; + + // CHECK: define i32 @_ZN5Test71fEPNS_3zedE + int f(zed *z) { + // CHECK: alloca + // CHECK-NEXT: store + // CHECK-NEXT: load + // CHECK-NEXT: bitcast + // CHECK-NEXT: call {{.*}} @_ZN5Test73zed1fEv + // CHECK-NEXT: ret + return static_cast<bar*>(z)->f(); + } +} + +namespace Test8 { + struct A { virtual ~A() {} }; + struct B { + int b; + virtual int foo() { return b; } + }; + struct C final : A, B { }; + // CHECK: define i32 @_ZN5Test84testEPNS_1CE + int test(C *c) { + // CHECK: %[[THIS:.*]] = phi + // CHECK-NEXT: call i32 @_ZN5Test81B3fooEv(%"struct.Test8::B"* %[[THIS]]) + return static_cast<B*>(c)->foo(); + } +} + +namespace Test9 { + struct A { + int a; + }; + struct B { + int b; + }; + struct C : public B, public A { + }; + struct RA { + virtual A *f() { + return 0; + } + }; + struct RC final : public RA { + virtual C *f() { + C *x = new C(); + x->a = 1; + x->b = 2; + return x; + } + }; + // CHECK: define {{.*}} @_ZN5Test91fEPNS_2RCE + A *f(RC *x) { + // FIXME: It should be possible to devirtualize this case, but that is + // not implemented yet. + // CHECK: getelementptr + // CHECK-NEXT: %[[FUNC:.*]] = load + // CHECK-NEXT: bitcast + // CHECK-NEXT: = call {{.*}} %[[FUNC]] + return static_cast<RA*>(x)->f(); + } +} diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp index 5eede66..c5a4094 100644 --- a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp +++ b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp @@ -53,3 +53,33 @@ void f() { B().h().f(); } +namespace test2 { + struct foo { + virtual void f(); + virtual ~foo(); + }; + + struct bar : public foo { + virtual void f(); + virtual ~bar(); + }; + + void f(bar *b) { + // CHECK: call void @_ZN5test23foo1fEv + // CHECK: call void @_ZN5test23fooD1Ev + b->foo::f(); + b->foo::~foo(); + } +} + +namespace test3 { + // Test that we don't crash in this case. + struct B { + }; + struct D : public B { + }; + void f(D d) { + // CHECK: define void @_ZN5test31fENS_1DE + d.B::~B(); + } +} diff --git a/test/CodeGenCXX/dynamic-cast-always-null.cpp b/test/CodeGenCXX/dynamic-cast-always-null.cpp index 2c3ea13..836cb11 100644 --- a/test/CodeGenCXX/dynamic-cast-always-null.cpp +++ b/test/CodeGenCXX/dynamic-cast-always-null.cpp @@ -17,3 +17,8 @@ C &f(B& b) { // CHECK: ret %struct.C* undef return dynamic_cast<C&>(b); } + +void dont_crash() { + (void) dynamic_cast<void*>((A*)0); + (void) dynamic_cast<void*>((B*)0); +} diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp index 079c1e5..8c20c9e 100644 --- a/test/CodeGenCXX/exceptions.cpp +++ b/test/CodeGenCXX/exceptions.cpp @@ -414,3 +414,39 @@ namespace test9 { // CHECK: [[TEST9_NEW:%.*]] = call noalias i8* @_Znam // CHECK: call void @_ZdaPv(i8* [[TEST9_NEW]]) } + +// In a destructor with a function-try-block, a return statement in a +// catch handler behaves differently from running off the end of the +// catch handler. PR13102. +namespace test10 { + extern void cleanup(); + extern bool suppress; + + struct A { ~A(); }; + A::~A() try { cleanup(); } catch (...) { return; } + // CHECK: 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: invoke void @_ZN6test107cleanupEv() + // CHECK: call i8* @__cxa_begin_catch + // CHECK-NEXT: invoke void @__cxa_rethrow() + // CHECK: unreachable + + struct C { ~C(); }; + C::~C() try { cleanup(); } catch (...) { if (suppress) return; } + // CHECK: define void @_ZN6test101CD1Ev( + // CHECK: invoke void @_ZN6test107cleanupEv() + // CHECK: call i8* @__cxa_begin_catch + // CHECK-NEXT: load i8* @_ZN6test108suppressE, align 1 + // CHECK-NEXT: trunc + // CHECK-NEXT: br i1 + // CHECK: call void @__cxa_end_catch() + // CHECK-NEXT: br label + // CHECK: invoke void @__cxa_rethrow() + // CHECK: unreachable +} diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp index 5b5dfac..076ef94 100644 --- a/test/CodeGenCXX/global-array-destruction.cpp +++ b/test/CodeGenCXX/global-array-destruction.cpp @@ -1,6 +1,4 @@ -// REQUIRES: 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 x86_64-apple-darwin -std=c++11 -emit-llvm %s -o - | FileCheck %s extern "C" int printf(...); @@ -24,11 +22,24 @@ static S sarr1[4]; S s2; S arr3[3]; -// CHECK-LP64: callq ___cxa_atexit -// CHECK-LP64: callq ___cxa_atexit -// CHECK-LP64: callq ___cxa_atexit -// CHECK-LP64: callq ___cxa_atexit -// CHECK-LP64: callq ___cxa_atexit -// CHECK-LP64: callq ___cxa_atexit -// CHECK-LP64: callq ___cxa_atexit -// CHECK-LP64: callq ___cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit +// CHECK: call {{.*}} @__cxa_atexit + +struct T { + double d; + int n; + ~T(); +}; +T t[2][3] = { 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 ({{.*}} bitcast {{.*}}* @t to %struct.T*), i64 6 +// CHECK: call void @_ZN1TD1Ev +// CHECK: icmp eq {{.*}} @t +// CHECK: br i1 {{.*}} diff --git a/test/CodeGenCXX/global-block-literal-helpers.cpp b/test/CodeGenCXX/global-block-literal-helpers.cpp new file mode 100644 index 0000000..350ea54 --- /dev/null +++ b/test/CodeGenCXX/global-block-literal-helpers.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 %s | FileCheck %s +// rdar://11343499 + +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 + 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( + int ival = func(^{}, ^{}, ^{}); + +// CHECK: define internal void @_ZN1N9gvarlobalE_block_invoke_7( + void (^gvarlobal)(void) = ^{}; + + struct S { + BL field = ^{}; + }; + +// CHECK: define internal void @_ZN1N3blfE_block_invoke_8( + S blf; +}; diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp index 8e6ef77..2a53ad9 100644 --- a/test/CodeGenCXX/global-init.cpp +++ b/test/CodeGenCXX/global-init.cpp @@ -70,17 +70,17 @@ namespace test3 { const char *test() { return var; } } -namespace test6 { +namespace test4 { struct A { A(); }; extern int foo(); // This needs an initialization function and guard variables. - // CHECK: load i8* bitcast (i64* @_ZGVN5test61xE - // CHECK: [[CALL:%.*]] = call i32 @_ZN5test63fooEv - // CHECK-NEXT: store i32 [[CALL]], i32* @_ZN5test61xE - // CHECK-NEXT: store i64 1, i64* @_ZGVN5test61xE + // CHECK: load i8* bitcast (i64* @_ZGVN5test41xE + // CHECK: [[CALL:%.*]] = call i32 @_ZN5test43fooEv + // CHECK-NEXT: store i32 [[CALL]], i32* @_ZN5test41xE + // CHECK-NEXT: store i64 1, i64* @_ZGVN5test41xE __attribute__((weak)) int x = foo(); } @@ -95,14 +95,6 @@ namespace PR5974 { A* a = &c; B* b = &c; } -// CHECK: define internal void [[TEST1_Z_INIT:@.*]]() -// CHECK: load i32* @_ZN5test1L1yE -// CHECK-NEXT: xor -// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1zE -// CHECK: define internal void [[TEST1_Y_INIT:@.*]]() -// CHECK: load i32* @_ZN5test1L1xE -// CHECK-NEXT: sub -// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1yE // PR9570: the indirect field shouldn't crash IR gen. namespace test5 { @@ -111,9 +103,98 @@ namespace test5 { }; } +namespace std { struct type_info; } + +namespace test6 { + struct A { virtual ~A(); }; + struct B : A {}; + extern A *p; + + // We must emit a dynamic initializer for 'q', because it could throw. + B *const q = &dynamic_cast<B&>(*p); + // CHECK: call void @__cxa_bad_cast() + // CHECK: store {{.*}} @_ZN5test6L1qE + + // We don't need to emit 'r' at all, because it has internal linkage, is + // unused, and its initialization has no side-effects. + B *const r = dynamic_cast<B*>(p); + // CHECK-NOT: call void @__cxa_bad_cast() + // CHECK-NOT: store {{.*}} @_ZN5test6L1rE + + // This can throw, so we need to emit it. + const std::type_info *const s = &typeid(*p); + // CHECK: store {{.*}} @_ZN5test6L1sE + + // This can't throw, so we don't. + const std::type_info *const t = &typeid(p); + // CHECK-NOT: @_ZN5test6L1tE + + extern B *volatile v; + // CHECK: store {{.*}} @_ZN5test6L1wE + B *const w = dynamic_cast<B*>(v); + + // CHECK: load volatile + // CHECK: store {{.*}} @_ZN5test6L1xE + const int x = *(volatile int*)0x1234; + + namespace { + int a = int(); + volatile int b = int(); + int c = a; + int d = b; + // CHECK-NOT: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1aE + // CHECK-NOT: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1bE + // CHECK-NOT: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1cE + // CHECK: load volatile {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1bE + // CHECK: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1dE + } +} + +namespace test7 { + struct A { A(); }; + struct B { ~B(); int n; }; + struct C { C() = default; C(const C&); int n; }; + struct D {}; + + // CHECK: call void @_ZN5test71AC1Ev({{.*}}@_ZN5test7L1aE) + const A a = A(); + + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN5test71BD1Ev{{.*}} @_ZN5test7L2b1E + // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN5test71BD1Ev{{.*}} @_ZGRN5test72b2E + // CHECK: call void @_ZN5test71BD1Ev( + // CHECK: store {{.*}} @_ZN5test7L2b3E + const B b1 = B(); + const B &b2 = B(); + const int b3 = B().n; + + // CHECK-NOT: @_ZN5test7L2c1E + // CHECK: @_ZN5test7L2c2E + // CHECK-NOT: @_ZN5test7L2c3E + // CHECK: @_ZN5test7L2c4E + const C c1 = C(); + const C c2 = static_cast<const C&>(C()); + const int c3 = C().n; + const int c4 = C(C()).n; + + // CHECK-NOT: @_ZN5test7L1dE + const D d = D(); + + // CHECK: store {{.*}} @_ZN5test71eE + int f(), e = f(); +} + // At the end of the file, we check that y is initialized before z. +// CHECK: define internal void [[TEST1_Z_INIT:@.*]]() +// CHECK: load i32* @_ZN5test1L1yE +// CHECK-NEXT: xor +// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1zE +// CHECK: define internal void [[TEST1_Y_INIT:@.*]]() +// CHECK: load i32* @_ZN5test1L1xE +// CHECK-NEXT: sub +// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1yE + // CHECK: define internal void @_GLOBAL__I_a() section "__TEXT,__StaticInit,regular,pure_instructions" { // CHECK: call void [[TEST1_Y_INIT]] // CHECK: call void [[TEST1_Z_INIT]] diff --git a/test/CodeGenCXX/inline-functions.cpp b/test/CodeGenCXX/inline-functions.cpp index 69dfe0d..8c011de 100644 --- a/test/CodeGenCXX/inline-functions.cpp +++ b/test/CodeGenCXX/inline-functions.cpp @@ -53,3 +53,17 @@ namespace test1 { c.func(); } } + +// PR13252 +namespace test2 { + struct A; + void f(const A& a); + struct A { + friend void f(const A& a) { } + }; + void g() { + A a; + f(a); + } + // CHECK: define linkonce_odr void @_ZN5test21fERKNS_1AE +} diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp index 797cbf4..e872cc4 100644 --- a/test/CodeGenCXX/lambda-expressions.cpp +++ b/test/CodeGenCXX/lambda-expressions.cpp @@ -1,7 +1,11 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s -// CHECK: @var = internal global -auto var = [](int i) { return i+1; }; +// CHECK-NOT: @unused +auto unused = [](int i) { return i+1; }; + +// CHECK: @used = internal global +auto used = [](int i) { return i+1; }; +void *use = &used; // CHECK: @cvar = global extern "C" auto cvar = []{}; diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp index cc53b01..16ddf48 100644 --- a/test/CodeGenCXX/mangle-lambdas.cpp +++ b/test/CodeGenCXX/mangle-lambdas.cpp @@ -1,5 +1,10 @@ // 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: define linkonce_odr void @_Z11inline_funci inline void inline_func(int n) { // CHECK: call i32 @_ZZ11inline_funciENKUlvE_clEv @@ -78,10 +83,10 @@ struct ST { // CHECK: define void @_Z7test_ST2STIdE void test_ST(ST<double> st) { - // CHECK: call double @_ZZN2ST1fET_S0_Ed0_NKUlvE_clEv - // CHECK-NEXT: call double @_ZZN2ST1fET_S0_Ed0_NKUlvE0_clEv + // CHECK: call double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv + // CHECK-NEXT: call double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv // CHECK-NEXT: fadd double - // CHECK-NEXT: call double @_ZZN2ST1fET_S0_Ed_NKUlvE_clEv + // CHECK-NEXT: call double @_ZZN2STIdE1fEddEd_NKUlvE_clEv // CHECK-NEXT: call void @_ZN2STIdE1fEdd st.f(); @@ -89,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 @_ZZN2ST1fET_S0_Ed0_NKUlvE_clEv +// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE_clEv // CHECK: ret double 1 -// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed0_NKUlvE0_clEv +// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd0_NKUlvE0_clEv // CHECK: ret double 2 -// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed_NKUlvE_clEv +// CHECK: define linkonce_odr double @_ZZN2STIdE1fEddEd_NKUlvE_clEv // CHECK: ret double 3 template<typename T> @@ -150,6 +155,24 @@ void use_func_template() { func_template<int>(); } + +template<typename...T> struct PR12917 { + PR12917(T ...t = []{ static int n = 0; return ++n; }()); + + static int n[3]; +}; +template<typename...T> int PR12917<T...>::n[3] = { + []{ static int n = 0; return ++n; }() +}; + +// CHECK: call i32 @_ZZN7PR12917IJicdEEC1EicdEd1_NKUlvE_clEv( +// CHECK: call i32 @_ZZN7PR12917IJicdEEC1EicdEd0_NKUlvE_clEv( +// CHECK: call i32 @_ZZN7PR12917IJicdEEC1EicdEd_NKUlvE_clEv( +// CHECK: call void @_ZN7PR12917IJicdEEC1Eicd( +PR12917<int, char, double> pr12917; +int *pr12917_p = PR12917<int, int>::n; + + // CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_ struct Members { diff --git a/test/CodeGenCXX/mangle-ms-abi-examples.cpp b/test/CodeGenCXX/mangle-ms-abi-examples.cpp new file mode 100644 index 0000000..d6726cab --- /dev/null +++ b/test/CodeGenCXX/mangle-ms-abi-examples.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fms-extensions -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +// CHECK: @"\01??_7D@C@?1??foo@@YAXXZ@6B@" = +// CHECK: @"\01??_7B@?1??foo@A@@QAEXH@Z@6B@" = +// CHECK: define {{.*}} @"\01?baz@E@?3??bar@C@?1??foo@@YAXXZ@QAEXXZ@QAEXXZ"( + +// Microsoft Visual C++ ABI examples. +struct A { + void foo (int) { + struct B { virtual ~B() {} }; + B(); + } +}; +void foo () { + struct C { + struct D { virtual ~D() {} }; + void bar () { + struct E { + void baz() { } + }; + E().baz(); + } + }; + A().foo(0); + C::D(); + C().bar(); +} + diff --git a/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp new file mode 100644 index 0000000..27b4768 --- /dev/null +++ b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp @@ -0,0 +1,165 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +// FIXME: add tests for return types with complex templates when PR13389 is fixed. + +template<class X, class Y, class Z> +class A {}; +template<class X> +class B {}; +template<class X> +class C {}; + +void foo_abbb(A<B<char>, B<char>, B<char> >) {} +// CHECK: "\01?foo_abbb@@YAXV?$A@V?$B@D@@V1@V1@@@@Z" +void foo_abb(A<char, B<char>, B<char> >) {} +// CHECK: "\01?foo_abb@@YAXV?$A@DV?$B@D@@V1@@@@Z" +void foo_abc(A<char, B<char>, C<char> >) {} +// CHECK: "\01?foo_abc@@YAXV?$A@DV?$B@D@@V?$C@D@@@@@Z" + +namespace N { +template<class X, class Y, class Z> +class A {}; +template<class X> +class B {}; +template<class X> +class C {}; +template<class X, class Y> +class D {}; +class Z {}; +} + +void foo_abbb(N::A<N::B<char>, N::B<char>, N::B<char> >) {} +// CHECK: "\01?foo_abbb@@YAXV?$A@V?$B@D@N@@V12@V12@@N@@@Z" +void foo_abb(N::A<char, N::B<char>, N::B<char> >) {} +// CHECK: "\01?foo_abb@@YAXV?$A@DV?$B@D@N@@V12@@N@@@Z" +void foo_abc(N::A<char, N::B<char>, N::C<char> >) {} +// CHECK: "\01?foo_abc@@YAXV?$A@DV?$B@D@N@@V?$C@D@2@@N@@@Z" + +N::A<char, N::B<char>, N::C<char> > abc_foo() { +// CHECK: ?abc_foo@@YA?AV?$A@DV?$B@D@N@@V?$C@D@2@@N@@XZ + return N::A<char, N::B<char>, N::C<char> >(); +} + +N::Z z_foo(N::Z arg) { +// CHECK: ?z_foo@@YA?AVZ@N@@V12@@Z + return arg; +} + +N::B<char> b_foo(N::B<char> arg) { +// CHECK: ?b_foo@@YA?AV?$B@D@N@@V12@@Z + return arg; +} + +N::D<char, char> d_foo(N::D<char, char> arg) { +// CHECK: ?d_foo@@YA?AV?$D@DD@N@@V12@@Z + return arg; +} + +N::A<char, N::B<char>, N::C<char> > abc_foo_abc(N::A<char, N::B<char>, N::C<char> >) { +// CHECK: ?abc_foo_abc@@YA?AV?$A@DV?$B@D@N@@V?$C@D@2@@N@@V12@@Z + return N::A<char, N::B<char>, N::C<char> >(); +} + +namespace NA { +class X {}; +template<class T> class Y {}; +} + +namespace NB { +class X {}; +template<class T> class Y {}; +} + +void foo5(NA::Y<NB::Y<NA::Y<NB::Y<NA::X> > > > arg) {} +// CHECK: "\01?foo5@@YAXV?$Y@V?$Y@V?$Y@V?$Y@VX@NA@@@NB@@@NA@@@NB@@@NA@@@Z" + +void foo11(NA::Y<NA::X>, NB::Y<NA::X>) {} +// CHECK: "\01?foo11@@YAXV?$Y@VX@NA@@@NA@@V1NB@@@Z" + +void foo112(NA::Y<NA::X>, NB::Y<NB::X>) {} +// CHECK: "\01?foo112@@YAXV?$Y@VX@NA@@@NA@@V?$Y@VX@NB@@@NB@@@Z" + +void foo22(NA::Y<NB::Y<NA::X> >, NB::Y<NA::Y<NA::X> >) {} +// CHECK: "\01?foo22@@YAXV?$Y@V?$Y@VX@NA@@@NB@@@NA@@V?$Y@V?$Y@VX@NA@@@NA@@@NB@@@Z" + +namespace PR13207 { +class A {}; +class B {}; +class C {}; + +template<class X> +class F {}; +template<class X> +class I {}; +template<class X, class Y> +class J {}; +template<class X, class Y, class Z> +class K {}; + +class L { + public: + void foo(I<A> x) {} +}; +// CHECK: "\01?foo@L@PR13207@@QAEXV?$I@VA@PR13207@@@2@@Z" + +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" +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) {} +// CHECK: "\01?spam@PR13207@@YAXV?$K@VA@PR13207@@VB@2@VC@2@@1@@Z" + +void baz(K<char, F<char>, I<char> >) {} +// CHECK: "\01?baz@PR13207@@YAXV?$K@DV?$F@D@PR13207@@V?$I@D@2@@1@@Z" +void qux(K<char, I<char>, I<char> >) {} +// CHECK: "\01?qux@PR13207@@YAXV?$K@DV?$I@D@PR13207@@V12@@1@@Z" + +namespace NA { +class X {}; +template<class T> class Y {}; +void foo(Y<X> x) {} +// CHECK: "\01?foo@NA@PR13207@@YAXV?$Y@VX@NA@PR13207@@@12@@Z" +void foofoo(Y<Y<X> > x) {} +// CHECK: "\01?foofoo@NA@PR13207@@YAXV?$Y@V?$Y@VX@NA@PR13207@@@NA@PR13207@@@12@@Z" +} + +namespace NB { +class X {}; +template<class T> class Y {}; +void foo(Y<NA::X> x) {} +// CHECK: "\01?foo@NB@PR13207@@YAXV?$Y@VX@NA@PR13207@@@12@@Z" + +void bar(NA::Y<X> x) {} +// CHECK: "\01?bar@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@NA@2@@Z" + +void spam(NA::Y<NA::X> x) {} +// CHECK: "\01?spam@NB@PR13207@@YAXV?$Y@VX@NA@PR13207@@@NA@2@@Z" + +void foobar(NA::Y<Y<X> > a, Y<Y<X> >) {} +// CHECK: "\01?foobar@NB@PR13207@@YAXV?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V312@@Z" + +void foobarspam(Y<X> a, NA::Y<Y<X> > b, Y<Y<X> >) {} +// CHECK: "\01?foobarspam@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@@Z" + +void foobarbaz(Y<X> a, NA::Y<Y<X> > b, Y<Y<X> >, Y<Y<X> > c) {} +// CHECK: "\01?foobarbaz@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@2@Z" + +void foobarbazqux(Y<X> a, NA::Y<Y<X> > b, Y<Y<X> >, Y<Y<X> > c , NA::Y<Y<Y<X> > > d) {} +// CHECK: "\01?foobarbazqux@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@2V?$Y@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NB@PR13207@@@52@@Z" +} + +namespace NC { +class X {}; +template<class T> class Y {}; + +void foo(Y<NB::X> x) {} +// CHECK: "\01?foo@NC@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@@Z" + +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" +} +} diff --git a/test/CodeGenCXX/mangle-ms-back-references.cpp b/test/CodeGenCXX/mangle-ms-back-references.cpp new file mode 100644 index 0000000..5f93590 --- /dev/null +++ b/test/CodeGenCXX/mangle-ms-back-references.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -fms-extensions -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +void f1(const char* a, const char* b) {} +// CHECK: "\01?f1@@YAXPBD0@Z" + +void f2(const char* a, char* b) {} +// CHECK: "\01?f2@@YAXPBDPAD@Z" + +void f3(int a, const char* b, const char* c) {} +// CHECK: "\01?f3@@YAXHPBD0@Z" + +const char *f4(const char* a, const char* b) { return 0; } +// CHECK: "\01?f4@@YAPBDPBD0@Z" + +void f5(char const* a, unsigned int b, char c, void const* d, char const* e, unsigned int f) {} +// CHECK: "\01?f5@@YAXPBDIDPBX0I@Z" + +void f6(bool a, bool b) {} +// CHECK: "\01?f6@@YAX_N0@Z" + +void f7(int a, int* b, int c, int* d, bool e, bool f, bool* g) {} +// CHECK: "\01?f7@@YAXHPAHH0_N1PA_N@Z" + +// FIXME: tests for more than 10 types? + +struct S { + void mbb(bool a, bool b) {} +}; + +void g1(struct S a) {} +// CHECK: "\01?g1@@YAXUS@@@Z" + +void g2(struct S a, struct S b) {} +// CHECK: "\01?g2@@YAXUS@@0@Z" + +void g3(struct S a, struct S b, struct S* c, struct S* d) {} +// CHECK: "\01?g3@@YAXUS@@0PAU1@1@Z" + +void g4(const char* a, struct S* b, const char* c, struct S* d) { +// CHECK: "\01?g4@@YAXPBDPAUS@@01@Z" + b->mbb(false, false); +// CHECK: "\01?mbb@S@@QAEX_N0@Z" +} + +// Make sure that different aliases of built-in types end up mangled as the +// built-ins. +typedef unsigned int uintptr_t; +typedef unsigned int size_t; +void *h(size_t a, uintptr_t b) { return 0; } +// CHECK: "\01?h@@YAPAXII@Z" + +// Function pointers might be mangled in a complex way. +typedef void (*VoidFunc)(); +typedef int* (*PInt3Func)(int* a, int* b); + +void h1(const char* a, const char* b, VoidFunc c, VoidFunc d) {} +// CHECK: "\01?h1@@YAXPBD0P6AXXZ1@Z" + +void h2(void (*f_ptr)(void *), void *arg) {} +// CHECK: "\01?h2@@YAXP6AXPAX@Z0@Z" + +PInt3Func h3(PInt3Func x, PInt3Func y, int* z) { return 0; } +// CHECK: "\01?h3@@YAP6APAHPAH0@ZP6APAH00@Z10@Z" diff --git a/test/CodeGenCXX/mangle-ms-cxx11.cpp b/test/CodeGenCXX/mangle-ms-cxx11.cpp new file mode 100644 index 0000000..6947a53 --- /dev/null +++ b/test/CodeGenCXX/mangle-ms-cxx11.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++11 -fms-extensions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +// CHECK: "\01?LRef@@YAXAAH@Z" +void LRef(int& a) { } + +// CHECK: "\01?RRef@@YAH$$QAH@Z" +int RRef(int&& a) { return a; } + +// CHECK: "\01?Null@@YAX$$T@Z" +namespace std { typedef decltype(__nullptr) nullptr_t; } +void Null(std::nullptr_t) {} diff --git a/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp new file mode 100644 index 0000000..a5d03b3 --- /dev/null +++ b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp @@ -0,0 +1,173 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +void a1() {} +// CHECK: "\01?a1@@YAXXZ" + +int a2() { return 0; } +// CHECK: "\01?a2@@YAHXZ" + +const int a3() { return 0; } +// CHECK: "\01?a3@@YA?BHXZ" + +volatile int a4() { return 0; } +// CHECK: "\01?a4@@YA?CHXZ" + +const volatile int a5() { return 0; } +// CHECK: "\01?a5@@YA?DHXZ" + +float a6() { return 0.0f; } +// CHECK: "\01?a6@@YAMXZ" + +int *b1() { return 0; } +// CHECK: "\01?b1@@YAPAHXZ" + +const char *b2() { return 0; } +// CHECK: "\01?b2@@YAPBDXZ" + +float *b3() { return 0; } +// CHECK: "\01?b3@@YAPAMXZ" + +const float *b4() { return 0; } +// CHECK: "\01?b4@@YAPBMXZ" + +volatile float *b5() { return 0; } +// CHECK: "\01?b5@@YAPCMXZ" + +const volatile float *b6() { return 0; } +// CHECK: "\01?b6@@YAPDMXZ" + +float &b7() { return *(float*)0; } +// CHECK: "\01?b7@@YAAAMXZ" + +const float &b8() { return *(float*)0; } +// CHECK: "\01?b8@@YAABMXZ" + +volatile float &b9() { return *(float*)0; } +// CHECK: "\01?b9@@YAACMXZ" + +const volatile float &b10() { return *(float*)0; } +// CHECK: "\01?b10@@YAADMXZ" + +const char** b11() { return 0; } +// CHECK: "\01?b11@@YAPAPBDXZ" + +class A {}; + +A c1() { return A(); } +// CHECK: "\01?c1@@YA?AVA@@XZ" + +const A c2() { return A(); } +// CHECK: "\01?c2@@YA?BVA@@XZ" + +volatile A c3() { return A(); } +// CHECK: "\01?c3@@YA?CVA@@XZ" + +const volatile A c4() { return A(); } +// CHECK: "\01?c4@@YA?DVA@@XZ" + +const A* c5() { return 0; } +// CHECK: "\01?c5@@YAPBVA@@XZ" + +volatile A* c6() { return 0; } +// CHECK: "\01?c6@@YAPCVA@@XZ" + +const volatile A* c7() { return 0; } +// CHECK: "\01?c7@@YAPDVA@@XZ" + +A &c8() { return *(A*)0; } +// CHECK: "\01?c8@@YAAAVA@@XZ" + +const A &c9() { return *(A*)0; } +// CHECK: "\01?c9@@YAABVA@@XZ" + +volatile A &c10() { return *(A*)0; } +// CHECK: "\01?c10@@YAACVA@@XZ" + +const volatile A &c11() { return *(A*)0; } +// CHECK: "\01?c11@@YAADVA@@XZ" + +template<typename T> class B {}; + +B<int> d1() { return B<int>(); } +// CHECK: "\01?d1@@YA?AV?$B@H@@XZ" + +B<const char*> d2() {return B<const char*>(); } +// CHECK: "\01?d2@@YA?AV?$B@PBD@@XZ" + +B<A> d3() {return B<A>(); } +// CHECK: "\01?d3@@YA?AV?$B@VA@@@@XZ" + +B<A>* d4() { return 0; } +// CHECK: "\01?d4@@YAPAV?$B@VA@@@@XZ" + +const B<A>* d5() { return 0; } +// CHECK: "\01?d5@@YAPBV?$B@VA@@@@XZ" + +volatile B<A>* d6() { return 0; } +// CHECK: "\01?d6@@YAPCV?$B@VA@@@@XZ" + +const volatile B<A>* d7() { return 0; } +// CHECK: "\01?d7@@YAPDV?$B@VA@@@@XZ" + +B<A>& d8() { return *(B<A>*)0; } +// CHECK: "\01?d8@@YAAAV?$B@VA@@@@XZ" + +const B<A>& d9() { return *(B<A>*)0; } +// CHECK: "\01?d9@@YAABV?$B@VA@@@@XZ" + +volatile B<A>& d10() { return *(B<A>*)0; } +// CHECK: "\01?d10@@YAACV?$B@VA@@@@XZ" + +const volatile B<A>& d11() { return *(B<A>*)0; } +// CHECK: "\01?d11@@YAADV?$B@VA@@@@XZ" + +enum Enum { DEFAULT }; + +Enum e1() { return DEFAULT; } +// CHECK: "\01?e1@@YA?AW4Enum@@XZ" + +const Enum e2() { return DEFAULT; } +// CHECK: "\01?e2@@YA?BW4Enum@@XZ" + +Enum* e3() { return 0; } +// CHECK: "\01?e3@@YAPAW4Enum@@XZ" + +Enum& e4() { return *(Enum*)0; } +// CHECK: "\01?e4@@YAAAW4Enum@@XZ" + +struct S {}; + +struct S f1() { struct S s; return s; } +// CHECK: "\01?f1@@YA?AUS@@XZ" + +const struct S f2() { struct S s; return s; } +// CHECK: "\01?f2@@YA?BUS@@XZ" + +struct S* f3() { return 0; } +// CHECK: "\01?f3@@YAPAUS@@XZ" + +const struct S* f4() { return 0; } +// CHECK: "\01?f4@@YAPBUS@@XZ" + +const volatile struct S* f5() { return 0; } +// CHECK: "\01?f5@@YAPDUS@@XZ" + +struct S& f6() { return *(struct S*)0; } +// CHECK: "\01?f6@@YAAAUS@@XZ" + +typedef int (*function_pointer)(int); + +function_pointer g1() { return 0; } +// CHECK: "\01?g1@@YAP6AHH@ZXZ" + +const function_pointer g2() { return 0; } +// CHECK: "\01?g2@@YAQ6AHH@ZXZ" + +function_pointer* g3() { return 0; } +// CHECK: "\01?g3@@YAPAP6AHH@ZXZ" + +const function_pointer* g4() { return 0; } +// The mangling of g4 is currently "\01?g4@@YAPQ6AHH@ZXZ" which is wrong. +// This looks related to http://llvm.org/PR13444 +// FIXME: replace CHECK-NOT with CHECK once it is fixed. +// CHECK-NOT: "\01?g4@@YAPBQ6AHH@ZXZ" diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp new file mode 100644 index 0000000..977ef35 --- /dev/null +++ b/test/CodeGenCXX/mangle-ms-templates.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +template<typename T> +class Class { + public: + void method() {} +}; + +class Typename { }; + +template<typename T> +class Nested { }; + +template<bool flag> +class BoolTemplate { + public: + BoolTemplate() {} +}; + +template<int param> +class IntTemplate { + public: + IntTemplate() {} +}; + +template<> +class BoolTemplate<true> { + public: + BoolTemplate() {} + template<class T> void Foo(T arg) {} +}; + +void template_mangling() { + Class<Typename> c1; + c1.method(); +// CHECK: call {{.*}} @"\01?method@?$Class@VTypename@@@@QAEXXZ" + + Class<Nested<Typename> > c2; + c2.method(); +// CHECK: call {{.*}} @"\01?method@?$Class@V?$Nested@VTypename@@@@@@QAEXXZ" + + BoolTemplate<false> _false; +// CHECK: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QAE@XZ" + + BoolTemplate<true> _true; + // PR13158 + _true.Foo(1); +// CHECK: call {{.*}} @"\01??0?$BoolTemplate@$00@@QAE@XZ" +// CHECK: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QAEXH@Z" + + IntTemplate<5> five; +// CHECK: call {{.*}} @"\01??0?$IntTemplate@$04@@QAE@XZ" + + IntTemplate<11> eleven; +// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QAE@XZ" + + IntTemplate<65535> ffff; +// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QAE@XZ" +} + +namespace space { + template<class T> const T& foo(const T& l) { return l; } +} +// CHECK: "\01??$foo@H@space@@YAABHABH@Z" + +void use() { + space::foo(42); +} diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp index fe5fde1..f392c17 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -12,6 +12,13 @@ // CHECK: @"\01?j@@3P6GHCE@ZA" // CHECK: @"\01?k@@3PTfoo@@DA" // CHECK: @"\01?l@@3P8foo@@AEHH@ZA" +// CHECK: @"\01?color1@@3PANA" + +// FIXME: The following three tests currently fail, see PR13182. +// Replace "CHECK-NOT" with "CHECK" when it is fixed. +// CHECK-NOT: @"\01?color2@@3QBNB" +// CHECK-NOT: @"\01?color3@@3QAY02$$CBNA" +// CHECK-NOT: @"\01?color4@@3QAY02$$CBNA" int a; @@ -39,8 +46,13 @@ public: foo(char *q){} //CHECK: @"\01??0foo@@QAE@PAD@Z" + + static foo* static_method() { return 0; } + }f,s1(1),s2((char*)0); +typedef foo (foo2); + struct bar { static int g; }; @@ -57,8 +69,17 @@ enum quux { qthree }; -int foo::operator+(int a) {return a;} -// CHECK: @"\01??Hfoo@@QAEHH@Z" +foo bar() { return foo(); } +//CHECK: @"\01?bar@@YA?AVfoo@@XZ" + +int foo::operator+(int a) { +//CHECK: @"\01??Hfoo@@QAEHH@Z" + + foo::static_method(); +//CHECK: @"\01?static_method@foo@@SAPAV1@XZ" + bar(); + return a; +} const short foo::d = 0; volatile long foo::e; @@ -72,9 +93,9 @@ int i[10][20]; int (__stdcall *j)(signed char, unsigned char); -const volatile char foo::*k; +const volatile char foo2::*k; -int (foo::*l)(int); +int (foo2::*l)(int); // Static functions are mangled, too. // Also make sure calling conventions, arglists, and throw specs work. @@ -99,7 +120,45 @@ void delta(int * const a, const long &) {} void epsilon(int a[][10][20]) {} // CHECK: @"\01?epsilon@@YAXQAY19BE@H@Z" -// Blocks mangling (Clang extension). -void zeta(int (^)(int, int)) {} -// CHECK: @"\01?zeta@@YAXP_EAHHH@Z@Z" +void zeta(int (*)(int, int)) {} +// CHECK: @"\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" + +void operator_new_delete() { + char *ptr = new char; +// CHECK: @"\01??2@YAPAXI@Z" + + delete ptr; +// CHECK: @"\01??3@YAXPAX@Z" + + char *array = new char[42]; +// CHECK: @"\01??_U@YAPAXI@Z" + + delete [] array; +// CHECK: @"\01??_V@YAXPAX@Z" +} +// PR13022 +void (redundant_parens)(); +void redundant_parens_use() { redundant_parens(); } +// CHECK: @"\01?redundant_parens@@YAXXZ" + +// PR13182, PR13047 +typedef double RGB[3]; +RGB color1; +extern const RGB color2 = {}; +extern RGB const color3[5] = {}; +extern RGB const ((color4)[5]) = {}; + +// PR12603 +enum E {}; +// CHECK: "\01?fooE@@YA?AW4E@@XZ" +E fooE() { return E(); } + +class X {}; +// CHECK: "\01?fooX@@YA?AVX@@XZ" +X fooX() { return X(); } diff --git a/test/CodeGenCXX/mangle-ref-qualifiers.cpp b/test/CodeGenCXX/mangle-ref-qualifiers.cpp index 568cf9f..ce2af50 100644 --- a/test/CodeGenCXX/mangle-ref-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ref-qualifiers.cpp @@ -12,5 +12,11 @@ int X::g() && { return 0; } // CHECK: define i32 @_ZNKO1X1hEv int X::h() const && { return 0; } -// CHECK: define void @_Z1fM1XRFivEMS_OFivEMS_KOFivE +// CHECK: 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() +template <class T> struct A {}; +void g(A<int()>, A<int()&>, A<int()&&>, + A<int() const>, A<int() const &>, A<int() const &&>, + A<int() const volatile>, A<int() const volatile &>, A<int() const volatile &&>) {} diff --git a/test/CodeGenCXX/member-data-pointers.cpp b/test/CodeGenCXX/member-data-pointers.cpp new file mode 100644 index 0000000..d347366 --- /dev/null +++ b/test/CodeGenCXX/member-data-pointers.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-unknown-unknown | FileCheck -check-prefix GLOBAL-LP64 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix GLOBAL-LP32 %s + +struct A; +typedef int A::*param_t; +struct { + const char *name; + param_t par; +} *ptr; +void test_ptr() { (void) ptr; } // forced use + +// GLOBAL-LP64: type { i8*, i64 } +// GLOBAL-LP32: type { i8*, i32 } diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 2417aa4..84b54b6 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -1,6 +1,8 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s -// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-apple-darwin9 | FileCheck -check-prefix LP32 %s -// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix ARM %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-unknown-unknown | FileCheck -check-prefix CODE-LP64 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-unknown-unknown | FileCheck -check-prefix CODE-LP32 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-unknown-unknown | FileCheck -check-prefix GLOBAL-LP64 %s +// 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 struct A { int a; void f(); virtual void vf1(); virtual void vf2(); }; struct B { int b; virtual void g(); }; @@ -11,66 +13,56 @@ void (A::*volatile vpa)(); void (B::*pb)(); void (C::*pc)(); -// CHECK: @pa2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8 +// GLOBAL-LP64: @pa2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8 void (A::*pa2)() = &A::f; -// CHECK: @pa3 = global { i64, i64 } { i64 1, i64 0 }, align 8 -// CHECK-LP32: @pa3 = global { i32, i32 } { i32 1, i32 0 }, align 4 +// GLOBAL-LP64: @pa3 = global { i64, i64 } { i64 1, i64 0 }, align 8 +// GLOBAL-LP32: @pa3 = global { i32, i32 } { i32 1, i32 0 }, align 4 void (A::*pa3)() = &A::vf1; -// CHECK: @pa4 = global { i64, i64 } { i64 9, i64 0 }, align 8 -// CHECK-LP32: @pa4 = global { i32, i32 } { i32 5, i32 0 }, align 4 +// GLOBAL-LP64: @pa4 = global { i64, i64 } { i64 9, i64 0 }, align 8 +// GLOBAL-LP32: @pa4 = global { i32, i32 } { i32 5, i32 0 }, align 4 void (A::*pa4)() = &A::vf2; -// CHECK: @pc2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8 +// GLOBAL-LP64: @pc2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8 void (C::*pc2)() = &C::f; -// CHECK: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8 +// GLOBAL-LP64: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8 void (A::*pc3)() = &A::vf1; -// Tests for test10. -// CHECK: @_ZN6test101aE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 0 }, align 8 -// CHECK: @_ZN6test101bE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 -// CHECK: @_ZN6test101cE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 -// CHECK: @_ZN6test101dE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 16 }, align 8 -// CHECK-LP32: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 -// CHECK-LP32: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 -// CHECK-LP32: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 -// CHECK-LP32: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 - void f() { - // CHECK: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa + // CODE-LP64: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa pa = 0; // Is this okay? What are LLVM's volatile semantics for structs? - // CHECK: store volatile { i64, i64 } zeroinitializer, { i64, i64 }* @vpa + // CODE-LP64: store volatile { i64, i64 } zeroinitializer, { i64, i64 }* @vpa vpa = 0; - // CHECK: [[TMP:%.*]] = load { i64, i64 }* @pa, align 8 - // CHECK: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1 - // CHECK: [[ADJ:%.*]] = add nsw i64 [[TMPADJ]], 16 - // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 - // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pc, align 8 + // CODE-LP64: [[TMP:%.*]] = load { i64, i64 }* @pa, align 8 + // CODE-LP64: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1 + // CODE-LP64: [[ADJ:%.*]] = add nsw i64 [[TMPADJ]], 16 + // CODE-LP64: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 + // CODE-LP64: store { i64, i64 } [[RES]], { i64, i64 }* @pc, align 8 pc = pa; - // CHECK: [[TMP:%.*]] = load { i64, i64 }* @pc, align 8 - // CHECK: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1 - // CHECK: [[ADJ:%.*]] = sub nsw i64 [[TMPADJ]], 16 - // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 - // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pa, align 8 + // CODE-LP64: [[TMP:%.*]] = load { i64, i64 }* @pc, align 8 + // CODE-LP64: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1 + // CODE-LP64: [[ADJ:%.*]] = sub nsw i64 [[TMPADJ]], 16 + // CODE-LP64: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 + // CODE-LP64: store { i64, i64 } [[RES]], { i64, i64 }* @pa, align 8 pa = static_cast<void (A::*)()>(pc); } void f2() { - // CHECK: store { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 } + // CODE-LP64: store { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 } void (A::*pa2)() = &A::f; - // CHECK: store { i64, i64 } { i64 1, i64 0 } - // CHECK-LP32: store { i32, i32 } { i32 1, i32 0 } + // CODE-LP64: store { i64, i64 } { i64 1, i64 0 } + // CODE-LP32: store { i32, i32 } { i32 1, i32 0 } void (A::*pa3)() = &A::vf1; - // CHECK: store { i64, i64 } { i64 9, i64 0 } - // CHECK-LP32: store { i32, i32 } { i32 5, i32 0 } + // CODE-LP64: store { i64, i64 } { i64 9, i64 0 } + // CODE-LP32: store { i32, i32 } { i32 5, i32 0 } void (A::*pa4)() = &A::vf2; } @@ -195,12 +187,12 @@ namespace test7 { struct B { void foo(); virtual void vfoo(); }; struct C : A, B { void foo(); virtual void vfoo(); }; - // CHECK-ARM: @_ZN5test74ptr0E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71A3fooEv to i32), i32 0 } - // CHECK-ARM: @_ZN5test74ptr1E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71B3fooEv to i32), i32 8 } - // CHECK-ARM: @_ZN5test74ptr2E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71C3fooEv to i32), i32 0 } - // CHECK-ARM: @_ZN5test74ptr3E = global {{.*}} { i32 0, i32 1 } - // CHECK-ARM: @_ZN5test74ptr4E = global {{.*}} { i32 0, i32 9 } - // CHECK-ARM: @_ZN5test74ptr5E = global {{.*}} { i32 0, i32 1 } + // GLOBAL-ARM: @_ZN5test74ptr0E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71A3fooEv to i32), i32 0 } + // GLOBAL-ARM: @_ZN5test74ptr1E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71B3fooEv to i32), i32 8 } + // GLOBAL-ARM: @_ZN5test74ptr2E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71C3fooEv to i32), i32 0 } + // GLOBAL-ARM: @_ZN5test74ptr3E = global {{.*}} { i32 0, i32 1 } + // GLOBAL-ARM: @_ZN5test74ptr4E = global {{.*}} { i32 0, i32 9 } + // GLOBAL-ARM: @_ZN5test74ptr5E = global {{.*}} { i32 0, i32 1 } void (C::*ptr0)() = &A::foo; void (C::*ptr1)() = &B::foo; void (C::*ptr2)() = &C::foo; @@ -234,9 +226,9 @@ namespace test9 { fooptr p; }; - // CHECK: define void @_ZN5test94testEv( - // CHECK: alloca i32 - // CHECK-NEXT: ret void + // CODE-LP64: define void @_ZN5test94testEv( + // CODE-LP64: alloca i32 + // CODE-LP64-NEXT: ret void void test() { int x; static S array[] = { (fooptr) &B::foo }; @@ -261,14 +253,37 @@ namespace test10 { virtual void requireNonZeroAdjustment(); }; - // Non-ARM tests at top of file. + +// It's not that the offsets are doubled on ARM, it's that they're left-shifted by 1. + +// GLOBAL-LP64: @_ZN6test101aE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 0 }, align 8 +// GLOBAL-LP32: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 +// GLOBAL-ARM: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 void (A::*a)() = &A::foo; + +// GLOBAL-LP64: @_ZN6test101bE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 +// GLOBAL-LP32: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 +// GLOBAL-ARM: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 void (B::*b)() = (void (B::*)()) &A::foo; + +// GLOBAL-LP64: @_ZN6test101cE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 +// GLOBAL-LP32: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 +// GLOBAL-ARM: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 void (C::*c)() = (void (C::*)()) (void (B::*)()) &A::foo; + +// GLOBAL-LP64: @_ZN6test101dE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 16 }, align 8 +// GLOBAL-LP32: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 +// GLOBAL-ARM: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 16 }, align 4 void (D::*d)() = (void (C::*)()) (void (B::*)()) &A::foo; } -// It's not that the offsets are doubled on ARM, it's that they're left-shifted by 1. -// CHECK-ARM: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 -// CHECK-ARM: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 -// CHECK-ARM: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 -// CHECK-ARM: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 16 }, align 4 + +namespace test11 { + struct A { virtual void a(); }; + struct B : A {}; + struct C : B { virtual void a(); }; + void (C::*x)() = &C::a; + + // GLOBAL-LP64: @_ZN6test111xE = global { i64, i64 } { i64 1, i64 0 } + // GLOBAL-LP32: @_ZN6test111xE = global { i32, i32 } { i32 1, i32 0 } + // GLOBAL-ARM: @_ZN6test111xE = global { i32, i32 } { i32 0, i32 1 } +} diff --git a/test/CodeGenCXX/member-init-anon-union.cpp b/test/CodeGenCXX/member-init-anon-union.cpp index 1ff7537..4db31f0 100644 --- a/test/CodeGenCXX/member-init-anon-union.cpp +++ b/test/CodeGenCXX/member-init-anon-union.cpp @@ -2,8 +2,10 @@ // PR10531. +int make_a(); + static union { - int a = 42; + int a = make_a(); char *b; }; @@ -32,4 +34,4 @@ int g() { // CHECK: define {{.*}}@"[[CONSTRUCT_GLOBAL]]C2Ev" // CHECK-NOT: } -// CHECK: store i32 42 +// CHECK: call {{.*}}@_Z6make_a diff --git a/test/CodeGenCXX/member-init-ctor.cpp b/test/CodeGenCXX/member-init-ctor.cpp deleted file mode 100644 index 2172394..0000000 --- a/test/CodeGenCXX/member-init-ctor.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s - -bool b(); -struct S { - int n = b() ? S().n + 1 : 0; -}; - -S s; - -// CHECK: define {{.*}} @_ZN1SC2Ev( -// CHECK-NOT } -// CHECK: call {{.*}} @_Z1bv() -// CHECK-NOT } -// CHECK: call {{.*}} @_ZN1SC1Ev( diff --git a/test/CodeGenCXX/member-pointer-type-convert.cpp b/test/CodeGenCXX/member-pointer-type-convert.cpp deleted file mode 100644 index 2970a2e..0000000 --- a/test/CodeGenCXX/member-pointer-type-convert.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s - -struct A; -typedef int A::*param_t; -struct { - const char *name; - param_t par; -} *ptr; -void test_ptr() { (void) ptr; } // forced use - -// CHECK: type { i8*, {{i..}} } diff --git a/test/CodeGenCXX/microsoft-abi-array-cookies.cpp b/test/CodeGenCXX/microsoft-abi-array-cookies.cpp new file mode 100644 index 0000000..e07b097 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-array-cookies.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct ClassWithoutDtor { + char x; +}; + +void check_array_no_cookies() { +// CHECK: define void @"\01?check_array_no_cookies@@YAXXZ"() nounwind + +// CHECK: call noalias i8* @"\01??_U@YAPAXI@Z"(i32 42) + ClassWithoutDtor *array = new ClassWithoutDtor[42]; + +// CHECK: call void @"\01??_V@YAXPAX@Z"( + delete [] array; + +} + +struct ClassWithDtor { + char x; + ~ClassWithDtor() {} +}; + +void check_array_cookies_simple() { +// CHECK: define {{.*}} @"\01?check_array_cookies_simple@@YAXXZ"() + + ClassWithDtor *array = new ClassWithDtor[42]; +// CHECK: [[ALLOCATED:%.*]] = call noalias i8* @"\01??_U@YAPAXI@Z"(i32 46) +// 46 = 42 + size of cookie (4) +// CHECK: [[COOKIE:%.*]] = bitcast i8* [[ALLOCATED]] to i32* +// CHECK: store i32 42, i32* [[COOKIE]] +// CHECK: [[ARRAY:%.*]] = getelementptr inbounds i8* [[ALLOCATED]], i64 4 +// CHECK: bitcast i8* [[ARRAY]] to [[CLASS:%.*]]* + + delete [] array; +// CHECK: [[ARRAY_AS_CHAR:%.*]] = bitcast [[CLASS]]* {{%.*}} to i8* +// CHECK: getelementptr inbounds i8* [[ARRAY_AS_CHAR]], i64 -4 +} + +struct __attribute__((aligned(8))) ClassWithAlignment { + // FIXME: replace __attribute__((aligned(8))) with __declspec(align(8)) once + // http://llvm.org/bugs/show_bug.cgi?id=12631 is fixed. + int *x, *y; + ~ClassWithAlignment() {} +}; + +void check_array_cookies_aligned() { +// CHECK: define {{.*}} @"\01?check_array_cookies_aligned@@YAXXZ"() + ClassWithAlignment *array = new ClassWithAlignment[42]; +// CHECK: [[ALLOCATED:%.*]] = call noalias i8* @"\01??_U@YAPAXI@Z"(i32 344) +// 344 = 42*8 + size of cookie (8, due to alignment) +// CHECK: [[COOKIE:%.*]] = bitcast i8* [[ALLOCATED]] to i32* +// CHECK: store i32 42, i32* [[COOKIE]] +// CHECK: [[ARRAY:%.*]] = getelementptr inbounds i8* [[ALLOCATED]], i64 8 +// CHECK: bitcast i8* [[ARRAY]] to [[CLASS:%.*]]* + + delete [] array; +// CHECK: [[ARRAY_AS_CHAR:%.*]] = bitcast [[CLASS]]* +// CHECK: getelementptr inbounds i8* [[ARRAY_AS_CHAR]], i64 -8 +} diff --git a/test/CodeGenCXX/microsoft-abi-constructors.cpp b/test/CodeGenCXX/microsoft-abi-constructors.cpp new file mode 100644 index 0000000..ac27f13 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-constructors.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +class A { + public: + A() { } + ~A() { } +}; + +void no_contstructor_destructor_infinite_recursion() { + A a; + +// Make sure that the constructor doesn't call itself: +// CHECK: define {{.*}} @"\01??0A@@QAE@XZ" +// CHECK-NOT: call void @"\01??0A@@QAE@XZ" +// CHECK: ret + +// Make sure that the destructor doesn't call itself: +// CHECK: define {{.*}} @"\01??1A@@QAE@XZ" +// CHECK-NOT: call void @"\01??1A@@QAE@XZ" +// CHECK: ret +} diff --git a/test/CodeGenCXX/microsoft-abi-methods.cpp b/test/CodeGenCXX/microsoft-abi-methods.cpp new file mode 100644 index 0000000..6b7f004 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-methods.cpp @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +class C { + public: + void simple_method() {} + + void __cdecl cdecl_method() {} + + void vararg_method(const char *fmt, ...) {} + + static void static_method() {} + + int a; +}; + +void call_simple_method() { + C instance; + + instance.simple_method(); +// Make sure that the call uses the right calling convention: +// CHECK: call x86_thiscallcc void @"\01?simple_method@C@@QAEXXZ" +// CHECK: ret + +// Make sure that the definition uses the right calling convention: +// CHECK: define linkonce_odr x86_thiscallcc void @"\01?simple_method@C@@QAEXXZ" +// CHECK: ret +} + +void call_cdecl_method() { + C instance; + instance.cdecl_method(); +// Make sure that the call uses the right calling convention: +// CHECK: call void @"\01?cdecl_method@C@@QAAXXZ" +// CHECK: ret + +// Make sure that the definition uses the right calling convention: +// CHECK: define linkonce_odr void @"\01?cdecl_method@C@@QAAXXZ" +// CHECK: ret +} + +void call_vararg_method() { + C instance; + instance.vararg_method("Hello"); +// Make sure that the call uses the right calling convention: +// CHECK: call void (%class.C*, i8*, ...)* @"\01?vararg_method@C@@QAAXPBDZZ" +// CHECK: ret + +// Make sure that the definition uses the right calling convention: +// CHECK: define linkonce_odr void @"\01?vararg_method@C@@QAAXPBDZZ" +} + +void call_static_method() { + C::static_method(); +// Make sure that the call uses the right calling convention: +// CHECK: call void @"\01?static_method@C@@SAXXZ" +// CHECK: ret + +// Make sure that the definition uses the right calling convention: +// CHECK: define linkonce_odr void @"\01?static_method@C@@SAXXZ" +} + +class Base { + public: + Base() {} + ~Base() {} +}; + +class Child: public Base { }; + +void constructors() { + Child c; +// Make sure that the Base constructor call in the Child constructor uses +// the right calling convention: +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0Child@@QAE@XZ" +// CHECK: call x86_thiscallcc void @"\01??0Base@@QAE@XZ" +// CHECK: ret + +// Make sure that the Base destructor call in the Child denstructor uses +// the right calling convention: +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1Child@@QAE@XZ" +// CHECK: call x86_thiscallcc void @"\01??1Base@@QAE@XZ" +// CHECK: ret + +// Make sure that the Base destructor definition uses the right CC: +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1Base@@QAE@XZ" + +// Make sure that the Base constructor definition uses the right CC: +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0Base@@QAE@XZ" +} diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp new file mode 100644 index 0000000..d8b7899 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct S { + S() {} + ~S() {} +} s; + +// CHECK: define internal void [[INIT_s:@.*global_var.*]] nounwind +// CHECK: call x86_thiscallcc void @"\01??0S@@QAE@XZ" +// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A") +// CHECK: ret void + +// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() nounwind { +// CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ" +// CHECK: ret void + +// Force WeakODRLinkage by using templates +class A { + public: + A() {} + ~A() {} +}; + +template<typename T> +class B { + public: + static A foo; +}; + +template<typename T> A B<T>::foo; + +void force_usage() { + (void)B<int>::foo; // (void) - force usage +} + +// CHECK: define internal void [[INIT_foo:@.*global_var.*]] nounwind +// CHECK: call x86_thiscallcc void @"\01??0A@@QAE@XZ" +// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]]) +// CHECK: ret void + +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0A@@QAE@XZ" + +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ" + +// CHECK: define internal void [[FOO_DTOR]] +// CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo +// CHECK: ret void + +// CHECK: define internal void @_GLOBAL__I_a() nounwind { +// CHECK: call void [[INIT_s]] +// CHECK: call void [[INIT_foo]] +// CHECK: ret void diff --git a/test/CodeGenCXX/ms_wide_predefined_expr.cpp b/test/CodeGenCXX/ms_wide_predefined_expr.cpp new file mode 100644 index 0000000..5f0bcde --- /dev/null +++ b/test/CodeGenCXX/ms_wide_predefined_expr.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -fms-extensions -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s + +// CHECK: @L__FUNCTION__._Z4funcv = private constant [5 x i16] [i16 102, i16 117, i16 110, i16 99, i16 0], align 2 + +void wprint(const wchar_t*); + +#define __STR2WSTR(str) L##str +#define _STR2WSTR(str) __STR2WSTR(str) +#define STR2WSTR(str) _STR2WSTR(str) + +void func() { + wprint(STR2WSTR(__FUNCTION__)); +} + +int main() { + func(); + + return 0; +} + diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp index 90024e4..fe69cd5 100644 --- a/test/CodeGenCXX/pointers-to-data-members.cpp +++ b/test/CodeGenCXX/pointers-to-data-members.cpp @@ -240,3 +240,17 @@ namespace PR11487 { // CHECK-GLOBAL: @_ZN7PR114871xE = global %"union.PR11487::U" { i64 -1, [8 x i8] zeroinitializer }, align 8 } + +namespace PR13097 { + struct X { int x; X(const X&); }; + struct A { + int qq; + X x; + }; + A f(); + X g() { return f().*&A::x; } + // CHECK: define void @_ZN7PR130971gEv + // CHECK: call void @_ZN7PR130971fEv + // CHECK-NOT: memcpy + // CHECK: call void @_ZN7PR130971XC1ERKS0_ +} diff --git a/test/CodeGenCXX/pr13396.cpp b/test/CodeGenCXX/pr13396.cpp new file mode 100644 index 0000000..7d4e2ce --- /dev/null +++ b/test/CodeGenCXX/pr13396.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -emit-llvm -o - | FileCheck %s +struct foo { + template<typename T> + __attribute__ ((regparm (3))) foo(T x) {} + __attribute__ ((regparm (3))) foo(); + __attribute__ ((regparm (3))) ~foo(); +}; + +foo::foo() { + // CHECK: define void @_ZN3fooC1Ev(%struct.foo* inreg %this) + // CHECK: 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) +} + +void dummy() { + // FIXME: how can we explicitly instantiate a template constructor? Gcc and + // 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) +} diff --git a/test/CodeGenCXX/pragma-visibility.cpp b/test/CodeGenCXX/pragma-visibility.cpp index e54626e..11a38c1 100644 --- a/test/CodeGenCXX/pragma-visibility.cpp +++ b/test/CodeGenCXX/pragma-visibility.cpp @@ -17,14 +17,6 @@ int x2::y = 10; #pragma GCC visibility pop #pragma GCC visibility push(hidden) -struct x3 { - static int y; -} __attribute((visibility("default"))); -int x3::y = 10; -// CHECK: @_ZN2x31yE = global -#pragma GCC visibility pop - -#pragma GCC visibility push(hidden) template<class T> struct x4 { static int y; }; @@ -60,3 +52,23 @@ namespace n __attribute((visibility("default"))) { // CHECK: define hidden void @_ZN1n1gEv #pragma GCC visibility pop } + +namespace test2 { +#pragma GCC visibility push(default) +#pragma GCC visibility push(hidden) + struct foo { // foo is hidden + }; +#pragma GCC visibility pop + struct foo; // declaration is ok, we ignore the default in the stack + template<typename T> + struct bar { // bar is default + static void f(){} + }; +#pragma GCC visibility pop + void zed() { + bar<foo>::f(); + bar<int>::f(); + } + // CHECK: define linkonce_odr hidden void @_ZN5test23barINS_3fooEE1fEv + // CHECK: define linkonce_odr void @_ZN5test23barIiE1fEv +} diff --git a/test/CodeGenCXX/rvalue-references.cpp b/test/CodeGenCXX/rvalue-references.cpp index 1c25543..b8d47dc 100644 --- a/test/CodeGenCXX/rvalue-references.cpp +++ b/test/CodeGenCXX/rvalue-references.cpp @@ -10,7 +10,7 @@ B &getB(); // CHECK: define %struct.A* @_Z4getAv() // CHECK: call %struct.B* @_Z4getBv() // CHECK-NEXT: bitcast %struct.B* -// CHECK-NEXT: getelementptr i8* +// CHECK-NEXT: getelementptr inbounds i8* // CHECK-NEXT: bitcast i8* {{.*}} to %struct.A* // CHECK-NEXT: ret %struct.A* A &&getA() { return static_cast<A&&>(getB()); } diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp index 09b3a4f..b90716b 100644 --- a/test/CodeGenCXX/template-instantiation.cpp +++ b/test/CodeGenCXX/template-instantiation.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -O1 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -O1 -disable-llvm-optzns -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s // CHECK: @_ZN7PR100011xE = global // CHECK-NOT: @_ZN7PR100014kBarE = external global i32 @@ -13,7 +13,7 @@ // CHECK-NOT: _ZTVN5test31SIiEE // CHECK-NOT: _ZTSN5test31SIiEE -// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* nocapture %this) unnamed_addr +// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* %this) unnamed_addr // CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_( // CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd( diff --git a/test/CodeGenCXX/throw-expression-cleanup.cpp b/test/CodeGenCXX/throw-expression-cleanup.cpp new file mode 100644 index 0000000..0c41bc6 --- /dev/null +++ b/test/CodeGenCXX/throw-expression-cleanup.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - | FileCheck %s +// PR13359 + +struct X { + ~X(); +}; +struct Error { + Error(const X&) noexcept; +}; + +void f() { + try { + throw Error(X()); + } catch (...) { } +} + +// CHECK: define void @_Z1fv +// CHECK: call void @_ZN5ErrorC1ERK1X +// CHECK: invoke void @__cxa_throw +// CHECK: landingpad +// CHECK: call void @_ZN1XD1Ev +// CHECK-NOT: __cxa_free_exception diff --git a/test/CodeGenCXX/virt-call-offsets.cpp b/test/CodeGenCXX/virt-call-offsets.cpp deleted file mode 100644 index 5eef6fe..0000000 --- a/test/CodeGenCXX/virt-call-offsets.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s - -struct A { virtual void a(); }; -struct B : A {}; -struct C : B { virtual void a(); }; -void (C::*x)() = &C::a; - -// CHECK: @x = global { i{{[0-9]+}}, i{{[0-9]+}} } { i{{[0-9]+}} 1, i{{[0-9]+}} 0 } diff --git a/test/CodeGenCXX/virt-template-vtable.cpp b/test/CodeGenCXX/virt-template-vtable.cpp index 25736fd..a6067d6 100644 --- a/test/CodeGenCXX/virt-template-vtable.cpp +++ b/test/CodeGenCXX/virt-template-vtable.cpp @@ -20,3 +20,13 @@ template class A<short>; // CHECK: @_ZTV1AIlE = weak_odr unnamed_addr constant // CHECK: @_ZTV1AIsE = weak_odr unnamed_addr constant // CHECK: @_ZTV1AIiE = linkonce_odr unnamed_addr constant + +template<class T> struct C { + virtual void c() {} +}; +struct D : C<int> { + virtual void d(); +}; +void D::d() {} + +// CHECK: define {{.*}}@_ZN1CIiE1cEv( diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp index 1cc8bcc..7ef50b2 100644 --- a/test/CodeGenCXX/virtual-destructor-calls.cpp +++ b/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -46,3 +46,14 @@ C::~C() { } // CHECK: call void @_ZdlPv // Base dtor: just an alias to B's base dtor. + +namespace PR12798 { + // A qualified call to a base class destructor should not undergo virtual + // dispatch. Template instantiation used to lose the qualifier. + struct A { virtual ~A(); }; + template<typename T> void f(T *p) { p->A::~A(); } + + // CHECK: define {{.*}} @_ZN7PR127981fINS_1AEEEvPT_( + // CHECK: call void @_ZN7PR127981AD1Ev( + template void f(A*); +} diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp index d660b1b..2bb1348 100644 --- a/test/CodeGenCXX/visibility-inlines-hidden.cpp +++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp @@ -108,3 +108,21 @@ namespace PR11642 { template class Foo<int>; // CHECK: define weak_odr i32 @_ZN7PR116423FooIiE3fooEi } + +// Test that clang implements the new gcc behaviour for inline functions. +// GCC PR30066. +namespace test3 { + inline void foo(void) { + } + template<typename T> + inline void zed() { + } + template void zed<float>(); + void bar(void) { + foo(); + zed<int>(); + } + // CHECK: define weak_odr void @_ZN5test33zedIfEEvv + // CHECK: define linkonce_odr hidden void @_ZN5test33fooEv + // CHECK: define linkonce_odr hidden void @_ZN5test33zedIiEEvv +} diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp index 59fd7c2..0145039 100644 --- a/test/CodeGenCXX/visibility.cpp +++ b/test/CodeGenCXX/visibility.cpp @@ -1,10 +1,24 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-HIDDEN +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-HIDDEN #define HIDDEN __attribute__((visibility("hidden"))) #define PROTECTED __attribute__((visibility("protected"))) #define DEFAULT __attribute__((visibility("default"))) +namespace test30 { + // When H is hidden, it should make X hidden, even if the template argument + // is not. + struct H { + }; + template<H *T> + struct X { + }; + H DEFAULT a; + X<&a> b; + // CHECK: _ZN6test301bE = global + // CHECK-HIDDEN: _ZN6test301bE = hidden global +} + namespace test25 { template<typename T> struct X { @@ -28,6 +42,62 @@ namespace test28 { // CHECK-HIDDEN: @_ZN6test285myvecE = hidden global } +namespace test29 { +#pragma GCC visibility push(hidden) + struct RECT { + int top; + }; + __attribute__ ((visibility ("default"))) extern RECT data_rect; + RECT data_rect = { -1}; +#pragma GCC visibility pop + // CHECK: @_ZN6test299data_rectE = global + // CHECK-HIDDEN: @_ZN6test299data_rectE = global +} + +namespace test40 { + template<typename T> + struct foo { + DEFAULT static int bar; + }; + template<typename T> + int foo<T>::bar; + template struct foo<int>; + // CHECK: _ZN6test403fooIiE3barE = weak_odr global + // CHECK-HIDDEN: _ZN6test403fooIiE3barE = weak_odr global +} + +namespace test41 { + // Unlike gcc we propagate the information that foo not only is hidden, but + // has been explicitly marked as so. This lets us produce a hidden undefined + // reference to bar. + struct __attribute__((visibility("hidden"))) foo {}; + extern foo bar; + foo *zed() { + return &bar; + } + // CHECK: @_ZN6test413barE = external hidden global + // CHECK-HIDDEN: @_ZN6test413barE = external hidden global +} + +namespace test48 { + // Test that we use the visibility of struct foo when instantiating the + // template. Note that is a case where we disagree with gcc, it produces + // a default symbol. + struct HIDDEN foo { + }; + DEFAULT foo x; + + struct bar { + template<foo *z> + struct zed { + }; + }; + + bar::zed<&x> y; + // CHECK: _ZN6test481yE = hidden global + // CHECK-HIDDEN: _ZN6test481yE = hidden global +} + // CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10 // CHECK: @_ZN5Test71aE = hidden global // CHECK: @_ZN5Test71bE = global @@ -510,6 +580,8 @@ namespace PR10113 { }; template class foo::bar<zed>; // CHECK: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv + + // FIXME: This should be hidden as zed is hidden. // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv } @@ -541,6 +613,8 @@ namespace PR11690_2 { }; template class foo::zed<baz>; // CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv + + // FIXME: This should be hidden as baz is hidden. // CHECK-HIDDEN: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv } @@ -605,3 +679,436 @@ namespace test26 { // CHECK: define void @_ZN6test261CIiE1fEv // CHECK-HIDDEN: define void @_ZN6test261CIiE1fEv } + +namespace test31 { + struct A { + struct HIDDEN B { + static void DEFAULT baz(); + }; + }; + void f() { + A::B::baz(); + } + // CHECK: declare void @_ZN6test311A1B3bazEv() + // CHECK-HIDDEN: declare void @_ZN6test311A1B3bazEv() +} + +namespace test32 { + struct HIDDEN A { + struct DEFAULT B { + void DEFAULT baz(); + }; + }; + void A::B::baz() { + } + // CHECK: define void @_ZN6test321A1B3bazEv + // CHECK-HIDDEN: define void @_ZN6test321A1B3bazEv +} + +namespace test33 { + template<typename T> + class foo { + void bar() {} + }; + struct HIDDEN zed { + }; + template class DEFAULT foo<zed>; + // CHECK: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv + // CHECK-HIDDEN: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv +} + +namespace test34 { + struct foo { + }; + 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 +} + +namespace test35 { + // This is a really ugly testcase. GCC propagates the DEFAULT in zed's + // definition. What we do instead is be conservative about merging + // implicit visibilities. + // FIXME: Maybe the best thing to do here is error? The test at least + // makes sure we don't produce a hidden symbol for foo<zed>::bar. + template<typename T> + struct DEFAULT foo { + void bar() {} + }; + class zed; + template class foo<zed>; + class DEFAULT zed { + }; + // CHECK: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv + // CHECK-HIDDEN: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv +} + +namespace test36 { + template<typename T1, typename T2> + class foo { + void bar() {} + }; + 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 +} + +namespace test37 { + struct HIDDEN foo { + }; + 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 +} + +namespace test38 { + template<typename T> + class DEFAULT foo { + void bar() {} + }; + struct HIDDEN zed { + }; + template class foo<zed>; + // CHECK: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv + // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv +} + +namespace test39 { + class DEFAULT default_t; + class HIDDEN hidden_t; + template <class T> class A { + template <class U> class B { + HIDDEN void hidden() {} + void noattr() {} + template <class V> void temp() {} + }; + }; + template class DEFAULT A<hidden_t>; + template class DEFAULT A<hidden_t>::B<hidden_t>; + 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 + + // GCC produces a default for this one. Why? + // CHECK: 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 + + // GCC produces a default for this one. Why? + // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv +} + +namespace test42 { + struct HIDDEN foo { + }; + template <class P> + struct bar { + }; + template <> + struct HIDDEN bar<foo> { + DEFAULT static void zed(); + }; + void bar<foo>::zed() { + } + // CHECK: define hidden void @_ZN6test423barINS_3fooEE3zedEv + // CHECK-HIDDEN: define hidden void @_ZN6test423barINS_3fooEE3zedEv +} + +namespace test43 { + struct HIDDEN foo { + }; + template <class P> + void bar() { + } + template <> + DEFAULT void bar<foo>() { + } + // CHECK: define hidden void @_ZN6test433barINS_3fooEEEvv + // CHECK-HIDDEN: define hidden void @_ZN6test433barINS_3fooEEEvv +} + +namespace test44 { + template <typename T> + struct foo { + foo() {} + }; + namespace { + struct bar; + } + 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 +} + +namespace test45 { + template <typename T> + struct foo { + template <typename T2> + struct bar { + bar() {}; + }; + }; + namespace { + struct zed; + } + 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 +} + +namespace test46 { + template <typename T> + void foo() { + } + namespace { + struct bar; + } + template DEFAULT void foo<bar>(); + void zed() { + foo<bar>(); + } + // CHECK: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv + // CHECK-HIDDEN: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv +} + +namespace test47 { + struct foo { + template <typename T> + static void bar() { + } + }; + namespace { + struct zed; + } + template __attribute__((visibility("default"))) void foo::bar<zed>(); + void baz() { + foo::bar<zed>(); + } + // CHECK: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv + // CHECK-HIDDEN: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv +} + +namespace test49 { + // Test that we use the visibility of struct foo when instantiating the + // template. Note that is a case where we disagree with gcc, it produces + // a default symbol. + + struct HIDDEN foo { + }; + + DEFAULT foo x; + + struct bar { + template<foo *z> + void zed() { + } + }; + + template void bar::zed<&x>(); + // CHECK: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv + // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv +} + +namespace test50 { + // Test that we use the visibility of struct foo when instantiating the + // template. Note that is a case where we disagree with gcc, it produces + // a default symbol. + + struct HIDDEN foo { + }; + DEFAULT foo x; + template<foo *z> + struct DEFAULT bar { + void zed() { + } + }; + template void bar<&x>::zed(); + // CHECK: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv + // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv +} + +namespace test51 { + // Test that we use the visibility of struct foo when instantiating the + // template. Note that is a case where we disagree with gcc, it produces + // a default symbol. + + struct HIDDEN foo { + }; + DEFAULT foo x; + template<foo *z> + 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 +} + +namespace test52 { + // Test that we use the linkage of struct foo when instantiating the + // template. Note that is a case where we disagree with gcc, it produces + // an external symbol. + + namespace { + struct foo { + }; + } + template<foo *x> + void zed() { + } + void f() { + zed<nullptr>(); + } + // CHECK: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv + // CHECK-HIDDEN: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv +} + +namespace test53 { + template<typename _Tp > struct vector { + static void _M_fill_insert(); + }; +#pragma GCC visibility push(hidden) + // GCC doesn't seem to use the visibility of enums at all, we do. + enum zed {v1}; + + // GCC fails to mark this specialization hidden, we mark it. + template<> + struct vector<int> { + static void _M_fill_insert(); + }; + void foo() { + vector<unsigned>::_M_fill_insert(); + vector<int>::_M_fill_insert(); + vector<zed>::_M_fill_insert(); + } +#pragma GCC visibility pop + // CHECK: declare void @_ZN6test536vectorIjE14_M_fill_insertEv + // CHECK-HIDDEN: declare void @_ZN6test536vectorIjE14_M_fill_insertEv + // CHECK: declare hidden void @_ZN6test536vectorIiE14_M_fill_insertEv + // CHECK-HIDDEN: declare hidden void @_ZN6test536vectorIiE14_M_fill_insertEv + // CHECK: declare hidden void @_ZN6test536vectorINS_3zedEE14_M_fill_insertEv + // CHECK-HIDDEN: declare hidden void @_ZN6test536vectorINS_3zedEE14_M_fill_insertEv +} + +namespace test54 { + template <class T> + struct foo { + static void bar(); + }; +#pragma GCC visibility push(hidden) + class zed { + zed(const zed &); + }; + void bah() { + foo<zed>::bar(); + } +#pragma GCC visibility pop + // CHECK: declare hidden void @_ZN6test543fooINS_3zedEE3barEv + // CHECK-HIDDEN: declare hidden void @_ZN6test543fooINS_3zedEE3barEv +} + +namespace test55 { + template <class T> + struct __attribute__((visibility("hidden"))) foo { + static void bar(); + }; + template <class T> struct foo; + void foobar() { + foo<int>::bar(); + } + // CHECK: declare hidden void @_ZN6test553fooIiE3barEv + // CHECK-HIDDEN: declare hidden void @_ZN6test553fooIiE3barEv +} + +namespace test56 { + template <class T> struct foo; + template <class T> + struct __attribute__((visibility("hidden"))) foo { + static void bar(); + }; + void foobar() { + foo<int>::bar(); + } + // CHECK: declare hidden void @_ZN6test563fooIiE3barEv + // CHECK-HIDDEN: declare hidden void @_ZN6test563fooIiE3barEv +} + +namespace test57 { +#pragma GCC visibility push(hidden) + template <class T> + struct foo; + void bar(foo<int>*); + template <class T> + struct foo { + static void zed(); + }; + void bah() { + foo<int>::zed(); + } +#pragma GCC visibility pop + // CHECK: declare hidden void @_ZN6test573fooIiE3zedEv + // CHECK-HIDDEN: declare hidden void @_ZN6test573fooIiE3zedEv +} + +namespace test58 { +#pragma GCC visibility push(hidden) + struct foo; + template<typename T> + struct __attribute__((visibility("default"))) bar { + static void zed() { + } + }; + void bah() { + bar<foo>::zed(); + } +#pragma GCC visibility pop + // CHECK: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv +} + +namespace test59 { + DEFAULT int f(); + HIDDEN int g(); + typedef int (*foo)(); + template<foo x, foo y> + 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 + + 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 + } +} + +namespace test60 { + template<int i> + class __attribute__((visibility("hidden"))) a {}; + template<int i> + class __attribute__((visibility("default"))) b {}; + template<template<int> class x, template<int> class y> + 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 + + test<b, a>(); + // CHECK: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv + } +} |