diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 2737b14ea187db1a150d6f6c140dab313aa43daa..9d65130154da41a89d8e1dc2d199473883681b9a 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); diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-1.c b/gcc/testsuite/gcc.dg/c2x-constexpr-1.c index d43d95ddd7c4d9c36d122e9bd9c6c3836b443062..97b54f17428f267e2c5bcb6e83f5da294a361fd8 100644 --- a/gcc/testsuite/gcc.dg/c2x-constexpr-1.c +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-1.c @@ -174,6 +174,8 @@ constexpr int v94 = alignof (int); alignas (v94) int v95; constexpr int v97[100] = { [v82.x.f] = 7 }; static int v98[v94]; +constexpr _Complex double v99 = 1.0; +constexpr _Complex float v100 = 12345; void f0 () @@ -247,6 +249,8 @@ f0 () (constexpr union u58) { 0 }; (constexpr union u58) { { } }; /* { dg-warning "braces around scalar initializer" } */ (constexpr union u58) { { 0 } }; /* { dg-warning "braces around scalar initializer" } */ + (constexpr _Complex double) { 1.0 }; + (constexpr _Complex float) { 12345 }; /* It's not entirely clear if constexpr declarations are allowed in this position in a for loop; presume they are, as implicitly auto just as if no storage class specifiers were used. */ diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-3.c b/gcc/testsuite/gcc.dg/c2x-constexpr-3.c index 29fedc03afd4c160b7693723dea69bb644ff3798..4f6b8ed67794a963a34dc19a0c9e4f6d26bf9d2e 100644 --- a/gcc/testsuite/gcc.dg/c2x-constexpr-3.c +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-3.c @@ -112,13 +112,9 @@ constexpr int v95 = (unsigned int) -1; /* { dg-error "'constexpr' initializer no constexpr unsigned char v96 = -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */ constexpr signed char v97 = 1234567LL; /* { dg-error "'constexpr' initializer not representable in type of object" } */ /* { dg-warning "overflow in conversion" "overflow warning" { target *-*-* } .-1 } */ -/* Disallow all real/complex conversions (the C2x CD is unclear about - real-to-complex and about complex-to-real with imaginary part positive 0, if - the real parts can be exactly represented in the relevant types). */ constexpr double v98 = __builtin_complex (1.0, 0.0); /* { dg-error "'constexpr' initializer for a real type is of complex type" } */ constexpr double v99 = __builtin_complex (1.0, 1.0); /* { dg-error "'constexpr' initializer for a real type is of complex type" } */ constexpr double v100 = __builtin_complex (1.0, -0.0); /* { dg-error "'constexpr' initializer for a real type is of complex type" } */ -constexpr _Complex double v101 = 1.0; /* { dg-error "'constexpr' initializer for a complex type is of real type" } */ constexpr float v102 = (unsigned long long) -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */ constexpr double v103 = (unsigned long long) -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */ constexpr float v104 = __LONG_LONG_MAX__; /* { dg-error "'constexpr' initializer not representable in type of object" } */ @@ -216,7 +212,6 @@ f0 () (constexpr double) { __builtin_complex (1.0, 0.0) }; /* { dg-error "'constexpr' initializer for a real type is of complex type" } */ (constexpr double) { __builtin_complex (1.0, 1.0) }; /* { dg-error "'constexpr' initializer for a real type is of complex type" } */ (constexpr double) { __builtin_complex (1.0, -0.0) }; /* { dg-error "'constexpr' initializer for a real type is of complex type" } */ - (constexpr _Complex double) { 1.0 }; /* { dg-error "'constexpr' initializer for a complex type is of real type" } */ (constexpr float) { (unsigned long long) -1 }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ (constexpr double) { (unsigned long long) -1 }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ (constexpr float) { __LONG_LONG_MAX__ }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-8.c b/gcc/testsuite/gcc.dg/c2x-constexpr-8.c index c7119c97a6978df7ebf7ef45fe812ea607aea7e8..11372cf1d5aad3ddbb4cd9c7c4c7ad71978031d9 100644 --- a/gcc/testsuite/gcc.dg/c2x-constexpr-8.c +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-8.c @@ -10,6 +10,7 @@ constexpr float fn = __builtin_nan (""); constexpr double dn = __builtin_nanf (""); constexpr float fns = __builtin_nansf (""); constexpr double dns = __builtin_nans (""); +constexpr _Complex double cdns = __builtin_nans (""); void f0 (void) @@ -20,4 +21,5 @@ f0 (void) (constexpr double) { __builtin_nanf ("") }; (constexpr float) { __builtin_nansf ("") }; (constexpr double) { __builtin_nans ("") }; + (constexpr _Complex double) { __builtin_nans ("") }; } diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-9.c b/gcc/testsuite/gcc.dg/c2x-constexpr-9.c index c62fc738fa055a21d48d9b27a4da6c3330075000..8a07ed5b3833793383620cba0e4d428f58c0397a 100644 --- a/gcc/testsuite/gcc.dg/c2x-constexpr-9.c +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-9.c @@ -4,10 +4,11 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target inff } */ -/* A conversion from signaling NaN to quiet NaN in a different format is not - valid for constexpr. */ +/* A conversion from signaling NaN to quiet NaN in a different format or type + is not valid for constexpr. */ constexpr float fns = __builtin_nans (""); /* { dg-error "'constexpr' initializer not representable in type of object" } */ constexpr double dns = __builtin_nansf (""); /* { dg-error "'constexpr' initializer not representable in type of object" } */ +constexpr long double ldns = __builtin_nans (""); /* { dg-error "'constexpr' initializer not representable in type of object" } */ /* Test out-of-range values. */ constexpr float fu = __DBL_MIN__; /* { dg-error "'constexpr' initializer not representable in type of object" } */ @@ -22,6 +23,9 @@ constexpr _Complex float cfui = __builtin_complex (0.0, __DBL_MIN__); /* { dg-er constexpr _Complex float cfoi = __builtin_complex (0.0, __DBL_MAX__); /* { dg-error "'constexpr' initializer not representable in type of object" } */ constexpr _Complex float cfpi = __builtin_complex (0.0, 0x1.ffffffp0); /* { dg-error "'constexpr' initializer not representable in type of object" } */ +constexpr _Complex float cfd = __DBL_MAX__; /* { dg-error "'constexpr' initializer not representable in type of object" } */ +constexpr _Complex float cfi = __LONG_LONG_MAX__; /* { dg-error "'constexpr' initializer not representable in type of object" } */ + void f0 () { @@ -36,4 +40,6 @@ f0 () (constexpr _Complex float) { __builtin_complex (0.0, __DBL_MIN__) }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ (constexpr _Complex float) { __builtin_complex (0.0, __DBL_MAX__) }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ (constexpr _Complex float) { __builtin_complex (0.0, 0x1.ffffffp0) }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ + (constexpr _Complex float) { __DBL_MAX__ }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ + (constexpr _Complex float) { __LONG_LONG_MAX__ }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ } diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c index 568f1428b40bf7c24027e4471bfe72938b139e3c..4ac6629ff5af782bd6125f20250291b378f14abc 100644 --- a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c +++ b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c @@ -37,6 +37,11 @@ constexpr _Decimal128 v32 = __builtin_nansd128 (""); constexpr _Decimal32 v33 = {}; constexpr _Decimal64 v34 = {}; constexpr _Decimal128 v35 = {}; +constexpr _Decimal32 v36 = 0.0; +constexpr _Decimal32 v37 = 0.0009765625; +constexpr _Decimal64 v38 = 6.103515625e-05; +constexpr _Decimal32 v39 = __builtin_inf (); +constexpr _Decimal32 v40 = __builtin_nan (""); void f0 () @@ -76,4 +81,9 @@ f0 () (constexpr _Decimal32) {}; (constexpr _Decimal64) {}; (constexpr _Decimal128) {}; + (constexpr _Decimal32) { 0.0 }; + (constexpr _Decimal32) { 0.0009765625 }; + (constexpr _Decimal64) { 6.103515625e-05 }; + (constexpr _Decimal32) { __builtin_inf () }; + (constexpr _Decimal32) { __builtin_nan ("") }; } diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c index 8b1ecf239083e653a380258658a352138cacc2cc..8ce0d088ac3d75b7709e2bf993f5086a04413104 100644 --- a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c +++ b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c @@ -3,8 +3,10 @@ /* { dg-options "-std=c2x -pedantic-errors" } */ /* Test conversions between binary and decimal. */ -constexpr _Decimal32 v1 = 0.0; /* { dg-error "'constexpr' initializer for a decimal floating-point type is of binary type" } */ constexpr double v2 = 0.0DF; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */ +constexpr double v2i = __builtin_infd32 (); /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */ +constexpr double v2n = __builtin_nand32 (""); /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */ +constexpr _Decimal128 v2d = 0x1p-100f; /* { dg-error "'constexpr' initializer not representable in type of object" } */ /* A conversion from signaling NaN to quiet NaN in a different format is not valid for constexpr. */ @@ -30,8 +32,10 @@ constexpr _Decimal32 v15 = 0e200DL; /* { dg-error "'constexpr' initializer not r void f0 () { - (constexpr _Decimal32) { 0.0 }; /* { dg-error "'constexpr' initializer for a decimal floating-point type is of binary type" } */ (constexpr double) { 0.0DF }; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */ + (constexpr double) { __builtin_infd32 () }; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */ + (constexpr double) { __builtin_nand32 ("") }; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */ + (constexpr _Decimal128) { 0x1p-100f }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ (constexpr _Decimal32) { __builtin_nansd64 ("") }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ (constexpr _Decimal32) { __builtin_nansd128 ("") }; /* { dg-error "'constexpr' initializer not representable in type of object" } */ (constexpr _Decimal64) { __builtin_nansd32 ("") }; /* { dg-error "'constexpr' initializer not representable in type of object" } */