diff options
author | Joseph Myers <joseph@codesourcery.com> | 2021-11-03 14:58:25 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2021-11-03 14:59:22 +0000 |
commit | 600dcd74b8e614c996b492d97878660faf484094 (patch) | |
tree | 8dc7b818bb5a1b08b33fe1c391510e9e93a16cca /gcc/c | |
parent | 502ffb1f389011b28ee51815242c7397790802d5 (diff) | |
download | gcc-600dcd74b8e614c996b492d97878660faf484094.zip gcc-600dcd74b8e614c996b492d97878660faf484094.tar.gz gcc-600dcd74b8e614c996b492d97878660faf484094.tar.bz2 |
c: Fold implicit integer-to-floating conversions in static initializers with -frounding-math [PR103031]
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.
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.c (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.
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/c-convert.c | 35 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 27 |
2 files changed, 52 insertions, 10 deletions
diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c index d0035a3..905b26a 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 0aac978..782414f 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); |