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