forked from OSchip/llvm-project
[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 <phabouzit@apple.com> Differential Revision: https://reviews.llvm.org/D73208
This commit is contained in:
parent
31905c2bbb
commit
6eb969b7c5
|
@ -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(
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue