From 6eb969b7c5b5195d7f85b70e2e060eb2989cdc3c Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 22 Jan 2020 08:46:54 -0800 Subject: [PATCH] [objc_direct] fix codegen for mismatched Decl/Impl return types For non direct methods, the codegen uses the type of the Implementation. Because Objective-C rules allow some differences between the Declaration and Implementation return types, when the Implementation is in this translation unit, the type of the Implementation should be preferred to emit the Function over the Declaration. Radar-Id: rdar://problem/58797748 Signed-off-by: Pierre Habouzit Differential Revision: https://reviews.llvm.org/D73208 --- clang/lib/CodeGen/CGObjCMac.cpp | 47 +++++++++++++++---- .../CodeGenObjC/direct-method-ret-mismatch.m | 19 ++++++++ 2 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 clang/test/CodeGenObjC/direct-method-ret-mismatch.m diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index f994ec92da14..547a1f352f94 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -4032,22 +4032,49 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, llvm::Function * CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { - auto I = DirectMethodDefinitions.find(OMD->getCanonicalDecl()); - if (I != DirectMethodDefinitions.end()) - return I->second; + auto *COMD = OMD->getCanonicalDecl(); + auto I = DirectMethodDefinitions.find(COMD); + llvm::Function *OldFn = nullptr, *Fn = nullptr; - SmallString<256> Name; - GetNameForMethod(OMD, CD, Name, /*ignoreCategoryNamespace*/true); + if (I != DirectMethodDefinitions.end()) { + // Objective-C allows for the declaration and implementation types + // to differ slightly. + // + // If we're being asked for the Function associated for a method + // implementation, a previous value might have been cached + // based on the type of the canonical declaration. + // + // If these do not match, then we'll replace this function with + // a new one that has the proper type below. + if (!OMD->getBody() || COMD->getReturnType() == OMD->getReturnType()) + return I->second; + OldFn = I->second; + } CodeGenTypes &Types = CGM.getTypes(); llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD)); - llvm::Function *Method = - llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage, - Name.str(), &CGM.getModule()); - DirectMethodDefinitions.insert(std::make_pair(OMD->getCanonicalDecl(), Method)); - return Method; + if (OldFn) { + Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage, + "", &CGM.getModule()); + Fn->takeName(OldFn); + OldFn->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(Fn, OldFn->getType())); + OldFn->eraseFromParent(); + + // Replace the cached function in the map. + I->second = Fn; + } else { + SmallString<256> Name; + GetNameForMethod(OMD, CD, Name, /*ignoreCategoryNamespace*/ true); + + Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage, + Name.str(), &CGM.getModule()); + DirectMethodDefinitions.insert(std::make_pair(COMD, Fn)); + } + + return Fn; } void CGObjCCommonMac::GenerateDirectMethodPrologue( diff --git a/clang/test/CodeGenObjC/direct-method-ret-mismatch.m b/clang/test/CodeGenObjC/direct-method-ret-mismatch.m new file mode 100644 index 000000000000..65b253de1476 --- /dev/null +++ b/clang/test/CodeGenObjC/direct-method-ret-mismatch.m @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -o - | FileCheck %s + +__attribute__((objc_root_class)) +@interface Root +- (Root *)method __attribute__((objc_direct)); +@end + +@implementation Root +// CHECK-LABEL: define internal i8* @"\01-[Root something]"( +- (id)something { + // CHECK: %{{[^ ]*}} = call {{.*}} @"\01-[Root method]" + return [self method]; +} + +// CHECK-LABEL: define hidden i8* @"\01-[Root method]"( +- (id)method { + return self; +} +@end