[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:
Pierre Habouzit 2020-01-22 08:46:54 -08:00
parent 31905c2bbb
commit 6eb969b7c5
2 changed files with 56 additions and 10 deletions

View File

@ -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(

View File

@ -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