PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument
authorMartin Sebor <msebor@redhat.com>
Thu, 15 Nov 2018 22:53:57 +0000 (22:53 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 15 Nov 2018 22:53:57 +0000 (15:53 -0700)
PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument
PR c++/87542 - bogus error on attribute format with a named constant argument

gcc/ChangeLog:

PR c++/87541
PR c++/87542
* tree.c (type_argument_type): New function.
* tree.h (type_argument_type): Declare it.
* gcc/doc/extend.texi (alloc_align): Update and clarify.
(alloc_size, nonnull, sentinel): Same.

gcc/c-family/ChangeLog:

PR c++/87541
PR c++/87542
* c-attribs.c (positional_argument): New function.
(handle_alloc_size_attribute): Use it and simplify.
(handle_alloc_align_attribute): Same.
(handle_assume_aligned_attribute): Same.
(handle_nonnull_attribute): Same.
* c-common.c (check_function_arguments): Pass fntype to
check_function_format.
* c-common.h (check_function_format): Add an argument.
(PosArgFlags, positional_argument): Declare new type and function.
* c-format.c (decode_format_attr): Add arguments.
(check_format_string, get_constant): Same.
(convert_format_name_to_system_name): Adjust.

gcc/testsuite/ChangeLog:

PR c++/87541
PR c++/87542
* g++.dg/ext/attr-alloc_size.C: New test.
* c-c++-common/pr71574.c: Adjust diagnostics.
* c-c++-common/attributes-1.c: Same.
* gcc.dg/attr-alloc_align-2.c: Same.
* gcc.dg/attr-alloc_align-4.c: New test.
* gcc.dg/attr-alloc_size-2.c: Adjust diagnostics.
* gcc.dg/attr-alloc_size.c: Same.
* gcc.dg/attr-assume_aligned-4.c: New test.
* gcc.dg/format/attr-3.c: Adjust diagnostics.
* gcc.dg/nonnull-2.c: Same.
* gcc.dg/torture/pr80612.c: Same.
* obj-c++.dg/attributes/method-format-1.mm: Same.
* obj-c++.dg/attributes/method-nonnull-1.mm: Same.
* objc.dg/attributes/method-format-1.m: same.
* objc.dg/attributes/method-nonnull-1.m: Same.

From-SVN: r266195

26 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/attributes-1.c
gcc/testsuite/c-c++-common/pr71574.c
gcc/testsuite/g++.dg/ext/attr-alloc_size.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-alloc_align-2.c
gcc/testsuite/gcc.dg/attr-alloc_align-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-alloc_size-12.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-alloc_size-2.c
gcc/testsuite/gcc.dg/attr-alloc_size.c
gcc/testsuite/gcc.dg/attr-assume_aligned-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/format/attr-3.c
gcc/testsuite/gcc.dg/nonnull-2.c
gcc/testsuite/gcc.dg/torture/pr80612.c
gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm
gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm
gcc/testsuite/objc.dg/attributes/method-format-1.m
gcc/testsuite/objc.dg/attributes/method-nonnull-1.m
gcc/tree.c
gcc/tree.h

index 7b46b67122776672a0766f91afaeffd35739c372..04d2166e501c4f15150767404df0d786bbab335d 100644 (file)
@@ -1,3 +1,12 @@
+2018-11-15  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/87541
+       PR c++/87542
+       * tree.c (type_argument_type): New function.
+       * tree.h (type_argument_type): Declare it.
+       * gcc/doc/extend.texi (alloc_align): Update and clarify.
+       (alloc_size, nonnull, sentinel): Same.
+
 2018-11-15  Andrew Stubbs  <ams@codesourcery.com>
             Kwok Cheung Yeung  <kcy@codesourcery.com>
 
index 93ee0d4947b6624a500e83a2f179a4c134f979ff..057009b9d42406793e24cd4aa96dd1410523c8db 100644 (file)
@@ -1,3 +1,20 @@
+2018-11-15  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/87541
+       PR c++/87542
+       * c-attribs.c (positional_argument): New function.
+       (handle_alloc_size_attribute): Use it and simplify.
+       (handle_alloc_align_attribute): Same.
+       (handle_assume_aligned_attribute): Same.
+       (handle_nonnull_attribute): Same.
+       * c-common.c (check_function_arguments): Pass fntype to
+       check_function_format.
+       * c-common.h (check_function_format): Add an argument.
+       (PosArgFlags, positional_argument): Declare new type and function.
+       * c-format.c (decode_format_attr): Add arguments.
+       (check_format_string, get_constant): Same.
+       (convert_format_name_to_system_name): Adjust.
+
 2018-11-15  David Malcolm  <dmalcolm@redhat.com>
 
        PR other/19165
index 1657df7f9df41f0f2fcbcc3479bd9172256c3ec5..c9afa1f78f416c921161f9f0fc38fb6eb7c6c569 100644 (file)
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "opts.h"
 #include "gimplify.h"
+#include "tree-pretty-print.h"
 
 static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
@@ -495,6 +496,188 @@ attribute_takes_identifier_p (const_tree attr_id)
     return targetm.attribute_takes_identifier_p (attr_id);
 }
 
+/* Verify that argument value POS at position ARGNO to attribute NAME
+   applied to function TYPE refers to a function parameter at position
+   POS and the expected type CODE.  If so, return POS after default
+   conversions, if any.  Otherwise, issue appropriate warnings and
+   return null.  A non-zero 1-based ARGNO should be passed ib by
+   callers only for attributes with more than one argument.  */
+
+tree
+positional_argument (const_tree fntype, const_tree atname, tree pos,
+                    tree_code code, int argno /* = 0 */,
+                    int flags /* = posargflags () */)
+{
+  if (pos && TREE_CODE (pos) != IDENTIFIER_NODE
+      && TREE_CODE (pos) != FUNCTION_DECL)
+    pos = default_conversion (pos);
+
+  tree postype = TREE_TYPE (pos);
+  if (pos == error_mark_node || !postype)
+    {
+      /* Only mention the positional argument number when it's non-zero.  */
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument is invalid", atname);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i is invalid", atname, argno);
+
+      return NULL_TREE;
+    }
+
+  if (!INTEGRAL_TYPE_P (postype))
+    {
+      /* Handle this case specially to avoid mentioning the value
+        of pointer constants in diagnostics.  Only mention
+        the positional argument number when it's non-zero.  */
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument has type %qT",
+                atname, postype);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i has type %qT",
+                atname, argno, postype);
+
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (pos) != INTEGER_CST)
+    {
+      /* Only mention the argument number when it's non-zero.  */
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE is not an integer "
+                "constant",
+                atname, pos);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE is not an integer "
+                "constant",
+                atname, argno, pos);
+
+      return NULL_TREE;
+    }
+
+  /* Argument positions are 1-based.  */
+  if (integer_zerop (pos))
+    {
+      if (flags & POSARG_ZERO)
+       /* Zero is explicitly allowed.  */
+       return pos;
+
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE does not refer to "
+                "a function parameter",
+                atname, pos);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE does not refer to "
+                "a function parameter",
+                atname, argno, pos);
+
+      return NULL_TREE;
+    }
+
+  if (!prototype_p (fntype))
+    return pos;
+
+  /* Verify that the argument position does not exceed the number
+     of formal arguments to the function.  When POSARG_ELLIPSIS
+     is set, ARGNO may be beyond the last argument of a vararg
+     function.  */
+  unsigned nargs = type_num_arguments (fntype);
+  if (!nargs
+      || !tree_fits_uhwi_p (pos)
+      || ((flags & POSARG_ELLIPSIS) == 0
+         && !IN_RANGE (tree_to_uhwi (pos), 1, nargs)))
+    {
+
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE exceeds the number "
+                "of function parameters %u",
+                atname, pos, nargs);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE exceeds the number "
+                "of function parameters %u",
+                atname, argno, pos, nargs);
+      return NULL_TREE;
+    }
+
+  /* Verify that the type of the referenced formal argument matches
+     the expected type.  */
+  unsigned HOST_WIDE_INT ipos = tree_to_uhwi (pos);
+
+  /* Zero was handled above.  */
+  gcc_assert (ipos != 0);
+
+  if (tree argtype = type_argument_type (fntype, ipos))
+    {
+      if (flags & POSARG_ELLIPSIS)
+       {
+         if (argno < 1)
+           error ("%qE attribute argument value %qE does not refer to "
+                  "a variable argument list",
+                  atname, pos);
+         else
+           error ("%qE attribute argument %i value %qE does not refer to "
+                  "a variable argument list",
+                  atname, argno, pos);
+         return NULL_TREE;
+       }
+
+      /* Where the expected code is STRING_CST accept any pointer
+        to a narrow character type, qualified or otherwise.  */
+      bool type_match;
+      if (code == STRING_CST && POINTER_TYPE_P (argtype))
+       {
+         tree type = TREE_TYPE (argtype);
+         type = TYPE_MAIN_VARIANT (type);
+         type_match = (type == char_type_node
+                       || type == signed_char_type_node
+                       || type == unsigned_char_type_node);
+       }
+      else
+       type_match = TREE_CODE (argtype) == code;
+
+      if (!type_match)
+       {
+         if (argno < 1)
+           warning (OPT_Wattributes,
+                    "%qE attribute argument value %qE refers to "
+                    "parameter type %qT",
+                    atname, pos, argtype);
+         else
+           warning (OPT_Wattributes,
+                  "%qE attribute argument %i value %qE refers to "
+                    "parameter type %qT",
+                    atname, argno, pos, argtype);
+         return NULL_TREE;
+       }
+    }
+  else if (!(flags & POSARG_ELLIPSIS))
+    {
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE refers to "
+                "a variadic function parameter of unknown type",
+                atname, pos);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE refers to "
+                "a variadic function parameter of unknown type",
+                atname, argno, pos);
+      return NULL_TREE;
+    }
+
+  return pos;
+}
+
+
 /* Attribute handlers common to C front ends.  */
 
 /* Handle a "packed" attribute; arguments as in
@@ -2563,27 +2746,40 @@ handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
    struct attribute_spec.handler.  */
 
 static tree
-handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+handle_alloc_size_attribute (tree *node, tree name, tree args,
                             int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  unsigned arg_count = type_num_arguments (*node);
-  for (; args; args = TREE_CHAIN (args))
+  tree decl = *node;
+  tree rettype = TREE_TYPE (decl);
+  if (!POINTER_TYPE_P (rettype))
     {
-      tree position = TREE_VALUE (args);
-      if (position && TREE_CODE (position) != IDENTIFIER_NODE
-         && TREE_CODE (position) != FUNCTION_DECL)
-       position = default_conversion (position);
+      warning (OPT_Wattributes,
+              "%qE attribute ignored on a function returning %qT",
+              name, rettype);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
 
-      if (!tree_fits_uhwi_p (position)
-         || !arg_count
-         || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
+  for (int i = 1; args; ++i)
+    {
+      tree pos = TREE_VALUE (args);
+      /* NEXT is null when the attribute includes just one argument.
+        That's used to tell positional_argument to avoid mentioning
+        the argument number in diagnostics (since there's just one
+        mentioning it is unnecessary and coule be confusing).  */
+      tree next = TREE_CHAIN (args);
+      if (tree val = positional_argument (decl, name, pos, INTEGER_TYPE,
+                                         next || i > 1 ? i : 0))
+       TREE_VALUE (args) = val;
+      else
        {
-         warning (OPT_Wattributes,
-                  "alloc_size parameter outside range");
          *no_add_attrs = true;
-         return NULL_TREE;
+         break;
        }
+
+      args = next;
     }
+
   return NULL_TREE;
 }
 
@@ -2591,24 +2787,23 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
    struct attribute_spec.handler.  */
 
 static tree
-handle_alloc_align_attribute (tree *node, tree, tree args, int,
+handle_alloc_align_attribute (tree *node, tree name, tree args, int,
                              bool *no_add_attrs)
 {
-  unsigned arg_count = type_num_arguments (*node);
-  tree position = TREE_VALUE (args);
-  if (position && TREE_CODE (position) != IDENTIFIER_NODE
-      && TREE_CODE (position) != FUNCTION_DECL)
-    position = default_conversion (position);
-
-  if (!tree_fits_uhwi_p (position)
-      || !arg_count
-      || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
+  tree decl = *node;
+  tree rettype = TREE_TYPE (decl);
+  if (!POINTER_TYPE_P (rettype))
     {
       warning (OPT_Wattributes,
-              "alloc_align parameter outside range");
+              "%qE attribute ignored on a function returning %qT",
+              name, rettype);
       *no_add_attrs = true;
       return NULL_TREE;
     }
+
+  if (!positional_argument (*node, name, TREE_VALUE (args), INTEGER_TYPE))
+    *no_add_attrs = true;
+
   return NULL_TREE;
 }
 
@@ -2616,20 +2811,60 @@ handle_alloc_align_attribute (tree *node, tree, tree args, int,
    struct attribute_spec.handler.  */
 
 static tree
-handle_assume_aligned_attribute (tree *, tree, tree args, int,
+handle_assume_aligned_attribute (tree *node, tree name, tree args, int,
                                 bool *no_add_attrs)
 {
+  tree decl = *node;
+  tree rettype = TREE_TYPE (decl);
+  if (TREE_CODE (rettype) != POINTER_TYPE)
+    {
+      warning (OPT_Wattributes,
+              "%qE attribute ignored on a function returning %qT",
+              name, rettype);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* The alignment specified by the first argument.  */
+  tree align = NULL_TREE;
+
   for (; args; args = TREE_CHAIN (args))
     {
-      tree position = TREE_VALUE (args);
-      if (position && TREE_CODE (position) != IDENTIFIER_NODE
-         && TREE_CODE (position) != FUNCTION_DECL)
-       position = default_conversion (position);
+      tree val = TREE_VALUE (args);
+      if (val && TREE_CODE (val) != IDENTIFIER_NODE
+         && TREE_CODE (val) != FUNCTION_DECL)
+       val = default_conversion (val);
 
-      if (TREE_CODE (position) != INTEGER_CST)
+      if (!tree_fits_shwi_p (val))
        {
          warning (OPT_Wattributes,
-                  "assume_aligned parameter not integer constant");
+                  "%qE attribute %E is not an integer constant",
+                  name, val);
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+
+      if (!align)
+       {
+         /* Validate and save the alignment.  */
+         if (!integer_pow2p (val))
+           {
+             warning (OPT_Wattributes,
+                      "%qE attribute argument %E is not a power of 2",
+                      name, val);
+             *no_add_attrs = true;
+             return NULL_TREE;
+           }
+
+         align = val;
+       }
+      else if (tree_int_cst_sgn (val) < 0 || tree_int_cst_le (align, val))
+       {
+         /* The misalignment specified by the second argument
+            must be non-negative and less than the alignment.  */
+         warning (OPT_Wattributes,
+                  "%qE attribute argument %E is not in the range [0, %E)",
+                  name, val, align);
          *no_add_attrs = true;
          return NULL_TREE;
        }
@@ -3262,12 +3497,11 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
 /* Handle the "nonnull" attribute.  */
 
 static tree
-handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
+handle_nonnull_attribute (tree *node, tree name,
                          tree args, int ARG_UNUSED (flags),
                          bool *no_add_attrs)
 {
   tree type = *node;
-  unsigned HOST_WIDE_INT attr_arg_num;
 
   /* If no arguments are specified, all pointer arguments should be
      non-null.  Verify a full prototype is given so that the arguments
@@ -3286,57 +3520,23 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
       return NULL_TREE;
     }
 
-  /* Argument list specified.  Verify that each argument number references
-     a pointer argument.  */
-  for (attr_arg_num = 1; args; attr_arg_num++, args = TREE_CHAIN (args))
+  for (int i = 1; args; ++i)
     {
-      unsigned HOST_WIDE_INT arg_num = 0, ck_num;
-
-      tree arg = TREE_VALUE (args);
-      if (arg && TREE_CODE (arg) != IDENTIFIER_NODE
-         && TREE_CODE (arg) != FUNCTION_DECL)
-       TREE_VALUE (args) = arg = default_conversion (arg);
-
-      if (!get_nonnull_operand (arg, &arg_num))
+      tree pos = TREE_VALUE (args);
+      /* NEXT is null when the attribute includes just one argument.
+        That's used to tell positional_argument to avoid mentioning
+        the argument number in diagnostics (since there's just one
+        mentioning it is unnecessary and coule be confusing).  */
+      tree next = TREE_CHAIN (args);
+      if (tree val = positional_argument (type, name, pos, POINTER_TYPE,
+                                         next || i > 1 ? i : 0))
+       TREE_VALUE (args) = val;
+      else
        {
-         error ("nonnull argument has invalid operand number (argument %lu)",
-                (unsigned long) attr_arg_num);
          *no_add_attrs = true;
-         return NULL_TREE;
-       }
-
-      if (prototype_p (type))
-       {
-         function_args_iterator iter;
-         tree argument;
-
-         function_args_iter_init (&iter, type);
-         for (ck_num = 1; ; ck_num++, function_args_iter_next (&iter))
-           {
-             argument = function_args_iter_cond (&iter);
-             if (argument == NULL_TREE || ck_num == arg_num)
-               break;
-           }
-
-         if (!argument
-             || TREE_CODE (argument) == VOID_TYPE)
-           {
-             error ("nonnull argument with out-of-range operand number "
-                    "(argument %lu, operand %lu)",
-                    (unsigned long) attr_arg_num, (unsigned long) arg_num);
-             *no_add_attrs = true;
-             return NULL_TREE;
-           }
-
-         if (TREE_CODE (argument) != POINTER_TYPE)
-           {
-             error ("nonnull argument references non-pointer operand "
-                    "(argument %lu, operand %lu)",
-                    (unsigned long) attr_arg_num, (unsigned long) arg_num);
-             *no_add_attrs = true;
-             return NULL_TREE;
-           }
+         break;
        }
+      args = next;
     }
 
   return NULL_TREE;
index cd88f3a5ed304a04954f23ac4afb4e1ca083ce89..69be3d3b2a0d002277be9426a7ae6c9be2631b55 100644 (file)
@@ -5658,7 +5658,8 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
   /* Check for errors in format strings.  */
 
   if (warn_format || warn_suggest_attribute_format)
-    check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray, arglocs);
+    check_function_format (fntype, TYPE_ATTRIBUTES (fntype), nargs, argarray,
+                          arglocs);
 
   if (warn_format)
     check_function_sentinel (fntype, nargs, argarray);
index 31cc27325c21a1e99166d9b88ce8f8f4b991b502..8eeeba7531921f3dd19dff565989532b32120445 100644 (file)
@@ -808,7 +808,8 @@ extern void check_function_arguments_recurse (void (*)
                                              unsigned HOST_WIDE_INT);
 extern bool check_builtin_function_arguments (location_t, vec<location_t>,
                                              tree, int, tree *);
-extern void check_function_format (tree, int, tree *, vec<location_t> *);
+extern void check_function_format (const_tree, tree, int, tree *,
+                                  vec<location_t> *);
 extern bool attribute_fallthrough_p (tree);
 extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
 extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
@@ -1330,6 +1331,18 @@ extern int tm_attr_to_mask (tree);
 extern tree tm_mask_to_attr (int);
 extern tree find_tm_attribute (tree);
 
+/* A bitmap of flags to positional_argument.  */
+enum posargflags {
+  /* Consider positional attribute argument value zero valid.  */
+  POSARG_ZERO = 1,
+  /* Consider positional attribute argument value valid if it refers
+     to the ellipsis (i.e., beyond the last typed argument).  */
+  POSARG_ELLIPSIS = 2
+};
+
+extern tree positional_argument (const_tree, const_tree, tree, tree_code,
+                                int = 0, int = posargflags ());
+
 extern enum flt_eval_method
 excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method);
 
index 6613092c6fdcab61403b87fc9085ec28556e6e35..8b17f5399744163e5fe116236814e86e234ee26c 100644 (file)
@@ -63,15 +63,17 @@ static GTY(()) tree local_gimple_ptr_node;
 static GTY(()) tree local_cgraph_node_ptr_node;
 static GTY(()) tree locus;
 
-static bool decode_format_attr (tree, function_format_info *, int);
+static bool decode_format_attr (const_tree, tree, tree, function_format_info *,
+                               bool);
 static int decode_format_type (const char *);
 
-static bool check_format_string (tree argument,
+static bool check_format_string (const_tree argument,
                                 unsigned HOST_WIDE_INT format_num,
                                 int flags, bool *no_add_attrs,
                                 int expected_format_type);
-static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
-                         int validated_p);
+static tree get_constant (const_tree fntype, const_tree atname, tree expr,
+                         int argno, unsigned HOST_WIDE_INT *value,
+                         int flags, bool validated_p);
 static const char *convert_format_name_to_system_name (const char *attr_name);
 
 static int first_target_format_type;
@@ -133,16 +135,19 @@ valid_stringptr_type_p (tree strref)
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
-handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
+handle_format_arg_attribute (tree *node, tree atname,
                             tree args, int flags, bool *no_add_attrs)
 {
   tree type = *node;
-  tree format_num_expr = TREE_VALUE (args);
+  /* Note that TREE_VALUE (args) is changed in place below.  */
+  tree *format_num_expr = &TREE_VALUE (args);
   unsigned HOST_WIDE_INT format_num = 0;
 
-  if (!get_constant (format_num_expr, &format_num, 0))
+  if (tree val = get_constant (type, atname, *format_num_expr, 0, &format_num,
+                              0, false))
+    *format_num_expr = val;
+  else
     {
-      error ("format string has invalid operand number");
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -171,7 +176,7 @@ handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
    error).  When we know the specific reference type expected, this is also 
    checked.  */
 static bool
-check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
+check_format_string (const_tree fntype, unsigned HOST_WIDE_INT format_num,
                     int flags, bool *no_add_attrs, int expected_format_type)
 {
   unsigned HOST_WIDE_INT i;
@@ -264,19 +269,20 @@ check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
 
 /* Verify EXPR is a constant, and store its value.
    If validated_p is true there should be no errors.
-   Returns true on success, false otherwise.  */
-static bool
-get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p)
+   Returns the converted constant value on success, null otherwise.  */
+static tree
+get_constant (const_tree fntype, const_tree atname, tree expr, int argno,
+             unsigned HOST_WIDE_INT *value, int flags, bool validated_p)
 {
-  if (!tree_fits_uhwi_p (expr))
+  if (tree val = positional_argument (fntype, atname, expr, STRING_CST,
+                                     argno, flags))
     {
-      gcc_assert (!validated_p);
-      return false;
+      *value = TREE_INT_CST_LOW (val);
+      return val;
     }
 
-  *value = TREE_INT_CST_LOW (expr);
-
-  return true;
+  gcc_assert (!validated_p);
+  return NULL_TREE;
 }
 
 /* Decode the arguments to a "format" attribute into a
@@ -287,12 +293,14 @@ get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p)
    attributes are successfully decoded, false otherwise.  */
 
 static bool
-decode_format_attr (tree args, function_format_info *info, int validated_p)
+decode_format_attr (const_tree fntype, tree atname, tree args,
+                   function_format_info *info, bool validated_p)
 {
   tree format_type_id = TREE_VALUE (args);
-  tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
-  tree first_arg_num_expr
-    = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
+  /* Note that TREE_VALUE (args) is changed in place below.  Ditto
+     for the value of the next element on the list.  */
+  tree *format_num_expr = &TREE_VALUE (TREE_CHAIN (args));
+  tree *first_arg_num_expr = &TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
 
   if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
     {
@@ -327,17 +335,18 @@ decode_format_attr (tree args, function_format_info *info, int validated_p)
        }
     }
 
-  if (!get_constant (format_num_expr, &info->format_num, validated_p))
-    {
-      error ("format string has invalid operand number");
-      return false;
-    }
+  if (tree val = get_constant (fntype, atname, *format_num_expr,
+                              2, &info->format_num, 0, validated_p))
+    *format_num_expr = val;
+  else
+    return false;
 
-  if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p))
-    {
-      error ("%<...%> has invalid operand number");
-      return false;
-    }
+  if (tree val = get_constant (fntype, atname, *first_arg_num_expr,
+                              3, &info->first_arg_num,
+                              (POSARG_ZERO | POSARG_ELLIPSIS), validated_p))
+    *first_arg_num_expr = val;
+  else
+    return false;
 
   if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
     {
@@ -1083,11 +1092,13 @@ decode_format_type (const char *s)
    attribute themselves.  */
 
 void
-check_function_format (tree attrs, int nargs, tree *argarray,
-                      vec<location_t> *arglocs)
+check_function_format (const_tree fntype, tree attrs, int nargs,
+                      tree *argarray, vec<location_t> *arglocs)
 {
   tree a;
 
+  tree atname = get_identifier ("format");
+
   /* See if this function has any format attributes.  */
   for (a = attrs; a; a = TREE_CHAIN (a))
     {
@@ -1095,7 +1106,8 @@ check_function_format (tree attrs, int nargs, tree *argarray,
        {
          /* Yup; check it.  */
          function_format_info info;
-         decode_format_attr (TREE_VALUE (a), &info, /*validated=*/true);
+         decode_format_attr (fntype, atname, TREE_VALUE (a), &info,
+                             /*validated=*/true);
          if (warn_format)
            {
              /* FIXME: Rewrite all the internal functions in this file
@@ -4124,10 +4136,10 @@ convert_format_name_to_system_name (const char *attr_name)
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
-handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+handle_format_attribute (tree *node, tree atname, tree args,
                         int flags, bool *no_add_attrs)
 {
-  tree type = *node;
+  const_tree type = *node;
   function_format_info info;
 
 #ifdef TARGET_FORMAT_TYPES
@@ -4153,7 +4165,7 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
   if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
     TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args));
 
-  if (!decode_format_attr (args, &info, 0))
+  if (!decode_format_attr (type, atname, args, &info, /* validated_p = */false))
     {
       *no_add_attrs = true;
       return NULL_TREE;
index d4b1046b6ae5ce133ba38be761aab143492736c5..d0146baa06f097789993834302ca21965442d4e8 100644 (file)
@@ -2406,33 +2406,39 @@ further information.
 The @code{aligned} attribute can also be used for variables and fields
 (@pxref{Variable Attributes}.)
 
-@item alloc_align
+@item alloc_align (@var{position})
 @cindex @code{alloc_align} function attribute
-The @code{alloc_align} attribute is used to tell the compiler that the
-function return value points to memory, where the returned pointer minimum
-alignment is given by one of the functions parameters.  GCC uses this
-information to improve pointer alignment analysis.
+The @code{alloc_align} attribute may be applied to a function that
+returns a pointer and takes at least one argument of an integer type.
+It indicates that the returned pointer is aligned on a boundary given
+by the function argument at @var{position}.  Meaningful alignments are
+powers of 2 greater than one.  GCC uses this information to improve
+pointer alignment analysis.
 
 The function parameter denoting the allocated alignment is specified by
-one integer argument, whose number is the argument of the attribute.
+one constant integer argument whose number is the argument of the attribute.
 Argument numbering starts at one.
 
 For instance,
 
 @smallexample
-void* my_memalign(size_t, size_t) __attribute__((alloc_align(1)))
+void* my_memalign (size_t, size_t) __attribute__ ((alloc_align (1)));
 @end smallexample
 
 @noindent
 declares that @code{my_memalign} returns memory with minimum alignment
 given by parameter 1.
 
-@item alloc_size
+@item alloc_size (@var{position})
+@itemx alloc_size (@var{position-1}, @var{position-2})
 @cindex @code{alloc_size} function attribute
-The @code{alloc_size} attribute is used to tell the compiler that the
-function return value points to memory, where the size is given by
-one or two of the functions parameters.  GCC uses this
-information to improve the correctness of @code{__builtin_object_size}.
+The @code{alloc_size} attribute may be applied to a function that
+returns a pointer and takes at least one argument of an integer type.
+It indicates that the returned pointer points to memory whose size is
+given by the function argument at @var{position-1}, or by the product
+of the arguments at @var{position-1} and @var{position-2}.  Meaningful
+sizes are positive values less than @code{PTRDIFF_MAX}.  GCC uses this
+information to improve the results of @code{__builtin_object_size}.
 
 The function parameter(s) denoting the allocated size are specified by
 one or two integer arguments supplied to the attribute.  The allocated size
@@ -2443,8 +2449,8 @@ one.
 For instance,
 
 @smallexample
-void* my_calloc(size_t, size_t) __attribute__((alloc_size(1,2)))
-void* my_realloc(void*, size_t) __attribute__((alloc_size(2)))
+void* my_calloc (size_t, size_t) __attribute__ ((alloc_size (1, 2)));
+void* my_realloc (void*, size_t) __attribute__ ((alloc_size (2)));
 @end smallexample
 
 @noindent
@@ -2470,22 +2476,25 @@ info format it either means marking the function as artificial
 or using the caller location for all instructions within the inlined
 body.
 
-@item assume_aligned
+@item assume_aligned (@var{alignment})
+@itemx assume_aligned (@var{alignment}, @var{offset})
 @cindex @code{assume_aligned} function attribute
-The @code{assume_aligned} attribute is used to tell the compiler that the
-function return value points to memory, where the returned pointer minimum
-alignment is given by the first argument.
-If the attribute has two arguments, the second argument is misalignment offset.
+The @code{assume_aligned} attribute may be applied to a function that
+returns a pointer.  It indicates that the returned pointer is aligned
+on a boundary given by @var{alignment}.  If the attribute has two
+arguments, the second argument is misalignment @var{offset}.  Meaningful
+values of @var{alignment} are powers of 2 greater than one.  Meaningful
+values of @var{offset} are greater than zero and less than @var{alignment}.
 
 For instance
 
 @smallexample
-void* my_alloc1(size_t) __attribute__((assume_aligned(16)))
-void* my_alloc2(size_t) __attribute__((assume_aligned(32, 8)))
+void* my_alloc1 (size_t) __attribute__((assume_aligned (16)));
+void* my_alloc2 (size_t) __attribute__((assume_aligned (32, 8)));
 @end smallexample
 
 @noindent
-declares that @code{my_alloc1} returns 16-byte aligned pointer and
+declares that @code{my_alloc1} returns 16-byte aligned pointers and
 that @code{my_alloc2} returns a pointer whose value modulo 32 is equal
 to 8.
 
@@ -3118,8 +3127,9 @@ of testing the compiler.
 @itemx nonnull (@var{arg-index}, @dots{})
 @cindex @code{nonnull} function attribute
 @cindex functions with non-null pointer arguments
-The @code{nonnull} attribute specifies that some function parameters should
-be non-null pointers.  For instance, the declaration:
+The @code{nonnull} attribute may be applied to a function that takes at
+least one argument of a pointer type.  It indicates that the referenced
+arguments must be non-null pointers.  For instance, the declaration:
 
 @smallexample
 extern void *
@@ -3354,13 +3364,14 @@ If you need to map the entire contents of a module to a particular
 section, consider using the facilities of the linker instead.
 
 @item sentinel
+@itemx sentinel (@var{position})
 @cindex @code{sentinel} function attribute
-This function attribute ensures that a parameter in a function call is
-an explicit @code{NULL}.  The attribute is only valid on variadic
-functions.  By default, the sentinel is located at position zero, the
-last parameter of the function call.  If an optional integer position
-argument P is supplied to the attribute, the sentinel must be located at
-position P counting backwards from the end of the argument list.
+This function attribute indicates that an argument in a call to the function
+is expected to be an explicit @code{NULL}.  The attribute is only valid on
+variadic functions.  By default, the sentinel is expected to be the last
+argument of the function call.  If the optional @var{position} argument
+is specified to the attribute, the sentinel must be located at
+@var{position} counting backwards from the end of the argument list.
 
 @smallexample
 __attribute__ ((sentinel))
@@ -3372,10 +3383,11 @@ The attribute is automatically set with a position of 0 for the built-in
 functions @code{execl} and @code{execlp}.  The built-in function
 @code{execle} has the attribute set with a position of 1.
 
-A valid @code{NULL} in this context is defined as zero with any pointer
-type.  If your system defines the @code{NULL} macro with an integer type
-then you need to add an explicit cast.  GCC replaces @code{stddef.h}
-with a copy that redefines NULL appropriately.
+A valid @code{NULL} in this context is defined as zero with any object
+pointer type.  If your system defines the @code{NULL} macro with
+an integer type then you need to add an explicit cast.  During
+installation GCC replaces the system @code{<stddef.h>} header with
+a copy that redefines NULL appropriately.
 
 The warnings for missing or incorrect sentinels are enabled with
 @option{-Wformat}.
index c2ec7861c122c72dc25e9467f2037bbcb79b57ed..a31b59d2cc9a42ba35ff0aefe0e1785aef614440 100644 (file)
@@ -1,3 +1,23 @@
+2018-11-15  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/87541
+       PR c++/87542
+       * g++.dg/ext/attr-alloc_size.C: New test.
+       * c-c++-common/pr71574.c: Adjust diagnostics.
+       * c-c++-common/attributes-1.c: Same.
+       * gcc.dg/attr-alloc_align-2.c: Same.
+       * gcc.dg/attr-alloc_align-4.c: New test.
+       * gcc.dg/attr-alloc_size-2.c: Adjust diagnostics.
+       * gcc.dg/attr-alloc_size.c: Same.
+       * gcc.dg/attr-assume_aligned-4.c: New test.
+       * gcc.dg/format/attr-3.c: Adjust diagnostics.
+       * gcc.dg/nonnull-2.c: Same.
+       * gcc.dg/torture/pr80612.c: Same.
+       * obj-c++.dg/attributes/method-format-1.mm: Same.
+       * obj-c++.dg/attributes/method-nonnull-1.mm: Same.
+       * objc.dg/attributes/method-format-1.m: same.
+       * objc.dg/attributes/method-nonnull-1.m: Same.
+
 2018-11-15  Martin Sebor  <msebor@redhat.com>
 
        PR c/83656
index 1657da10d5e40023250544aed9f5e1c03121292e..c4b232dad002aef244bbb5a0542627b6c5657a39 100644 (file)
@@ -1,21 +1,22 @@
 /* { dg-do compile } */
 /* { dg-prune-output "undeclared here \\(not in a function\\)|\[^\n\r\]* was not declared in this scope" } */
 
-void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,bar))); /* { dg-warning "outside range" } */
-void* my_realloc(void*, unsigned) __attribute__((alloc_size(bar))); /* { dg-warning "outside range" } */
+void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,bar))); /* { dg-warning ".alloc_size. attribute argument 2 is invalid" } */
+void* my_realloc(void*, unsigned) __attribute__((alloc_size(bar))); /* { dg-warning ".alloc_size. attribute argument is invalid" } */
 
 typedef char vec __attribute__((vector_size(bar))); /* { dg-warning "ignored" } */
 
-void f1(char*) __attribute__((nonnull(bar))); /* { dg-error "invalid operand" } */
-void f2(char*) __attribute__((nonnull(1,bar))); /* { dg-error "invalid operand" } */
+void f1(char*) __attribute__((nonnull(bar))); /* { dg-warning ".nonnull. attribute argument is invalid" } */
 
-void foo(void);
-void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,foo))); /* { dg-warning "outside range" } */
-void* my_realloc(void*, unsigned) __attribute__((alloc_size(foo))); /* { dg-warning "outside range" } */
+void f2(char*) __attribute__((nonnull(1,bar))); /* { dg-warning ".nonnull. attribute argument 2 is invalid" } */
+
+void foo(int);
+void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,foo))); /* { dg-warning ".alloc_size. attribute argument 2 has type .void\\\(int\\\)." } */
+void* my_realloc(void*, unsigned) __attribute__((alloc_size(foo))); /* { dg-warning ".alloc_size. attribute argument has type .void ?\\\(int\\\)" } */
 
 typedef char vec __attribute__((vector_size(foo))); /* { dg-warning "ignored" } */
 
-void f1(char*) __attribute__((nonnull(foo))); /* { dg-error "invalid operand" } */
-void f2(char*) __attribute__((nonnull(1,foo))); /* { dg-error "invalid operand" } */
+void f1(char*) __attribute__((nonnull(foo))); /* { dg-warning ".nonnull. attribute argument has type .void ?\\\(int\\\)." } */
+void f2(char*) __attribute__((nonnull(1,foo))); /* { dg-warning ".nonnull. attribute argument 2 has type .void ?\\\(int\\\)." } */
 
 void g() __attribute__((aligned(foo))); /* { dg-error "invalid value|not an integer" } */
index 320ae3853cddb709bd849c540af812a01383ab4e..f06624c2d77cad0e3cebd235d3d470aa4bda65fd 100644 (file)
@@ -1,12 +1,15 @@
-/* PR c/71574 */
+/* PR c/71574 - ICE on code with alloc_align attribute */
 /* { dg-do compile } */
 
-int fn1 (void);
-int fn2 (void) __attribute__ ((alloc_align (fn1))); /* { dg-warning "parameter outside range" } */
-int fn3 (void) __attribute__ ((alloc_size (fn1))); /* { dg-warning "parameter outside range" } */
-int fn4 (void) __attribute__ ((assume_aligned (fn1))); /* { dg-warning "not integer constant" } */
-int fn5 (char *, char *) __attribute__((nonnull (fn1))); /* { dg-error "nonnull argument has invalid operand" } */
+int fn1 (int);
+int fn2 (void) __attribute__ ((alloc_align (fn1))); /* { dg-warning ".alloc_align. attribute ignored on a function returning .int." } */
+int fn3 (void) __attribute__ ((alloc_size (fn1))); /* { dg-warning ".alloc_size. attribute ignored on a function returning .int." } */
+int fn4 (void) __attribute__ ((assume_aligned (fn1))); /* { dg-warning ".assume_aligned. attribute ignored on a function returning .int." } */
+int fn5 (char *, char *) __attribute__((nonnull (fn1))); /* { dg-warning ".nonnull. attribute argument has type .int\\\(int\\\)." } */
 int fn6 (const char *, ...) __attribute__ ((sentinel (fn1))); /* { dg-warning "not an integer constant" } */
 
+void* fn7 (void) __attribute__ ((alloc_align (fn1))); /* { dg-warning ".alloc_align. attribute argument has type .int\\\(int\\\)." } */
+void* fn8 (void) __attribute__ ((assume_aligned (fn1))); /* { dg-warning "not an integer constant" } */
+
 typedef int __attribute__((vector_size (fn1))) v4si; /* { dg-warning "attribute ignored" } */
 typedef int T __attribute__((aligned (fn1))); /* { dg-error "requested alignment is not" } */
diff --git a/gcc/testsuite/g++.dg/ext/attr-alloc_size.C b/gcc/testsuite/g++.dg/ext/attr-alloc_size.C
new file mode 100644 (file)
index 0000000..9a42110
--- /dev/null
@@ -0,0 +1,53 @@
+/* PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+#define ALLOC_SIZE(N)   __attribute__ ((alloc_size (N)))
+
+const int i1 = 1;
+ALLOC_SIZE (i1) void* fcst (int);
+
+void* call_fcst (void)
+{
+  void *p = fcst (1);
+  __builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1));   // { dg-warning "\\\[-Wstringop-overflow=" }
+  return p;
+}
+
+
+enum { e1 = 1 };
+ALLOC_SIZE (e1) void* fenum (int);
+
+void* call_fenum (void)
+{
+  void *p = fenum (1);
+  __builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1));   // { dg-warning "\\\[-Wstringop-overflow=" }
+  return p;
+}
+
+
+template <class T>
+struct A
+{
+  ALLOC_SIZE (T::N1) static void* ftemplarg_1 (int);
+  ALLOC_SIZE (T::N2) static void*
+  ftemplarg_2 (int); // { dg-warning "attribute argument value .2. exceeds the number of function parameters 1" }
+};
+
+struct B { static const int N1 = 1; static const int N2 = 1; };
+
+void* call_ftemplarg_1 (A<B> *pa)
+{
+  void *p = pa->ftemplarg_1 (1);
+  __builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1));   // { dg-warning "\\\[-Wstringop-overflow=" }
+  return p;
+}
+
+struct C { static const int N1 = 1; static const int N2 = 2; };
+
+void* call_ftemplarg_2 (A<C> *pa)
+{
+  void *p = pa->ftemplarg_2 (1);
+  __builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1));
+  return p;
+}
index 3dc7a219839c18ce52339516acf2050e9ba3bd94..01321e7785dddbfab312a199e87b9ab282d8508b 100644 (file)
@@ -5,6 +5,6 @@ void *f1 (int) __attribute__((alloc_align (1)));
 void *f2 (int, int, int) __attribute__((alloc_align (3)));
 void *f3 (void) __attribute__((alloc_align)); /* { dg-error "wrong number of arguments specified" } */
 void *f4 (int, int) __attribute__((alloc_align (1, 2))); /* { dg-error "wrong number of arguments specified" } */
-void *f5 (void) __attribute__((alloc_align (i))); /* { dg-warning "outside range" } */
-void *f6 (int) __attribute__((alloc_align (0))); /* { dg-warning "outside range" } */
-void *f7 (int) __attribute__((alloc_align (2))); /* { dg-warning "outside range" } */
+void *f5 (void) __attribute__((alloc_align (i))); /* { dg-warning ".alloc_align. attribute argument value .i. is not an integer constant" } */
+void *f6 (int) __attribute__((alloc_align (0))); /* { dg-warning ".alloc_align. attribute argument value .0. does not refer to a function parameter" } */
+void *f7 (int) __attribute__((alloc_align (2))); /* { dg-warning ".alloc_align. attribute argument value .2. exceeds the number of function parameters 1" } */
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_align-4.c b/gcc/testsuite/gcc.dg/attr-alloc_align-4.c
new file mode 100644 (file)
index 0000000..7cdfc7d
--- /dev/null
@@ -0,0 +1,43 @@
+/* PR middle-end/81871 - bogus attribute alloc_align accepted
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+#define ALIGN(N)   __attribute__ ((alloc_align (N)))
+#define SIZE_MAX  __SIZE_MAX__
+
+ALIGN (1) void fvv_m1 (void);     /* { dg-warning ".alloc_align. attribute ignored on a function returning .void." } */
+
+ALIGN (1) int fiv_1 (void);       /* { dg-warning ".alloc_align. attribute ignored on a function returning .int." } */
+
+ALIGN (0) void* fpvv_0 (void);    /* { dg-warning ".alloc_align. attribute argument value .0. does not refer to a function parameter" } */
+
+ALIGN (1) void* fpvv_1 (void);    /* { dg-warning ".alloc_align. attribute argument value .1. exceeds the number of function parameters 0" } */
+
+ALIGN (2) void* fii_2 (int);      /* { dg-warning ".alloc_align. attribute argument value .2. exceeds the number of function parameters 1" } */
+
+ALIGN (1) void fvi_1 (int);       /* { dg-warning ".alloc_align. attribute ignored on a function returning .void." } */
+
+/* Using alloc_align with a function returning a pointer to a function
+   should perhaps trigger a warning.  */
+typedef void (F)(void);
+ALIGN (1) F* fpF_i_1 (int);
+
+ALIGN (SIZE_MAX) void*
+fpvi_szmax (int);                 /* { dg-warning ".alloc_align. attribute argument value .\[0-9\]+. exceeds the number of function parameters 1" } */
+
+ALIGN ("1") void*
+fpvi_str_1 (int);                 /* { dg-warning ".alloc_align. attribute argument has type .char\\\[2]" } */
+
+ALIGN ((void*)0) void*
+fpvi_pv0 (int);                   /* { dg-warning ".alloc_align. attribute argument has type .void \\\*." } */
+
+ALIGN ((double*)1) void*
+fpvi_pd1 (int);                   /* { dg-warning ".alloc_align. attribute argument has type .double \\\*." } */
+
+ALIGN (1) void*
+fpvi_pv_1 (void*);                /* { dg-warning ".alloc_align. attribute argument value .1. refers to parameter type .void \\\*." } */
+
+struct S { int i; };
+ALIGN (2) void*
+fpvi_S_2 (int, struct S);         /* { dg-warning ".alloc_align. attribute argument value .2. refers to parameter type .struct S." } */
+
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-12.c b/gcc/testsuite/gcc.dg/attr-alloc_size-12.c
new file mode 100644 (file)
index 0000000..2e9be1e
--- /dev/null
@@ -0,0 +1,60 @@
+/* PR middle-end/81871 - bogus attribute alloc_align accepted
+   Test exercising the problem with attribute alloc_size.
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+#define ASIZE(...)   __attribute__ ((alloc_size (__VA_ARGS__)))
+#define SIZE_MAX  __SIZE_MAX__
+
+ASIZE (-1) void fvv_m1 (void);    /* { dg-warning ".alloc_size. attribute ignored on a function returning .void." } */
+
+ASIZE (1) int fiv_1 (void);       /* { dg-warning ".alloc_size. attribute ignored on a function returning .int." } */
+
+ASIZE (1, 2) int fiv_1_2 (void);  /* { dg-warning ".alloc_size. attribute ignored on a function returning .int." } */
+
+ASIZE (0) void* fpvv_0 (void);    /* { dg-warning ".alloc_size. attribute argument value .0. does not refer to a function parameter" } */
+
+ASIZE (1, 0) void*
+fpvv_1_0 (int);                   /* { dg-warning ".alloc_size. attribute argument 2 value .0. does not refer to a function parameter" } */
+
+ASIZE (1) void* fpvv_1 (void);    /* { dg-warning ".alloc_size. attribute argument value .1. exceeds the number of function parameters 0" } */
+
+ASIZE (1, 9) void*
+fpvv_1_9 (int);                   /* { dg-warning ".alloc_size. attribute argument 2 value .9. exceeds the number of function parameters 1" } */
+
+ASIZE (2) void* fii_2 (int);      /* { dg-warning ".alloc_size. attribute argument value .2. exceeds the number of function parameters 1" } */
+
+ASIZE (1) void fvi_1 (int);       /* { dg-warning ".alloc_size. attribute ignored on a function returning .void." } */
+
+/* Using alloc_size with a function returning a pointer to a function
+   should perhaps trigger a warning.  */
+typedef void (F)(void);
+ASIZE (1) F* fpF_i_1 (int);
+
+ASIZE (SIZE_MAX) void*
+fpvi_szmax (int);                 /* { dg-warning ".alloc_size. attribute argument value .\[0-9\]+. exceeds the number of function parameters 1" } */
+
+ASIZE ("12") void*
+fpvi_str_1 (int);                 /* { dg-warning ".alloc_size. attribute argument has type .char\\\[3]." } */
+
+ASIZE (1, "123") void*
+fpvi_str_2 (int, int);            /* { dg-warning ".alloc_size. attribute argument 2 has type .char\\\[4]." } */
+
+ASIZE ((void*)0) void*
+fpvi_pv0 (int);                   /* { dg-warning ".alloc_size. attribute argument has type .void \\\*." } */
+
+ASIZE ((double*)sizeof (double)) void*
+fpvi_pd1 (int);                   /* { dg-warning ".alloc_size. attribute argument has type .double \\\*." } */
+
+ASIZE (1) void*
+fpvi_pv_1 (void*);                /* { dg-warning ".alloc_size. attribute argument value .1. refers to parameter type .void \\\*." } */
+
+struct S { int i; };
+ASIZE (2) void*
+fpvi_S_2 (int, struct S);         /* { dg-warning ".alloc_size. attribute argument value .2. refers to parameter type .struct S." } */
+
+ASIZE ((struct S){ 1 }) void*
+fpvi_S (int);                     /* { dg-warning ".alloc_size. attribute argument has type .struct S." } */
+
+ASIZE (1, (struct S){ 1 }) void*
+fpvi_1_S (int);                   /* { dg-warning ".alloc_size. attribute argument 2 has type .struct S." } */
index 3cac807370ff4e07d97647f1bd8d21e51e2c93a2..3bbd3e2b987917c2f8ed733abe05d80ed740ce6e 100644 (file)
@@ -1,4 +1,5 @@
-/* { dg-do compile } */
-
-char *foo() __attribute__((alloc_size(1))); /* { dg-warning "outside range" } */
+/* PR c/36021 - __attribute__((alloc_size(n))) with function of no
+   arguments causes gcc to segfault
+   { dg-do compile } */
 
+char *foo() __attribute__((alloc_size(1)));
index f50ba7c53db642d24cfdfbf25e90716cbe4581d3..88a777158054f95b9e850dc684edc427f5d6a254 100644 (file)
@@ -5,13 +5,13 @@ extern void abort (void);
 
 #include "../gcc.c-torture/execute/builtins/chk.h"
 
-extern char *mallocminus1(int size) __attribute__((alloc_size(-1))); /* { dg-warning "parameter outside range" } */
-extern char *malloc0(int size) __attribute__((alloc_size(0))); /* { dg-warning "parameter outside range" } */
+extern char *mallocminus1(int size) __attribute__((alloc_size(-1))); /* { dg-warning ".alloc_size. attribute argument value .-1. exceeds the number of function parameters 1" } */
+extern char *malloc0(int size) __attribute__((alloc_size(0))); /* { dg-warning ".alloc_size. attribute argument value .0. does not refer to a function parameter" } */
 extern char *malloc1(int size) __attribute__((alloc_size(1)));
 extern char *malloc2(int empty, int size) __attribute__((alloc_size(2)));
 extern char *calloc1(int size, int elements) __attribute__((alloc_size(1,2)));
 extern char *calloc2(int size, int empty, int elements) __attribute__((alloc_size(1,3)));
-extern char *balloc1(void *size) __attribute__((alloc_size(1)));
+extern char *balloc1(void *size) __attribute__((alloc_size(1)));   /* { dg-warning ".alloc_size. attribute argument value .1. refers to parameter type .void *." } */
 
 void
 test (void)
diff --git a/gcc/testsuite/gcc.dg/attr-assume_aligned-4.c b/gcc/testsuite/gcc.dg/attr-assume_aligned-4.c
new file mode 100644 (file)
index 0000000..84f4523
--- /dev/null
@@ -0,0 +1,36 @@
+/* PR middle-end/87533 - bogus assume_aligned attribute silently accepted
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+#define A(...)  __attribute__ ((assume_aligned (__VA_ARGS__)))
+
+A (1) void fv_1 (void);       /* { dg-warning ".assume_aligned. attribute ignored on a function returning .void." } */
+
+A (1) int fi_1 (void);        /* { dg-warning ".assume_aligned. attribute ignored on a function returning .int." } */
+
+A (-1) void* fpv_m1 (void);   /* { dg-warning ".assume_aligned. attribute argument -1 is not a power of 2" } */
+
+A (0) void* fpv_0 (void);     /* { dg-warning ".assume_aligned. attribute argument 0 is not a power of 2" } */
+
+/* Alignment of 1 is fine, it just doesn't offer any benefits.  */
+A (1) void* fpv_1 (void);
+
+A (3) void* fpv_3 (void);     /* { dg-warning ".assume_aligned. attribute argument 3 is not a power of 2" } */
+
+A (16383) void* fpv_16km1 (void);     /* { dg-warning ".assume_aligned. attribute argument 16383 is not a power of 2" } */
+A (16384) void* fpv_16k (void);
+A (16385) void* fpv_16kp1 (void);    /* { dg-warning ".assume_aligned. attribute argument 16385 is not a power of 2" } */
+
+A (32767) void* fpv_32km1 (void);     /* { dg-warning ".assume_aligned. attribute argument 32767 is not a power of 2" } */
+
+A (4, -1) void* fpv_4_m1 (void);      /* { dg-warning ".assume_aligned. attribute argument -1 is not in the range \\\[0, 4\\\)" } */
+
+A (4, 0) void* fpv_4_0 (void);
+A (4, 1) void* fpv_4_1 (void);
+A (4, 2) void* fpv_4_2 (void);
+A (4, 3) void* fpv_4_3 (void);
+
+A (4, 4) void* fpv_4_3 (void);        /* { dg-warning ".assume_aligned. attribute argument 4 is not in the range \\\[0, 4\\\)" } */
+
+A (4) void* gpv_4_3 (void);
+A (2) void* gpv_4_3 (void);
index bee5ff4841b0d2202255d6d2d17967ce93f8ff2c..31cc05ec5270a609f36e239459d216806e3bcedf 100644 (file)
@@ -41,10 +41,10 @@ extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* {
 /* Both the numbers must be integer constant expressions.  */
 extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-warning ".format. attribute argument 2 value .foo. is not an integer constant" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-warning ".format. attribute argument 3 value .foo. is not an integer constant" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
-extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-warning ".format_arg. attribute argument value .foo. is not an integer constant" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
@@ -56,14 +56,14 @@ extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-warning ".format. attribute argument 2 value .1. refers to parameter type .int." "format int string" } */
 extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
 extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
 extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error ".format. attribute argument 3 value .2. does not refer to a variable argument list" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
-extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-warning ".format_arg. attribute argument value .1. refers to parameter type .int." } */
 extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
 extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
 extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
index d570a467e6a0ae6b2a533038bc0d2a61737c1356..4e3e48dd88de275d5b19797456fc304ebc0c09c4 100644 (file)
@@ -4,11 +4,12 @@
 
 extern void func1 () __attribute__((nonnull)); /* { dg-error "without arguments" } */
 
-extern void func2 (char *) __attribute__((nonnull(2))); /* { dg-error "out-of-range operand" } */
+extern void func2 (char *) __attribute__((nonnull(2))); /* { dg-warning ".nonnull. attribute argument value .2. exceeds the number of function parameters 1" } */
 
-extern void func3 (char *) __attribute__((nonnull(foo))); /* { dg-error "invalid operand number|undeclared" } */
+extern void func3 (char *) __attribute__((nonnull (foo))); /* { dg-warning ".nonnull. attribute argument is invalid" } */
+/* { dg-error ".foo. undeclared" "undeclared argument" { target *-*-* } .-1 } */
 
-extern void func4 (int) __attribute__((nonnull(1))); /* { dg-error "references non-pointer" } */
+extern void func4 (int) __attribute__((nonnull(1))); /* { dg-warning ".nonnull. attribute argument value .1. refers to parameter type .int." } */
 
 void
 foo (void)
index 225b81127a66c6b3c040f8ad21f08b60ca7ac5c2..e648e82559c26f75d22f93c1af7c06b70c963534 100644 (file)
@@ -13,3 +13,5 @@ struct obstack {
 }
 void fn2(int) __attribute__((__alloc_size__(1)));
 void fn3() { fn1(fn2); }
+
+/* { dg-prune-output "attribute ignored" } */
index 11ce8eebbb5e6536fd20fda627960d8fb6e15615..9ff34f92fb179545b4c97ba0094981c164352ac4 100644 (file)
@@ -19,8 +19,8 @@
 - (void) log2: (int)level  message: (const char *) my_format, ...  __attribute__ ((format (printf, 2)));    /* { dg-error "wrong" } */
 + (void) debug2: (const char *) my_format, ...  __attribute__ ((format (printf))); /* { dg-error "wrong" } */
 - (void) debug2: (const char *) my_format, ...  __attribute__ ((format (printf))); /* { dg-error "wrong" } */
-+ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
-- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
++ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
+- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
 @end
 
 void test (LogObject *object)
index 58b8f367439ca5e0f6e86d71338183bbc5b794ce..f83c85377066821bfdecfc3e8d407bca8d292449 100644 (file)
 - (void) insertObject: (id)object  atIndex: (size_t)index  andObject: (id)anotherObject  atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
 
 /* Test the behavior with invalid code.  */
-+ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
-- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
++ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
 
-+ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
-- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
++ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
 
-+ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
-- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
++ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
+- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
 
 + (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "" } */
+  /* { dg-warning "attribute argument is invalid" "" { target *-*-* } .-1 } */
 - (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "" } */
+  /* { dg-warning "attribute argument is invalid" "" { target *-*-* } .-1 } */
 @end
 
 void test (MyArray *object)
index 11ce8eebbb5e6536fd20fda627960d8fb6e15615..9ff34f92fb179545b4c97ba0094981c164352ac4 100644 (file)
@@ -19,8 +19,8 @@
 - (void) log2: (int)level  message: (const char *) my_format, ...  __attribute__ ((format (printf, 2)));    /* { dg-error "wrong" } */
 + (void) debug2: (const char *) my_format, ...  __attribute__ ((format (printf))); /* { dg-error "wrong" } */
 - (void) debug2: (const char *) my_format, ...  __attribute__ ((format (printf))); /* { dg-error "wrong" } */
-+ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
-- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
++ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
+- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
 @end
 
 void test (LogObject *object)
index b60d5a6ba5bda52c84d6c835ee2af604c03612ec..e1974aa3caeba84cab23edcbcd6089a34dc2ab02 100644 (file)
 - (void) insertObject: (id)object  atIndex: (size_t)index  andObject: (id)anotherObject  atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
 
 /* Test the behavior with invalid code.  */
-+ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
-- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
++ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
 
-+ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
-- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
++ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
 
-+ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
-- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
++ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
+- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
 
-+ (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "invalid operand" } */
-- (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "invalid operand" } */
++ (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-warning "is invalid" } */
+- (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-warning "is invalid" } */
 @end
 
 void test (MyArray *object)
index db680a9bae34021f7780c55f32ba7175f7a888f5..be89897d43a9bb0080a84aa59dad7bd57e5b97c8 100644 (file)
@@ -4955,7 +4955,8 @@ build_nt_call_vec (tree fn, vec<tree, va_gc> *args)
   return ret;
 }
 \f
-/* Create a DECL_... node of code CODE, name NAME and data type TYPE.
+/* Create a DECL_... node of code CODE, name NAME  (if non-null)
+   and data type TYPE.
    We do NOT enter this node in any sort of symbol table.
 
    LOC is the location of the decl.
@@ -6944,12 +6945,11 @@ type_list_equal (const_tree l1, const_tree l2)
    then this function counts only the ordinary arguments.  */
 
 int
-type_num_arguments (const_tree type)
+type_num_arguments (const_tree fntype)
 {
   int i = 0;
-  tree t;
 
-  for (t = TYPE_ARG_TYPES (type); t; t = TREE_CHAIN (t))
+  for (tree t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
     /* If the function does not take a variable number of arguments,
        the last element in the list will have type `void'.  */
     if (VOID_TYPE_P (TREE_VALUE (t)))
@@ -6960,6 +6960,40 @@ type_num_arguments (const_tree type)
   return i;
 }
 
+/* Return the type of the function TYPE's argument ARGNO if known.
+   For vararg function's where ARGNO refers to one of the variadic
+   arguments return null.  Otherwise, return a void_type_node for
+   out-of-bounds ARGNO.  */
+
+tree
+type_argument_type (const_tree fntype, unsigned argno)
+{
+  /* Treat zero the same as an out-of-bounds argument number.  */
+  if (!argno)
+    return void_type_node;
+
+  function_args_iterator iter;
+
+  tree argtype;
+  unsigned i = 1;
+  FOREACH_FUNCTION_ARGS (fntype, argtype, iter)
+    {
+      /* A vararg function's argument list ends in a null.  Otherwise,
+        an ordinary function's argument list ends with void.  Return
+        null if ARGNO refers to a vararg argument, void_type_node if
+        it's out of bounds, and the formal argument type otherwise.  */
+      if (!argtype)
+       break;
+
+      if (i == argno || VOID_TYPE_P (argtype))
+       return argtype;
+
+      ++i;
+    }
+
+  return NULL_TREE;
+}
+
 /* Nonzero if integer constants T1 and T2
    represent the same constant value.  */
 
index b825cade61e449ed770c355c0dcd69107f7ba750..c21af9ff6d9781262aa0de0b84628180329939f1 100644 (file)
@@ -4834,6 +4834,7 @@ extern tree get_file_function_name (const char *);
 extern tree get_callee_fndecl (const_tree);
 extern combined_fn get_call_combined_fn (const_tree);
 extern int type_num_arguments (const_tree);
+extern tree type_argument_type (const_tree, unsigned) ATTRIBUTE_NONNULL (1);
 extern bool associative_tree_code (enum tree_code);
 extern bool commutative_tree_code (enum tree_code);
 extern bool commutative_ternary_tree_code (enum tree_code);