This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Avoid duplicate -Wnonnull warnings (PR c++/28656)


On Thu, Jul 19, 2012 at 6:53 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> On the following testcase we emit various (correct) -Wnonnull warnings
> more than once, sometimes many times.  The problem on the reported memcpy
> testcase is that glibc uses __attribute__((nonnull (1, 2))) and gcc
> uses __attribute__((nonnull)) on the memset builtin and we end up with both of
> the attributes (as they have different parameters and thus aren't merged).
> The check_function_nonnull then for each nonnull attribute went through all
> the arguments and warned if the argument matched the current nonnull
> attribute (so, for the combination of glibc and gcc provided nonnull
> argument 1 and argument 2 each matched twice, once the list variant, once
> the non-argument variant).  The following patch fixes it by first looking
> if there is any nonnull attribute without argument, then it warns about all
> pointer arguments, or otherwise for each argument walks the list of
> nonnull attributes and if any of them matches, warns.
>
> tree-vrp.c apparently handled just the first nonnull attribute and not more
> than one of them.  That seems to be all users of that attribute in GCC.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Hum.  How hard would it be to merge the attributes?

Richard.

> 2012-07-19  Jakub Jelinek  <jakub@redhat.com>
>
>         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.
>
> --- gcc/tree-vrp.c.jj   2012-07-16 14:38:13.000000000 +0200
> +++ gcc/tree-vrp.c      2012-07-19 14:24:27.277354132 +0200
> @@ -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));
> -
> -  /* 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;
> -
> -  /* 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++)
> +  for (attrs = TYPE_ATTRIBUTES (fntype); attrs; attrs = TREE_CHAIN (attrs))
>      {
> -      if (t == arg)
> -       break;
> -    }
> +      attrs = lookup_attribute ("nonnull", attrs);
>
> -  gcc_assert (t == arg);
> +      /* If "nonnull" wasn't specified, we know nothing about the argument.  */
> +      if (attrs == NULL_TREE)
> +       return false;
>
> -  /* 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)
> +      /* 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;
> +       }
> +
> +      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;
> +       }
>      }
>
>    return false;
> --- gcc/c-family/c-common.c.jj  2012-07-18 12:02:11.000000000 +0200
> +++ gcc/c-family/c-common.c     2012-07-19 14:32:05.915905501 +0200
> @@ -8194,26 +8194,42 @@ handle_nonnull_attribute (tree *node, tr
>  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);
>         }
>      }
>  }
> --- gcc/testsuite/c-c++-common/pr28656.c.jj     2012-07-19 15:05:56.790975802 +0200
> +++ gcc/testsuite/c-c++-common/pr28656.c        2012-07-19 15:19:55.098486448 +0200
> @@ -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 } */
>
>         Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]