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.
This commit is contained in:
parent
502ffb1f38
commit
600dcd74b8
8 changed files with 97 additions and 15 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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). */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
11
gcc/testsuite/gcc.dg/init-rounding-math-1.c
Normal file
11
gcc/testsuite/gcc.dg/init-rounding-math-1.c
Normal file
|
@ -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;
|
Loading…
Add table
Reference in a new issue