aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2021-05-18 12:29:33 -0400
committerJason Merrill <jason@redhat.com>2021-05-19 15:43:07 -0400
commitcd67343703ef4fa61de837f4690eba70d2760825 (patch)
treeb704f95df735f0fe15d70ea5e9ff4e529b7ea5f4 /gcc
parent9b50282b0dcf79d3141979e466465a23d1816166 (diff)
downloadgcc-cd67343703ef4fa61de837f4690eba70d2760825.zip
gcc-cd67343703ef4fa61de837f4690eba70d2760825.tar.gz
gcc-cd67343703ef4fa61de837f4690eba70d2760825.tar.bz2
c++: ICE with <=> fallback [PR100367]
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/method.c42
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/spaceship-fallback1.C17
2 files changed, 52 insertions, 7 deletions
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index f8c9456..dd74523 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -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
index 0000000..5ce4949
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-fallback1.C
@@ -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;
+}