From: Alex Lorenz Date: Fri, 28 Oct 2016 10:25:10 +0000 (+0000) Subject: [Objective-C] Add objc_subclassing_restricted attribute X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8cebf7af3758abd9f03878d3f98099187d1f90e0;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@285391 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 3376f640a1..709af0a6db 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -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>; diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index 44e0a8e400..f6ebda7656 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -2667,3 +2667,11 @@ transparent union should have the same calling convention as its first member. 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. + }]; +} diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 29a3e08991..a715731f23 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 9413b6e51a..936c29767d 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -5776,6 +5776,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, 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; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 79cdd6ead9..1b030801f2 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -3853,6 +3853,18 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, 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 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, 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. diff --git a/test/SemaObjC/subclassing-restricted-attr.m b/test/SemaObjC/subclassing-restricted-attr.m new file mode 100644 index 0000000000..d0db5e452f --- /dev/null +++ b/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