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  <ro...@nextmovesoftware.com>

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)

Reply via email to