diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index fec2607fac78..2b12bb5c1b6d 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -469,6 +469,11 @@ public: ReferencedProtocols.set(List, Num, C); } + /// mergeClassExtensionProtocolList - Merge class extension's protocol list + /// into the protocol list for this class. + void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List, unsigned Num, + ASTContext &C); + void setIVarList(ObjCIvarDecl * const *List, unsigned Num, ASTContext &C) { IVars.set(List, Num, C); } diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 4185ac168289..e978a5b60fab 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -118,6 +118,47 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return 0; } +void ObjCInterfaceDecl::mergeClassExtensionProtocolList( + ObjCProtocolDecl *const* ExtList, unsigned ExtNum, + ASTContext &C) +{ + if (ReferencedProtocols.empty()) { + ReferencedProtocols.set(ExtList, ExtNum, C); + return; + } + // Check for duplicate protocol in class's protocol list. + // This is (O)2. But it is extremely rare and number of protocols in + // class or its extension are very few. + llvm::SmallVector ProtocolRefs; + for (unsigned i = 0; i < ExtNum; i++) { + bool protocolExists = false; + ObjCProtocolDecl *ProtoInExtension = ExtList[i]; + for (protocol_iterator p = protocol_begin(), e = protocol_end(); + p != e; p++) { + ObjCProtocolDecl *Proto = (*p); + if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) { + protocolExists = true; + break; + } + } + // Do we want to warn on a protocol in extension class which + // already exist in the class? Probably not. + if (!protocolExists) + ProtocolRefs.push_back(ProtoInExtension); + } + if (ProtocolRefs.empty()) + return; + + for (protocol_iterator p = protocol_begin(), e = protocol_end(); + p != e; p++) + ProtocolRefs.push_back(*p); + ReferencedProtocols.Destroy(C); + unsigned NumProtoRefs = ProtocolRefs.size(); + setProtocolList((ObjCProtocolDecl**)&ProtocolRefs[0], NumProtoRefs, C); + // Merge ProtocolRefs into class's protocol list; + +} + ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { ObjCInterfaceDecl* ClassDecl = this; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index c11b4e06667b..51651ab4bba4 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -588,8 +588,15 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, CDecl->insertNextClassCategory(); if (NumProtoRefs) { - CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); - CDecl->setLocEnd(EndProtoLoc); + // Protocols in the class extension belong to the class. + if (!CDecl->getIdentifier()) + IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, + NumProtoRefs,Context); + else { + CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + Context); + CDecl->setLocEnd(EndProtoLoc); + } } CheckObjCDeclScope(CDecl); diff --git a/clang/test/CodeGenObjC/protocol-in-extended-class.m b/clang/test/CodeGenObjC/protocol-in-extended-class.m new file mode 100644 index 000000000000..87bda46faeaa --- /dev/null +++ b/clang/test/CodeGenObjC/protocol-in-extended-class.m @@ -0,0 +1,29 @@ +// RUN: clang-cc -triple x86_64-apple-darwin10 -S %s -o %t-64.s && +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s && +// RUN: clang-cc -triple i386-apple-darwin -S %s -o %t-32.s && +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s && +// RUN: true + +@protocol MyProtocol +@end + +@protocol ExtendedProtocol +@end + +@interface ItDoesntWork { +} +-(void) Meth; +@end + +@interface ItDoesntWork() +@end + +@implementation ItDoesntWork +-(void) Meth { + ItDoesntWork *p = 0; + } +@end + +// CHECK-LP64: l_OBJC_PROTOCOL_$_ExtendedProtocol: + +// CHECK-LP32: L_OBJC_PROTOCOL_ExtendedProtocol: