re PR tree-optimization/79327 (wrong code at -O2 and -fprintf-return-value)
PR tree-optimization/79327 * gimple-ssa-sprintf.c (adjust_range_for_overflow): If returning true, always set *argmin and *argmax to TYPE_{MIN,MAX}_VALUE of dirtype. (format_integer): Use wide_int_to_tree instead of build_int_cst + to_?hwi. If argmin is NULL, just set argmin and argmax to TYPE_{MIN,MAX}_VALUE of argtype. Simplify and fix computation of shortest and longest sequence. * gcc.dg/tree-ssa/pr79327.c: New test. * gcc.dg/tree-ssa/builtin-sprintf-warn-1.c (test_sprintf_chk_hh_nonconst): Don't expect 2 bogus warnings. * gcc.dg/tree-ssa/builtin-sprintf-warn-3.c (test_sprintf_chk_range_schar): Adjust dg-message. * gcc.dg/tree-ssa/builtin-sprintf-warn-12.c: New test. * gcc.c-torture/execute/pr79327.c: New test. Co-Authored-By: Martin Sebor <msebor@redhat.com> From-SVN: r245166
This commit is contained in:
parent
b333e8ebb0
commit
5b00f9d236
8 changed files with 340 additions and 78 deletions
|
@ -1,3 +1,14 @@
|
|||
2017-02-03 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR tree-optimization/79327
|
||||
* gimple-ssa-sprintf.c (adjust_range_for_overflow): If returning
|
||||
true, always set *argmin and *argmax to TYPE_{MIN,MAX}_VALUE of
|
||||
dirtype.
|
||||
(format_integer): Use wide_int_to_tree instead of build_int_cst
|
||||
+ to_?hwi. If argmin is NULL, just set argmin and argmax to
|
||||
TYPE_{MIN,MAX}_VALUE of argtype. Simplify and fix computation
|
||||
of shortest and longest sequence.
|
||||
|
||||
2017-02-03 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* config/i386/i386.c (dimode_scalar_chain::convert_reg):
|
||||
|
|
|
@ -1014,8 +1014,8 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
|
|||
determined by checking for the actual argument being in the range
|
||||
of the type of the directive. If it isn't it must be assumed to
|
||||
take on the full range of the directive's type.
|
||||
Return true when the range has been adjusted to the full unsigned
|
||||
range of DIRTYPE, or [0, DIRTYPE_MAX], and false otherwise. */
|
||||
Return true when the range has been adjusted to the full range
|
||||
of DIRTYPE, and false otherwise. */
|
||||
|
||||
static bool
|
||||
adjust_range_for_overflow (tree dirtype, tree *argmin, tree *argmax)
|
||||
|
@ -1051,20 +1051,8 @@ adjust_range_for_overflow (tree dirtype, tree *argmin, tree *argmax)
|
|||
return false;
|
||||
}
|
||||
|
||||
tree dirmin = TYPE_MIN_VALUE (dirtype);
|
||||
tree dirmax = TYPE_MAX_VALUE (dirtype);
|
||||
|
||||
if (TYPE_UNSIGNED (dirtype))
|
||||
{
|
||||
*argmin = dirmin;
|
||||
*argmax = dirmax;
|
||||
}
|
||||
else
|
||||
{
|
||||
*argmin = integer_zero_node;
|
||||
*argmax = dirmin;
|
||||
}
|
||||
|
||||
*argmin = TYPE_MIN_VALUE (dirtype);
|
||||
*argmax = TYPE_MAX_VALUE (dirtype);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1260,10 +1248,8 @@ format_integer (const directive &dir, tree arg)
|
|||
enum value_range_type range_type = get_range_info (arg, &min, &max);
|
||||
if (range_type == VR_RANGE)
|
||||
{
|
||||
argmin = build_int_cst (argtype, wi::fits_uhwi_p (min)
|
||||
? min.to_uhwi () : min.to_shwi ());
|
||||
argmax = build_int_cst (argtype, wi::fits_uhwi_p (max)
|
||||
? max.to_uhwi () : max.to_shwi ());
|
||||
argmin = wide_int_to_tree (argtype, min);
|
||||
argmax = wide_int_to_tree (argtype, max);
|
||||
|
||||
/* Set KNOWNRANGE if the argument is in a known subrange
|
||||
of the directive's type (KNOWNRANGE may be reset below). */
|
||||
|
@ -1307,47 +1293,16 @@ format_integer (const directive &dir, tree arg)
|
|||
|
||||
if (!argmin)
|
||||
{
|
||||
/* For an unknown argument (e.g., one passed to a vararg function)
|
||||
or one whose value range cannot be determined, create a T_MIN
|
||||
constant if the argument's type is signed and T_MAX otherwise,
|
||||
and use those to compute the range of bytes that the directive
|
||||
can output. When precision may be zero, use zero as the minimum
|
||||
since it results in no bytes on output (unless width is specified
|
||||
to be greater than 0). */
|
||||
bool zero = dir.prec[0] <= 0 && dir.prec[1] >= 0;
|
||||
argmin = build_int_cst (argtype, !zero);
|
||||
|
||||
int typeprec = TYPE_PRECISION (dirtype);
|
||||
int argprec = TYPE_PRECISION (argtype);
|
||||
|
||||
if (argprec < typeprec)
|
||||
if (TREE_CODE (argtype) == POINTER_TYPE)
|
||||
{
|
||||
if (POINTER_TYPE_P (argtype))
|
||||
argmax = build_all_ones_cst (argtype);
|
||||
else if (TYPE_UNSIGNED (argtype))
|
||||
argmax = TYPE_MAX_VALUE (argtype);
|
||||
else
|
||||
argmax = TYPE_MIN_VALUE (argtype);
|
||||
argmin = build_int_cst (pointer_sized_int_node, 0);
|
||||
argmax = build_all_ones_cst (pointer_sized_int_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (POINTER_TYPE_P (dirtype))
|
||||
argmax = build_all_ones_cst (dirtype);
|
||||
else if (TYPE_UNSIGNED (dirtype))
|
||||
argmax = TYPE_MAX_VALUE (dirtype);
|
||||
else
|
||||
argmax = TYPE_MIN_VALUE (dirtype);
|
||||
argmin = TYPE_MIN_VALUE (argtype);
|
||||
argmax = TYPE_MAX_VALUE (argtype);
|
||||
}
|
||||
|
||||
res.argmin = argmin;
|
||||
res.argmax = argmax;
|
||||
}
|
||||
|
||||
if (tree_int_cst_lt (argmax, argmin))
|
||||
{
|
||||
tree tmp = argmax;
|
||||
argmax = argmin;
|
||||
argmin = tmp;
|
||||
}
|
||||
|
||||
/* Clear KNOWNRANGE if the range has been adjusted to the maximum
|
||||
|
@ -1361,34 +1316,33 @@ format_integer (const directive &dir, tree arg)
|
|||
res.argmax = argmax;
|
||||
}
|
||||
|
||||
/* Recursively compute the minimum and maximum from the known range,
|
||||
taking care to swap them if the lower bound results in longer
|
||||
output than the upper bound (e.g., in the range [-1, 0]. */
|
||||
|
||||
if (TYPE_UNSIGNED (dirtype))
|
||||
/* Recursively compute the minimum and maximum from the known range. */
|
||||
if (TYPE_UNSIGNED (dirtype) || tree_int_cst_sgn (argmin) >= 0)
|
||||
{
|
||||
/* For unsigned conversions/directives, use the minimum (i.e., 0
|
||||
or 1) and maximum to compute the shortest and longest output,
|
||||
respectively. */
|
||||
/* For unsigned conversions/directives or signed when
|
||||
the minimum is positive, use the minimum and maximum to compute
|
||||
the shortest and longest output, respectively. */
|
||||
res.range.min = format_integer (dir, argmin).range.min;
|
||||
res.range.max = format_integer (dir, argmax).range.max;
|
||||
}
|
||||
else
|
||||
else if (tree_int_cst_sgn (argmax) < 0)
|
||||
{
|
||||
/* For signed conversions/directives, use the maximum (i.e., 0)
|
||||
to compute the shortest output and the minimum (i.e., TYPE_MIN)
|
||||
to compute the longest output. This is important when precision
|
||||
is specified but unknown because otherwise both output lengths
|
||||
would reflect the largest possible precision (i.e., INT_MAX). */
|
||||
/* For signed conversions/directives if maximum is negative,
|
||||
use the minimum as the longest output and maximum as the
|
||||
shortest output. */
|
||||
res.range.min = format_integer (dir, argmax).range.min;
|
||||
res.range.max = format_integer (dir, argmin).range.max;
|
||||
}
|
||||
|
||||
if (res.range.max < res.range.min)
|
||||
else
|
||||
{
|
||||
unsigned HOST_WIDE_INT tmp = res.range.max;
|
||||
res.range.max = res.range.min;
|
||||
res.range.min = tmp;
|
||||
/* Otherwise, 0 is inside of the range and minimum negative. Use 0
|
||||
as the shortest output and for the longest output compute the
|
||||
length of the output of both minimum and maximum and pick the
|
||||
longer. */
|
||||
unsigned HOST_WIDE_INT max1 = format_integer (dir, argmin).range.max;
|
||||
unsigned HOST_WIDE_INT max2 = format_integer (dir, argmax).range.max;
|
||||
res.range.min = format_integer (dir, integer_zero_node).range.min;
|
||||
res.range.max = MAX (max1, max2);
|
||||
}
|
||||
|
||||
res.range.likely = res.knownrange ? res.range.max : res.range.min;
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
2017-02-03 Jakub Jelinek <jakub@redhat.com>
|
||||
Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/79327
|
||||
* gcc.dg/tree-ssa/pr79327.c: New test.
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
|
||||
(test_sprintf_chk_hh_nonconst): Don't expect 2 bogus warnings.
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-3.c
|
||||
(test_sprintf_chk_range_schar): Adjust dg-message.
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-12.c: New test.
|
||||
* gcc.c-torture/execute/pr79327.c: New test.
|
||||
|
||||
2017-02-03 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR target/79354
|
||||
|
|
26
gcc/testsuite/gcc.c-torture/execute/pr79327.c
Normal file
26
gcc/testsuite/gcc.c-torture/execute/pr79327.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* PR tree-optimization/79327 */
|
||||
/* { dg-require-effective-target c99_runtime } */
|
||||
|
||||
volatile int a;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int i;
|
||||
char buf[64];
|
||||
if (__builtin_sprintf (buf, "%#hho", a) != 1)
|
||||
__builtin_abort ();
|
||||
if (__builtin_sprintf (buf, "%#hhx", a) != 1)
|
||||
__builtin_abort ();
|
||||
a = 1;
|
||||
if (__builtin_sprintf (buf, "%#hho", a) != 2)
|
||||
__builtin_abort ();
|
||||
if (__builtin_sprintf (buf, "%#hhx", a) != 3)
|
||||
__builtin_abort ();
|
||||
a = 127;
|
||||
if (__builtin_sprintf (buf, "%#hho", a) != 4)
|
||||
__builtin_abort ();
|
||||
if (__builtin_sprintf (buf, "%#hhx", a) != 4)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
|
@ -1151,8 +1151,8 @@ void test_sprintf_chk_hh_nonconst (int w, int p, int a)
|
|||
T (2, "% hhu", a); /* { dg-warning ". . flag used with .%u." } */
|
||||
T (2, "% hhx", a); /* { dg-warning ". . flag used with .%x." } */
|
||||
|
||||
T (2, "%#hho", a); /* { dg-warning "nul past the end" } */
|
||||
T (2, "%#hhx", a); /* { dg-warning ".%#hhx. directive writing between 3 and . bytes into a region of size 2" } */
|
||||
T (2, "%#hho", a);
|
||||
T (2, "%#hhx", a);
|
||||
|
||||
T (3, "%0hhd", a);
|
||||
T (3, "%1hhd", a);
|
||||
|
|
228
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-12.c
Normal file
228
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-12.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/* PR tree-optimization/79327 - wrong code at -O2 and -fprintf-return-value
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -Wformat-overflow=1 -ftrack-macro-expansion=0" }
|
||||
{ dg-require-effective-target int32plus } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef __WCHAR_TYPE__ wchar_t;
|
||||
|
||||
#define INT_MAX __INT_MAX__
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
|
||||
/* When debugging, define LINE to the line number of the test case to exercise
|
||||
and avoid exercising any of the others. The buffer and objsize macros
|
||||
below make use of LINE to avoid warnings for other lines. */
|
||||
#ifndef LINE
|
||||
# define LINE 0
|
||||
#endif
|
||||
|
||||
void sink (char*, char*);
|
||||
|
||||
int dummy_sprintf (char*, const char*, ...);
|
||||
|
||||
char buffer [256];
|
||||
extern char *ptr;
|
||||
|
||||
int int_range (int min, int max)
|
||||
{
|
||||
extern int int_value (void);
|
||||
int n = int_value ();
|
||||
return n < min || max < n ? min : n;
|
||||
}
|
||||
|
||||
unsigned uint_range (unsigned min, unsigned max)
|
||||
{
|
||||
extern unsigned uint_value (void);
|
||||
unsigned n = uint_value ();
|
||||
return n < min || max < n ? min : n;
|
||||
}
|
||||
|
||||
/* Evaluate to an array of SIZE characters when non-negative, or to
|
||||
a pointer to an unknown object otherwise. */
|
||||
#define buffer(size) \
|
||||
((0 <= size) ? buffer + sizeof buffer - (size) : ptr)
|
||||
|
||||
/* Helper to expand function to either __builtin_f or dummy_f to
|
||||
make debugging GCC easy. */
|
||||
#define FUNC(f) \
|
||||
((!LINE || LINE == __LINE__) ? __builtin_ ## f : dummy_ ## f)
|
||||
|
||||
/* Macro to verify that calls to __builtin_sprintf (i.e., with no size
|
||||
argument) issue diagnostics by correctly determining the size of
|
||||
the destination buffer. */
|
||||
#define T(size, ...) \
|
||||
(FUNC (sprintf) (buffer (size), __VA_ARGS__), \
|
||||
sink (buffer, ptr))
|
||||
|
||||
/* Return a signed integer in the range [MIN, MAX]. */
|
||||
#define R(min, max) int_range (min, max)
|
||||
|
||||
/* Return a unsigned integer in the range [MIN, MAX]. */
|
||||
#define U(min, max) uint_range (min, max)
|
||||
|
||||
/* Exercise the hh length modifier with ranges. */
|
||||
void test_hh (void)
|
||||
{
|
||||
T (0, "%hhi", R ( -1, 0)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%hhi", R ( -1, 1)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%hhi", R ( -1, 12)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%hhi", R ( -1, 123)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhi", R ( -1, 128)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R ( -1, 257)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R ( -1, 1234)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R ( -12, -11)); /* { dg-warning "writing 3 bytes" } */
|
||||
T (0, "%hhi", R ( -12, -1)); /* { dg-warning "between 2 and 3 bytes" } */
|
||||
T (0, "%hhi", R ( -12, 0)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhi", R ( -12, 1)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhi", R ( -12, 12)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhi", R ( -12, 123)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhi", R ( -12, 128)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R ( -12, 257)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R ( -12, 1234)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R ( -99, -10)); /* { dg-warning "writing 3 bytes" } */
|
||||
T (0, "%hhi", R (-123, -1)); /* { dg-warning "between 2 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-123, 0)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-123, 1)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-123, 12)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-123, 123)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-123, 257)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-123, 1234)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-129, 1)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hhi", R (-130, -129)); /* { dg-warning "writing 3 bytes" } */
|
||||
|
||||
T (0, "%hhi", U ( 0, 127)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
|
||||
/* The following results in either "127" and "-128" so the ideal result
|
||||
should be "between 3 and 4 bytes" but because of the overflow from
|
||||
128 to -128 in the %hhi directive the input range is reset to that
|
||||
of char, or [CHAR_MIN, CHAR_MAX], and the warning reflects that. */
|
||||
T (0, "%hhi", U ( 127, 128)); /* { dg-warning "between \[13\] and 4 bytes" } */
|
||||
/* The following results in either "-128" or "-127". */
|
||||
T (0, "%hhi", U ( 128, 129)); /* { dg-warning "writing 4 bytes" } */
|
||||
/* The following results in between "-128" and "-99". */
|
||||
T (0, "%hhi", U ( 128, 157)); /* { dg-warning "writing between 3 and 4 bytes" } */
|
||||
/* Between "-128" and "-1". */
|
||||
T (0, "%hhi", U ( 128, 255)); /* { dg-warning "writing between 2 and 4 bytes" } */
|
||||
/* Between "-128" and "0". */
|
||||
T (0, "%hhi", U ( 128, 256)); /* { dg-warning "writing between 1 and 4 bytes" } */
|
||||
/* Between "-128" and "" (zero formats as nothing with zero precision). */
|
||||
T (0, "%.0hhi", U ( 128, 256)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
/* Same as above but with a range of precisions including zero. */
|
||||
T (0, "%.*hhi", /* { dg-warning "writing up to 4 bytes" } */
|
||||
R (0, 1), U ( 128, 256));
|
||||
/* Same as above but with a positive range of precisions. */
|
||||
T (0, "%.*hhi", /* { dg-warning "between 1 and 4 bytes" } */
|
||||
R (1, 2), U ( 128, 256));
|
||||
/* Precision range includes zero but width is non-zero so output cannot
|
||||
be empty. */
|
||||
T (0, "%1.*hhi", /* { dg-warning "between 1 and 4 bytes" } */
|
||||
R (0, 2), U ( 128, 256));
|
||||
/* Same as above but with a width range. */
|
||||
T (0, "%*.*hhi", /* { dg-warning "between 1 and 4 bytes" } */
|
||||
R (1, 2), R (0, 2), U ( 128, 256));
|
||||
/* Same as above but this time width range does include zero. */
|
||||
T (0, "%*.*hhi", /* { dg-warning "up to 4 bytes" } */
|
||||
R (0, 2), R (0, 2), U ( 128, 256));
|
||||
|
||||
/* Range of precisions in excess of the number of digits and sign. */
|
||||
T (0, "%.*hhi", /* { dg-warning "between 5 and 8 bytes" } */
|
||||
R (5, 7), U ( 128, 256));
|
||||
|
||||
/* Between "-128" and "+0". */
|
||||
T (0, "%+hhi", U ( 128, 256)); /* { dg-warning "between 2 and 4 bytes" } */
|
||||
/* Between "-128" and " 0". */
|
||||
T (0, "% hhi", U ( 128, 256)); /* { dg-warning "between 2 and 4 bytes" } */
|
||||
|
||||
T (0, "%hhu", R ( -1, 1)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -1, 12)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -1, 123)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -1, 128)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -1, 257)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -1, 1234)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -12, 1)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -12, 12)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -12, 123)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -12, 128)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -12, 257)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R ( -12, 1234)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R (-123, 1)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R (-123, 12)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R (-123, 123)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R (-123, 257)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R (-123, 1234)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R (-129, 1)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hhu", R (-199, -159)); /* { dg-warning "writing 2 bytes" } */
|
||||
T (0, "%hhu", R (-255, -250)); /* { dg-warning "writing 1 byte" } */
|
||||
}
|
||||
|
||||
/* Exercise the h length modifier. */
|
||||
void test_h (void)
|
||||
{
|
||||
T (0, "%hi", R ( -1, 0)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%hi", R ( 0, 1)); /* { dg-warning "writing 1 byte" } */
|
||||
T (0, "%hi", R ( -1, 1)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%hi", R ( -1, 12)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%hi", R ( -12, 1)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%hi", R ( -99, -10)); /* { dg-warning "writing 3 bytes" } */
|
||||
T (0, "%hi", R ( -123, 4)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%hi", R ( -1234, 56)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hi", R ( -1234, 567)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hi", R ( -1234, 5678)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%ho", R (-32768,-32767)); /* { dg-warning "writing 6 bytes" } */
|
||||
|
||||
T (0, "%ho", R ( -1, 0)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R ( 0, 1)); /* { dg-warning "writing 1 byte" } */
|
||||
T (0, "%ho", R ( -1, 1)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R ( -1, 12)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R ( -12, 1)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R ( -123, 4)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R ( -1234, 56)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R ( -1234, 567)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R ( -1234, 5678)); /* { dg-warning "between 1 and 6 bytes" } */
|
||||
T (0, "%ho", R (-32768,-32767)); /* { dg-warning "writing 6 bytes" } */
|
||||
|
||||
T (0, "%hu", R ( -1, 0)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R ( 0, 1)); /* { dg-warning "writing 1 byte" } */
|
||||
T (0, "%hu", R ( -1, 1)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R ( -1, 12)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R ( -12, 1)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R ( -123, 4)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R ( -1234, 56)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R ( -1234, 567)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R ( -1234, 5678)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%hu", R (-32768,-32767)); /* { dg-warning "writing 5 bytes" } */
|
||||
|
||||
T (0, "%hx", R (-32768,-32767)); /* { dg-warning "writing 4 bytes" } */
|
||||
}
|
||||
|
||||
/* Exercise integer directives with no length modifier. */
|
||||
void test_diou (void)
|
||||
{
|
||||
T (0, "%d", R ( -1, 0)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%i", R ( 0, 1)); /* { dg-warning "writing 1 byte" } */
|
||||
T (0, "%d", R ( -1, 1)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%i", R ( -1, 12)); /* { dg-warning "between 1 and 2 bytes" } */
|
||||
T (0, "%d", R ( -12, 1)); /* { dg-warning "between 1 and 3 bytes" } */
|
||||
T (0, "%i", R ( -123, 4)); /* { dg-warning "between 1 and 4 bytes" } */
|
||||
T (0, "%d", R ( -1234, 56)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%i", R ( -1234, 567)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
T (0, "%d", R ( -1234, 5678)); /* { dg-warning "between 1 and 5 bytes" } */
|
||||
|
||||
T (0, "%u", R ( -1, 0)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
T (0, "%u", R ( 0, 1)); /* { dg-warning "writing 1 byte" } */
|
||||
T (0, "%u", R ( -1, 1)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
T (0, "%u", R ( -1, 12)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
T (0, "%u", R ( -12, 1)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
T (0, "%u", R ( -123, 4)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
T (0, "%u", R ( -1234, 56)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
T (0, "%u", R ( -1234, 567)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
T (0, "%u", R ( -1234, 5678)); /* { dg-warning "between 1 and 10 bytes" } */
|
||||
|
||||
T (0, "%o", R ( -1, 0)); /* { dg-warning "between 1 and 11 bytes" } */
|
||||
T (0, "%o", R ( -2, 1)); /* { dg-warning "between 1 and 11 bytes" } */
|
||||
T (0, "%o", R ( 0, 1)); /* { dg-warning "writing 1 byte" } */
|
||||
|
||||
T (0, "%x", R ( -1, 0)); /* { dg-warning "between 1 and 8 bytes" } */
|
||||
T (0, "%x", R ( -2, 1)); /* { dg-warning "between 1 and 8 bytes" } */
|
||||
T (0, "%x", R ( 0, 1)); /* { dg-warning "writing 1 byte" } */
|
||||
}
|
|
@ -198,7 +198,7 @@ void test_sprintf_chk_range_schar (void)
|
|||
/* { dg-message "directive argument in the range \\\[1024, 1034\\\]" "note" { target *-*-* } .-1 } */
|
||||
|
||||
T ( 0, "%hhi", R (1024, 2035)); /* { dg-warning ".%hhi. directive writing between 1 and 4 bytes into a region of size 0" } */
|
||||
/* { dg-message "using the range \\\[0, -128\\\] for directive argument" "note" { target *-*-* } .-1 } */
|
||||
/* { dg-message "using the range \\\[-128, 127\\\] for directive argument" "note" { target *-*-* } .-1 } */
|
||||
|
||||
#undef R
|
||||
#define R(min, max) range_schar (min, max)
|
||||
|
|
31
gcc/testsuite/gcc.dg/tree-ssa/pr79327.c
Normal file
31
gcc/testsuite/gcc.dg/tree-ssa/pr79327.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* PR tree-optimization/79327 - wrong code at -O2 and -fprintf-return-value
|
||||
{ dg-do run }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
volatile int a, b = -1;
|
||||
char buf[64];
|
||||
|
||||
#define FMT "%+03d%02d"
|
||||
const char *volatile fmt = FMT;
|
||||
|
||||
int main ()
|
||||
{
|
||||
int c = a;
|
||||
int d = b;
|
||||
if (c >= -35791395 && c < 35791394 && d >= -1 && d < __INT_MAX__)
|
||||
{
|
||||
/* In the following the range of return values can be computed
|
||||
by GCC. */
|
||||
int n1 = __builtin_sprintf (buf, FMT, c + 1, d + 1);
|
||||
if (n1 > 7)
|
||||
__builtin_abort ();
|
||||
|
||||
/* Here GCC can't see the format string so the return value
|
||||
must be computed by a libc call. */
|
||||
int n2 = __builtin_sprintf (buf, fmt, c + 1, d + 1);
|
||||
|
||||
if (n1 != n2)
|
||||
__builtin_abort ();
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue