https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109359
--- Comment #6 from Richard Biener <rguenth at gcc dot gnu.org> --- output_constant gets called with {(float) 1.91399999999999990279997419406754488591104745864868164062e-3, (float) 6.305389999999999606217215841752476990222930908203125e-1} it then eventually does /* Eliminate any conversions since we'll be outputting the underlying constant. */ while (CONVERT_EXPR_P (exp) || TREE_CODE (exp) == NON_LVALUE_EXPR || TREE_CODE (exp) == VIEW_CONVERT_EXPR) { HOST_WIDE_INT type_size = int_size_in_bytes (TREE_TYPE (exp)); HOST_WIDE_INT op_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))); /* Make sure eliminating the conversion is really a no-op, except with VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and union types to allow for Ada unchecked unions. */ if (type_size > op_size && TREE_CODE (exp) != VIEW_CONVERT_EXPR && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE) /* Keep the conversion. */ break; else exp = TREE_OPERAND (exp, 0); } where we strip conversions with type_size < op_size (aka float from double). For float conversions not sure if just keying on type size is good enough though (ibm double double vs long double 128 for example). Fixing that "improves" the behavior to t.ii:1:34: error: initializer for floating value is not a floating constant 1 | float xs[] = {0.001914, 0.630539}; | ^ t.ii:1:34: error: initializer for floating value is not a floating constant aka from wrong-code to rejects-valid. diff --git a/gcc/varasm.cc b/gcc/varasm.cc index cd0cd88321c..e6ab581dc5f 100644 --- a/gcc/varasm.cc +++ b/gcc/varasm.cc @@ -5202,7 +5202,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, /* Make sure eliminating the conversion is really a no-op, except with VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and union types to allow for Ada unchecked unions. */ - if (type_size > op_size + if (type_size != op_size && TREE_CODE (exp) != VIEW_CONVERT_EXPR && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE) /* Keep the conversion. */ note that for integral and pointer types we do cst = expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); if (reverse) cst = flip_storage_order (TYPE_MODE (TREE_TYPE (exp)), cst); if (!assemble_integer (cst, MIN (size, thissize), align, 0)) error ("initializer for integer/fixed-point value is too complicated"); so we handle "narrowing" in a weird way. So in case FEs leave around nop-casts the following should be safer diff --git a/gcc/varasm.cc b/gcc/varasm.cc index cd0cd88321c..81f7288449c 100644 --- a/gcc/varasm.cc +++ b/gcc/varasm.cc @@ -5196,13 +5196,17 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, || TREE_CODE (exp) == NON_LVALUE_EXPR || TREE_CODE (exp) == VIEW_CONVERT_EXPR) { - HOST_WIDE_INT type_size = int_size_in_bytes (TREE_TYPE (exp)); - HOST_WIDE_INT op_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))); + tree type = TREE_TYPE (exp); + tree op_type = TREE_TYPE (TREE_OPERAND (exp, 0)); + HOST_WIDE_INT type_size = int_size_in_bytes (type); + HOST_WIDE_INT op_size = int_size_in_bytes (op_type); /* Make sure eliminating the conversion is really a no-op, except with VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and union types to allow for Ada unchecked unions. */ - if (type_size > op_size + if ((type_size > op_size + || (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (op_type) + && FLOAT_TYPE_P (type))) && TREE_CODE (exp) != VIEW_CONVERT_EXPR && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE) /* Keep the conversion. */ The real fix is of course in the frontend, the above is just a safety net.