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<const ObjCProtocolDecl *> &IPs) const;
+
ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName);
// Lookup a method. First, we search locally. If a method isn't
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>;
}];
}
+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 = [{
"string is ill-formed as UTF-8 and will become a null %0 when boxed">,
InGroup<ObjCBoxing>;
+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">;
#include <cassert>
#include <cstdint>
#include <cstring>
+#include <queue>
#include <utility>
using namespace clang;
return Result;
}
+bool ObjCProtocolDecl::isNonRuntimeProtocol() const {
+ return hasAttr<ObjCNonRuntimeProtocolAttr>();
+}
+
+void ObjCProtocolDecl::getImpliedProtocols(
+ llvm::DenseSet<const ObjCProtocolDecl *> &IPs) const {
+ std::queue<const ObjCProtocolDecl *> 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;
Method);
}
+static void AppendFirstImpliedRuntimeProtocols(
+ const ObjCProtocolDecl *PD,
+ llvm::UniqueVector<const ObjCProtocolDecl *> &PDs) {
+ if (!PD->isNonRuntimeProtocol()) {
+ const auto *Can = PD->getCanonicalDecl();
+ PDs.insert(Can);
+ return;
+ }
+
+ for (const auto *ParentPD : PD->protocols())
+ AppendFirstImpliedRuntimeProtocols(ParentPD, PDs);
+}
+
+std::vector<const ObjCProtocolDecl *>
+CGObjCRuntime::GetRuntimeProtocolList(ObjCProtocolDecl::protocol_iterator begin,
+ ObjCProtocolDecl::protocol_iterator end) {
+ std::vector<const ObjCProtocolDecl *> RuntimePds;
+ llvm::DenseSet<const ObjCProtocolDecl *> 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<const ObjCProtocolDecl *> 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<const ObjCProtocolDecl *> 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.
}
llvm::Constant *GenerateCategoryProtocolList(const ObjCCategoryDecl *OCD)
override {
- SmallVector<llvm::Constant*, 16> Protocols;
- for (const auto *PI : OCD->getReferencedProtocols())
+ const auto &ReferencedProtocols = OCD->getReferencedProtocols();
+ auto RuntimeProtocols = GetRuntimeProtocolList(ReferencedProtocols.begin(),
+ ReferencedProtocols.end());
+ SmallVector<llvm::Constant *, 16> Protocols;
+ for (const auto *PI : RuntimeProtocols)
Protocols.push_back(
llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI),
ProtocolPtrTy));
}
SmallVector<llvm::Constant*, 16> 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));
// struct objc_class *sibling_class
classFields.addNullPointer(PtrTy);
// struct objc_protocol_list *protocols;
- SmallVector<llvm::Constant*, 16> Protocols;
- for (const auto *I : classDecl->protocols())
+ auto RuntimeProtocols = GetRuntimeProtocolList(classDecl->protocol_begin(),
+ classDecl->protocol_end());
+ SmallVector<llvm::Constant *, 16> Protocols;
+ for (const auto *I : RuntimeProtocols)
Protocols.push_back(
llvm::ConstantExpr::getBitCast(GenerateProtocolRef(I),
ProtocolPtrTy));
}
void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
+ if (PD->isNonRuntimeProtocol())
+ return;
+
std::string ProtocolName = PD->getNameAsString();
// Use the protocol definition, if there is one.
llvm::Constant *CGObjCGNU::GenerateCategoryProtocolList(const
ObjCCategoryDecl *OCD) {
+ const auto &RefPro = OCD->getReferencedProtocols();
+ const auto RuntimeProtos =
+ GetRuntimeProtocolList(RefPro.begin(), RefPro.end());
SmallVector<std::string, 16> Protocols;
- for (const auto *PD : OCD->getReferencedProtocols())
+ for (const auto *PD : RuntimeProtos)
Protocols.push_back(PD->getNameAsString());
return GenerateProtocolList(Protocols);
}
llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl);
// Collect the names of referenced protocols
+ auto RefProtocols = ClassDecl->protocols();
+ auto RuntimeProtocols =
+ GetRuntimeProtocolList(RefProtocols.begin(), RefProtocols.end());
SmallVector<std::string, 16> Protocols;
- for (const auto *I : ClassDecl->protocols())
+ for (const auto *I : RuntimeProtocols)
Protocols.push_back(I->getNameAsString());
// Get the superclass pointer.
#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"
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);
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.
// 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());
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
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<llvm::Constant *, 16> 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?
// 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);
#include "CGValue.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/IdentifierTable.h" // Selector
+#include "llvm/ADT/UniqueVector.h"
namespace llvm {
class Constant;
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<const ObjCProtocolDecl *>
+ 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,
D->addAttr(newAttr);
}
+static void handleObjCNonRuntimeProtocolAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ handleSimpleAttribute<ObjCNonRuntimeProtocolAttr>(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<ObjCProtocolDecl>(D->getDeclContext())) {
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<ObjCDirectMembersAttr>(S, D, AL);
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;
--- /dev/null
+// 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 <C>
+@end
+@protocol A <B>
+@end
+__attribute__((objc_non_runtime_protocol)) @protocol Alpha<A>
+@end
+__attribute__((objc_non_runtime_protocol)) @protocol Beta<B>
+@end
+@interface Implementer : Root <Alpha, Beta, C>
+@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 <NonRuntimeProtocol>
+- (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 <R1>
+@end
+__attribute__((objc_non_runtime_protocol)) @protocol N3
+@end
+__attribute__((objc_non_runtime_protocol)) @protocol N1<R3, R2, N3>
+@end
+__attribute__((objc_non_runtime_protocol)) @protocol N2<N1, R2>
+@end
+@interface Implementer : Root <N2, R2>
+@end
+@implementation Implementer
+@end
+#endif
// 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)