// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -fobjc-arc -fblocks -Wno-objc-root-class -O0 %s -S -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -fobjc-arc -fblocks -Wno-objc-root-class -O0 -xobjective-c++ -std=c++11 %s -S -emit-llvm -o - | FileCheck %s --check-prefix CHECKXX #define EXT_RET __attribute__((objc_externally_retained)) @interface ObjTy @end ObjTy *global; #if __cplusplus // Suppress name mangling in C++ mode for the sake of check lines. extern "C" void param(ObjTy *p); extern "C" void local(); extern "C" void in_init(); extern "C" void anchor(); extern "C" void block_capture(ObjTy *); extern "C" void esc(void (^)()); extern "C" void escp(void (^)(ObjTy *)); extern "C" void block_param(); #endif void param(ObjTy *p) EXT_RET { // CHECK-LABEL: define{{.*}} void @param // CHECK-NOT: llvm.objc. // CHECK: ret } void local() { EXT_RET ObjTy *local = global; // CHECK-LABEL: define{{.*}} void @local // CHECK-NOT: llvm.objc. // CHECK: ret } void in_init() { // Test that we do the right thing when a variable appears in it's own // initializer. Here, we release the value stored in 'wat' after overwriting // it, in case it was somehow set to point to a non-null object while it's // initializer is being evaluated. EXT_RET ObjTy *wat = 0 ? wat : global; // CHECK-LABEL: define{{.*}} void @in_init // CHECK: [[WAT:%.*]] = alloca // CHECK-NEXT: store {{.*}} null, {{.*}} [[WAT]] // CHECK-NEXT: [[GLOBAL:%.*]] = load {{.*}} @global // CHECK-NEXT: [[WAT_LOAD:%.*]] = load {{.*}} [[WAT]] // CHECK-NEXT: store {{.*}} [[GLOBAL]], {{.*}} [[WAT]] // CHECK-NEXT: [[CASTED:%.*]] = bitcast {{.*}} [[WAT_LOAD]] to // CHECK-NEXT: call void @llvm.objc.release(i8* [[CASTED]]) // CHECK-NOT: llvm.objc. // CHECK: ret } void esc(void (^)()); void block_capture(ObjTy *obj) EXT_RET { esc(^{ (void)obj; }); // CHECK-LABEL: define{{.*}} void @block_capture // CHECK-NOT: llvm.objc. // CHECK: call i8* @llvm.objc.retain // CHECK-NOT: llvm.objc. // CHECK: call void @esc // CHECK-NOT: llvm.objc. // CHECK: call void @llvm.objc.storeStrong({{.*}} null) // CHECK-NOT: llvm.objc. // CHECK: ret // CHECK-LABEL: define {{.*}} void @__copy_helper_block_ // CHECK-NOT: llvm.objc. // CHECK: llvm.objc.storeStrong // CHECK-NOT: llvm.objc. // CHECK: ret // CHECK-LABEL: define {{.*}} void @__destroy_helper_block_ // CHECK-NOT: llvm.objc. // CHECK: llvm.objc.storeStrong({{.*}} null) // CHECK-NOT: llvm.objc. // CHECK: ret } void escp(void (^)(ObjTy *)); void block_param() { escp(^(ObjTy *p) EXT_RET {}); // CHECK-LABEL: define internal void @__block_param_block_invoke // CHECK-NOT: llvm.objc. // CHECK: ret } @interface Inter -(void)m1: (ObjTy *)w; @end @implementation Inter -(void)m1: (ObjTy *) w EXT_RET { // CHECK-LABEL: define internal void @"\01-[Inter m1:]" // CHECK-NOT: llvm.objc. // CHECK: ret } -(void)m2: (ObjTy *) w EXT_RET { // CHECK-LABEL: define internal void @"\01-[Inter m2:]" // CHECK-NOT: llvm.objc. // CHECK: ret } @end #if __cplusplus // Verify that the decltype(p) is resolved before 'p' is made implicitly const. __attribute__((objc_externally_retained)) void foo(ObjTy *p, decltype(p) *) {} // CHECKXX: _Z3fooP5ObjTyPU8__strongS0_ #endif