Don't actually add the __unsafe_unretained qualifier in MRC;
driving a canonical difference between that and an unqualified
type is a really bad idea when both are valid. Instead, remember
that it was there in a non-canonical way, then look for that in
the one place we really care about it: block captures. The net
effect closely resembles the behavior of a decl attribute, except
still closely following ARC's standard qualifier parsing rules.
llvm-svn: 253534
diff --git a/clang/test/CodeGenObjC/mrc-weak.m b/clang/test/CodeGenObjC/mrc-weak.m
index 9072b1a..e2c78f0 100644
--- a/clang/test/CodeGenObjC/mrc-weak.m
+++ b/clang/test/CodeGenObjC/mrc-weak.m
@@ -160,3 +160,32 @@
// CHECK-LABEL: define internal void @__Block_byref_object_dispose
// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define void @test9_baseline()
+// CHECK: define internal void @__copy_helper
+// CHECK: define internal void @__destroy_helper
+void test9_baseline(void) {
+ Foo *p = get_object();
+ use_block(^{ [p run]; });
+}
+
+// CHECK-LABEL: define void @test9()
+// CHECK-NOT: define internal void @__copy_helper
+// CHECK-NOT: define internal void @__destroy_helper
+// CHECK: define void @test9_fin()
+void test9(void) {
+ __unsafe_unretained Foo *p = get_object();
+ use_block(^{ [p run]; });
+}
+void test9_fin() {}
+
+// CHECK-LABEL: define void @test10()
+// CHECK-NOT: define internal void @__copy_helper
+// CHECK-NOT: define internal void @__destroy_helper
+// CHECK: define void @test10_fin()
+void test10(void) {
+ typedef __unsafe_unretained Foo *UnsafeFooPtr;
+ UnsafeFooPtr p = get_object();
+ use_block(^{ [p run]; });
+}
+void test10_fin() {}
diff --git a/clang/test/CodeGenObjCXX/mrc-weak.mm b/clang/test/CodeGenObjCXX/mrc-weak.mm
new file mode 100644
index 0000000..17ceb31
--- /dev/null
+++ b/clang/test/CodeGenObjCXX/mrc-weak.mm
@@ -0,0 +1,183 @@
+// 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: @"\01l_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 @objc_destroyWeak
+@end
+
+
+void test1(__weak id x) {}
+// CHECK-LABEL: define void @_Z5test1P11objc_object(
+// CHECK: [[X:%.*]] = alloca i8*,
+// CHECK-NEXT: objc_initWeak
+// CHECK-NEXT: objc_destroyWeak
+// CHECK-NEXT: ret void
+
+void test2(id y) {
+ __weak id z = y;
+}
+// CHECK-LABEL: define void @_Z5test2P11objc_object(
+// CHECK: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: [[Z:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[Z]], i8* [[T0]])
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[Z]])
+// CHECK-NEXT: ret void
+
+void test3(id y) {
+ __weak id z;
+ z = y;
+}
+// CHECK-LABEL: define void @_Z5test3P11objc_object(
+// CHECK: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: [[Z:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: store i8* null, i8** [[Z]]
+// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-NEXT: call i8* @objc_storeWeak(i8** [[Z]], i8* [[T0]])
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[Z]])
+// CHECK-NEXT: ret void
+
+void test4(__weak id *p) {
+ id y = *p;
+}
+// CHECK-LABEL: define void @_Z5test4PU6__weakP11objc_object(
+// CHECK: [[P:%.*]] = alloca i8**,
+// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]]
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
+// CHECK-NEXT: ret void
+
+void test5(__weak id *p) {
+ id y = [*p retain];
+}
+// CHECK-LABEL: define void @_Z5test5PU6__weakP11objc_object
+// CHECK: [[P:%.*]] = alloca i8**,
+// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]]
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
+// CHECK-NEXT: ret void
+
+void test6(__weak Foo **p) {
+ Foo *y = [*p retain];
+}
+// CHECK-LABEL: define void @_Z5test6PU6__weakP3Foo
+// CHECK: [[P:%.*]] = alloca [[FOO:%.*]]**,
+// CHECK-NEXT: [[Y:%.*]] = alloca [[FOO]]*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load [[FOO]]**, [[FOO]]*** [[P]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[FOO]]** [[T0]] to i8**
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[FOO]]*
+// CHECK-NEXT: store [[FOO]]* [[T3]], [[FOO]]** [[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 [[FOO]]*,
+// CHECK: [[T0:%.*]] = call i8* @get_object()
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[FOO]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[FOO]]** [[P]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[FOO]]* [[T1]] to i8*
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]])
+// CHECK: call void @objc_copyWeak
+// CHECK: call void @use_block
+// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK: @objc_copyWeak
+
+// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK: @objc_destroyWeak
+
+void test8(void) {
+ __block __weak Foo *p = get_object();
+ use_block(^{ [p run ]; });
+}
+// CHECK-LABEL: define void @_Z5test8v
+// CHECK: call i8* @objc_initWeak
+// CHECK-NOT: call void @objc_copyWeak
+// CHECK: call void @use_block
+// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define internal void @__Block_byref_object_copy
+// CHECK: call void @objc_moveWeak
+
+// CHECK-LABEL: define internal void @__Block_byref_object_dispose
+// CHECK: call void @objc_destroyWeak
+
+// CHECK-LABEL: define void @_Z14test9_baselinev()
+// CHECK: define internal void @__copy_helper
+// CHECK: define internal 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() {}
diff --git a/clang/test/SemaObjC/mrc-weak.m b/clang/test/SemaObjC/mrc-weak.m
index ec03cf7..e961e0a 100644
--- a/clang/test/SemaObjC/mrc-weak.m
+++ b/clang/test/SemaObjC/mrc-weak.m
@@ -12,7 +12,7 @@
@property (unsafe_unretained) id ud;
@property (strong) id sa;
@property (strong) id sb; // expected-note {{property declared here}}
-@property (strong) id sc; // expected-note {{property declared here}}
+@property (strong) id sc;
@property (strong) id sd;
@end
@@ -25,7 +25,7 @@
__unsafe_unretained id _uc;
id _sa;
__weak id _sb; // expected-error {{existing instance variable '_sb' for strong property 'sb' may not be __weak}}
- __unsafe_unretained id _sc; // expected-error {{existing instance variable '_sc' for strong property 'sc' may not be __unsafe_unretained}}
+ __unsafe_unretained id _sc;
}
@synthesize wa = _wa; // expected-note {{property synthesized here}}
@synthesize wb = _wb;
@@ -37,7 +37,7 @@
@synthesize ud = _ud;
@synthesize sa = _sa;
@synthesize sb = _sb; // expected-note {{property synthesized here}}
-@synthesize sc = _sc; // expected-note {{property synthesized here}}
+@synthesize sc = _sc;
@synthesize sd = _sd;
@end
@@ -62,6 +62,6 @@
void test_cast_qualifier_inference(__weak id *value) {
__weak id *a = (id*) value;
- __unsafe_unretained id *b = (id*) value; // expected-error {{initializing '__unsafe_unretained id *' with an expression of type '__weak id *' changes retain/release properties of pointer}}
+ __unsafe_unretained id *b = (id*) value; // expected-error {{initializing 'id *' with an expression of type '__weak id *' changes retain/release properties of pointer}}
}