diff options
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 1081 |
1 files changed, 8 insertions, 1073 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index ff60620..e50d3fc 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -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. */ @@ -1002,7 +999,8 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, /* If the value is a non-legitimate constant, force it into a pseudo now. TLS symbols sometimes need a call to resolve. */ if (CONSTANT_P (args[i].value) - && !targetm.legitimate_constant_p (args[i].mode, args[i].value)) + && (!targetm.legitimate_constant_p (args[i].mode, args[i].value) + || targetm.precompute_tls_p (args[i].mode, args[i].value))) args[i].value = force_reg (args[i].mode, args[i].value); /* If we're going to have to load the value by parts, pull the @@ -1221,704 +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 (integral) - { - value_range vr; - if (query && 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 = determine_value_range (exp, &min, &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 (TREE_NO_WARNING (exp) || !warn_stringop_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) - TREE_NO_WARNING (exp) = true; - - 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) - TREE_NO_WARNING (exp) = true; - - return any_arg_warned; -} - /* Issue an error if CALL_EXPR was flagged as requiring tall-call optimization. */ @@ -1932,308 +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). */ - bool any_warned = false; - - /* 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. */ - bool arg_warned = false; - 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); - - arg_warned = 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 ()); - } - else - arg_warned = warning_at (loc, OPT_Wstringop_overflow_, - "%Kargument %i value %s is negative", - exp, sizidx + 1, sizstr); - - if (arg_warned) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - any_warned = true; - 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); - - arg_warned = 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); - } - else - arg_warned = warning_at (loc, OPT_Wnonnull, - "%Kargument %i is null but " - "the corresponding size argument " - "%i value is %s", - exp, ptridx + 1, sizidx + 1, - sizstr); - } - 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. */ - arg_warned = warning_at (loc, OPT_Wnonnull, - "%Kargument %i to %<%T[static %E]%> " - "is null where non-null expected", - exp, ptridx + 1, argtype, - access_size); - } - - if (arg_warned) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - any_warned = true; - 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. */ - TREE_NO_WARNING (exp) = 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 (TREE_NO_WARNING (exp)) - { - any_warned = true; - - 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 (any_warned) - { - 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. */ - TREE_NO_WARNING (exp) = true; -} - /* Fill in ARGS_SIZE and ARGS array based on the parameters found in CALL_EXPR EXP. @@ -2333,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++) { @@ -2396,7 +1373,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, already in memory, instead of making a copy. Likewise if we want to make the copy in the callee instead of the caller. */ if ((call_from_thunk_p || callee_copies) - && (base = get_base_address (args[i].tree_value)) + && TREE_CODE (args[i].tree_value) != WITH_SIZE_EXPR + && ((base = get_base_address (args[i].tree_value)), true) && TREE_CODE (base) != SSA_NAME && (!DECL_P (base) || MEM_P (DECL_RTL (base)))) { @@ -2585,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. @@ -3726,7 +2663,7 @@ expand_call (tree exp, rtx target, int ignore) So the entire argument block must then be preallocated (i.e., we ignore PUSH_ROUNDING in that case). */ - int must_preallocate = !PUSH_ARGS; + int must_preallocate = !targetm.calls.push_argument (0); /* Size of the stack reserved for parameter registers. */ int reg_parm_stack_space = 0; @@ -3807,6 +2744,7 @@ expand_call (tree exp, rtx target, int ignore) side-effects. */ if ((flags & (ECF_CONST | ECF_PURE)) && (!(flags & ECF_LOOPING_CONST_OR_PURE)) + && (flags & ECF_NOTHROW) && (ignore || target == const0_rtx || TYPE_MODE (rettype) == VOIDmode)) { @@ -3834,7 +2772,7 @@ expand_call (tree exp, rtx target, int ignore) #endif if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))) - && reg_parm_stack_space > 0 && PUSH_ARGS) + && reg_parm_stack_space > 0 && targetm.calls.push_argument (0)) must_preallocate = 1; /* Set up a place to return a structure. */ @@ -5475,7 +4413,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, } else { - if (!PUSH_ARGS) + if (!targetm.calls.push_argument (0)) argblock = push_block (gen_int_mode (args_size.constant, Pmode), 0, 0); } @@ -6325,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" |