From 0add6aa837f9aeb2954009fe61921650b578e50c Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 17 Feb 2016 21:09:50 +0000 Subject: [PATCH] [CodeGen] Fix an assert in CodeGenFunction::EmitFunctionEpilog The assert is triggered because isObjCRetainableType() is called on the canonicalized return type that has been stripped of the typedefs and attributes attached to it. To fix this assert, this commit gets the original return type from CurCodeDecl or BlockInfo and uses it instead of the canoicalized type. rdar://problem/24470031 Differential Revision: http://reviews.llvm.org/D16914 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@261151 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCall.cpp | 20 ++++++++++- .../auto-release-result-assert.mm | 35 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 test/CodeGenObjCXX/auto-release-result-assert.mm diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 61b2fe78db..281292f764 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -14,6 +14,7 @@ #include "CGCall.h" #include "ABIInfo.h" +#include "CGBlocks.h" #include "CGCXXABI.h" #include "CGCleanup.h" #include "CodeGenFunction.h" @@ -2462,9 +2463,26 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, // In ARC, end functions that return a retainable type with a call // to objc_autoreleaseReturnValue. if (AutoreleaseResult) { +#ifndef NDEBUG + // Type::isObjCRetainabletype has to be called on a QualType that hasn't + // been stripped of the typedefs, so we cannot use RetTy here. Get the + // original return type of FunctionDecl, CurCodeDecl, and BlockDecl from + // CurCodeDecl or BlockInfo. + QualType RT; + + if (auto *FD = dyn_cast(CurCodeDecl)) + RT = FD->getReturnType(); + else if (auto *MD = dyn_cast(CurCodeDecl)) + RT = MD->getReturnType(); + else if (isa(CurCodeDecl)) + RT = BlockInfo->BlockExpression->getFunctionType()->getReturnType(); + else + llvm_unreachable("Unexpected function/method type"); + assert(getLangOpts().ObjCAutoRefCount && !FI.isReturnsRetained() && - RetTy->isObjCRetainableType()); + RT->isObjCRetainableType()); +#endif RV = emitAutoreleaseOfResult(*this, RV); } diff --git a/test/CodeGenObjCXX/auto-release-result-assert.mm b/test/CodeGenObjCXX/auto-release-result-assert.mm new file mode 100644 index 0000000000..044dc9d7d9 --- /dev/null +++ b/test/CodeGenObjCXX/auto-release-result-assert.mm @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -o - %s | FileCheck %s + +// CHECK-LABEL: define %struct.S1* @_Z4foo1i( +// CHECK: %[[CALL:[a-z0-9]+]] = call %struct.S1* @_Z4foo0i +// CHECK: ret %struct.S1* %[[CALL]] + +// CHECK-LABEL: define %struct.S1* @_ZN2S22m1Ev( +// CHECK: %[[CALL:[a-z0-9]+]] = call %struct.S1* @_Z4foo0i +// CHECK: ret %struct.S1* %[[CALL]] + +// CHECK-LABEL: define internal %struct.S1* @Block1_block_invoke( +// CHECK: %[[CALL:[a-z0-9]+]] = call %struct.S1* @_Z4foo0i +// CHECK: ret %struct.S1* %[[CALL]] + +struct S1; + +typedef __attribute__((NSObject)) struct __attribute__((objc_bridge(id))) S1 * S1Ref; + +S1Ref foo0(int); + +struct S2 { + S1Ref m1(); +}; + +S1Ref foo1(int a) { + return foo0(a); +} + +S1Ref S2::m1() { + return foo0(0); +} + +S1Ref (^Block1)(void) = ^{ + return foo0(0); +}; -- 2.40.0