On 6/3/22 14:13, Patrick Palka wrote:
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.

OK.

        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>();

Reply via email to