diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -2178,6 +2178,14 @@ data().ReferencedProtocols.set(List, Num, Locs, C); } + /// This is true iff the protocol is tagged with the `objc_static_protocol` + /// attribute. + bool isNonRuntimeProtocol() const; + + /// Get the set of all protocols implied by this protocols inheritance + /// hierarchy. + void getImpliedProtocols(llvm::DenseSet &IPs) const; + ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName); // Lookup a method. First, we search locally. If a method isn't diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2024,6 +2024,13 @@ let Documentation = [ObjCDirectMembersDocs]; } +def ObjCNonRuntimeProtocol : Attr { + let Spellings = [Clang<"objc_non_runtime_protocol">]; + let Subjects = SubjectList<[ObjCProtocol], ErrorDiag>; + let LangOpts = [ObjC]; + let Documentation = [ObjCNonRuntimeProtocolDocs]; +} + def ObjCRuntimeName : Attr { let Spellings = [Clang<"objc_runtime_name">]; let Subjects = SubjectList<[ObjCInterface, ObjCProtocol], ErrorDiag>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4620,6 +4620,22 @@ }]; } +def ObjCNonRuntimeProtocolDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ +The ``objc_non_runtime_protocol`` attribute can be used to mark that an +Objective-C protocol is only used during static type-checking and doesn't need +to be represented dynamically. This avoids several small code-size and run-time +overheads associated with handling the protocol's metadata. A non-runtime +protocol cannot be used as the operand of a ``@protocol`` expression, and +dynamic attempts to find it with ``objc_getProtocol`` will fail. + +If a non-runtime protocol inherits from any ordinary protocols, classes and +derived protocols that declare conformance to the non-runtime protocol will +dynamically list their conformance to those bare protocols. + }]; +} + def SelectAnyDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1034,6 +1034,8 @@ "string is ill-formed as UTF-8 and will become a null %0 when boxed">, InGroup; +def err_objc_non_runtime_protocol_in_protocol_expr : Error< + "cannot use a protocol declared 'objc_non_runtime_protocol' in a @protocol expression">; def err_objc_direct_on_protocol : Error< "'objc_direct' attribute cannot be applied to %select{methods|properties}0 " "declared in an Objective-C protocol">; diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include using namespace clang; @@ -1905,6 +1906,27 @@ return Result; } +bool ObjCProtocolDecl::isNonRuntimeProtocol() const { + return hasAttr(); +} + +void ObjCProtocolDecl::getImpliedProtocols( + llvm::DenseSet &IPs) const { + std::queue WorkQueue; + WorkQueue.push(this); + + while (!WorkQueue.empty()) { + const auto *PD = WorkQueue.front(); + WorkQueue.pop(); + for (const auto *Parent : PD->protocols()) { + const auto *Can = Parent->getCanonicalDecl(); + auto Result = IPs.insert(Can); + if (Result.second) + WorkQueue.push(Parent); + } + } +} + ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { ObjCProtocolDecl *PDecl = this; diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -445,6 +445,75 @@ Method); } +static void AppendFirstImpliedRuntimeProtocols( + const ObjCProtocolDecl *PD, + llvm::UniqueVector &PDs) { + if (!PD->isNonRuntimeProtocol()) { + const auto *Can = PD->getCanonicalDecl(); + PDs.insert(Can); + return; + } + + for (const auto *ParentPD : PD->protocols()) + AppendFirstImpliedRuntimeProtocols(ParentPD, PDs); +} + +std::vector +CGObjCRuntime::GetRuntimeProtocolList(ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end) { + std::vector RuntimePds; + llvm::DenseSet NonRuntimePDs; + + for (; begin != end; ++begin) { + const auto *It = *begin; + const auto *Can = It->getCanonicalDecl(); + if (Can->isNonRuntimeProtocol()) + NonRuntimePDs.insert(Can); + else + RuntimePds.push_back(Can); + } + + // If there are no non-runtime protocols then we can just stop now. + if (NonRuntimePDs.empty()) + return RuntimePds; + + // Else we have to search through the non-runtime protocol's inheritancy + // hierarchy DAG stopping whenever a branch either finds a runtime protocol or + // a non-runtime protocol without any parents. These are the "first-implied" + // protocols from a non-runtime protocol. + llvm::UniqueVector FirstImpliedProtos; + for (const auto *PD : NonRuntimePDs) + AppendFirstImpliedRuntimeProtocols(PD, FirstImpliedProtos); + + // Walk the Runtime list to get all protocols implied via the inclusion of + // this protocol, e.g. all protocols it inherits from including itself. + llvm::DenseSet AllImpliedProtocols; + for (const auto *PD : RuntimePds) { + const auto *Can = PD->getCanonicalDecl(); + AllImpliedProtocols.insert(Can); + Can->getImpliedProtocols(AllImpliedProtocols); + } + + // Similar to above, walk the list of first-implied protocols to find the set + // all the protocols implied excluding the listed protocols themselves since + // they are not yet a part of the `RuntimePds` list. + for (const auto *PD : FirstImpliedProtos) { + PD->getImpliedProtocols(AllImpliedProtocols); + } + + // From the first-implied list we have to finish building the final protocol + // list. If a protocol in the first-implied list was already implied via some + // inheritance path through some other protocols then it would be redundant to + // add it here and so we skip over it. + for (const auto *PD : FirstImpliedProtos) { + if (!AllImpliedProtocols.contains(PD)) { + RuntimePds.push_back(PD); + } + } + + return RuntimePds; +} + /// Instead of '[[MyClass alloc] init]', try to generate /// 'objc_alloc_init(MyClass)'. This provides a code size improvement on the /// caller side, as well as the optimized objc_alloc. diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -1187,8 +1187,11 @@ } llvm::Constant *GenerateCategoryProtocolList(const ObjCCategoryDecl *OCD) override { - SmallVector Protocols; - for (const auto *PI : OCD->getReferencedProtocols()) + const auto &ReferencedProtocols = OCD->getReferencedProtocols(); + auto RuntimeProtocols = GetRuntimeProtocolList(ReferencedProtocols.begin(), + ReferencedProtocols.end()); + SmallVector Protocols; + for (const auto *PI : RuntimeProtocols) Protocols.push_back( llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI), ProtocolPtrTy)); @@ -1371,7 +1374,9 @@ } SmallVector Protocols; - for (const auto *PI : PD->protocols()) + auto RuntimeProtocols = + GetRuntimeProtocolList(PD->protocol_begin(), PD->protocol_end()); + for (const auto *PI : RuntimeProtocols) Protocols.push_back( llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI), ProtocolPtrTy)); @@ -1910,8 +1915,10 @@ // struct objc_class *sibling_class classFields.addNullPointer(PtrTy); // struct objc_protocol_list *protocols; - SmallVector Protocols; - for (const auto *I : classDecl->protocols()) + auto RuntimeProtocols = GetRuntimeProtocolList(classDecl->protocol_begin(), + classDecl->protocol_end()); + SmallVector Protocols; + for (const auto *I : RuntimeProtocols) Protocols.push_back( llvm::ConstantExpr::getBitCast(GenerateProtocolRef(I), ProtocolPtrTy)); @@ -3076,6 +3083,9 @@ } void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { + if (PD->isNonRuntimeProtocol()) + return; + std::string ProtocolName = PD->getNameAsString(); // Use the protocol definition, if there is one. @@ -3228,8 +3238,11 @@ llvm::Constant *CGObjCGNU::GenerateCategoryProtocolList(const ObjCCategoryDecl *OCD) { + const auto &RefPro = OCD->getReferencedProtocols(); + const auto RuntimeProtos = + GetRuntimeProtocolList(RefPro.begin(), RefPro.end()); SmallVector Protocols; - for (const auto *PD : OCD->getReferencedProtocols()) + for (const auto *PD : RuntimeProtos) Protocols.push_back(PD->getNameAsString()); return GenerateProtocolList(Protocols); } @@ -3515,8 +3528,11 @@ llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl); // Collect the names of referenced protocols + auto RefProtocols = ClassDecl->protocols(); + auto RuntimeProtocols = + GetRuntimeProtocolList(RefProtocols.begin(), RefProtocols.end()); SmallVector Protocols; - for (const auto *I : ClassDecl->protocols()) + for (const auto *I : RuntimeProtocols) Protocols.push_back(I->getNameAsString()); // Get the superclass pointer. 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 @@ -32,6 +32,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/UniqueVector.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/IntrinsicInst.h" @@ -3196,7 +3197,8 @@ ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end) { // Just return null for empty protocol lists - if (begin == end) + auto PDs = GetRuntimeProtocolList(begin, end); + if (PDs.empty()) return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); ConstantInitBuilder builder(CGM); @@ -3209,9 +3211,9 @@ auto countSlot = values.addPlaceholder(); auto refsArray = values.beginArray(ObjCTypes.ProtocolPtrTy); - for (; begin != end; ++begin) { - refsArray.add(GetProtocolRef(*begin)); - } + for (const auto *Proto : PDs) + refsArray.add(GetProtocolRef(Proto)); + auto count = refsArray.size(); // This list is null terminated. @@ -6648,7 +6650,8 @@ // This routine is called for @protocol only. So, we must build definition // of protocol's meta-data (not a reference to it!) - // + assert(!PD->isNonRuntimeProtocol() && + "attempting to get a protocol ref to a static protocol."); llvm::Constant *Init = llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD), ObjCTypes.getExternalProtocolPtrTy()); @@ -7005,6 +7008,8 @@ const ObjCProtocolDecl *PD) { llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()]; + assert(!PD->isNonRuntimeProtocol() && + "attempting to GetOrEmit a non-runtime protocol"); if (!Entry) { // We use the initializer as a marker of whether this is a forward // reference or not. At module finalization we add the empty @@ -7148,10 +7153,20 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end) { + // Just return null for empty protocol lists + auto Protocols = GetRuntimeProtocolList(begin, end); + if (Protocols.empty()) + return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); + SmallVector ProtocolRefs; + ProtocolRefs.reserve(Protocols.size()); - // Just return null for empty protocol lists - if (begin == end) + for (const auto *PD : Protocols) + ProtocolRefs.push_back(GetProtocolRef(PD)); + + // If all of the protocols in the protocol list are objc_non_runtime_protocol + // just return null + if (ProtocolRefs.size() == 0) return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); // FIXME: We shouldn't need to do this lookup here, should we? @@ -7168,8 +7183,8 @@ // A null-terminated array of protocols. auto array = values.beginArray(ObjCTypes.ProtocolnfABIPtrTy); - for (; begin != end; ++begin) - array.add(GetProtocolRef(*begin)); // Implemented??? + for (auto const &proto : ProtocolRefs) + array.add(proto); auto count = array.size(); array.addNullPointer(ObjCTypes.ProtocolnfABIPtrTy); diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -20,6 +20,7 @@ #include "CGValue.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/IdentifierTable.h" // Selector +#include "llvm/ADT/UniqueVector.h" namespace llvm { class Constant; @@ -205,6 +206,16 @@ const CallArgList &CallArgs, const ObjCMethodDecl *Method = nullptr) = 0; + /// Walk the list of protocol references from a class, category or + /// protocol to traverse the DAG formed from it's inheritance hierarchy. Find + /// the list of protocols that ends each walk at either a runtime + /// protocol or a non-runtime protocol with no parents. For the common case of + /// just a list of standard runtime protocols this just returns the same list + /// that was passed in. + std::vector + GetRuntimeProtocolList(ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end); + /// Emit the code to return the named protocol as an object, as in a /// \@protocol expression. virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2617,6 +2617,11 @@ D->addAttr(newAttr); } +static void handleObjCNonRuntimeProtocolAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + handleSimpleAttribute(S, D, AL); +} + static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // objc_direct cannot be set on methods declared in the context of a protocol if (isa(D->getDeclContext())) { @@ -7665,6 +7670,9 @@ case ParsedAttr::AT_ObjCDirect: handleObjCDirectAttr(S, D, AL); break; + case ParsedAttr::AT_ObjCNonRuntimeProtocol: + handleObjCNonRuntimeProtocolAttr(S, D, AL); + break; case ParsedAttr::AT_ObjCDirectMembers: handleObjCDirectMembersAttr(S, D, AL); handleSimpleAttribute(S, D, AL); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1394,6 +1394,9 @@ Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; } + if (PDecl->isNonRuntimeProtocol()) + Diag(ProtoLoc, diag::err_objc_non_runtime_protocol_in_protocol_expr) + << PDecl; if (!PDecl->hasDefinition()) { Diag(ProtoLoc, diag::err_atprotocol_protocol) << PDecl; Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl; diff --git a/clang/test/CodeGenObjC/non-runtime-protocol.m b/clang/test/CodeGenObjC/non-runtime-protocol.m new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenObjC/non-runtime-protocol.m @@ -0,0 +1,142 @@ +// RUN: not %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -DPROTOEXPR -o - 2>&1 \ +// RUN: | FileCheck -check-prefix=PROTOEXPR %s + +// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -DREDUNDANCY -o - \ +// RUN: | FileCheck -check-prefix=REDUNDANCY1 %s +// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -DREDUNDANCY -o - \ +// RUN: | FileCheck -check-prefix=REDUNDANCY2 %s + +// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -DBASE -o - \ +// RUN: | FileCheck -check-prefix=NONFRAGILE %s +// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -DINHERITANCE -o - \ +// RUN: | FileCheck -check-prefix=INHERITANCE %s + +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 %s -DBASE -o - \ +// RUN: | FileCheck -check-prefix=FRAGILE %s +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 %s -DINHERITANCE -o - \ +// RUN: | FileCheck -check-prefix=FRAGILEINHERITANCE %s + +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -fobjc-runtime=gnustep %s -DBASE -o - \ +// RUN: | FileCheck -check-prefix=GNU %s +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -fobjc-runtime=gnustep %s -DINHERITANCE -o - \ +// RUN: | FileCheck -check-prefix=GNUINHERITANCE %s +// +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -fobjc-runtime=gnustep-2 %s -DBASE -o - \ +// RUN: | FileCheck -check-prefix=GNU2 %s +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -fobjc-runtime=gnustep-2 %s -DINHERITANCE -o - \ +// RUN: | FileCheck -check-prefix=GNU2INHERITANCE %s + +__attribute__((objc_root_class)) +@interface Root +@end +@implementation Root +@end + +#ifdef REDUNDANCY +// REDUNDANCY1-NOT: _OBJC_CLASS_PROTOCOLS_$_Implementer{{.*}}_OBJC_PROTOCOL_$_B +// REDUNDANCY2: _OBJC_CLASS_PROTOCOLS_$_Implementer{{.*}}_OBJC_PROTOCOL_$_C{{.*}}_OBJC_PROTOCOL_$_A +@protocol C +@end +@protocol B +@end +@protocol A +@end +__attribute__((objc_non_runtime_protocol)) @protocol Alpha +@end +__attribute__((objc_non_runtime_protocol)) @protocol Beta +@end +@interface Implementer : Root +@end +@implementation Implementer +@end +#endif + +#ifdef BASE +// Confirm that we're not emitting protocol information for the +// NONFRAGILE-NOT: OBJC_CLASS_NAME{{.*}}NonRuntimeProtocol +// NONFRAGILE-NOT: _OBJC_$_PROTOCOL_INSTANCE_METHODS_NonRuntimeProtocol +// NONFRAGILE-NOT: _OBJC_$_PROTOCOL_CLASS_METHODS_NonRuntimeProtocol +// NONFRAGILE-NOT: _OBJC_PROTOCOL_$_NonRuntimeProtocol +// NONFRAGILE-NOT: _OBJC_LABEL_PROTOCOL_$_NonRuntimeProtocol +// NONFRAGILE-NOT: _OBJC_CLASS_PROTOCOLS_$_NonRuntimeImplementer +// FRAGILE-NOT: OBJC_CLASS_NAME_.{{.*}}"Runtime\00" +// FRAGILE-NOT: OBJC_PROTOCOL_NonRuntime +// FRAGILE_NOT: OBJC_PROTOCOLS_NonRuntimeImplementer +// GNU-NOT: private unnamed_addr constant {{.*}} c"NonRuntimeProtocol\00" +// GNU-NOT: @.objc_protocol {{.*}} +// GNU2-NOT: private unnamed_addr constant {{.*}} c"NonRuntimeProtocol\00" +// GNU2-NOT: @.objc_protocol {{.*}} +__attribute__((objc_non_runtime_protocol)) +@protocol NonRuntimeProtocol +- (void)doThing; ++ (void)doClassThing; +@end +// NONFRAGILE: @"_OBJC_METACLASS_RO_$_NonRuntimeImplementer" {{.*}} %struct._objc_protocol_list* null +// NONFRAGILE: @"_OBJC_CLASS_RO_$_NonRuntimeImplementer" {{.*}} %struct._objc_protocol_list* null +@interface NonRuntimeImplementer : Root +- (void)doThing; ++ (void)doClassThing; +@end + +@implementation NonRuntimeImplementer +- (void)doThing { +} ++ (void)doClassThing { +} +@end +#endif + +#ifdef PROTOEXPR +__attribute__((objc_non_runtime_protocol)) +@protocol NonRuntimeProtocol +@end +void use() { + // PROTOEXPR: cannot use a protocol declared 'objc_non_runtime_protocol' in a @protocol expression + Protocol *p = @protocol(NonRuntimeProtocol); +} +#endif + +#ifdef INHERITANCE +// Confirm that we only emit references to the non-runtime protocols and +// properly walk the DAG to find the right protocols. +// INHERITANCE: OBJC_PROTOCOL_$_R2{{.*}} +// INHERITANCE: OBJC_PROTOCOL_$_R3{{.*}} +// INHERITANCE: @"_OBJC_CLASS_PROTOCOLS_$_Implementer" {{.*}}_OBJC_PROTOCOL_$_R2{{.*}}_OBJC_PROTOCOL_$_R3 + +// FRAGILEINHERITANCE: OBJC_PROTOCOL_R2 +// FRAGILEINHERITANCE: OBJC_PROTOCOL_R3 +// FRAGILEINHERITANCE: OBJC_CLASS_PROTOCOLS_Implementer{{.*}}OBJC_PROTOCOL_R2{{.*}}OBJC_PROTOCOL_R3 + +// GNUINHERITANCE-DAG: @[[Proto1:[0-9]]]{{.*}}c"R1\00" +// GNUINHERITANCE-DAG: [[P1Name:@.objc_protocol.[0-9]*]]{{.*}}@[[Proto1]] +// GNUINHERITANCE-DAG: @[[Proto2:[0-9]]]{{.*}}c"R2\00" +// GNUINHERITANCE-DAG: [[P2Name:@.objc_protocol.[0-9]+]]{{.*}}@[[Proto2]] +// GNUINHERITANCE-DAG: @[[Proto3:[0-9]]]{{.*}}c"R3\00" +// GNUINHERITANCE-DAG: [[P3Name:@.objc_protocol.[0-9]+]]{{.*}}@[[Proto3]] +// GNUINHERITANCE-DAG: @.objc_protocol_list{{.*}} +// GNUINHERITANCE: @.objc_protocol_list{{.*}}[[Proto3]]{{.*}}[[Proto2]] + +// GNU2INHERITANCE-DAG: @[[Proto1:[0-9]]]{{.*}}c"R1\00" +// GNU2INHERITANCE-DAG: _OBJC_PROTOCOL_R1{{.*}}@[[Proto1]] +// GNU2INHERITANCE-DAG: @[[Proto2:[0-9]]]{{.*}}c"R2\00" +// GNU2INHERITANCE-DAG: _OBJC_PROTOCOL_R2{{.*}}@[[Proto2]] +// GNU2INHERITANCE-DAG: @[[Proto3:[0-9]]]{{.*}}c"R3\00" +// GNU2INHERITANCE-DAG: _OBJC_PROTOCOL_R3{{.*}}@[[Proto3]] +// GNU2INHERITANCE: @.objc_protocol_list{{.*}}_OBJC_PROTOCOL_R2{{.*}}_OBJC_PROTOCOL_R3 +@protocol R1 +@end +@protocol R2 +@end +@protocol R3 +@end +__attribute__((objc_non_runtime_protocol)) @protocol N3 +@end +__attribute__((objc_non_runtime_protocol)) @protocol N1 +@end +__attribute__((objc_non_runtime_protocol)) @protocol N2 +@end +@interface Implementer : Root +@end +@implementation Implementer +@end +#endif diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -118,6 +118,7 @@ // CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method) // CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method) // CHECK-NEXT: ObjCNonLazyClass (SubjectMatchRule_objc_interface, SubjectMatchRule_objc_implementation) +// CHECK-NEXT: ObjCNonRuntimeProtocol (SubjectMatchRule_objc_protocol) // CHECK-NEXT: ObjCPreciseLifetime (SubjectMatchRule_variable) // CHECK-NEXT: ObjCRequiresPropertyDefs (SubjectMatchRule_objc_interface) // CHECK-NEXT: ObjCRequiresSuper (SubjectMatchRule_objc_method)