aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2021-11-03 14:58:25 +0000
committerJoseph Myers <joseph@codesourcery.com>2021-11-03 14:59:22 +0000
commit600dcd74b8e614c996b492d97878660faf484094 (patch)
tree8dc7b818bb5a1b08b33fe1c391510e9e93a16cca /gcc/c
parent502ffb1f389011b28ee51815242c7397790802d5 (diff)
downloadgcc-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.c35
-rw-r--r--gcc/c/c-typeck.c27
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);