diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 89bf402c19f8a..bdb9f4002f3c2 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -2221,6 +2221,12 @@ static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF, // Call the function. llvm::CallBase *Inst = CGF.EmitCallOrInvoke(fn, value); + // Mark calls to objc_autorelease as tail on the assumption that methods + // overriding autorelease do not touch anything on the stack. + if (fnName == "objc_autorelease") + if (auto *Call = dyn_cast(Inst)) + Call->setTailCall(); + // Cast the result back to the original type. return CGF.Builder.CreateBitCast(Inst, origType); } diff --git a/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m b/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m index c51b56b66fff5..4a415be21cb0e 100644 --- a/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m +++ b/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m @@ -30,7 +30,7 @@ void test1(id x) { // CALLS: {{call.*@objc_allocWithZone}} // CALLS: {{call.*@objc_retain}} // CALLS: {{call.*@objc_release}} - // CALLS: {{call.*@objc_autorelease}} + // CALLS: {{tail call.*@objc_autorelease}} [NSObject alloc]; [NSObject allocWithZone:nil]; [x retain]; @@ -121,7 +121,7 @@ void test_alloc_instance(A *a) { // call will return i8* which we have to cast to A* // CHECK-LABEL: define {{.*}}void @test_autorelease_class_ptr A* test_autorelease_class_ptr(B *b) { - // CALLS: {{call.*@objc_autorelease}} + // CALLS: {{tail call.*@objc_autorelease}} // CALLS-NEXT: bitcast i8* // CALLS-NEXT: ret return [b autorelease];