[C++ PATCH] Implement P1946R0 - Allow defaulting comparisons by value
Jakub Jelinek
jakub@redhat.com
Mon Nov 11 08:17:00 GMT 2019
Hi!
>From https://www.reddit.com/r/cpp/comments/dtuov8/201911_belfast_iso_c_committee_trip_report/
I understood P1946R0 made it into C++20, so here is my attempt at
implementing it, you had most of it implemented anyway because
in system headers
friend constexpr bool
operator==(partial_ordering, partial_ordering) noexcept = default;
etc. has been already accepted.
Tested so far with make check-c++-all RUNTESTFLAGS=dg.exp=spaceship*
and make check-target-libstdc++-v3 RUNTESTFLAGS=conformance.exp=18_support/comparisons/common/1.cc
Ok for trunk if it passes full bootstrap/regtest?
2019-11-11 Jakub Jelinek <jakub@redhat.com>
Implement P1946R0 - Allow defaulting comparisons by value
* method.c (early_check_defaulted_comparison): Remove unused
variable i. For non-static data members always require argument
type to be const C &, for friends allow either both arguments
to be const C &, or both to be C.
* g++.dg/cpp2a/spaceship-synth1-neg.C: New test.
* g++.dg/cpp2a/spaceship-synth4.C: New test.
* g++.dg/cpp2a/spaceship-synth5.C: New test.
--- gcc/cp/method.c.jj 2019-11-07 21:21:27.097760879 +0100
+++ gcc/cp/method.c 2019-11-11 08:28:22.633822845 +0100
@@ -1098,34 +1098,39 @@ early_check_defaulted_comparison (tree f
ok = false;
}
- int i = DECL_NONSTATIC_MEMBER_FUNCTION_P (fn);
- if (i && type_memfn_quals (TREE_TYPE (fn)) != TYPE_QUAL_CONST)
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+ && type_memfn_quals (TREE_TYPE (fn)) != TYPE_QUAL_CONST)
{
error_at (loc, "defaulted %qD must be %<const%>", fn);
ok = false;
}
- tree parmnode = FUNCTION_FIRST_USER_PARMTYPE (fn);
- for (; parmnode != void_list_node; parmnode = TREE_CHAIN (parmnode))
+ tree firstparmnode = FUNCTION_FIRST_USER_PARMTYPE (fn);
+ for (tree parmnode = firstparmnode; parmnode != void_list_node;
+ parmnode = TREE_CHAIN (parmnode))
{
- ++i;
tree parmtype = TREE_VALUE (parmnode);
- diagnostic_t kind = DK_UNSPECIFIED;
- int opt = 0;
- if (same_type_p (parmtype, ctx))
- /* The draft specifies const reference, but let's also allow by-value
- unless -Wpedantic, hopefully it will be added soon. */
- kind = DK_PEDWARN,
- opt = OPT_Wpedantic;
- else if (TREE_CODE (parmtype) != REFERENCE_TYPE
- || TYPE_QUALS (TREE_TYPE (parmtype)) != TYPE_QUAL_CONST
- || !(same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (parmtype), ctx)))
- kind = DK_ERROR;
- if (kind)
- emit_diagnostic (kind, loc, opt, "defaulted %qD must have "
- "parameter type %<const %T&%>", fn, ctx);
- if (kind == DK_ERROR)
- ok = false;
+ /* a non-static const member of C having one parameter of type const C&,
+ or a friend of C having either two parameters of type const C& or two
+ parameters of type C. */
+ if ((!DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+ && !same_type_p (TREE_VALUE (firstparmnode), parmtype))
+ || ((DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+ || !same_type_p (parmtype, ctx))
+ && (TREE_CODE (parmtype) != REFERENCE_TYPE
+ || TYPE_QUALS (TREE_TYPE (parmtype)) != TYPE_QUAL_CONST
+ || !(same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (parmtype), ctx)))))
+ {
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+ error_at (loc, "defaulted %qD must have parameter type "
+ "%<const %T&%>", fn, ctx);
+ else
+ error_at (loc, "defaulted %qD must have parameter types "
+ "%<const %T&%>, %<const %T&%> or "
+ "%qT, %qT", fn, ctx, ctx, ctx, ctx);
+ ok = false;
+ break;
+ }
}
/* We still need to deduce deleted/constexpr/noexcept and maybe return. */
--- gcc/testsuite/g++.dg/cpp2a/spaceship-synth1-neg.C.jj 2019-11-11 08:23:34.040215264 +0100
+++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth1-neg.C 2019-11-11 08:32:56.206659041 +0100
@@ -0,0 +1,15 @@
+// Test with all operators explicitly defaulted.
+// { dg-do compile { target c++2a } }
+
+#include <compare>
+
+struct D
+{
+ int i;
+ auto operator<=>(D& x) const = default; // { dg-error "defaulted \[^\n\r]* must have parameter type 'const D&'" }
+ bool operator==(int x) const = default; // { dg-error "defaulted \[^\n\r]* must have parameter type 'const D&'" }
+ bool operator!=(const int& x) const = default; // { dg-error "defaulted \[^\n\r]* must have parameter type 'const D&'" }
+ friend bool operator<(int& x, D& y) = default; // { dg-error "defaulted \[^\n\r]* must have parameter types 'const D&', 'const D&' or 'D', 'D'" }
+ friend bool operator<=(const D& x, D y) = default; // { dg-error "defaulted \[^\n\r]* must have parameter types 'const D&', 'const D&' or 'D', 'D'" }
+ friend bool operator>(D x, const D& y) = default; // { dg-error "defaulted \[^\n\r]* must have parameter types 'const D&', 'const D&' or 'D', 'D'" }
+};
--- gcc/testsuite/g++.dg/cpp2a/spaceship-synth4.C.jj 2019-11-10 16:35:34.296158460 +0100
+++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth4.C 2019-11-10 16:37:05.881767368 +0100
@@ -0,0 +1,43 @@
+// Test with all operators explicitly defaulted.
+// { dg-do run { target c++2a } }
+
+#include <compare>
+
+struct D
+{
+ int i;
+ friend auto operator<=>(const D& x, const D& y) = default;
+ friend bool operator==(const D& x, const D& y) = default;
+ friend bool operator!=(const D& x, const D& y) = default;
+ friend bool operator<(const D& x, const D& y) = default;
+ friend bool operator<=(const D& x, const D& y) = default;
+ friend bool operator>(const D& x, const D& y) = default;
+ friend bool operator>=(const D& x, const D& y) = default;
+};
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+int main()
+{
+ D d{42};
+ D d2{24};
+
+ assert (is_eq (d <=> d));
+ assert (is_lteq (d <=> d));
+ assert (is_gteq (d <=> d));
+ assert (is_lt (d2 <=> d));
+ assert (is_lteq (d2 <=> d));
+ assert (is_gt (d <=> d2));
+ assert (is_gteq (d <=> d2));
+
+ assert (d == d);
+ assert (!(d2 == d));
+ assert (!(d == d2));
+ assert (d != d2);
+ assert (!(d2 != d2));
+
+ assert (d2 < d);
+ assert (d2 <= d);
+ assert (d > d2);
+ assert (d >= d2);
+}
--- gcc/testsuite/g++.dg/cpp2a/spaceship-synth5.C.jj 2019-11-10 16:41:54.673380871 +0100
+++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth5.C 2019-11-11 08:32:49.270764604 +0100
@@ -0,0 +1,43 @@
+// Test with all operators explicitly defaulted.
+// { dg-do run { target c++2a } }
+
+#include <compare>
+
+struct D
+{
+ int i;
+ friend auto operator<=>(D x, D y) = default;
+ friend bool operator==(D x, D y) = default;
+ friend bool operator!=(D x, D y) = default;
+ friend bool operator<(D x, D y) = default;
+ friend bool operator<=(D x, D y) = default;
+ friend bool operator>(D x, D y) = default;
+ friend bool operator>=(const D x, const D y) = default;
+};
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+int main()
+{
+ D d{42};
+ D d2{24};
+
+ assert (is_eq (d <=> d));
+ assert (is_lteq (d <=> d));
+ assert (is_gteq (d <=> d));
+ assert (is_lt (d2 <=> d));
+ assert (is_lteq (d2 <=> d));
+ assert (is_gt (d <=> d2));
+ assert (is_gteq (d <=> d2));
+
+ assert (d == d);
+ assert (!(d2 == d));
+ assert (!(d == d2));
+ assert (d != d2);
+ assert (!(d2 != d2));
+
+ assert (d2 < d);
+ assert (d2 <= d);
+ assert (d > d2);
+ assert (d >= d2);
+}
Jakub
More information about the Gcc-patches
mailing list