static HOST_WIDE_INT
target_int_min ()
{
- static const unsigned HOST_WIDE_INT int_min
- = 1LLU << (sizeof int_min * CHAR_BIT
- - TYPE_PRECISION (integer_type_node) + 1);
+ const unsigned HOST_WIDE_INT int_min
+ = HOST_WIDE_INT_M1U << (TYPE_PRECISION (integer_type_node) - 1);
+
return int_min;
}
static unsigned HOST_WIDE_INT
target_int_max ()
{
- static const unsigned HOST_WIDE_INT int_max
- = HOST_WIDE_INT_M1U >> (sizeof int_max * CHAR_BIT
+ const unsigned HOST_WIDE_INT int_max
+ = HOST_WIDE_INT_M1U >> (HOST_BITS_PER_WIDE_INT
- TYPE_PRECISION (integer_type_node) + 1);
return int_max;
}
case FMT_LEN_L:
case FMT_LEN_ll:
- dirtype = sign ? long_integer_type_node : long_unsigned_type_node;
+ dirtype = (sign
+ ? long_long_integer_type_node
+ : long_long_unsigned_type_node);
break;
case FMT_LEN_z:
*minmax[i] = mpfr_snprintf (NULL, 0, fmtstr, mpfrval);
}
- res.bounded = res.range.min < HOST_WIDE_INT_MAX;
+ res.bounded = res.range.min < target_int_max ();
return res;
}
/* Set RES.BOUNDED to true if and only if all strings referenced
by STR are known to be bounded (though not necessarily by their
actual length but perhaps by their maximum possible length). */
- res.bounded = res.range.max < HOST_WIDE_INT_MAX;
+ res.bounded = res.range.max < target_int_max ();
/* Set RES.CONSTANT to false even though that may be overly
conservative in rare cases like: 'x ? a : b' where a and
: 2 == warn_format_length ? 0 <= prec ? prec : 1
: HOST_WIDE_INT_MAX);
+ /* The result is bounded unless overriddden for a non-constant string
+ of an unknown length. */
+ bool bounded = true;
+
if (spec.specifier == 'c')
{
if (spec.modifier == FMT_LEN_l)
if (0 <= prec)
{
if ((unsigned)prec < slen.range.min
- || slen.range.min >= HOST_WIDE_INT_MAX)
+ || slen.range.min >= target_int_max ())
slen.range.min = prec;
if ((unsigned)prec < slen.range.max
- || slen.range.max >= HOST_WIDE_INT_MAX)
+ || slen.range.max >= target_int_max ())
slen.range.max = prec;
}
- else if (slen.range.min >= HOST_WIDE_INT_MAX)
+ else if (slen.range.min >= target_int_max ())
{
slen.range.min = max_bytes_for_unknown_str;
slen.range.max = max_bytes_for_unknown_str;
+ bounded = false;
}
res.range = slen.range;
res.range.max = width;
/* Adjust BOUNDED if width happens to make them equal. */
- if (res.range.min == res.range.max && res.range.min < HOST_WIDE_INT_MAX)
+ if (res.range.min == res.range.max && res.range.min < target_int_max ()
+ && bounded)
res.bounded = true;
return res;
unsigned HOST_WIDE_INT maxbytes;
if (lhs
+ && res.bounded
&& ((maxbytes = res.number_chars - 1) <= target_int_max ()
|| (res.number_chars_min - 1 <= target_int_max ()
&& (maxbytes = res.number_chars_max - 1) <= target_int_max ()))
--- /dev/null
+/* PR bootstrap/77676 - powerpc64 and powerpc64le stage2 bootstrap fail
+ Test case derived from the one submitted in the bug. It verifies
+ that the sprintf return value (or value range) optimization is not
+ performed for an unknown string. */
+/* { dg-compile } */
+/* { dg-options "-O2 -Wall -Werror -fdump-tree-optimized -fprintf-return-value" } */
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-INT_MAX - 1)
+
+extern void string_eq_min_fail ();
+extern void string_eq_max_fail ();
+
+extern void string_lt_0_fail ();
+extern void string_eq_0_fail ();
+extern void string_gt_0_fail ();
+
+void test_string (char *d, const char *s)
+{
+ int n = __builtin_sprintf (d, "%-s", s);
+
+ /* Verify that the return value is NOT assumed NOT to be INT_MIN
+ or INT_MAX. (This is a white box test based on knowing that
+ the optimization computes its own values of the two constants.) */
+ if (n == INT_MIN) string_eq_min_fail ();
+ if (n == INT_MAX) string_eq_max_fail ();
+
+ /* The return value could be negative when strlen(s) is in excess
+ of 4095 (the maximum number of bytes a single directive is required
+ to handle). */
+ if (n < 0) string_lt_0_fail ();
+ if (n == 0) string_eq_0_fail ();
+ if (n > 0) string_gt_0_fail ();
+}
+
+/* { dg-final { scan-tree-dump-times "string_eq_min_fail" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "string_eq_max_fail" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "string_lt_0_fail" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "string_eq_0_fail" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "string_gt_0_fail" 1 "optimized" } } */
typedef __WCHAR_TYPE__ wchar_t;
#endif
+typedef __WINT_TYPE__ wint_t;
+
typedef unsigned char UChar;
const char s0[] = "";
format null pointers as 0 or 0x0 and so the following will only be
diagnosed on the former targets. */
T (5, "%p", (void*)0);
- /* { dg-warning "nul past the end" "(nil)" { target *-linux-gnu *-*-uclinux } 94 } */
+ /* { dg-warning "nul past the end" "(nil)" { target *-linux-gnu *-*-uclinux } 96 } */
/* The exact output for %p is unspecified by C. Two formats are known:
same as %tx (for example AIX) and same as %#tx (for example Solaris). */
as with signed integer conversions (i.e., it prepends a space). Other
known implementations ignore it. */
T (6, "% p", (void*)0x234); /* { dg-warning ". . flag used with .%p." } */
- /* { dg-warning "nul past the end" "Glibc %p" { target *-linux-gnu } 106 } */
- /* { dg-warning "nul past the end" "Generic %p" { target *-*-uclinux } 106 } */
+ /* { dg-warning "nul past the end" "Glibc %p" { target *-linux-gnu } 108 } */
+ /* { dg-warning "nul past the end" "Generic %p" { target *-*-uclinux } 108 } */
}
/* Verify that no warning is issued for calls that write into a flexible
/* The following could result in as few as no bytes and in as many as
MB_CUR_MAX, but since the MB_CUR_MAX value is a runtime property
the write cannot be reliably diagnosed. */
- T (2, "%lc", L'1');
- T (2, "%1lc", L'1');
+ T (2, "%lc", (wint_t)L'1');
+ T (2, "%1lc", (wint_t)L'1');
/* Writing some unknown number of bytes into a field two characters wide. */
- T (2, "%2lc", L'1'); /* { dg-warning "nul past the end" } */
+ T (2, "%2lc", (wint_t)L'1'); /* { dg-warning "nul past the end" } */
- T (3, "%lc%c", L'1', '2');
+ T (3, "%lc%c", (wint_t)L'1', '2');
/* Here in the best case each argument will format as single character,
causing the terminating NUL to be written past the end. */
- T (3, "%lc%c%c", L'1', '2', '3'); /* { dg-warning "nul past the end" } */
- T (3, "%lc%lc%c", L'1', L'2', '3'); /* { dg-warning "nul past the end" } */
+ T (3, "%lc%c%c", (wint_t)L'1', '2', '3'); /* { dg-warning "nul past the end" } */
+ T (3, "%lc%lc%c", (wint_t)L'1', (wint_t)L'2', '3'); /* { dg-warning "nul past the end" } */
}
/* Exercise the "%s" and "%ls" directive with constant arguments. */
/* The following could result in as few as a single byte and in as many
as MB_CUR_MAX, but since the MB_CUR_MAX value is a runtime property
the write cannot be reliably diagnosed. */
- T (2, "%lc", L'1');
- T (2, "%1lc", L'1');
+ T (2, "%lc", (wint_t)L'1');
+ T (2, "%1lc", (wint_t)L'1');
/* Writing at least 1 characted into a field two characters wide. */
- T (2, "%2lc", L'1'); /* { dg-warning "output truncated before the last format character" } */
+ T (2, "%2lc", (wint_t)L'1'); /* { dg-warning "output truncated before the last format character" } */
- T (3, "%lc%c", L'1', '2');
+ T (3, "%lc%c", (wint_t)'1', '2');
/* Here in the best case each argument will format as single character,
causing the output to be truncated just before the terminating NUL
(i.e., cutting off the '3'). */
- T (3, "%lc%c%c", L'1', '2', '3'); /* { dg-warning "output truncated" } */
- T (3, "%lc%lc%c", L'1', L'2', '3'); /* { dg-warning "output truncated" } */
+ T (3, "%lc%c%c", (wint_t)'1', '2', '3'); /* { dg-warning "output truncated" } */
+ T (3, "%lc%lc%c", (wint_t)'1', (wint_t)'2', '3'); /* { dg-warning "output truncated" } */
}
#undef T
/* The following could result in as few as a single byte and in as many
as MB_CUR_MAX, but since the MB_CUR_MAX value is a runtime property
the write cannot be reliably diagnosed. */
- T (2, "%lc", L'1');
- T (2, "%1lc", L'1');
+ T (2, "%lc", (wint_t)L'1');
+ T (2, "%1lc", (wint_t)L'1');
/* Writing at least 1 characted into a field two characters wide. */
- T (2, "%2lc", L'1'); /* { dg-warning "output truncated before the last format character" } */
+ T (2, "%2lc", (wint_t)'1'); /* { dg-warning "output truncated before the last format character" } */
- T (3, "%lc%c", L'1', '2');
+ T (3, "%lc%c", (wint_t)'1', '2');
/* Here in the best case each argument will format as single character,
causing the output to be truncated just before the terminating NUL
(i.e., cutting off the '3'). */
- T (3, "%lc%c%c", L'1', '2', '3'); /* { dg-warning "output truncated" } */
- T (3, "%lc%lc%c", L'1', L'2', '3'); /* { dg-warning "output truncated" } */
+ T (3, "%lc%c%c", (wint_t)'1', '2', '3'); /* { dg-warning "output truncated" } */
+ T (3, "%lc%lc%c", (wint_t)'1', (wint_t)'2', '3'); /* { dg-warning "output truncated" } */
}
/* Macro to verify that calls to __builtin_vsprintf (i.e., with no size