Index: cfe/trunk/include/clang/Basic/Attr.td =================================================================== --- cfe/trunk/include/clang/Basic/Attr.td +++ cfe/trunk/include/clang/Basic/Attr.td @@ -1285,6 +1285,12 @@ let Documentation = [Undocumented]; } +def ObjCSubclassingRestricted : InheritableAttr { + let Spellings = [GNU<"objc_subclassing_restricted">]; + let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; + let Documentation = [ObjCSubclassingRestrictedDocs]; +} + def ObjCExplicitProtocolImpl : InheritableAttr { let Spellings = [GNU<"objc_protocol_requires_explicit_implementation">]; let Subjects = SubjectList<[ObjCProtocol], ErrorDiag>; Index: cfe/trunk/include/clang/Basic/AttrDocs.td =================================================================== --- cfe/trunk/include/clang/Basic/AttrDocs.td +++ cfe/trunk/include/clang/Basic/AttrDocs.td @@ -2667,3 +2667,11 @@ Transparent unions are not supported in C++. }]; } + +def ObjCSubclassingRestrictedDocs : Documentation { + let Category = DocCatType; + let Content = [{ +This attribute can be added to an Objective-C ``@interface`` declaration to +ensure that this class cannot be subclassed. + }]; +} Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -781,6 +781,9 @@ "class with specified objc_requires_property_definitions attribute is declared here">; def err_objc_root_class_subclass : Error< "objc_root_class attribute may only be specified on a root class declaration">; +def err_restricted_superclass_mismatch : Error< + "cannot subclass a class that was declared with the " + "'objc_subclassing_restricted' attribute">; def warn_objc_root_class_missing : Warning< "class %0 defined without specifying a base class">, InGroup; Index: cfe/trunk/lib/Sema/SemaDeclAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp @@ -5776,6 +5776,9 @@ case AttributeList::AT_ObjCRootClass: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_ObjCSubclassingRestricted: + handleSimpleAttribute(S, D, Attr); + break; case AttributeList::AT_ObjCExplicitProtocolImpl: handleObjCSuppresProtocolAttr(S, D, Attr); break; Index: cfe/trunk/lib/Sema/SemaDeclObjC.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp @@ -3853,6 +3853,18 @@ Diag(IDecl->getLocation(), diag::err_objc_root_class_subclass); } + if (const ObjCInterfaceDecl *Super = IDecl->getSuperClass()) { + // An interface can subclass another interface with a + // objc_subclassing_restricted attribute when it has that attribute as + // well (because of interfaces imported from Swift). Therefore we have + // to check if we can subclass in the implementation as well. + if (IDecl->hasAttr() && + Super->hasAttr()) { + Diag(IC->getLocation(), diag::err_restricted_superclass_mismatch); + Diag(Super->getLocation(), diag::note_class_declared); + } + } + if (LangOpts.ObjCRuntime.isNonFragile()) { while (IDecl->getSuperClass()) { DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass()); @@ -3873,6 +3885,14 @@ ImplMethodsVsClassMethods(S, CatImplClass, Cat); } } + } else if (const auto *IntfDecl = dyn_cast(ClassDecl)) { + if (const ObjCInterfaceDecl *Super = IntfDecl->getSuperClass()) { + if (!IntfDecl->hasAttr() && + Super->hasAttr()) { + Diag(IntfDecl->getLocation(), diag::err_restricted_superclass_mismatch); + Diag(Super->getLocation(), diag::note_class_declared); + } + } } if (isInterfaceDeclKind) { // Reject invalid vardecls. Index: cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m =================================================================== --- cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m +++ cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s +// rdar://16560476 + +__attribute__((objc_subclassing_restricted)) +@interface Leaf // okay +@end + +__attribute__((objc_subclassing_restricted)) +@interface SubClassOfLeaf : Leaf // expected-note {{class is declared here}} +@end + + +@interface SubClass : SubClassOfLeaf // expected-error {{cannot subclass a class that was declared with the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_root_class)) +@interface PlainRoot +@end + +__attribute__((objc_subclassing_restricted)) +@interface Sub2Class : PlainRoot // okay +@end + +// rdar://28753587 +__attribute__((objc_subclassing_restricted)) +@interface SuperImplClass // expected-note {{class is declared here}} +@end +@implementation SuperImplClass +@end + +__attribute__((objc_subclassing_restricted)) +@interface SubImplClass : SuperImplClass +@end +@implementation SubImplClass // expected-error {{cannot subclass a class that was declared with the 'objc_subclassing_restricted' attribute}} +@end