/* 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;
{
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;
}
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)
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);
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)
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);
&& 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)
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);
+}
#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
};
pedwarn (LOCATION, OPT, AS); \
break; \
case ic_init: \
+ case ic_init_const: \
pedwarn_init (LOCATION, OPT, IN); \
break; \
case ic_return: \
warning_at (LOCATION, OPT, AS, QUALS); \
break; \
case ic_init: \
+ case ic_init_const: \
if (PEDWARN) \
pedwarn (LOCATION, OPT, IN, QUALS); \
else \
break;
case ic_init:
+ case ic_init_const:
parmno = -2;
break;
"%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);
&& 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;
}
break;
}
case ic_init:
+ case ic_init_const:
{
const char msg[] = G_("initialization from pointer to "
"non-enclosed address space");
"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");
"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
"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,
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 "
"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);
"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);
break;
}
case ic_init:
+ case ic_init_const:
{
const char msg[]
= G_("incompatible types when initializing type %qT using type %qT");
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;
}
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);
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). */
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)
{
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);
--- /dev/null
+/* 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;