diff options
author | Jason Merrill <jason@redhat.com> | 2021-05-18 12:29:33 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2021-05-19 15:43:07 -0400 |
commit | cd67343703ef4fa61de837f4690eba70d2760825 (patch) | |
tree | b704f95df735f0fe15d70ea5e9ff4e529b7ea5f4 /gcc | |
parent | 9b50282b0dcf79d3141979e466465a23d1816166 (diff) | |
download | gcc-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.c | 42 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/spaceship-fallback1.C | 17 |
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; +} |