diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index df8c4edc2c85..2268fa64789c 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -684,6 +684,11 @@ def ObjCSuppressProtocol : InheritableAttr { let Args = [IdentifierArgument<"Protocol">]; } +def ObjCDesignatedInitializer : Attr { + let Spellings = [GNU<"objc_designated_initializer">]; + let Subjects = SubjectList<[ObjCMethod], ErrorDiag>; +} + def Overloadable : Attr { let Spellings = [GNU<"overloadable">]; let Subjects = SubjectList<[Function], ErrorDiag>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a22df2b1af69..8315c78f259e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2427,6 +2427,12 @@ def warn_objc_requires_super_protocol : Warning< def note_protocol_decl : Note< "protocol is declared here">; +// objc_designated_initializer attribute diagnostics. +def err_attr_objc_designated_not_init_family : Error< + "'objc_designated_initializer' only applies to methods of the init family">; +def err_attr_objc_designated_not_interface : Error< + "'objc_designated_initializer' only applies to methods of interface declarations">; + def err_ns_bridged_not_interface : Error< "parameter of 'ns_bridged' attribute does not name an Objective-C class">; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 24f9f5fd2520..b732fccacf89 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3713,6 +3713,28 @@ static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleObjCDesignatedInitializer(Sema &S, Decl *D, + const AttributeList &Attr) { + SourceLocation Loc = Attr.getLoc(); + ObjCMethodDecl *Method = cast(D); + + if (Method->getMethodFamily() != OMF_init) { + S.Diag(D->getLocStart(), diag::err_attr_objc_designated_not_init_family) + << SourceRange(Loc, Loc); + return; + } + DeclContext *DC = Method->getDeclContext(); + if (!isa(DC)) { + S.Diag(D->getLocStart(), diag::err_attr_objc_designated_not_interface) + << SourceRange(Loc, Loc); + return; + } + + Method->addAttr(::new (S.Context) + ObjCDesignatedInitializerAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); +} + static void handleObjCOwnershipAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (hasDeclarator(D)) return; @@ -3963,6 +3985,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ObjCBridgeMutable: handleObjCBridgeMutableAttr(S, scope, D, Attr); break; + case AttributeList::AT_ObjCDesignatedInitializer: + handleObjCDesignatedInitializer(S, D, Attr); break; + case AttributeList::AT_CFAuditedTransfer: handleCFAuditedTransferAttr(S, D, Attr); break; case AttributeList::AT_CFUnknownTransfer: diff --git a/clang/test/SemaObjC/attr-designated-init.m b/clang/test/SemaObjC/attr-designated-init.m new file mode 100644 index 000000000000..f607bb694472 --- /dev/null +++ b/clang/test/SemaObjC/attr-designated-init.m @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) + +void fnfoo(void) NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to methods}} + +@protocol P1 +-(id)init NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to methods of interface declarations}} +@end + +__attribute__((objc_root_class)) +@interface I1 +-(void)meth NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to methods of the init family}} +-(id)init NS_DESIGNATED_INITIALIZER; ++(id)init NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to methods of the init family}} +@end + +@interface I1(cat) +-(id)init2 NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to methods of interface declarations}} +@end + +@interface I1() +-(id)init3 NS_DESIGNATED_INITIALIZER; // expected-error {{only applies to methods of interface declarations}} +@end + +@implementation I1 +-(void)meth {} +-(id)init NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}} ++(id)init { return 0; } +-(id)init3 { return 0; } +-(id)init4 NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}} +@end