From 431be04b8b6e31d950ddab340ed866d197d23d4d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 4 Nov 2022 15:22:45 -0400 Subject: c++: implement P2468R2, the equality operator you are looking for This paper is resolving the problem of well-formed C++17 code becoming ambiguous in C++20 due to asymmetrical operator== being compared with itself in reverse. I had previously implemented a tiebreaker such that if the two candidates were functions with the same parameter types, we would prefer the non-reversed candidate. But the committee went with a different approach: if there's an operator!= with the same parameter types as the operator==, don't consider the reversed form of the ==. So this patch implements that, and changes my old tiebreaker to give a pedwarn if it is used. I also noticed that we were giving duplicate errors for some testcases, and fixed the tourney logic to avoid that. As a result, a lot of tests of the form struct A { bool operator==(const A&); }; need to be fixed to add a const function-cv-qualifier, e.g. struct A { bool operator==(const A&) const; }; The committee thought such code ought to be fixed, so breaking it was fine. 18_support/comparisons/algorithms/fallback.cc also breaks with this patch, because of the similarly asymmetrical bool operator==(const S&, S&) { return true; } As a result, some of the asserts need to be reversed. The H test in spaceship-eq15.C is specified in the standard to be well-formed because the op!= in the inline namespace is not found by the search, but that seems wrong to me. I've implemented that behavior, but disabled it for now; if we decide that is the way we want to go, we can just remove the "0 &&" in add_candidates to enable it. Co-authored-by: Jakub Jelinek gcc/cp/ChangeLog: * cp-tree.h (fns_correspond): Declare. * decl.cc (fns_correspond): New. * call.cc (add_candidates): Look for op!= matching op==. (joust): Complain about non-standard reversed tiebreaker. (tourney): Fix champ_compared_to_predecessor logic. (build_new_op): Don't complain about error_mark_node not having 'bool' type. * pt.cc (tsubst_copy_and_build): Don't try to be permissive when seen_error(). gcc/testsuite/ChangeLog: * g++.dg/cpp2a/spaceship-eq15.C: New test. * g++.dg/cpp0x/defaulted3.C: Add const. * g++.dg/cpp2a/bit-cast7.C: Add const. * g++.dg/cpp2a/spaceship-rewrite1.C: Expect error. * g++.dg/cpp2a/spaceship-rewrite5.C: Expect error. * g++.old-deja/g++.jason/byval2.C: Expect error. * g++.old-deja/g++.other/overload13.C: Add const. libstdc++-v3/ChangeLog: * testsuite/18_support/comparisons/algorithms/fallback.cc: Adjust asserts. --- gcc/cp/pt.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc/cp/pt.cc') diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c3fc56a13ff..57917de321f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -20937,8 +20937,9 @@ tsubst_copy_and_build (tree t, /* In a lambda fn, we have to be careful to not introduce new this captures. Legacy code can't be using lambdas anyway, so it's ok to be - stricter. Be strict with C++20 template-id ADL too. */ - bool strict = in_lambda || template_id_p; + stricter. Be strict with C++20 template-id ADL too. + And be strict if we're already failing anyway. */ + bool strict = in_lambda || template_id_p || seen_error(); bool diag = true; if (strict) error_at (cp_expr_loc_or_input_loc (t), -- cgit v1.2.1