diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 95e4ee498d23..e8f48afb3b5a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -498,6 +498,22 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, OpenCLKernelMetadata->addOperand(kernelMDNode); } +/// Determine whether the function F ends with a return stmt. +static bool endsWithReturn(const Decl* F) { + const Stmt *Body = nullptr; + if (auto *FD = dyn_cast_or_null(F)) + Body = FD->getBody(); + else if (auto *OMD = dyn_cast_or_null(F)) + Body = OMD->getBody(); + + if (auto *CS = dyn_cast_or_null(Body)) { + auto LastStmt = CS->body_rbegin(); + if (LastStmt != CS->body_rend()) + return isa(*LastStmt); + } + return false; +} + void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, @@ -593,6 +609,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, if (RetTy->isVoidType()) { // Void type; nothing to return. ReturnValue = 0; + + // Count the implicit return. + if (!endsWithReturn(D)) + ++NumReturnExprs; } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect && !hasScalarEvaluationKind(CurFnInfo->getReturnType())) { // Indirect aggregate return; emit returned value directly into sret slot. diff --git a/clang/test/CodeGenObjC/arc-linetable.m b/clang/test/CodeGenObjC/arc-linetable.m index 7af02edc5b62..20a3de78f47f 100644 --- a/clang/test/CodeGenObjC/arc-linetable.m +++ b/clang/test/CodeGenObjC/arc-linetable.m @@ -32,6 +32,15 @@ // CHECK: @objc_msgSend{{.*}} !dbg ![[MSG7:[0-9]+]] // CHECK: ret {{.*}} !dbg ![[RET7:[0-9]+]] +// CHECK: define {{.*}}testCleanupVoid +// CHECK: icmp ne {{.*}}!dbg ![[SKIP1:[0-9]+]] +// CHECK-NEXT: br {{.*}}, label %[[CLEANUP:.*]], label +// CHECK: [[CLEANUP]]: +// CHECK-NEXT: !dbg ![[RET8:[0-9]+]] +// CHECK: @objc_storeStrong{{.*}}, !dbg ![[ARC8:[0-9]+]] +// CHECK: ret {{.*}} !dbg ![[RET8]] + +typedef signed char BOOL; @interface NSObject + (id)alloc; @@ -93,6 +102,22 @@ return 1; } +- (void)testCleanupVoid:(BOOL)skip withDelegate: (AppDelegate *) delegate { + static BOOL skip_all; + // CHECK: ![[SKIP1]] = metadata !{i32 [[@LINE+1]], i32 0, + if (!skip_all) { + if (!skip) { + return; + } + NSString *s = @"bar"; + if (!skip) { + [delegate testVoid :s]; + } + } + // CHECK: ![[RET8]] = metadata !{i32 [[@LINE+2]], i32 0, + // CHECK: ![[ARC8]] = metadata !{i32 [[@LINE+1]], i32 0, +} + @end