brintos

brintos / llvm-project-archived public Read only

0
0
Text · 32.7 KiB · 605dda7 Raw
701 lines · plain
1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-HEAP -check-prefix=CHECK-COMMON %s2// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -fobjc-avoid-heapify-local-blocks -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-NOHEAP -check-prefix=CHECK-COMMON %s3// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s4 5// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP44:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, i64 } { i64 0, i64 40, ptr @__copy_helper_block_8_32s, ptr @__destroy_helper_block_8_32s, ptr @{{.*}}, i64 256 }, align 86// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, i64 } { i64 0, i64 40, ptr @__copy_helper_block_8_32r, ptr @__destroy_helper_block_8_32r, ptr @{{.*}}, i64 16 }, align 87// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP46:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 48, ptr @__copy_helper_block_8_32s, ptr @__destroy_helper_block_8_32s, ptr @{{.*}}, ptr @{{.*}} }, align 88// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP48:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr, ptr, i64 } { i64 0, i64 40, ptr @__copy_helper_block_8_32b, ptr @__destroy_helper_block_8_32s, ptr @{{.*}}, i64 256 }, align 89 10// Check that no copy/dispose helpers are emitted for this block.11 12// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP10:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr } { i64 0, i64 40, ptr @{{.*}}, ptr @{{.*}} }, align 813 14// This shouldn't crash.15void test0(id (^maker)(void)) {16  maker();17}18 19int (^test1(int x))(void) {20  // CHECK-LABEL:    define{{.*}} ptr @test1(21  // CHECK:      [[X:%.*]] = alloca i32,22  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],23  // CHECK-NEXT: store i32 {{%.*}}, ptr [[X]]24  // CHECK: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]]) [[NUW:#[0-9]+]]25  // CHECK-NEXT: [[T5:%.*]] = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr [[T2]]) [[NUW]]26  // CHECK-NEXT: ret ptr [[T5]]27  return ^{ return x; };28}29 30void test2(id x) {31// CHECK-LABEL:    define{{.*}} void @test2(32// CHECK:      [[X:%.*]] = alloca ptr,33// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],34// CHECK-NEXT: [[PARM:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}})35// CHECK-NEXT: store ptr [[PARM]], ptr [[X]]36// CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 537// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]],38// CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])39// CHECK-NEXT: store ptr [[T1]], ptr [[SLOT]],40// CHECK-NEXT: call void @test2_helper(41// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]]42// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release43// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]44// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release45// CHECK-NEXT: ret void46  extern void test2_helper(id (^)(void));47  test2_helper(^{ return x; });48 49// CHECK:    define linkonce_odr hidden void @__copy_helper_block_8_32s(ptr noundef %0, ptr noundef %1) unnamed_addr #{{[0-9]+}} {50// CHECK:      [[SRC:%.*]] = load ptr, ptr51// CHECK-NEXT: [[DST:%.*]] = load ptr, ptr52// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[SRC]], i32 0, i32 553// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[T0]]54// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]]) [[NUW]]55// CHECK-NEXT: ret void56 57 58// CHECK:    define linkonce_odr hidden void @__destroy_helper_block_8_32s(ptr noundef %0) unnamed_addr #{{[0-9]+}} {59// CHECK:      [[T0:%.*]] = load ptr, ptr60// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[T0]], i32 0, i32 561// CHECK-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]62// CHECK-NEXT: call void @llvm.objc.release(ptr [[T3]])63// CHECK-NEXT: ret void64}65 66void test3(void (^sink)(id*)) {67  __strong id strong;68  sink(&strong);69 70  // CHECK-LABEL:    define{{.*}} void @test3(71  // CHECK:      [[SINK:%.*]] = alloca ptr72  // CHECK-NEXT: [[STRONG:%.*]] = alloca ptr73  // CHECK-NEXT: [[TEMP:%.*]] = alloca ptr74  // CHECK-NEXT: call ptr @llvm.objc.retain(75  // CHECK-NEXT: store ptr {{%.*}}, ptr [[SINK]]76  // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[STRONG]])77  // CHECK-NEXT: store ptr null, ptr [[STRONG]]78 79  // CHECK-NEXT: [[BLOCK:%.*]] = load ptr, ptr [[SINK]]80  // CHECK-NEXT: getelementptr81  // CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[STRONG]]82  // CHECK-NEXT: store ptr [[V]], ptr [[TEMP]]83  // CHECK-NEXT: [[F0:%.*]] = load ptr, ptr84  // CHECK-NEXT: call void [[F0]](ptr noundef [[BLOCK]], ptr noundef [[TEMP]])85  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[TEMP]]86  // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])87  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[V]]) [[NUW]]88  // CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[STRONG]]89  // CHECK-NEXT: store ptr [[T1]], ptr [[STRONG]]90  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T2]])91 92  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[STRONG]]93  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])94  // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[STRONG]])95 96  // CHECK-NEXT: load ptr, ptr [[SINK]]97  // CHECK-NEXT: call void @llvm.objc.release98  // CHECK-NEXT: ret void99 100}101 102void test4(void) {103  id test4_source(void);104  void test4_helper(void (^)(void));105  __block id var = test4_source();106  test4_helper(^{ var = 0; });107 108  // CHECK-LABEL:    define{{.*}} void @test4()109  // CHECK:      [[VAR:%.*]] = alloca [[BYREF_T:%.*]],110  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],111  // CHECK:      [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 2112  // 0x02000000 - has copy/dispose helpers strong113  // CHECK-NEXT: store i32 838860800, ptr [[T0]]114  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6115  // CHECK-NEXT: [[T0:%.*]] = call ptr @test4_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]116  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])117  // CHECK-NEXT: store ptr [[T0]], ptr [[SLOT]]118  // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6119  // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT120  // CHECK:      store i32 -1040187392,121  // CHECK: store ptr [[VAR]], ptr122  // CHECK:      call void @test4_helper(123  // CHECK: call void @_Block_object_dispose(ptr [[VAR]], i32 8)124  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]]125  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])126  // CHECK: ret void127 128  // CHECK-LABEL:    define internal void @__Block_byref_object_copy_(ptr noundef %0, ptr noundef %1) #{{[0-9]+}} {129  // CHECK:      [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6130  // CHECK-NEXT: load ptr, ptr131  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6132  // CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T1]]133  // CHECK-NEXT: store ptr [[T2]], ptr [[T0]]134  // CHECK-NEXT: store ptr null, ptr [[T1]]135 136  // CHECK-LABEL:    define internal void @__Block_byref_object_dispose_(ptr noundef %0) #{{[0-9]+}} {137  // CHECK:      [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6138  // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[T0]]139  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])140 141  // CHECK-LABEL:    define internal void @__test4_block_invoke142  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw {{.*}}, i32 0, i32 6143  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align 8144  // CHECK-NEXT: store ptr null, ptr [[SLOT]],145  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])146  // CHECK-NEXT: ret void147 148  // CHECK-LABEL:    define linkonce_odr hidden void @__copy_helper_block_8_32r(ptr noundef %0, ptr noundef %1) unnamed_addr #{{[0-9]+}} {149  // CHECK:      call void @_Block_object_assign(ptr {{%.*}}, ptr {{%.*}}, i32 8)150 151  // CHECK-LABEL:    define linkonce_odr hidden void @__destroy_helper_block_8_32r(ptr noundef %0) unnamed_addr #{{[0-9]+}} {152  // CHECK:      call void @_Block_object_dispose(ptr {{%.*}}, i32 8)153}154 155void test5(void) {156  extern id test5_source(void);157  void test5_helper(void (^)(void));158  __unsafe_unretained id var = test5_source();159  test5_helper(^{ (void) var; });160 161  // CHECK-LABEL:    define{{.*}} void @test5()162  // CHECK:      [[VAR:%.*]] = alloca ptr163  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],164  // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[VAR]])165  // CHECK: [[T1:%.*]] = call ptr @test5_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]166  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])167  // CHECK-NEXT: store ptr [[T1]], ptr [[VAR]],168  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])169  // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT170  // CHECK:      store i32 -1073741824, ptr171  // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5172  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[VAR]]173  // CHECK-NEXT: store ptr [[T0]], ptr [[CAPTURE]]174  // CHECK: call void @test5_helper175  // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VAR]])176  // CHECK-NEXT: ret void177}178 179void test6(void) {180  id test6_source(void);181  void test6_helper(void (^)(void));182  __block __weak id var = test6_source();183  test6_helper(^{ var = 0; });184 185  // CHECK-LABEL:    define{{.*}} void @test6()186  // CHECK:      [[VAR:%.*]] = alloca [[BYREF_T:%.*]],187  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],188  // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[VAR]])189  // CHECK:      [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 2190  // 0x02000000 - has copy/dispose helpers weak191  // CHECK-NEXT: store i32 1107296256, ptr [[T0]]192  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6193  // CHECK-NEXT: [[T1:%.*]] = call ptr @test6_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]194  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])195  // CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr [[SLOT]], ptr [[T1]])196  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])197  // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[VAR]], i32 0, i32 6198  // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT199  // CHECK:      store i32 -1040187392,200  // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4201// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP9]], ptr %[[BLOCK_DESCRIPTOR]], align 8202  // CHECK: store ptr [[VAR]], ptr203  // CHECK:      call void @test6_helper(204  // CHECK: call void @_Block_object_dispose(ptr [[VAR]], i32 8)205  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[SLOT]])206  // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VAR]])207  // CHECK-NEXT: ret void208 209  // CHECK-LABEL:    define internal void @__Block_byref_object_copy_.{{[0-9]+}}(ptr noundef %0, ptr noundef %1) #{{[0-9]+}} {210  // CHECK:      [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6211  // CHECK-NEXT: load ptr, ptr212  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6213  // CHECK-NEXT: call void @llvm.objc.moveWeak(ptr [[T0]], ptr [[T1]])214 215  // CHECK-LABEL:    define internal void @__Block_byref_object_dispose_.{{[0-9]+}}(ptr noundef %0) #{{[0-9]+}} {216  // CHECK:      [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr {{%.*}}, i32 0, i32 6217  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[T0]])218 219  // CHECK-LABEL:    define internal void @__test6_block_invoke220  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw {{.*}}, i32 0, i32 6221  // CHECK-NEXT: call ptr @llvm.objc.storeWeak(ptr [[SLOT]], ptr null)222  // CHECK-NEXT: ret void223}224 225void test7(void) {226  id test7_source(void);227  void test7_helper(void (^)(void));228  void test7_consume(id);229  __weak id var = test7_source();230  test7_helper(^{ test7_consume(var); });231 232  // CHECK-LABEL:    define{{.*}} void @test7()233  // CHECK:      [[VAR:%.*]] = alloca ptr,234  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],235  // CHECK:      [[T1:%.*]] = call ptr @test7_source() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]236  // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T1]])237  // CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr [[VAR]], ptr [[T1]])238  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]])239  // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT240  // CHECK:      store i32 -1040187392,241  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5242  // CHECK-NEXT: call void @llvm.objc.copyWeak(ptr [[SLOT]], ptr [[VAR]])243  // CHECK:      call void @test7_helper(244  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr {{%.*}})245  // CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[VAR]])246  // CHECK: ret void247 248  // CHECK-LABEL:    define internal void @__test7_block_invoke249  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr {{%.*}}, i32 0, i32 5250  // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.loadWeakRetained(ptr [[SLOT]])251  // CHECK-NEXT: call void @test7_consume(ptr noundef [[T0]])252  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])253  // CHECK: ret void254 255  // CHECK-LABEL:    define linkonce_odr hidden void @__copy_helper_block_8_32w(ptr noundef %0, ptr noundef %1) unnamed_addr #{{[0-9]+}} {256  // CHECK:      getelementptr257  // CHECK-NEXT: getelementptr258  // CHECK-NEXT: call void @llvm.objc.copyWeak(259 260  // CHECK-LABEL:    define linkonce_odr hidden void @__destroy_helper_block_8_32w(ptr noundef %0) unnamed_addr #{{[0-9]+}} {261  // CHECK:      getelementptr262  // CHECK-NEXT: call void @llvm.objc.destroyWeak(263}264 265@interface Test8 @end266@implementation Test8267- (void) test {268// CHECK:    define internal void @"\01-[Test8 test]"269// CHECK:      [[SELF:%.*]] = alloca ptr,270// CHECK-NEXT: alloca ptr271// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],272// CHECK: store273// CHECK-NEXT: store274// CHECK:      [[T0:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5275// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]],276// CHECK-NEXT: store ptr [[T1]], ptr [[T0]]277// CHECK: call void @test8_helper(278// CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T0]]279// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[T2]])280// CHECK: ret void281 282  extern void test8_helper(void (^)(void));283  test8_helper(^{ (void) self; });284}285@end286 287id test9(void) {288  typedef id __attribute__((ns_returns_retained)) blocktype(void);289  extern void test9_consume_block(blocktype^);290  return ^blocktype {291      extern id test9_produce(void);292      return test9_produce();293  }();294 295// CHECK-LABEL:    define{{.*}} ptr @test9(296// CHECK:      load ptr, ptr getelementptr297// CHECK-NEXT: call ptr298// CHECK-NEXT: tail call ptr @llvm.objc.autoreleaseReturnValue299// CHECK-NEXT: ret ptr300 301// CHECK:      call ptr @test9_produce() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]302// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(303// CHECK-NEXT: ret ptr304}305 306// Test that we correctly initialize __block variables307// when the initialization captures the variable.308void test10a(void) {309  __block void (^block)(void) = ^{ block(); };310  // CHECK-LABEL:       define{{.*}} void @test10a()311  // CHECK:             [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],312  // CHECK-NOHEAP:      [[BLOCK1:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8313 314  // Zero-initialization before running the initializer.315  // CHECK:             [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6316  // CHECK-NEXT:        store ptr null, ptr [[T0]], align 8317 318  // Run the initializer as an assignment.319  // CHECK-HEAP:   [[T1:%.*]] = call ptr @llvm.objc.retainBlock(ptr {{%.*}})320  // CHECK:        [[T3:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1321  // CHECK-NEXT:        [[T4:%.*]] = load ptr, ptr [[T3]]322  // CHECK-NEXT:        [[T5:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[T4]], i32 0, i32 6323  // CHECK-NEXT:        [[T6:%.*]] = load ptr, ptr [[T5]], align 8324  // CHECK-HEAP-NEXT:   store ptr {{%.*}}, ptr [[T5]], align 8325  // CHECK-NOHEAP-NEXT: store ptr [[BLOCK1]], ptr [[T5]], align 8326  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T6]])327 328  // Destroy at end of function.329  // CHECK-NEXT:        [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6330  // CHECK-NEXT:        call void @_Block_object_dispose(ptr [[BYREF]], i32 8)331  // CHECK-NEXT:        [[T1:%.*]] = load ptr, ptr [[SLOT]]332  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T1]])333  // CHECK: ret void334}335 336// do this copy and dispose with objc_retainBlock/release instead of337// _Block_object_assign/destroy. We can also use _Block_object_assign/destroy338// with BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER.339 340// CHECK-LABEL: define internal void @__Block_byref_object_copy_.{{[0-9]+}}(ptr noundef %0, ptr noundef %1) #{{[0-9]+}} {341// CHECK:      [[D0:%.*]] = load ptr, ptr {{%.*}}342// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[D0]], i32 0, i32 6343// CHECK-NEXT: [[S0:%.*]] = load ptr, ptr {{%.*}}344// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[S0]], i32 0, i32 6345// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[S2]], align 8346// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[T0]])347// CHECK-NEXT: store ptr [[T2]], ptr [[D2]], align 8348// CHECK: ret void349 350// CHECK-LABEL: define internal void @__Block_byref_object_dispose_.{{[0-9]+}}(ptr noundef %0) #{{[0-9]+}} {351// CHECK:      [[T0:%.*]] = load ptr, ptr {{%.*}}352// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[T0]], i32 0, i32 6353// CHECK-NEXT: [[T3:%.*]] = load ptr, ptr [[T2]]354// CHECK-NEXT: call void @llvm.objc.release(ptr [[T3]])355// CHECK-NEXT: ret void356 357// Test that we correctly assign to __block variables when the358// assignment captures the variable.359void test10b(void) {360  __block void (^block)(void);361  block = ^{ block(); };362 363  // CHECK-LABEL:       define{{.*}} void @test10b()364  // CHECK:             [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],365  // CHECK-NOHEAP:      [[BLOCK3:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8366 367  // Zero-initialize.368  // CHECK:             [[T0:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6369  // CHECK-NEXT:        store ptr null, ptr [[T0]], align 8370 371  // CHECK-NEXT:        [[SLOT:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 6372 373  // The assignment.374  // CHECK-HEAP:   [[T1:%.*]] = call ptr @llvm.objc.retainBlock(ptr {{%.*}})375  // CHECK:        [[T3:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 1376  // CHECK-NEXT:        [[T4:%.*]] = load ptr, ptr [[T3]]377  // CHECK-NEXT:        [[T5:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[T4]], i32 0, i32 6378  // CHECK-NEXT:        [[T6:%.*]] = load ptr, ptr [[T5]], align 8379  // CHECK-HEAP-NEXT:   store ptr {{%.*}}, ptr [[T5]], align 8380  // CHECK-NOHEAP-NEXT: store ptr [[BLOCK3]], ptr [[T5]], align 8381  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T6]])382 383  // Destroy at end of function.384  // CHECK-NEXT:        call void @_Block_object_dispose(ptr [[BYREF]], i32 8)385  // CHECK-NEXT:        [[T1:%.*]] = load ptr, ptr [[SLOT]]386  // CHECK-NEXT:        call void @llvm.objc.release(ptr [[T1]])387  // CHECK: ret void388}389 390void test11_helper(id);391void test11a(void) {392  int x;393  test11_helper(^{ (void) x; });394 395  // CHECK-LABEL:    define{{.*}} void @test11a()396  // CHECK:      [[X:%.*]] = alloca i32, align 4397  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8398  // CHECK: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]])399  // CHECK-NEXT: call void @test11_helper(ptr noundef [[T2]])400  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T2]])401  // CHECK: ret void402}403void test11b(void) {404  int x;405  id b = ^{ (void) x; };406 407  // CHECK-LABEL:    define{{.*}} void @test11b()408  // CHECK:      [[X:%.*]] = alloca i32, align 4409  // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8410  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8411  // CHECK: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]])412  // CHECK-NEXT: store ptr [[T2]], ptr [[B]], align 8413  // CHECK-NEXT: [[T5:%.*]] = load ptr, ptr [[B]]414  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T5]])415  // CHECK: ret void416}417 418@interface Test12419@property (strong) void(^ablock)(void);420@property (nonatomic, strong) void(^nblock)(void);421@end422@implementation Test12423@synthesize ablock, nblock;424// CHECK:    define internal ptr @"\01-[Test12 ablock]"(425// CHECK:    call ptr @objc_getProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef 0, i1 noundef zeroext true)426 427// CHECK:    define internal void @"\01-[Test12 setAblock:]"(428// CHECK:    call void @objc_setProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef 0, ptr noundef {{%.*}}, i1 noundef zeroext true, i1 noundef zeroext true)429 430// CHECK:    define internal ptr @"\01-[Test12 nblock]"(431// CHECK:    %add.ptr = getelementptr inbounds i8, ptr %0, i64 8432 433// CHECK:    define internal void @"\01-[Test12 setNblock:]"(434// CHECK:    call void @objc_setProperty(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef 8, ptr noundef {{%.*}}, i1 noundef zeroext false, i1 noundef zeroext true)435@end436 437void test13(id x) {438  extern void test13_helper(id);439  extern void test13_use(void(^)(void));440 441  void (^b)(void) = (x ? ^{test13_helper(x);} : 0);442  test13_use(b);443 444  // CHECK-LABEL:    define{{.*}} void @test13(445  // CHECK:      [[X:%.*]] = alloca ptr, align 8446  // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8447  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8448  // CHECK-NEXT: [[COND_CLEANUP_SAVE:%.*]] = alloca ptr,449  // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1450  // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}})451  // CHECK-NEXT: store ptr [[T0]], ptr [[X]], align 8452  // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B]])453  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]], align 8454  // CHECK-NEXT: [[T1:%.*]] = icmp ne ptr [[T0]], null455  // CHECK-NEXT: store i1 false, ptr [[CLEANUP_ACTIVE]]456  // CHECK-NEXT: br i1 [[T1]],457 458  // CHECK-NOT:  br459  // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5460  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]], align 8461  // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])462  // CHECK-NEXT: store ptr [[T1]], ptr [[CAPTURE]], align 8463  // CHECK-NEXT: store ptr [[CAPTURE]], ptr [[COND_CLEANUP_SAVE]], align 8464  // CHECK-NEXT: store i1 true, ptr [[CLEANUP_ACTIVE]]465  // CHECK-NEXT: br label466  // CHECK:      br label467  // CHECK:      [[T0:%.*]] = phi ptr468  // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[T0]])469  // CHECK-NEXT: store ptr [[T2]], ptr [[B]], align 8470  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]], align 8471  // CHECK-NEXT: call void @test13_use(ptr noundef [[T0]])472  // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]]473  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])474 475  // CHECK-NEXT: [[T0:%.*]] = load i1, ptr [[CLEANUP_ACTIVE]]476  // CHECK-NEXT: br i1 [[T0]]477  // CHECK:      [[V12:%.*]] = load ptr, ptr [[COND_CLEANUP_SAVE]], align 8478  // CHECK:      [[T0:%.*]] = load ptr, ptr [[V12]]479  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])480  // CHECK-NEXT: br label481 482  // CHECK: call void @llvm.lifetime.end.p0(ptr [[B]])483  // CHECK-NEXT:      [[T0:%.*]] = load ptr, ptr [[X]]484  // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])485  // CHECK-NEXT: ret void486}487 488void test14(void) {489  void (^const x[1])(void) = { ^{} };490}491 492// Don't make invalid ASTs and crash.493void test15_helper(void (^block)(void), int x);494void test15(int a) {495  test15_helper(^{ (void) a; }, ({ a; }));496}497 498void test16(void) {499  void (^BLKVAR)(void) = ^{ BLKVAR(); };500 501  // CHECK-LABEL: define{{.*}} void @test16(502  // CHECK: [[BLKVAR:%.*]]  = alloca ptr, align 8503  // CHECK-NEXT:  [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],504  // CHECK-NEXT:  call void @llvm.lifetime.start.p0(ptr [[BLKVAR]])505  // CHECK-NEXT:  store ptr null, ptr [[BLKVAR]], align 8506}507 508// This is an intentional exception to our conservative jump-scope509// checking for full-expressions containing block literals with510// non-trivial cleanups: if the block literal appears in the operand511// of a return statement, there's no need to extend its lifetime.512id (^test17(id self, int which))(void) {513  switch (which) {514  case 1: return ^{ return self; };515  case 0: return ^{ return self; };516  }517  return (void*) 0;518}519// CHECK-LABEL:    define{{.*}} ptr @test17(520// CHECK:      [[RET:%.*]] = alloca ptr, align521// CHECK-NEXT: [[SELF:%.*]] = alloca ptr,522// CHECK:      [[B0:%.*]] = alloca [[BLOCK:<.*>]], align523// CHECK:      [[B1:%.*]] = alloca [[BLOCK]], align524// CHECK:      [[T0:%.*]] = call ptr @llvm.objc.retain(ptr525// CHECK-NEXT: store ptr [[T0]], ptr [[SELF]], align526// CHECK-NOT:  objc_retain527// CHECK-NOT:  objc_release528// CHECK:      [[CAPTURED:%.*]] = getelementptr inbounds nuw [[BLOCK]], ptr [[B0]], i32 0, i32 5529// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]], align530// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]])531// CHECK-NEXT: store ptr [[T2]], ptr [[CAPTURED]],532// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[B0]])533// CHECK-NEXT: store ptr [[T2]], ptr [[RET]]534// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[CAPTURED]]535// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])536// CHECK-NEXT: store i32537// CHECK-NEXT: br label538// CHECK-NOT:  objc_retain539// CHECK-NOT:  objc_release540// CHECK:      [[CAPTURED:%.*]] = getelementptr inbounds nuw [[BLOCK]], ptr [[B1]], i32 0, i32 5541// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[SELF]], align542// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T1]])543// CHECK-NEXT: store ptr [[T2]], ptr [[CAPTURED]],544// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[B1]])545// CHECK-NEXT: store ptr [[T2]], ptr [[RET]]546// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[CAPTURED]]547// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])548// CHECK-NEXT: store i32549// CHECK-NEXT: br label550 551void test18(id x) {552// CHECK-UNOPT-LABEL:    define{{.*}} void @test18(553// CHECK-UNOPT:      [[X:%.*]] = alloca ptr,554// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],555// CHECK-UNOPT-NEXT: store ptr null, ptr [[X]]556// CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(ptr [[X]], 557// CHECK-UNOPT: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 4558// CHECK-UNOPT: store ptr @[[BLOCK_DESCRIPTOR_TMP44]], ptr %[[BLOCK_DESCRIPTOR]], align 8559// CHECK-UNOPT:      [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5560// CHECK-UNOPT-NEXT: [[T0:%.*]] = load ptr, ptr [[X]],561// CHECK-UNOPT-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])562// CHECK-UNOPT-NEXT: store ptr [[T1]], ptr [[SLOT]],563// CHECK-UNOPT-NEXT: call void @test18_helper(564// CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(ptr [[SLOT]], ptr null) [[NUW:#[0-9]+]]565// CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(ptr [[X]], ptr null) [[NUW]]566// CHECK-UNOPT-NEXT: ret void567  extern void test18_helper(id (^)(void));568  test18_helper(^{ return x; });569}570 571// Ensure that we don't emit helper code in copy/dispose routines for variables572// that are const-captured.573void testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(id x, id y) {574  id __unsafe_unretained unsafeObject = x;575  (^ { testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(x, unsafeObject); })();576}577 578// CHECK-LABEL: define{{.*}} void @testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers579// %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4580// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP46]], ptr %[[BLOCK_DESCRIPTOR]], align 8581 582// CHECK-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke583// CHECK-UNOPT-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke584 585void test19_sink(void (^)(int));586void test19(void (^b)(void)) {587// CHECK-LABEL:    define{{.*}} void @test19(588//   Prologue.589// CHECK:      [[B:%.*]] = alloca ptr,590// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],591// CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}})592// CHECK-NEXT: store ptr [[T1]], ptr [[B]]593 594//   Block setup.  We skip most of this.  Note the bare retain.595// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 4596// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP48]], ptr %[[BLOCK_DESCRIPTOR]], align 8597// CHECK:      [[SLOT:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5598// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]],599// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retain(ptr [[T0]])600// CHECK-NEXT: store ptr [[T2]], ptr [[SLOT]],601//   Call.602// CHECK-NEXT: call void @test19_sink(ptr noundef [[BLOCK]])603 604  test19_sink(^(int x) { b(); });605 606//   Block teardown.607// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]]608// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])609 610//   Local cleanup.611// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[B]]612// CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]])613 614// CHECK-NEXT: ret void615}616 617// CHECK-LABEL: define{{.*}} void @test20(618// CHECK: [[XADDR:%.*]] = alloca ptr619// CHECK-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]>620// CHECK-NEXT: [[RETAINEDX:%.*]] = call ptr @llvm.objc.retain(ptr %{{.*}})621// CHECK-NEXT: store ptr [[RETAINEDX]], ptr [[XADDR]]622// CHECK: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds nuw <[[BLOCKTY]]>, ptr [[BLOCK]], i32 0, i32 5623// CHECK: [[CAPTURED:%.*]] = load ptr, ptr [[XADDR]]624// CHECK: store ptr [[CAPTURED]], ptr [[BLOCKCAPTURED]]625// CHECK: [[CAPTURE:%.*]] = load ptr, ptr [[BLOCKCAPTURED]]626// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[CAPTURE]])627// CHECK-NEXT: [[X:%.*]] = load ptr, ptr [[XADDR]]628// CHECK-NEXT: call void @llvm.objc.release(ptr [[X]])629// CHECK-NEXT: ret void630 631// CHECK-UNOPT-LABEL: define{{.*}} void @test20(632// CHECK-UNOPT: [[XADDR:%.*]] = alloca ptr633// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]>634// CHECK-UNOPT: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds nuw <[[BLOCKTY]]>, ptr [[BLOCK]], i32 0, i32 5635// CHECK-UNOPT: [[CAPTURED:%.*]] = load ptr, ptr [[XADDR]]636// CHECK-UNOPT: [[RETAINED:%.*]] = call ptr @llvm.objc.retain(ptr [[CAPTURED]])637// CHECK-UNOPT: store ptr [[RETAINED]], ptr [[BLOCKCAPTURED]]638// CHECK-UNOPT: call void @llvm.objc.storeStrong(ptr [[BLOCKCAPTURED]], ptr null)639 640void test20_callee(void (^)(void));641void test20(const id x) {642  test20_callee(^{ (void)x; });643}644 645// CHECK-LABEL: define{{.*}} void @test21(646// CHECK: %[[V6:.*]] = call ptr @llvm.objc.retainBlock(647// CHECK: call void (i32, ...) @test21_callee(i32 noundef 1, ptr noundef %[[V6]]),648 649void test21_callee(int n, ...);650void test21(id x) {651  test21_callee(1, ^{ (void)x; });652}653 654// The lifetime of 'x', which is captured by the block in the statement655// expression, should be extended.656 657// CHECK-COMMON-LABEL: define{{.*}} ptr @test22(658// CHECK-COMMON: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 5659// CHECK-COMMON: %[[V3:.*]] = call ptr @llvm.objc.retain(ptr %{{.*}})660// CHECK-COMMON: store ptr %[[V3]], ptr %[[BLOCK_CAPTURED]], align 8661// CHECK-COMMON: call void @test22_1()662// CHECK-UNOPT: call void @llvm.objc.storeStrong(ptr %[[BLOCK_CAPTURED]], ptr null)663// CHECK: %[[V15:.*]] = load ptr, ptr %[[BLOCK_CAPTURED]], align 8664// CHECK: call void @llvm.objc.release(ptr %[[V15]])665 666id test22(int c, id x) {667  extern id test22_0(void);668  extern void test22_1(void);669  return c ? test22_0() : ({ id (^b)(void) = ^{ return x; }; test22_1(); b(); });670}671 672@interface Test23673-(void)m:(int)i, ...;674@end675 676// CHECK-COMMON-LABEL: define{{.*}} void @test23(677// CHECK-COMMON: %[[V9:.*]] = call ptr @llvm.objc.retainBlock(678// CHECK-COMMON: call void (ptr, ptr, i32, ...) @objc_msgSend(ptr noundef %{{.*}}, ptr noundef %{{.*}}, i32 noundef 123, ptr noundef %[[V9]])679 680void test23(id x, Test23 *t) {681  [t m:123, ^{ (void)x; }];682}683 684// CHECK-COMMON-LABEL: define internal void @"\01+[Test24 m]"(685// CHECK-COMMON: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr %{{.*}}, i32 0, i32 4686// CHECK: store ptr @[[BLOCK_DESCRIPTOR_TMP10]], ptr %[[BLOCK_DESCRIPTOR]],687 688@interface Test24689@property (class) void (^block)(void);690+(void)m;691@end692 693@implementation Test24694+(void)m {695  self.block = ^{ (void)self; };696}697@end698 699// CHECK: attributes [[NUW]] = { nounwind }700// CHECK-UNOPT: attributes [[NUW]] = { nounwind }701