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" } */

Reply via email to