// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-MODERN
// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-FRAGILE
@interface Object
- (instancetype) retain;
- (void) run;
@end
// CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00"
// CHECK-MODERN: @"_OBJC_CLASS_RO_$_Foo" = {{.*}} { i32 772
// 772 == 0x304
// ^ HasMRCWeakIvars
// ^ HasCXXDestructorOnly
// ^ HasCXXStructors
// CHECK-FRAGILE: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00"
// CHECK-FRAGILE: @OBJC_CLASS_Foo = {{.*}} i32 134225921,
// 134225921 == 0x08002001
// ^ HasMRCWeakIvars
// ^ HasCXXStructors
// ^ Factory
@interface Foo : Object {
__weak id ivar;
}
@end
@implementation Foo
// CHECK-LABEL: define internal void @"\01-[Foo .cxx_destruct]"
// CHECK: call void @llvm.objc.destroyWeak
@end
void test1(__weak id x) {}
// CHECK-LABEL: define{{.*}} void @_Z5test1P11objc_object(
// CHECK: [[X:%.*]] = alloca ptr,
// CHECK-NEXT: llvm.objc.initWeak
// CHECK-NEXT: llvm.objc.destroyWeak
// CHECK-NEXT: ret void
void test2(id y) {
__weak id z = y;
}
// CHECK-LABEL: define{{.*}} void @_Z5test2P11objc_object(
// CHECK: [[Y:%.*]] = alloca ptr,
// CHECK-NEXT: [[Z:%.*]] = alloca ptr,
// CHECK-NEXT: store
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[Y]]
// CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr [[Z]], ptr [[T0]])
// CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[Z]])
// CHECK-NEXT: ret void
void test3(id y) {
__weak id z;
z = y;
}
// CHECK-LABEL: define{{.*}} void @_Z5test3P11objc_object(
// CHECK: [[Y:%.*]] = alloca ptr,
// CHECK-NEXT: [[Z:%.*]] = alloca ptr,
// CHECK-NEXT: store
// CHECK-NEXT: store ptr null, ptr [[Z]]
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[Y]]
// CHECK-NEXT: call ptr @llvm.objc.storeWeak(ptr [[Z]], ptr [[T0]])
// CHECK-NEXT: call void @llvm.objc.destroyWeak(ptr [[Z]])
// CHECK-NEXT: ret void
void test4(__weak id *p) {
id y = *p;
}
// CHECK-LABEL: define{{.*}} void @_Z5test4PU6__weakP11objc_object(
// CHECK: [[P:%.*]] = alloca ptr,
// CHECK-NEXT: [[Y:%.*]] = alloca ptr,
// CHECK-NEXT: store
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[P]]
// CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.loadWeak(ptr [[T0]])
// CHECK-NEXT: store ptr [[T1]], ptr [[Y]]
// CHECK-NEXT: ret void
void test5(__weak id *p) {
id y = [*p retain];
}
// CHECK-LABEL: define{{.*}} void @_Z5test5PU6__weakP11objc_object
// CHECK: [[P:%.*]] = alloca ptr,
// CHECK-NEXT: [[Y:%.*]] = alloca ptr,
// CHECK-NEXT: store
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[P]]
// CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.loadWeakRetained(ptr [[T0]])
// CHECK-NEXT: store ptr [[T1]], ptr [[Y]]
// CHECK-NEXT: ret void
void test6(__weak Foo **p) {
Foo *y = [*p retain];
}
// CHECK-LABEL: define{{.*}} void @_Z5test6PU6__weakP3Foo
// CHECK: [[P:%.*]] = alloca ptr,
// CHECK-NEXT: [[Y:%.*]] = alloca ptr,
// CHECK-NEXT: store
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[P]]
// CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.loadWeakRetained(ptr [[T0]])
// CHECK-NEXT: store ptr [[T2]], ptr [[Y]]
// CHECK-NEXT: ret void
extern "C" id get_object(void);
extern "C" void use_block(void (^)(void));
void test7(void) {
__weak Foo *p = get_object();
use_block(^{ [p run ]; });
}
// CHECK-LABEL: define{{.*}} void @_Z5test7v
// CHECK: [[P:%.*]] = alloca ptr,
// CHECK: [[T0:%.*]] = call ptr @get_object()
// CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr [[P]], ptr [[T0]])
// CHECK: call void @llvm.objc.copyWeak
// CHECK: call void @use_block
// CHECK: call void @llvm.objc.destroyWeak
// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
// CHECK: @llvm.objc.copyWeak
// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
// CHECK: @llvm.objc.destroyWeak
void test8(void) {
__block __weak Foo *p = get_object();
use_block(^{ [p run ]; });
}
// CHECK-LABEL: define{{.*}} void @_Z5test8v
// CHECK: call ptr @llvm.objc.initWeak
// CHECK-NOT: call void @llvm.objc.copyWeak
// CHECK: call void @use_block
// CHECK: call void @llvm.objc.destroyWeak
// CHECK-LABEL: define internal void @__Block_byref_object_copy
// CHECK: call void @llvm.objc.moveWeak
// CHECK-LABEL: define internal void @__Block_byref_object_dispose
// CHECK: call void @llvm.objc.destroyWeak
// CHECK-LABEL: define{{.*}} void @_Z14test9_baselinev()
// CHECK: define linkonce_odr hidden void @__copy_helper
// CHECK: define linkonce_odr hidden void @__destroy_helper
void test9_baseline(void) {
Foo *p = get_object();
use_block(^{ [p run]; });
}
// CHECK-LABEL: define{{.*}} void @_Z5test9v()
// CHECK-NOT: define internal void @__copy_helper
// CHECK-NOT: define internal void @__destroy_helper
// CHECK: define{{.*}} void @_Z9test9_finv()
void test9(void) {
__unsafe_unretained Foo *p = get_object();
use_block(^{ [p run]; });
}
void test9_fin() {}
// CHECK-LABEL: define{{.*}} void @_Z6test10v()
// CHECK-NOT: define internal void @__copy_helper
// CHECK-NOT: define internal void @__destroy_helper
// CHECK: define{{.*}} void @_Z10test10_finv()
void test10(void) {
typedef __unsafe_unretained Foo *UnsafeFooPtr;
UnsafeFooPtr p = get_object();
use_block(^{ [p run]; });
}
void test10_fin() {}
// CHECK-LABEL: define weak_odr void @_Z6test11ILj0EEvv()
// CHECK-NOT: define internal void @__copy_helper
// CHECK-NOT: define internal void @__destroy_helper
// CHECK: define{{.*}} void @_Z10test11_finv()
template <unsigned i> void test11(void) {
typedef __unsafe_unretained Foo *UnsafeFooPtr;
UnsafeFooPtr p = get_object();
use_block(^{ [p run]; });
}
template void test11<0>();
void test11_fin() {}