Index: cfe/trunk/lib/CodeGen/CGBlocks.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGBlocks.cpp +++ cfe/trunk/lib/CodeGen/CGBlocks.cpp @@ -619,7 +619,13 @@ // Block captures count as local values and have imprecise semantics. // They also can't be arrays, so need to worry about that. - if (dtorKind == QualType::DK_objc_strong_lifetime) { + // + // For const-qualified captures, emit clang.arc.use to ensure the captured + // object doesn't get released while we are still depending on its validity + // within the block. + if (VT.isConstQualified() && VT.getObjCLifetime() == Qualifiers::OCL_Strong) + destroyer = CodeGenFunction::emitARCIntrinsicUse; + else if (dtorKind == QualType::DK_objc_strong_lifetime) { destroyer = CodeGenFunction::destroyARCStrongImprecise; } else { destroyer = CGF.getDestroyer(dtorKind); @@ -866,6 +872,12 @@ } else if (type->isReferenceType()) { Builder.CreateStore(src.getPointer(), blockField); + // If type is const-qualified, copy the value into the block field. + } else if (type.isConstQualified() && + type.getObjCLifetime() == Qualifiers::OCL_Strong) { + llvm::Value *value = Builder.CreateLoad(src, "captured"); + Builder.CreateStore(value, blockField); + // If this is an ARC __strong block-pointer variable, don't do a // block copy. // Index: cfe/trunk/lib/CodeGen/CGObjC.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGObjC.cpp +++ cfe/trunk/lib/CodeGen/CGObjC.cpp @@ -2415,6 +2415,12 @@ CGF.EmitARCDestroyWeak(addr); } +void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr, + QualType type) { + llvm::Value *value = CGF.Builder.CreateLoad(addr); + CGF.EmitARCIntrinsicUse(value); +} + namespace { struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup { llvm::Value *Token; Index: cfe/trunk/lib/CodeGen/CodeGenFunction.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h @@ -3369,6 +3369,7 @@ static Destroyer destroyARCStrongImprecise; static Destroyer destroyARCStrongPrecise; static Destroyer destroyARCWeak; + static Destroyer emitARCIntrinsicUse; void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr); llvm::Value *EmitObjCAutoreleasePoolPush(); Index: cfe/trunk/test/CodeGenObjC/arc-blocks.m =================================================================== --- cfe/trunk/test/CodeGenObjC/arc-blocks.m +++ cfe/trunk/test/CodeGenObjC/arc-blocks.m @@ -298,15 +298,11 @@ // CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]*, [[TEST8]]** [[SELF]], -// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* -// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) -// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]* -// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]] +// CHECK-NEXT: store %0* [[T1]], %0** [[T0]] // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to // CHECK: call void @test8_helper( -// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]*, [[TEST8]]** [[D0]] -// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T2]]) +// CHECK-NEXT: [[T2:%.*]] = load [[TEST8]]*, [[TEST8]]** [[D0]] +// CHECK-NEXT: call void (...) @clang.arc.use([[TEST8]]* [[T2]]) // CHECK: ret void extern void test8_helper(void (^)(void)); @@ -741,5 +737,31 @@ // CHECK-NEXT: ret void } +// CHECK-LABEL: define void @test20( +// CHECK: [[XADDR:%.*]] = alloca i8* +// CHECK-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]> +// CHECK-NEXT: [[RETAINEDX:%.*]] = call i8* @objc_retain(i8* %{{.*}}) +// CHECK-NEXT: store i8* [[RETAINEDX]], i8** [[XADDR]] +// CHECK-NEXT: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 +// CHECK: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 +// CHECK: [[CAPTURED:%.*]] = load i8*, i8** [[XADDR]] +// CHECK: store i8* [[CAPTURED]], i8** [[BLOCKCAPTURED]] +// CHECK: [[CAPTURE:%.*]] = load i8*, i8** [[CAPTUREFIELD]] +// CHECK-NEXT: call void (...) @clang.arc.use(i8* [[CAPTURE]]) +// CHECK-NEXT: [[X:%.*]] = load i8*, i8** [[XADDR]] +// CHECK-NEXT: call void @objc_release(i8* [[X]]) +// CHECK-NEXT: ret void + +// CHECK-LABEL: define internal void @__copy_helper_block +// CHECK: [[BLOCKSOURCE:%.*]] = bitcast i8* %{{.*}} to <[[BLOCKTY]]>* +// CHECK: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCKSOURCE]], i32 0, i32 5 +// CHECK: [[BLOCKCOPYSRC:%.*]] = load i8*, i8** [[CAPTUREFIELD]] +// CHECK: call i8* @objc_retain(i8* [[BLOCKCOPYSRC]]) + +void test20_callee(void (^)()); +void test20(const id x) { + test20_callee(^{ (void)x; }); +} + // CHECK: attributes [[NUW]] = { nounwind } // CHECK-UNOPT: attributes [[NUW]] = { nounwind } Index: cfe/trunk/test/CodeGenObjC/arc-foreach.m =================================================================== --- cfe/trunk/test/CodeGenObjC/arc-foreach.m +++ cfe/trunk/test/CodeGenObjC/arc-foreach.m @@ -63,11 +63,11 @@ // CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64-NEXT: [[T1:%.*]] = load i8*, i8** [[X]] -// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) -// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]] -// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] -// CHECK-LP64: call void @use_block( -// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null) +// CHECK-LP64-NEXT: store i8* [[T1]], i8** [[T0]] +// CHECK-LP64-NEXT: [[BLOCK1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] +// CHECK-LP64-NEXT: call void @use_block(void ()* [[BLOCK1]]) +// CHECK-LP64-NEXT: [[CAPTURE:%.*]] = load i8*, i8** [[D0]] +// CHECK-LP64: call void (...) @clang.arc.use(i8* [[CAPTURE]]) // CHECK-LP64: [[T0:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8* @@ -200,13 +200,10 @@ // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[BC:%.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[T1:%.*]] = load [[TY]]*, [[TY]]** [[SELF_ADDR]] -// CHECK-LP64: [[T2:%.*]] = bitcast [[TY]]* [[T1]] to i8* -// CHECK-LP64: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) -// CHECK-LP64: [[T4:%.*]] = bitcast i8* [[T3]] to [[TY]]* -// CHECK-LP64: store [[TY]]* [[T4]], [[TY]]** [[BC]] +// CHECK-LP64: store [[TY]]* [[T1]], [[TY]]** [[BC]] -// CHECK-LP64: [[T5:%.*]] = bitcast [[TY]]** [[T0]] to i8** -// CHECK-LP64: call void @objc_storeStrong(i8** [[T5]], i8* null) +// CHECK-LP64: [[T5:%.*]] = load [[TY]]*, [[TY]]** [[T0]] +// CHECK-LP64: call void (...) @clang.arc.use([[TY]]* [[T5]]) // CHECK-LP64: switch i32 {{%.*}}, label %[[UNREACHABLE:.*]] [ // CHECK-LP64-NEXT: i32 0, label %[[CLEANUP_CONT:.*]] // CHECK-LP64-NEXT: i32 2, label %[[FORCOLL_END:.*]]