Hi,
This patch attempts to add returns_arg attribute for c-family
languages. For C++ methods, first arg is assumed to be this pointer,
similar to alloc_size.
I have a couple of doubts:
(a) I am not sure why DECL_ARGUMENTS (decl) in
handle_returns_arg_attribute returns NULL ? My intent was to check
that the return-type and argument-types are compatible.
(b) AFAIU the bottom two bits of call return flags are used for storing
args from 0 - 3 and the arg number can be obtained by
masking with ERF_RETURN_ARG_MASK.
So, does that mean we can only allow first 4 arguments to be annotated
with returns_arg attribute ?
In the patch, I use fn_spec ('argnum'), which gimple_call_return_flags
uses to mark the corresponding arg with ERF_RETURN_ARG:
(c) How to write dejaGNU test to check if fn_spec ('argnum') has been correctly
applied to the corresponding parameter ? In the patch, I am just
testing for validation.
Thanks,
Prathamesh
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index dc9579c5c60..3fe3d2a6298 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -150,6 +150,7 @@ static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);
static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
int, bool *);
static tree handle_copy_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_arg_attribute (tree *, tree, tree, int, bool *);
/* Helper to define attribute exclusions. */
#define ATTR_EXCL(name, function, type, variable) \
@@ -484,6 +485,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_noinit_attribute, attr_noinit_exclusions },
{ "access", 1, 3, false, true, true, false,
handle_access_attribute, NULL },
+ { "returns_arg", 1, 1, true, false, false, false,
+ handle_returns_arg_attribute, NULL },
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
@@ -4603,6 +4606,80 @@ handle_patchable_function_entry_attribute (tree *, tree name, tree args,
return NULL_TREE;
}
+/* Handle a "returns_arg" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_returns_arg_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ tree decl = *node;
+ tree rettype = TREE_TYPE (decl);
+
+ if (TREE_CODE (rettype) == METHOD_TYPE
+ || TREE_CODE (rettype) == FUNCTION_TYPE)
+ rettype = TREE_TYPE (rettype);
+
+ if (VOID_TYPE_P (rettype))
+ {
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
+ "%qE attribute ignored on a function returning %qT",
+ name, rettype);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ gcc_assert (args);
+ tree val = TREE_VALUE (args);
+ if (TREE_CODE (val) != INTEGER_CST)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute requires integer constant.", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ int argnum = TREE_INT_CST_LOW (val);
+ if (argnum >= 4)
+ {
+ warning (OPT_Wattributes, "%qE attribute can only be applied"
+ " to first 4 arguments.", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ tree parm;
+ int i;
+
+ for (i = 0, parm = DECL_ARGUMENTS (decl);
+ i < argnum && parm;
+ i++, parm = DECL_CHAIN (decl))
+ ;
+
+ if (parm &&
+ !types_compatible_p (TREE_TYPE (parm), rettype))
+ {
+ warning (OPT_Wattributes, "%qE attribute parameter type %qT is"
+ " incompatible with return-type %qT", name, TREE_TYPE (parm),
+ rettype);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ *no_add_attrs = false;
+
+ char s[2];
+ s[0] = argnum + '0';
+ s[1] = '\0';
+
+
+ tree attr = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE, build_string (1, s)),
+ NULL_TREE);
+ decl_attributes (node, attr, flags);
+ return NULL_TREE;
+}
+
/* Attempt to partially validate a single attribute ATTR as if
it were to be applied to an entity OPER. */
diff --git a/gcc/testsuite/g++.dg/Wattributes-6.C b/gcc/testsuite/g++.dg/Wattributes-6.C
new file mode 100644
index 00000000000..fcf660a4684
--- /dev/null
+++ b/gcc/testsuite/g++.dg/Wattributes-6.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* Check that 'this' is counted as first arg to the attribute. */
+
+struct X
+{
+ X *f() __attribute__((returns_arg(1)));
+};
+
+int main()
+{
+ X x;
+ x.f();
+}
diff --git a/gcc/testsuite/gcc.dg/Wattributes-11.c b/gcc/testsuite/gcc.dg/Wattributes-11.c
new file mode 100644
index 00000000000..e291107243f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wattributes-11.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-Wattributes" } */
+
+int f1 (int) __attribute__((returns_arg)); /* { dg-error "wrong number of arguments specified for 'returns_arg' attribute" } */
+
+void f2 (int) __attribute__((returns_arg(1))); /* { dg-warning "'returns_arg' attribute ignored on a function returning 'void'" } */
+
+int f3 (int) __attribute__((returns_arg("foo"))); /* { dg-error "'returns_arg' attribute requires integer constant" } */