From 332f1d2404d4e69a8fb88a3d2b6fc302901caec4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 20 Jul 2012 11:37:25 +0200 Subject: [PATCH] re PR c++/28656 (duplicated null argument warning on memcpy()) PR c++/28656 * tree-vrp.c (nonnull_arg_p): Handle all nonnull attributes instead of just the first one. * c-common.c (check_function_nonnull): Handle multiple nonnull attributes properly. * c-c++-common/pr28656.c: New test. From-SVN: r189707 --- gcc/ChangeLog | 6 ++++ gcc/c-family/ChangeLog | 6 ++++ gcc/c-family/c-common.c | 44 ++++++++++++++++++--------- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/c-c++-common/pr28656.c | 29 ++++++++++++++++++ gcc/tree-vrp.c | 45 +++++++++++++++------------- 6 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/pr28656.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2c4c2735823..28f7722cc83 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2012-07-20 Jakub Jelinek + + PR c++/28656 + * tree-vrp.c (nonnull_arg_p): Handle all nonnull attributes instead + of just the first one. + 2012-07-20 Richard Guenther * builtins.c (get_object_alignment_2): Correct offset handling diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index b6c72553826..ddea75a00e1 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2012-07-20 Jakub Jelinek + + PR c++/28656 + * c-common.c (check_function_nonnull): Handle multiple nonnull + attributes properly. + 2012-07-16 Steven Bosscher * c-gimplify.c: Include dumpfile.h instead of tree-dump.h. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 4a8b56d8f90..b72506b212f 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -8051,26 +8051,42 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), static void check_function_nonnull (tree attrs, int nargs, tree *argarray) { - tree a, args; + tree a; int i; - for (a = attrs; a; a = TREE_CHAIN (a)) + attrs = lookup_attribute ("nonnull", attrs); + if (attrs == NULL_TREE) + return; + + a = attrs; + /* See if any of the nonnull attributes has no arguments. If so, + then every pointer argument is checked (in which case the check + for pointer type is done in check_nonnull_arg). */ + if (TREE_VALUE (a) != NULL_TREE) + do + a = lookup_attribute ("nonnull", TREE_CHAIN (a)); + while (a != NULL_TREE && TREE_VALUE (a) != NULL_TREE); + + if (a != NULL_TREE) + for (i = 0; i < nargs; i++) + check_function_arguments_recurse (check_nonnull_arg, NULL, argarray[i], + i + 1); + else { - if (is_attribute_p ("nonnull", TREE_PURPOSE (a))) + /* Walk the argument list. If we encounter an argument number we + should check for non-null, do it. */ + for (i = 0; i < nargs; i++) { - args = TREE_VALUE (a); - - /* Walk the argument list. If we encounter an argument number we - should check for non-null, do it. If the attribute has no args, - then every pointer argument is checked (in which case the check - for pointer type is done in check_nonnull_arg). */ - for (i = 0; i < nargs; i++) + for (a = attrs; ; a = TREE_CHAIN (a)) { - if (!args || nonnull_check_p (args, i + 1)) - check_function_arguments_recurse (check_nonnull_arg, NULL, - argarray[i], - i + 1); + a = lookup_attribute ("nonnull", a); + if (a == NULL_TREE || nonnull_check_p (TREE_VALUE (a), i + 1)) + break; } + + if (a != NULL_TREE) + check_function_arguments_recurse (check_nonnull_arg, NULL, + argarray[i], i + 1); } } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8ae7ff8f3c9..f02f16ededf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-07-20 Jakub Jelinek + + PR c++/28656 + * c-c++-common/pr28656.c: New test. + 2012-07-19 Jason Merrill PR c++/54026 diff --git a/gcc/testsuite/c-c++-common/pr28656.c b/gcc/testsuite/c-c++-common/pr28656.c new file mode 100644 index 00000000000..a0c2339f593 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr28656.c @@ -0,0 +1,29 @@ +/* PR c++/28656 */ +/* { dg-do compile } */ +/* { dg-options "-Wnonnull" } */ + +#ifdef __cplusplus +extern "C" { +#endif +extern void *memcpy (void *__restrict, const void *__restrict, __SIZE_TYPE__) + __attribute__((nonnull (1), nonnull (2), nonnull (1, 2), nonnull)); +#ifdef __cplusplus +} +#endif + +extern void bar (void *p1, void *p2, void *p3, void *p4, void *p5) + __attribute__((nonnull (1), nonnull (1, 3), nonnull (3, 5), nonnull (4))); + +void +foo (void) +{ + memcpy (0, 0, 0); + bar (0, 0, 0, 0, 0); +} + +/* { dg-warning "null argument where non-null required\[^\n\r\]*argument 1" "" { target *-*-* } 20 } */ +/* { dg-warning "null argument where non-null required\[^\n\r\]*argument 2" "" { target *-*-* } 20 } */ +/* { dg-warning "null argument where non-null required\[^\n\r\]*argument 1" "" { target *-*-* } 21 } */ +/* { dg-warning "null argument where non-null required\[^\n\r\]*argument 3" "" { target *-*-* } 21 } */ +/* { dg-warning "null argument where non-null required\[^\n\r\]*argument 4" "" { target *-*-* } 21 } */ +/* { dg-warning "null argument where non-null required\[^\n\r\]*argument 5" "" { target *-*-* } 21 } */ diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 66cc4066830..68c449e0acc 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -353,32 +353,35 @@ nonnull_arg_p (const_tree arg) return true; fntype = TREE_TYPE (current_function_decl); - attrs = lookup_attribute ("nonnull", TYPE_ATTRIBUTES (fntype)); + for (attrs = TYPE_ATTRIBUTES (fntype); attrs; attrs = TREE_CHAIN (attrs)) + { + attrs = lookup_attribute ("nonnull", attrs); - /* If "nonnull" wasn't specified, we know nothing about the argument. */ - if (attrs == NULL_TREE) - return false; + /* If "nonnull" wasn't specified, we know nothing about the argument. */ + if (attrs == NULL_TREE) + return false; - /* If "nonnull" applies to all the arguments, then ARG is non-null. */ - if (TREE_VALUE (attrs) == NULL_TREE) - return true; + /* If "nonnull" applies to all the arguments, then ARG is non-null. */ + if (TREE_VALUE (attrs) == NULL_TREE) + return true; - /* Get the position number for ARG in the function signature. */ - for (arg_num = 1, t = DECL_ARGUMENTS (current_function_decl); - t; - t = DECL_CHAIN (t), arg_num++) - { - if (t == arg) - break; - } + /* Get the position number for ARG in the function signature. */ + for (arg_num = 1, t = DECL_ARGUMENTS (current_function_decl); + t; + t = DECL_CHAIN (t), arg_num++) + { + if (t == arg) + break; + } - gcc_assert (t == arg); + gcc_assert (t == arg); - /* Now see if ARG_NUM is mentioned in the nonnull list. */ - for (t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t)) - { - if (compare_tree_int (TREE_VALUE (t), arg_num) == 0) - return true; + /* Now see if ARG_NUM is mentioned in the nonnull list. */ + for (t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t)) + { + if (compare_tree_int (TREE_VALUE (t), arg_num) == 0) + return true; + } } return false; -- 2.30.2