On Thu, 2 Jun 2022, Patrick Palka wrote:

> On Thu, 2 Jun 2022, Jason Merrill wrote:
> 
> > On 6/1/22 14:20, Patrick Palka wrote:
> > > r12-7564-gec0f53a3a542e7 made us instantiate non-constant non-dependent
> > > decltype operands by relaxing instantiate_non_dependent_expr to check
> > > instantiation_dependent_uneval_expression_p.  But as the testcase below
> > > demonstrates, this predicate is too permissive here because it allows
> > > value-dependent-only expressions to go through and get instantiated
> > > ahead of time, which causes us to crash during constexpr evaluation of
> > > (5 % N).
> > 
> > Why are we doing constexpr evaluation in unevaluated context?
> 
> Looks like because cp_build_binary_op attempts to fold the resulting
> operator expression via cp_fully_fold (which performs speculate
> constexpr evaluation):
> 
> 6261  if (!processing_template_decl)
> 6262    {
> 6263      if (resultcode == SPACESHIP_EXPR)
> 6264        result = get_target_expr (result, complain);
> 6265      op0 = cp_fully_fold (op0);
> 6266      /* Only consider the second argument if the first isn't overflowed. 
>  */
> 6267      if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0))
> 6268        return result;
> 6269      op1 = cp_fully_fold (op1);
> 6270      if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
> 6271        return result;
> 6272    }
> 
> But in an unevaluated context I suppose we don't need or want to do this
> folding.  I'll work on a patch to that effect.

Here it is:

-- >8 --
Subject: [PATCH] c++: value-dep but not type-dep decltype operand [PR105756]

Here we're crashing when instantiating ahead of time the value-dependent
but not type-dependent decltype operand (5 % N) == 0, ultimately
because cp_build_binary_op folds its operands for sake of its overflow
diagnostics, and as part of this folding it performs speculative
constexpr evaluation for the operand (5 % N) during which we crash since
it's value-dependent.

Since the operand folding performed by cp_build_binary_op appears to
be solely for sake of diagnosing overflow, and since these diagnostics
are suppressed when in an unevaluated context, this patch fixes this
crash by suppressing cp_build_binary_op's operand folding accordingly.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/12?  The diff was generated with -w to suppress noisy whitespace
changes.

        PR c++/105756

gcc/cp/ChangeLog:

        * typeck.cc (cp_build_binary_op): Don't fold operands
        when c_inhibit_evaluation_warnings.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/decltype82.C: New test.
---
 gcc/cp/typeck.cc                        |  8 ++++++--
 gcc/testsuite/g++.dg/cpp0x/decltype82.C | 10 ++++++++++
 2 files changed, 16 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype82.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 190d710cd27..7c910d57b7e 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -6263,10 +6263,13 @@ cp_build_binary_op (const op_location_t &location,
     result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
                     instrument_expr, result);
 
+  if (resultcode == SPACESHIP_EXPR && !processing_template_decl)
+    result = get_target_expr_sfinae (result, complain);
+
+  if (!c_inhibit_evaluation_warnings)
+    {
       if (!processing_template_decl)
        {
-      if (resultcode == SPACESHIP_EXPR)
-       result = get_target_expr_sfinae (result, complain);
          op0 = cp_fully_fold (op0);
          /* Only consider the second argument if the first isn't overflowed.  
*/
          if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0))
@@ -6282,6 +6285,7 @@ cp_build_binary_op (const op_location_t &location,
       result_ovl = fold_build2 (resultcode, build_type, op0, op1);
       if (TREE_OVERFLOW_P (result_ovl))
        overflow_warning (location, result_ovl);
+    }
 
   return result;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype82.C 
b/gcc/testsuite/g++.dg/cpp0x/decltype82.C
new file mode 100644
index 00000000000..915e5e37675
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype82.C
@@ -0,0 +1,10 @@
+// PR c++/105756
+// { dg-do compile { target c++11 } }
+
+template<int N>
+void f() {
+  using ty1 = decltype((5 % N) == 0);
+  using ty2 = decltype((5 / N) == 0);
+}
+
+template void f<0>();
-- 
2.36.1.210.g2668e3608e

Reply via email to