diff options
-rw-r--r-- | clang/include/clang/Basic/Attr.td | 9 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 26 | ||||
-rw-r--r-- | clang/test/Misc/pragma-attribute-supported-attributes-list.test | 1 | ||||
-rw-r--r-- | clang/test/SemaObjC/attr-designated-init.m | 15 |
5 files changed, 43 insertions, 11 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 015d5f7d66a..849d2c228b3 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -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]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 71f205de349..c01b0a5db4b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 859ef80807c..1440b6c433e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -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. diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 22ad3ac9872..45012ae9bfd 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -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) diff --git a/clang/test/SemaObjC/attr-designated-init.m b/clang/test/SemaObjC/attr-designated-init.m index 05085884784..3558916dbe5 100644 --- a/clang/test/SemaObjC/attr-designated-init.m +++ b/clang/test/SemaObjC/attr-designated-init.m @@ -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 |