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