]> granicus.if.org Git - clang/commitdiff
[Sema] Delay checking whether objc_designated_initializer is being applied to an...
authorErik Pilkington <erik.pilkington@gmail.com>
Wed, 13 Feb 2019 20:32:37 +0000 (20:32 +0000)
committerErik Pilkington <erik.pilkington@gmail.com>
Wed, 13 Feb 2019 20:32:37 +0000 (20:32 +0000)
This fixes a regression that was caused by r335084, which reversed
the order that attributes are applied. objc_method_family can change
whether a method is an init method, so the order that these
attributes are applied matters. The commit fixes this by delaying the
init check until after all attributes have been applied.

rdar://47829358

Differential revision: https://reviews.llvm.org/D58152

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@353976 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclAttr.cpp
test/Misc/pragma-attribute-supported-attributes-list.test
test/SemaObjC/attr-designated-init.m

index 015d5f7d66ac31365d8cbc73d4101ef85ca2fc04..849d2c228b3225da67fddc25161a332c1d2f2acd 100644 (file)
@@ -102,13 +102,6 @@ def ObjCInstanceMethod : SubsetSubject<ObjCMethod,
                                        [{S->isInstanceMethod()}],
                                        "Objective-C instance methods">;
 
-def ObjCInterfaceDeclInitMethod : SubsetSubject<ObjCMethod,
-                               [{S->getMethodFamily() == OMF_init &&
-                                 (isa<ObjCInterfaceDecl>(S->getDeclContext()) ||
-                                  (isa<ObjCCategoryDecl>(S->getDeclContext()) &&
-            cast<ObjCCategoryDecl>(S->getDeclContext())->IsClassExtension()))}],
-            "init methods of interface or class extension declarations">;
-
 def Struct : SubsetSubject<Record,
                            [{!S->isUnion()}], "structs">;
 
@@ -1786,7 +1779,7 @@ def ObjCExplicitProtocolImpl : InheritableAttr {
 
 def ObjCDesignatedInitializer : Attr {
   let Spellings = [Clang<"objc_designated_initializer">];
-  let Subjects = SubjectList<[ObjCInterfaceDeclInitMethod], ErrorDiag>;
+  let Subjects = SubjectList<[ObjCMethod], ErrorDiag>;
   let Documentation = [Undocumented];
 }
 
index 71f205de3497d599a211028bbbe38aeec5506f27..c01b0a5db4ba64d1bc727f03ab0f41828851f715 100644 (file)
@@ -3481,6 +3481,9 @@ def warn_objc_secondary_init_missing_init_call : Warning<
 def warn_objc_implementation_missing_designated_init_override : Warning<
   "method override for the designated initializer of the superclass %objcinstance0 not found">,
   InGroup<ObjCDesignatedInit>;
+def err_designated_init_attr_non_init : Error<
+  "'objc_designated_initializer' attribute only applies to init methods "
+  "of interface or class extension declarations">;
 
 // objc_bridge attribute diagnostics.
 def err_objc_attr_not_id : Error<
index 859ef80807c1e63d283e342c41da42cad65b65b4..1440b6c433ef8af40bad112f49edd0ebc23e7283 100644 (file)
@@ -5249,11 +5249,22 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
 
 static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
                                             const ParsedAttr &AL) {
+  DeclContext *Ctx = D->getDeclContext();
+
+  // This attribute can only be applied to methods in interfaces or class
+  // extensions.
+  if (!isa<ObjCInterfaceDecl>(Ctx) &&
+      !(isa<ObjCCategoryDecl>(Ctx) &&
+        cast<ObjCCategoryDecl>(Ctx)->IsClassExtension())) {
+    S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
+    return;
+  }
+
   ObjCInterfaceDecl *IFace;
-  if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))
+  if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(Ctx))
     IFace = CatDecl->getClassInterface();
   else
-    IFace = cast<ObjCInterfaceDecl>(D->getDeclContext());
+    IFace = cast<ObjCInterfaceDecl>(Ctx);
 
   if (!IFace)
     return;
@@ -7243,6 +7254,17 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
       }
     }
   }
+
+  // Do this check after processing D's attributes because the attribute
+  // objc_method_family can change whether the given method is in the init
+  // family, and it can be applied after objc_designated_initializer. This is a
+  // bit of a hack, but we need it to be compatible with versions of clang that
+  // processed the attribute list in the wrong order.
+  if (D->hasAttr<ObjCDesignatedInitializerAttr>() &&
+      cast<ObjCMethodDecl>(D)->getMethodFamily() != OMF_init) {
+    Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
+    D->dropAttr<ObjCDesignatedInitializerAttr>();
+  }
 }
 
 // Helper for delayed processing TransparentUnion attribute.
index 22ad3ac987230a23cb906f217e76f1b9511ce9e2..45012ae9bfdd1153acd3d6e0944553951feea09d 100644 (file)
@@ -97,6 +97,7 @@
 // CHECK-NEXT: ObjCBridge (SubjectMatchRule_record, SubjectMatchRule_type_alias)
 // CHECK-NEXT: ObjCBridgeMutable (SubjectMatchRule_record)
 // CHECK-NEXT: ObjCBridgeRelated (SubjectMatchRule_record)
+// CHECK-NEXT: ObjCDesignatedInitializer (SubjectMatchRule_objc_method)
 // CHECK-NEXT: ObjCException (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol)
 // CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method)
index 05085884784b01ba6a3c133b749f4394bc57a18d..3558916dbe54a615175c7bcd3284761aa351d6ac 100644 (file)
@@ -3,7 +3,7 @@
 #define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
 #define NS_UNAVAILABLE __attribute__((unavailable))
 
-void fnfoo(void) NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to init methods of interface or class extension declarations}}
+void fnfoo(void) NS_DESIGNATED_INITIALIZER; // expected-error {{'objc_designated_initializer' attribute only applies to Objective-C methods}}
 
 @protocol P1
 -(id)init NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to init methods of interface or class extension declarations}}
@@ -428,3 +428,16 @@ __attribute__((objc_root_class))
 @interface CategoryForMissingInterface(Cat) // expected-error{{cannot find interface declaration}}
 - (instancetype)init NS_DESIGNATED_INITIALIZER; // expected-error{{only applies to init methods of interface or class extension declarations}}
 @end
+
+@interface TwoAttrs
+-(instancetype)foo
+    __attribute__((objc_designated_initializer))
+    __attribute__((objc_method_family(init)));
+-(instancetype)bar
+    __attribute__((objc_method_family(init)))
+    __attribute__((objc_designated_initializer));
+-(instancetype)baz
+  __attribute__((objc_designated_initializer, objc_method_family(init)));
+-(instancetype)quux
+  __attribute__((objc_method_family(init), objc_designated_initializer));
+@end