diff options
-rw-r--r-- | include/clang/Basic/Attr.td | 9 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 1 | ||||
-rw-r--r-- | include/clang/Sema/AttributeList.h | 1 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 16 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/AttributeList.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 48 |
7 files changed, 77 insertions, 0 deletions
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 57e5be4ae8..282c5082ed 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -369,6 +369,15 @@ def ObjCException : InheritableAttr { let Spellings = ["objc_exception"]; } +def ObjCMethodFamily : InheritableAttr { + let Spellings = ["objc_method_family"]; + let Subjects = [ObjCMethod]; + let Args = [EnumArgument<"Family", "FamilyKind", + ["none", "alloc", "copy", "init", "mutableCopy", "new"], + ["OMF_None", "OMF_alloc", "OMF_copy", "OMF_init", + "OMF_mutableCopy", "OMF_new"]>]; +} + def ObjCNSObject : InheritableAttr { let Spellings = ["NSObject"]; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8c36f37513..68b2447024 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1028,6 +1028,7 @@ def err_format_attribute_result_not : Error<"function does not return %0">; def err_format_attribute_implicit_this_format_string : Error< "format attribute cannot specify the implicit this argument as the format " "string">; +def warn_unknown_method_family : Warning<"unrecognized method family">; def err_attribute_invalid_size : Error< "vector size not an integral multiple of component size">; def err_attribute_zero_size : Error<"zero vector size">; diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 45ee579a02..10b859e9f9 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -125,6 +125,7 @@ public: AT_nothrow, AT_nsobject, AT_objc_exception, + AT_objc_method_family, AT_cf_returns_not_retained, // Clang-specific. AT_cf_returns_retained, // Clang-specific. AT_ns_returns_not_retained, // Clang-specific. diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 3a7c2a6e70..e9d537029b 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -403,6 +403,22 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { if (family != InvalidObjCMethodFamily) return family; + // Check for an explicit attribute. + if (const ObjCMethodFamilyAttr *attr = getAttr<ObjCMethodFamilyAttr>()) { + // The unfortunate necessity of mapping between enums here is due + // to the attributes framework. + switch (attr->getFamily()) { + case ObjCMethodFamilyAttr::OMF_None: family = OMF_None; break; + case ObjCMethodFamilyAttr::OMF_alloc: family = OMF_alloc; break; + case ObjCMethodFamilyAttr::OMF_copy: family = OMF_copy; break; + case ObjCMethodFamilyAttr::OMF_init: family = OMF_init; break; + case ObjCMethodFamilyAttr::OMF_mutableCopy: family = OMF_mutableCopy; break; + case ObjCMethodFamilyAttr::OMF_new: family = OMF_new; break; + } + Family = static_cast<unsigned>(family); + return family; + } + family = getSelector().getMethodFamily(); switch (family) { case OMF_None: break; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 374f85d8b8..10abfb4b83 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -540,6 +540,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("attribute_ns_consumed", true) .Case("attribute_cf_consumed", true) .Case("attribute_objc_ivar_unused", true) + .Case("attribute_objc_method_family", true) .Case("attribute_overloadable", true) .Case("attribute_unavailable_with_message", true) .Case("blocks", LangOpts.Blocks) diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index c0a305365a..1663fd58a9 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -98,6 +98,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("returns_twice", IgnoredAttribute) .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) + .Case("objc_method_family", AT_objc_method_family) .Case("ext_vector_type", AT_ext_vector_type) .Case("neon_vector_type", AT_neon_vector_type) .Case("neon_polyvector_type", AT_neon_polyvector_type) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 893cf6ac26..db4bc3e4af 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1094,6 +1094,51 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type)); } +static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr, + Sema &S) { + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl); + if (!method) { + S.Diag(attr.getLoc(), diag::err_attribute_wrong_decl_type) + << 13; // methods + return; + } + + if (attr.getNumArgs() != 0 || !attr.getParameterName()) { + if (!attr.getParameterName() && attr.getNumArgs() == 1) { + S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "objc_method_family" << 1; + } else { + S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + } + attr.setInvalid(); + return; + } + + llvm::StringRef param = attr.getParameterName()->getName(); + ObjCMethodFamilyAttr::FamilyKind family; + if (param == "none") + family = ObjCMethodFamilyAttr::OMF_None; + else if (param == "alloc") + family = ObjCMethodFamilyAttr::OMF_alloc; + else if (param == "copy") + family = ObjCMethodFamilyAttr::OMF_copy; + else if (param == "init") + family = ObjCMethodFamilyAttr::OMF_init; + else if (param == "mutableCopy") + family = ObjCMethodFamilyAttr::OMF_mutableCopy; + else if (param == "new") + family = ObjCMethodFamilyAttr::OMF_new; + else { + // Just warn and ignore it. This is future-proof against new + // families being used in system headers. + S.Diag(attr.getParameterLoc(), diag::warn_unknown_method_family); + return; + } + + decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(), + S.Context, family)); +} + static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() != 0) { @@ -2752,6 +2797,9 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, case AttributeList::AT_objc_exception: HandleObjCExceptionAttr(D, Attr, S); break; + case AttributeList::AT_objc_method_family: + HandleObjCMethodFamilyAttr(D, Attr, S); + break; case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; |