diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -772,9 +772,10 @@ // If we're emitting a value with lifetime, we have to do the // initialization *before* we leave the cleanup scopes. - if (const ExprWithCleanups *EWC = dyn_cast(init)) - init = EWC->getSubExpr(); - CodeGenFunction::RunCleanupsScope Scope(*this); + if (auto *EWC = dyn_cast(init)) { + CodeGenFunction::RunCleanupsScope Scope(*this); + return EmitScalarInit(EWC->getSubExpr(), D, lvalue, capturedByInit); + } // We have to maintain the illusion that the variable is // zero-initialized. If the variable might be accessed in its diff --git a/clang/test/CodeGenObjCXX/arc-blocks.mm b/clang/test/CodeGenObjCXX/arc-blocks.mm --- a/clang/test/CodeGenObjCXX/arc-blocks.mm +++ b/clang/test/CodeGenObjCXX/arc-blocks.mm @@ -204,10 +204,10 @@ // Test that calls to @llvm.objc.retainBlock aren't emitted in some cases. -namespace test_block_retain { - typedef void (^BlockTy)(); +typedef void (^BlockTy)(); +void foo1(id); - void foo1(id); +namespace test_block_retain { // CHECK-LABEL: define{{.*}} void @_ZN17test_block_retain14initializationEP11objc_object( // CHECK-NOT: @llvm.objc.retainBlock( @@ -320,4 +320,25 @@ b1 = b0; ((BlockTy)b1)(); } -} + } + + // Check that the block capture is released after the full expression. + + // CHECK-LABEL: define void @_ZN13test_rval_ref4testEP11objc_object( + // CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 + // CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5 + // CHECK: %[[V1:.*]] = call i8* @llvm.objc.retain( + // CHECK: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8 + // CHECK: invoke void @_ZN13test_rval_ref17callTemplateBlockEOU15__autoreleasingU13block_pointerFvvE( + + // CHECK: call void @llvm.objc.storeStrong(i8** %[[BLOCK_CAPTURED]], i8* null) + + namespace test_rval_ref { + void callTemplateBlock(BlockTy &&func); + + void test(id str) { + return callTemplateBlock(^void() { + foo1(str); + }); + } + } diff --git a/clang/test/CodeGenObjCXX/arc.mm b/clang/test/CodeGenObjCXX/arc.mm --- a/clang/test/CodeGenObjCXX/arc.mm +++ b/clang/test/CodeGenObjCXX/arc.mm @@ -334,3 +334,17 @@ // CHECK: [[T0:%.*]] = load i8**, i8*** [[X]] // CHECK-NEXT: call void @llvm.objc.moveWeak(i8** [[Y]], i8** [[T0]]) // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[Y]]) + +void test42() { + __attribute__((ns_returns_retained)) id test42_0(); + id test42_1(id); + void test42_2(id &&); + test42_2(test42_1(test42_0())); +} + +// Check that the pointer returned by test42_0 is released after the full expression. + +// CHECK-LABEL: define void @_Z6test42v() +// CHECK: %[[CALL:.*]] = call i8* @_Z8test42_0v() +// CHECK: call void @_Z8test42_2OU15__autoreleasingP11objc_object( +// CHECK: call void @llvm.objc.release(i8* %[[CALL]])