PR middle-end/79692 - [7 Regression] -Wformat-overflow false positive
gcc/ChangeLog: PR middle-end/79692 * gimple-ssa-sprintf.c (directive::known_width_and_precision): New function. (format_integer): Use it. (get_mpfr_format_length): Consider the full range of precision when computing %g output with the # flag. Set the likely byte count to 3 rather than 1 when precision is indeterminate. (format_floating): Correct the lower bound of precision. gcc/testsuite/ChangeLog: PR middle-end/79692 * gcc.dg/tree-ssa/builtin-sprintf-2.c: Add test cases. * gcc.dg/tree-ssa/builtin-sprintf-warn-10.c: Correct %#g. * gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: New test. * gcc.dg/tree-ssa/builtin-snprintf-3.c: Ditto. From-SVN: r245822
This commit is contained in:
parent
538d7dba84
commit
71dedb336f
@ -1,3 +1,14 @@
|
||||
2017-03-01 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/79692
|
||||
* gimple-ssa-sprintf.c
|
||||
(directive::known_width_and_precision): New function.
|
||||
(format_integer): Use it.
|
||||
(get_mpfr_format_length): Consider the full range of precision
|
||||
when computing %g output with the # flag. Set the likely byte
|
||||
count to 3 rather than 1 when precision is indeterminate.
|
||||
(format_floating): Correct the lower bound of precision.
|
||||
|
||||
2017-03-01 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
|
||||
|
||||
* doc/invoke.texi: Document default code model for 64-bit Linux.
|
||||
|
@ -692,6 +692,16 @@ struct directive
|
||||
{
|
||||
get_int_range (arg, integer_type_node, prec, prec + 1, false, -1);
|
||||
}
|
||||
|
||||
/* Return true if both width and precision are known to be
|
||||
either constant or in some range, false otherwise. */
|
||||
bool known_width_and_precision () const
|
||||
{
|
||||
return ((width[1] < 0
|
||||
|| (unsigned HOST_WIDE_INT)width[1] <= target_int_max ())
|
||||
&& (prec[1] < 0
|
||||
|| (unsigned HOST_WIDE_INT)prec[1] < target_int_max ()));
|
||||
}
|
||||
};
|
||||
|
||||
/* Return the logarithm of X in BASE. */
|
||||
@ -1180,10 +1190,10 @@ format_integer (const directive &dir, tree arg)
|
||||
/* As a special case, a precision of zero with a zero argument
|
||||
results in zero bytes except in base 8 when the '#' flag is
|
||||
specified, and for signed conversions in base 8 and 10 when
|
||||
flags when either the space or '+' flag has been specified
|
||||
when it results in just one byte (with width having the normal
|
||||
effect). This must extend to the case of a specified precision
|
||||
with an unknown value because it can be zero. */
|
||||
either the space or '+' flag has been specified and it results
|
||||
in just one byte (with width having the normal effect). This
|
||||
must extend to the case of a specified precision with
|
||||
an unknown value because it can be zero. */
|
||||
res.range.min = ((base == 8 && dir.get_flag ('#')) || maybesign);
|
||||
if (res.range.min == 0 && dir.prec[0] != dir.prec[1])
|
||||
{
|
||||
@ -1254,10 +1264,12 @@ format_integer (const directive &dir, tree arg)
|
||||
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). */
|
||||
of the directive's type and neither width nor precision
|
||||
is unknown. (KNOWNRANGE may be reset below). */
|
||||
res.knownrange
|
||||
= (!tree_int_cst_equal (TYPE_MIN_VALUE (dirtype), argmin)
|
||||
|| !tree_int_cst_equal (TYPE_MAX_VALUE (dirtype), argmax));
|
||||
= ((!tree_int_cst_equal (TYPE_MIN_VALUE (dirtype), argmin)
|
||||
|| !tree_int_cst_equal (TYPE_MAX_VALUE (dirtype), argmax))
|
||||
&& dir.known_width_and_precision ());
|
||||
|
||||
res.argmin = argmin;
|
||||
res.argmax = argmax;
|
||||
@ -1421,12 +1433,12 @@ get_mpfr_format_length (mpfr_ptr x, const char *flags, HOST_WIDE_INT prec,
|
||||
|
||||
HOST_WIDE_INT p = prec;
|
||||
|
||||
if (spec == 'G')
|
||||
if (spec == 'G' && !strchr (flags, '#'))
|
||||
{
|
||||
/* For G/g, precision gives the maximum number of significant
|
||||
digits which is bounded by LDBL_MAX_10_EXP, or, for a 128
|
||||
bit IEEE extended precision, 4932. Using twice as much
|
||||
here should be more than sufficient for any real format. */
|
||||
/* For G/g without the pound flag, precision gives the maximum number
|
||||
of significant digits which is bounded by LDBL_MAX_10_EXP, or, for
|
||||
a 128 bit IEEE extended precision, 4932. Using twice as much here
|
||||
should be more than sufficient for any real format. */
|
||||
if ((IEEE_MAX_10_EXP * 2) < prec)
|
||||
prec = IEEE_MAX_10_EXP * 2;
|
||||
p = prec;
|
||||
@ -1609,7 +1621,12 @@ format_floating (const directive &dir)
|
||||
/* Compute the upper bound for -TYPE_MAX. */
|
||||
res.range.max = format_floating_max (type, 'f', dir.prec[1]);
|
||||
|
||||
res.range.likely = res.range.min;
|
||||
/* The minimum output with unknown precision is a single byte
|
||||
(e.g., "0") but the more likely output is 3 bytes ("0.0"). */
|
||||
if (dir.prec[0] < 0 && dir.prec[1] > 0)
|
||||
res.range.likely = 3;
|
||||
else
|
||||
res.range.likely = res.range.min;
|
||||
|
||||
/* The unlikely maximum accounts for the longest multibyte
|
||||
decimal point character. */
|
||||
@ -1625,10 +1642,43 @@ format_floating (const directive &dir)
|
||||
/* The %g output depends on precision and the exponent of
|
||||
the argument. Since the value of the argument isn't known
|
||||
the lower bound on the range of bytes (not counting flags
|
||||
or width) is 1. */
|
||||
res.range.min = flagmin;
|
||||
res.range.max = format_floating_max (type, 'g', dir.prec[1]);
|
||||
res.range.likely = res.range.max;
|
||||
or width) is 1 plus radix (i.e., either "0" or "0." for
|
||||
"%g" and "%#g", respectively, with a zero argument). */
|
||||
res.range.min = flagmin + radix;
|
||||
|
||||
char spec = 'g';
|
||||
HOST_WIDE_INT maxprec = dir.prec[1];
|
||||
if (radix && maxprec)
|
||||
{
|
||||
/* When the pound flag (radix) is set, trailing zeros aren't
|
||||
trimmed and so the longest output is the same as for %e,
|
||||
except with precision minus 1 (as specified in C11). */
|
||||
spec = 'e';
|
||||
if (maxprec > 0)
|
||||
--maxprec;
|
||||
else if (maxprec < 0)
|
||||
maxprec = 5;
|
||||
}
|
||||
|
||||
res.range.max = format_floating_max (type, spec, maxprec);
|
||||
|
||||
/* The likely output is either the maximum computed above
|
||||
minus 1 (assuming the maximum is positive) when precision
|
||||
is known (or unspecified), or the same minimum as for %e
|
||||
(which is computed for a non-negative argument). Unlike
|
||||
for the other specifiers above the likely output isn't
|
||||
the minimum because for %g that's 1 which is unlikely. */
|
||||
if (dir.prec[1] < 0
|
||||
|| (unsigned HOST_WIDE_INT)dir.prec[1] < target_int_max ())
|
||||
res.range.likely = res.range.max - 1;
|
||||
else
|
||||
{
|
||||
HOST_WIDE_INT minprec = 6 + !radix /* decimal point */;
|
||||
res.range.likely = (flagmin
|
||||
+ radix
|
||||
+ minprec
|
||||
+ 2 /* e+ */ + 2);
|
||||
}
|
||||
|
||||
/* The unlikely maximum accounts for the longest multibyte
|
||||
decimal point character. */
|
||||
@ -1657,24 +1707,63 @@ format_floating (const directive &dir, tree arg)
|
||||
|
||||
HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] };
|
||||
|
||||
/* For an indeterminate precision the lower bound must be assumed
|
||||
to be zero. */
|
||||
if (TOUPPER (dir.specifier) == 'A')
|
||||
{
|
||||
/* Get the number of fractional decimal digits needed to represent
|
||||
the argument without a loss of accuracy. */
|
||||
tree type = arg ? TREE_TYPE (arg) :
|
||||
(dir.modifier == FMT_LEN_L || dir.modifier == FMT_LEN_ll
|
||||
? long_double_type_node : double_type_node);
|
||||
|
||||
unsigned fmtprec
|
||||
= REAL_MODE_FORMAT (TYPE_MODE (type))->p;
|
||||
|
||||
/* The precision of the IEEE 754 double format is 53.
|
||||
The precision of all other GCC binary double formats
|
||||
is 56 or less. */
|
||||
unsigned maxprec = fmtprec <= 56 ? 13 : 15;
|
||||
|
||||
/* For %a, leave the minimum precision unspecified to let
|
||||
MFPR trim trailing zeros (as it and many other systems
|
||||
including Glibc happen to do) and set the maximum
|
||||
precision to reflect what it would be with trailing zeros
|
||||
present (as Solaris and derived systems do). */
|
||||
if (prec[0] < 0)
|
||||
prec[0] = -1;
|
||||
if (prec[1] < 0)
|
||||
if (dir.prec[1] < 0)
|
||||
{
|
||||
unsigned fmtprec
|
||||
= REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->p;
|
||||
|
||||
/* The precision of the IEEE 754 double format is 53.
|
||||
The precision of all other GCC binary double formats
|
||||
is 56 or less. */
|
||||
prec[1] = fmtprec <= 56 ? 13 : 15;
|
||||
/* Both bounds are negative implies that precision has
|
||||
not been specified. */
|
||||
prec[0] = maxprec;
|
||||
prec[1] = -1;
|
||||
}
|
||||
else if (dir.prec[0] < 0)
|
||||
{
|
||||
/* With a negative lower bound and a non-negative upper
|
||||
bound set the minimum precision to zero and the maximum
|
||||
to the greater of the maximum precision (i.e., with
|
||||
trailing zeros present) and the specified upper bound. */
|
||||
prec[0] = 0;
|
||||
prec[1] = dir.prec[1] < maxprec ? maxprec : dir.prec[1];
|
||||
}
|
||||
}
|
||||
else if (dir.prec[0] < 0)
|
||||
{
|
||||
if (dir.prec[1] < 0)
|
||||
{
|
||||
/* A precision in a strictly negative range is ignored and
|
||||
the default of 6 is used instead. */
|
||||
prec[0] = prec[1] = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For a precision in a partly negative range, the lower bound
|
||||
must be assumed to be zero and the new upper bound is the
|
||||
greater of 6 (the default precision used when the specified
|
||||
precision is negative) and the upper bound of the specified
|
||||
range. */
|
||||
prec[0] = 0;
|
||||
prec[1] = dir.prec[1] < 6 ? 6 : dir.prec[1];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1734,12 +1823,23 @@ format_floating (const directive &dir, tree arg)
|
||||
res.range.max = tmp;
|
||||
}
|
||||
|
||||
res.knownrange = true;
|
||||
/* The range is known unless either width or precision is unknown. */
|
||||
res.knownrange = dir.known_width_and_precision ();
|
||||
|
||||
/* For the same floating point constant, unless width or precision
|
||||
is unknown, use the longer output as the likely maximum since
|
||||
with round to nearest either is equally likely. Otheriwse, when
|
||||
precision is unknown, use the greater of the minimum and 3 as
|
||||
the likely output (for "0.0" since zero precision is unlikely). */
|
||||
if (res.knownrange)
|
||||
res.range.likely = res.range.max;
|
||||
else if (res.range.min < 3
|
||||
&& dir.prec[0] < 0
|
||||
&& (unsigned HOST_WIDE_INT)dir.prec[1] == target_int_max ())
|
||||
res.range.likely = 3;
|
||||
else
|
||||
res.range.likely = res.range.min;
|
||||
|
||||
/* For the same floating point constant use the longer output
|
||||
as the likely maximum since with round to nearest either is
|
||||
equally likely. */
|
||||
res.range.likely = res.range.max;
|
||||
res.range.unlikely = res.range.max;
|
||||
|
||||
if (res.range.max > 2 && (prec[0] != 0 || prec[1] != 0))
|
||||
|
@ -1,3 +1,11 @@
|
||||
2017-03-01 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/79692
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-2.c: Add test cases.
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-10.c: Correct %#g.
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-15.c: New test.
|
||||
* gcc.dg/tree-ssa/builtin-snprintf-3.c: Ditto.
|
||||
|
||||
2017-03-01 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* gcc.target/i386/invsize-2.c: New test.
|
||||
|
77
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-3.c
Normal file
77
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-3.c
Normal file
@ -0,0 +1,77 @@
|
||||
/* Verify the lower and upper bounds of floating directives with
|
||||
precision whose range crosses zero.
|
||||
{ do-do compile }
|
||||
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
|
||||
|
||||
static const double x = 1.23456789;
|
||||
|
||||
/* All calls to failure_range must be eliminated. */
|
||||
extern void failure_range (int, int, int);
|
||||
|
||||
/* All calls to verify_{lo,hi}_bound must be retained. */
|
||||
extern void verify_lo_bound (int, int);
|
||||
extern void verify_hi_bound (int, int);
|
||||
|
||||
int test_a (int p)
|
||||
{
|
||||
if (p < -1 || 3 < p)
|
||||
p = -1;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%.*A", p, x);
|
||||
if (n < 6 || 25 < n)
|
||||
failure_range ('A', 6, 25);
|
||||
|
||||
if (n == 6) verify_lo_bound ('A', 6);
|
||||
if (n == 25) verify_hi_bound ('A', 25);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int test_e (int p)
|
||||
{
|
||||
if (p < -1 || 3 < p)
|
||||
p = -1;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%.*E", p, x);
|
||||
if (n < 5 || 17 < n)
|
||||
failure_range ('E', 5, 17);
|
||||
|
||||
if (n == 5) verify_lo_bound ('E', 5);
|
||||
if (n == 17) verify_hi_bound ('E', 17);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int test_f (int p)
|
||||
{
|
||||
if (p < -1 || 3 < p)
|
||||
p = -1;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%.*F", p, x);
|
||||
if (n < 1 || 13 < n)
|
||||
failure_range ('F', 1, 13);
|
||||
|
||||
if (n == 1) verify_lo_bound ('F', 1);
|
||||
if (n == 13) verify_hi_bound ('F', 13);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int test_g (int p)
|
||||
{
|
||||
if (p < -1 || 3 < p)
|
||||
p = -1;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%.*G", p, x);
|
||||
if (n < 1 || 12 < n)
|
||||
failure_range ('G', 1, 12);
|
||||
|
||||
if (n == 1) verify_lo_bound ('G', 1);
|
||||
if (n == 12) verify_hi_bound ('G', 12);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "snprintf" 4 "optimized"} }
|
||||
{ dg-final { scan-tree-dump-not "failure_range" "optimized"} }
|
||||
{ dg-final { scan-tree-dump-times "verify_" 8 "optimized"} } */
|
@ -7,7 +7,7 @@
|
||||
The test is compiled with warnings disabled to make sure the absence
|
||||
of optimizations does not depend on the presence of warnings. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fprintf-return-value -fdump-tree-optimized -ftrack-macro-expansion=0 -w" } */
|
||||
/* { dg-options "-O2 -fprintf-return-value -fdump-tree-optimized -w" } */
|
||||
|
||||
#ifndef LINE
|
||||
# define LINE 0
|
||||
@ -243,6 +243,14 @@ RNG (6, 6, 7, "%La", 0.0L) /* Glibc output: "0x0p+0" */
|
||||
RNG (6, 6, 7, "%La", ld)
|
||||
RNG (6, 6, 7, "%.4096La", ld)
|
||||
|
||||
/* Verify that the pound flag with unknown precision prevents the %g
|
||||
directive from trimming trailing zeros as it otherwise does. As
|
||||
a consequence, the result must be assumed to be as large as
|
||||
precision. */
|
||||
RNG (1, 315, 316, "%#.*g", i, d);
|
||||
RNG (1, 4095, 4096, "%#.*g", i, d);
|
||||
RNG (1, 4095, 4096, "%#.*g", i, 0.0);
|
||||
|
||||
/* Verify that the result of formatting an unknown string isn't optimized
|
||||
into a non-negative range. The string could be longer that 4,095 bytes,
|
||||
resulting in the formatting function having undefined behavior (and
|
||||
@ -282,7 +290,7 @@ RNG (0, 6, 8, "%s%ls", "1", L"2");
|
||||
|
||||
/* Only conditional calls to must_not_eliminate must be made (with
|
||||
any probability):
|
||||
{ dg-final { scan-tree-dump-times "> \\\[\[0-9.\]+%\\\]:\n *must_not_eliminate" 124 "optimized" { target { ilp32 || lp64 } } } }
|
||||
{ dg-final { scan-tree-dump-times "> \\\[\[0-9.\]+%\\\]:\n *must_not_eliminate" 93 "optimized" { target { { ! ilp32 } && { ! lp64 } } } } }
|
||||
{ dg-final { scan-tree-dump-times "> \\\[\[0-9.\]+%\\\]:\n *must_not_eliminate" 127 "optimized" { target { ilp32 || lp64 } } } }
|
||||
{ dg-final { scan-tree-dump-times "> \\\[\[0-9.\]+%\\\]:\n *must_not_eliminate" 96 "optimized" { target { { ! ilp32 } && { ! lp64 } } } } }
|
||||
No unconditional calls to abort should be made:
|
||||
{ dg-final { scan-tree-dump-not ";\n *must_not_eliminate" "optimized" } } */
|
||||
|
@ -239,9 +239,11 @@ void test_g_va (va_list va)
|
||||
T ("%g"); /* { dg-warning "between 1 and 13 bytes" } */
|
||||
T ("%+g"); /* { dg-warning "between 2 and 13 bytes" } */
|
||||
T ("% g"); /* { dg-warning "between 2 and 13 bytes" } */
|
||||
T ("%#g"); /* { dg-warning "between 1 and 13 bytes" } */
|
||||
T ("%#+g"); /* { dg-warning "between 2 and 13 bytes" } */
|
||||
T ("%# g"); /* { dg-warning "between 2 and 13 bytes" } */
|
||||
|
||||
/* The pound flag means the radix character is always present. */
|
||||
T ("%#g"); /* { dg-warning "between 2 and 13 bytes" } */
|
||||
T ("%#+g"); /* { dg-warning "between 3 and 13 bytes" } */
|
||||
T ("%# g"); /* { dg-warning "between 3 and 13 bytes" } */
|
||||
|
||||
T ("%.g"); /* { dg-warning "between 1 and 7 bytes" } */
|
||||
T ("%.0g"); /* { dg-warning "between 1 and 7 bytes" } */
|
||||
|
197
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-15.c
Normal file
197
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-15.c
Normal file
@ -0,0 +1,197 @@
|
||||
/* PR middle-end/79692 - -Wformat-overflow false positive on an integer
|
||||
directive with unknown width
|
||||
{ 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 [1024];
|
||||
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)
|
||||
|
||||
void test_unknown_width_integer (int w, int i)
|
||||
{
|
||||
T (10, "%*d", w, i);
|
||||
T (10, "%*d", w, R (0, 12345));
|
||||
|
||||
T (10, "%*i", w, i);
|
||||
T (10, "%*i", w, R (0, 12345));
|
||||
|
||||
T (10, "%*o", w, i);
|
||||
T (10, "%*o", w, R (0, 12345));
|
||||
|
||||
T (10, "%*i", w, i);
|
||||
T (10, "%*i", w, R (0, 12345));
|
||||
}
|
||||
|
||||
void test_unknown_width_floating (int w, double d)
|
||||
{
|
||||
T ( 7, "%*a", w, d);
|
||||
T (21, "%*a", w, 3.141);
|
||||
|
||||
T (12, "%*e", w, d); /* { dg-warning "writing a terminating nul" } */
|
||||
T (12, "%#*e", w, d); /* { dg-warning "writing a terminating nul" } */
|
||||
T (13, "%*e", w, d);
|
||||
T (13, "%#*e", w, d);
|
||||
T (13, "%*e", w, 3.141);
|
||||
|
||||
T ( 8, "%*f", w, d); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 8, "%#*f", w, d); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 9, "%*f", w, d);
|
||||
T ( 9, "%#*f", w, d);
|
||||
T ( 9, "%*f", w, 3.141);
|
||||
T ( 9, "%#*f", w, 3.141);
|
||||
|
||||
T (12, "%*g", w, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T (13, "%*g", w, d);
|
||||
T (13, "%*g", w, 3.141);
|
||||
}
|
||||
|
||||
void test_unknown_precision_integer (int p, int i, double d)
|
||||
{
|
||||
T (10, "%.*d", p, i);
|
||||
T (10, "%.*d", p, R (0, 12345));
|
||||
|
||||
T (10, "%.*i", p, i);
|
||||
T (10, "%.*i", p, R (0, 12345));
|
||||
|
||||
T (10, "%.*o", p, i);
|
||||
T (10, "%.*o", p, R (0, 12345));
|
||||
|
||||
T (10, "%.*i", p, i);
|
||||
T (10, "%.*i", p, R (0, 12345));
|
||||
}
|
||||
|
||||
void test_unknown_precision_floating (int p, double d)
|
||||
{
|
||||
T ( 7, "%.*a", p, d);
|
||||
T (21, "%.*a", p, 3.141);
|
||||
|
||||
/* "%.0e", 0.0 results in 5 bytes: "0e+00" */
|
||||
T ( 5, "%.*e", p, d); /* { dg-warning "writing a terminating nul" } */
|
||||
/* "%#.0e", 0.0 results in 6 bytes: "0.e+00" */
|
||||
T ( 6, "%#.*e", p, d); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 6, "%.*e", p, d);
|
||||
T ( 6, "%.*e", p, 3.141);
|
||||
T ( 6, "%#.*e", p, 3.141); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 7, "%#.*e", p, 3.141);
|
||||
|
||||
/* "%.0f", 0.0 results in 1 byte: "0" but precision of at least 1
|
||||
is likely, resulting in "0.0". */
|
||||
T ( 3, "%.*f", p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
/* "%#.0f", 0.0 results in 2 bytes: "0." but precision of at least 1
|
||||
is likely, resulting in "0.0". */
|
||||
T ( 3, "%#.*f", p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%.*f", p, d);
|
||||
T ( 4, "%#.*f", p, d);
|
||||
T ( 3, "%.*f", p, 3.141); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%.*f", p, 3.141);
|
||||
T ( 3, "%#.*f", p, 3.141); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%#.*f", p, 3.141);
|
||||
|
||||
T (12, "%.*g", p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T (12, "%#.*g", p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T (13, "%.*g", p, d);
|
||||
T (13, "%#.*g", p, d);
|
||||
T ( 6, "%#.*g", R (-1, 0), d);/* { dg-warning "may write a terminating nul" } */
|
||||
T ( 7, "%#.*g", R (-1, 0), d);
|
||||
T ( 6, "%#.*g", R ( 0, 0), d);/* { dg-warning "may write a terminating nul" } */
|
||||
T ( 7, "%#.*g", R ( 0, 0), d);
|
||||
T ( 6, "%#.*g", R ( 0, 1), d);/* { dg-warning "may write a terminating nul" } */
|
||||
T ( 7, "%#.*g", R ( 0, 1), d);
|
||||
T ( 3, "%.*g", p, 3.141); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%.*g", p, 3.141);
|
||||
T ( 3, "%#.*g", p, 3.141); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%#.*g", p, 3.141);
|
||||
}
|
||||
|
||||
|
||||
void test_unknown_width_and_precision_integer (int w, int p, int i)
|
||||
{
|
||||
T (10, "%*.*d", w, p, i);
|
||||
T (10, "%*.*d", w, p, R (0, 12345));
|
||||
|
||||
T (10, "%*.*i", w, p, i);
|
||||
T (10, "%*.*i", w, p, R (0, 12345));
|
||||
|
||||
T (10, "%*.*o", w, p, i);
|
||||
T (10, "%*.*o", w, p, R (0, 12345));
|
||||
|
||||
T (10, "%*.*i", w, p, i);
|
||||
T (10, "%*.*i", w, p, R (0, 12345));
|
||||
}
|
||||
|
||||
void test_unknown_width_and_precision_floating (int w, int p, double d)
|
||||
{
|
||||
T ( 7, "%*.*a", w, p, d);
|
||||
T (21, "%*.*a", w, p, 3.141);
|
||||
|
||||
/* "%0.0e", 0.0 results in 5 bytes: "0e+00" */
|
||||
T ( 5, "%*.*e", w, p, d); /* { dg-warning "writing a terminating nul" } */
|
||||
/* "%#0.0e", 0.0 results in 6 bytes: "0.e+00" */
|
||||
T ( 6, "%#*.*e", w, p, d); /* { dg-warning "writing a terminating nul" } */
|
||||
T ( 6, "%*.*e", w, p, d);
|
||||
T ( 6, "%*.*e", w, p, 3.141);
|
||||
T ( 6, "%#*.*e", w, p, 3.141);/* { dg-warning "writing a terminating nul" } */
|
||||
T ( 7, "%#*.*e", w, p, 3.141);
|
||||
|
||||
T ( 3, "%*.*f", w, p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 3, "%#*.*f", w, p, d); /* { dg-warning "may write a terminating nul" } */
|
||||
T ( 4, "%*.*f", w, p, d);
|
||||
T ( 4, "%*.*f", w, p, 3.141);
|
||||
T ( 4, "%#*.*f", w, p, 3.141);
|
||||
|
||||
T (13, "%*.*g", w, p, d);
|
||||
T (13, "%#*.*g", w, p, d);
|
||||
T (13, "%*.*g", w, p, 3.141);
|
||||
T (13, "%#*.*g", w, p, 3.141);
|
||||
}
|
Loading…
Reference in New Issue
Block a user