Author: arphaman Date: Fri Oct 28 05:25:10 2016 New Revision: 285391 URL: http://llvm.org/viewvc/llvm-project?rev=285391&view=rev Log: [Objective-C] Add objc_subclassing_restricted attribute
This patch adds an objc_subclassing_restricted attribute into clang. This attribute acts similarly to 'final' - Objective-C classes with this attribute can't be subclassed. However, @interface declarations that have objc_subclassing_restricted but don't have @implementation are allowed to inherit other @interface declarations with objc_subclassing_restricted. This is needed to describe the Swift class hierarchy in clang while making sure that the Objective-C classes cannot subclass the Swift classes. This attribute is already implemented in a fork of clang that's used for Swift (https://github.com/apple/swift-clang) and this patch moves that code to the upstream clang repository. rdar://28937548 Differential Revision: https://reviews.llvm.org/D25993 Added: cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m Modified: cfe/trunk/include/clang/Basic/Attr.td cfe/trunk/include/clang/Basic/AttrDocs.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/lib/Sema/SemaDeclObjC.cpp Modified: cfe/trunk/include/clang/Basic/Attr.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=285391&r1=285390&r2=285391&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Attr.td (original) +++ cfe/trunk/include/clang/Basic/Attr.td Fri Oct 28 05:25:10 2016 @@ -1285,6 +1285,12 @@ def ObjCRootClass : InheritableAttr { 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>; Modified: cfe/trunk/include/clang/Basic/AttrDocs.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=285391&r1=285390&r2=285391&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/AttrDocs.td (original) +++ cfe/trunk/include/clang/Basic/AttrDocs.td Fri Oct 28 05:25:10 2016 @@ -2667,3 +2667,11 @@ transparent union should have the same c 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. + }]; +} Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=285391&r1=285390&r2=285391&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Oct 28 05:25:10 2016 @@ -781,6 +781,9 @@ def note_suppressed_class_declare : Note "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<ObjCRootClass>; Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=285391&r1=285390&r2=285391&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Oct 28 05:25:10 2016 @@ -5776,6 +5776,9 @@ static void ProcessDeclAttribute(Sema &S case AttributeList::AT_ObjCRootClass: handleSimpleAttribute<ObjCRootClassAttr>(S, D, Attr); break; + case AttributeList::AT_ObjCSubclassingRestricted: + handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, Attr); + break; case AttributeList::AT_ObjCExplicitProtocolImpl: handleObjCSuppresProtocolAttr(S, D, Attr); break; Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=285391&r1=285390&r2=285391&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Fri Oct 28 05:25:10 2016 @@ -3853,6 +3853,18 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceR 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<ObjCSubclassingRestrictedAttr>() && + Super->hasAttr<ObjCSubclassingRestrictedAttr>()) { + 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 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceR ImplMethodsVsClassMethods(S, CatImplClass, Cat); } } + } else if (const auto *IntfDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { + if (const ObjCInterfaceDecl *Super = IntfDecl->getSuperClass()) { + if (!IntfDecl->hasAttr<ObjCSubclassingRestrictedAttr>() && + Super->hasAttr<ObjCSubclassingRestrictedAttr>()) { + Diag(IntfDecl->getLocation(), diag::err_restricted_superclass_mismatch); + Diag(Super->getLocation(), diag::note_class_declared); + } + } } if (isInterfaceDeclKind) { // Reject invalid vardecls. Added: cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m?rev=285391&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m (added) +++ cfe/trunk/test/SemaObjC/subclassing-restricted-attr.m Fri Oct 28 05:25:10 2016 @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits