diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2012-04-14 14:01:31 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2012-04-14 14:01:31 +0000 |
commit | dbe13110f59f48b4dbb7552b3ac2935acdeece7f (patch) | |
tree | be1815eb79b42ff482a8562b13c2dcbf0c5dcbee /test/CodeGenObjC | |
parent | 9da628931ebf2609493570f87824ca22402cc65f (diff) |
Notes
Diffstat (limited to 'test/CodeGenObjC')
44 files changed, 1612 insertions, 505 deletions
diff --git a/test/CodeGenObjC/2009-08-05-utf16.m b/test/CodeGenObjC/2009-08-05-utf16.m index 38c9c82e78355..06458e730ae2a 100644 --- a/test/CodeGenObjC/2009-08-05-utf16.m +++ b/test/CodeGenObjC/2009-08-05-utf16.m @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -emit-llvm -w -x objective-c %s -o - | FileCheck %s // rdar://7095855 rdar://7115749 -// CHECK: internal unnamed_addr constant [12 x i8] +// CHECK: internal unnamed_addr constant [6 x i16] [i16 105, i16 80, i16 111, i16 100, i16 8482, i16 0], align 2 void *P = @"iPod™"; diff --git a/test/CodeGenObjC/Inputs/literal-support.h b/test/CodeGenObjC/Inputs/literal-support.h new file mode 100644 index 0000000000000..5680a20c9fb56 --- /dev/null +++ b/test/CodeGenObjC/Inputs/literal-support.h @@ -0,0 +1,35 @@ +#ifndef OBJC_LITERAL_SUPPORT_H +#define OBJC_LITERAL_SUPPORT_H + +typedef unsigned char BOOL; + +@interface NSNumber @end + +@interface NSNumber (NSNumberCreation) ++ (NSNumber *)numberWithChar:(char)value; ++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value; ++ (NSNumber *)numberWithShort:(short)value; ++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value; ++ (NSNumber *)numberWithInt:(int)value; ++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value; ++ (NSNumber *)numberWithLong:(long)value; ++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value; ++ (NSNumber *)numberWithLongLong:(long long)value; ++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value; ++ (NSNumber *)numberWithFloat:(float)value; ++ (NSNumber *)numberWithDouble:(double)value; ++ (NSNumber *)numberWithBool:(BOOL)value; +@end + +@interface NSArray +@end + +@interface NSArray (NSArrayCreation) ++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt; +@end + +@interface NSDictionary ++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; +@end + +#endif // OBJC_LITERAL_SUPPORT_H diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m new file mode 100644 index 0000000000000..06acf01ce0f73 --- /dev/null +++ b/test/CodeGenObjC/arc-blocks.m @@ -0,0 +1,523 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s + +// This shouldn't crash. +void test0(id (^maker)(void)) { + maker(); +} + +int (^test1(int x))(void) { + // CHECK: define i32 ()* @test1( + // CHECK: [[X:%.*]] = alloca i32, + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], + // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]] + // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()* + // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()* + // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8* + // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind + // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()* + // CHECK-NEXT: ret i32 ()* [[T6]] + return ^{ return x; }; +} + +void test2(id x) { +// CHECK: define void @test2( +// CHECK: [[X:%.*]] = alloca i8*, +// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], +// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}}) +// CHECK-NEXT: store i8* [[PARM]], i8** [[X]] +// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], +// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) +// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]], +// CHECK-NEXT: bitcast +// CHECK-NEXT: call void @test2_helper( +// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]] +// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release +// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]] +// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release +// CHECK-NEXT: ret void + extern void test2_helper(id (^)(void)); + test2_helper(^{ return x; }); +} + +void test3(void (^sink)(id*)) { + __strong id strong; + sink(&strong); + + // CHECK: define void @test3( + // CHECK: [[SINK:%.*]] = alloca void (i8**)* + // CHECK-NEXT: [[STRONG:%.*]] = alloca i8* + // CHECK-NEXT: [[TEMP:%.*]] = alloca i8* + // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8* + // CHECK-NEXT: call i8* @objc_retain( + // CHECK-NEXT: bitcast i8* + // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]] + // CHECK-NEXT: store i8* null, i8** [[STRONG]] + + // CHECK-NEXT: load void (i8**)** [[SINK]] + // CHECK-NEXT: bitcast + // CHECK-NEXT: getelementptr + // CHECK-NEXT: [[BLOCK:%.*]] = bitcast + // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]] + // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP]] + // CHECK-NEXT: [[F0:%.*]] = load i8** + // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)* + // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]]) + // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]] + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) + // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]] + // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]] + // CHECK-NEXT: call void @objc_release(i8* [[T2]]) + + // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]] + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + + // CHECK-NEXT: load void (i8**)** [[SINK]] + // CHECK-NEXT: bitcast + // CHECK-NEXT: call void @objc_release + // CHECK-NEXT: ret void + +} + +void test4(void) { + id test4_source(void); + void test4_helper(void (^)(void)); + __block id var = test4_source(); + test4_helper(^{ var = 0; }); + + // CHECK: define void @test4() + // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2 + // 0x02000000 - has copy/dispose helpers + // CHECK-NEXT: store i32 33554432, i32* [[T0]] + // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 + // CHECK-NEXT: [[T0:%.*]] = call i8* @test4_source() + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]] + // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 + // 0x42000000 - has signature, copy/dispose helpers + // CHECK: store i32 1107296256, + // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* + // CHECK-NEXT: store i8* [[T0]], i8** + // CHECK: call void @test4_helper( + // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* + // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) + // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]] + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: ret void + + // CHECK: define internal void @__Block_byref_object_copy_ + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 + // CHECK-NEXT: load i8** + // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* + // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 + // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]] + // CHECK-NEXT: store i8* [[T2]], i8** [[T0]] + // CHECK-NEXT: store i8* null, i8** [[T1]] + + // CHECK: define internal void @__Block_byref_object_dispose_ + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 + // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]] + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) + + // CHECK: define internal void @__test4_block_invoke_ + // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 + // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8 + // CHECK-NEXT: store i8* null, i8** [[SLOT]], + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: ret void + + // CHECK: define internal void @__copy_helper_block_ + // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8) + + // CHECK: define internal void @__destroy_helper_block_ + // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8) +} + +void test5(void) { + extern id test5_source(void); + void test5_helper(void (^)(void)); + __unsafe_unretained id var = test5_source(); + test5_helper(^{ (void) var; }); + + // CHECK: define void @test5() + // CHECK: [[VAR:%.*]] = alloca i8* + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], + // CHECK: [[T0:%.*]] = call i8* @test5_source() + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]], + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) + // 0x40000000 - has signature but no copy/dispose + // CHECK: store i32 1073741824, i32* + // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]] + // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]] + // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to + // CHECK: call void @test5_helper + // CHECK-NEXT: ret void +} + +void test6(void) { + id test6_source(void); + void test6_helper(void (^)(void)); + __block __weak id var = test6_source(); + test6_helper(^{ var = 0; }); + + // CHECK: define void @test6() + // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2 + // 0x02000000 - has copy/dispose helpers + // CHECK-NEXT: store i32 33554432, i32* [[T0]] + // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 + // CHECK-NEXT: [[T0:%.*]] = call i8* @test6_source() + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]]) + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) + // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 + // 0x42000000 - has signature, copy/dispose helpers + // CHECK: store i32 1107296256, + // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* + // CHECK-NEXT: store i8* [[T0]], i8** + // CHECK: call void @test6_helper( + // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* + // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) + // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]]) + // CHECK-NEXT: ret void + + // CHECK: define internal void @__Block_byref_object_copy_ + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 + // CHECK-NEXT: load i8** + // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* + // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 + // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]]) + + // CHECK: define internal void @__Block_byref_object_dispose_ + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 + // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) + + // CHECK: define internal void @__test6_block_invoke_ + // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 + // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null) + // CHECK-NEXT: ret void + + // CHECK: define internal void @__copy_helper_block_ + // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control) + // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8) + + // CHECK: define internal void @__destroy_helper_block_ + // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control) + // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8) +} + +void test7(void) { + id test7_source(void); + void test7_helper(void (^)(void)); + void test7_consume(id); + __weak id var = test7_source(); + test7_helper(^{ test7_consume(var); }); + + // CHECK: define void @test7() + // CHECK: [[VAR:%.*]] = alloca i8*, + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], + // CHECK: [[T0:%.*]] = call i8* @test7_source() + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]]) + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) + // 0x42000000 - has signature, copy/dispose helpers + // CHECK: store i32 1107296256, + // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]]) + // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]]) + // CHECK: call void @test7_helper( + // CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}}) + // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]]) + // CHECK-NEXT: ret void + + // CHECK: define internal void @__test7_block_invoke_ + // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]]) + // CHECK-NEXT: call void @test7_consume(i8* [[T0]]) + // CHECK-NEXT: ret void + + // CHECK: define internal void @__copy_helper_block_ + // CHECK: getelementptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: call void @objc_copyWeak( + + // CHECK: define internal void @__destroy_helper_block_ + // CHECK: getelementptr + // CHECK-NEXT: call void @objc_destroyWeak( +} + +@interface Test8 @end +@implementation Test8 +- (void) test { +// CHECK: define internal void @"\01-[Test8 test]" +// CHECK: [[SELF:%.*]] = alloca [[TEST8:%.*]]*, +// CHECK-NEXT: alloca i8* +// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], +// CHECK: store +// CHECK-NEXT: store +// CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[SELF]], +// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* +// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) +// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]* +// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]] +// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to +// CHECK: call void @test8_helper( +// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]] +// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* +// CHECK-NEXT: call void @objc_release(i8* [[T2]]) +// CHECK-NEXT: ret void + + extern void test8_helper(void (^)(void)); + test8_helper(^{ (void) self; }); +} +@end + +id test9(void) { + typedef id __attribute__((ns_returns_retained)) blocktype(void); + extern void test9_consume_block(blocktype^); + return ^blocktype { + extern id test9_produce(void); + return test9_produce(); + }(); + +// CHECK: define i8* @test9( +// CHECK: load i8** getelementptr +// CHECK-NEXT: bitcast i8* +// CHECK-NEXT: call i8* +// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue +// CHECK-NEXT: ret i8* + +// CHECK: call i8* @test9_produce() +// CHECK-NEXT: call i8* @objc_retain +// CHECK-NEXT: ret i8* +} + +// rdar://problem/9814099 +// Test that we correctly initialize __block variables +// when the initialization captures the variable. +void test10a(void) { + __block void (^block)(void) = ^{ block(); }; + // CHECK: define void @test10a() + // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], + + // Zero-initialization before running the initializer. + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 + // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 + + // Run the initializer as an assignment. + // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]]) + // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1 + // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]] + // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6 + // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8 + // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 + // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T7]]) + + // Destroy at end of function. + // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 + // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* + // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) + // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]] + // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T2]]) + // CHECK-NEXT: ret void +} + +// <rdar://problem/10402698>: do this copy and dispose with +// objc_retainBlock/release instead of _Block_object_assign/destroy. +// We can also use _Block_object_assign/destroy with +// BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER. + +// CHECK: define internal void @__Block_byref_object_copy +// CHECK: [[D0:%.*]] = load i8** {{%.*}} +// CHECK-NEXT: [[D1:%.*]] = bitcast i8* [[D0]] to [[BYREF_T]]* +// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[D1]], i32 0, i32 6 +// CHECK-NEXT: [[S0:%.*]] = load i8** {{%.*}} +// CHECK-NEXT: [[S1:%.*]] = bitcast i8* [[S0]] to [[BYREF_T]]* +// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[S1]], i32 0, i32 6 +// CHECK-NEXT: [[T0:%.*]] = load void ()** [[S2]], align 8 +// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* +// CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8 +// CHECK-NEXT: ret void + +// CHECK: define internal void @__Block_byref_object_dispose +// CHECK: [[T0:%.*]] = load i8** {{%.*}} +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]* +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6 +// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]], align 8 +// CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* +// CHECK-NEXT: call void @objc_release(i8* [[T4]]) +// CHECK-NEXT: ret void + +// Test that we correctly assign to __block variables when the +// assignment captures the variable. +void test10b(void) { + __block void (^block)(void); + block = ^{ block(); }; + + // CHECK: define void @test10b() + // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], + + // Zero-initialize. + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 + // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 + + // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 + + // The assignment. + // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]]) + // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1 + // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]] + // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6 + // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8 + // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 + // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T7]]) + + // Destroy at end of function. + // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* + // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) + // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]] + // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T2]]) + // CHECK-NEXT: ret void +} + +// rdar://problem/10088932 +void test11_helper(id); +void test11a(void) { + int x; + test11_helper(^{ (void) x; }); + + // CHECK: define void @test11a() + // CHECK: [[X:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 + // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* + // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* + // CHECK-NEXT: call void @test11_helper(i8* [[T4]]) + // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T5]]) + // CHECK-NEXT: ret void +} +void test11b(void) { + int x; + id b = ^{ (void) x; }; + + // CHECK: define void @test11b() + // CHECK: [[X:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8 + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 + // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* + // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* + // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8 + // CHECK-NEXT: [[T5:%.*]] = load i8** [[B]] + // CHECK-NEXT: call void @objc_release(i8* [[T5]]) + // CHECK-NEXT: ret void +} + +// rdar://problem/9979150 +@interface Test12 +@property (strong) void(^ablock)(void); +@property (nonatomic, strong) void(^nblock)(void); +@end +@implementation Test12 +@synthesize ablock, nblock; +// CHECK: define internal void ()* @"\01-[Test12 ablock]"( +// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true) + +// CHECK: define internal void @"\01-[Test12 setAblock:]"( +// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true) + +// CHECK: define internal void ()* @"\01-[Test12 nblock]"( +// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false) + +// CHECK: define internal void @"\01-[Test12 setNblock:]"( +// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true) +@end + +// rdar://problem/10131784 +void test13(id x) { + extern void test13_helper(id); + extern void test13_use(void(^)(void)); + + void (^b)(void) = (x ? ^{test13_helper(x);} : 0); + test13_use(b); + + // CHECK: define void @test13( + // CHECK: [[X:%.*]] = alloca i8*, align 8 + // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8 + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8 + // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) + // CHECK-NEXT: store i8* [[T0]], i8** [[X]], align 8 + // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8 + // CHECK-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null + // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: br i1 [[T1]], + + // CHECK-NOT: br + // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8 + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) + // CHECK-NEXT: store i8* [[T1]], i8** [[CAPTURE]], align 8 + // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK-NEXT: br label + // CHECK: br label + // CHECK: [[T0:%.*]] = phi void ()* + // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* + // CHECK-NEXT: store void ()* [[T3]], void ()** [[B]], align 8 + // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]], align 8 + // CHECK-NEXT: call void @test13_use(void ()* [[T0]]) + // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]] + // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) + + // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_ADDR]] + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: br label + + // CHECK: [[T0:%.*]] = load i8** [[X]] + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: ret void +} + +// <rdar://problem/10907510> +void test14() { + void (^const x[1])(void) = { ^{} }; +} + +// rdar://11149025 +// Don't make invalid ASTs and crash. +void test15_helper(void (^block)(void), int x); +void test15(int a) { + test15_helper(^{ (void) a; }, ({ a; })); +} diff --git a/test/CodeGenObjC/arc-cond-stmt.m b/test/CodeGenObjC/arc-cond-stmt.m new file mode 100644 index 0000000000000..d8ee6bb084b5e --- /dev/null +++ b/test/CodeGenObjC/arc-cond-stmt.m @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -o - %s +// rdar://10327068 + +@class NSString; + +@interface NSAssertionHandler { +} + ++ (NSAssertionHandler *)currentHandler; + +- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(int)line ,...; + +@end + +typedef enum +{ + MWRaceOrder_MeetName, + MWRaceOrder_MeetPosition, + MWRaceOrder_MeetDistance, + MWRaceOrder_Name, + MWRaceOrder_Position, + MWRaceOrder_Distance, + MWRaceOrder_Default = MWRaceOrder_Name, + MWRaceOrder_MeetDefault = MWRaceOrder_MeetName, +} MWRaceOrder; + +@interface MWViewMeetController +@property (nonatomic, assign) MWRaceOrder raceOrder; +@end + +@implementation MWViewMeetController + +- (int)orderSegment +{ + switch (self.raceOrder) + { + + default: + { [(NSAssertionHandler *)0 handleFailureInMethod:_cmd object:self file:(NSString*)0 lineNumber:192 ]; }; + break; + } + + return 0; +} + +@synthesize raceOrder; + +@end diff --git a/test/CodeGenObjC/arc-exceptions.m b/test/CodeGenObjC/arc-exceptions.m new file mode 100644 index 0000000000000..5ef5ababe695f --- /dev/null +++ b/test/CodeGenObjC/arc-exceptions.m @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-runtime-has-weak -o - %s | FileCheck %s + +@class Ety; + +// These first two tests are all PR11732 / rdar://problem/10667070. + +void test0_helper(void); +void test0(void) { + @try { + test0_helper(); + } @catch (Ety *e) { + } +} +// CHECK: define void @test0() +// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8 +// CHECK-NEXT: invoke void @test0_helper() +// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch( +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]* +// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]* [[T1]] to i8* +// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind +// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]* +// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]] +// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]] +// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8* +// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind +// CHECK-NEXT: call void @objc_end_catch() nounwind + +void test1_helper(void); +void test1(void) { + @try { + test1_helper(); + } @catch (__weak Ety *e) { + } +} +// CHECK: define void @test1() +// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8 +// CHECK-NEXT: invoke void @test1_helper() +// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch( +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]* +// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]** [[E]] to i8** +// CHECK-NEXT: [[T3:%.*]] = bitcast [[ETY]]* [[T1]] to i8* +// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) nounwind +// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8** +// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind +// CHECK-NEXT: call void @objc_end_catch() nounwind diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m index 9449b3d2d602a..67fad4d9b04a1 100644 --- a/test/CodeGenObjC/arc-foreach.m +++ b/test/CodeGenObjC/arc-foreach.m @@ -60,13 +60,14 @@ void test0(NSArray *array) { // CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]] // CHECK-LP64-NEXT: store i8* [[T3]], i8** [[X]] +// CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[X]] // CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) // CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]] // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] // CHECK-LP64: call void @use_block( -// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[T0]] +// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[D0]] // CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]]) // CHECK-LP64: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ @@ -108,12 +109,13 @@ void test1(NSArray *array) { // CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]] // CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T3]]) +// CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[X]]) // CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]]) // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to // CHECK-LP64: call void @use_block -// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[T0]]) +// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[D0]]) // CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]]) // rdar://problem/9817306 diff --git a/test/CodeGenObjC/arc-ivar-layout.m b/test/CodeGenObjC/arc-ivar-layout.m index 30c90fac9e404..7f58a0cad3bd6 100644 --- a/test/CodeGenObjC/arc-ivar-layout.m +++ b/test/CodeGenObjC/arc-ivar-layout.m @@ -42,3 +42,14 @@ // CHECK-LP64: L_OBJC_CLASS_NAME_15: // CHECK-LP64-NEXT: .asciz "\022" +@interface UnsafePerson { +@public + __unsafe_unretained id name; + __unsafe_unretained id age; + id value; +} +@end + +@implementation UnsafePerson @end +// CHECK-LP64: L_OBJC_CLASS_NAME_20: +// CHECK-LP64-NEXT: .asciz "!" diff --git a/test/CodeGenObjC/arc-literals.m b/test/CodeGenObjC/arc-literals.m new file mode 100644 index 0000000000000..203c2ad1eea17 --- /dev/null +++ b/test/CodeGenObjC/arc-literals.m @@ -0,0 +1,121 @@ +// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s + +#include "literal-support.h" + +// Check the various selector names we'll be using, in order. + +// CHECK: c"numberWithInt:\00" +// CHECK: c"numberWithUnsignedInt:\00" +// CHECK: c"numberWithUnsignedLongLong:\00" +// CHECK: c"numberWithChar:\00" +// CHECK: c"arrayWithObjects:count:\00" +// CHECK: c"dictionaryWithObjects:forKeys:count:\00" +// CHECK: c"prop\00" + +// CHECK: define void @test_numeric() +void test_numeric() { + // CHECK: {{call.*objc_msgSend.*i32 17}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id ilit = @17; + // CHECK: {{call.*objc_msgSend.*i32 25}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id ulit = @25u; + // CHECK: {{call.*objc_msgSend.*i64 42}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id ulllit = @42ull; + // CHECK: {{call.*objc_msgSend.*i8 signext 97}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id charlit = @'a'; + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK-NEXT: ret void +} + +// CHECK: define void @test_array +void test_array(id a, id b) { + // Retaining parameters + // CHECK: call i8* @objc_retain(i8* + // CHECK: call i8* @objc_retain(i8* + + // Constructing the array + // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0 + // CHECK: store i8* + // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1 + // CHECK: store i8* + + // CHECK: {{call i8*.*objc_msgSend.*i64 2}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id arr = @[a, b]; + + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK-NEXT: ret void +} + +// CHECK: define void @test_dictionary +void test_dictionary(id k1, id o1, id k2, id o2) { + // Retaining parameters + // CHECK: call i8* @objc_retain(i8* + // CHECK: call i8* @objc_retain(i8* + // CHECK: call i8* @objc_retain(i8* + // CHECK: call i8* @objc_retain(i8* + + // Constructing the arrays + // CHECK: getelementptr inbounds [2 x i8*]* [[KEYS:%[A-Za-z0-9]+]], i32 0, i32 0 + // CHECK: store i8* + // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0 + // CHECK: store i8* + // CHECK: getelementptr inbounds [2 x i8*]* [[KEYS]], i32 0, i32 1 + // CHECK: store i8* + // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1 + // CHECK: store i8* + + // Constructing the dictionary + // CHECK: {{call i8.*@objc_msgSend}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id dict = @{ k1 : o1, k2 : o2 }; + + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK: call void @objc_release + // CHECK-NEXT: ret void +} + +@interface A +@end + +@interface B +@property (retain) A* prop; +@end + +// CHECK: define void @test_property +void test_property(B *b) { + // Retain parameter + // CHECK: call i8* @objc_retain + + // Invoke 'prop' + // CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES + // CHECK: {{call.*@objc_msgSend}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + + // Invoke arrayWithObjects:count: + // CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES + // CHECK: {{call.*objc_msgSend}} + // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id arr = @[ b.prop ]; + + // Release b.prop + // CHECK: call void @objc_release + + // Destroy arr + // CHECK: call void @objc_release + + // Destroy b + // CHECK: call void @objc_release + // CHECK-NEXT: ret void +} diff --git a/test/CodeGenObjC/arc-no-arc-exceptions.m b/test/CodeGenObjC/arc-no-arc-exceptions.m new file mode 100644 index 0000000000000..7ae061f414674 --- /dev/null +++ b/test/CodeGenObjC/arc-no-arc-exceptions.m @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O0 -disable-llvm-optzns -o - %s | FileCheck -check-prefix=NO-METADATA %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s -fobjc-arc-exceptions | FileCheck -check-prefix=NO-METADATA %s + +// The front-end should emit clang.arc.no_objc_arc_exceptions in -fobjc-arc-exceptions +// mode when optimization is enabled, and not otherwise. + +void thrower(void); +void not(void) __attribute__((nothrow)); + +// CHECK: define void @test0( +// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions ! +// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions ! +// NO-METADATA: define void @test0( +// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions +// NO-METADATA: } +void test0(void) { + thrower(); + not(); +} + +// CHECK: define void @test1( +// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions ! +// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions ! +// NO-METADATA: define void @test1( +// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions +// NO-METADATA: } +void test1(id x) { + id y = x; + thrower(); + not(); +} + +void NSLog(id, ...); + +// CHECK: define void @test2( +// CHECK: invoke void (i8*, ...)* @NSLog(i8* bitcast (%struct.NSConstantString* @_unnamed_cfstring_ to i8*), i32* %{{.*}}) +// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions ! +// NO-METADATA: define void @test2( +// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions +// NO-METADATA: } +void test2(void) { + @autoreleasepool { + __attribute__((__blocks__(byref))) int x; + NSLog(@"Address of x outside of block: %p", &x); + } +} + +// CHECK: define void @test3( +// CHECK: invoke void %{{.*}}(i8* %{{.*}}) +// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions ! +// NO-METADATA: define void @test3( +// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions +// NO-METADATA: } +void test3(void) { + @autoreleasepool { + __attribute__((__blocks__(byref))) int x; + ^{ + NSLog(@"Address of x in non-assigned block: %p", &x); + }(); + } +} + +// CHECK: define void @test4( +// CHECK: invoke void %{{.*}}(i8* %{{.*}}) +// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions ! +// NO-METADATA: define void @test4( +// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions +// NO-METADATA: } +void test4(void) { + @autoreleasepool { + __attribute__((__blocks__(byref))) int x; + void (^b)(void) = ^{ + NSLog(@"Address of x in assigned block: %p", &x); + }; + b(); + } +} diff --git a/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m new file mode 100644 index 0000000000000..6c5180b1c347e --- /dev/null +++ b/test/CodeGenObjC/arc-property.m @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -emit-llvm %s -o - | FileCheck %s + +// rdar://problem/10290317 +@interface Test0 +- (void) setValue: (id) x; +@end +void test0(Test0 *t0, id value) { + t0.value = value; +} +// CHECK: define void @test0( +// CHECK: call i8* @objc_retain( +// CHECK: call i8* @objc_retain( +// CHECK: @objc_msgSend +// CHECK: call void @objc_release( +// CHECK: call void @objc_release( diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index e97e625b06eb5..2a98b10909bb8 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -13,23 +13,20 @@ void test0(id x) { // CHECK: define i8* @test1(i8* id test1(id x) { - // CHECK: [[RET:%.*]] = alloca i8* - // CHECK-NEXT: [[X:%.*]] = alloca i8* + // CHECK: [[X:%.*]] = alloca i8* // CHECK-NEXT: [[Y:%.*]] = alloca i8* // CHECK-NEXT: alloca i32 // CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}}) // CHECK-NEXT: store i8* [[PARM]], i8** [[X]] // CHECK-NEXT: store i8* null, i8** [[Y]] // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]] - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) - // CHECK-NEXT: store i8* [[T1]], i8** [[RET]] + // CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T0]]) // CHECK-NEXT: store i32 // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]] // CHECK-NEXT: call void @objc_release(i8* [[T0]]) // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]] // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]] - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[RET]]) // CHECK-NEXT: ret i8* [[T1]] id y; return y; @@ -449,11 +446,6 @@ void test13(void) { - (int) x { return super.x + 1; } @end -// This shouldn't crash. -void test18(id (^maker)(void)) { - maker(); -} - void test19() { // CHECK: define void @test19() // CHECK: [[X:%.*]] = alloca [5 x i8*], align 16 @@ -615,22 +607,6 @@ void test22(_Bool cond) { @interface Test24 {} @end @implementation Test24 @end -int (^test25(int x))(void) { - // CHECK: define i32 ()* @test25( - // CHECK: [[X:%.*]] = alloca i32, - // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], - // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]] - // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()* - // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind - // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()* - // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8* - // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind - // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()* - // CHECK-NEXT: ret i32 ()* [[T6]] - return ^{ return x; }; -} - // rdar://problem/8941012 @interface Test26 { id x[4]; } @end @implementation Test26 @end @@ -657,24 +633,19 @@ int (^test25(int x))(void) { @implementation Test27 - (id) init { return self; } // CHECK: define internal i8* @"\01-[Test27 init]" -// CHECK: [[RET:%.*]] = alloca i8*, -// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST27:%.*]]*, +// CHECK: [[SELF:%.*]] = alloca [[TEST27:%.*]]*, // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, // CHECK-NEXT: [[DEST:%.*]] = alloca i32 // CHECK-NEXT: store [[TEST27]]* {{%.*}}, [[TEST27]]** [[SELF]] // CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]] // CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) -// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] -// CHECK-NEXT: [[T2:%.*]] = bitcast -// CHECK-NEXT: store i8* [[T2]], i8** [[RET]] +// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) // CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]] // CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8* // CHECK-NEXT: call void @objc_release(i8* [[T1]]) -// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]] -// CHECK-NEXT: ret i8* [[T0]] +// CHECK-NEXT: ret i8* [[RET]] @end @@ -705,8 +676,7 @@ int (^test25(int x))(void) { static id _test29_allocator = 0; - (id) init { // CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%.*]]* {{%.*}}, -// CHECK: [[RET:%.*]] = alloca i8*, align 8 -// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8 +// CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8 // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8 // CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32 // CHECK-NEXT: store [[TEST29]]* {{%.*}}, [[TEST29]]** [[SELF]] @@ -734,10 +704,7 @@ static id _test29_allocator = 0; // Return statement. // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[CALL]] // CHECK-NEXT: [[CALL:%.*]] = bitcast -// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind -// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] -// CHECK-NEXT: [[T1:%.*]] = bitcast -// CHECK-NEXT: store i8* [[T1]], i8** [[RET]] +// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind // CHECK-NEXT: store i32 1, i32* [[CLEANUP]] // Cleanup. @@ -746,14 +713,12 @@ static id _test29_allocator = 0; // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release // Return. -// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]] -// CHECK-NEXT: ret i8* [[T0]] +// CHECK-NEXT: ret i8* [[RET]] return [self initWithAllocator: _test29_allocator]; } - (id) initWithAllocator: (id) allocator { // CHECK: define internal i8* @"\01-[Test29 initWithAllocator:]"( -// CHECK: [[RET:%.*]] = alloca i8*, align 8 -// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8 +// CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8 // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8 // CHECK-NEXT: [[ALLOCATOR:%.*]] = alloca i8*, align 8 // CHECK-NEXT: alloca @@ -793,10 +758,7 @@ static id _test29_allocator = 0; // Return statement. // CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind -// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] -// CHECK-NEXT: [[T2:%.*]] = bitcast -// CHECK-NEXT: store i8* [[T2]], i8** [[RET]] +// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind // CHECK-NEXT: store i32 1, i32* [[CLEANUP]] // Cleanup. @@ -808,8 +770,7 @@ static id _test29_allocator = 0; // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release // Return. -// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]] -// CHECK-NEXT: ret i8* [[T0]] +// CHECK-NEXT: ret i8* [[RET]] self = [super initWithAllocator: allocator]; return self; } @@ -825,8 +786,7 @@ char *helper; } - (id) init { // CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%.*]]* {{%.*}}, -// CHECK: [[RET:%.*]] = alloca i8* -// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST30]]* +// CHECK: [[RET:%.*]] = alloca [[TEST30]]* // CHECK-NEXT: alloca i8* // CHECK-NEXT: alloca i32 // CHECK-NEXT: store [[TEST30]]* {{%.*}}, [[TEST30]]** [[SELF]] @@ -853,10 +813,7 @@ char *helper; // Return. // CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) -// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] -// CHECK-NEXT: [[T2:%.*]] = bitcast -// CHECK-NEXT: store i8* [[T2]], i8** [[RET]] +// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) // CHECK-NEXT: store i32 1 // Cleanup. @@ -865,8 +822,7 @@ char *helper; // CHECK-NEXT: call void @objc_release(i8* [[T1]]) // Epilogue. -// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]] -// CHECK-NEXT: ret i8* [[T0]] +// CHECK-NEXT: ret i8* [[RET]] self->helper = [self initHelper]; return self; } @@ -882,27 +838,6 @@ char *helper; @end -void test31(id x) { -// CHECK: define void @test31( -// CHECK: [[X:%.*]] = alloca i8*, -// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], -// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}}) -// CHECK-NEXT: store i8* [[PARM]], i8** [[X]] -// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 -// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], -// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) -// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]], -// CHECK-NEXT: bitcast -// CHECK-NEXT: call void @test31_helper( -// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]] -// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release -// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]] -// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release -// CHECK-NEXT: ret void - extern void test31_helper(id (^)(void)); - test31_helper(^{ return x; }); -} - __attribute__((ns_returns_retained)) id test32(void) { // CHECK: define i8* @test32() // CHECK: [[CALL:%.*]] = call i8* @test32_helper() @@ -1060,45 +995,6 @@ void test34(int cond) { // CHECK: ret void } -void test35(void (^sink)(id*)) { - __strong id strong; - sink(&strong); - - // CHECK: define void @test35( - // CHECK: [[SINK:%.*]] = alloca void (i8**)* - // CHECK-NEXT: [[STRONG:%.*]] = alloca i8* - // CHECK-NEXT: [[TEMP:%.*]] = alloca i8* - // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8* - // CHECK-NEXT: call i8* @objc_retain( - // CHECK-NEXT: bitcast i8* - // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]] - // CHECK-NEXT: store i8* null, i8** [[STRONG]] - - // CHECK-NEXT: load void (i8**)** [[SINK]] - // CHECK-NEXT: bitcast - // CHECK-NEXT: getelementptr - // CHECK-NEXT: [[BLOCK:%.*]] = bitcast - // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]] - // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]] - // CHECK-NEXT: [[F0:%.*]] = load i8** - // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)* - // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP1]]) - // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP1]] - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) - // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]] - // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]] - // CHECK-NEXT: call void @objc_release(i8* [[T2]]) - - // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) - - // CHECK-NEXT: load void (i8**)** [[SINK]] - // CHECK-NEXT: bitcast - // CHECK-NEXT: call void @objc_release - // CHECK-NEXT: ret void - -} - // CHECK: define void @test36 void test36(id x) { // CHECK: [[X:%.*]] = alloca i8* @@ -1152,205 +1048,6 @@ void test37(void) { // CHECK-NEXT: ret void } -void test38(void) { - id test38_source(void); - void test38_helper(void (^)(void)); - __block id var = test38_source(); - test38_helper(^{ var = 0; }); - - // CHECK: define void @test38() - // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], - // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2 - // 0x02000000 - has copy/dispose helpers - // CHECK-NEXT: store i32 33554432, i32* [[T0]] - // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 - // CHECK-NEXT: [[T0:%.*]] = call i8* @test38_source() - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) - // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]] - // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 - // 0x42000000 - has signature, copy/dispose helpers - // CHECK: store i32 1107296256, - // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* - // CHECK-NEXT: store i8* [[T0]], i8** - // CHECK: call void @test38_helper( - // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* - // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) - // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) - // CHECK-NEXT: ret void - - // CHECK: define internal void @__Block_byref_object_copy_ - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 - // CHECK-NEXT: load i8** - // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* - // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 - // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]] - // CHECK-NEXT: store i8* [[T2]], i8** [[T0]] - // CHECK-NEXT: store i8* null, i8** [[T1]] - - // CHECK: define internal void @__Block_byref_object_dispose_ - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 - // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]] - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - - // CHECK: define internal void @__test38_block_invoke_ - // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 - // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8 - // CHECK-NEXT: store i8* null, i8** [[SLOT]], - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) - // CHECK-NEXT: ret void - - // CHECK: define internal void @__copy_helper_block_ - // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8) - - // CHECK: define internal void @__destroy_helper_block_ - // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8) -} - -void test39(void) { - extern id test39_source(void); - void test39_helper(void (^)(void)); - __unsafe_unretained id var = test39_source(); - test39_helper(^{ (void) var; }); - - // CHECK: define void @test39() - // CHECK: [[VAR:%.*]] = alloca i8* - // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], - // CHECK: [[T0:%.*]] = call i8* @test39_source() - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) - // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]], - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // 0x40000000 - has signature but no copy/dispose - // CHECK: store i32 1073741824, i32* - // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 - // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]] - // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]] - // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to - // CHECK: call void @test39_helper - // CHECK-NEXT: ret void -} - -void test40(void) { - id test40_source(void); - void test40_helper(void (^)(void)); - __block __weak id var = test40_source(); - test40_helper(^{ var = 0; }); - - // CHECK: define void @test40() - // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], - // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2 - // 0x02000000 - has copy/dispose helpers - // CHECK-NEXT: store i32 33554432, i32* [[T0]] - // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 - // CHECK-NEXT: [[T0:%.*]] = call i8* @test40_source() - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) - // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]]) - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 - // 0x42000000 - has signature, copy/dispose helpers - // CHECK: store i32 1107296256, - // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* - // CHECK-NEXT: store i8* [[T0]], i8** - // CHECK: call void @test40_helper( - // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* - // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) - // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]]) - // CHECK-NEXT: ret void - - // CHECK: define internal void @__Block_byref_object_copy_ - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 - // CHECK-NEXT: load i8** - // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* - // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 - // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]]) - - // CHECK: define internal void @__Block_byref_object_dispose_ - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6 - // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) - - // CHECK: define internal void @__test40_block_invoke_ - // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 - // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null) - // CHECK-NEXT: ret void - - // CHECK: define internal void @__copy_helper_block_ - // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control) - // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8) - - // CHECK: define internal void @__destroy_helper_block_ - // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control) - // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8) -} - -void test41(void) { - id test41_source(void); - void test41_helper(void (^)(void)); - void test41_consume(id); - __weak id var = test41_source(); - test41_helper(^{ test41_consume(var); }); - - // CHECK: define void @test41() - // CHECK: [[VAR:%.*]] = alloca i8*, - // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], - // CHECK: [[T0:%.*]] = call i8* @test41_source() - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) - // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]]) - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // 0x42000000 - has signature, copy/dispose helpers - // CHECK: store i32 1107296256, - // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 - // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]]) - // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]]) - // CHECK: call void @test41_helper( - // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]]) - // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]]) - // CHECK-NEXT: ret void - - // CHECK: define internal void @__test41_block_invoke_ - // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5 - // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]]) - // CHECK-NEXT: call void @test41_consume(i8* [[T0]]) - // CHECK-NEXT: ret void - - // CHECK: define internal void @__copy_helper_block_ - // CHECK: getelementptr - // CHECK-NEXT: getelementptr - // CHECK-NEXT: call void @objc_copyWeak( - - // CHECK: define internal void @__destroy_helper_block_ - // CHECK: getelementptr - // CHECK-NEXT: call void @objc_destroyWeak( -} - -@interface Test42 @end -@implementation Test42 -- (void) test { -// CHECK: define internal void @"\01-[Test42 test]" -// CHECK: [[SELF:%.*]] = alloca [[TEST42:%.*]]*, -// CHECK-NEXT: alloca i8* -// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], -// CHECK: store -// CHECK-NEXT: store -// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 -// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[SELF]], -// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8* -// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) -// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST42]]* -// CHECK-NEXT: store [[TEST42]]* [[T4]], [[TEST42]]** [[T0]] -// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to -// CHECK: call void @test42_helper( -// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[T0]] -// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T2]]) -// CHECK-NEXT: ret void - - extern void test42_helper(void (^)(void)); - test42_helper(^{ (void) self; }); -} -@end - @interface Test43 @end @implementation Test43 - (id) test __attribute__((ns_returns_retained)) { @@ -1362,26 +1059,6 @@ void test41(void) { } @end -id test44(void) { - typedef id __attribute__((ns_returns_retained)) blocktype(void); - extern test44_consume_block(blocktype^); - return ^blocktype { - extern id test44_produce(void); - return test44_produce(); - }(); - -// CHECK: define i8* @test44( -// CHECK: load i8** getelementptr -// CHECK-NEXT: bitcast i8* -// CHECK-NEXT: call i8* -// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue -// CHECK-NEXT: ret i8* - -// CHECK: call i8* @test44_produce() -// CHECK-NEXT: call i8* @objc_retain -// CHECK-NEXT: ret i8* -} - @interface Test45 @property (retain) id x; @end @@ -1685,76 +1362,6 @@ void test59(void) { // CHECK-NEXT: ret void } -// rdar://problem/9814099 -// Test that we correctly initialize __block variables -// when the initialization captures the variable. -void test60a(void) { - __block void (^block)(void) = ^{ block(); }; - // CHECK: define void @test60a() - // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], - - // Zero-initialization before running the initializer. - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 - // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 - - // Run the initializer as an assignment. - // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]]) - // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* - // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1 - // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]] - // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6 - // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8 - // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 - // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T7]]) - - // Destroy at end of function. - // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 - // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* - // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) - // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]] - // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T2]]) - // CHECK-NEXT: ret void -} - -// Test that we correctly assign to __block variables when the -// assignment captures the variable. -void test60b(void) { - __block void (^block)(void); - block = ^{ block(); }; - - // CHECK: define void @test60b() - // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], - - // Zero-initialize. - // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 - // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 - - // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6 - - // The assignment. - // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]]) - // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* - // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1 - // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]] - // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6 - // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8 - // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 - // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T7]]) - - // Destroy at end of function. - // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* - // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) - // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]] - // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T2]]) - // CHECK-NEXT: ret void -} - // Verify that we don't try to reclaim the result of performSelector. // rdar://problem/9887545 @interface Test61 @@ -1855,64 +1462,6 @@ void test62(void) { // CHECK: call i8* @objc_getProperty // CHECK: call void @objc_setProperty -// rdar://problem/10088932 -void test64_helper(id); -void test64a(void) { - int x; - test64_helper(^{ (void) x; }); - - // CHECK: define void @test64a() - // CHECK: [[X:%.*]] = alloca i32, align 4 - // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 - // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* - // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) - // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* - // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* - // CHECK-NEXT: call void @test64_helper(i8* [[T4]]) - // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T5]]) - // CHECK-NEXT: ret void -} -void test64b(void) { - int x; - id b = ^{ (void) x; }; - - // CHECK: define void @test64b() - // CHECK: [[X:%.*]] = alloca i32, align 4 - // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8 - // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 - // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* - // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) - // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* - // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* - // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8 - // CHECK-NEXT: [[T5:%.*]] = load i8** [[B]] - // CHECK-NEXT: call void @objc_release(i8* [[T5]]) - // CHECK-NEXT: ret void -} - -// rdar://problem/9979150 -@interface Test65 -@property (strong) void(^ablock)(void); -@property (nonatomic, strong) void(^nblock)(void); -@end -@implementation Test65 -@synthesize ablock, nblock; -// CHECK: define internal void ()* @"\01-[Test65 ablock]"( -// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true) - -// CHECK: define internal void @"\01-[Test65 setAblock:]"( -// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true) - -// CHECK: define internal void ()* @"\01-[Test65 nblock]"( -// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false) - -// CHECK: define internal void @"\01-[Test65 setNblock:]"( -// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true) -@end - // Verify that we successfully parse and preserve this attribute in // this position. @interface Test66 @@ -1932,7 +1481,59 @@ void test66(void) { // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]]) // CHECK-NEXT: [[T6:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES // CHECK-NEXT: [[T7:%.*]] = bitcast [[TEST66]]* [[T3]] to i8* -// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]]) -// CHECK-NEXT: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8* +// CHECK-NEXT: [[SIX:%.*]] = icmp eq i8* [[T7]], null +// CHECK-NEXT: br i1 [[SIX]], label [[NULINIT:%.*]], label [[CALL:%.*]] +// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]]) +// CHECK-NEXT: br label [[CONT:%.*]] +// CHECK: call void @objc_release(i8* [[T5]]) nounwind +// CHECK-NEXT: br label [[CONT:%.*]] +// CHECK: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8* // CHECK-NEXT: call void @objc_release(i8* [[T8]]) // CHECK-NEXT: ret void + +// rdar://problem/9953540 +Class test67_helper(void); +void test67(void) { + Class cl = test67_helper(); +} +// CHECK: define void @test67() +// CHECK: [[CL:%.*]] = alloca i8*, align 8 +// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper() +// CHECK-NEXT: store i8* [[T0]], i8** [[CL]], align 8 +// CHECK-NEXT: ret void + +Class test68_helper(void); +void test68(void) { + __strong Class cl = test67_helper(); +} +// CHECK: define void @test68() +// CHECK: [[CL:%.*]] = alloca i8*, align 8 +// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper() +// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) +// CHECK-NEXT: store i8* [[T1]], i8** [[CL]], align 8 +// CHECK-NEXT: [[T2:%.*]] = load i8** [[CL]] +// CHECK-NEXT: call void @objc_release(i8* [[T2]]) +// CHECK-NEXT: ret void + +// rdar://problem/10564852 +@interface Test69 @end +@implementation Test69 +- (id) foo { return self; } +@end +// CHECK: define internal i8* @"\01-[Test69 foo]"( +// CHECK: [[SELF:%.*]] = alloca [[TEST69:%.*]]*, align 8 +// CHECK: [[T0:%.*]] = load [[TEST69]]** [[SELF]], align 8 +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST69]]* [[T0]] to i8* +// CHECK-NEXT: ret i8* [[T1]] + +// rdar://problem/10907547 +void test70(id i) { + // CHECK: define void @test70 + // CHECK: store i8* null, i8** + // CHECK: store i8* null, i8** + // CHECK: [[ID:%.*]] = call i8* @objc_retain(i8* + // CHECK: store i8* [[ID]], i8** + id x[3] = { + [2] = i + }; +} diff --git a/test/CodeGenObjC/auto-property-synthesize-protocol.m b/test/CodeGenObjC/auto-property-synthesize-protocol.m new file mode 100644 index 0000000000000..49a4037e26453 --- /dev/null +++ b/test/CodeGenObjC/auto-property-synthesize-protocol.m @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -fobjc-default-synthesize-properties -emit-llvm %s -o - | FileCheck %s +// rdar://10907410 + +@protocol P +@optional +@property int auto_opt_window; +@property int no_auto_opt_window; +@end + +@interface I<P> +@property int auto_opt_window; +@end + +@implementation I +@end + +@protocol P1 +@property int auto_req_window; +@property int no_auto_req_window; // expected-note {{property declared here}} +@end + +@interface I1<P1> +@property int auto_req_window; +@end + +@implementation I1 // expected-warning {{auto property synthesis will not synthesize property declared in a protocol}} +@end + +// CHECK: define internal i32 @"\01-[I auto_opt_window]"( +// CHECK: define internal void @"\01-[I setAuto_opt_window:]"( +// CHECK: define internal i32 @"\01-[I1 auto_req_window]"( +// CHECK: define internal void @"\01-[I1 setAuto_req_window:]"( + +// CHECK-NOT: define internal i32 @"\01-[I1 no_auto_opt_window]"( +// CHECK-NOT: define internal void @"\01-[I1 setNo_auto_opt_window:]"( +// CHECK-NOT: define internal i32 @"\01-[I no_auto_req_window]"( +// CHECK-NOT: define internal void @"\01-[I setNo_auto_req_window:]"( diff --git a/test/CodeGenObjC/catch-lexical-block.m b/test/CodeGenObjC/catch-lexical-block.m new file mode 100644 index 0000000000000..f4a6a222182e6 --- /dev/null +++ b/test/CodeGenObjC/catch-lexical-block.m @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -g -fobjc-exceptions -emit-llvm %s -o - | FileCheck %s +@interface Foo @end +void f0() { + @try { + @throw @"a"; + } @catch(Foo *e) { + } +} + +// We should have 4 lexical blocks here at the moment, including one +// for the catch block. +// CHECK: lexical_block +// CHECK: lexical_block +// CHECK: lexical_block +// CHECK: auto_variable +// CHECK: lexical_block diff --git a/test/CodeGenObjC/complex-double-abi.m b/test/CodeGenObjC/complex-double-abi.m new file mode 100644 index 0000000000000..08246d5824f68 --- /dev/null +++ b/test/CodeGenObjC/complex-double-abi.m @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm -triple i386-apple-macosx10.7.2 %s -o - | FileCheck %s +// rdar://10331109 + +@interface CNumber +- (double _Complex)sum; +@end + +double _Complex foo(CNumber *x) { + return [x sum]; +} + +// CHECK: [[T4:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[R1:%.*]], [[MSGCALL:%.*]] ] +// CHECK: [[T5:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[I1:%.*]], [[MSGCALL:%.*]] ] + +// CHECK: store double [[T4]] +// CHECK: store double [[T5]] diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m index 398981362e086..c308d7a475dc8 100644 --- a/test/CodeGenObjC/constant-strings.m +++ b/test/CodeGenObjC/constant-strings.m @@ -8,11 +8,9 @@ // RUN: %clang_cc1 -fgnu-runtime -emit-llvm -o %t %s // RUN: FileCheck --check-prefix=CHECK-GNU < %t %s // CHECK-GNU: NXConstantString -// CHECK-GNU-NOT: NXConstantString // RUN: %clang_cc1 -fgnu-runtime -fconstant-string-class NSConstantString -emit-llvm -o %t %s // RUN: FileCheck --check-prefix=CHECK-GNU-WITH-CLASS < %t %s // CHECK-GNU-WITH-CLASS: NSConstantString -// CHECK-GNU-WITH-CLASS-NOT: NSConstantString id a = @"Hello World!"; diff --git a/test/CodeGenObjC/debug-info-block-helper.m b/test/CodeGenObjC/debug-info-block-helper.m index 644e458bbd2c5..83db0c97e5a80 100644 --- a/test/CodeGenObjC/debug-info-block-helper.m +++ b/test/CodeGenObjC/debug-info-block-helper.m @@ -1,8 +1,8 @@ // REQUIRES: x86-64-registered-target -// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 -fobjc-fragile-abi %s -o - | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -fblocks -g -triple x86_64-apple-darwin10 -fobjc-fragile-abi %s -o - | FileCheck %s extern void foo(void(^)(void)); -// CHECK: .ascii "__destroy_helper_block_" ## DW_AT_name +// CHECK: metadata !{i32 786478, i32 0, metadata !27, metadata !"__destroy_helper_block_", metadata !"__destroy_helper_block_", metadata !"", metadata !27, i32 24, metadata !43, i1 true, i1 true, i32 0, i32 0, null, i32 0, i1 false, void (i8*)* @__destroy_helper_block_, null, null, metadata !45, i32 24} ; [ DW_TAG_subprogram ] @interface NSObject { struct objc_object *isa; diff --git a/test/CodeGenObjC/debug-info-fwddecl.m b/test/CodeGenObjC/debug-info-fwddecl.m new file mode 100644 index 0000000000000..ebdc5f290a571 --- /dev/null +++ b/test/CodeGenObjC/debug-info-fwddecl.m @@ -0,0 +1,5 @@ +// RUN: %clang -fverbose-asm -g -S -emit-llvm %s -o - | FileCheck %s +@class ForwardObjcClass; +ForwardObjcClass *ptr = 0; + +// CHECK: metadata !{i32 {{.*}}, null, metadata !"ForwardObjcClass", metadata !{{.*}}, i32 2, i32 0, i32 0, i32 0, i32 4, null, null, i32 16} ; [ DW_TAG_structure_type ] diff --git a/test/CodeGenObjC/debug-info-getter-name.m b/test/CodeGenObjC/debug-info-getter-name.m index e7d3a9a8749e5..3939f355b68f6 100644 --- a/test/CodeGenObjC/debug-info-getter-name.m +++ b/test/CodeGenObjC/debug-info-getter-name.m @@ -1,11 +1,7 @@ // REQUIRES: x86-64-registered-target -// RUN: %clang_cc1 -fno-dwarf2-cfi-asm -triple x86_64-apple-darwin10 -fexceptions -fobjc-exceptions -S -g %s -o - | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 -fexceptions -fobjc-exceptions -g %s -o - | FileCheck %s -//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString]": -//CHECK: .quad "-[InstanceVariablesEverywhereButTheInterface someString]" -//CHECK: .ascii "-[InstanceVariablesEverywhereButTheInterface someString]" -//CHECK: .asciz "-[InstanceVariablesEverywhereButTheInterface someString]" -//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString].eh": +// CHECK: {{.*}}, metadata !"-[InstanceVariablesEverywhereButTheInterface someString]", {{.*}}} ; [ DW_TAG_subprogram ] //rdar: //8498026 diff --git a/test/CodeGenObjC/debug-info-impl.m b/test/CodeGenObjC/debug-info-impl.m new file mode 100644 index 0000000000000..8ad590357b0d6 --- /dev/null +++ b/test/CodeGenObjC/debug-info-impl.m @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -S -emit-llvm %s -o - | FileCheck %s +// CHECK: metadata !{i32 {{.*}}, metadata {{.*}}, metadata !"Circle", metadata {{.*}}, i32 11, i64 64, i64 64, i32 0, i32 512, null, metadata {{.*}}, i32 16, i32 0} ; [ DW_TAG_structure_type ] +@interface NSObject { + struct objc_object *isa; +} +@end + +@interface Shape : NSObject + +@end +@interface Circle : Shape + +@end +@implementation Circle + +@end diff --git a/test/CodeGenObjC/debug-info-property.m b/test/CodeGenObjC/debug-info-property.m index d86b7c7a5eba0..dd105a58bdf41 100644 --- a/test/CodeGenObjC/debug-info-property.m +++ b/test/CodeGenObjC/debug-info-property.m @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s // CHECK: AT_APPLE_property_name +// CHECK: AT_APPLE_property_attribute +// CHECK: AT_APPLE_property @interface I1 { int p1; } diff --git a/test/CodeGenObjC/debug-info-property3.m b/test/CodeGenObjC/debug-info-property3.m new file mode 100644 index 0000000000000..f96ec44c6b216 --- /dev/null +++ b/test/CodeGenObjC/debug-info-property3.m @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -S -emit-llvm -g %s -o - | FileCheck %s + +// CHECK: metadata !"p1", metadata !6, i32 5, metadata !"", metadata !"", i32 2316, metadata !9} ; [ DW_TAG_APPLE_property ] +@interface I1 +@property int p1; +@end + +@implementation I1 +@synthesize p1; +@end + +void foo(I1 *iptr) {} diff --git a/test/CodeGenObjC/debug-info-property4.m b/test/CodeGenObjC/debug-info-property4.m new file mode 100644 index 0000000000000..6d9973c3e0e20 --- /dev/null +++ b/test/CodeGenObjC/debug-info-property4.m @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fobjc-default-synthesize-properties -masm-verbose -S -g %s -o - | FileCheck %s + +// CHECK: AT_APPLE_property_name +// CHECK-NOT: AT_APPLE_property_getter +// CHECK-NOT: AT_APPLE_property_setter +// CHECK: AT_APPLE_property_attribute +// CHECK: AT_APPLE_property + + +@interface I1 +@property int p1; +@end + +@implementation I1 +@end + +void foo(I1 *ptr) {} diff --git a/test/CodeGenObjC/debug-info-property5.m b/test/CodeGenObjC/debug-info-property5.m new file mode 100644 index 0000000000000..35215749ecd98 --- /dev/null +++ b/test/CodeGenObjC/debug-info-property5.m @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fobjc-default-synthesize-properties -masm-verbose -S -g %s -o - | FileCheck %s + +// CHECK: AT_APPLE_property_name +// CHECK: AT_APPLE_property_getter +// CHECK: AT_APPLE_property_setter +// CHECK: AT_APPLE_property_attribute +// CHECK: AT_APPLE_property + +@interface BaseClass2 +{ + int _baseInt; +} +- (int) myGetBaseInt; +- (void) mySetBaseInt: (int) in_int; +@property(getter=myGetBaseInt,setter=mySetBaseInt:) int baseInt; +@end + +@implementation BaseClass2 + +- (int) myGetBaseInt +{ + return _baseInt; +} + +- (void) mySetBaseInt: (int) in_int +{ + _baseInt = 2 * in_int; +} +@end + + +void foo(BaseClass2 *ptr) {} diff --git a/test/CodeGenObjC/debug-info-pubtypes.m b/test/CodeGenObjC/debug-info-pubtypes.m index 744a366ce7c5f..658430d9307b1 100644 --- a/test/CodeGenObjC/debug-info-pubtypes.m +++ b/test/CodeGenObjC/debug-info-pubtypes.m @@ -1,12 +1,7 @@ // REQUIRES: x86-64-registered-target -// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -S %s -o %t -// RUN: FileCheck %s < %t +// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -emit-llvm %s -o - | FileCheck %s -//CHECK: .long Lset6 -//CHECK-NEXT: .long -//CHECK-NEXT: .asciz "H" -//CHECK-NEXT: .long 0 -//CHECK-NEXT: Lpubtypes_end1: +// CHECK: !5 = metadata !{i32 {{.*}}, metadata !6, metadata !"H", metadata !6, i32 6, i64 0, i64 8, i32 0, i32 512, null, metadata !2, i32 16, i32 0} ; [ DW_TAG_structure_type ] @interface H -(void) foo; diff --git a/test/CodeGenObjC/debug-info-static-var.m b/test/CodeGenObjC/debug-info-static-var.m index 1f281d042d106..c65e77c4d8d4c 100644 --- a/test/CodeGenObjC/debug-info-static-var.m +++ b/test/CodeGenObjC/debug-info-static-var.m @@ -3,9 +3,8 @@ // Radar 8801045 // Do not emit AT_MIPS_linkage_name for static variable i -// CHECK: DW_TAG_variable -// CHECK-NEXT: .byte 105 ## DW_AT_name -// CHECK-NEXT: .byte 0 +// CHECK: Lset6 = Lstring3-Lsection_str ## DW_AT_name +// CHECK-NEXT: .long Lset6 // CHECK-NEXT: DW_AT_type // CHECK-NEXT: DW_AT_decl_file // CHECK-NEXT: DW_AT_decl_line diff --git a/test/CodeGenObjC/debug-info-synthesis.m b/test/CodeGenObjC/debug-info-synthesis.m new file mode 100644 index 0000000000000..7e263cf74c6ee --- /dev/null +++ b/test/CodeGenObjC/debug-info-synthesis.m @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -emit-llvm -g -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s +# 1 "foo.m" 1 +# 1 "foo.m" 2 +# 1 "./foo.h" 1 +@interface NSObject { + struct objc_object *isa; +} +@end +@class NSDictionary; + +@interface Foo : NSObject {} +@property (strong, nonatomic) NSDictionary *dict; +@end +# 2 "foo.m" 2 + + + + +@implementation Foo +@synthesize dict = _dict; + +- (void) bork { +} +@end + +int main(int argc, char *argv[]) { + @autoreleasepool { + Foo *f = [Foo new]; + [f bork]; + } +} + +// CHECK: !7 = metadata !{i32 {{.*}}, metadata !"./foo.h" +// CHECK: !31 = metadata !{i32 {{.*}}, i32 0, metadata !7, metadata !"-[Foo dict]", metadata !"-[Foo dict]", metadata !"", metadata !7, i32 8, metadata !32, i1 true, i1 true, i32 0, i32 0, null, i32 320, i1 false, %1* (%0*, i8*)* @"\01-[Foo dict]", null, null, metadata !34, i32 8} ; [ DW_TAG_subprogram ] diff --git a/test/CodeGenObjC/debug-property-synth.m b/test/CodeGenObjC/debug-property-synth.m index 05852b7e29254..954620a635980 100644 --- a/test/CodeGenObjC/debug-property-synth.m +++ b/test/CodeGenObjC/debug-property-synth.m @@ -16,4 +16,5 @@ int main() { return 0; } -// CHECK: .loc 2 10 0 +// FIXME: Make this test ir files. +// CHECK: .loc 2 6 0 diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m index 2472869ff58b5..24fb6575e4403 100644 --- a/test/CodeGenObjC/exceptions.m +++ b/test/CodeGenObjC/exceptions.m @@ -53,11 +53,7 @@ int f2() { // CHECK-NEXT: [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0 // CHECK-NEXT: br i1 [[CAUGHT]] @try { - // If the optimizers ever figure out how to make this store 6, - // that's okay. - // CHECK: [[T1:%.*]] = load i32* [[X]] - // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], 1 - // CHECK-NEXT: store i32 [[T2]], i32* [[X]] + // CHECK: store i32 6, i32* [[X]] x++; // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* [[X]] // CHECK-NEXT: call void @foo() diff --git a/test/CodeGenObjC/forward-class-impl-metadata.m b/test/CodeGenObjC/forward-class-impl-metadata.m index e9e08589d19f1..371abf2ade9cd 100644 --- a/test/CodeGenObjC/forward-class-impl-metadata.m +++ b/test/CodeGenObjC/forward-class-impl-metadata.m @@ -39,3 +39,9 @@ int f0(A *a) { @implementation A @synthesize p0 = _p0; @end + +@interface B +@end +@class B; +@implementation B +@end diff --git a/test/CodeGenObjC/fp2ret.m b/test/CodeGenObjC/fp2ret.m new file mode 100644 index 0000000000000..9c956aec9b3f2 --- /dev/null +++ b/test/CodeGenObjC/fp2ret.m @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-X86_32 %s +// +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-X86_64 %s +// +// RUN: %clang_cc1 -triple armv7-apple-darwin10 -fobjc-fragile-abi -emit-llvm -target-abi apcs-gnu -o - %s | \ +// RUN: FileCheck --check-prefix=CHECK-ARMV7 %s + +@interface A +-(_Complex long double) complexLongDoubleValue; +@end + + +// CHECK-X86_32: define void @t0() +// CHECK-X86_32: call void bitcast {{.*}} @objc_msgSend_stret to +// CHECK-X86_32: } +// +// CHECK-X86_64: define void @t0() +// CHECK-X86_64: call { x86_fp80, x86_fp80 } bitcast {{.*}} @objc_msgSend_fp2ret to +// CHECK-X86_64: } +// +// CHECK-ARMV7: define void @t0() +// CHECK-ARMV7: call i128 bitcast {{.*}} @objc_msgSend to +// CHECK-ARMV7: } +void t0() { + [(A*)0 complexLongDoubleValue]; +} diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m index 22f7229b69508..613b272bdea25 100644 --- a/test/CodeGenObjC/image-info.m +++ b/test/CodeGenObjC/image-info.m @@ -4,5 +4,14 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s // RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s -// CHECK-FRAGILE: @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__OBJC, __image_info,regular" -// CHECK-NONFRAGILE: @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip" +// CHECK-FRAGILE: !llvm.module.flags = !{!0, !1, !2, !3} +// CHECK-FRAGILE: !0 = metadata !{i32 1, metadata !"Objective-C Version", i32 1} +// CHECK-FRAGILE-NEXT: !1 = metadata !{i32 1, metadata !"Objective-C Image Info Version", i32 0} +// CHECK-FRAGILE-NEXT: !2 = metadata !{i32 1, metadata !"Objective-C Image Info Section", metadata !"__OBJC, __image_info,regular"} +// CHECK-FRAGILE-NEXT: !3 = metadata !{i32 4, metadata !"Objective-C Garbage Collection", i32 0} + +// CHECK-NONFRAGILE: !llvm.module.flags = !{!0, !1, !2, !3} +// CHECK-NONFRAGILE: !0 = metadata !{i32 1, metadata !"Objective-C Version", i32 2} +// CHECK-NONFRAGILE-NEXT: !1 = metadata !{i32 1, metadata !"Objective-C Image Info Version", i32 0} +// CHECK-NONFRAGILE-NEXT: !2 = metadata !{i32 1, metadata !"Objective-C Image Info Section", metadata !"__DATA, __objc_imageinfo, regular, no_dead_strip"} +// CHECK-NONFRAGILE-NEXT: !3 = metadata !{i32 4, metadata !"Objective-C Garbage Collection", i32 0} diff --git a/test/CodeGenObjC/ivar-base-as-invariant-load.m b/test/CodeGenObjC/ivar-base-as-invariant-load.m new file mode 100644 index 0000000000000..8b660cf483d95 --- /dev/null +++ b/test/CodeGenObjC/ivar-base-as-invariant-load.m @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -x objective-c %s -o - | FileCheck %s +// rdar://10840980 + +@interface A { + struct { + unsigned char a : 1; + unsigned char b : 1; + unsigned char c : 1; + } _flags; +} + +@end + +@implementation A + +- (id)init { + _flags.a = 1; + _flags.b = 1; + _flags.c = 1; + + return self; +} + +@end + +// CHECK: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4 +// CHECK: [[T2:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4 +// CHECK: [[T3:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4 + diff --git a/test/CodeGenObjC/ns_consume_null_check.m b/test/CodeGenObjC/ns_consume_null_check.m new file mode 100644 index 0000000000000..e3b60759e91b3 --- /dev/null +++ b/test/CodeGenObjC/ns_consume_null_check.m @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-dispatch-method=mixed -o - %s | FileCheck %s +// rdar://10444476 + +@interface NSObject +- (id) new; +@end + +@interface MyObject : NSObject +- (char)isEqual:(id) __attribute__((ns_consumed)) object; +@end + +MyObject *x; + +void foo() +{ + id obj = [NSObject new]; + [x isEqual : obj]; +} + +// CHECK: [[TMP:%.*]] = alloca i8 +// CHECK: [[FIVE:%.*]] = call i8* @objc_retain +// CHECK-NEXT: [[SIX:%.*]] = bitcast +// CHECK-NEXT: [[SEVEN:%.*]] = icmp eq i8* [[SIX]], null +// CHECK-NEXT: br i1 [[SEVEN]], label [[NULLINIT:%.*]], label [[CALL_LABEL:%.*]] +// CHECK: [[FN:%.*]] = load i8** getelementptr inbounds +// CHECK-NEXT: [[EIGHT:%.*]] = bitcast i8* [[FN]] +// CHECK-NEXT: [[CALL:%.*]] = call signext i8 [[EIGHT]] +// CHECK-NEXT store i8 [[CALL]], i8* [[TMP]] +// CHECK-NEXT br label [[CONT:%.*]] +// CHECK: call void @objc_release(i8* [[FIVE]]) nounwind +// CHECK-NEXT: call void @llvm.memset +// CHECK-NEXT br label [[CONT]] diff --git a/test/CodeGenObjC/objc-align.m b/test/CodeGenObjC/objc-align.m index f07272516f1c0..f3c586eeb2149 100644 --- a/test/CodeGenObjC/objc-align.m +++ b/test/CodeGenObjC/objc-align.m @@ -6,7 +6,6 @@ // RUN: grep '@"\\01L_OBJC_CLASS_A" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t // RUN: grep '@"\\01L_OBJC_CLASS_C" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t // RUN: grep '@"\\01L_OBJC_CLASS_PROTOCOLS_C" = internal global .*, section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t -// RUN: grep '@"\\01L_OBJC_IMAGE_INFO" = internal constant .*, section "__OBJC, __image_info,regular"' %t // RUN: grep '@"\\01L_OBJC_METACLASS_A" = internal global .*, section "__OBJC,__meta_class,regular,no_dead_strip", align 4' %t // RUN: grep '@"\\01L_OBJC_METACLASS_C" = internal global .*, section "__OBJC,__meta_class,regular,no_dead_strip", align 4' %t // RUN: grep '@"\\01L_OBJC_MODULES" = internal global .*, section "__OBJC,__module_info,regular,no_dead_strip", align 4' %t @@ -20,7 +19,6 @@ // RUNX: grep '@"OBJC_METACLASS_$_A" = global' %t && // RUNX: grep '@"OBJC_METACLASS_$_C" = global' %t && // RUNX: grep '@"\\01L_OBJC_CLASSLIST_REFERENCES_$_0" = internal global .*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8' %t && -// RUNX: grep '@"\\01L_OBJC_IMAGE_INFO" = internal constant .*, section "__DATA, __objc_imageinfo, regular, no_dead_strip"' %t && // RUNX: grep '@"\\01L_OBJC_LABEL_CATEGORY_$" = internal global .*, section "__DATA, __objc_catlist, regular, no_dead_strip", align 8' %t && // RUNX: grep '@"\\01L_OBJC_LABEL_CLASS_$" = internal global .*, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8' %t && // RUNX: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = internal global .*, section "__DATA, __objc_const", align 8' %t && diff --git a/test/CodeGenObjC/objc-arc-container-subscripting.m b/test/CodeGenObjC/objc-arc-container-subscripting.m new file mode 100644 index 0000000000000..892491630e6e5 --- /dev/null +++ b/test/CodeGenObjC/objc-arc-container-subscripting.m @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -fobjc-arc -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s + +@interface NSMutableArray +- (id)objectAtIndexedSubscript:(int)index; +- (void)setObject:(id)object atIndexedSubscript:(int)index; +@end + +id func() { + NSMutableArray *array; + array[3] = 0; + return array[3]; +} + +// CHECK: [[call:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend +// CHECK: [[SIX:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[call]]) nounwind +// CHECK: [[ARRAY:%.*]] = load %0** +// CHECK: [[ARRAY_CASTED:%.*]] = bitcast{{.*}}[[ARRAY]] to i8* +// CHECK: call void @objc_release(i8* [[ARRAY_CASTED]]) +// CHECK: [[EIGHT:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[SIX]]) nounwind +// CHECK: ret i8* [[EIGHT]] + diff --git a/test/CodeGenObjC/objc-container-subscripting-1.m b/test/CodeGenObjC/objc-container-subscripting-1.m new file mode 100644 index 0000000000000..91b7f468ea958 --- /dev/null +++ b/test/CodeGenObjC/objc-container-subscripting-1.m @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s + +typedef unsigned int size_t; +@protocol P @end + +@interface NSMutableArray +- (id)objectAtIndexedSubscript:(size_t)index; +- (void)setObject:(id)object atIndexedSubscript:(size_t)index; +@end + +@interface NSMutableDictionary +- (id)objectForKeyedSubscript:(id)key; +- (void)setObject:(id)object forKeyedSubscript:(id)key; +@end + +int main() { + NSMutableArray *array; + id val; + + id oldObject = array[10]; +// CHECK: [[ARR:%.*]] = load {{%.*}} [[array:%.*]], align 8 +// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_" +// CHECK-NEXT: [[ARRC:%.*]] = bitcast {{%.*}} [[ARR]] to i8* +// CHECK-NEXT: [[CALL:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8* [[ARRC]], i8* [[SEL]], i32 10) +// CHECK-NEXT: store i8* [[CALL]], i8** [[OLDOBJ:%.*]], align 8 + + val = (array[10] = oldObject); +// CHECK: [[THREE:%.*]] = load {{%.*}} [[array:%.*]], align 8 +// CHECK-NEXT: [[FOUR:%.*]] = load i8** [[oldObject:%.*]], align 8 +// CHECK-NEXT: [[FIVE:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2" +// CHECK-NEXT: [[SIX:%.*]] = bitcast {{%.*}} [[THREE]] to i8* +// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i32)*)(i8* [[SIX]], i8* [[FIVE]], i8* [[FOUR]], i32 10) +// CHECK-NEXT: store i8* [[FOUR]], i8** [[val:%.*]] + + NSMutableDictionary *dictionary; + id key; + id newObject; + oldObject = dictionary[key]; +// CHECK: [[SEVEN:%.*]] = load {{%.*}} [[DICTIONARY:%.*]], align 8 +// CHECK-NEXT: [[EIGHT:%.*]] = load i8** [[KEY:%.*]], align 8 +// CHECK-NEXT: [[TEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_4" +// CHECK-NEXT: [[ELEVEN:%.*]] = bitcast {{%.*}} [[SEVEN]] to i8* +// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[ELEVEN]], i8* [[TEN]], i8* [[EIGHT]]) +// CHECK-NEXT: store i8* [[CALL1]], i8** [[oldObject:%.*]], align 8 + + + val = (dictionary[key] = newObject); +// CHECK: [[TWELVE:%.*]] = load {{%.*}} [[DICTIONARY]], align 8 +// CHECK-NEXT: [[THIRTEEN:%.*]] = load i8** [[KEY]], align 8 +// CHECK-NEXT: [[FOURTEEN:%.*]] = load i8** [[NEWOBJECT:%.*]], align 8 +// CHECK-NEXT: [[SIXTEEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_6" +// CHECK-NEXT: [[SEVENTEEN:%.*]] = bitcast {{%.*}} [[TWELVE]] to i8* +// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i8*)*)(i8* [[SEVENTEEN]], i8* [[SIXTEEN]], i8* [[FOURTEEN]], i8* [[THIRTEEN]]) +// CHECK-NEXT: store i8* [[FOURTEEN]], i8** [[val:%.*]] +} + diff --git a/test/CodeGenObjC/objc-container-subscripting.m b/test/CodeGenObjC/objc-container-subscripting.m new file mode 100644 index 0000000000000..fd8f8effac6d0 --- /dev/null +++ b/test/CodeGenObjC/objc-container-subscripting.m @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin %s -o /dev/null + +typedef unsigned int size_t; +@protocol P @end + +@interface NSMutableArray +#if __has_feature(objc_subscripting) +- (id)objectAtIndexedSubscript:(size_t)index; +- (void)setObject:(id)object atIndexedSubscript:(size_t)index; +#endif +@end + +#if __has_feature(objc_subscripting) +@interface XNSMutableArray +- (id)objectAtIndexedSubscript:(size_t)index; +- (void)setObject:(id)object atIndexedSubscript:(size_t)index; +#endif +@end + +@interface NSMutableDictionary +- (id)objectForKeyedSubscript:(id)key; +- (void)setObject:(id)object forKeyedSubscript:(id)key; +@end + +@class NSString; + +int main() { + NSMutableArray<P> * array; + id oldObject = array[10]; + + array[10] = oldObject; + + id unknown_array; + oldObject = unknown_array[1]; + + unknown_array[1] = oldObject; + + NSMutableDictionary *dictionary; + NSString *key; + id newObject; + oldObject = dictionary[key]; + dictionary[key] = newObject; // replace oldObject with newObject + +} + diff --git a/test/CodeGenObjC/objc-dictionary-literal.m b/test/CodeGenObjC/objc-dictionary-literal.m new file mode 100644 index 0000000000000..b335582ed2be8 --- /dev/null +++ b/test/CodeGenObjC/objc-dictionary-literal.m @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -x objective-c -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o /dev/null +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o /dev/null +// rdar://10614657 + +@interface NSNumber ++ (NSNumber *)numberWithChar:(char)value; ++ (NSNumber *)numberWithInt:(int)value; +@end + +@protocol NSCopying @end +typedef unsigned long NSUInteger; + +@interface NSDictionary ++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt; +@end + +@interface NSString<NSCopying> +@end + +int main() { + NSDictionary *dict = @{ @"name":@666 }; + NSDictionary *dict1 = @{ @"name":@666 }; + NSDictionary *dict2 = @{ @"name":@666 }; + return 0; +} diff --git a/test/CodeGenObjC/objc-literal-debugger-test.m b/test/CodeGenObjC/objc-literal-debugger-test.m new file mode 100644 index 0000000000000..389ef2248a481 --- /dev/null +++ b/test/CodeGenObjC/objc-literal-debugger-test.m @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdebugger-objc-literal -emit-llvm -o - %s | FileCheck %s + +int main() { + id l = @'a'; + l = @'a'; + l = @42; + l = @-42; + l = @42u; + l = @3.141592654f; + l = @__objc_yes; + l = @__objc_no; + l = @{ @"name":@666 }; + l = @[ @"foo", @"bar" ]; +} + +// CHECK: declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind diff --git a/test/CodeGenObjC/objc-literal-tests.m b/test/CodeGenObjC/objc-literal-tests.m new file mode 100644 index 0000000000000..c513d4961103a --- /dev/null +++ b/test/CodeGenObjC/objc-literal-tests.m @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -x objective-c -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o - | FileCheck %s +// rdar://10111397 + +#if __has_feature(objc_bool) +#define YES __objc_yes +#define NO __objc_no +#else +#define YES ((BOOL)1) +#define NO ((BOOL)0) +#endif + +#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 +typedef unsigned long NSUInteger; +typedef long NSInteger; +#else +typedef unsigned int NSUInteger; +typedef int NSInteger; +#endif +typedef signed char BOOL; + +@interface NSNumber @end + +@interface NSNumber (NSNumberCreation) +#if __has_feature(objc_array_literals) ++ (NSNumber *)numberWithChar:(char)value; ++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value; ++ (NSNumber *)numberWithShort:(short)value; ++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value; ++ (NSNumber *)numberWithInt:(int)value; ++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value; ++ (NSNumber *)numberWithLong:(long)value; ++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value; ++ (NSNumber *)numberWithLongLong:(long long)value; ++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value; ++ (NSNumber *)numberWithFloat:(float)value; ++ (NSNumber *)numberWithDouble:(double)value; ++ (NSNumber *)numberWithBool:(BOOL)value; ++ (NSNumber *)numberWithInteger:(NSInteger)value ; ++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value ; +#endif +@end + +@interface NSDate ++ (NSDate *) date; +@end + +#if __has_feature(objc_dictionary_literals) +@interface NSDictionary ++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(NSUInteger)cnt; +@end +#endif + +id NSUserName(); + +// CHECK: define i32 @main() nounwind +int main() { + // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 97 + NSNumber *aNumber = @'a'; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 42 + NSNumber *fortyTwo = @42; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 -42 + NSNumber *negativeFortyTwo = @-42; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 42 + NSNumber *positiveFortyTwo = @+42; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 42 + NSNumber *fortyTwoUnsigned = @42u; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i64 42 + NSNumber *fortyTwoLong = @42l; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i64 42 + NSNumber *fortyTwoLongLong = @42ll; + // CHECK: call{{.*}}@objc_msgSend{{.*}}float 0x400921FB60000000 + NSNumber *piFloat = @3.141592654f; + // CHECK: call{{.*}}@objc_msgSend{{.*}}double 0x400921FB54411744 + NSNumber *piDouble = @3.1415926535; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 1 + NSNumber *yesNumber = @__objc_yes; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 0 + NSNumber *noNumber = @__objc_no; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 1 + NSNumber *yesNumber1 = @YES; + // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 0 + NSNumber *noNumber1 = @NO; +NSDictionary *dictionary = @{@"name" : NSUserName(), + @"date" : [NSDate date] }; + return __objc_yes == __objc_no; +} + +// rdar://10579122 +typedef BOOL (^foo)(void); +extern void bar(foo a); + +void baz(void) { + bar(^(void) { return YES; }); +} diff --git a/test/CodeGenObjC/optimized-setter.m b/test/CodeGenObjC/optimized-setter.m new file mode 100644 index 0000000000000..0e1b388595198 --- /dev/null +++ b/test/CodeGenObjC/optimized-setter.m @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-macosx10.8.0 -o - | FileCheck %s +// rdar://10179974 + +@interface I +// void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset); +// objc_setProperty(..., NO, NO) +@property (nonatomic, retain) id nonatomicProperty; + +// void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset); +// objc_setProperty(..., NO, YES) +@property (nonatomic, copy) id nonatomicPropertyCopy; + +// void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset); +// objc_setProperty(..., YES, NO) +@property (retain) id atomicProperty; + +// void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset); +// objc_setProperty(..., YES, YES) +@property (copy) id atomicPropertyCopy; +@end + +@implementation I +@synthesize nonatomicProperty; +@synthesize nonatomicPropertyCopy; +@synthesize atomicProperty; +@synthesize atomicPropertyCopy; +@end + +// CHECK: call void @objc_setProperty_nonatomic +// CHECK: call void @objc_setProperty_nonatomic_copy +// CHECK: call void @objc_setProperty_atomic +// CHECK: call void @objc_setProperty_atomic_copy + diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m index 3cc9200f333c8..16881d608bf2e 100644 --- a/test/CodeGenObjC/property.m +++ b/test/CodeGenObjC/property.m @@ -112,3 +112,57 @@ void test4(Test4 *t) { @implementation Test5 @synthesize x = _x; @end + +// rdar://problem/10410531 +@interface Test6 +@property void (*prop)(void); +@end + +void test6_func(void); +void test6(Test6 *a) { + a.prop = test6_func; +} + +// rdar://problem/10507455 +@interface Test7 +@property unsigned char x; +@end +void test7(Test7 *t) { + t.x &= 2; + t.x |= 5; + t.x ^= 8; +} +// CHECK: define void @test7([[TEST7:%.*]]* +// CHECK: [[T:%.*]] = alloca [[TEST7]]*, +// CHECK-NEXT: store +// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align +// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast +// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32 +// CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 2 +// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8 +// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* +// CHECK-NEXT: call void bitcast +// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align +// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast +// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32 +// CHECK-NEXT: [[T4:%.*]] = or i32 [[T3]], 5 +// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8 +// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* +// CHECK-NEXT: call void bitcast +// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align +// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast +// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32 +// CHECK-NEXT: [[T4:%.*]] = xor i32 [[T3]], 8 +// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8 +// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8* +// CHECK-NEXT: call void bitcast +// CHECK-NEXT: ret void diff --git a/test/CodeGenObjC/selector-ref-invariance.m b/test/CodeGenObjC/selector-ref-invariance.m new file mode 100644 index 0000000000000..e356419de9e8c --- /dev/null +++ b/test/CodeGenObjC/selector-ref-invariance.m @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fblocks -o - %s | FileCheck %s + +// rdar://6027699 + +void test(id x) { +// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", !invariant.load +// CHECK: @objc_msgSend + [x foo]; +} diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m index 7e557b0178d8d..94d7bafba472a 100644 --- a/test/CodeGenObjC/variadic-sends.m +++ b/test/CodeGenObjC/variadic-sends.m @@ -20,8 +20,8 @@ void f1(A *a) { } void f2(A *a) { - // CHECK-X86-32: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*) - // CHECK-X86-64: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*) + // CHECK-X86-32: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*) + // CHECK-X86-64: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*) [a im2: 1, 2]; } @@ -33,8 +33,8 @@ void f2(A *a) { [super im1: 1]; } -(void) bar { - // CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*) - // CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*) + // CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*) + // CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*) [super im2: 1, 2]; } |