diff options
author | Joseph Myers <joseph@codesourcery.com> | 2023-02-02 20:07:08 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2023-02-02 20:07:08 +0000 |
commit | 66337ff8a44559fa4600014786051a2bdd1f986b (patch) | |
tree | 62e2cf7940c5b27d54abdf792979a2bdd2b5d1d3 /gcc/c | |
parent | 5c43f06c228d169c370e99fa009154344fa305b8 (diff) | |
download | gcc-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.cc | 111 |
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); |