@@ -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);
@@ -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. */
@@ -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" } */
@@ -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 ("") };
}
@@ -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" } */
}
@@ -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 ("") };
}
@@ -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" } */