aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2023-02-02 20:07:08 +0000
committerJoseph Myers <joseph@codesourcery.com>2023-02-02 20:07:08 +0000
commit66337ff8a44559fa4600014786051a2bdd1f986b (patch)
tree62e2cf7940c5b27d54abdf792979a2bdd2b5d1d3 /gcc/c
parent5c43f06c228d169c370e99fa009154344fa305b8 (diff)
downloadgcc-66337ff8a44559fa4600014786051a2bdd1f986b.zip
gcc-66337ff8a44559fa4600014786051a2bdd1f986b.tar.gz
gcc-66337ff8a44559fa4600014786051a2bdd1f986b.tar.bz2
c: Update checks on constexpr floating-point initializers
WG14 has agreed some changes (detailed at the end of N3082) to the rules on constexpr initializers for floating types. Update GCC's implementation to match: binary initializers are now allowed for decimal types, and real initializers for complex types, but signaling NaN initializers can't be used for a different type with the same mode. There are also changes to the constexpr rules for pointer types (allowing null pointer address constants that aren't null pointer constants), which I'll deal with separately. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/c/ * c-typeck.cc: Include "realmpfr.h". (constexpr_init_fits_real_type): Do not allow signaling NaN conversions to different types with the same mode. Handle conversions from binary to decimal types. (check_constexpr_init): Do not disallow real initializers for complex types. Do not disallow binary initializers for decimal floating types. gcc/testsuite/ * gcc.dg/c2x-constexpr-1.c: Test constexpr initializers of complex types with real initializers are allowed. * gcc.dg/c2x-constexpr-3.c: Do not test for constexpr initializers of complex types with real initializers being disallowed. * gcc.dg/c2x-constexpr-8.c: Add tests of signaling NaN complex initializers. * gcc.dg/c2x-constexpr-9.c: Add more tests. * gcc.dg/dfp/c2x-constexpr-dfp-1.c: Add tests of binary floating initializers for decimal types. * gcc.dg/dfp/c2x-constexpr-dfp-2.c: Change tests of binary initializers for decimal types. Add more tests of decimal initializers for binary types.
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/c-typeck.cc111
1 files changed, 68 insertions, 43 deletions
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2737b14..9d65130 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "asan.h"
+#include "realmpfr.h"
/* Possible cases of implicit conversions. Used to select diagnostic messages
and control folding initializers in convert_for_assignment. */
@@ -8121,8 +8122,9 @@ print_spelling (char *buffer)
}
/* Check whether INIT, a floating or integer constant, is
- representable in TYPE, a real floating type with the same radix.
- Return true if OK, false if not. */
+ representable in TYPE, a real floating type with the same radix or
+ a decimal floating type initialized with a binary floating
+ constant. Return true if OK, false if not. */
static bool
constexpr_init_fits_real_type (tree type, tree init)
{
@@ -8130,8 +8132,16 @@ constexpr_init_fits_real_type (tree type, tree init)
gcc_assert (TREE_CODE (init) == INTEGER_CST || TREE_CODE (init) == REAL_CST);
if (TREE_CODE (init) == REAL_CST
&& TYPE_MODE (TREE_TYPE (init)) == TYPE_MODE (type))
- /* Same mode, no conversion required. */
- return true;
+ {
+ /* Same mode, no conversion required except for the case of
+ signaling NaNs if the types are incompatible (e.g. double and
+ long double with the same mode). */
+ if (REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (init))
+ && !comptypes (TYPE_MAIN_VARIANT (type),
+ TYPE_MAIN_VARIANT (TREE_TYPE (init))))
+ return false;
+ return true;
+ }
if (TREE_CODE (init) == INTEGER_CST)
{
tree converted = build_real_from_int_cst (type, init);
@@ -8140,6 +8150,33 @@ constexpr_init_fits_real_type (tree type, tree init)
TYPE_PRECISION (TREE_TYPE (init)));
return !fail && wi::eq_p (w, wi::to_wide (init));
}
+ if (REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (init)))
+ return false;
+ if ((REAL_VALUE_ISINF (TREE_REAL_CST (init))
+ && MODE_HAS_INFINITIES (TYPE_MODE (type)))
+ || (REAL_VALUE_ISNAN (TREE_REAL_CST (init))
+ && MODE_HAS_NANS (TYPE_MODE (type))))
+ return true;
+ if (DECIMAL_FLOAT_TYPE_P (type)
+ && !DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init)))
+ {
+ /* This is valid if the real number represented by the
+ initializer can be exactly represented in the decimal
+ type. Compare the values using MPFR. */
+ REAL_VALUE_TYPE t;
+ real_convert (&t, TYPE_MODE (type), &TREE_REAL_CST (init));
+ mpfr_t bin_val, dec_val;
+ mpfr_init2 (bin_val, REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (init)))->p);
+ mpfr_init2 (dec_val, REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (init)))->p);
+ mpfr_from_real (bin_val, &TREE_REAL_CST (init), MPFR_RNDN);
+ char string[256];
+ real_to_decimal (string, &t, sizeof string, 0, 1);
+ bool res = (mpfr_strtofr (dec_val, string, NULL, 10, MPFR_RNDN) == 0
+ && mpfr_equal_p (bin_val, dec_val));
+ mpfr_clear (bin_val);
+ mpfr_clear (dec_val);
+ return res;
+ }
/* exact_real_truncate is not quite right here, since it doesn't
allow even an exact conversion to subnormal values. */
REAL_VALUE_TYPE t;
@@ -8194,18 +8231,12 @@ check_constexpr_init (location_t loc, tree type, tree init,
if (TREE_CODE (type) == COMPLEX_TYPE
&& TREE_CODE (TREE_TYPE (type)) != REAL_TYPE)
return;
- /* Both the normative text and the relevant footnote are unclear, as
- of the C2x CD, about what exactly counts as a change of value in
- floating-point cases. Here, we consider all conversions between
- binary and decimal types (even of infinities and NaNs, where
- quantum exponents are not involved) as involving a change of
- value, and likewise for conversions between real and complex
- types (even when the complex constant has imaginary part positive
- zero), and conversions of signaling NaN to a different machine
- mode. But we allow exact conversions of integers to binary or
- decimal floating types, and exact conversions between different
- binary types or different decimal types, where "exact" in the
- decimal case requires the quantum exponent to be preserved. */
+ /* Following N3082, a real type cannot be initialized from a complex
+ type and a binary type cannot be initialized from a decimal type
+ (but initializing a decimal type from a binary type is OK).
+ Signaling NaN initializers are OK only if the types are
+ compatible (not just the same mode); all quiet NaN and infinity
+ initializations are considered to preserve the value. */
if (TREE_CODE (TREE_TYPE (init)) == COMPLEX_TYPE
&& TREE_CODE (type) == REAL_TYPE)
{
@@ -8213,39 +8244,33 @@ check_constexpr_init (location_t loc, tree type, tree init,
"complex type");
return;
}
- if (TREE_CODE (type) == COMPLEX_TYPE
- && TREE_CODE (TREE_TYPE (init)) != COMPLEX_TYPE)
- {
- error_at (loc, "%<constexpr%> initializer for a complex type is of "
- "real type");
- return;
- }
if (TREE_CODE (type) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (init)) == REAL_TYPE)
+ && TREE_CODE (TREE_TYPE (init)) == REAL_TYPE
+ && DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init))
+ && !DECIMAL_FLOAT_TYPE_P (type))
{
- if (DECIMAL_FLOAT_TYPE_P (type)
- && !DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init)))
- {
- error_at (loc, "%<constexpr%> initializer for a decimal "
- "floating-point type is of binary type");
- return;
- }
- else if (DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init))
- && !DECIMAL_FLOAT_TYPE_P (type))
- {
- error_at (loc, "%<constexpr%> initializer for a binary "
- "floating-point type is of decimal type");
- return;
- }
+ error_at (loc, "%<constexpr%> initializer for a binary "
+ "floating-point type is of decimal type");
+ return;
}
bool fits;
if (TREE_CODE (type) == COMPLEX_TYPE)
{
- gcc_assert (TREE_CODE (init) == COMPLEX_CST);
- fits = (constexpr_init_fits_real_type (TREE_TYPE (type),
- TREE_REALPART (init))
- && constexpr_init_fits_real_type (TREE_TYPE (type),
- TREE_IMAGPART (init)));
+ switch (TREE_CODE (init))
+ {
+ case INTEGER_CST:
+ case REAL_CST:
+ fits = constexpr_init_fits_real_type (TREE_TYPE (type), init);
+ break;
+ case COMPLEX_CST:
+ fits = (constexpr_init_fits_real_type (TREE_TYPE (type),
+ TREE_REALPART (init))
+ && constexpr_init_fits_real_type (TREE_TYPE (type),
+ TREE_IMAGPART (init)));
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
else
fits = constexpr_init_fits_real_type (type, init);