]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: ICE with <=> fallback [PR100367]
authorJason Merrill <jason@redhat.com>
Tue, 18 May 2021 16:29:33 +0000 (12:29 -0400)
committerJason Merrill <jason@redhat.com>
Wed, 19 May 2021 20:17:15 +0000 (16:17 -0400)
Here, when genericizing lexicographical_compare_three_way, we haven't yet
walked the operands, so (a == a) still sees ADDR_EXPR <a>, but this is after
we've changed the type of a to REFERENCE_TYPE.  When we try to fold (a == a)
by constexpr evaluation, the constexpr code doesn't understand trying to
take the address of a reference, and we end up crashing.

Fixed by avoiding constexpr evaluation in genericize_spaceship, by using
fold_build2 instead of build_new_op on scalar operands.  Class operands
should have been expanded during parsing.

PR c++/100367
PR c++/96299

gcc/cp/ChangeLog:

* method.c (genericize_spaceship): Use fold_build2 for scalar
operands.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/spaceship-fallback1.C: New test.

gcc/cp/method.c
gcc/testsuite/g++.dg/cpp2a/spaceship-fallback1.C [new file with mode: 0644]

index 0f416bec35b5e562f4448b5110b64d6ae9817667..1c3cf834bf497bbc4293ac9ec499ee741124ee82 100644 (file)
@@ -1087,7 +1087,8 @@ genericize_spaceship (location_t loc, tree type, tree op0, tree op1)
   gcc_checking_assert (tag < cc_last);
 
   tree r;
-  if (SCALAR_TYPE_P (TREE_TYPE (op0)))
+  bool scalar = SCALAR_TYPE_P (TREE_TYPE (op0));
+  if (scalar)
     {
       op0 = save_expr (op0);
       op1 = save_expr (op1);
@@ -1097,26 +1098,53 @@ genericize_spaceship (location_t loc, tree type, tree op0, tree op1)
 
   int flags = LOOKUP_NORMAL;
   tsubst_flags_t complain = tf_none;
+  tree comp;
 
   if (tag == cc_partial_ordering)
     {
       /* op0 == op1 ? equivalent : op0 < op1 ? less :
         op1 < op0 ? greater : unordered */
       tree uo = lookup_comparison_result (tag, type, 3);
-      tree comp = build_new_op (loc, LT_EXPR, flags, op1, op0, complain);
-      r = build_conditional_expr (loc, comp, gt, uo, complain);
+      if (scalar)
+       {
+         /* For scalars use the low level operations; using build_new_op causes
+            trouble with constexpr eval in the middle of genericize (100367).  */
+         comp = fold_build2 (LT_EXPR, boolean_type_node, op1, op0);
+         r = fold_build3 (COND_EXPR, type, comp, gt, uo);
+       }
+      else
+       {
+         comp = build_new_op (loc, LT_EXPR, flags, op1, op0, complain);
+         r = build_conditional_expr (loc, comp, gt, uo, complain);
+       }
     }
   else
     /* op0 == op1 ? equal : op0 < op1 ? less : greater */
     r = gt;
 
   tree lt = lookup_comparison_result (tag, type, 2);
-  tree comp = build_new_op (loc, LT_EXPR, flags, op0, op1, complain);
-  r = build_conditional_expr (loc, comp, lt, r, complain);
+  if (scalar)
+    {
+      comp = fold_build2 (LT_EXPR, boolean_type_node, op0, op1);
+      r = fold_build3 (COND_EXPR, type, comp, lt, r);
+    }
+  else
+    {
+      comp = build_new_op (loc, LT_EXPR, flags, op0, op1, complain);
+      r = build_conditional_expr (loc, comp, lt, r, complain);
+    }
 
   tree eq = lookup_comparison_result (tag, type, 0);
-  comp = build_new_op (loc, EQ_EXPR, flags, op0, op1, complain);
-  r = build_conditional_expr (loc, comp, eq, r, complain);
+  if (scalar)
+    {
+      comp = fold_build2 (EQ_EXPR, boolean_type_node, op0, op1);
+      r = fold_build3 (COND_EXPR, type, comp, eq, r);
+    }
+  else
+    {
+      comp = build_new_op (loc, EQ_EXPR, flags, op0, op1, complain);
+      r = build_conditional_expr (loc, comp, eq, r, complain);
+    }
 
   return r;
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-fallback1.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-fallback1.C
new file mode 100644 (file)
index 0000000..5ce4949
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/100367
+// { dg-do compile { target c++20 } }
+
+#include <compare>
+
+struct iter {
+  bool current;
+  iter(iter &);
+};
+
+constexpr bool operator==(const iter &, const iter &y) {
+  return y.current;
+}
+
+void lexicographical_compare_three_way(iter a) {
+  (a == a) <=> true;
+}