]> granicus.if.org Git - clang/commitdiff
[objc-gnustep2] Fix a bug in category generation.
authorDavid Chisnall <csdavec@swan.ac.uk>
Fri, 28 Dec 2018 17:44:54 +0000 (17:44 +0000)
committerDavid Chisnall <csdavec@swan.ac.uk>
Fri, 28 Dec 2018 17:44:54 +0000 (17:44 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@350130 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGObjCGNU.cpp
test/CodeGenObjC/gnustep2-category-protocol.m [new file with mode: 0644]

index 534650b1108598f45b3e475b398ab758c41edac4..548bd6b3fd72a5d7c6a8ed6596f7591455c9f7a7 100644 (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());
diff --git a/test/CodeGenObjC/gnustep2-category-protocol.m b/test/CodeGenObjC/gnustep2-category-protocol.m
new file mode 100644 (file)
index 0000000..6463474
--- /dev/null
@@ -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
+
+