c++: value-dep but not type-dep decltype expr [PR105756]
authorPatrick Palka <ppalka@redhat.com>
Fri, 3 Jun 2022 18:58:22 +0000 (14:58 -0400)
committerPatrick Palka <ppalka@redhat.com>
Fri, 3 Jun 2022 18:58:22 +0000 (14:58 -0400)
Here during ahead of time instantiation of the value-dependent but not
type-dependent decltype expression (5 % N) == 0, cp_build_binary_op folds
the operands of the == via cp_fully_fold, which performs speculative
constexpr evaluation, and from which we crash for (5 % N) due to the
value-dependence.

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 avoids this
crash by suppressing cp_build_binary_op's operand folding accordingly.

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
gcc/testsuite/g++.dg/cpp0x/decltype82.C [new file with mode: 0644]

index 190d710..f9ce14f 100644 (file)
@@ -4939,7 +4939,7 @@ cp_build_binary_op (const op_location_t &location,
      convert it to this type.  */
   tree final_type = 0;
 
-  tree result, result_ovl;
+  tree result;
 
   /* Nonzero if this is an operation like MIN or MAX which can
      safely be computed in short if both args are promoted shorts.
@@ -6263,25 +6263,29 @@ cp_build_binary_op (const op_location_t &location,
     result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
                     instrument_expr, result);
 
-  if (!processing_template_decl)
+  if (resultcode == SPACESHIP_EXPR && !processing_template_decl)
+    result = get_target_expr_sfinae (result, complain);
+
+  if (!c_inhibit_evaluation_warnings)
     {
-      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))
-       return result;
-      op1 = cp_fully_fold (op1);
-      if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
+      if (!processing_template_decl)
+       {
+         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))
+           return result;
+         op1 = cp_fully_fold (op1);
+         if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
+           return result;
+       }
+      else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1)
+              || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1))
        return result;
-    }
-  else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1)
-          || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1))
-    return result;
 
-  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
-  if (TREE_OVERFLOW_P (result_ovl))
-    overflow_warning (location, result_ovl);
+      tree 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 (file)
index 0000000..915e5e3
--- /dev/null
@@ -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>();