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 @@ -6659,6 +6659,8 @@ values.add(GetClassGlobal(Interface, /*metaclass*/ false, NotForDefinition)); std::string listName = (Interface->getObjCRuntimeNameAsString() + "_$_" + OCD->getName()).str(); + // Keep track of whether we have actual metadata to emit. + bool isEmptyCategory = true; SmallVector instanceMethods; SmallVector classMethods; @@ -6672,46 +6674,61 @@ } } - values.add(emitMethodList(listName, MethodListType::CategoryInstanceMethods, - instanceMethods)); - values.add(emitMethodList(listName, MethodListType::CategoryClassMethods, - classMethods)); + auto instanceMethodList = emitMethodList( + listName, MethodListType::CategoryInstanceMethods, instanceMethods); + auto classMethodList = emitMethodList( + listName, MethodListType::CategoryClassMethods, classMethods); + values.add(instanceMethodList); + values.add(classMethodList); + isEmptyCategory &= + instanceMethodList->isNullValue() && classMethodList->isNullValue(); const ObjCCategoryDecl *Category = - Interface->FindCategoryDeclaration(OCD->getIdentifier()); + Interface->FindCategoryDeclaration(OCD->getIdentifier()); if (Category) { SmallString<256> ExtName; - llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_" - << OCD->getName(); - values.add(EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" - + Interface->getObjCRuntimeNameAsString() + "_$_" - + Category->getName(), - Category->protocol_begin(), - Category->protocol_end())); - values.add(EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, false)); - values.add(EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, true)); + llvm::raw_svector_ostream(ExtName) + << Interface->getObjCRuntimeNameAsString() << "_$_" << OCD->getName(); + auto protocolList = + EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" + + Interface->getObjCRuntimeNameAsString() + "_$_" + + Category->getName(), + Category->protocol_begin(), Category->protocol_end()); + auto propertyList = EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes, false); + auto classPropertyList = + EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), OCD, + Category, ObjCTypes, true); + values.add(protocolList); + values.add(propertyList); + values.add(classPropertyList); + isEmptyCategory &= protocolList->isNullValue() && + propertyList->isNullValue() && + classPropertyList->isNullValue(); } else { values.addNullPointer(ObjCTypes.ProtocolListnfABIPtrTy); values.addNullPointer(ObjCTypes.PropertyListPtrTy); values.addNullPointer(ObjCTypes.PropertyListPtrTy); } - unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy); + unsigned Size = + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy); values.addInt(ObjCTypes.IntTy, Size); llvm::GlobalVariable *GCATV = finishAndCreateGlobal(values, ExtCatName.str(), CGM); - CGM.addCompilerUsedGlobal(GCATV); - if (Interface->hasAttr()) - DefinedStubCategories.push_back(GCATV); - else - DefinedCategories.push_back(GCATV); - // Determine if this category is also "non-lazy". - if (ImplementationIsNonLazy(OCD)) - DefinedNonLazyCategories.push_back(GCATV); + if (!isEmptyCategory) { + CGM.addCompilerUsedGlobal(GCATV); + if (Interface->hasAttr()) + DefinedStubCategories.push_back(GCATV); + else + DefinedCategories.push_back(GCATV); + + // Determine if this category is also "non-lazy". + if (ImplementationIsNonLazy(OCD)) + DefinedNonLazyCategories.push_back(GCATV); + } // method definition entries must be clear for next implementation. MethodDefinitions.clear(); } diff --git a/clang/test/CodeGenObjC/category-class-empty.m b/clang/test/CodeGenObjC/category-class-empty.m new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenObjC/category-class-empty.m @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -O3 -emit-llvm -o - %s | FileCheck %s +// PR7431 + +// CHECK-NOT: @"_OBJC_$_CATEGORY_A_$_foo" = internal global %struct._category_t + +@interface A +@end +__attribute__((objc_direct_members)) +@interface A(foo) +- (void)foo_myStuff; +@end +@implementation A(foo) +- (void)foo_myStuff { +} +@end + diff --git a/clang/test/CodeGenObjC/non-lazy-classes.m b/clang/test/CodeGenObjC/non-lazy-classes.m --- a/clang/test/CodeGenObjC/non-lazy-classes.m +++ b/clang/test/CodeGenObjC/non-lazy-classes.m @@ -42,4 +42,7 @@ @implementation E @end __attribute__((objc_nonlazy_class)) -@implementation E (MyCat) @end +@implementation E (MyCat) +-(void) load { +} +@end