diff options
Diffstat (limited to 'test/CodeGenCXX')
57 files changed, 1112 insertions, 249 deletions
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp index 2ddafec..324ff4a 100644 --- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp +++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -86,7 +86,7 @@ namespace test3 { // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 // CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to // CHECK-NEXT: [[CALLBACK:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0 - // CHECK-NEXT: store void (i8*)* null, void (i8*)** [[CALLBACK]] + // CHECK: store // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 // CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 1 @@ -114,3 +114,19 @@ template <typename T> struct Foo { }; }; Foo<int> f; + +namespace PR9683 { + struct QueueEntry { + union { + struct { + void* mPtr; + union { + unsigned mSubmissionTag; + }; + }; + unsigned mValue; + }; + QueueEntry() {} + }; + QueueEntry QE; +} diff --git a/test/CodeGenCXX/attr-used.cpp b/test/CodeGenCXX/attr-used.cpp index 26109e7..2c82184 100644 --- a/test/CodeGenCXX/attr-used.cpp +++ b/test/CodeGenCXX/attr-used.cpp @@ -2,8 +2,8 @@ // <rdar://problem/8684363>: clang++ not respecting __attribute__((used)) on destructors struct X0 { - // CHECK: define linkonce_odr void @_ZN2X0C1Ev + // CHECK: define linkonce_odr {{.*}} @_ZN2X0C1Ev __attribute__((used)) X0() {} - // CHECK: define linkonce_odr void @_ZN2X0D1Ev + // CHECK: define linkonce_odr {{.*}} @_ZN2X0D1Ev __attribute__((used)) ~X0() {} }; diff --git a/test/CodeGenCXX/block-byref-cxx-objc.cpp b/test/CodeGenCXX/block-byref-cxx-objc.cpp index a4fbd6c..135e0c7 100644 --- a/test/CodeGenCXX/block-byref-cxx-objc.cpp +++ b/test/CodeGenCXX/block-byref-cxx-objc.cpp @@ -16,9 +16,9 @@ int main() } // CHECK: define internal void @__Block_byref_object_copy_ -// CHECK: call void @_ZN1AC1ERKS_ +// CHECK: call {{.*}} @_ZN1AC1ERKS_ // CHECK: define internal void @__Block_byref_object_dispose_ -// CHECK: call void @_ZN1AD1Ev +// CHECK: call {{.*}} @_ZN1AD1Ev // CHECK: define internal void @__copy_helper_block_ // CHECK: call void @_Block_object_assign // CHECK: define internal void @__destroy_helper_block_ diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp index a4d5b86..0e310bd 100644 --- a/test/CodeGenCXX/blocks.cpp +++ b/test/CodeGenCXX/blocks.cpp @@ -31,7 +31,7 @@ namespace test1 { // ...unless they have mutable fields... // CHECK: define void @_ZN5test15test3Ev() - // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]], + // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* // CHECK: store void ()* [[T0]], void ()** @out struct mut { mutable int x; }; @@ -43,7 +43,7 @@ namespace test1 { // ...or non-trivial destructors... // CHECK: define void @_ZN5test15test4Ev() // CHECK: [[OBJ:%.*]] = alloca - // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]], + // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* // CHECK: store void ()* [[T0]], void ()** @out struct scope { int x; ~scope(); }; diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp index 96fbae8..9569f47 100644 --- a/test/CodeGenCXX/class-layout.cpp +++ b/test/CodeGenCXX/class-layout.cpp @@ -20,8 +20,8 @@ namespace Test3 { namespace Test4 { // Test from PR5589. - // CHECK: %"struct.Test4::A" = type { i32, i8, float } // CHECK: %"struct.Test4::B" = type { %"struct.Test4::A", i16, double } + // CHECK: %"struct.Test4::A" = type { i32, i8, float } struct A { int a; char c; diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp new file mode 100644 index 0000000..cd44e97 --- /dev/null +++ b/test/CodeGenCXX/compound-literals.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +struct X { + X(); + X(const X&); + X(const char*); + ~X(); +}; + +struct Y { + int i; + X x; +}; + +// CHECK: define i32 @_Z1fv() +int f() { + // CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca + // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}}* [[LVALUE]], i32 0, i32 0 + // CHECK-NEXT: store i32 17, i32* [[I]] + // CHECK-NEXT: [[X:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 1 + // CHECK-NEXT: call void @_ZN1XC1EPKc({{.*}}[[X]] + // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 0 + // CHECK-NEXT: [[RESULT:%[a-z0-9]+]] = load i32* + // CHECK-NEXT: call void @_ZN1YD1Ev + // CHECK-NEXT: ret i32 [[RESULT]] + return ((Y){17, "seventeen"}).i; +} diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp index a8c6f30..797d137 100644 --- a/test/CodeGenCXX/const-init.cpp +++ b/test/CodeGenCXX/const-init.cpp @@ -10,7 +10,7 @@ void f(); void (&fr)() = f; struct S { int& a; }; -// CHECK: @s = global %0 { i32* @a } +// CHECK: @s = global %struct.S { i32* @a } S s = { a }; // PR5581 @@ -21,7 +21,7 @@ public: unsigned f; }; -// CHECK: @_ZN6PR55812g0E = global %1 { i32 1 } +// CHECK: @_ZN6PR55812g0E = global %"class.PR5581::C" { i32 1 } C g0 = { C::e1 }; } diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp index 47e3b7b..a195afe 100644 --- a/test/CodeGenCXX/constructor-init.cpp +++ b/test/CodeGenCXX/constructor-init.cpp @@ -113,6 +113,22 @@ namespace InitVTable { B::B(int x) : A(x + 5) {} } +namespace rdar9694300 { + struct X { + int x; + }; + + // CHECK: define void @_ZN11rdar96943001fEv + void f() { + // CHECK: alloca + X x; + // CHECK-NEXT: [[I:%.*]] = alloca i32 + // CHECK-NEXT: store i32 17, i32* [[I]] + int i = 17; + // CHECK-NEXT: ret void + } +} + template<typename T> struct X { X(const X &); diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp index 75588ce..ec7f06c 100644 --- a/test/CodeGenCXX/constructors.cpp +++ b/test/CodeGenCXX/constructors.cpp @@ -83,12 +83,12 @@ struct D : A { D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {} -// CHECK: define void @_ZN1DC1Eiz(%struct.B* %this, i32 %x, ...) unnamed_addr +// CHECK: define void @_ZN1DC1Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( -// CHECK: define void @_ZN1DC2Eiz(%struct.B* %this, i32 %x, ...) unnamed_addr +// CHECK: define void @_ZN1DC2Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr // CHECK: call void @_ZN10ValueClassC1Eii( // CHECK: call void @_ZN1AC2E10ValueClass( // CHECK: call void @_ZN6MemberC1Ei( @@ -104,3 +104,14 @@ namespace test0 { C tmp = in; } } + +namespace test1 { + struct A { A(); void *ptr; }; + struct B { B(); int x; A a[0]; }; + B::B() {} + // CHECK: define void @_ZN5test11BC2Ev( + // CHECK: [[THIS:%.*]] = load [[B:%.*]]** + // CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[B:%.*]]* [[THIS]], i32 0, i32 1 + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [0 x {{%.*}}]* [[A]], i32 0, i32 0 + // CHECK-NEXT: ret void +} diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp index 4f4a8e9..a4a688f 100644 --- a/test/CodeGenCXX/copy-constructor-elim-2.cpp +++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp @@ -3,7 +3,7 @@ struct A { int x; A(int); ~A(); }; A f() { return A(0); } // CHECK: define void @_Z1fv -// CHECK: call void @_ZN1AC1Ei +// CHECK: call {{.*}} @_ZN1AC1Ei // CHECK-NEXT: ret void // Verify that we do not elide copies when constructing a base class. @@ -21,14 +21,14 @@ namespace no_elide_base { Derived(const Other &O); }; - // CHECK: define void @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.PR8683::A"* %O) unnamed_addr + // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr Derived::Derived(const Other &O) - // CHECK: call void @_ZNK13no_elide_base5OthercvNS_4BaseEEv - // CHECK: call void @_ZN13no_elide_base4BaseC2ERKS0_ - // CHECK: call void @_ZN13no_elide_base4BaseD1Ev + // CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv + // CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_ + // CHECK: call {{.*}} @_ZN13no_elide_base4BaseD1Ev : Base(O) { - // CHECK: ret void + // CHECK: ret } } @@ -48,7 +48,7 @@ struct B { void f() { // Verify that we don't mark the copy constructor in this expression as elidable. - // CHECK: call void @_ZN6PR86831AC1ERKS0_ + // CHECK: call {{.*}} @_ZN6PR86831AC1ERKS0_ A a = (B().a); } diff --git a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp index a556679..d028a28 100644 --- a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp +++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp @@ -3,5 +3,5 @@ struct A { virtual void a(); }; A x(A& y) { return y; } -// CHECK: define linkonce_odr void @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) diff --git a/test/CodeGenCXX/copy-initialization.cpp b/test/CodeGenCXX/copy-initialization.cpp index 62b9f26..aecd64e 100644 --- a/test/CodeGenCXX/copy-initialization.cpp +++ b/test/CodeGenCXX/copy-initialization.cpp @@ -12,7 +12,7 @@ struct Bar { void f(Foo); -// CHECK: define void @_Z1g3Foo(%struct.Bar* %foo) +// CHECK: define void @_Z1g3Foo(%struct.Foo* %foo) void g(Foo foo) { // CHECK: call void @_ZN3BarC1Ev // CHECK: @_ZNK3BarcvRK3FooEv diff --git a/test/CodeGenCXX/cxx0x-defaulted-templates.cpp b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp index 3d4000e..09eb4fe 100644 --- a/test/CodeGenCXX/cxx0x-defaulted-templates.cpp +++ b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp @@ -5,15 +5,15 @@ struct X { X(); }; -// CHECK: define void @_ZN1XIbEC1Ev -// CHECK: define void @_ZN1XIbEC2Ev +// CHECK: define {{.*}} @_ZN1XIbEC1Ev +// CHECK: define {{.*}} @_ZN1XIbEC2Ev template <> X<bool>::X() = default; -// CHECK: define weak_odr void @_ZN1XIiEC1Ev -// CHECK: define weak_odr void @_ZN1XIiEC2Ev +// CHECK: define weak_odr {{.*}} @_ZN1XIiEC1Ev +// CHECK: define weak_odr {{.*}} @_ZN1XIiEC2Ev template <typename T> X<T>::X() = default; template X<int>::X(); -// CHECK: define linkonce_odr void @_ZN1XIcEC1Ev -// CHECK: define linkonce_odr void @_ZN1XIcEC2Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1XIcEC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1XIcEC2Ev X<char> x; diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp index 15c8e7f..0bac492 100644 --- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp +++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp @@ -26,28 +26,28 @@ delegator::delegator() { delegator::delegator(bool) {} -// CHECK: define void @_ZN9delegatorC1Ec -// CHECK: void @_ZN9delegatorC1Eb +// CHECK: define {{.*}} @_ZN9delegatorC1Ec +// CHECK: {{.*}} @_ZN9delegatorC1Eb // CHECK: void @__cxa_throw // CHECK: void @_ZSt9terminatev -// CHECK: void @_ZN9delegatorD1Ev -// CHECK: define void @_ZN9delegatorC2Ec -// CHECK: void @_ZN9delegatorC2Eb +// CHECK: {{.*}} @_ZN9delegatorD1Ev +// CHECK: define {{.*}} @_ZN9delegatorC2Ec +// CHECK: {{.*}} @_ZN9delegatorC2Eb // CHECK: void @__cxa_throw // CHECK: void @_ZSt9terminatev -// CHECK: void @_ZN9delegatorD2Ev +// CHECK: {{.*}} @_ZN9delegatorD2Ev delegator::delegator(char) : delegator(true) { throw 0; } -// CHECK: define void @_ZN9delegatorC1Ei -// CHECK: void @_ZN9delegatorC1Ev +// CHECK: define {{.*}} @_ZN9delegatorC1Ei +// CHECK: {{.*}} @_ZN9delegatorC1Ev // CHECK-NOT: void @_ZSt9terminatev // CHECK: ret // CHECK-NOT: void @_ZSt9terminatev -// CHECK: define void @_ZN9delegatorC2Ei -// CHECK: void @_ZN9delegatorC2Ev +// CHECK: define {{.*}} @_ZN9delegatorC2Ei +// CHECK: {{.*}} @_ZN9delegatorC2Ev // CHECK-NOT: void @_ZSt9terminatev // CHECK: ret // CHECK-NOT: void @_ZSt9terminatev diff --git a/test/CodeGenCXX/default-constructor-default-argument.cpp b/test/CodeGenCXX/default-constructor-default-argument.cpp index f2c7f6d..374a967 100644 --- a/test/CodeGenCXX/default-constructor-default-argument.cpp +++ b/test/CodeGenCXX/default-constructor-default-argument.cpp @@ -5,4 +5,4 @@ struct A { A(int x = 2); }; struct B : public A {}; B x; -// CHECK: call void @_ZN1AC2Ei +// CHECK: call {{.*}} @_ZN1AC2Ei diff --git a/test/CodeGenCXX/default-constructor-template-member.cpp b/test/CodeGenCXX/default-constructor-template-member.cpp index 422cc09..0dd64df 100644 --- a/test/CodeGenCXX/default-constructor-template-member.cpp +++ b/test/CodeGenCXX/default-constructor-template-member.cpp @@ -5,6 +5,6 @@ struct B { A<int> x; }; void a() { B b; } -// CHECK: call void @_ZN1BC1Ev -// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr -// CHECK: call void @_ZN1AIiEC1Ev +// CHECK: call {{.*}} @_ZN1BC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN1AIiEC1Ev diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp index ddc7bb8..08ce0de 100644 --- a/test/CodeGenCXX/delete.cpp +++ b/test/CodeGenCXX/delete.cpp @@ -54,7 +54,7 @@ namespace test0 { delete a; } - // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%class.A* %this) unnamed_addr + // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%"struct.test0::A"* %this) unnamed_addr // CHECK: define linkonce_odr void @_ZN5test01AdlEPv } @@ -67,31 +67,22 @@ namespace test1 { // CHECK: define void @_ZN5test14testEPA10_A20_NS_1AE( void test(A (*arr)[10][20]) { delete [] arr; - // CHECK: icmp eq [10 x [20 x [[S:%.*]]]]* [[PTR:%.*]], null + // CHECK: icmp eq [10 x [20 x [[A:%.*]]]]* [[PTR:%.*]], null // CHECK-NEXT: br i1 - // CHECK: [[ARR:%.*]] = getelementptr inbounds [10 x [20 x [[S]]]]* [[PTR]], i32 0, i32 0, i32 0 - // CHECK-NEXT: bitcast {{.*}} to i8* - // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8 - // CHECK-NEXT: bitcast i8* [[ALLOC]] to i64* - // CHECK-NEXT: load - // CHECK-NEXT: store i64 {{.*}}, i64* [[IDX:%.*]] - - // CHECK: load i64* [[IDX]] - // CHECK-NEXT: icmp ne {{.*}}, 0 - // CHECK-NEXT: br i1 - - // CHECK: load i64* [[IDX]] - // CHECK-NEXT: [[I:%.*]] = sub i64 {{.*}}, 1 - // CHECK-NEXT: getelementptr inbounds [[S]]* [[ARR]], i64 [[I]] - // CHECK-NEXT: call void @_ZN5test11AD1Ev( - // CHECK-NEXT: br label - - // CHECK: load i64* [[IDX]] - // CHECK-NEXT: sub - // CHECK-NEXT: store {{.*}}, i64* [[IDX]] - // CHECK-NEXT: br label - + // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[PTR]], i32 0, i32 0, i32 0 + // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[BEGIN]] to i8* + // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8* [[T0]], i64 -8 + // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[ALLOC]] to i64* + // CHECK-NEXT: [[COUNT:%.*]] = load i64* [[T1]] + // CHECK: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 [[COUNT]] + // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[END]] + // CHECK-NEXT: br i1 [[ISEMPTY]], + // CHECK: [[PAST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[PAST]], i64 -1 + // CHECK-NEXT: call void @_ZN5test11AD1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]] + // CHECK-NEXT: br i1 [[ISDONE]] // CHECK: call void @_ZdaPv(i8* [[ALLOC]]) } } @@ -112,3 +103,22 @@ namespace test3 { delete a; } } + +namespace test4 { + // PR10341: ::delete with a virtual destructor + struct X { + virtual ~X(); + void operator delete (void *); + }; + + // CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE + void global_delete_virtual(X *xp) { + // CHECK: [[VTABLE:%.*]] = load void ([[X:%.*]])*** + // CHECK-NEXT: [[VFN:%.*]] = getelementptr inbounds void ([[X]])** [[VTABLE]], i64 0 + // CHECK-NEXT: [[VFNPTR:%.*]] = load void ([[X]])** [[VFN]] + // CHECK-NEXT: call void [[VFNPTR]]([[X]] [[OBJ:%.*]]) + // CHECK-NEXT: [[OBJVOID:%.*]] = bitcast [[X]] [[OBJ]] to i8* + // CHECK-NEXT: call void @_ZdlPv(i8* [[OBJVOID]]) nounwind + ::delete xp; + } +} diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index 94d8833..3381985 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -40,11 +40,11 @@ namespace PR7526 { struct allocator_derived : allocator { }; - // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR5529::A"* %this) unnamed_addr + // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr // CHECK: call void @__cxa_call_unexpected allocator::~allocator() throw() { foo(); } - // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR5529::A"* %this) unnamed_addr + // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR7526::allocator_derived"* %this) unnamed_addr // CHECK-NOT: call void @__cxa_call_unexpected // CHECK: } void foo() { @@ -145,10 +145,10 @@ namespace test1 { P::~P() {} // CHECK: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr struct Q : A, B { ~Q(); }; - Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::M"* %this) unnamed_addr + Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr struct R : A { ~R(); }; - R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::M"* %this) unnamed_addr + R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr struct S : A { ~S(); int x; }; S::~S() {} // alias tested above @@ -168,7 +168,7 @@ namespace test2 { struct B : A { ~B(); }; B::~B() {} - // CHECK: define void @_ZN5test21BD2Ev(%"struct.test1::M"* %this) unnamed_addr + // CHECK: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr // CHECK: call void @_ZN5test21AD2Ev } @@ -233,28 +233,28 @@ namespace test4 { namespace test5 { struct A { ~A(); }; - // This is really unnecessarily verbose; we should be using phis, - // even at -O0. - // CHECK: define void @_ZN5test53fooEv() // CHECK: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align - // CHECK-NEXT: [[IVAR:%.*]] = alloca i64 - // CHECK: [[ELEMSARRAY:%.*]] = bitcast [5 x [[A]]]* [[ELEMS]] to [[A]] - // CHECK-NEXT: store i64 5, i64* [[IVAR]] - // CHECK-NEXT: br label - // CHECK: [[I:%.*]] = load i64* [[IVAR]] - // CHECK-NEXT: icmp ne i64 [[I]], 0 - // CHECK-NEXT: br i1 - // CHECK: [[I:%.*]] = load i64* [[IVAR]] - // CHECK-NEXT: [[I2:%.*]] = sub i64 [[I]], 1 - // CHECK-NEXT: getelementptr inbounds [[A]]* [[ELEMSARRAY]], i64 [[I2]] - // CHECK-NEXT: call void @_ZN5test51AD1Ev( - // CHECK-NEXT: br label - // CHECK: [[I:%.*]] = load i64* [[IVAR]] - // CHECK-NEXT: [[I1:%.*]] = sub i64 [[I]], 1 - // CHECK-NEXT: store i64 [[I1]], i64* [[IVAR]] + // CHECK-NEXT: [[EXN:%.*]] = alloca i8* + // CHECK-NEXT: [[SEL:%.*]] = alloca i32 + // CHECK-NEXT: [[EHCLEANUP:%.*]] = alloca i32 + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]]* [[ELEMS]], i32 0, i32 0 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5 // CHECK-NEXT: br label + // CHECK: [[POST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ] + // CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[POST]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[ELT]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ELT]], [[BEGIN]] + // CHECK-NEXT: br i1 [[T0]], // CHECK: ret void + // lpad + // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[ELT]] + // CHECK-NEXT: br i1 [[EMPTY]] + // CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[ELT]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[CUR]]) + // CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]] + // CHECK-NEXT: br i1 [[DONE]], void foo() { A elems[5]; } diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp index 44219b4..58cb445 100644 --- a/test/CodeGenCXX/eh.cpp +++ b/test/CodeGenCXX/eh.cpp @@ -14,7 +14,7 @@ void test1() { // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] // CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8* // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false) -// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn +// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8* }* @_ZTI7test1_D to i8*), i8* null) noreturn // CHECK-NEXT: unreachable @@ -38,7 +38,7 @@ void test2() { // CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2) // CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}} // : [[CONT]]: (can't check this in Release-Asserts builds) -// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn +// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn // CHECK-NEXT: unreachable @@ -56,7 +56,7 @@ void test3() { // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]** // CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]] -// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn +// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPV7test3_D to i8*), i8* null) noreturn // CHECK-NEXT: unreachable @@ -84,10 +84,10 @@ namespace test5 { // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1) // CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]* // CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]]) -// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn +// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn // CHECK-NEXT: to label {{%.*}} unwind label %[[HANDLER:[^ ]*]] // : [[HANDLER]]: (can't check this in Release-Asserts builds) -// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*)) +// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*)) } namespace test6 { @@ -177,11 +177,11 @@ namespace test9 { struct A { A(); }; - // CHECK: define void @_ZN5test91AC1Ev(%"struct.test10::A"* %this) unnamed_addr + // CHECK: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr // CHECK: call void @_ZN5test91AC2Ev // CHECK-NEXT: ret void - // CHECK: define void @_ZN5test91AC2Ev(%"struct.test10::A"* %this) unnamed_addr + // CHECK: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr A::A() try { // CHECK: invoke void @_ZN5test96opaqueEv() opaque(); diff --git a/test/CodeGenCXX/elide-call-reference.cpp b/test/CodeGenCXX/elide-call-reference.cpp index c82eee7..55d30e2 100644 --- a/test/CodeGenCXX/elide-call-reference.cpp +++ b/test/CodeGenCXX/elide-call-reference.cpp @@ -7,5 +7,5 @@ void b() { A x = a(); } -// CHECK: call void @_ZN1AC1ERKS_ -// CHECK: call void @_ZN1AD1Ev +// CHECK: call {{.*}} @_ZN1AC1ERKS_ +// CHECK: call {{.*}} @_ZN1AD1Ev diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp index af46644..ab1a231 100644 --- a/test/CodeGenCXX/for-range.cpp +++ b/test/CodeGenCXX/for-range.cpp @@ -69,8 +69,8 @@ void for_range() { A a; for (B b : C()) { // CHECK: call void @_ZN1CC1Ev( - // CHECK: = call %struct.A* @_ZSt5beginR1C( - // CHECK: = call %struct.A* @_ZSt3endR1C( + // CHECK: = call %struct.B* @_ZSt5beginR1C( + // CHECK: = call %struct.B* @_ZSt3endR1C( // CHECK: br label %[[COND:.*]] // CHECK: [[COND]]: @@ -101,8 +101,8 @@ void for_member_range() { A a; for (B b : D()) { // CHECK: call void @_ZN1DC1Ev( - // CHECK: = call %struct.A* @_ZN1D5beginEv( - // CHECK: = call %struct.A* @_ZN1D3endEv( + // CHECK: = call %struct.B* @_ZN1D5beginEv( + // CHECK: = call %struct.B* @_ZN1D3endEv( // CHECK: br label %[[COND:.*]] // CHECK: [[COND]]: diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp index 9bd7390..053210b 100644 --- a/test/CodeGenCXX/global-init.cpp +++ b/test/CodeGenCXX/global-init.cpp @@ -21,21 +21,21 @@ struct D { ~D(); }; // PR6205: The casts should not require global initializers // CHECK: @_ZN6PR59741cE = external global %"struct.PR5974::C" // CHECK: @_ZN6PR59741aE = global %"struct.PR5974::A"* getelementptr inbounds (%"struct.PR5974::C"* @_ZN6PR59741cE, i32 0, i32 0) -// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::A"* bitcast (i8* getelementptr (i8* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to i8*), i64 4) to %"struct.PR5974::A"*), align 8 +// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::B"* bitcast (i8* getelementptr (i8* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to i8*), i64 4) to %"struct.PR5974::B"*), align 8 // CHECK: call void @_ZN1AC1Ev(%struct.A* @a) // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) A a; -// CHECK: call void @_ZN1BC1Ev(%struct.A* @b) -// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @b, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) +// CHECK: call void @_ZN1BC1Ev(%struct.B* @b) +// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.B*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.B* @b, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) B b; // PR6205: this should not require a global initializer // CHECK-NOT: call void @_ZN1CC1Ev(%struct.C* @c) C c; -// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) +// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.D*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.D* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) D d; // <rdar://problem/7458115> @@ -70,6 +70,20 @@ namespace test3 { const char *test() { return var; } } +namespace test6 { + 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 + __attribute__((weak)) int x = foo(); +} + namespace PR5974 { struct A { int a; }; struct B { int b; }; @@ -97,15 +111,6 @@ namespace test5 { }; } -namespace test6 { - struct A { - A(); - }; - extern int foo(); - - // This needs an initialization function but not guard variables. - __attribute__((weak)) int x = foo(); -} // At the end of the file, we check that y is initialized before z. diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp index 5008601..8bc84a5 100644 --- a/test/CodeGenCXX/implicit-copy-constructor.cpp +++ b/test/CodeGenCXX/implicit-copy-constructor.cpp @@ -70,3 +70,13 @@ void test_X2() pimpl pdata; pdata.f0( new impl(*i)); } + +// rdar://problem/9598341 +namespace test3 { + struct A { A(const A&); A&operator=(const A&); }; + struct B { A a; unsigned : 0; }; + void test(const B &x) { + B y = x; + y = x; + } +} diff --git a/test/CodeGenCXX/init-incomplete-type.cpp b/test/CodeGenCXX/init-incomplete-type.cpp index 3312d3e..1755dfb 100644 --- a/test/CodeGenCXX/init-incomplete-type.cpp +++ b/test/CodeGenCXX/init-incomplete-type.cpp @@ -10,3 +10,22 @@ static struct Bar<int> bar[1] = { { 0 } }; + + +namespace incomplete_type_refs { + struct A; + extern A g[]; + void foo(A*); + void f(void) { + foo(g); // Reference to array with unknown element type. + } + + struct A { // define the element type. + int a,b,c; + }; + + A *f2() { + return &g[1]; + } + +}
\ No newline at end of file diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp index 837d4fa..30b579c 100644 --- a/test/CodeGenCXX/mangle-subst-std.cpp +++ b/test/CodeGenCXX/mangle-subst-std.cpp @@ -15,8 +15,8 @@ namespace std { struct A { A(); }; - // CHECK: define void @_ZNSt1AC1Ev(%"struct.N::std::A"* %this) unnamed_addr - // CHECK: define void @_ZNSt1AC2Ev(%"struct.N::std::A"* %this) unnamed_addr + // CHECK: define void @_ZNSt1AC1Ev(%"struct.std::A"* %this) unnamed_addr + // CHECK: define void @_ZNSt1AC2Ev(%"struct.std::A"* %this) unnamed_addr A::A() { } }; diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp index 463f15d..f95e152 100644 --- a/test/CodeGenCXX/mangle-template.cpp +++ b/test/CodeGenCXX/mangle-template.cpp @@ -82,7 +82,7 @@ namespace test7 { X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { } }; - // CHECK: define weak_odr void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE(%"class.test1::T"* %this, double*, float*) unnamed_addr + // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr template X<int>::X(double*, float*); } @@ -101,7 +101,7 @@ namespace test8 { template<typename T> void f(int_c<meta<T>::type::value>) { } - // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE + // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE template void f<int>(int_c<sizeof(int)>); } diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index 01dcf8b..453b7b7 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -196,9 +196,9 @@ template<typename T> struct __enable_if<true, T> { // PR5063 template<typename T> typename __enable_if<__is_scalar_type<T>::__value, void>::__type ft7() { } -// CHECK: @_Z3ft7IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv +// CHECK: @_Z3ft7IiEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv template void ft7<int>(); -// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv +// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv template void ft7<void*>(); // PR5144 @@ -226,9 +226,9 @@ S7::S7() {} // PR5063 template<typename T> typename __enable_if<(__is_scalar_type<T>::__value), void>::__type ft8() { } -// CHECK: @_Z3ft8IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv +// CHECK: @_Z3ft8IiEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv template void ft8<int>(); -// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv +// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv template void ft8<void*>(); // PR5796 @@ -241,7 +241,7 @@ template<bool, typename> struct __enable_if {}; template<typename T> struct __enable_if<true, T> { typedef T __type; }; template<typename T> -// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsrNS_16__is_scalar_typeIT_EE7__valueEvE6__typeEv +// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv typename __enable_if<!__is_scalar_type<T>::__value, void>::__type __fill_a() { }; void f() { __fill_a<int>(); } @@ -711,3 +711,150 @@ namespace test27 { b<A>(f); } } + +// An injected class name type in a unresolved-name. +namespace test28 { + template <class T> struct A { + enum { bit }; + }; + + template <class T> void foo(decltype(A<T>::A::bit) x); + + void test() { + foo<char>(A<char>::bit); + // CHECK: call void @_ZN6test283fooIcEEvDtsr1AIT_E1AE3bitE( + } +} + +// An enclosing template type parameter in an unresolved-name. +namespace test29 { + template <class T> struct A { + template <class U> static void foo(decltype(T::fn(U())) x); + }; + struct B { static int fn(int); static long fn(long); }; + + void test() { + A<B>::foo<int>(0); + // CHECK: call void @_ZN6test291AINS_1BEE3fooIiEEvDTclsrS1_2fncvT__EEE( + } +} + +// An enclosing template template parameter in an unresolved-name. +namespace test30 { + template <template <class> class T> struct A { + template <class U> static void foo(decltype(T<U>::fn()) x); + }; + template <class T> struct B { static T fn(); }; + + void test() { + A<B>::foo<int>(0); + // CHECK: call void @_ZN6test301AINS_1BEE3fooIiEEvDTclsrS1_IT_EE2fnEE( + } +} + +namespace test31 { // instantiation-dependent mangling of decltype + int x; + template<class T> auto f1(T p)->decltype(x) { return 0; } + // The return type in the mangling of the template signature + // is encoded as "i". + template<class T> auto f2(T p)->decltype(p) { return 0; } + // The return type in the mangling of the template signature + // is encoded as "Dtfp_E". + void g(int); + template<class T> auto f3(T p)->decltype(g(p)) {} + + // CHECK: define weak_odr i32 @_ZN6test312f1IiEEiT_( + template int f1(int); + // CHECK: define weak_odr i32 @_ZN6test312f2IiEEDtfp_ET_ + template int f2(int); + // CHECK: define weak_odr void @_ZN6test312f3IiEEDTcl1gfp_EET_ + template void f3(int); +} + +// PR10205 +namespace test32 { + template<typename T, int=T::value> struct A { + typedef int type; + }; + struct B { enum { value = 4 }; }; + + template <class T> typename A<T>::type foo() { return 0; } + void test() { + foo<B>(); + // CHECK: call i32 @_ZN6test323fooINS_1BEEENS_1AIT_XsrS3_5valueEE4typeEv() + } +} + +namespace test33 { + template <class T> struct X { + enum { value = T::value }; + }; + + template<typename T, int=X<T>::value> struct A { + typedef int type; + }; + struct B { enum { value = 4 }; }; + + template <class T> typename A<T>::type foo() { return 0; } + + void test() { + foo<B>(); + // CHECK: call i32 @_ZN6test333fooINS_1BEEENS_1AIT_Xsr1XIS3_EE5valueEE4typeEv() + } +} + +namespace test34 { + // Mangling for instantiation-dependent decltype expressions. + template<typename T> + void f(decltype(sizeof(decltype(T() + T())))) {} + + // CHECK: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE + template void f<int>(decltype(sizeof(1))); + + // Mangling for non-instantiation-dependent sizeof expressions. + template<unsigned N> + void f2(int (&)[N + sizeof(int*)]) {} + + // CHECK: define weak_odr void @_ZN6test342f2ILj4EEEvRAplT_Lm8E_i + template void f2<4>(int (&)[4 + sizeof(int*)]); + + // Mangling for non-instantiation-dependent sizeof expressions + // involving an implicit conversion of the result of the sizeof. + template<unsigned long long N> + void f3(int (&)[N + sizeof(int*)]) {} + + // CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i + template void f3<4>(int (&)[4 + sizeof(int*)]); + + // Mangling for instantiation-dependent sizeof() expressions as + // template arguments. + template<unsigned> struct A { }; + + template<typename T> void f4(::test34::A<sizeof(sizeof(decltype(T() + T())))>) { } + + // CHECK: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE + template void f4<int>(A<sizeof(sizeof(int))>); +} + +namespace test35 { + // Dependent operator names of unknown arity. + struct A { + template<typename U> A operator+(U) const; + }; + + template<typename T> + void f1(decltype(sizeof(&T::template operator+<int>))) {} + + // CHECK: define weak_odr void @_ZN6test352f1INS_1AEEEvDTszadsrT_plIiEE + template void f1<A>(__SIZE_TYPE__); +} + +namespace test36 { + template<unsigned> struct A { }; + + template<typename ...Types> + auto f1(Types... values) -> A<sizeof...(values)> { } + + // CHECK: define weak_odr {{.*}} @_ZN6test362f1IJifEEENS_1AIXsZfp_EEEDpT_ + template A<2> f1(int, float); +} diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 011e9cd..4c42bd8 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -11,56 +11,56 @@ void (A::*volatile vpa)(); void (B::*pb)(); void (C::*pc)(); -// CHECK: @pa2 = global %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8 +// CHECK: @pa2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8 void (A::*pa2)() = &A::f; -// CHECK: @pa3 = global %0 { i64 1, i64 0 }, align 8 -// CHECK-LP32: @pa3 = global %0 { i32 1, i32 0 }, align 4 +// CHECK: @pa3 = global { i64, i64 } { i64 1, i64 0 }, align 8 +// CHECK-LP32: @pa3 = global { i32, i32 } { i32 1, i32 0 }, align 4 void (A::*pa3)() = &A::vf1; -// CHECK: @pa4 = global %0 { i64 9, i64 0 }, align 8 -// CHECK-LP32: @pa4 = global %0 { i32 5, i32 0 }, align 4 +// CHECK: @pa4 = global { i64, i64 } { i64 9, i64 0 }, align 8 +// CHECK-LP32: @pa4 = global { i32, i32 } { i32 5, i32 0 }, align 4 void (A::*pa4)() = &A::vf2; -// CHECK: @pc2 = global %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8 +// CHECK: @pc2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8 void (C::*pc2)() = &C::f; -// CHECK: @pc3 = global %0 { i64 1, i64 0 }, align 8 +// CHECK: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8 void (A::*pc3)() = &A::vf1; void f() { - // CHECK: store %0 zeroinitializer, %0* @pa + // CHECK: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa pa = 0; // Is this okay? What are LLVM's volatile semantics for structs? - // CHECK: volatile store %0 zeroinitializer, %0* @vpa + // CHECK: volatile store { i64, i64 } zeroinitializer, { i64, i64 }* @vpa vpa = 0; - // CHECK: [[TMP:%.*]] = load %0* @pa, align 8 - // CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1 + // 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 %0 [[TMP]], i64 [[ADJ]], 1 - // CHECK: store %0 [[RES]], %0* @pc, align 8 + // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 + // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pc, align 8 pc = pa; - // CHECK: [[TMP:%.*]] = load %0* @pc, align 8 - // CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1 + // 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 %0 [[TMP]], i64 [[ADJ]], 1 - // CHECK: store %0 [[RES]], %0* @pa, align 8 + // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 + // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pa, align 8 pa = static_cast<void (A::*)()>(pc); } void f2() { - // CHECK: store %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 } + // CHECK: store { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 } void (A::*pa2)() = &A::f; - // CHECK: store %0 { i64 1, i64 0 } - // CHECK-LP32: store %0 { i32 1, i32 0 } + // CHECK: store { i64, i64 } { i64 1, i64 0 } + // CHECK-LP32: store { i32, i32 } { i32 1, i32 0 } void (A::*pa3)() = &A::vf1; - // CHECK: store %0 { i64 9, i64 0 } - // CHECK-LP32: store %0 { i32 5, i32 0 } + // CHECK: store { i64, i64 } { i64 9, i64 0 } + // CHECK-LP32: store { i32, i32 } { i32 5, i32 0 } void (A::*pa4)() = &A::vf2; } diff --git a/test/CodeGenCXX/member-init-assignment.cpp b/test/CodeGenCXX/member-init-assignment.cpp index 128cb88..84c4a36 100644 --- a/test/CodeGenCXX/member-init-assignment.cpp +++ b/test/CodeGenCXX/member-init-assignment.cpp @@ -10,8 +10,8 @@ struct Foo { Foo::Foo(unsigned arg) : file_id(arg = 42) { } -// CHECK: define void @_ZN3FooC2Ej(%struct.Foo* %this, i32 %arg) unnamed_addr +// CHECK: define {{.*}} @_ZN3FooC2Ej(%struct.Foo* %this, i32 %arg) unnamed_addr // CHECK: [[ARG:%.*]] = alloca i32 // CHECK: store i32 42, i32* [[ARG]] // CHECK: store i32 42, i32* %{{.*}} -// CHECK: ret void +// CHECK: ret {{void|%struct.Foo}} diff --git a/test/CodeGenCXX/member-init-ctor.cpp b/test/CodeGenCXX/member-init-ctor.cpp index d9a6734..d70947b 100644 --- a/test/CodeGenCXX/member-init-ctor.cpp +++ b/test/CodeGenCXX/member-init-ctor.cpp @@ -7,7 +7,7 @@ struct S { S s; -// CHECK: define{{.*}} void @_ZN1SC2Ev( +// CHECK: define {{.*}} @_ZN1SC2Ev( // CHECK-NOT } // CHECK: call {{.*}} @_Z1bv() // CHECK-NOT } diff --git a/test/CodeGenCXX/new-overflow.cpp b/test/CodeGenCXX/new-overflow.cpp new file mode 100644 index 0000000..68f89c3 --- /dev/null +++ b/test/CodeGenCXX/new-overflow.cpp @@ -0,0 +1,209 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s + +// rdar://problem/9246208 + +// Basic test. +namespace test0 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test04testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T3]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(short s) { + return new elt[s]; + } +} + +// test0 with a nested array. +namespace test1 { + struct A { + A(); + int x; + }; + + typedef A elt[100]; + + // CHECK: define [100 x [[A:%.*]]]* @_ZN5test14testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100 + // CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T4]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]] + elt *test(short s) { + return new elt[s]; + } +} + +// test1 with an array cookie. +namespace test2 { + struct A { + A(); + ~A(); + int x; + }; + + typedef A elt[100]; + + // CHECK: define [100 x [[A:%.*]]]* @_ZN5test24testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100 + // CHECK-NEXT: [[T4:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T2]], i32 4) + // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T4]], 1 + // CHECK-NEXT: [[T6:%.*]] = or i1 [[T1]], [[T5]] + // CHECK-NEXT: [[T7:%.*]] = extractvalue { i32, i1 } [[T4]], 0 + // CHECK-NEXT: [[T8:%.*]] = select i1 [[T6]], i32 -1, i32 [[T7]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T8]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]] + elt *test(short s) { + return new elt[s]; + } +} + +// test0 with a 1-byte element. +namespace test4 { + struct A { + A(); + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test44testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[N]], 0 + // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 -1, i32 [[N]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T1]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(short s) { + return new elt[s]; + } +} + +// test4 with no sext required. +namespace test5 { + struct A { + A(); + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test54testEi(i32 + // CHECK: [[N:%.*]] = load i32* + // CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[N]], 0 + // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 -1, i32 [[N]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T1]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(int s) { + return new elt[s]; + } +} + +// test0 with an unsigned size. +namespace test6 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test64testEt(i16 zeroext + // CHECK: [[N:%.*]] = zext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T3]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(unsigned short s) { + return new elt[s]; + } +} + +// test1 with an unsigned size. +namespace test7 { + struct A { + A(); + int x; + }; + + typedef A elt[100]; + + // CHECK: define [100 x [[A:%.*]]]* @_ZN5test74testEt(i16 zeroext + // CHECK: [[N:%.*]] = zext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100 + // CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T4]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]] + elt *test(unsigned short s) { + return new elt[s]; + } +} + +// test0 with a signed type larger than size_t. +namespace test8 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test84testEx(i64 + // CHECK: [[N:%.*]] = load i64* + // CHECK-NEXT: [[T0:%.*]] = icmp uge i64 [[N]], 4294967296 + // CHECK-NEXT: [[T1:%.*]] = trunc i64 [[N]] to i32 + // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 4) + // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 1 + // CHECK-NEXT: [[T4:%.*]] = or i1 [[T0]], [[T3]] + // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T2]], 0 + // CHECK-NEXT: [[T6:%.*]] = select i1 [[T4]], i32 -1, i32 [[T5]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T6]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T1]] + elt *test(long long s) { + return new elt[s]; + } +} + +// test8 with an unsigned type. +namespace test9 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test94testEy(i64 + // CHECK: [[N:%.*]] = load i64* + // CHECK-NEXT: [[T0:%.*]] = icmp uge i64 [[N]], 4294967296 + // CHECK-NEXT: [[T1:%.*]] = trunc i64 [[N]] to i32 + // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 4) + // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 1 + // CHECK-NEXT: [[T4:%.*]] = or i1 [[T0]], [[T3]] + // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T2]], 0 + // CHECK-NEXT: [[T6:%.*]] = select i1 [[T4]], i32 -1, i32 [[T5]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T6]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T1]] + elt *test(unsigned long long s) { + return new elt[s]; + } +} diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp index d14a5e2..3a72bb84 100644 --- a/test/CodeGenCXX/new.cpp +++ b/test/CodeGenCXX/new.cpp @@ -182,12 +182,17 @@ namespace test15 { } // CHECK: define void @_ZN6test155test1EPv( - // CHECK: [[P:%.*]] = load i8* + // CHECK: [[P:%.*]] = load i8** // CHECK-NEXT: icmp eq i8* [[P]], null // CHECK-NEXT: br i1 - // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]* - // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]]* [[T0]], - // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T1]]) + // CHECK: [[BEGIN:%.*]] = bitcast i8* [[P]] to [[A:%.*]]* + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1 + // CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 [[DONE]] void test1(void *p) { new (p) A[5]; } @@ -202,10 +207,27 @@ namespace test15 { // CHECK-NEXT: [[P:%.*]] = load i8* // CHECK-NEXT: icmp eq i8* [[P]], null // CHECK-NEXT: br i1 - // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]* - // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]]* [[T0]], - // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T1]]) + // CHECK: [[BEGIN:%.*]] = bitcast i8* [[P]] to [[A:%.*]]* + // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq i64 [[T0]], 0 + // CHECK-NEXT: br i1 [[ISEMPTY]], + // CHECK: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 [[T0]] + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], + // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[CUR]]) void test2(void *p, int n) { new (p) A[n]; } } + +namespace PR10197 { + // CHECK: define weak_odr void @_ZN7PR101971fIiEEvv() + template<typename T> + void f() { + // CHECK: [[CALL:%.*]] = call noalias i8* @_Znwm + // CHECK-NEXT: [[CASTED:%.*]] = bitcast i8* [[CALL]] to + new T; + // CHECK-NEXT: ret void + } + + template void f<int>(); +} diff --git a/test/CodeGenCXX/noinline-template.cpp b/test/CodeGenCXX/noinline-template.cpp new file mode 100644 index 0000000..6ee3935 --- /dev/null +++ b/test/CodeGenCXX/noinline-template.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// This was a problem in Sema, but only shows up as noinline missing +// in CodeGen. + +// CHECK: define linkonce_odr void @_ZN6VectorIiE13growStorageByEv(%struct.Vector* %this) nounwind noinline + +template <class Ty> struct Vector { + void growStorageBy(); +}; +template <class T> __attribute__((noinline)) void Vector<T>::growStorageBy() { +} +void foo() { + Vector<int> strs; + strs.growStorageBy(); +} diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp index 82caff8..0efb355 100644 --- a/test/CodeGenCXX/nrvo.cpp +++ b/test/CodeGenCXX/nrvo.cpp @@ -13,10 +13,10 @@ public: // CHECK-EH: define void @_Z5test0v X test0() { X x; - // CHECK: call void @_ZN1XC1Ev + // CHECK: call {{.*}} @_ZN1XC1Ev // CHECK-NEXT: ret void - // CHECK-EH: call void @_ZN1XC1Ev + // CHECK-EH: call {{.*}} @_ZN1XC1Ev // CHECK-EH-NEXT: ret void return x; } @@ -24,13 +24,13 @@ X test0() { // CHECK: define void @_Z5test1b( // CHECK-EH: define void @_Z5test1b( X test1(bool B) { - // CHECK: tail call void @_ZN1XC1Ev + // CHECK: tail call {{.*}} @_ZN1XC1Ev // CHECK-NEXT: ret void X x; if (B) return (x); return x; - // CHECK-EH: tail call void @_ZN1XC1Ev + // CHECK-EH: tail call {{.*}} @_ZN1XC1Ev // CHECK-EH-NEXT: ret void } @@ -45,18 +45,18 @@ X test2(bool B) { return y; return x; - // CHECK: call void @_ZN1XC1Ev - // CHECK-NEXT: call void @_ZN1XC1Ev - // CHECK: call void @_ZN1XC1ERKS_ - // CHECK: call void @_ZN1XC1ERKS_ - // CHECK: call void @_ZN1XD1Ev - // CHECK: call void @_ZN1XD1Ev + // CHECK: call {{.*}} @_ZN1XC1Ev + // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev + // CHECK: call {{.*}} @_ZN1XC1ERKS_ + // CHECK: call {{.*}} @_ZN1XC1ERKS_ + // CHECK: call {{.*}} @_ZN1XD1Ev + // CHECK: call {{.*}} @_ZN1XD1Ev // CHECK: ret void // The block ordering in the -fexceptions IR is unfortunate. - // CHECK-EH: call void @_ZN1XC1Ev - // CHECK-EH-NEXT: invoke void @_ZN1XC1Ev + // CHECK-EH: call {{.*}} @_ZN1XC1Ev + // CHECK-EH-NEXT: invoke {{.*}} @_ZN1XC1Ev // -> %invoke.cont, %lpad // %invoke.cont: @@ -64,7 +64,7 @@ X test2(bool B) { // -> %if.then, %if.end // %if.then: returning 'x' - // CHECK-EH: invoke void @_ZN1XC1ERKS_ + // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_ // -> %cleanup, %lpad1 // %lpad: landing pad for ctor of 'y', dtor of 'y' @@ -74,23 +74,23 @@ X test2(bool B) { // -> %eh.cleanup // %lpad1: landing pad for return copy ctors, EH cleanup for 'y' - // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev // -> %eh.cleanup, %terminate.lpad // %if.end: returning 'y' - // CHECK-EH: invoke void @_ZN1XC1ERKS_ + // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_ // -> %cleanup, %lpad1 // %cleanup: normal cleanup for 'y' - // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev // -> %invoke.cont11, %lpad // %invoke.cont11: normal cleanup for 'x' - // CHECK-EH: call void @_ZN1XD1Ev + // CHECK-EH: call {{.*}} @_ZN1XD1Ev // CHECK-EH-NEXT: ret void // %eh.cleanup: EH cleanup for 'x' - // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev // -> %invoke.cont17, %terminate.lpad // %invoke.cont17: rethrow block for %eh.cleanup. @@ -121,13 +121,13 @@ extern "C" void exit(int) throw(); // CHECK: define void @_Z5test4b X test4(bool B) { { - // CHECK: tail call void @_ZN1XC1Ev + // CHECK: tail call {{.*}} @_ZN1XC1Ev X x; // CHECK: br i1 if (B) return x; } - // CHECK: tail call void @_ZN1XD1Ev + // CHECK: tail call {{.*}} @_ZN1XD1Ev // CHECK: tail call void @exit(i32 1) exit(1); } @@ -139,7 +139,7 @@ X test5() { try { may_throw(); } catch (X x) { - // CHECK-EH: invoke void @_ZN1XC1ERKS_ + // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_ // CHECK-EH: call void @__cxa_end_catch() // CHECK-EH: ret void return x; diff --git a/test/CodeGenCXX/partial-destruction.cpp b/test/CodeGenCXX/partial-destruction.cpp new file mode 100644 index 0000000..82deca0 --- /dev/null +++ b/test/CodeGenCXX/partial-destruction.cpp @@ -0,0 +1,169 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s + +// Test IR generation for partial destruction of aggregates. + +void opaque(); + +// Initializer lists. +namespace test0 { + struct A { A(int); A(); ~A(); void *v; }; + void test() { + A as[10] = { 5, 7 }; + opaque(); + } + // CHECK: define void @_ZN5test04testEv() + // CHECK: [[AS:%.*]] = alloca [10 x [[A:%.*]]], align + // CHECK-NEXT: [[ENDVAR:%.*]] = alloca [[A]]* + // CHECK-NEXT: [[EXN:%.*]] = alloca i8* + // CHECK-NEXT: [[SEL:%.*]] = alloca i32 + // CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32 + + // Initialize. + // CHECK-NEXT: [[E_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i64 0, i64 0 + // CHECK-NEXT: store [[A]]* [[E_BEGIN]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E_BEGIN]], i32 5) + // CHECK: [[E1:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 1 + // CHECK-NEXT: store [[A]]* [[E1]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E1]], i32 7) + // CHECK: [[E2:%.*]] = getelementptr inbounds [[A]]* [[E1]], i64 1 + // CHECK-NEXT: store [[A]]* [[E2]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 10 + // CHECK-NEXT: br label + // CHECK: [[E_CUR:%.*]] = phi [[A]]* [ [[E2]], {{%.*}} ], [ [[E_NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[E_CUR]]) + // CHECK: [[E_NEXT]] = getelementptr inbounds [[A]]* [[E_CUR]], i64 1 + // CHECK-NEXT: store [[A]]* [[E_NEXT]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_NEXT]], [[E_END]] + // CHECK-NEXT: br i1 [[T0]], + + // Run. + // CHECK: invoke void @_Z6opaquev() + + // Normal destroy. + // CHECK: [[ED_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0 + // CHECK-NEXT: [[ED_END:%.*]] = getelementptr inbounds [[A]]* [[ED_BEGIN]], i64 10 + // CHECK-NEXT: br label + // CHECK: [[ED_AFTER:%.*]] = phi [[A]]* [ [[ED_END]], {{%.*}} ], [ [[ED_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[ED_CUR]] = getelementptr inbounds [[A]]* [[ED_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[ED_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ED_CUR]], [[ED_BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + // CHECK: ret void + + // Partial destroy for initialization. + // CHECK: llvm.eh.selector({{.*}}, i32 0) + // CHECK: [[PARTIAL_END:%.*]] = load [[A]]** [[ENDVAR]] + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_BEGIN]], [[PARTIAL_END]] + // CHECK-NEXT: br i1 [[T0]], + // CHECK: [[E_AFTER:%.*]] = phi [[A]]* [ [[PARTIAL_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E_BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + + // Primary EH destructor. + // CHECK: llvm.eh.selector({{.*}}, i32 0) + // CHECK: [[E0:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0 + // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E0]], i64 10 + // CHECK-NEXT: br label + + // Partial destructor for primary normal destructor. + // FIXME: There's some really bad block ordering here which causes + // the partial destroy for the primary normal destructor to fall + // within the primary EH destructor. + // CHECK: llvm.eh.selector({{.*}}, i32 0) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ED_BEGIN]], [[ED_CUR]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: [[EDD_AFTER:%.*]] = phi [[A]]* [ [[ED_CUR]], {{%.*}} ], [ [[EDD_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[EDD_CUR]] = getelementptr inbounds [[A]]* [[EDD_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[EDD_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[EDD_CUR]], [[ED_BEGIN]] + // CHECK-NEXT: br i1 [[T0]] + + // Back to the primary EH destructor. + // CHECK: [[E_AFTER:%.*]] = phi [[A]]* [ [[E_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E0]] + // CHECK-NEXT: br i1 [[T0]], + +} + +namespace test1 { + struct A { A(); A(int); ~A(); }; + struct B { A x, y, z; int w; }; + + void test() { + B v = { 5, 6, 7, 8 }; + } + // CHECK: define void @_ZN5test14testEv() + // CHECK: [[V:%.*]] = alloca [[B:%.*]], align 4 + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: alloca i32 + // CHECK-NEXT: alloca i32 + // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 0 + // CHECK-NEXT: call void @_ZN5test11AC1Ei([[A:%.*]]* [[X]], i32 5) + // CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 1 + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[Y]], i32 6) + // CHECK: [[Z:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 2 + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[Z]], i32 7) + // CHECK: [[W:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 3 + // CHECK-NEXT: store i32 8, i32* [[W]], align 4 + // CHECK-NEXT: call void @_ZN5test11BD1Ev([[B]]* [[V]]) + // CHECK-NEXT: ret void + + // FIXME: again, the block ordering is pretty bad here + // CHECK: eh.selector({{.*}}, i32 0) + // CHECK: eh.selector({{.*}}, i32 0) + // CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[Y]]) + // CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[X]]) +} + +namespace test2 { + struct A { A(); ~A(); }; + + void test() { + A v[4][7]; + + // CHECK: define void @_ZN5test24testEv() + // CHECK: [[V:%.*]] = alloca [4 x [7 x [[A:%.*]]]], align 1 + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: alloca i32 + // CHECK-NEXT: alloca i32 + + // Main initialization loop. + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x [7 x [[A]]]]* [[V]], i32 0, i32 0, i32 0 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 28 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: invoke void @_ZN5test21AC1Ev([[A]]* [[CUR]]) + // CHECK: [[NEXT:%.*]] = getelementptr inbounds [[A]]* [[CUR]], i64 1 + // CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 [[DONE]], + + // Partial destruction landing pad. + // CHECK: llvm.eh.exception() + // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[CUR]] + // CHECK-NEXT: br i1 [[EMPTY]], + // CHECK: [[PAST:%.*]] = phi [[A]]* [ [[CUR]], {{%.*}} ], [ [[DEL:%.*]], {{%.*}} ] + // CHECK-NEXT: [[DEL]] = getelementptr inbounds [[A]]* [[PAST]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test21AD1Ev([[A]]* [[DEL]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[DEL]], [[BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + } + +} + +// PR10351 +namespace test3 { + struct A { A(); ~A(); void *p; }; + struct B { + B() {} + A a; + }; + + B *test() { + return new B[10]; + // invoke void @_ZN5test31BD1Ev( + } +} diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp index 2a22d23..f0246c8 100644 --- a/test/CodeGenCXX/pointers-to-data-members.cpp +++ b/test/CodeGenCXX/pointers-to-data-members.cpp @@ -35,7 +35,7 @@ namespace ZeroInit { } ssa[2]; void test_ssa() { (void) ssa; } - // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %1 { %struct.anon { i64 -1 } } + // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %struct.anon.1 { %struct.anon.2 { i64 -1 } } struct { struct { int A::*pa; @@ -55,7 +55,7 @@ namespace ZeroInit { }; struct C : A, B { int j; }; - // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.PR7139::ptr_to_member_struct"] [%"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8 + // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8 C c; } @@ -227,6 +227,6 @@ namespace test4 { struct C : virtual B { int *C_p; }; struct D : C { int *D_p; }; - // CHECK-GLOBAL: @_ZN5test41dE = global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, i32* null, %"struct.VirtualBases::C.base" { i32 (...)** null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8 + // CHECK-GLOBAL: @_ZN5test41dE = global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, i32* null, %"struct.test4::B.base" { i32 (...)** null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8 D d; } diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp index b87fcf4..596dee9 100644 --- a/test/CodeGenCXX/pr9965.cpp +++ b/test/CodeGenCXX/pr9965.cpp @@ -7,6 +7,6 @@ struct X X<int> x; // CHECK: define internal void @__cxx_global_var_init() -// CHECK: call void @_ZN1XIiEC1Ev -// CHECK: define linkonce_odr void @_ZN1XIiEC1Ev -// CHECK: define linkonce_odr void @_ZN1XIiEC2Ev +// CHECK: call {{.*}} @_ZN1XIiEC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC2Ev diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index 25bc8d8..4bbc251 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -235,7 +235,7 @@ struct A { }; // CHECK: define internal void @__cxx_global_var_init -// CHECK: call void @_ZN2N31AC1Ei(%"class.N2::X"* @_ZGRN2N35sA123E, i32 123) +// CHECK: call void @_ZN2N31AC1Ei(%"struct.N3::A"* @_ZGRN2N35sA123E, i32 123) // CHECK: call i32 @__cxa_atexit // CHECK: ret void const A &sA123 = A(123); @@ -250,7 +250,7 @@ struct A { void f() { // CHECK: define void @_ZN2N41fEv - // CHECK: call void @_ZN2N41AC1Ev(%"class.N2::X"* @_ZGRZN2N41fEvE2ar) + // CHECK: call void @_ZN2N41AC1Ev(%"struct.N4::A"* @_ZGRZN2N41fEvE2ar) // CHECK: call i32 @__cxa_atexit // CHECK: ret void static const A& ar = A(); @@ -269,3 +269,31 @@ void h() { f(g().b); } } + +// PR9565 +namespace PR9565 { + struct a { int a : 10, b : 10; }; + // CHECK: define void @_ZN6PR95651fEv() + void f() { + // CHECK: call void @llvm.memcpy + a x = { 0, 0 }; + // CHECK: [[WITH_SEVENTEEN:%[a-zA-Z0-9]+]] = or i32 [[WITHOUT_SEVENTEEN:%[a-zA-Z0-9]+]], 17 + // CHECK: store i32 [[WITH_SEVENTEEN]], i32* [[XA:%[a-zA-Z0-9]+]] + x.a = 17; + // CHECK-NEXT: bitcast + // CHECK-NEXT: load + // CHECK-NEXT: and + // CHECK-NEXT: shl + // CHECK-NEXT: ashr + // CHECK-NEXT: store i32 + // CHECK-NEXT: store i32* + const int &y = x.a; + // CHECK-NEXT: bitcast + // CHECK-NEXT: load + // CHECK-NEXT: and + // CHECK-NEXT: or + // CHECK-NEXT: store i32 + x.b = 19; + // CHECK-NEXT: ret void + } +} diff --git a/test/CodeGenCXX/static-init-3.cpp b/test/CodeGenCXX/static-init-3.cpp index bd717ca..dc28d5a 100644 --- a/test/CodeGenCXX/static-init-3.cpp +++ b/test/CodeGenCXX/static-init-3.cpp @@ -16,8 +16,8 @@ struct X1 } }; -// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak_odr global %struct.X0* null, align 8 -// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak_odr global %struct.X0* null, align 8 +// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak_odr global %struct.X2* null, align 8 +// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak_odr global %struct.X2* null, align 8 template<class T> T & X1<T>::instance = X1<T>::get(); class A { }; diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp index 78749a7..d488e63 100644 --- a/test/CodeGenCXX/static-init.cpp +++ b/test/CodeGenCXX/static-init.cpp @@ -16,6 +16,9 @@ void f() { // CHECK: call void @_ZN1AC1Ev // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) // CHECK: call void @__cxa_guard_release + + // rdar://problem/9496726 + // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 false, i1 false, i1 false) static A a; } diff --git a/test/CodeGenCXX/stmtexpr.cpp b/test/CodeGenCXX/stmtexpr.cpp index 0828d59..1f0e4ac 100644 --- a/test/CodeGenCXX/stmtexpr.cpp +++ b/test/CodeGenCXX/stmtexpr.cpp @@ -46,11 +46,11 @@ void foo3() void foo4() { -// CHECK: call void @_ZN1AC1Ei -// CHECK: call void @_ZN1AC1ERKS_ -// CHECK: call void @_ZN1AD1Ev -// CHECK: call void @_ZN1BC1ERK1A -// CHECK: call void @_ZN1AD1Ev +// CHECK: call {{.*}} @_ZN1AC1Ei +// CHECK: call {{.*}} @_ZN1AC1ERKS_ +// CHECK: call {{.*}} @_ZN1AD1Ev +// CHECK: call {{.*}} @_ZN1BC1ERK1A +// CHECK: call {{.*}} @_ZN1AD1Ev const B &b = ({ A a(1); a; }); if (b.i != 1) abort(); diff --git a/test/CodeGenCXX/template-anonymous-types.cpp b/test/CodeGenCXX/template-anonymous-types.cpp index 68bdc0c..72fe090 100644 --- a/test/CodeGenCXX/template-anonymous-types.cpp +++ b/test/CodeGenCXX/template-anonymous-types.cpp @@ -32,6 +32,6 @@ void test() { // CHECK: define internal void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr // // FOO's instantiation of X: - // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X* %this) - // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr + // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X.0* %this) + // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X.0* %this, i32 %t) unnamed_addr } diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp index 348d51e..8aeca65 100644 --- a/test/CodeGenCXX/temporaries.cpp +++ b/test/CodeGenCXX/temporaries.cpp @@ -421,28 +421,24 @@ namespace Elision { void test4() { // CHECK: [[X:%.*]] = alloca [[A]], align 8 // CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16 - // CHECK-NEXT: [[I:%.*]] = alloca i64 // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[X]]) A x; - // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0 + // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i64 0, i64 0 // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[XS0]]) - // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 1 + // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [[A]]* [[XS0]], i64 1 // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[XS1]], [[A]]* [[X]]) - // CHECK-NEXT: [[XSB:%.*]] = bitcast [2 x [[A]]]* [[XS]] to [[A]]* A xs[] = { A(), x }; - // CHECK-NEXT: store i64 2, i64* [[I]] - // CHECK-NEXT: br label - // CHECK: [[I0:%.*]] = load i64* [[I]] - // CHECK-NEXT: icmp ne i64 [[I0]], 0 - // CHECK-NEXT: br i1 - // CHECK: [[I1:%.*]] = load i64* [[I]] - // CHECK-NEXT: [[I2:%.*]] = sub i64 [[I1]], 1 - // CHECK-NEXT: [[XSI:%.*]] = getelementptr inbounds [[A]]* [[XSB]], i64 [[I2]] - // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[XSI]]) + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 2 // CHECK-NEXT: br label + // CHECK: [[AFTER:%.*]] = phi [[A]]* + // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1 + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]] + // CHECK-NEXT: br i1 [[T0]], // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]]) } diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp index a5a0b67..04a18b3 100644 --- a/test/CodeGenCXX/value-init.cpp +++ b/test/CodeGenCXX/value-init.cpp @@ -105,34 +105,24 @@ void f() { // CHECK: call void @_ZN6PR98014TestC1Ei // CHECK-NOT: call void @llvm.memset.p0i8.i64 // CHECK: call void @_ZN6PR98014TestC1Ev - // CHECK-NOT: call void @llvm.memset.p0i8.i64 - // CHECK: call void @_ZN6PR98014TestC1Ev Test partial[3] = { 1 }; // CHECK-NOT: call void @llvm.memset.p0i8.i64 // CHECK: call void @_ZN6PR98014TestC1Ev - // CHECK-NOT: call void @llvm.memset.p0i8.i64 - // CHECK: call void @_ZN6PR98014TestC1Ev - // CHECK-NOT: call void @llvm.memset.p0i8.i64 - // CHECK: call void @_ZN6PR98014TestC1Ev + // CHECK-NOT: call void @_ZN6PR98014TestC1Ev Test empty[3] = {}; // CHECK: call void @llvm.memset.p0i8.i64 // CHECK-NOT: call void @llvm.memset.p0i8.i64 // CHECK: call void @_ZN6PR98015Test2C1Ev - // CHECK-NOT: call void @llvm.memset.p0i8.i64 - // CHECK: call void @_ZN6PR98015Test2C1Ev - // CHECK-NOT: call void @llvm.memset.p0i8.i64 - // CHECK: call void @_ZN6PR98015Test2C1Ev + // CHECK-NOT: call void @_ZN6PR98015Test2C1Ev Test2 empty2[3] = {}; // CHECK: call void @llvm.memset.p0i8.i64 // CHECK-NOT: call void @llvm.memset.p0i8.i64 // CHECK: call void @_ZN6PR98015Test3C1Ev // CHECK-NOT: call void @llvm.memset.p0i8.i64 - // CHECK: call void @_ZN6PR98015Test3C1Ev - // CHECK-NOT: call void @llvm.memset.p0i8.i64 - // CHECK: call void @_ZN6PR98015Test3C1Ev + // CHECK-NOT: call void @_ZN6PR98015Test3C1Ev Test3 empty3[3] = {}; } @@ -189,10 +179,7 @@ namespace zeroinit { X3<int>().f(); } - // CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr - // CHECK: call void @llvm.memset.p0i8.i64 - // CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev - // CHECK-NEXT: ret void + // More checks at EOF } namespace PR8726 { @@ -207,3 +194,51 @@ void f(const C& c) { } } + +// rdar://problem/9355931 +namespace test6 { + struct A { A(); A(int); }; + + void test() { + A arr[10][20] = { 5 }; + }; + // CHECK: define void @_ZN5test64testEv() + // CHECK: [[ARR:%.*]] = alloca [10 x [20 x [[A:%.*]]]], + + // CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[ARR]], i64 0, i64 0 + // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 0, i64 0 + // CHECK-NEXT: call void @_ZN5test61AC1Ei([[A]]* [[T0]], i32 5) + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 1 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 20 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1 + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 + + // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 1 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 10 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [20 x [[A]]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + + // Inner loop. + // CHECK-NEXT: [[IBEGIN:%.*]] = getelementptr inbounds [20 x [[A]]]* [[CUR]], i32 0, i32 0 + // CHECK-NEXT: [[IEND:%.*]] = getelementptr inbounds [[A]]* [[IBEGIN]], i64 20 + // CHECK-NEXT: br label + // CHECK: [[ICUR:%.*]] = phi [[A]]* [ [[IBEGIN]], {{%.*}} ], [ [[INEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[ICUR]]) + // CHECK-NEXT: [[INEXT:%.*]] = getelementptr inbounds [[A]]* [[ICUR]], i64 1 + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[INEXT]], [[IEND]] + // CHECK-NEXT: br i1 [[T0]], + + // CHECK: [[NEXT]] = getelementptr inbounds [20 x [[A]]]* [[CUR]], i64 1 + // CHECK-NEXT: [[T0:%.*]] = icmp eq [20 x [[A]]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: ret void +} + +// CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr +// CHECK: call void @llvm.memset.p0i8.i64 +// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev +// CHECK-NEXT: ret void diff --git a/test/CodeGenCXX/variadic-templates.cpp b/test/CodeGenCXX/variadic-templates.cpp index 4f3cf1f..90c8370 100644 --- a/test/CodeGenCXX/variadic-templates.cpp +++ b/test/CodeGenCXX/variadic-templates.cpp @@ -9,4 +9,15 @@ int get_num_types(Types...) { // CHECK: ret i32 3 template int get_num_types(int, float, double); +// PR10260 - argument packs that expand to nothing +namespace test1 { + template <class... T> void foo() { + int values[sizeof...(T)+1] = { T::value... }; + // CHECK: define linkonce_odr void @_ZN5test13fooIJEEEvv() + // CHECK: alloca [1 x i32], align 4 + } + void test() { + foo<>(); + } +} diff --git a/test/CodeGenCXX/virt-call-offsets.cpp b/test/CodeGenCXX/virt-call-offsets.cpp index 3eb6b5d..5eef6fe 100644 --- a/test/CodeGenCXX/virt-call-offsets.cpp +++ b/test/CodeGenCXX/virt-call-offsets.cpp @@ -5,4 +5,4 @@ struct B : A {}; struct C : B { virtual void a(); }; void (C::*x)() = &C::a; -// CHECK: @x = global %0 { i{{[0-9]+}} 1, i{{[0-9]+}} 0 } +// CHECK: @x = global { i{{[0-9]+}}, i{{[0-9]+}} } { i{{[0-9]+}} 1, i{{[0-9]+}} 0 } diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp index f028e4c..2424d21 100644 --- a/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -18,34 +18,34 @@ int main() { // basic_iostream's complete dtor calls its base dtor, then its // virtual base's dtor. -// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr -// CHECK: call void @_ZN14basic_iostreamIcED2Ev -// CHECK: call void @_ZN9basic_iosD2Ev +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev +// CHECK: call {{.*}} @_ZN9basic_iosD2Ev // basic_iostream's base dtor calls its non-virtual base dtor. -// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr -// CHECK: call void @_ZN13basic_istreamIcED2Ev +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr +// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: } // basic_iostream's deleting dtor calls its complete dtor, then // operator delete(). -// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr -// CHECK: call void @_ZN14basic_iostreamIcED1Ev -// CHECK: call void @_ZdlPv +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev +// CHECK: call {{.*}} @_ZdlPv // basic_istream's complete dtor calls the base dtor, // then its virtual base's base dtor. -// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr -// CHECK: call void @_ZN13basic_istreamIcED2Ev -// CHECK: call void @_ZN9basic_iosD2Ev +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev +// CHECK: call {{.*}} @_ZN9basic_iosD2Ev // basic_istream's deleting dtor calls the complete dtor, then // operator delete(). -// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr -// CHECK: call void @_ZN13basic_istreamIcED1Ev -// CHECK: call void @_ZdlPv +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev +// CHECK: call {{.*}} @_ZdlPv // basic_istream's base dtor is a no-op. -// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr // CHECK-NOT: call // CHECK: } diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp index cfb4c83..c9f13f8 100644 --- a/test/CodeGenCXX/virtual-bases.cpp +++ b/test/CodeGenCXX/virtual-bases.cpp @@ -20,8 +20,8 @@ struct C : virtual A { C(bool); }; -// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext) unnamed_addr -// CHECK: define void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext) unnamed_addr +// CHECK: define void @_ZN1CC1Eb(%struct.C* %this, i1 zeroext) unnamed_addr +// CHECK: define void @_ZN1CC2Eb(%struct.C* %this, i8** %vtt, i1 zeroext) unnamed_addr C::C(bool) { } // PR6251 diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp index 052a019..afa658f 100644 --- a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp +++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp @@ -9,7 +9,7 @@ struct B { void B::f() { } -// CHECK: define i32 @_ZN1D1gEv(%struct.B* %this) +// CHECK: define i32 @_ZN1D1gEv(%struct.D* %this) // CHECK: declare void @_ZN1B1gEv() struct C; diff --git a/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp b/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp index 285e3da..0d3574e 100644 --- a/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp @@ -5,6 +5,10 @@ struct A { }; void f(A *a) { - // CHECK: call void % + // CHECK: define {{.*}} @_Z1fP1A + // CHECK: load + // CHECK: load + // CHECK: [[CALLEE:%[a-zA-Z0-9.]*]] = load + // CHECK: call {{.*}} [[CALLEE]]( a->~A(); } diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp index 760879a..f7fabed 100644 --- a/test/CodeGenCXX/visibility-inlines-hidden.cpp +++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp @@ -77,7 +77,7 @@ namespace test1 { a.foo(); } // CHECK: declare void @_ZN5test11A3fooEv -// CHECK: declare void @_ZN5test11AD1Ev +// CHECK: declare {{.*}} @_ZN5test11AD1Ev } // PR8713 diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp index 7644e47..fdccd46 100644 --- a/test/CodeGenCXX/visibility.cpp +++ b/test/CodeGenCXX/visibility.cpp @@ -422,3 +422,35 @@ namespace test21 { // CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv( template void A<en>::foo(); } + +// rdar://problem/9616154 +// Visibility on explicit specializations should take precedence. +namespace test22 { + class A1 {}; + class A2 {}; + + template <class T> struct B {}; + template <> struct DEFAULT B<A1> { + static void foo(); + static void bar() {} + }; + template <> struct B<A2> { + static void foo(); + static void bar() {} + }; + + void test() { + B<A1>::foo(); + B<A1>::bar(); + B<A2>::foo(); + B<A2>::bar(); + } + // CHECK: declare void @_ZN6test221BINS_2A1EE3fooEv() + // CHECK: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK: declare void @_ZN6test221BINS_2A2EE3fooEv() + // CHECK: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv() + // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A1EE3fooEv() + // CHECK-HIDDEN: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv() + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv() +} diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp new file mode 100644 index 0000000..58cdf79 --- /dev/null +++ b/test/CodeGenCXX/vla.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s + +// rdar://problem/9506377 +void test0(void *array, int n) { + // CHECK: define void @_Z5test0Pvi( + // CHECK: [[ARRAY:%.*]] = alloca i8*, align 8 + // CHECK-NEXT: [[N:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[REF:%.*]] = alloca i16*, align 8 + // CHECK-NEXT: [[S:%.*]] = alloca i16, align 2 + // CHECK-NEXT: store i8* + // CHECK-NEXT: store i32 + + // Capture the bounds. + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[DIM0:%.*]] = zext i32 [[T0]] to i64 + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[T1:%.*]] = add nsw i32 [[T0]], 1 + // CHECK-NEXT: [[DIM1:%.*]] = zext i32 [[T1]] to i64 + typedef short array_t[n][n+1]; + + // CHECK-NEXT: [[T0:%.*]] = load i8** [[ARRAY]], align 8 + // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i16* + // CHECK-NEXT: store i16* [[T1]], i16** [[REF]], align 8 + array_t &ref = *(array_t*) array; + + // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]] + // CHECK-NEXT: [[T1:%.*]] = mul nsw i64 1, [[DIM1]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]] + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 2 + // CHECK-NEXT: store i16 3, i16* [[T3]] + ref[1][2] = 3; + + // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]] + // CHECK-NEXT: [[T1:%.*]] = mul nsw i64 4, [[DIM1]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]] + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 5 + // CHECK-NEXT: [[T4:%.*]] = load i16* [[T3]] + // CHECK-NEXT: store i16 [[T4]], i16* [[S]], align 2 + short s = ref[4][5]; + + // CHECK-NEXT: ret void +} + diff --git a/test/CodeGenCXX/volatile-1.cpp b/test/CodeGenCXX/volatile-1.cpp index 3ae17bd..1a69648 100644 --- a/test/CodeGenCXX/volatile-1.cpp +++ b/test/CodeGenCXX/volatile-1.cpp @@ -4,7 +4,7 @@ volatile int i, j, k; volatile int ar[5]; volatile char c; -// CHECK: @ci = global [[CINT:%.*]] zeroinitializer +// CHECK: @ci = global [[CINT:.*]] zeroinitializer volatile _Complex int ci; volatile struct S { #ifdef __cplusplus diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp index f629c2d..9b1eaa5 100644 --- a/test/CodeGenCXX/vtable-pointer-initialization.cpp +++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp @@ -41,16 +41,16 @@ struct B : Base { void f() { B b; } -// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.A* %this) unnamed_addr +// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN1BC2Ev( -// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.A* %this) unnamed_addr +// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( // CHECK: ret void -// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.A* %this) unnamed_addr +// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr // CHECK: call void @_ZN4BaseC2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldC1Ev diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp index 4c06033..4d43393 100644 --- a/test/CodeGenCXX/x86_32-arguments.cpp +++ b/test/CodeGenCXX/x86_32-arguments.cpp @@ -89,7 +89,7 @@ struct s5 { s5(); int &x; }; s5 f5() { return s5(); } // CHECK: define i32 @_Z4f6_0M2s6i(i32 %a) -// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval align 4) +// CHECK: define i64 @_Z4f6_1M2s6FivE({ i32, i32 }* byval align 4) // FIXME: It would be nice to avoid byval on the previous case. struct s6 {}; typedef int s6::* s6_mdp; diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp index 01f1a44..e1d9dfc 100644 --- a/test/CodeGenCXX/x86_64-arguments.cpp +++ b/test/CodeGenCXX/x86_64-arguments.cpp @@ -115,3 +115,37 @@ namespace test6 { } // CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1) } + +namespace test7 { + struct StringRef {char* ptr; long len; }; + class A { public: ~A(); }; + A x(A, A, long, long, StringRef) { return A(); } + // Check that the StringRef is passed byval instead of expanded + // (which would split it between registers and memory). + // rdar://problem/9686430 + // CHECK: define void @_ZN5test71xENS_1AES0_llNS_9StringRefE({{.*}} byval align 8) + + // And a couple extra related tests: + A y(A, long double, long, long, StringRef) { return A(); } + // CHECK: define void @_ZN5test71yENS_1AEellNS_9StringRefE({{.*}} i8* + struct StringDouble {char * ptr; double d;}; + A z(A, A, A, A, A, StringDouble) { return A(); } + A zz(A, A, A, A, StringDouble) { return A(); } + // CHECK: define void @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE({{.*}} byval align 8) + // CHECK: define void @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE({{.*}} i8* +} + +namespace test8 { + // CHECK: declare void @_ZN5test83fooENS_1BE(%"class.test8::B"* byval align 8) + class A { + char big[17]; + }; + + class B : public A {}; + + void foo(B b); + void bar() { + B b; + foo(b); + } +} |