+2012-07-20  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/28656
+       * tree-vrp.c (nonnull_arg_p): Handle all nonnull attributes instead
+       of just the first one.
+
 2012-07-20  Richard Guenther  <rguenther@suse.de>
 
        * builtins.c (get_object_alignment_2): Correct offset handling
 
+2012-07-20  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/28656
+       * c-common.c (check_function_nonnull): Handle multiple nonnull
+       attributes properly.
+
 2012-07-16  Steven Bosscher  <steven@gcc.gnu.org>
 
        * c-gimplify.c: Include dumpfile.h instead of tree-dump.h.
 
 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);
        }
     }
 }
 
+2012-07-20  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/28656
+       * c-c++-common/pr28656.c: New test.
+
 2012-07-19  Jason Merrill  <jason@redhat.com>
 
        PR c++/54026
 
--- /dev/null
+/* 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 } */
 
     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;