]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/calls.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / calls.c
index 27e8c4516353aa8972894fca8a245489f1863204..e50d3fc3b62080b0e59630c247f7a55aec17eb56 100644 (file)
@@ -17,7 +17,6 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-#define INCLUDE_STRING
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -50,7 +49,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl-iter.h"
 #include "tree-vrp.h"
 #include "tree-ssanames.h"
-#include "tree-ssa-strlen.h"
 #include "intl.h"
 #include "stringpool.h"
 #include "hash-map.h"
@@ -60,7 +58,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "attr-fnspec.h"
 #include "value-query.h"
-
 #include "tree-pretty-print.h"
 
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
@@ -1222,705 +1219,6 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
       }
 }
 
-/* The limit set by -Walloc-larger-than=.  */
-static GTY(()) tree alloc_object_size_limit;
-
-/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than=
-   setting if the option is specified, or to the maximum object size if it
-   is not.  Return the initialized value.  */
-
-static tree
-alloc_max_size (void)
-{
-  if (alloc_object_size_limit)
-    return alloc_object_size_limit;
-
-  HOST_WIDE_INT limit = warn_alloc_size_limit;
-  if (limit == HOST_WIDE_INT_MAX)
-    limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node));
-
-  alloc_object_size_limit = build_int_cst (size_type_node, limit);
-
-  return alloc_object_size_limit;
-}
-
-/* Return true when EXP's range can be determined and set RANGE[] to it
-   after adjusting it if necessary to make EXP a represents a valid size
-   of object, or a valid size argument to an allocation function declared
-   with attribute alloc_size (whose argument may be signed), or to a string
-   manipulation function like memset.
-   When ALLOW_ZERO is set in FLAGS, allow returning a range of [0, 0] for
-   a size in an anti-range [1, N] where N > PTRDIFF_MAX.  A zero range is
-   a (nearly) invalid argument to allocation functions like malloc but it
-   is a valid argument to functions like memset.
-   When USE_LARGEST is set in FLAGS set RANGE to the largest valid subrange
-   in a multi-range, otherwise to the smallest valid subrange.  */
-
-bool
-get_size_range (range_query *query, tree exp, gimple *stmt, tree range[2],
-               int flags /* = 0 */)
-{
-  if (!exp)
-    return false;
-
-  if (tree_fits_uhwi_p (exp))
-    {
-      /* EXP is a constant.  */
-      range[0] = range[1] = exp;
-      return true;
-    }
-
-  tree exptype = TREE_TYPE (exp);
-  bool integral = INTEGRAL_TYPE_P (exptype);
-
-  wide_int min, max;
-  enum value_range_kind range_type;
-
-  if (!query)
-    query = get_global_range_query ();
-
-  if (integral)
-    {
-      value_range vr;
-
-      query->range_of_expr (vr, exp, stmt);
-
-      if (vr.undefined_p ())
-       vr.set_varying (TREE_TYPE (exp));
-      range_type = vr.kind ();
-      min = wi::to_wide (vr.min ());
-      max = wi::to_wide (vr.max ());
-    }
-  else
-    range_type = VR_VARYING;
-
-  if (range_type == VR_VARYING)
-    {
-      if (integral)
-       {       
-         /* Use the full range of the type of the expression when
-            no value range information is available.  */
-         range[0] = TYPE_MIN_VALUE (exptype);
-         range[1] = TYPE_MAX_VALUE (exptype);
-         return true;
-       }
-
-      range[0] = NULL_TREE;
-      range[1] = NULL_TREE;
-      return false;
-    }
-
-  unsigned expprec = TYPE_PRECISION (exptype);
-
-  bool signed_p = !TYPE_UNSIGNED (exptype);
-
-  if (range_type == VR_ANTI_RANGE)
-    {
-      if (signed_p)
-       {
-         if (wi::les_p (max, 0))
-           {
-             /* EXP is not in a strictly negative range.  That means
-                it must be in some (not necessarily strictly) positive
-                range which includes zero.  Since in signed to unsigned
-                conversions negative values end up converted to large
-                positive values, and otherwise they are not valid sizes,
-                the resulting range is in both cases [0, TYPE_MAX].  */
-             min = wi::zero (expprec);
-             max = wi::to_wide (TYPE_MAX_VALUE (exptype));
-           }
-         else if (wi::les_p (min - 1, 0))
-           {
-             /* EXP is not in a negative-positive range.  That means EXP
-                is either negative, or greater than max.  Since negative
-                sizes are invalid make the range [MAX + 1, TYPE_MAX].  */
-             min = max + 1;
-             max = wi::to_wide (TYPE_MAX_VALUE (exptype));
-           }
-         else
-           {
-             max = min - 1;
-             min = wi::zero (expprec);
-           }
-       }
-      else
-       {
-         wide_int maxsize = wi::to_wide (max_object_size ());
-         min = wide_int::from (min, maxsize.get_precision (), UNSIGNED);
-         max = wide_int::from (max, maxsize.get_precision (), UNSIGNED);
-         if (wi::eq_p (0, min - 1))
-           {
-             /* EXP is unsigned and not in the range [1, MAX].  That means
-                it's either zero or greater than MAX.  Even though 0 would
-                normally be detected by -Walloc-zero, unless ALLOW_ZERO
-                is set, set the range to [MAX, TYPE_MAX] so that when MAX
-                is greater than the limit the whole range is diagnosed.  */
-             wide_int maxsize = wi::to_wide (max_object_size ());
-             if (flags & SR_ALLOW_ZERO)
-               {
-                 if (wi::leu_p (maxsize, max + 1)
-                     || !(flags & SR_USE_LARGEST))
-                   min = max = wi::zero (expprec);
-                 else
-                   {
-                     min = max + 1;
-                     max = wi::to_wide (TYPE_MAX_VALUE (exptype));
-                   }
-               }
-             else
-               {
-                 min = max + 1;
-                 max = wi::to_wide (TYPE_MAX_VALUE (exptype));
-               }
-           }
-         else if ((flags & SR_USE_LARGEST)
-                  && wi::ltu_p (max + 1, maxsize))
-           {
-             /* When USE_LARGEST is set and the larger of the two subranges
-                is a valid size, use it...  */
-             min = max + 1;
-             max = maxsize;
-           }
-         else
-           {
-             /* ...otherwise use the smaller subrange.  */
-             max = min - 1;
-             min = wi::zero (expprec);
-           }
-       }
-    }
-
-  range[0] = wide_int_to_tree (exptype, min);
-  range[1] = wide_int_to_tree (exptype, max);
-
-  return true;
-}
-
-bool
-get_size_range (tree exp, tree range[2], int flags /* = 0 */)
-{
-  return get_size_range (/*query=*/NULL, exp, /*stmt=*/NULL, range, flags);
-}
-
-/* Diagnose a call EXP to function FN decorated with attribute alloc_size
-   whose argument numbers given by IDX with values given by ARGS exceed
-   the maximum object size or cause an unsigned oveflow (wrapping) when
-   multiplied.  FN is null when EXP is a call via a function pointer.
-   When ARGS[0] is null the function does nothing.  ARGS[1] may be null
-   for functions like malloc, and non-null for those like calloc that
-   are decorated with a two-argument attribute alloc_size.  */
-
-void
-maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
-{
-  /* The range each of the (up to) two arguments is known to be in.  */
-  tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } };
-
-  /* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2.  */
-  tree maxobjsize = alloc_max_size ();
-
-  location_t loc = EXPR_LOCATION (exp);
-
-  tree fntype = fn ? TREE_TYPE (fn) : TREE_TYPE (TREE_TYPE (exp));
-  bool warned = false;
-
-  /* Validate each argument individually.  */
-  for (unsigned i = 0; i != 2 && args[i]; ++i)
-    {
-      if (TREE_CODE (args[i]) == INTEGER_CST)
-       {
-         argrange[i][0] = args[i];
-         argrange[i][1] = args[i];
-
-         if (tree_int_cst_lt (args[i], integer_zero_node))
-           {
-             warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "%Kargument %i value %qE is negative",
-                                  exp, idx[i] + 1, args[i]);
-           }
-         else if (integer_zerop (args[i]))
-           {
-             /* Avoid issuing -Walloc-zero for allocation functions other
-                than __builtin_alloca that are declared with attribute
-                returns_nonnull because there's no portability risk.  This
-                avoids warning for such calls to libiberty's xmalloc and
-                friends.
-                Also avoid issuing the warning for calls to function named
-                "alloca".  */
-             if (fn && fndecl_built_in_p (fn, BUILT_IN_ALLOCA)
-                 ? IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6
-                 : !lookup_attribute ("returns_nonnull",
-                                      TYPE_ATTRIBUTES (fntype)))
-               warned = warning_at (loc, OPT_Walloc_zero,
-                                    "%Kargument %i value is zero",
-                                    exp, idx[i] + 1);
-           }
-         else if (tree_int_cst_lt (maxobjsize, args[i]))
-           {
-             /* G++ emits calls to ::operator new[](SIZE_MAX) in C++98
-                mode and with -fno-exceptions as a way to indicate array
-                size overflow.  There's no good way to detect C++98 here
-                so avoid diagnosing these calls for all C++ modes.  */
-             if (i == 0
-                 && fn
-                 && !args[1]
-                 && lang_GNU_CXX ()
-                 && DECL_IS_OPERATOR_NEW_P (fn)
-                 && integer_all_onesp (args[i]))
-               continue;
-
-             warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "%Kargument %i value %qE exceeds "
-                                  "maximum object size %E",
-                                  exp, idx[i] + 1, args[i], maxobjsize);
-           }
-       }
-      else if (TREE_CODE (args[i]) == SSA_NAME
-              && get_size_range (args[i], argrange[i]))
-       {
-         /* Verify that the argument's range is not negative (including
-            upper bound of zero).  */
-         if (tree_int_cst_lt (argrange[i][0], integer_zero_node)
-             && tree_int_cst_le (argrange[i][1], integer_zero_node))
-           {
-             warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "%Kargument %i range [%E, %E] is negative",
-                                  exp, idx[i] + 1,
-                                  argrange[i][0], argrange[i][1]);
-           }
-         else if (tree_int_cst_lt (maxobjsize, argrange[i][0]))
-           {
-             warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                                  "%Kargument %i range [%E, %E] exceeds "
-                                  "maximum object size %E",
-                                  exp, idx[i] + 1,
-                                  argrange[i][0], argrange[i][1],
-                                  maxobjsize);
-           }
-       }
-    }
-
-  if (!argrange[0])
-    return;
-
-  /* For a two-argument alloc_size, validate the product of the two
-     arguments if both of their values or ranges are known.  */
-  if (!warned && tree_fits_uhwi_p (argrange[0][0])
-      && argrange[1][0] && tree_fits_uhwi_p (argrange[1][0])
-      && !integer_onep (argrange[0][0])
-      && !integer_onep (argrange[1][0]))
-    {
-      /* Check for overflow in the product of a function decorated with
-        attribute alloc_size (X, Y).  */
-      unsigned szprec = TYPE_PRECISION (size_type_node);
-      wide_int x = wi::to_wide (argrange[0][0], szprec);
-      wide_int y = wi::to_wide (argrange[1][0], szprec);
-
-      wi::overflow_type vflow;
-      wide_int prod = wi::umul (x, y, &vflow);
-
-      if (vflow)
-       warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                            "%Kproduct %<%E * %E%> of arguments %i and %i "
-                            "exceeds %<SIZE_MAX%>",
-                            exp, argrange[0][0], argrange[1][0],
-                            idx[0] + 1, idx[1] + 1);
-      else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod))
-       warned = warning_at (loc, OPT_Walloc_size_larger_than_,
-                            "%Kproduct %<%E * %E%> of arguments %i and %i "
-                            "exceeds maximum object size %E",
-                            exp, argrange[0][0], argrange[1][0],
-                            idx[0] + 1, idx[1] + 1,
-                            maxobjsize);
-
-      if (warned)
-       {
-         /* Print the full range of each of the two arguments to make
-            it clear when it is, in fact, in a range and not constant.  */
-         if (argrange[0][0] != argrange [0][1])
-           inform (loc, "argument %i in the range [%E, %E]",
-                   idx[0] + 1, argrange[0][0], argrange[0][1]);
-         if (argrange[1][0] != argrange [1][1])
-           inform (loc, "argument %i in the range [%E, %E]",
-                   idx[1] + 1, argrange[1][0], argrange[1][1]);
-       }
-    }
-
-  if (warned && fn)
-    {
-      location_t fnloc = DECL_SOURCE_LOCATION (fn);
-
-      if (DECL_IS_UNDECLARED_BUILTIN (fn))
-       inform (loc,
-               "in a call to built-in allocation function %qD", fn);
-      else
-       inform (fnloc,
-               "in a call to allocation function %qD declared here", fn);
-    }
-}
-
-/* If EXPR refers to a character array or pointer declared attribute
-   nonstring return a decl for that array or pointer and set *REF to
-   the referenced enclosing object or pointer.  Otherwise returns
-   null.  */
-
-tree
-get_attr_nonstring_decl (tree expr, tree *ref)
-{
-  tree decl = expr;
-  tree var = NULL_TREE;
-  if (TREE_CODE (decl) == SSA_NAME)
-    {
-      gimple *def = SSA_NAME_DEF_STMT (decl);
-
-      if (is_gimple_assign (def))
-       {
-         tree_code code = gimple_assign_rhs_code (def);
-         if (code == ADDR_EXPR
-             || code == COMPONENT_REF
-             || code == VAR_DECL)
-           decl = gimple_assign_rhs1 (def);
-       }
-      else
-       var = SSA_NAME_VAR (decl);
-    }
-
-  if (TREE_CODE (decl) == ADDR_EXPR)
-    decl = TREE_OPERAND (decl, 0);
-
-  /* To simplify calling code, store the referenced DECL regardless of
-     the attribute determined below, but avoid storing the SSA_NAME_VAR
-     obtained above (it's not useful for dataflow purposes).  */
-  if (ref)
-    *ref = decl;
-
-  /* Use the SSA_NAME_VAR that was determined above to see if it's
-     declared nonstring.  Otherwise drill down into the referenced
-     DECL.  */
-  if (var)
-    decl = var;
-  else if (TREE_CODE (decl) == ARRAY_REF)
-    decl = TREE_OPERAND (decl, 0);
-  else if (TREE_CODE (decl) == COMPONENT_REF)
-    decl = TREE_OPERAND (decl, 1);
-  else if (TREE_CODE (decl) == MEM_REF)
-    return get_attr_nonstring_decl (TREE_OPERAND (decl, 0), ref);
-
-  if (DECL_P (decl)
-      && lookup_attribute ("nonstring", DECL_ATTRIBUTES (decl)))
-    return decl;
-
-  return NULL_TREE;
-}
-
-/* Warn about passing a non-string array/pointer to a built-in function
-   that expects a nul-terminated string argument.  Returns true if
-   a warning has been issued.*/
-
-bool
-maybe_warn_nonstring_arg (tree fndecl, tree exp)
-{
-  if (!fndecl || !fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
-    return false;
-
-  if (!warn_stringop_overread || warning_suppressed_p (exp, OPT_Wstringop_overread))
-    return false;
-
-  /* Avoid clearly invalid calls (more checking done below).  */
-  unsigned nargs = call_expr_nargs (exp);
-  if (!nargs)
-    return false;
-
-  /* The bound argument to a bounded string function like strncpy.  */
-  tree bound = NULL_TREE;
-
-  /* The longest known or possible string argument to one of the comparison
-     functions.  If the length is less than the bound it is used instead.
-     Since the length is only used for warning and not for code generation
-     disable strict mode in the calls to get_range_strlen below.  */
-  tree maxlen = NULL_TREE;
-
-  /* It's safe to call "bounded" string functions with a non-string
-     argument since the functions provide an explicit bound for this
-     purpose.  The exception is strncat where the bound may refer to
-     either the destination or the source.  */
-  int fncode = DECL_FUNCTION_CODE (fndecl);
-  switch (fncode)
-    {
-    case BUILT_IN_STRCMP:
-    case BUILT_IN_STRNCMP:
-    case BUILT_IN_STRNCASECMP:
-      {
-       /* For these, if one argument refers to one or more of a set
-          of string constants or arrays of known size, determine
-          the range of their known or possible lengths and use it
-          conservatively as the bound for the unbounded function,
-          and to adjust the range of the bound of the bounded ones.  */
-       for (unsigned argno = 0;
-            argno < MIN (nargs, 2)
-              && !(maxlen && TREE_CODE (maxlen) == INTEGER_CST); argno++)
-         {
-           tree arg = CALL_EXPR_ARG (exp, argno);
-           if (!get_attr_nonstring_decl (arg))
-             {
-               c_strlen_data lendata = { };
-               /* Set MAXBOUND to an arbitrary non-null non-integer
-                  node as a request to have it set to the length of
-                  the longest string in a PHI.  */
-               lendata.maxbound = arg;
-               get_range_strlen (arg, &lendata, /* eltsize = */ 1);
-               maxlen = lendata.maxbound;
-             }
-         }
-      }
-      /* Fall through.  */
-
-    case BUILT_IN_STRNCAT:
-    case BUILT_IN_STPNCPY:
-    case BUILT_IN_STRNCPY:
-      if (nargs > 2)
-       bound = CALL_EXPR_ARG (exp, 2);
-      break;
-
-    case BUILT_IN_STRNDUP:
-      if (nargs > 1)
-       bound = CALL_EXPR_ARG (exp, 1);
-      break;
-
-    case BUILT_IN_STRNLEN:
-      {
-       tree arg = CALL_EXPR_ARG (exp, 0);
-       if (!get_attr_nonstring_decl (arg))
-         {
-           c_strlen_data lendata = { };
-           /* Set MAXBOUND to an arbitrary non-null non-integer
-              node as a request to have it set to the length of
-              the longest string in a PHI.  */
-           lendata.maxbound = arg;
-           get_range_strlen (arg, &lendata, /* eltsize = */ 1);
-           maxlen = lendata.maxbound;
-         }
-       if (nargs > 1)
-         bound = CALL_EXPR_ARG (exp, 1);
-       break;
-      }
-
-    default:
-      break;
-    }
-
-  /* Determine the range of the bound argument (if specified).  */
-  tree bndrng[2] = { NULL_TREE, NULL_TREE };
-  if (bound)
-    {
-      STRIP_NOPS (bound);
-      get_size_range (bound, bndrng);
-    }
-
-  location_t loc = EXPR_LOCATION (exp);
-
-  if (bndrng[0])
-    {
-      /* Diagnose excessive bound prior to the adjustment below and
-        regardless of attribute nonstring.  */
-      tree maxobjsize = max_object_size ();
-      if (tree_int_cst_lt (maxobjsize, bndrng[0]))
-       {
-         bool warned = false;
-         if (tree_int_cst_equal (bndrng[0], bndrng[1]))
-           warned = warning_at (loc, OPT_Wstringop_overread,
-                                "%K%qD specified bound %E "
-                                "exceeds maximum object size %E",
-                                exp, fndecl, bndrng[0], maxobjsize);
-         else
-           warned = warning_at (loc, OPT_Wstringop_overread,
-                                "%K%qD specified bound [%E, %E] "
-                                "exceeds maximum object size %E",
-                                exp, fndecl, bndrng[0], bndrng[1],
-                                maxobjsize);
-         if (warned)
-           suppress_warning (exp, OPT_Wstringop_overread);
-
-         return warned;
-       }
-    }
-
-  if (maxlen && !integer_all_onesp (maxlen))
-    {
-      /* Add one for the nul.  */
-      maxlen = const_binop (PLUS_EXPR, TREE_TYPE (maxlen), maxlen,
-                           size_one_node);
-
-      if (!bndrng[0])
-       {
-         /* Conservatively use the upper bound of the lengths for
-            both the lower and the upper bound of the operation.  */
-         bndrng[0] = maxlen;
-         bndrng[1] = maxlen;
-         bound = void_type_node;
-       }
-      else if (maxlen)
-       {
-         /* Replace the bound on the operation with the upper bound
-            of the length of the string if the latter is smaller.  */
-         if (tree_int_cst_lt (maxlen, bndrng[0]))
-           bndrng[0] = maxlen;
-         else if (tree_int_cst_lt (maxlen, bndrng[1]))
-           bndrng[1] = maxlen;
-       }
-    }
-
-  bool any_arg_warned = false;
-  /* Iterate over the built-in function's formal arguments and check
-     each const char* against the actual argument.  If the actual
-     argument is declared attribute non-string issue a warning unless
-     the argument's maximum length is bounded.  */
-  function_args_iterator it;
-  function_args_iter_init (&it, TREE_TYPE (fndecl));
-
-  for (unsigned argno = 0; ; ++argno, function_args_iter_next (&it))
-    {
-      /* Avoid iterating past the declared argument in a call
-        to function declared without a prototype.  */
-      if (argno >= nargs)
-       break;
-
-      tree argtype = function_args_iter_cond (&it);
-      if (!argtype)
-       break;
-
-      if (TREE_CODE (argtype) != POINTER_TYPE)
-       continue;
-
-      argtype = TREE_TYPE (argtype);
-
-      if (TREE_CODE (argtype) != INTEGER_TYPE
-         || !TYPE_READONLY (argtype))
-       continue;
-
-      argtype = TYPE_MAIN_VARIANT (argtype);
-      if (argtype != char_type_node)
-       continue;
-
-      tree callarg = CALL_EXPR_ARG (exp, argno);
-      if (TREE_CODE (callarg) == ADDR_EXPR)
-       callarg = TREE_OPERAND (callarg, 0);
-
-      /* See if the destination is declared with attribute "nonstring".  */
-      tree decl = get_attr_nonstring_decl (callarg);
-      if (!decl)
-       continue;
-
-      /* The maximum number of array elements accessed.  */
-      offset_int wibnd = 0;
-
-      if (argno && fncode == BUILT_IN_STRNCAT)
-       {
-         /* See if the bound in strncat is derived from the length
-            of the strlen of the destination (as it's expected to be).
-            If so, reset BOUND and FNCODE to trigger a warning.  */
-         tree dstarg = CALL_EXPR_ARG (exp, 0);
-         if (is_strlen_related_p (dstarg, bound))
-           {
-             /* The bound applies to the destination, not to the source,
-                so reset these to trigger a warning without mentioning
-                the bound.  */
-             bound = NULL;
-             fncode = 0;
-           }
-         else if (bndrng[1])
-           /* Use the upper bound of the range for strncat.  */
-           wibnd = wi::to_offset (bndrng[1]);
-       }
-      else if (bndrng[0])
-       /* Use the lower bound of the range for functions other than
-          strncat.  */
-       wibnd = wi::to_offset (bndrng[0]);
-
-      /* Determine the size of the argument array if it is one.  */
-      offset_int asize = wibnd;
-      bool known_size = false;
-      tree type = TREE_TYPE (decl);
-
-      /* Determine the array size.  For arrays of unknown bound and
-        pointers reset BOUND to trigger the appropriate warning.  */
-      if (TREE_CODE (type) == ARRAY_TYPE)
-       {
-         if (tree arrbnd = TYPE_DOMAIN (type))
-           {
-             if ((arrbnd = TYPE_MAX_VALUE (arrbnd)))
-               {
-                 asize = wi::to_offset (arrbnd) + 1;
-                 known_size = true;
-               }
-           }
-         else if (bound == void_type_node)
-           bound = NULL_TREE;
-       }
-      else if (bound == void_type_node)
-       bound = NULL_TREE;
-
-      /* In a call to strncat with a bound in a range whose lower but
-        not upper bound is less than the array size, reset ASIZE to
-        be the same as the bound and the other variable to trigger
-        the apprpriate warning below.  */
-      if (fncode == BUILT_IN_STRNCAT
-         && bndrng[0] != bndrng[1]
-         && wi::ltu_p (wi::to_offset (bndrng[0]), asize)
-         && (!known_size
-             || wi::ltu_p (asize, wibnd)))
-       {
-         asize = wibnd;
-         bound = NULL_TREE;
-         fncode = 0;
-       }
-
-      bool warned = false;
-
-      auto_diagnostic_group d;
-      if (wi::ltu_p (asize, wibnd))
-       {
-         if (bndrng[0] == bndrng[1])
-           warned = warning_at (loc, OPT_Wstringop_overread,
-                                "%qD argument %i declared attribute "
-                                "%<nonstring%> is smaller than the specified "
-                                "bound %wu",
-                                fndecl, argno + 1, wibnd.to_uhwi ());
-         else if (wi::ltu_p (asize, wi::to_offset (bndrng[0])))
-           warned = warning_at (loc, OPT_Wstringop_overread,
-                                "%qD argument %i declared attribute "
-                                "%<nonstring%> is smaller than "
-                                "the specified bound [%E, %E]",
-                                fndecl, argno + 1, bndrng[0], bndrng[1]);
-         else
-           warned = warning_at (loc, OPT_Wstringop_overread,
-                                "%qD argument %i declared attribute "
-                                "%<nonstring%> may be smaller than "
-                                "the specified bound [%E, %E]",
-                                fndecl, argno + 1, bndrng[0], bndrng[1]);
-       }
-      else if (fncode == BUILT_IN_STRNCAT)
-       ; /* Avoid warning for calls to strncat() when the bound
-            is equal to the size of the non-string argument.  */
-      else if (!bound)
-       warned = warning_at (loc, OPT_Wstringop_overread,
-                            "%qD argument %i declared attribute %<nonstring%>",
-                            fndecl, argno + 1);
-
-      if (warned)
-       {
-         inform (DECL_SOURCE_LOCATION (decl),
-                 "argument %qD declared here", decl);
-         any_arg_warned = true;
-       }
-    }
-
-  if (any_arg_warned)
-    suppress_warning (exp, OPT_Wstringop_overread);
-
-  return any_arg_warned;
-}
-
 /* Issue an error if CALL_EXPR was flagged as requiring
    tall-call optimization.  */
 
@@ -1934,312 +1232,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason)
   error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason);
 }
 
-/* Returns the type of the argument ARGNO to function with type FNTYPE
-   or null when the typoe cannot be determined or no such argument exists.  */
-
-static tree
-fntype_argno_type (tree fntype, unsigned argno)
-{
-  if (!prototype_p (fntype))
-    return NULL_TREE;
-
-  tree argtype;
-  function_args_iterator it;
-  FOREACH_FUNCTION_ARGS (fntype, argtype, it)
-    if (argno-- == 0)
-      return argtype;
-
-  return NULL_TREE;
-}
-
-/* Helper to append the "human readable" attribute access specification
-   described by ACCESS to the array ATTRSTR with size STRSIZE.  Used in
-   diagnostics.  */
-
-static inline void
-append_attrname (const std::pair<int, attr_access> &access,
-                char *attrstr, size_t strsize)
-{
-  if (access.second.internal_p)
-    return;
-
-  tree str = access.second.to_external_string ();
-  gcc_assert (strsize >= (size_t) TREE_STRING_LENGTH (str));
-  strcpy (attrstr, TREE_STRING_POINTER (str));
-}
-
-/* Iterate over attribute access read-only, read-write, and write-only
-   arguments and diagnose past-the-end accesses and related problems
-   in the function call EXP.  */
-
-static void
-maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp)
-{
-  auto_diagnostic_group adg;
-
-  /* Set if a warning has been issued for any argument (used to decide
-     whether to emit an informational note at the end).  */
-  opt_code opt_warned = N_OPTS;
-
-  /* A string describing the attributes that the warnings issued by this
-     function apply to.  Used to print one informational note per function
-     call, rather than one per warning.  That reduces clutter.  */
-  char attrstr[80];
-  attrstr[0] = 0;
-
-  for (rdwr_map::iterator it = rwm->begin (); it != rwm->end (); ++it)
-    {
-      std::pair<int, attr_access> access = *it;
-
-      /* Get the function call arguments corresponding to the attribute's
-        positional arguments.  When both arguments have been specified
-        there will be two entries in *RWM, one for each.  They are
-        cross-referenced by their respective argument numbers in
-        ACCESS.PTRARG and ACCESS.SIZARG.  */
-      const int ptridx = access.second.ptrarg;
-      const int sizidx = access.second.sizarg;
-
-      gcc_assert (ptridx != -1);
-      gcc_assert (access.first == ptridx || access.first == sizidx);
-
-      /* The pointer is set to null for the entry corresponding to
-        the size argument.  Skip it.  It's handled when the entry
-        corresponding to the pointer argument comes up.  */
-      if (!access.second.ptr)
-       continue;
-
-      tree ptrtype = fntype_argno_type (fntype, ptridx);
-      tree argtype = TREE_TYPE (ptrtype);
-
-      /* The size of the access by the call.  */
-      tree access_size;
-      if (sizidx == -1)
-       {
-         /* If only the pointer attribute operand was specified and
-            not size, set SIZE to the greater of MINSIZE or size of
-            one element of the pointed to type to detect smaller
-            objects (null pointers are diagnosed in this case only
-            if the pointer is also declared with attribute nonnull.  */
-         if (access.second.minsize
-             && access.second.minsize != HOST_WIDE_INT_M1U)
-           access_size = build_int_cstu (sizetype, access.second.minsize);
-         else
-           access_size = size_one_node;
-       }
-      else
-       access_size = rwm->get (sizidx)->size;
-
-      /* Format the value or range to avoid an explosion of messages.  */
-      char sizstr[80];
-      tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) };
-      if (get_size_range (access_size, sizrng, true))
-       {
-         char *s0 = print_generic_expr_to_str (sizrng[0]);
-         if (tree_int_cst_equal (sizrng[0], sizrng[1]))
-           {
-             gcc_checking_assert (strlen (s0) < sizeof sizstr);
-             strcpy (sizstr, s0);
-           }
-         else
-           {
-             char *s1 = print_generic_expr_to_str (sizrng[1]);
-             gcc_checking_assert (strlen (s0) + strlen (s1)
-                                  < sizeof sizstr - 4);
-             sprintf (sizstr, "[%s, %s]", s0, s1);
-             free (s1);
-           }
-         free (s0);
-       }
-      else
-       *sizstr = '\0';
-
-      /* Set if a warning has been issued for the current argument.  */
-      opt_code arg_warned = N_OPTS;
-      location_t loc = EXPR_LOCATION (exp);
-      tree ptr = access.second.ptr;
-      if (*sizstr
-         && tree_int_cst_sgn (sizrng[0]) < 0
-         && tree_int_cst_sgn (sizrng[1]) < 0)
-       {
-         /* Warn about negative sizes.  */
-         if (access.second.internal_p)
-           {
-             const std::string argtypestr
-               = access.second.array_as_string (ptrtype);
-
-             if (warning_at (loc, OPT_Wstringop_overflow_,
-                             "%Kbound argument %i value %s is "
-                             "negative for a variable length array "
-                             "argument %i of type %s",
-                             exp, sizidx + 1, sizstr,
-                             ptridx + 1, argtypestr.c_str ()))
-               arg_warned = OPT_Wstringop_overflow_;
-           }
-         else if (warning_at (loc, OPT_Wstringop_overflow_,
-                              "%Kargument %i value %s is negative",
-                              exp, sizidx + 1, sizstr))
-           arg_warned = OPT_Wstringop_overflow_;
-
-         if (arg_warned != N_OPTS)
-           {
-             append_attrname (access, attrstr, sizeof attrstr);
-             /* Remember a warning has been issued and avoid warning
-                again below for the same attribute.  */
-             opt_warned = arg_warned;
-             continue;
-           }
-       }
-
-      if (tree_int_cst_sgn (sizrng[0]) >= 0)
-       {
-         if (COMPLETE_TYPE_P (argtype))
-           {
-             /* Multiply ACCESS_SIZE by the size of the type the pointer
-                argument points to.  If it's incomplete the size is used
-                as is.  */
-             if (tree argsize = TYPE_SIZE_UNIT (argtype))
-               if (TREE_CODE (argsize) == INTEGER_CST)
-                 {
-                   const int prec = TYPE_PRECISION (sizetype);
-                   wide_int minsize = wi::to_wide (sizrng[0], prec);
-                   minsize *= wi::to_wide (argsize, prec);
-                   access_size = wide_int_to_tree (sizetype, minsize);
-                 }
-           }
-       }
-      else
-       access_size = NULL_TREE;
-
-      if (integer_zerop (ptr))
-       {
-         if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0)
-           {
-             /* Warn about null pointers with positive sizes.  This is
-                different from also declaring the pointer argument with
-                attribute nonnull when the function accepts null pointers
-                only when the corresponding size is zero.  */
-             if (access.second.internal_p)
-               {
-                 const std::string argtypestr
-                   = access.second.array_as_string (ptrtype);
-
-                 if (warning_at (loc, OPT_Wnonnull,
-                                 "%Kargument %i of variable length "
-                                 "array %s is null but "
-                                 "the corresponding bound argument "
-                                 "%i value is %s",
-                                 exp, sizidx + 1, argtypestr.c_str (),
-                                 ptridx + 1, sizstr))
-                   arg_warned = OPT_Wnonnull;
-               }
-             else if (warning_at (loc, OPT_Wnonnull,
-                                  "%Kargument %i is null but "
-                                  "the corresponding size argument "
-                                  "%i value is %s",
-                                  exp, ptridx + 1, sizidx + 1,
-                                  sizstr))
-               arg_warned = OPT_Wnonnull;
-           }
-         else if (access_size && access.second.static_p)
-           {
-             /* Warn about null pointers for [static N] array arguments
-                but do not warn for ordinary (i.e., nonstatic) arrays.  */
-             if (warning_at (loc, OPT_Wnonnull,
-                             "%Kargument %i to %<%T[static %E]%> "
-                             "is null where non-null expected",
-                             exp, ptridx + 1, argtype,
-                             access_size))
-               arg_warned = OPT_Wnonnull;              
-           }
-
-         if (arg_warned)
-           {
-             append_attrname (access, attrstr, sizeof attrstr);
-             /* Remember a warning has been issued and avoid warning
-                again below for the same attribute.  */
-             opt_warned = OPT_Wnonnull;
-             continue;
-           }
-       }
-
-      access_data data (ptr, access.second.mode, NULL_TREE, false,
-                       NULL_TREE, false);
-      access_ref* const pobj = (access.second.mode == access_write_only
-                               ? &data.dst : &data.src);
-      tree objsize = compute_objsize (ptr, 1, pobj);
-
-      /* The size of the destination or source object.  */
-      tree dstsize = NULL_TREE, srcsize = NULL_TREE;
-      if (access.second.mode == access_read_only
-         || access.second.mode == access_none)
-       {
-         /* For a read-only argument there is no destination.  For
-            no access, set the source as well and differentiate via
-            the access flag below.  */
-         srcsize = objsize;
-         if (access.second.mode == access_read_only
-             || access.second.mode == access_none)
-           {
-             /* For a read-only attribute there is no destination so
-                clear OBJSIZE.  This emits "reading N bytes" kind of
-                diagnostics instead of the "writing N bytes" kind,
-                unless MODE is none.  */
-             objsize = NULL_TREE;
-           }
-       }
-      else
-       dstsize = objsize;
-
-      /* Clear the no-warning bit in case it was set by check_access
-        in a prior iteration so that accesses via different arguments
-        are diagnosed.  */
-      suppress_warning (exp, OPT_Wstringop_overflow_, false);
-      access_mode mode = data.mode;
-      if (mode == access_deferred)
-       mode = TYPE_READONLY (argtype) ? access_read_only : access_read_write;
-      check_access (exp, access_size, /*maxread=*/ NULL_TREE, srcsize,
-                   dstsize, mode, &data);
-
-      if (warning_suppressed_p (exp, OPT_Wstringop_overflow_))
-       opt_warned = OPT_Wstringop_overflow_;
-      if (opt_warned != N_OPTS)
-       {
-         if (access.second.internal_p)
-           inform (loc, "referencing argument %u of type %qT",
-                   ptridx + 1, ptrtype);
-         else
-           /* If check_access issued a warning above, append the relevant
-              attribute to the string.  */
-           append_attrname (access, attrstr, sizeof attrstr);
-       }
-    }
-
-  if (*attrstr)
-    {
-      if (fndecl)
-       inform (DECL_SOURCE_LOCATION (fndecl),
-               "in a call to function %qD declared with attribute %qs",
-               fndecl, attrstr);
-      else
-       inform (EXPR_LOCATION (fndecl),
-               "in a call with type %qT and attribute %qs",
-               fntype, attrstr);
-    }
-  else if (opt_warned != N_OPTS)
-    {
-      if (fndecl)
-       inform (DECL_SOURCE_LOCATION (fndecl),
-               "in a call to function %qD", fndecl);
-      else
-       inform (EXPR_LOCATION (fndecl),
-               "in a call with type %qT", fntype);
-    }
-
-  /* Set the bit in case if was cleared and not set above.  */
-  if (opt_warned != N_OPTS)
-    suppress_warning (exp, opt_warned);
-}
-
 /* Fill in ARGS_SIZE and ARGS array based on the parameters found in
    CALL_EXPR EXP.
 
@@ -2339,27 +1331,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
 
   bitmap_obstack_release (NULL);
 
-  tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
-  /* Extract attribute alloc_size from the type of the called expression
-     (which could be a function or a function pointer) and if set, store
-     the indices of the corresponding arguments in ALLOC_IDX, and then
-     the actual argument(s) at those indices in ALLOC_ARGS.  */
-  int alloc_idx[2] = { -1, -1 };
-  if (tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs))
-    {
-      tree args = TREE_VALUE (alloc_size);
-      alloc_idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
-      if (TREE_CHAIN (args))
-       alloc_idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
-    }
-
-  /* Array for up to the two attribute alloc_size arguments.  */
-  tree alloc_args[] = { NULL_TREE, NULL_TREE };
-
-  /* Map of attribute accewss specifications for function arguments.  */
-  rdwr_map rdwr_idx;
-  init_attr_rdwr_indices (&rdwr_idx, fntypeattrs);
-
   /* I counts args in order (to be) pushed; ARGPOS counts in order written.  */
   for (argpos = 0; argpos < num_actuals; i--, argpos++)
     {
@@ -2592,48 +1563,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
         does pass the promoted mode.  */
       arg.mode = TYPE_MODE (type);
       targetm.calls.function_arg_advance (args_so_far, arg);
-
-      /* Store argument values for functions decorated with attribute
-        alloc_size.  */
-      if (argpos == alloc_idx[0])
-       alloc_args[0] = args[i].tree_value;
-      else if (argpos == alloc_idx[1])
-       alloc_args[1] = args[i].tree_value;
-
-      /* Save the actual argument that corresponds to the access attribute
-        operand for later processing.  */
-      if (attr_access *access = rdwr_idx.get (argpos))
-       {
-         if (POINTER_TYPE_P (type))
-           {
-             access->ptr = args[i].tree_value;
-             // A nonnull ACCESS->SIZE contains VLA bounds.  */
-           }
-         else
-           {
-             access->size = args[i].tree_value;
-             gcc_assert (access->ptr == NULL_TREE);
-           }
-       }
-    }
-
-  if (alloc_args[0])
-    {
-      /* Check the arguments of functions decorated with attribute
-        alloc_size.  */
-      maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx);
     }
-
-  /* Detect passing non-string arguments to functions expecting
-     nul-terminated strings.  */
-  maybe_warn_nonstring_arg (fndecl, exp);
-
-  /* Check attribute access arguments.  */
-  maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, exp);
-
-  /* Check calls to operator new for mismatched forms and attempts
-     to deallocate unallocated objects.  */
-  maybe_emit_free_warning (exp);
 }
 
 /* Update ARGS_SIZE to contain the total size for the argument block.
@@ -6333,6 +5263,3 @@ cxx17_empty_base_field_p (const_tree field)
          && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
          && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field)));
 }
-
-/* Tell the garbage collector about GTY markers in this source file.  */
-#include "gt-calls.h"