diff options
Diffstat (limited to 'test/CodeGenObjCXX/property-objects.mm')
-rw-r--r-- | test/CodeGenObjCXX/property-objects.mm | 134 |
1 files changed, 132 insertions, 2 deletions
diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm index 73ed21d..8e0b6ae 100644 --- a/test/CodeGenObjCXX/property-objects.mm +++ b/test/CodeGenObjCXX/property-objects.mm @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -g -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -std=c++11 -emit-llvm -debug-info-kind=limited -o - | FileCheck %s class S { public: @@ -37,7 +37,7 @@ struct CGRect { // Don't attach debug locations to the prologue instructions. These were // leaking over from the previous function emission by accident. -// CHECK: define internal void @"\01-[I setBounds:]" +// CHECK: define internal void @"\01-[I setBounds:]"({{.*}} { // CHECK-NOT: !dbg // CHECK: call void @llvm.dbg.declare - (void)setFrame:(CGRect)frameRect {} @@ -91,3 +91,133 @@ struct X { void f(A* a) { a.x = X(); } + +// rdar://21801088 +// Ensure that pseudo-objecet expressions that require the RHS to be +// rewritten don't result in crashes or redundant emission of code. +struct B0 { long long x; }; +struct B1 { long long x; }; B1 operator+(B1, B1); +struct B2 { B1 x; }; +struct B3 { B3(); B1 x; operator B1(); }; +@interface B +@property B0 b0; +@property B1 b1; +@property B2 b2; +@property B3 b3; +@end + +int b_makeInt(); + +// Note that there's a promotion from int to long long, so +// the syntactic form of the RHS will be bogus. +void testB0(B *b) { + b.b0 = { b_makeInt() }; +} +void testB1(B *b) { + b.b1 += { b_makeInt() }; +} +// CHECK: define void @_Z6testB0P1B([[B:%.*]]* +// CHECK: [[BVAR:%.*]] = alloca [[B]]*, align 8 +// CHECK: [[TEMP:%.*]] = alloca [[B0:%.*]], align 8 +// CHECK: load [[B]]*, [[B]]** [[BVAR]] +// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[B0]], [[B0]]* [[TEMP]], i32 0, i32 0 +// CHECK-NEXT: [[T0:%.*]] = call i32 @_Z9b_makeIntv() +// CHECK-NEXT: [[T1:%.*]] = sext i32 [[T0]] to i64 +// CHECK-NEXT: store i64 [[T1]], i64* [[X]], align 8 +// CHECK-NOT: call +// CHECK: call void @llvm.memcpy +// CHECK-NOT: call +// CHECK: call void bitcast {{.*}} @objc_msgSend +// CHECK-NOT: call +// CHECK: ret void + +// CHECK: define void @_Z6testB1P1B([[B]]* +// CHECK: [[BVAR:%.*]] = alloca [[B]]*, align 8 +// CHECK: load [[B]]*, [[B]]** [[BVAR]] +// CHECK-NOT: call +// CHECK: [[T0:%.*]] = call i64 bitcast {{.*}} @objc_msgSend +// CHECK-NOT: call +// CHECK: store i64 [[T0]], +// CHECK-NOT: call +// CHECK: [[T0:%.*]] = call i32 @_Z9b_makeIntv() +// CHECK-NEXT: [[T1:%.*]] = sext i32 [[T0]] to i64 +// CHECK-NEXT: store i64 [[T1]], i64* {{.*}}, align 8 +// CHECK-NOT: call +// CHECK: [[T0:%.*]] = call i64 @_Zpl2B1S_ +// CHECK-NOT: call +// CHECK: store i64 [[T0]], +// CHECK-NOT: call +// CHECK: call void @llvm.memcpy +// CHECK-NOT: call +// CHECK: call void bitcast {{.*}} @objc_msgSend +// CHECK-NOT: call +// CHECK: ret void + +// Another example of a conversion that needs to be applied +// in the semantic form. +void testB2(B *b) { + b.b2 = { B3() }; +} + +// CHECK: define void @_Z6testB2P1B([[B]]* +// CHECK: [[BVAR:%.*]] = alloca [[B]]*, align 8 +// CHECK: load [[B]]*, [[B]]** [[BVAR]] +// CHECK-NOT: call +// CHECK: call void @_ZN2B3C1Ev( +// CHECK-NEXT: [[T0:%.*]] = call i64 @_ZN2B3cv2B1Ev( +// CHECK-NOT: call +// CHECK: store i64 [[T0]], +// CHECK-NOT: call +// CHECK: call void @llvm.memcpy +// CHECK-NOT: call +// CHECK: call void bitcast {{.*}} @objc_msgSend +// CHECK-NOT: call +// CHECK: ret void + +// A similar test to B, but using overloaded function references. +struct C1 { + int x; + friend C1 operator+(C1, void(&)()); +}; +@interface C +@property void (*c0)(); +@property C1 c1; +@end + +void c_helper(); +void c_helper(int); + +void testC0(C *c) { + c.c0 = c_helper; + c.c0 = &c_helper; +} +// CHECK: define void @_Z6testC0P1C([[C:%.*]]* +// CHECK: [[CVAR:%.*]] = alloca [[C]]*, align 8 +// CHECK: load [[C]]*, [[C]]** [[CVAR]] +// CHECK-NOT: call +// CHECK: call void bitcast {{.*}} @objc_msgSend {{.*}} @_Z8c_helperv +// CHECK-NOT: call +// CHECK: call void bitcast {{.*}} @objc_msgSend {{.*}} @_Z8c_helperv +// CHECK-NOT: call +// CHECK: ret void + +void testC1(C *c) { + c.c1 += c_helper; +} +// CHECK: define void @_Z6testC1P1C([[C]]* +// CHECK: [[CVAR:%.*]] = alloca [[C]]*, align 8 +// CHECK: load [[C]]*, [[C]]** [[CVAR]] +// CHECK-NOT: call +// CHECK: [[T0:%.*]] = call i32 bitcast {{.*}} @objc_msgSend +// CHECK-NOT: call +// CHECK: store i32 [[T0]], +// CHECK-NOT: call +// CHECK: [[T0:%.*]] = call i32 @_Zpl2C1RFvvE({{.*}} @_Z8c_helperv +// CHECK-NOT: call +// CHECK: store i32 [[T0]], +// CHECK-NOT: call +// CHECK: call void @llvm.memcpy +// CHECK-NOT: call +// CHECK: call void bitcast {{.*}} @objc_msgSend +// CHECK-NOT: call +// CHECK: ret void |