aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/Attr.td9
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td1
-rw-r--r--include/clang/Sema/AttributeList.h1
-rw-r--r--lib/AST/DeclObjC.cpp16
-rw-r--r--lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--lib/Sema/AttributeList.cpp1
-rw-r--r--lib/Sema/SemaDeclAttr.cpp48
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;