From patchwork Wed Apr 10 08:45:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 88283 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EBE573858433 for ; Wed, 10 Apr 2024 08:51:44 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 4AE233858D20 for ; Wed, 10 Apr 2024 08:50:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4AE233858D20 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4AE233858D20 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739048; cv=none; b=PWtmtwC0vZqoWHrKcsgGJf8stRx9vcjeFlqKo56CUVgu7GgBXn2l3yn0YlEHhXjvmlOs705afHT7RumH37cgRKZ32LPQbZMORGjP6okpodcQiy0AGFRoM8Jscf3yMrwRLRvHU0FPIUHECvZAC+Xuvg8Vg67nGNbq9VZ01iBvRrc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739048; c=relaxed/simple; bh=+iLIc64PsN3chMfAca1MJ+BVIVSsCndDrsm2D5S8yhA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=LMqVK46tTtTHEE0S26LXBVzHcySUjC6ISXwgClHG9PVU525hm2g7mWGKQKhfLBPqy93NtliP32QdvPSIXOz7sEDuSakDpqTpt0x0oBnqWmRBsc/qXPd0wdtBSh3JcdUF0iNPo+QD9bzq4Ffv8ILAcVkH8LF9MShNvRzjG0Ud8cw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1712739045; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=kvKlvDxajaEx2rFFN9HVbyCSpxzHd5wTvw+WgoeecNs=; b=hZPxxa2iBf18prkZIngpFMTop3EVxio8m01jfzt1hUorpmrfDt2lJo31GLF1z0P6N18ups KErinxrCHsUVqQkIQCWtRBHtfZZo+3u/QjOY5IjKeOhH121nXoucOHkSNS/0bWtu9g/XsE ifAbkPLnJldkq/YS1cAqhfJsYLSVgn0= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-33-hYYdZQeMPpioIrEvWDHGQA-1; Wed, 10 Apr 2024 04:50:44 -0400 X-MC-Unique: hYYdZQeMPpioIrEvWDHGQA-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 39AC0890520; Wed, 10 Apr 2024 08:50:44 +0000 (UTC) Received: from localhost (unknown [10.42.28.163]) by smtp.corp.redhat.com (Postfix) with ESMTP id 09EDA1C060A6; Wed, 10 Apr 2024 08:50:43 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 1/4] libstdc++: Heterogeneous std::pair comparisons [PR113386] Date: Wed, 10 Apr 2024 09:45:53 +0100 Message-ID: <20240410085039.267589-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Tested x86_64-linux. Since this only affects C++20 and later it seems OK for trunk now. -- >8 -- I'm only treating this as a DR for C++20 for now, because it's less work and only requires changes to operator== and operator<=>. To do this for older standards would require changes to the six relational operators used pre-C++20. libstdc++-v3/ChangeLog: PR libstdc++/113386 * include/bits/stl_pair.h (operator==, operator<=>): Support heterogeneous comparisons, as per LWG 3865. * testsuite/20_util/pair/comparison_operators/lwg3865.cc: New test. --- libstdc++-v3/include/bits/stl_pair.h | 32 ++++++++++++++----- .../pair/comparison_operators/lwg3865.cc | 15 +++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/pair/comparison_operators/lwg3865.cc diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 4f5c8389fa6..45317417c9c 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -1000,23 +1000,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template pair(_T1, _T2) -> pair<_T1, _T2>; #endif - /// Two pairs of the same type are equal iff their members are equal. - template +#if __cpp_lib_three_way_comparison && __cpp_lib_concepts + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3865. Sorting a range of pairs + + /// Two pairs are equal iff their members are equal. + template inline _GLIBCXX_CONSTEXPR bool - operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + operator==(const pair<_T1, _T2>& __x, const pair<_U1, _U2>& __y) { return __x.first == __y.first && __x.second == __y.second; } -#if __cpp_lib_three_way_comparison && __cpp_lib_concepts - template - constexpr common_comparison_category_t<__detail::__synth3way_t<_T1>, - __detail::__synth3way_t<_T2>> - operator<=>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + /** Defines a lexicographical order for pairs. + * + * For two pairs of comparable types, `P` is ordered before `Q` if + * `P.first` is less than `Q.first`, or if `P.first` and `Q.first` + * are equivalent (neither is less than the other) and `P.second` is + * less than `Q.second`. + */ + template + constexpr common_comparison_category_t<__detail::__synth3way_t<_T1, _U1>, + __detail::__synth3way_t<_T2, _U2>> + operator<=>(const pair<_T1, _T2>& __x, const pair<_U1, _U2>& __y) { if (auto __c = __detail::__synth3way(__x.first, __y.first); __c != 0) return __c; return __detail::__synth3way(__x.second, __y.second); } #else + /// Two pairs of the same type are equal iff their members are equal. + template + inline _GLIBCXX_CONSTEXPR bool + operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { return __x.first == __y.first && __x.second == __y.second; } + /** Defines a lexicographical order for pairs. * * For two pairs of the same type, `P` is ordered before `Q` if diff --git a/libstdc++-v3/testsuite/20_util/pair/comparison_operators/lwg3865.cc b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/lwg3865.cc new file mode 100644 index 00000000000..2bbd54af192 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/lwg3865.cc @@ -0,0 +1,15 @@ +// { dg-do run { target c++20 } } + +// LWG 3865. Sorting a range of pairs + +#include +#include + +int main() +{ + std::pair p(1, 2); + std::pair p2(p.first, p.second); + VERIFY( p == p2 ); + VERIFY( p <= p2 ); + VERIFY( p >= p2 ); +} From patchwork Wed Apr 10 08:45:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 88284 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 07CFB3858289 for ; Wed, 10 Apr 2024 08:51:55 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 0EED03858C32 for ; Wed, 10 Apr 2024 08:50:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0EED03858C32 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0EED03858C32 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739053; cv=none; b=mM9E9F15bfG0OWtiY+LPWerY3QfYBTcjN5jfB48f65aIWC/QcXT7txgsT+SY/9lIuY74gPfb1RTutHaSgIQcBCrFwOLLz3cy0jgMVNwyGV3uZRBTYOws5AkG+ROKOuxMSVFzAEC2eeKed9tKO/buaY9A3zN9IeuJ5E6Q5TyII4w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739053; c=relaxed/simple; bh=+pr+1zeJb/wng0j1AtKsSqg/7QoJsuxNxuB0sOTaFbU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=nR2Yns0xUMhb8MZ2kc2xTYWIGchV6XfE8XxruL8OVxdU+TNEThYo0mAXG38ymNL+z4PEYH7gnJKGGpK7BsB8G8CSOhihwV6VAVqR7VyI9sk66y4jm4hZJCf/2lTjHn0aewDUyMlSf/HH+4t+lp/bizuKY25Ph0x1J19JIvg5UXk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1712739050; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ptTJ8TYFf8S8nHiNtE6JNU7+tD5c82lHIoB96MYdFmk=; b=S//Zz5zTbWlAsC+9ni46aLmVLdo628Nvs1Y5XZkbCxoiX6ad8rffl0g0xEQ5RSIt6Yln3U WBuyawR++fiQILvUlHQXEPhR+8gGSedNcX/a0LG/FijZn0rGz3ZD+0O9CVeCazTrCEUVMD DIM4+DEZ12sv7qDtpN/V5deRDTLYT2w= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-657-NswFvJEiODC7IvxK-L58bQ-1; Wed, 10 Apr 2024 04:50:49 -0400 X-MC-Unique: NswFvJEiODC7IvxK-L58bQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EE4EF29ABA04; Wed, 10 Apr 2024 08:50:48 +0000 (UTC) Received: from localhost (unknown [10.42.28.163]) by smtp.corp.redhat.com (Postfix) with ESMTP id BD98C1C06667; Wed, 10 Apr 2024 08:50:48 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 2/4] libstdc++: Add std::reference_wrapper comparison operators for C++26 Date: Wed, 10 Apr 2024 09:45:54 +0100 Message-ID: <20240410085039.267589-2-jwakely@redhat.com> In-Reply-To: <20240410085039.267589-1-jwakely@redhat.com> References: <20240410085039.267589-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Tested x86_64-linux. Since this only affects C++26 it seems OK for trunk now. -- >8 -- This C++26 change was just approved in Tokyo, in P2944R3. It adds operator== and operator<=> overloads to std::reference_wrapper. The operator<=> overloads in the paper cause compilation errors for any type without <=> so they're implemented here with deduced return types and constrained by a requires clause. libstdc++-v3/ChangeLog: * include/bits/refwrap.h (reference_wrapper): Add comparison operators as proposed by P2944R3. * include/bits/version.def (reference_wrapper): Define. * include/bits/version.h: Regenerate. * include/std/functional: Enable feature test macro. * testsuite/20_util/reference_wrapper/compare.cc: New test. --- libstdc++-v3/include/bits/refwrap.h | 45 +++++++++ libstdc++-v3/include/bits/version.def | 8 ++ libstdc++-v3/include/bits/version.h | 10 ++ libstdc++-v3/include/std/functional | 1 + .../20_util/reference_wrapper/compare.cc | 95 +++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc diff --git a/libstdc++-v3/include/bits/refwrap.h b/libstdc++-v3/include/bits/refwrap.h index 2d4338b718f..fd1cc2b63e6 100644 --- a/libstdc++-v3/include/bits/refwrap.h +++ b/libstdc++-v3/include/bits/refwrap.h @@ -38,6 +38,10 @@ #include #include // for unary_function and binary_function +#if __glibcxx_reference_wrapper >= 202403L // >= C++26 +# include +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -358,6 +362,47 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type) #endif return std::__invoke(get(), std::forward<_Args>(__args)...); } + +#if __glibcxx_reference_wrapper >= 202403L // >= C++26 + // [refwrap.comparisons], comparisons + [[nodiscard]] + friend constexpr bool + operator==(reference_wrapper __x, reference_wrapper __y) + requires requires { { __x.get() == __y.get() } -> convertible_to; } + { return __x.get() == __y.get(); } + + [[nodiscard]] + friend constexpr bool + operator==(reference_wrapper __x, const _Tp& __y) + requires requires { { __x.get() == __y } -> convertible_to; } + { return __x.get() == __y; } + + [[nodiscard]] + friend constexpr bool + operator==(reference_wrapper __x, reference_wrapper __y) + requires (!is_const_v<_Tp>) + && requires { { __x.get() == __y.get() } -> convertible_to; } + { return __x.get() == __y.get(); } + + [[nodiscard]] + friend constexpr auto + operator<=>(reference_wrapper __x, reference_wrapper<_Tp> __y) + requires requires { __detail::__synth3way(__x.get(), __y.get()); } + { return __detail::__synth3way(__x.get(), __y.get()); } + + [[nodiscard]] + friend constexpr auto + operator<=>(reference_wrapper __x, const _Tp& __y) + requires requires { __detail::__synth3way(__x.get(), __y); } + { return __detail::__synth3way(__x.get(), __y); } + + [[nodiscard]] + friend constexpr auto + operator<=>(reference_wrapper __x, reference_wrapper __y) + requires (!is_const_v<_Tp>) + && requires { __detail::__synth3way(__x.get(), __y.get()); } + { return __detail::__synth3way(__x.get(), __y.get()); } +#endif }; #if __cpp_deduction_guides diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 5ad44941bff..5c0477fb61e 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1760,6 +1760,14 @@ ftms = { }; }; +ftms = { + name = reference_wrapper; + values = { + v = 202403; + cxxmin = 26; + }; +}; + ftms = { name = saturation_arithmetic; values = { diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 460a3e0116a..65e708c73fb 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1963,6 +1963,16 @@ #endif /* !defined(__cpp_lib_ratio) && defined(__glibcxx_want_ratio) */ #undef __glibcxx_want_ratio +#if !defined(__cpp_lib_reference_wrapper) +# if (__cplusplus > 202302L) +# define __glibcxx_reference_wrapper 202403L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_reference_wrapper) +# define __cpp_lib_reference_wrapper 202403L +# endif +# endif +#endif /* !defined(__cpp_lib_reference_wrapper) && defined(__glibcxx_want_reference_wrapper) */ +#undef __glibcxx_want_reference_wrapper + #if !defined(__cpp_lib_saturation_arithmetic) # if (__cplusplus > 202302L) # define __glibcxx_saturation_arithmetic 202311L diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 766558b3ce0..99364286a72 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -83,6 +83,7 @@ #define __glibcxx_want_move_only_function #define __glibcxx_want_not_fn #define __glibcxx_want_ranges +#define __glibcxx_want_reference_wrapper #define __glibcxx_want_transparent_operators #include diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc new file mode 100644 index 00000000000..039c9d26496 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc @@ -0,0 +1,95 @@ +// { dg-do compile { target c++26 } } + + +#include + +#ifndef __cpp_lib_reference_wrapper +# error "Feature-test macro for reference_wrapper missing" +#elif __cpp_lib_reference_wrapper != 202403 +# error "Feature-test macro for reference_wrapper has wrong value" +#endif + +// P2944R3 Comparisons for reference_wrapper + +auto check(int i, std::reference_wrapper r) -> bool { + return i == r; +} + +template using Ref = std::reference_wrapper; + +template +concept ref_equality_comparable += requires (T a, T const ca, Ref r, Ref cr) { + // the usual T is equality-comparable with itself + a == a; + a == ca; + ca == ca; + + // Ref is equality-comparable with itself + r == r; + r == cr; + cr == cr; + + // T and Ref are equality-comparable + a == r; + a == cr; + ca == r; + ca == cr; +}; + +static_assert( ref_equality_comparable ); + +struct A { + auto operator==(A const&) const -> bool { return true; } +}; + +struct B { + friend auto operator==(B const&, B const&) -> bool { return true; } +}; + +template +struct C { + friend auto operator==(C const&, C const&) -> bool { return true; } +}; + +template +struct D { }; +template +auto operator==(D const&, D const&) -> bool { return true; } + +static_assert(ref_equality_comparable); +static_assert(ref_equality_comparable); +static_assert(ref_equality_comparable); +static_assert(ref_equality_comparable>); +static_assert(ref_equality_comparable>); +#include +static_assert(ref_equality_comparable); + +template +struct ValArray { + friend auto operator==(ValArray const&, ValArray const&) -> ValArray { + return {}; + } +}; + +void f(ValArray v) { + // this is valid and has type ValArray + v == v; + + // this is also valid today and has the same type + std::ref(v) == std::ref(v); +} + +struct ComparesAsInt { + friend auto operator==(ComparesAsInt, ComparesAsInt) -> int; +}; + +auto f(std::reference_wrapper a, + std::reference_wrapper b) { + // today: compiles and returns int + // proposed: compiles and returns bool + return a == b; +} + +ComparesAsInt& c(); +static_assert( std::is_same_v ); From patchwork Wed Apr 10 08:45:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 88286 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D5A5C3858401 for ; Wed, 10 Apr 2024 08:54:32 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id B383A3858431 for ; Wed, 10 Apr 2024 08:50:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B383A3858431 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B383A3858431 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739074; cv=none; b=Xw+Lx5stl5E05hHSccMh2zSImEXvkx8J+NY7daV+HnPq348HQoXpyIQIovwBe54mrGdjLuvPAlP+Iywc6shzk/0JuGwv1PBhY8CPfBg04g7PZctZgJoG/dmtnf5/oLkxsAFmrvc3IlU2AA/mlG6NYTdEC4UkziSqU/pfQJXDmSs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739074; c=relaxed/simple; bh=oBvMMyRRVJ/H4XnsIm+gFT5tZAA+NdbrzNBJtEdmYOI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Snz4XMH+6+cSXny3zyWqFT+3G8AVBlMEadB7hlq2OeKZYTeiOTWkiadL2gl4BL9uvoU2aB5m6U0un6CGuqbCKJEzedagaNbwSgCOQUy5nGF50k/80KnXya/NCtbKXZs08yIurr6bC+U+TBpcb/e5DiEb1CCHBUFoORQu/wvhbaA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1712739056; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bRK0nxGZ+fNse58AebqMWkjQ3ab8tqt1PUX4sxD/K84=; b=T/kbtuOooJUwWEg7ATjRXSc4zLzjB1xOh/WAyokCioLyjSotwXkMD/7SO0Uqk6xDtXXLH0 9Ta1G/snxDcJ+uznc+a1DmMRv7b+DgSEgekTyl7JQpgHdSwOrVzrvAPeuz7EsxXqYC8aXR 1h85+wXYbEzNpYANaQ6bDWkgHHiAxBk= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-679-o0GG1y8MMZyfPLF6nBGBYQ-1; Wed, 10 Apr 2024 04:50:54 -0400 X-MC-Unique: o0GG1y8MMZyfPLF6nBGBYQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 15E2F29ABA0D; Wed, 10 Apr 2024 08:50:54 +0000 (UTC) Received: from localhost (unknown [10.42.28.163]) by smtp.corp.redhat.com (Postfix) with ESMTP id 971E61C060A6; Wed, 10 Apr 2024 08:50:53 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 3/4] libstdc++: Constrain equality ops for std::pair, std::tuple, std::variant Date: Wed, 10 Apr 2024 09:45:55 +0100 Message-ID: <20240410085039.267589-3-jwakely@redhat.com> In-Reply-To: <20240410085039.267589-1-jwakely@redhat.com> References: <20240410085039.267589-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Tested x86_64-linux. Since this only affects C++20 and later (except for adding [[nodiscard]] to relational ops) it seems OK for trunk now. -- >8 -- Implement the changes from P2944R3 which add constraints to the comparison operators of std::pair, std::tuple, and std::variant. The paper also changes std::optional, but we already constrain its comparisons using SFINAE on the return type. However, we need some additional constraints on the [optional.comp.with.t] operators that compare an optional with a value. The paper doesn't say to do that, but I think it's needed because otherwise when the comparison for two optional objects fails its constraints, the two overloads that are supposed to be for comparing to a non-optional become the best overload candidates, but are ambiguous (and we don't even get as far as checking the constraints for satisfaction). The paper does not change std::expected, but probably should have done. I'll submit an LWG issue about that and implement it separately. Also add [[nodiscard]] to all these comparison operators. libstdc++-v3/ChangeLog: * include/bits/stl_pair.h (operator==): Add constraint. * include/bits/version.def (constrained_equality): Define. * include/bits/version.h: Regenerate. * include/std/optional: Define feature test macro. (__optional_rep_op_t): Use is_convertible_v instead of is_convertible. * include/std/tuple: Define feature test macro. (operator==, __tuple_cmp, operator<=>): Reimplement C++20 comparisons using lambdas. Add constraints. * include/std/utility: Define feature test macro. * include/std/variant: Define feature test macro. (_VARIANT_RELATION_FUNCTION_TEMPLATE): Add constraints. (variant): Remove unnecessary friend declarations for comparison operators. * testsuite/20_util/optional/relops/constrained.cc: New test. * testsuite/20_util/pair/comparison_operators/constrained.cc: New test. * testsuite/20_util/tuple/comparison_operators/constrained.cc: New test. * testsuite/20_util/variant/relops/constrained.cc: New test. * testsuite/20_util/tuple/comparison_operators/overloaded.cc: Disable for C++20 and later. * testsuite/20_util/tuple/comparison_operators/overloaded2.cc: Remove dg-error line for target c++20. --- libstdc++-v3/include/bits/stl_pair.h | 16 +- libstdc++-v3/include/bits/version.def | 9 + libstdc++-v3/include/bits/version.h | 10 + libstdc++-v3/include/std/optional | 48 +++- libstdc++-v3/include/std/tuple | 102 ++++--- libstdc++-v3/include/std/utility | 1 + libstdc++-v3/include/std/variant | 28 +- .../20_util/optional/relops/constrained.cc | 258 ++++++++++++++++++ .../pair/comparison_operators/constrained.cc | 48 ++++ .../tuple/comparison_operators/constrained.cc | 50 ++++ .../tuple/comparison_operators/overloaded.cc | 6 +- .../tuple/comparison_operators/overloaded2.cc | 1 - .../20_util/variant/relops/constrained.cc | 175 ++++++++++++ 13 files changed, 677 insertions(+), 75 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc create mode 100644 libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc create mode 100644 libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc create mode 100644 libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 45317417c9c..0c1e5719a1a 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -1000,14 +1000,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template pair(_T1, _T2) -> pair<_T1, _T2>; #endif -#if __cpp_lib_three_way_comparison && __cpp_lib_concepts +#if __cpp_lib_three_way_comparison // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3865. Sorting a range of pairs /// Two pairs are equal iff their members are equal. template - inline _GLIBCXX_CONSTEXPR bool + [[nodiscard]] + constexpr bool operator==(const pair<_T1, _T2>& __x, const pair<_U1, _U2>& __y) + requires requires { + { __x.first == __y.first } -> __detail::__boolean_testable; + { __x.second == __y.second } -> __detail::__boolean_testable; + } { return __x.first == __y.first && __x.second == __y.second; } /** Defines a lexicographical order for pairs. @@ -1018,6 +1023,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * less than `Q.second`. */ template + [[nodiscard]] constexpr common_comparison_category_t<__detail::__synth3way_t<_T1, _U1>, __detail::__synth3way_t<_T2, _U2>> operator<=>(const pair<_T1, _T2>& __x, const pair<_U1, _U2>& __y) @@ -1029,6 +1035,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #else /// Two pairs of the same type are equal iff their members are equal. template + _GLIBCXX_NODISCARD inline _GLIBCXX_CONSTEXPR bool operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return __x.first == __y.first && __x.second == __y.second; } @@ -1041,6 +1048,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * than `Q.second`. */ template + _GLIBCXX_NODISCARD inline _GLIBCXX_CONSTEXPR bool operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return __x.first < __y.first @@ -1048,24 +1056,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Uses @c operator== to find the result. template + _GLIBCXX_NODISCARD inline _GLIBCXX_CONSTEXPR bool operator!=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return !(__x == __y); } /// Uses @c operator< to find the result. template + _GLIBCXX_NODISCARD inline _GLIBCXX_CONSTEXPR bool operator>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return __y < __x; } /// Uses @c operator< to find the result. template + _GLIBCXX_NODISCARD inline _GLIBCXX_CONSTEXPR bool operator<=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return !(__y < __x); } /// Uses @c operator< to find the result. template + _GLIBCXX_NODISCARD inline _GLIBCXX_CONSTEXPR bool operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return !(__x < __y); } diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 5c0477fb61e..f0ba4f2bb3d 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1237,6 +1237,15 @@ ftms = { }; }; +ftms = { + name = constrained_equality; + values = { + v = 202403; + cxxmin = 20; + extra_cond = "__glibcxx_three_way_comparison"; + }; +}; + ftms = { name = erase_if; values = { diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 65e708c73fb..f30f51dcedc 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1373,6 +1373,16 @@ #endif /* !defined(__cpp_lib_constexpr_vector) && defined(__glibcxx_want_constexpr_vector) */ #undef __glibcxx_want_constexpr_vector +#if !defined(__cpp_lib_constrained_equality) +# if (__cplusplus >= 202002L) && (__glibcxx_three_way_comparison) +# define __glibcxx_constrained_equality 202403L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constrained_equality) +# define __cpp_lib_constrained_equality 202403L +# endif +# endif +#endif /* !defined(__cpp_lib_constrained_equality) && defined(__glibcxx_want_constrained_equality) */ +#undef __glibcxx_want_constrained_equality + #if !defined(__cpp_lib_erase_if) # if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED # define __glibcxx_erase_if 202002L diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 3507c36a4d8..e245e76e7a0 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -34,6 +34,7 @@ #define __glibcxx_want_freestanding_optional #define __glibcxx_want_optional +#define __glibcxx_want_constrained_equality #include #ifdef __cpp_lib_optional // C++ >= 17 @@ -1194,7 +1195,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using __optional_relop_t = - enable_if_t::value, bool>; + enable_if_t, bool>; template using __optional_eq_t = __optional_relop_t< @@ -1279,6 +1280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef __cpp_lib_three_way_comparison template _Up> + [[nodiscard]] constexpr compare_three_way_result_t<_Tp, _Up> operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) { @@ -1288,12 +1290,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Comparisons with nullopt. template + [[nodiscard]] constexpr bool operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } #ifdef __cpp_lib_three_way_comparison template + [[nodiscard]] constexpr strong_ordering operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept { return bool(__x) <=> false; } @@ -1354,76 +1358,94 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return !__rhs; } #endif // three-way-comparison +#if __cpp_lib_concepts +# define _REQUIRES_NOT_OPTIONAL(T) requires (!__is_optional_v) +#else +# define _REQUIRES_NOT_OPTIONAL(T) +#endif + // Comparisons with value type. template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator==(const optional<_Tp>& __lhs, const _Up& __rhs) + operator== [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_eq_t<_Tp, _Up> { return __lhs && *__lhs == __rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator==(const _Up& __lhs, const optional<_Tp>& __rhs) -> __optional_eq_t<_Up, _Tp> { return __rhs && __lhs == *__rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator!= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_ne_t<_Tp, _Up> { return !__lhs || *__lhs != __rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator!= [[nodiscard]] (const _Up& __lhs, const optional<_Tp>& __rhs) -> __optional_ne_t<_Up, _Tp> { return !__rhs || __lhs != *__rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator<(const optional<_Tp>& __lhs, const _Up& __rhs) + operator< [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_lt_t<_Tp, _Up> { return !__lhs || *__lhs < __rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator<(const _Up& __lhs, const optional<_Tp>& __rhs) + operator< [[nodiscard]] (const _Up& __lhs, const optional<_Tp>& __rhs) -> __optional_lt_t<_Up, _Tp> { return __rhs && __lhs < *__rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator>(const optional<_Tp>& __lhs, const _Up& __rhs) + operator> [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_gt_t<_Tp, _Up> { return __lhs && *__lhs > __rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator>(const _Up& __lhs, const optional<_Tp>& __rhs) + operator> [[nodiscard]] (const _Up& __lhs, const optional<_Tp>& __rhs) -> __optional_gt_t<_Up, _Tp> { return !__rhs || __lhs > *__rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator<= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_le_t<_Tp, _Up> { return !__lhs || *__lhs <= __rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator<= [[nodiscard]] (const _Up& __lhs, const optional<_Tp>& __rhs) -> __optional_le_t<_Up, _Tp> { return __rhs && __lhs <= *__rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator>= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_ge_t<_Tp, _Up> { return __lhs && *__lhs >= __rhs; } template + _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto - operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator>= [[nodiscard]] (const _Up& __lhs, const optional<_Tp>& __rhs) -> __optional_ge_t<_Up, _Tp> { return !__rhs || __lhs >= *__rhs; } @@ -1432,7 +1454,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION requires (!__is_optional_v<_Up>) && three_way_comparable_with<_Up, _Tp> constexpr compare_three_way_result_t<_Tp, _Up> - operator<=>(const optional<_Tp>& __x, const _Up& __v) + operator<=> [[nodiscard]] (const optional<_Tp>& __x, const _Up& __v) { return bool(__x) ? *__x <=> __v : strong_ordering::less; } #endif diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 3065058e184..df3f6e38eeb 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -51,6 +51,7 @@ #define __glibcxx_want_make_from_tuple #define __glibcxx_want_ranges_zip #define __glibcxx_want_tuple_like +#define __glibcxx_want_constrained_equality #include namespace std _GLIBCXX_VISIBILITY(default) @@ -250,17 +251,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cpp_lib_tuple_like // >= C++23 struct __tuple_like_tag_t { explicit __tuple_like_tag_t() = default; }; - // These forward declarations are used by the operator<=> overload for + // This forward declaration is used by the operator<=> overload for // tuple-like types. - template + template constexpr _Cat - __tuple_cmp(const _Tp&, const _Up&, index_sequence<>); - - template - constexpr _Cat - __tuple_cmp(const _Tp& __t, const _Up& __u, - index_sequence<_Idx0, _Idxs...>); + __tuple_cmp(const _Tp& __t, const _Up& __u, _IndexSeq); #endif // C++23 /** @@ -1848,7 +1843,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<__tuple_like _UTuple> requires (!__is_tuple_v<_UTuple>) friend constexpr bool - operator==(const tuple& __t, const _UTuple& __u) + operator== [[nodiscard]] (const tuple& __t, const _UTuple& __u) { static_assert(sizeof...(_Elements) == tuple_size_v<_UTuple>, "tuple objects can only be compared if they have equal sizes."); @@ -2521,6 +2516,58 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif +#if __cpp_lib_three_way_comparison + template + requires (sizeof...(_Tps) == sizeof...(_Ups)) + && (requires (const _Tps& __t, const _Ups& __u) { + { __t == __u } -> __detail::__boolean_testable; + } && ...) + constexpr bool + operator== [[nodiscard]] (const tuple<_Tps...>& __t, + const tuple<_Ups...>& __u) + { + return [&](index_sequence<_Inds...>) { + // Fold == over the tuples until non-equal elements are found. + return ((std::get<_Inds>(__t) == std::get<_Inds>(__u)) && ...); + }(index_sequence_for<_Tps...>{}); + } + + template + [[nodiscard]] + constexpr _Cat + __tuple_cmp(const _Tp& __t, const _Up& __u, _IndexSeq __indices) + { + _Cat __c = _Cat::equivalent; + + // Set __c to the comparison result of two corresponding elements. + // Return true they are equivalent. + auto __cmp = [&](integral_constant) { + __c = __detail::__synth3way(std::get<_Ind>(__t), std::get<_Ind>(__u)); + return __c == 0; + }; + + [&](index_sequence<_Inds...>) { + // Fold __cmp over the tuples until non-equivalent elements are found. + (void)(__cmp(integral_constant{}) && ...); + }(__indices); + + return __c; + } + + template + requires (sizeof...(_Tps) == sizeof...(_Ups)) + && (requires { typename __detail::__synth3way_t<_Tps, _Ups>; } && ...) + constexpr + common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...> + operator<=> [[nodiscard]] (const tuple<_Tps...>& __t, + const tuple<_Ups...>& __u) + { + using _Cat + = common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>; + return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Tps...>()); + } +#else + // This class performs the comparison operations on tuples template struct __tuple_compare @@ -2552,6 +2599,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template + _GLIBCXX_NODISCARD constexpr bool operator==(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u) @@ -2564,36 +2612,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __compare::__eq(__t, __u); } -#if __cpp_lib_three_way_comparison - template - constexpr _Cat - __tuple_cmp(const _Tp&, const _Up&, index_sequence<>) - { return _Cat::equivalent; } - - template - constexpr _Cat - __tuple_cmp(const _Tp& __t, const _Up& __u, - index_sequence<_Idx0, _Idxs...>) - { - auto __c - = __detail::__synth3way(std::get<_Idx0>(__t), std::get<_Idx0>(__u)); - if (__c != 0) - return __c; - return std::__tuple_cmp<_Cat>(__t, __u, index_sequence<_Idxs...>()); - } - - template - constexpr - common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...> - operator<=>(const tuple<_Tps...>& __t, const tuple<_Ups...>& __u) - { - using _Cat - = common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>; - return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Tps...>()); - } -#else template + _GLIBCXX_NODISCARD constexpr bool operator<(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u) @@ -2607,24 +2627,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template + _GLIBCXX_NODISCARD constexpr bool operator!=(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u) { return !(__t == __u); } template + _GLIBCXX_NODISCARD constexpr bool operator>(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u) { return __u < __t; } template + _GLIBCXX_NODISCARD constexpr bool operator<=(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u) { return !(__u < __t); } template + _GLIBCXX_NODISCARD constexpr bool operator>=(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u) diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index 212513f6f48..56467160a2f 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -93,6 +93,7 @@ #define __glibcxx_want_tuples_by_type #define __glibcxx_want_unreachable #define __glibcxx_want_tuple_like +#define __glibcxx_want_constrained_equality #include namespace std _GLIBCXX_VISIBILITY(default) diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index f79d95db7a8..5ba6d9d42e3 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -33,6 +33,7 @@ #define __glibcxx_want_freestanding_variant #define __glibcxx_want_variant +#define __glibcxx_want_constrained_equality #include #ifdef __cpp_lib_variant // C++ >= 17 @@ -1236,9 +1237,19 @@ namespace __variant struct monostate { }; +#if __cpp_lib_concepts +# define _VARIANT_RELATION_FUNCTION_CONSTRAINTS(TYPES, OP) \ + requires ((requires (const TYPES& __t) { \ + { __t OP __t } -> __detail::__boolean_testable; }) && ...) +#else +# define _VARIANT_RELATION_FUNCTION_CONSTRAINTS(TYPES, OP) +#endif + #define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP, __NAME) \ template \ - constexpr bool operator __OP(const variant<_Types...>& __lhs, \ + _VARIANT_RELATION_FUNCTION_CONSTRAINTS(_Types, __OP) \ + constexpr bool \ + operator __OP [[nodiscard]] (const variant<_Types...>& __lhs, \ const variant<_Types...>& __rhs) \ { \ bool __ret = true; \ @@ -1690,21 +1701,6 @@ namespace __variant template friend constexpr decltype(auto) __detail::__variant::__get(_Vp&& __v) noexcept; - -#define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP) \ - template \ - friend constexpr bool \ - operator __OP(const variant<_Tp...>& __lhs, \ - const variant<_Tp...>& __rhs); - - _VARIANT_RELATION_FUNCTION_TEMPLATE(<) - _VARIANT_RELATION_FUNCTION_TEMPLATE(<=) - _VARIANT_RELATION_FUNCTION_TEMPLATE(==) - _VARIANT_RELATION_FUNCTION_TEMPLATE(!=) - _VARIANT_RELATION_FUNCTION_TEMPLATE(>=) - _VARIANT_RELATION_FUNCTION_TEMPLATE(>) - -#undef _VARIANT_RELATION_FUNCTION_TEMPLATE }; template diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc new file mode 100644 index 00000000000..0e325618008 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc @@ -0,0 +1,258 @@ +// { dg-do compile { target c++20 } } + +#include + +#ifndef __cpp_lib_constrained_equality +# error "Feature-test macro for constrained_equality missing" +#elif __cpp_lib_constrained_equality != 202403 +# error "Feature-test macro for constrained_equality has wrong value" +#endif + +template +concept eq_comparable += requires (const std::optional& t, const std::optional& u) { + t == u; + *t == u; + t == *u; +}; + +template +concept ne_comparable += requires (const std::optional& t, const std::optional& u) { + t != u; + *t != u; + t != *u; +}; + +template +concept lt_comparable += requires (const std::optional& t, const std::optional& u) { + t < u; + *t < u; + t < *u; +}; + +template +concept le_comparable += requires (const std::optional& t, const std::optional& u) { + t <= u; + *t <= u; + t <= *u; +}; + +template +concept gt_comparable += requires (const std::optional& t, const std::optional& u) { + t > u; + *t > u; + t > *u; +}; + +template +concept ge_comparable += requires (const std::optional& t, const std::optional& u) { + t >= u; + *t >= u; + t >= *u; +}; + +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); + +struct A { }; +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct B { }; +void operator==(B, B); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct C { }; +bool operator==(C, C); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); + +struct D { }; +int operator==(D, D); +bool operator!=(D, D) = delete; +static_assert( eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( eq_comparable ); +static_assert( ! ne_comparable ); + +struct E { }; +bool operator==(/* not-const */ E&, const E&); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); + +struct F { }; +bool operator<(F, F); +void operator>(F, F); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( lt_comparable ); +static_assert( lt_comparable ); + +struct G { }; +bool operator<=(G, G); +void operator<(G, G); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( le_comparable ); +static_assert( le_comparable ); + +struct H { }; +bool operator>(H, H); +void operator>=(H, H); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( gt_comparable ); +static_assert( gt_comparable ); + +struct I { }; +bool operator>=(I, I); +void operator<=(I, I); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ge_comparable ); +static_assert( ge_comparable ); +static_assert( ge_comparable ); + +struct J { }; +bool operator==(J, J); +std::weak_ordering operator<=>(J, J); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); + +struct K { }; +int operator==(K, K); // non-bool prevents synthesis of != +void operator<=(K, K); +std::weak_ordering operator<=>(K, K); +static_assert( eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( lt_comparable ); +static_assert( ! le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); + +bool operator==(A, B); +static_assert( eq_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +int operator==(C, D); // non-bool prevents synthesis of != and reversed args +static_assert( eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +std::weak_ordering operator<=>(E, F); +static_assert( ! eq_comparable ); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); diff --git a/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc new file mode 100644 index 00000000000..a35dbd265a7 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc @@ -0,0 +1,48 @@ +// { dg-do compile { target c++20 } } + +#include + +#ifndef __cpp_lib_constrained_equality +# error "Feature-test macro for constrained_equality missing" +#elif __cpp_lib_constrained_equality != 202403 +# error "Feature-test macro for constrained_equality has wrong value" +#endif + +template +concept equality_comparable = requires (const T& t) { t == t; t != t; }; + +static_assert( equality_comparable> ); + +struct A { }; +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct B { }; +void operator==(B, B); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct C { }; +int operator==(C, C); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct D { }; +bool operator==(D, D); +bool operator!=(D, D) = delete; +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct E { }; +bool operator==(/* not-const */ E&, const E&); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); diff --git a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc new file mode 100644 index 00000000000..47035ab18ba --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc @@ -0,0 +1,50 @@ +// { dg-do compile { target c++20 } } + +#include + +#ifndef __cpp_lib_constrained_equality +# error "Feature-test macro for constrained_equality missing" +#elif __cpp_lib_constrained_equality != 202403 +# error "Feature-test macro for constrained_equality has wrong value" +#endif + +template +concept equality_comparable = requires (const T& t) { t == t; t != t; }; + +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); + +struct A { }; +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct B { }; +void operator==(B, B); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct C { }; +int operator==(C, C); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct D { }; +bool operator==(D, D); +bool operator!=(D, D) = delete; +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( equality_comparable> ); +static_assert( ! equality_comparable> ); + +struct E { }; +bool operator==(/* not-const */ E&, const E&); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); +static_assert( ! equality_comparable> ); diff --git a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded.cc b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded.cc index 9f8a0f91785..7ae7f42d1a1 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded.cc @@ -1,4 +1,5 @@ -// { dg-do compile { target c++11 } } +// { dg-do compile { target { c++11 && c++17_down } } } +// Not valid in C++20, because TwistedLogic doesn't model boolean-testable. // Copyright (C) 2014-2024 Free Software Foundation, Inc. // @@ -49,8 +50,5 @@ TwistedLogic operator<(const Compares&, const Compares&) { return {false}; } auto a = std::make_tuple(nullptr, Compares{}, 2, 'U'); auto b = a == a; -#if ! __cpp_lib_three_way_comparison -// Not valid in C++20, because TwistedLogic doesn't model boolean-testable. auto c = std::make_tuple("", Compares{}, 2, 'U'); auto d = c < c; -#endif diff --git a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded2.cc b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded2.cc index 19617a5676e..8ea7ed0b797 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded2.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/overloaded2.cc @@ -50,5 +50,4 @@ auto a = std::make_tuple(nullptr, Compares{}, 2, 'U'); auto b = a < a; // { dg-error "no match for 'operator<'" "" { target c++20 } 0 } -// { dg-error "no match for .*_Synth3way|in requirements" "" { target c++20 } 0 } // { dg-error "ordered comparison" "" { target c++17_down } 0 } diff --git a/libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc b/libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc new file mode 100644 index 00000000000..95e8f754d1e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc @@ -0,0 +1,175 @@ +// { dg-do compile { target c++20 } } + +#include + +#ifndef __cpp_lib_constrained_equality +# error "Feature-test macro for constrained_equality missing" +#elif __cpp_lib_constrained_equality != 202403 +# error "Feature-test macro for constrained_equality has wrong value" +#endif + +template +concept eq_comparable += requires (const std::variant& t) { t == t; }; + +template +concept ne_comparable += requires (const std::variant& t) { t != t; }; + +template +concept lt_comparable += requires (const std::variant& t) { t < t; }; + +template +concept le_comparable += requires (const std::variant& t) { t <= t; }; + +template +concept gt_comparable += requires (const std::variant& t) { t > t; }; + +template +concept ge_comparable += requires (const std::variant& t) { t >= t; }; + +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); + +struct A { }; +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct B { }; +void operator==(B, B); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct C { }; +bool operator==(C, C); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( ne_comparable ); + +struct D { }; +int operator==(D, D); // variant's operator== returns bool despite int here +bool operator!=(D, D) = delete; +static_assert( eq_comparable ); +static_assert( ne_comparable ); // variant's operator== can be used +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct E { }; +bool operator==(/* not-const */ E&, const E&); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct F { }; +bool operator<(F, F); +void operator>(F, F); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct G { }; +bool operator<=(G, G); +void operator<(G, G); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ! ge_comparable ); + +struct H { }; +bool operator>(H, H); +void operator>=(H, H); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( gt_comparable ); +static_assert( ! ge_comparable ); +static_assert( gt_comparable ); +static_assert( gt_comparable ); + +struct I { }; +bool operator>=(I, I); +void operator<=(I, I); +static_assert( ! eq_comparable ); +static_assert( ! ne_comparable ); +static_assert( ! lt_comparable ); +static_assert( ! le_comparable ); +static_assert( ! gt_comparable ); +static_assert( ge_comparable ); +static_assert( ge_comparable ); +static_assert( ge_comparable ); + +struct J { }; +bool operator==(J, J); +std::weak_ordering operator<=>(J, J); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); + +struct K { }; +int operator==(K, K); // variant's operator== returns bool despite int here +void operator<=(K, K); +std::weak_ordering operator<=>(K, K); +static_assert( eq_comparable ); +static_assert( ne_comparable ); // variant's operator== can be used +static_assert( lt_comparable ); +static_assert( ! le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); +static_assert( eq_comparable ); +static_assert( ne_comparable ); +static_assert( lt_comparable ); +static_assert( ! le_comparable ); +static_assert( gt_comparable ); +static_assert( ge_comparable ); From patchwork Wed Apr 10 08:45:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 88285 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C9E9E3858404 for ; Wed, 10 Apr 2024 08:53:16 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 62A1C3858C52 for ; Wed, 10 Apr 2024 08:51:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 62A1C3858C52 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 62A1C3858C52 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739070; cv=none; b=o2jIUD6BLF8CJICB7ZLD5+uk8b2tMHToKhHfLwYW0VQY+zDIn3UVAddERPnR+HkdwkCxO9MHzCKmDspqIKAnQa3rj/EVYEMi2ij2n5VzIa5UC48zZ2tshrpeVHxUDd+VDgDQcf+BPm10LgFm0d5SErfa5hV3DY5pB17GSsbPlJY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712739070; c=relaxed/simple; bh=xV234a6HscIIqDJE+fcg0Pd8xep3cCFWIFiFnPOVLYs=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=bxwJLThC+Z5H1KlDYs3vuy9AsdZhxRbERfyh7CCxJmpbaT2d/cX24W0dcUelS+/gh7dlc1AYlkl9qtxtCzQu7o7G/KAVI6TUKQXLRNvcP9oLYyKZYlk4ilkKp/Gl3IY6qEMRJBxETvbDK3Us3mFT8LKLuoeJLWg/o2gGFbinsXA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1712739062; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=foUj9RN20P8rQCQXZP5pJlCTCtkc6lxVc0GwHOQzeTI=; b=i1Bv2paWe15uFp9ZYjnu40nWw2R+2hsWo2s15U+guUtXvEuhfGON0yx7qX3C8XKAYQwaEQ go/ucNVgyPAqJI9wwyQvedlp9NlshaICT118ylvKK6SuBwV9hEfnjt1kFpsINUfPbkj7L5 Z4PUAjROdYRdRWG8ewB0n7+tdwod2wI= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-56-ZRvSY48CMtGBI9iAcm89hQ-1; Wed, 10 Apr 2024 04:50:59 -0400 X-MC-Unique: ZRvSY48CMtGBI9iAcm89hQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E63CE3800096; Wed, 10 Apr 2024 08:50:58 +0000 (UTC) Received: from localhost (unknown [10.42.28.163]) by smtp.corp.redhat.com (Postfix) with ESMTP id B62C31C060A6; Wed, 10 Apr 2024 08:50:58 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 4/4] libstdc++: Simplify std::variant comparison operators Date: Wed, 10 Apr 2024 09:45:56 +0100 Message-ID: <20240410085039.267589-4-jwakely@redhat.com> In-Reply-To: <20240410085039.267589-1-jwakely@redhat.com> References: <20240410085039.267589-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Tested x86_64-linux. This is just a minor clean-up and could wait for stage 1. -- >8 -- libstdc++-v3/ChangeLog: * include/std/variant (_VARIANT_RELATION_FUNCTION_TEMPLATE): Simplify. --- libstdc++-v3/include/std/variant | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 5ba6d9d42e3..2be0f0c1db7 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -1245,7 +1245,7 @@ namespace __variant # define _VARIANT_RELATION_FUNCTION_CONSTRAINTS(TYPES, OP) #endif -#define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP, __NAME) \ +#define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP) \ template \ _VARIANT_RELATION_FUNCTION_CONSTRAINTS(_Types, __OP) \ constexpr bool \ @@ -1262,22 +1262,20 @@ namespace __variant { \ auto& __this_mem = std::get<__rhs_index>(__lhs); \ __ret = __this_mem __OP __rhs_mem; \ + return; \ } \ - else \ - __ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \ } \ - else \ - __ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \ + __ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \ }, __rhs); \ return __ret; \ } - _VARIANT_RELATION_FUNCTION_TEMPLATE(<, less) - _VARIANT_RELATION_FUNCTION_TEMPLATE(<=, less_equal) - _VARIANT_RELATION_FUNCTION_TEMPLATE(==, equal) - _VARIANT_RELATION_FUNCTION_TEMPLATE(!=, not_equal) - _VARIANT_RELATION_FUNCTION_TEMPLATE(>=, greater_equal) - _VARIANT_RELATION_FUNCTION_TEMPLATE(>, greater) + _VARIANT_RELATION_FUNCTION_TEMPLATE(<) + _VARIANT_RELATION_FUNCTION_TEMPLATE(<=) + _VARIANT_RELATION_FUNCTION_TEMPLATE(==) + _VARIANT_RELATION_FUNCTION_TEMPLATE(!=) + _VARIANT_RELATION_FUNCTION_TEMPLATE(>=) + _VARIANT_RELATION_FUNCTION_TEMPLATE(>) #undef _VARIANT_RELATION_FUNCTION_TEMPLATE