I was wondering if I may ask the C++ language experts for their opinion
on whether (potential) floating point exceptions/traps can be ignored
in constant expressions; this is related to PR c++/96862. I think my
question boils down to whether (or not) the following is valid C++:
constexpr float my_inf = 7.0 / 0.0;
[This is currently an error with "-O2", but OK with "-O2 -ffast-math"!]
There's a long history of g++'s semantics being accidentally tied to
the middle-end's constant folding, such that the current status quo
is that some middle-end bugs can't be fixed without breaking C++,
and vice versa. I'm hoping that the patch below (following Jakub's
lead with rounding math) might be a next step to improving things,
provided that my understanding of the desired/correct behaviour of
the C++ front-end is correct.
This patch has been tested on x86_64-pc-linux-gnu with a "make bootstrap"
and "make -k check" with no new failures after tweaking two checks in
g++.dg/ubsan/pr63956.C. With this change the middle-end can become more
strict about respecting flag_trapping_math without affecting C++'s
behavior. Ideally, what the front-end considers valid should be
independent of whether the user specified -fno-trapping-math (or
-ffast-math) to the middle-end.
Thoughts? Ok for mainline?
2021-09-21 Roger Sayle <[email protected]>
gcc/cp/ChangeLog
* constexpr.c (cxx_eval_outermost_const_expr): Temporarily disable
the middle-end from honoring floating point exceptions/traps while
folding "manifestly constant" expressions.
gcc/testsuite/ChangeLog
* g++.dg/ubsan/pr63956.C: Update to (always) allow floating point
division in constexpr (if both operands are constexpr).
Roger
--
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 8a5dd06..ddea132 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -7276,6 +7276,13 @@ cxx_eval_outermost_constant_expr (tree t, bool
allow_non_constant,
/* Turn off -frounding-math for manifestly constant evaluation. */
warning_sentinel rm (flag_rounding_math, ctx.manifestly_const_eval);
+ /* For manifestly constant evaluation, trapping (floating point)
+ exceptions don't prevent evaluation at compile-time, so temporarily
+ turn off -fsignaling-nans, -ftrapping-math and -ftrapv. */
+ warning_sentinel sn (flag_signaling_nans, ctx.manifestly_const_eval);
+ warning_sentinel tm (flag_trapping_math, ctx.manifestly_const_eval);
+ warning_sentinel tv (flag_trapv, ctx.manifestly_const_eval);
+
tree type = initialized_type (t);
tree r = t;
bool is_consteval = false;
diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C
b/gcc/testsuite/g++.dg/ubsan/pr63956.C
index 3a1596e..126ed1d 100644
--- a/gcc/testsuite/g++.dg/ubsan/pr63956.C
+++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C
@@ -69,12 +69,12 @@ constexpr float
fn4 (float a, float b)
{
if (b != 2.0)
- a = a / b; // { dg-error "is not a constant expression" }
+ a = a / b;
return a;
}
constexpr float l1 = fn4 (5.0, 3.0);
-constexpr float l2 = fn4 (7.0, 0.0); // { dg-message "in .constexpr.
expansion" }
+constexpr float l2 = fn4 (7.0, 0.0);
constexpr int
fn5 (const int *a, int b)