On Wed, Nov 3, 2021 at 1:22 AM Joseph Myers <jos...@codesourcery.com> wrote: > > Recent fixes to avoid inappropriate folding of some conversions to > floating-point types with -frounding-math also prevented such folding > in C static initializers, when folding (in the default rounding mode, > exceptions discarded) is required for correctness. > > Folding for static initializers is handled via functions in > fold-const.c calling START_FOLD_INIT and END_FOLD_INIT to adjust flags > such as flag_rounding_math that should not apply in static initializer > context, but no such function was being called for the folding of > these implicit conversions to the type of the object being > initialized, only for explicit conversions as part of the initializer. > > Arrange for relevant folding (a fold call in convert, in particular) > to use this special initializer handling (via a new fold_init > function, in particular). > > Because convert is used by language-independent code but defined in > each front end, this isn't as simple as just adding a new default > argument to it. Instead, I added a new convert_init function; that > then gets called by c-family code, and C and C++ need convert_init > implementations (the C++ one does nothing different from convert and > will never actually get called because the new convert_and_check > argument will never be true from C++), but other languages don't. > > Bootstrapped with no regressions for x86_64-pc-linux-gnu. OK to commit > (the changes outside the C front end)?
OK. Thanks, Richard. > gcc/ > PR c/103031 > * fold-const.c (fold_init): New function. > * fold-const.h (fold_init): New prototype. > > gcc/c-family/ > PR c/103031 > * c-common.c (convert_and_check): Add argument init_const. Call > convert_init if init_const. > * c-common.h (convert_and_check): Update prototype. > (convert_init): New prototype. > > gcc/c/ > PR c/103031 > * c-convert.c (c_convert): New function, based on convert. > (convert): Make into wrapper of c_convert. > (convert_init): New function. > * c-typeck.h (enum impl_conv): Add ic_init_const. > (convert_for_assignment): Handle ic_init_const like ic_init. Add > new argument to convert_and_check call. > (digest_init): Pass ic_init_const to convert_for_assignment for > initializers required to be constant. > > gcc/cp/ > PR c/103031 > * cvt.c (convert_init): New function. > > gcc/testsuite/ > PR c/103031 > * gcc.dg/init-rounding-math-1.c: New test. > > diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c > index 32c7e3e8972..436df45df68 100644 > --- a/gcc/c-family/c-common.c > +++ b/gcc/c-family/c-common.c > @@ -1739,10 +1739,13 @@ unsafe_conversion_p (tree type, tree expr, tree > result, bool check_sign) > > /* Convert EXPR to TYPE, warning about conversion problems with constants. > Invoke this function on every expression that is converted implicitly, > - i.e. because of language rules and not because of an explicit cast. */ > + i.e. because of language rules and not because of an explicit cast. > + INIT_CONST is true if the conversion is for arithmetic types for a static > + initializer and folding must apply accordingly (discarding floating-point > + exceptions and assuming the default rounding mode is in effect). */ > > tree > -convert_and_check (location_t loc, tree type, tree expr) > +convert_and_check (location_t loc, tree type, tree expr, bool init_const) > { > tree result; > tree expr_for_warning; > @@ -1754,7 +1757,9 @@ convert_and_check (location_t loc, tree type, tree expr) > { > tree orig_type = TREE_TYPE (expr); > expr = TREE_OPERAND (expr, 0); > - expr_for_warning = convert (orig_type, expr); > + expr_for_warning = (init_const > + ? convert_init (orig_type, expr) > + : convert (orig_type, expr)); > if (orig_type == type) > return expr_for_warning; > } > @@ -1764,7 +1769,7 @@ convert_and_check (location_t loc, tree type, tree expr) > if (TREE_TYPE (expr) == type) > return expr; > > - result = convert (type, expr); > + result = init_const ? convert_init (type, expr) : convert (type, expr); > > if (c_inhibit_evaluation_warnings == 0 > && !TREE_OVERFLOW_P (expr) > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > index f60714e3416..d5dad99ff97 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -886,7 +886,7 @@ extern tree c_alignof_expr (location_t, tree); > NOP_EXPR is used as a special case (see truthvalue_conversion). */ > extern void binary_op_error (rich_location *, enum tree_code, tree, tree); > extern tree fix_string_type (tree); > -extern tree convert_and_check (location_t, tree, tree); > +extern tree convert_and_check (location_t, tree, tree, bool = false); > extern bool c_determine_visibility (tree); > extern bool vector_types_compatible_elements_p (tree, tree); > extern void mark_valid_location_for_stdc_pragma (bool); > @@ -908,6 +908,8 @@ extern tree c_common_get_narrower (tree, int *); > extern bool get_attribute_operand (tree, unsigned HOST_WIDE_INT *); > extern void c_common_finalize_early_debug (void); > > +/* Used by convert_and_check; in front ends. */ > +extern tree convert_init (tree, tree); > > #define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, false, 1) > #define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1) > diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c > index d0035a31723..905b26a09a1 100644 > --- a/gcc/c/c-convert.c > +++ b/gcc/c/c-convert.c > @@ -60,10 +60,13 @@ along with GCC; see the file COPYING3. If not see > converted to type TYPE. The TREE_TYPE of the value > is always TYPE. This function implements all reasonable > conversions; callers should filter out those that are > - not permitted by the language being compiled. */ > + not permitted by the language being compiled. > + INIT_CONST is true if the conversion is for arithmetic types for a static > + initializer and folding must apply accordingly (discarding floating-point > + exceptions and assuming the default rounding mode is in effect). */ > > -tree > -convert (tree type, tree expr) > +static tree > +c_convert (tree type, tree expr, bool init_const) > { > tree e = expr; > enum tree_code code = TREE_CODE (type); > @@ -115,7 +118,7 @@ convert (tree type, tree expr) > && COMPLETE_TYPE_P (type)) > { > expr = save_expr (expr); > - expr = c_fully_fold (expr, false, NULL); > + expr = c_fully_fold (expr, init_const, NULL); > tree check = ubsan_instrument_float_cast (loc, type, expr); > expr = fold_build1 (FIX_TRUNC_EXPR, type, expr); > if (check == NULL_TREE) > @@ -173,10 +176,32 @@ convert (tree type, tree expr) > > maybe_fold: > if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR) > - ret = fold (ret); > + ret = init_const ? fold_init (ret) : fold (ret); > return ret; > } > > error ("conversion to non-scalar type requested"); > return error_mark_node; > } > + > +/* Create an expression whose value is that of EXPR, converted to type TYPE. > + The TREE_TYPE of the value is always TYPE. This function implements all > + reasonable conversions; callers should filter out those that are not > + permitted by the language being compiled. */ > + > +tree > +convert (tree type, tree expr) > +{ > + return c_convert (type, expr, false); > +} > + > +/* Create an expression whose value is that of EXPR, converted to type TYPE, > in > + a static initializer. The TREE_TYPE of the value is always TYPE. This > + function implements all reasonable conversions; callers should filter out > + those that are not permitted by the language being compiled. */ > + > +tree > +convert_init (tree type, tree expr) > +{ > + return c_convert (type, expr, true); > +} > diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c > index 0aac978c02e..782414f8c8c 100644 > --- a/gcc/c/c-typeck.c > +++ b/gcc/c/c-typeck.c > @@ -53,12 +53,13 @@ along with GCC; see the file COPYING3. If not see > #include "attribs.h" > #include "asan.h" > > -/* Possible cases of implicit bad conversions. Used to select > - diagnostic messages in convert_for_assignment. */ > +/* Possible cases of implicit conversions. Used to select diagnostic > messages > + and control folding initializers in convert_for_assignment. */ > enum impl_conv { > ic_argpass, > ic_assign, > ic_init, > + ic_init_const, > ic_return > }; > > @@ -6802,6 +6803,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > pedwarn (LOCATION, OPT, AS); \ > break; \ > case ic_init: \ > + case ic_init_const: \ > pedwarn_init (LOCATION, OPT, IN); \ > break; \ > case ic_return: \ > @@ -6838,6 +6840,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > warning_at (LOCATION, OPT, AS, QUALS); \ > break; \ > case ic_init: \ > + case ic_init_const: \ > if (PEDWARN) \ > pedwarn (LOCATION, OPT, IN, QUALS); \ > else \ > @@ -6886,6 +6889,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > break; > > case ic_init: > + case ic_init_const: > parmno = -2; > break; > > @@ -6919,6 +6923,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > "%qT in assignment is invalid in C++", rhstype, type); > break; > case ic_init: > + case ic_init_const: > pedwarn_init (location, OPT_Wc___compat, "enum conversion from " > "%qT to %qT in initialization is invalid in C++", > rhstype, type); > @@ -7029,7 +7034,8 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > && sanitize_flags_p (SANITIZE_FLOAT_CAST))) > in_late_binary_op = true; > tree ret = convert_and_check (expr_loc != UNKNOWN_LOCATION > - ? expr_loc : location, type, orig_rhs); > + ? expr_loc : location, type, orig_rhs, > + errtype == ic_init_const); > in_late_binary_op = save; > return ret; > } > @@ -7252,6 +7258,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > break; > } > case ic_init: > + case ic_init_const: > { > const char msg[] = G_("initialization from pointer to " > "non-enclosed address space"); > @@ -7296,6 +7303,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > "a candidate for a format attribute"); > break; > case ic_init: > + case ic_init_const: > warning_at (location, OPT_Wsuggest_attribute_format, > "initialization left-hand side might be " > "a candidate for a format attribute"); > @@ -7339,6 +7347,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > "incompatible scalar storage order", type, rhstype); > break; > case ic_init: > + case ic_init_const: > /* Likewise. */ > if (TREE_CODE (rhs) != CALL_EXPR > || (t = get_callee_fndecl (rhs)) == NULL_TREE > @@ -7465,6 +7474,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > "differ in signedness", rhstype, type); > break; > case ic_init: > + case ic_init_const: > pedwarn_init (location, OPT_Wpointer_sign, > "pointer targets in initialization of %qT " > "from %qT differ in signedness", type, > @@ -7530,6 +7540,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > type, rhstype); > break; > case ic_init: > + case ic_init_const: > if (bltin) > pedwarn_init (location, OPT_Wincompatible_pointer_types, > "initialization of %qT from pointer to " > @@ -7599,6 +7610,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > "without a cast", type, rhstype); > break; > case ic_init: > + case ic_init_const: > pedwarn_init (location, OPT_Wint_conversion, > "initialization of %qT from %qT makes pointer from " > "integer without a cast", type, rhstype); > @@ -7635,6 +7647,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > "without a cast", type, rhstype); > break; > case ic_init: > + case ic_init_const: > pedwarn_init (location, OPT_Wint_conversion, > "initialization of %qT from %qT makes integer from " > "pointer without a cast", type, rhstype); > @@ -7686,6 +7699,7 @@ convert_for_assignment (location_t location, location_t > expr_loc, tree type, > break; > } > case ic_init: > + case ic_init_const: > { > const char msg[] > = G_("incompatible types when initializing type %qT using type > %qT"); > @@ -8195,7 +8209,9 @@ digest_init (location_t init_loc, tree type, tree init, > tree origtype, > if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE) > inside_init = convert_for_assignment (init_loc, UNKNOWN_LOCATION, > type, inside_init, origtype, > - ic_init, null_pointer_constant, > + (require_constant > + ? ic_init_const > + : ic_init), > null_pointer_constant, > NULL_TREE, NULL_TREE, 0); > return inside_init; > } > @@ -8215,7 +8231,8 @@ digest_init (location_t init_loc, tree type, tree init, > tree origtype, > inside_init); > inside_init > = convert_for_assignment (init_loc, UNKNOWN_LOCATION, type, > - inside_init, origtype, ic_init, > + inside_init, origtype, > + require_constant ? ic_init_const : ic_init, > null_pointer_constant, NULL_TREE, NULL_TREE, > 0); > > diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c > index d035e611be4..7e6752af1df 100644 > --- a/gcc/cp/cvt.c > +++ b/gcc/cp/cvt.c > @@ -1685,6 +1685,15 @@ convert (tree type, tree expr) > tf_warning_or_error); > } > > +/* Like convert, but in a static initializer (called from > + convert_and_check). */ > + > +tree > +convert_init (tree type, tree expr) > +{ > + return convert (type, expr); > +} > + > /* Like cp_convert, except permit conversions to take place which > are not normally allowed due to access restrictions > (such as conversion from sub-type to private super-type). */ > diff --git a/gcc/fold-const.c b/gcc/fold-const.c > index 2d3ba07e541..90d82257ae7 100644 > --- a/gcc/fold-const.c > +++ b/gcc/fold-const.c > @@ -13940,6 +13940,18 @@ fold_build_call_array_loc (location_t loc, tree > type, tree fn, > flag_trapv = saved_trapv;\ > folding_initializer = saved_folding_initializer; > > +tree > +fold_init (tree expr) > +{ > + tree result; > + START_FOLD_INIT; > + > + result = fold (expr); > + > + END_FOLD_INIT; > + return result; > +} > + > tree > fold_build1_initializer_loc (location_t loc, enum tree_code code, > tree type, tree op) > diff --git a/gcc/fold-const.h b/gcc/fold-const.h > index fed476842c7..56e9d399c0d 100644 > --- a/gcc/fold-const.h > +++ b/gcc/fold-const.h > @@ -44,6 +44,7 @@ extern void shift_bytes_in_array_right (unsigned char *, > unsigned int, > subexpressions are not changed. */ > > extern tree fold (tree); > +extern tree fold_init (tree); > #define fold_unary(CODE,T1,T2)\ > fold_unary_loc (UNKNOWN_LOCATION, CODE, T1, T2) > extern tree fold_unary_loc (location_t, enum tree_code, tree, tree); > diff --git a/gcc/testsuite/gcc.dg/init-rounding-math-1.c > b/gcc/testsuite/gcc.dg/init-rounding-math-1.c > new file mode 100644 > index 00000000000..2bece1a09d5 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/init-rounding-math-1.c > @@ -0,0 +1,11 @@ > +/* Test static initializer folding of implicit conversions to floating point > + types, even with -frounding-math and related options. Bug 103031. */ > +/* { dg-do compile } */ > +/* { dg-options "-frounding-math -ftrapping-math -fsignaling-nans" } */ > + > +float f1 = -1ULL; > +float f2 = __DBL_MAX__; > +float f3 = __DBL_MIN__; > +float f4 = 0.1; > +float f5 = __builtin_nans (""); > +double d1 = -1ULL; > > -- > Joseph S. Myers > jos...@codesourcery.com