1f4a2713aSLionel Sambuc// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s 2f4a2713aSLionel Sambuc 3f4a2713aSLionel Sambucstruct NSFastEnumerationState; 4f4a2713aSLionel Sambuc@interface NSArray 5f4a2713aSLionel Sambuc- (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state 6f4a2713aSLionel Sambuc objects: (id*) buffer 7f4a2713aSLionel Sambuc count: (unsigned long) bufferSize; 8f4a2713aSLionel Sambuc@end; 9f4a2713aSLionel SambucNSArray *nsarray() { return 0; } 10f4a2713aSLionel Sambuc// CHECK: define [[NSARRAY:%.*]]* @_Z7nsarrayv() 11f4a2713aSLionel Sambuc 12f4a2713aSLionel Sambucvoid use(id); 13f4a2713aSLionel Sambuc 14f4a2713aSLionel Sambuc// rdar://problem/9315552 15f4a2713aSLionel Sambuc// The analogous ObjC testcase test46 in arr.m. 16f4a2713aSLionel Sambucvoid test0(__weak id *wp, __weak volatile id *wvp) { 17f4a2713aSLionel Sambuc extern id test0_helper(void); 18f4a2713aSLionel Sambuc 19f4a2713aSLionel Sambuc // TODO: this is sub-optimal, we should retain at the actual call site. 20f4a2713aSLionel Sambuc // TODO: in the non-volatile case, we do not need to be reloading. 21f4a2713aSLionel Sambuc 22f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = call i8* @_Z12test0_helperv() 23f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) 24f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8 25f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]]) 26f4a2713aSLionel Sambuc // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retain(i8* [[T3]]) 27f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T4]], i8** 28f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T1]]) 29f4a2713aSLionel Sambuc id x = *wp = test0_helper(); 30f4a2713aSLionel Sambuc 31f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = call i8* @_Z12test0_helperv() 32f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) 33f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = load i8*** {{%.*}}, align 8 34f4a2713aSLionel Sambuc // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]]) 35f4a2713aSLionel Sambuc // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T2]]) 36f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T4]], i8** 37f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T1]]) 38f4a2713aSLionel Sambuc id y = *wvp = test0_helper(); 39f4a2713aSLionel Sambuc} 40f4a2713aSLionel Sambuc 41f4a2713aSLionel Sambuc// rdar://problem/9320648 42f4a2713aSLionel Sambucstruct Test1_helper { Test1_helper(); }; 43f4a2713aSLionel Sambuc@interface Test1 @end 44f4a2713aSLionel Sambuc@implementation Test1 { Test1_helper x; } @end 45f4a2713aSLionel Sambuc// CHECK: define internal i8* @"\01-[Test1 .cxx_construct]"( 46f4a2713aSLionel Sambuc// CHECK: call void @_ZN12Test1_helperC1Ev( 47f4a2713aSLionel Sambuc// CHECK-NEXT: load 48f4a2713aSLionel Sambuc// CHECK-NEXT: bitcast 49f4a2713aSLionel Sambuc// CHECK-NEXT: ret i8* 50f4a2713aSLionel Sambuc 51f4a2713aSLionel Sambucvoid test34(int cond) { 52f4a2713aSLionel Sambuc __strong id strong; 53f4a2713aSLionel Sambuc __weak id weak; 54f4a2713aSLionel Sambuc extern void test34_sink(id *); 55f4a2713aSLionel Sambuc test34_sink(cond ? &strong : 0); 56f4a2713aSLionel Sambuc test34_sink(cond ? &weak : 0); 57f4a2713aSLionel Sambuc 58f4a2713aSLionel Sambuc // CHECK-LABEL: define void @_Z6test34i( 59f4a2713aSLionel Sambuc // CHECK: [[COND:%.*]] = alloca i32 60f4a2713aSLionel Sambuc // CHECK-NEXT: [[STRONG:%.*]] = alloca i8* 61f4a2713aSLionel Sambuc // CHECK-NEXT: [[WEAK:%.*]] = alloca i8* 62f4a2713aSLionel Sambuc // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8* 63f4a2713aSLionel Sambuc // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8* 64f4a2713aSLionel Sambuc // CHECK-NEXT: [[CONDCLEANUPSAVE:%.*]] = alloca i8* 65f4a2713aSLionel Sambuc // CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i1 66f4a2713aSLionel Sambuc // CHECK-NEXT: store i32 67f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* null, i8** [[STRONG]] 68f4a2713aSLionel Sambuc // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null) 69f4a2713aSLionel Sambuc 70f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]] 71f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0 72f4a2713aSLionel Sambuc // CHECK: [[ARG:%.*]] = phi i8** 73f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 74f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]] 75f4a2713aSLionel Sambuc // CHECK-NEXT: br i1 [[T0]], 76f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = load i8** [[ARG]] 77f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]] 78f4a2713aSLionel Sambuc // CHECK-NEXT: br label 79f4a2713aSLionel Sambuc // CHECK: [[W0:%.*]] = phi i8* [ [[T0]], {{%.*}} ], [ undef, {{%.*}} ] 80f4a2713aSLionel Sambuc // CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]]) 81f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 82f4a2713aSLionel Sambuc // CHECK-NEXT: br i1 [[T0]], 83f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = load i8** [[TEMP1]] 84f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) 85f4a2713aSLionel Sambuc // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W0]]) 86f4a2713aSLionel Sambuc // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]] 87f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]] 88f4a2713aSLionel Sambuc // CHECK-NEXT: call void @objc_release(i8* [[T2]]) 89f4a2713aSLionel Sambuc // CHECK-NEXT: br label 90f4a2713aSLionel Sambuc 91f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = load i32* [[COND]] 92f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0 93f4a2713aSLionel Sambuc // CHECK: [[ARG:%.*]] = phi i8** 94f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 95f4a2713aSLionel Sambuc // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]] 96f4a2713aSLionel Sambuc // CHECK-NEXT: store i1 false, i1* [[CONDCLEANUP]] 97f4a2713aSLionel Sambuc // CHECK-NEXT: br i1 [[T0]], 98f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[ARG]]) 99f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T0]], i8** [[CONDCLEANUPSAVE]] 100f4a2713aSLionel Sambuc // CHECK-NEXT: store i1 true, i1* [[CONDCLEANUP]] 101f4a2713aSLionel Sambuc // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]] 102f4a2713aSLionel Sambuc // CHECK-NEXT: br label 103f4a2713aSLionel Sambuc // CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]]) 104f4a2713aSLionel Sambuc // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null 105f4a2713aSLionel Sambuc // CHECK-NEXT: br i1 [[T0]], 106f4a2713aSLionel Sambuc // CHECK: [[T0:%.*]] = load i8** [[TEMP2]] 107f4a2713aSLionel Sambuc // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]]) 108f4a2713aSLionel Sambuc // CHECK-NEXT: br label 109f4a2713aSLionel Sambuc 110f4a2713aSLionel Sambuc // CHECK: call void @objc_destroyWeak(i8** [[WEAK]]) 111f4a2713aSLionel Sambuc // CHECK: ret void 112f4a2713aSLionel Sambuc} 113f4a2713aSLionel Sambuc 114f4a2713aSLionel Sambucstruct Test35_Helper { 115f4a2713aSLionel Sambuc static id makeObject1() __attribute__((ns_returns_retained)); 116f4a2713aSLionel Sambuc id makeObject2() __attribute__((ns_returns_retained)); 117f4a2713aSLionel Sambuc static id makeObject3(); 118f4a2713aSLionel Sambuc id makeObject4(); 119f4a2713aSLionel Sambuc}; 120f4a2713aSLionel Sambuc 121f4a2713aSLionel Sambuc// CHECK-LABEL: define void @_Z6test3513Test35_HelperPS_ 122f4a2713aSLionel Sambucvoid test35(Test35_Helper x0, Test35_Helper *x0p) { 123f4a2713aSLionel Sambuc // CHECK: call i8* @_ZN13Test35_Helper11makeObject1Ev 124f4a2713aSLionel Sambuc // CHECK-NOT: call i8* @objc_retain 125f4a2713aSLionel Sambuc id obj1 = Test35_Helper::makeObject1(); 126f4a2713aSLionel Sambuc // CHECK: call i8* @_ZN13Test35_Helper11makeObject2Ev 127f4a2713aSLionel Sambuc // CHECK-NOT: call i8* @objc_retain 128f4a2713aSLionel Sambuc id obj2 = x0.makeObject2(); 129f4a2713aSLionel Sambuc // CHECK: call i8* @_ZN13Test35_Helper11makeObject2Ev 130f4a2713aSLionel Sambuc // CHECK-NOT: call i8* @objc_retain 131f4a2713aSLionel Sambuc id obj3 = x0p->makeObject2(); 132f4a2713aSLionel Sambuc id (Test35_Helper::*pmf)() __attribute__((ns_returns_retained)) 133f4a2713aSLionel Sambuc = &Test35_Helper::makeObject2; 134f4a2713aSLionel Sambuc // CHECK: call i8* % 135f4a2713aSLionel Sambuc // CHECK-NOT: call i8* @objc_retain 136f4a2713aSLionel Sambuc id obj4 = (x0.*pmf)(); 137f4a2713aSLionel Sambuc // CHECK: call i8* % 138f4a2713aSLionel Sambuc // CHECK-NOT: call i8* @objc_retain 139f4a2713aSLionel Sambuc id obj5 = (x0p->*pmf)(); 140f4a2713aSLionel Sambuc 141f4a2713aSLionel Sambuc // CHECK: call void @objc_release 142f4a2713aSLionel Sambuc // CHECK: call void @objc_release 143f4a2713aSLionel Sambuc // CHECK: call void @objc_release 144f4a2713aSLionel Sambuc // CHECK: call void @objc_release 145f4a2713aSLionel Sambuc // CHECK: call void @objc_release 146f4a2713aSLionel Sambuc // CHECK-NEXT: ret void 147f4a2713aSLionel Sambuc} 148f4a2713aSLionel Sambuc 149f4a2713aSLionel Sambuc// CHECK-LABEL: define void @_Z7test35b13Test35_HelperPS_ 150f4a2713aSLionel Sambucvoid test35b(Test35_Helper x0, Test35_Helper *x0p) { 151f4a2713aSLionel Sambuc // CHECK: call i8* @_ZN13Test35_Helper11makeObject3Ev 152f4a2713aSLionel Sambuc // CHECK: call i8* @objc_retain 153f4a2713aSLionel Sambuc id obj1 = Test35_Helper::makeObject3(); 154f4a2713aSLionel Sambuc // CHECK: call i8* @_ZN13Test35_Helper11makeObject4Ev 155f4a2713aSLionel Sambuc // CHECK: call i8* @objc_retain 156f4a2713aSLionel Sambuc id obj2 = x0.makeObject4(); 157f4a2713aSLionel Sambuc // CHECK: call i8* @_ZN13Test35_Helper11makeObject4Ev 158f4a2713aSLionel Sambuc // CHECK: call i8* @objc_retain 159f4a2713aSLionel Sambuc id obj3 = x0p->makeObject4(); 160f4a2713aSLionel Sambuc id (Test35_Helper::*pmf)() = &Test35_Helper::makeObject4; 161f4a2713aSLionel Sambuc // CHECK: call i8* % 162f4a2713aSLionel Sambuc // CHECK: call i8* @objc_retain 163f4a2713aSLionel Sambuc id obj4 = (x0.*pmf)(); 164f4a2713aSLionel Sambuc // CHECK: call i8* % 165f4a2713aSLionel Sambuc // CHECK: call i8* @objc_retain 166f4a2713aSLionel Sambuc id obj5 = (x0p->*pmf)(); 167f4a2713aSLionel Sambuc 168f4a2713aSLionel Sambuc // CHECK: call void @objc_release 169f4a2713aSLionel Sambuc // CHECK: call void @objc_release 170f4a2713aSLionel Sambuc // CHECK: call void @objc_release 171f4a2713aSLionel Sambuc // CHECK: call void @objc_release 172f4a2713aSLionel Sambuc // CHECK: call void @objc_release 173f4a2713aSLionel Sambuc // CHECK-NEXT: ret void 174f4a2713aSLionel Sambuc} 175f4a2713aSLionel Sambuc 176f4a2713aSLionel Sambuc// rdar://problem/9603128 177f4a2713aSLionel Sambuc// CHECK-LABEL: define i8* @_Z6test36P11objc_object( 178f4a2713aSLionel Sambucid test36(id z) { 179f4a2713aSLionel Sambuc // CHECK: objc_retain 180f4a2713aSLionel Sambuc // CHECK: objc_retain 181f4a2713aSLionel Sambuc // CHECK: objc_release 182f4a2713aSLionel Sambuc // CHECK: objc_autoreleaseReturnValue 183f4a2713aSLionel Sambuc return z; 184f4a2713aSLionel Sambuc} 185f4a2713aSLionel Sambuc 186f4a2713aSLionel Sambuc// Template instantiation side of rdar://problem/9817306 187f4a2713aSLionel Sambuc@interface Test37 188f4a2713aSLionel Sambuc+ alloc; 189f4a2713aSLionel Sambuc- init; 190f4a2713aSLionel Sambuc- (NSArray *) array; 191f4a2713aSLionel Sambuc@end 192f4a2713aSLionel Sambuctemplate <class T> void test37(T *a) { 193f4a2713aSLionel Sambuc for (id x in a.array) { 194f4a2713aSLionel Sambuc use(x); 195f4a2713aSLionel Sambuc } 196f4a2713aSLionel Sambuc} 197f4a2713aSLionel Sambucextern template void test37<Test37>(Test37 *a); 198f4a2713aSLionel Sambuctemplate void test37<Test37>(Test37 *a); 199f4a2713aSLionel Sambuc// CHECK-LABEL: define weak_odr void @_Z6test37I6Test37EvPT_( 200f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = call [[NSARRAY]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[NSARRAY]]* (i8*, i8*)*)( 201f4a2713aSLionel Sambuc// CHECK-NEXT: [[T1:%.*]] = bitcast [[NSARRAY]]* [[T0]] to i8* 202f4a2713aSLionel Sambuc// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) 203f4a2713aSLionel Sambuc// CHECK-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[NSARRAY]]* 204f4a2713aSLionel Sambuc 205f4a2713aSLionel Sambuc// Make sure it's not immediately released before starting the iteration. 206*0a6a1f1dSLionel Sambuc// CHECK-NEXT: load i8** @OBJC_SELECTOR_REFERENCES_ 207f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8* 208f4a2713aSLionel Sambuc// CHECK-NEXT: @objc_msgSend 209f4a2713aSLionel Sambuc 210f4a2713aSLionel Sambuc// This bitcast is for the mutation check. 211f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8* 212f4a2713aSLionel Sambuc// CHECK-NEXT: @objc_enumerationMutation 213f4a2713aSLionel Sambuc 214f4a2713aSLionel Sambuc// This bitcast is for the 'next' message send. 215f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8* 216f4a2713aSLionel Sambuc// CHECK-NEXT: @objc_msgSend 217f4a2713aSLionel Sambuc 218f4a2713aSLionel Sambuc// This bitcast is for the final release. 219f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8* 220f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release(i8* [[T0]]) 221f4a2713aSLionel Sambuc 222f4a2713aSLionel Sambuctemplate<typename T> 223f4a2713aSLionel Sambucvoid send_release() { 224f4a2713aSLionel Sambuc [Test37 array]; 225f4a2713aSLionel Sambuc} 226f4a2713aSLionel Sambuc 227f4a2713aSLionel Sambuc// CHECK-LABEL: define weak_odr void @_Z12send_releaseIiEvv( 228f4a2713aSLionel Sambuc// CHECK: call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend 229f4a2713aSLionel Sambuc// CHECK-NEXT: bitcast 230f4a2713aSLionel Sambuc// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue 231f4a2713aSLionel Sambuc// CHECK-NEXT: bitcast 232f4a2713aSLionel Sambuc// CHECK-NEXT: bitcast 233f4a2713aSLionel Sambuc// CHECK-NEXT: call void @objc_release 234f4a2713aSLionel Sambuc// CHECK-NEXT: ret void 235f4a2713aSLionel Sambuctemplate void send_release<int>(); 236f4a2713aSLionel Sambuc 237f4a2713aSLionel Sambuctemplate<typename T> 238f4a2713aSLionel SambucTest37 *instantiate_init() { 239f4a2713aSLionel Sambuc Test37 *result = [[Test37 alloc] init]; 240f4a2713aSLionel Sambuc return result; 241f4a2713aSLionel Sambuc} 242f4a2713aSLionel Sambuc 243f4a2713aSLionel Sambuc// CHECK-LABEL: define weak_odr %2* @_Z16instantiate_initIiEP6Test37v 244f4a2713aSLionel Sambuc// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend 245f4a2713aSLionel Sambuc// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend 246f4a2713aSLionel Sambuc// CHECK: call i8* @objc_retain 247f4a2713aSLionel Sambuc// CHECK: call void @objc_release 248f4a2713aSLionel Sambuc// CHECK: call i8* @objc_autoreleaseReturnValue 249f4a2713aSLionel Sambuctemplate Test37* instantiate_init<int>(); 250f4a2713aSLionel Sambuc 251f4a2713aSLionel Sambuc// Just make sure that the AST invariants hold properly here, 252f4a2713aSLionel Sambuc// i.e. that we don't crash. 253f4a2713aSLionel Sambuc// The block should get bound in the full-expression outside 254f4a2713aSLionel Sambuc// the statement-expression. 255f4a2713aSLionel Sambuctemplate <class T> class Test38 { 256f4a2713aSLionel Sambuc void test(T x) { 257f4a2713aSLionel Sambuc ^{ (void) x; }, ({ x; }); 258f4a2713aSLionel Sambuc } 259f4a2713aSLionel Sambuc}; 260f4a2713aSLionel Sambuc// CHECK-LABEL: define weak_odr void @_ZN6Test38IiE4testEi( 261f4a2713aSLionel Sambuctemplate class Test38<int>; 262f4a2713aSLionel Sambuc 263f4a2713aSLionel Sambuc// rdar://problem/11964832 264f4a2713aSLionel Sambucclass Test39_base1 { 265f4a2713aSLionel Sambuc virtual void foo(); 266f4a2713aSLionel Sambuc}; 267f4a2713aSLionel Sambucclass Test39_base2 { 268f4a2713aSLionel Sambuc virtual id bar(); 269f4a2713aSLionel Sambuc}; 270f4a2713aSLionel Sambucclass Test39 : Test39_base1, Test39_base2 { // base2 is at non-zero offset 271f4a2713aSLionel Sambuc virtual id bar(); 272f4a2713aSLionel Sambuc}; 273f4a2713aSLionel Sambucid Test39::bar() { return 0; } 274f4a2713aSLionel Sambuc// Note lack of autorelease. 275f4a2713aSLionel Sambuc// CHECK-LABEL: define i8* @_ZThn8_N6Test393barEv( 276f4a2713aSLionel Sambuc// CHECK: call i8* @_ZN6Test393barEv( 277f4a2713aSLionel Sambuc// CHECK-NEXT: ret i8* 278f4a2713aSLionel Sambuc 279f4a2713aSLionel Sambuc// rdar://13617051 280f4a2713aSLionel Sambuc// Just a basic sanity-check that IR-gen still works after instantiating 281f4a2713aSLionel Sambuc// a non-dependent message send that requires writeback. 282f4a2713aSLionel Sambuc@interface Test40 283f4a2713aSLionel Sambuc+ (void) foo:(id *)errorPtr; 284f4a2713aSLionel Sambuc@end 285f4a2713aSLionel Sambuctemplate <class T> void test40_helper() { 286f4a2713aSLionel Sambuc id x; 287f4a2713aSLionel Sambuc [Test40 foo: &x]; 288f4a2713aSLionel Sambuc}; 289f4a2713aSLionel Sambuctemplate void test40_helper<int>(); 290f4a2713aSLionel Sambuc// CHECK-LABEL: define weak_odr void @_Z13test40_helperIiEvv() 291f4a2713aSLionel Sambuc// CHECK: [[X:%.*]] = alloca i8* 292f4a2713aSLionel Sambuc// CHECK-NEXT: [[TEMP:%.*]] = alloca i8* 293f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* null, i8** [[X]] 294f4a2713aSLionel Sambuc// CHECK: [[T0:%.*]] = load i8** [[X]] 295f4a2713aSLionel Sambuc// CHECK-NEXT: store i8* [[T0]], i8** [[TEMP]] 296f4a2713aSLionel Sambuc// CHECK: @objc_msgSend 297f4a2713aSLionel Sambuc// CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]] 298f4a2713aSLionel Sambuc// CHECK-NEXT: call i8* @objc_retain(i8* [[T0]]) 299f4a2713aSLionel Sambuc 300