[objc-gnustep2] Fix a bug in category generation.

We were not emitting a protocol definition while generating the category
method list.  This was fine in most cases, because something else in the
library typically referenced any given protocol, but it caused linker
failures if the category was the only reference to a given protocol.

llvm-svn: 350130
This commit is contained in:
David Chisnall 2018-12-28 17:44:54 +00:00
parent 28eccf5ba0
commit 386477a541
2 changed files with 45 additions and 6 deletions

View File

@ -277,6 +277,8 @@ protected:
Fields.addInt(Int8Ty, 0);
}
virtual llvm::Constant *GenerateCategoryProtocolList(const
ObjCCategoryDecl *OCD);
virtual ConstantArrayBuilder PushPropertyListHeader(ConstantStructBuilder &Fields,
int count) {
// int count;
@ -1164,6 +1166,15 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
return MethodList.finishAndCreateGlobal(".objc_protocol_method_list",
CGM.getPointerAlign());
}
llvm::Constant *GenerateCategoryProtocolList(const ObjCCategoryDecl *OCD)
override {
SmallVector<llvm::Constant*, 16> Protocols;
for (const auto *PI : OCD->getReferencedProtocols())
Protocols.push_back(
llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI),
ProtocolPtrTy));
return GenerateProtocolList(Protocols);
}
llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper,
llvm::Value *cmd, MessageSendInfo &MSI) override {
@ -3099,18 +3110,21 @@ llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
return ptr;
}
llvm::Constant *CGObjCGNU::GenerateCategoryProtocolList(const
ObjCCategoryDecl *OCD) {
SmallVector<std::string, 16> Protocols;
for (const auto *PD : OCD->getReferencedProtocols())
Protocols.push_back(PD->getNameAsString());
return GenerateProtocolList(Protocols);
}
void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
const ObjCInterfaceDecl *Class = OCD->getClassInterface();
std::string ClassName = Class->getNameAsString();
std::string CategoryName = OCD->getNameAsString();
// Collect the names of referenced protocols
SmallVector<std::string, 16> Protocols;
const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl();
const ObjCList<ObjCProtocolDecl> &Protos = CatDecl->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
E = Protos.end(); I != E; ++I)
Protocols.push_back((*I)->getNameAsString());
ConstantInitBuilder Builder(CGM);
auto Elements = Builder.beginStruct();
@ -3132,7 +3146,7 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
GenerateMethodList(ClassName, CategoryName, ClassMethods, true),
PtrTy);
// Protocol list
Elements.addBitCast(GenerateProtocolList(Protocols), PtrTy);
Elements.addBitCast(GenerateCategoryProtocolList(CatDecl), PtrTy);
if (isRuntime(ObjCRuntime::GNUstep, 2)) {
const ObjCCategoryDecl *Category =
Class->FindCategoryDeclaration(OCD->getIdentifier());

View File

@ -0,0 +1,25 @@
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s
// Regression test. We weren't emitting definitions for protocols used in
// categories, causing linker errors when the category was the only reference
// to a protocol in a binary.
// CHECK: @._OBJC_PROTOCOL_Y = global
// CHEKC-SAME: section "__objc_protocols", comdat, align 8
@interface X
{
id isa;
}
@end
@implementation X
@end
@protocol Y @end
@interface X (y) <Y>
@end
@implementation X (y) @end