diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -4029,10 +4029,28 @@ llvm::Function * CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { - auto I = DirectMethodDefinitions.find(OMD->getCanonicalDecl()); + auto *COMD = OMD->getCanonicalDecl(); + auto I = DirectMethodDefinitions.find(COMD); if (I != DirectMethodDefinitions.end()) return I->second; + // If this translation unit sees the implementation, we need to use + // it to generate the llvm::Function below. It is important to do so + // because Objective-C allows for return types to be somewhat mismatched + // and the Body of the function will expect to be generated with + // the type of its implementation. + if (!OMD->getBody()) { + if (auto *OI = dyn_cast(CD)) { + if (auto *Impl = OI->getImplementation()) + if (auto *M = Impl->getMethod(OMD->getSelector(), OMD->isInstanceMethod())) + OMD = M; + } else if (auto *CI = dyn_cast(CD)) { + if (auto *Impl = OI->getImplementation()) + if (auto *M = Impl->getMethod(OMD->getSelector(), OMD->isInstanceMethod())) + OMD = M; + } + } + SmallString<256> Name; GetNameForMethod(OMD, CD, Name, /*ignoreCategoryNamespace*/true); @@ -4042,7 +4060,7 @@ llvm::Function *Method = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage, Name.str(), &CGM.getModule()); - DirectMethodDefinitions.insert(std::make_pair(OMD->getCanonicalDecl(), Method)); + DirectMethodDefinitions.insert(std::make_pair(COMD, Method)); return Method; } diff --git a/clang/test/CodeGenObjC/direct-method-ret-mismatch.m b/clang/test/CodeGenObjC/direct-method-ret-mismatch.m new file mode 100644 --- /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