aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGenObjC/arc.m
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenObjC/arc.m')
-rw-r--r--test/CodeGenObjC/arc.m70
1 files changed, 70 insertions, 0 deletions
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 3d0abc5c30..109e360b79 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -1684,3 +1684,73 @@ void test59(void) {
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// 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
+}