From patchwork Tue Jan 23 23:53:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1889937 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=FC8uo+T2; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4TKP8r59CHz1yS7 for ; Wed, 24 Jan 2024 10:55:08 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B6F273857828 for ; Tue, 23 Jan 2024 23:55:06 +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 8F2A93858C52 for ; Tue, 23 Jan 2024 23:53:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8F2A93858C52 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 8F2A93858C52 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=1706053998; cv=none; b=oUILCBbJAvoAupzm1avmC3TQWT4DWKxb/OFIgB4SeIpHTs2bbC/cWum7VvH8gPMWJSDxUIVPqzjaf3lkDut/G6Wr4iyKsnDOCUA/WmpGj24lsEbYgM0uYDVE3rSdKUBOZG9Cxx52/BI7frjmWbKaNlptMYOSdforMzBFlm9efkw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706053998; c=relaxed/simple; bh=iZTJzNIdEDRVI3oUJZhpYlWw13XOF4VzWXvpDFAC9b4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=TYj9D2IpX7G/9Mk1XAnAzDiD1CUZygqznR/sVZbg/DQo/Hgj+a2I/FirrFAt7pRsC7GhE4QCPgqh+pKSLWqv5nIp40fkFyWi5HazTpAk6QGH7qUg68spOmbkvE/Th10L9F9GcI0DTewx71BoBEoaCj+8jbm0ZmH9t9ZOVDXo+38= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1706053992; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0CjbtBYNQ8YriyaLL+imCRd8un6tEUwLp+6q2vkNQK0=; b=FC8uo+T21C6lmrTWP07iEkE5LM6y22KSt2MVdCfFjOpaB45LYP75IvLTxD4qhiKQ3FWORG 51iv97x/tnXlbtFojiWI94EWq0OQuqux3I33FoO/9rysiR6dqLZDS02XIv9bLl0BVtl9iY g2XNO7IGJaiCfwy2OskXA5k1QAGfMU4= Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-279-xUCaws-aOyO8eSXndXFY3A-1; Tue, 23 Jan 2024 18:53:10 -0500 X-MC-Unique: xUCaws-aOyO8eSXndXFY3A-1 Received: by mail-qv1-f71.google.com with SMTP id 6a1803df08f44-6818c26db2cso67790916d6.2 for ; Tue, 23 Jan 2024 15:53:10 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706053990; x=1706658790; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0CjbtBYNQ8YriyaLL+imCRd8un6tEUwLp+6q2vkNQK0=; b=EYvQSvoa39ABdPfCV/u9YQARoTDl7HOp77Xqv1syB4LP6uDQHJNZWNL4bX9TGSy/E8 AoBuZY5jqQPYtxL5fXkZ32k0cmhQNfCJi3XfQqS8RBvy2pRLWiUEVv0MgCcSZrEdYj4N LOYxaSrVMAKqFde9FLG7PI+EeongBoKh4g7VGifqZqxgiH/IcQOGhiXrDAVI12RmB7mM t26Ofggs0xxoE5NBxlpL8a/NM7OQvaDTl9DzfQN4jJHtnx1uK8MRaZbqtu1JUMHA9DUJ 3vMFc3kc3WD6x+pJt48hiAxMz+zyXVMnFqUsnhffkQI8JFZJVQCkpqHRqKL7HSxBG8bE 3uCw== X-Gm-Message-State: AOJu0YySOuSjlRncBz+ZabiaA/PfTD43s4BsWczcX7fVwBPfR/dp50gI sqJYN3fQ6liaCmGxVqgShO7cU0Z3bp7U0j1ehHUgkMwETPZxUTADjFv2o6euRALF2OsS+EuYkjR S4tjhkki/uPfoiUN+N1tV/nrITduVlSLTZWLM+ckTIxR6XCiiA5jX2prhZmQjZskIuOwfzEZZa/ FeYJjdGXd2yGCND5S1whbgtX8v9qpTf69Pcujn X-Received: by 2002:a05:6214:f23:b0:686:aa78:df45 with SMTP id iw3-20020a0562140f2300b00686aa78df45mr1088859qvb.51.1706053988980; Tue, 23 Jan 2024 15:53:08 -0800 (PST) X-Google-Smtp-Source: AGHT+IE9gG7xYezHBgDkaapgL1Sdi0FffoctMx+r6xQS0KT54RgEQmiU5R78Kj4VbagvDLXixkfD9w== X-Received: by 2002:a05:6214:f23:b0:686:aa78:df45 with SMTP id iw3-20020a0562140f2300b00686aa78df45mr1088838qvb.51.1706053987991; Tue, 23 Jan 2024 15:53:07 -0800 (PST) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id j7-20020a0ceb07000000b00681092cb7b4sm3888576qvp.103.2024.01.23.15.53.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jan 2024 15:53:06 -0800 (PST) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, Patrick Palka Subject: [PATCH 2/2] libstdc++: Implement P2165R4 changes to std::pair/tuple/etc Date: Tue, 23 Jan 2024 18:53:03 -0500 Message-ID: <20240123235303.1540890-2-ppalka@redhat.com> X-Mailer: git-send-email 2.43.0.386.ge02ecfcc53 In-Reply-To: <20240123235303.1540890-1-ppalka@redhat.com> References: <20240123235303.1540890-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.5 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, RCVD_IN_SORBS_WEB, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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+incoming=patchwork.ozlabs.org@gcc.gnu.org Tested on x86_64-pc-linux-gnu, does this look OK for trunK? -- >8 -- This implements the C++23 paper P2165R4 Compatibility between tuple, pair and tuple-like objects, which builds upon many changes from the earlier C++23 paper P2321R2 zip. Some declarations had to be moved around so that they're visible from without introducing new includes. In the end, the only new include is for from , for tuple_element_t. libstdc++-v3/ChangeLog: * include/bits/ranges_util.h (__detail::__pair_like): Don't define in C++23 mode. (__detail::__pair_like_convertible_from): Adjust as per P2165R4. (__detail::__is_subrange): Moved from . (__detail::__is_tuple_like_v): Likewise. * include/bits/stl_iterator.h: Include for C++23. (__different_from): Move to . (__iter_key_t): Adjust for C++23 as per P2165R4. (__iter_val_t): Likewise. * include/bits/stl_pair.h (pair, array): Forward declare. (get): Forward declare all overloads relevant to P2165R4 tuple-like constructors. (__is_tuple_v): Define for C++23. (__is_tuple_like_v): Define for C++23. (__tuple_like): Define for C++23 as per P2165R4. (__pair_like): Define for C++23 as per P2165R4. (__eligibile_tuple_like): Define for C++23. (__eligibile_pair_like): Define for C++23. (pair::_S_constructible_from_pair_like): Define for C++23. (pair::_S_convertible_from_pair_like): Define for C++23. (pair::pair): Define overload taking a tuple-like type for C++23 as per P2165R4. (pair::_S_assignable_from_tuple_like): Define for C++23. (pair::_S_const_assignable_from_tuple_like): Define for C++23. (pair::operator=): Define overloads taking a tuple-like type for C++23 as per P2165R4. * include/bits/utility.h (ranges::__detail::__is_subrange): Moved from . * include/bits/version.def (tuple_like): Define for C++23. * include/bits/version.h: Regenerate. * include/std/concepts (__different_from): Moved from . (ranges::__swap::__adl_swap): Clarify which __detail namespace. * include/std/map (__cpp_lib_tuple_like): Define C++23. * include/std/ranges (__detail::__is_subrange): Moved to . (__detail::__is_subrange): Moved to (__detail::__has_tuple_element): Adjust for C++23 as per P2165R4. (__detail::__tuple_or_pair): Remove as per P2165R4. Replace all uses with plain tuple as per P2165R4. * include/std/tuple (__cpp_lib_tuple_like): Define for C++23. (__tuple_like_tag_t): Define for C++23. (__tuple_cmp): Forward declare for C++23. (_Tuple_impl::_Tuple_impl): Define overloads taking __tuple_like_tag_t and a tuple-like type for C++23. (_Tuple_impl::_M_assign): Likewise. (tuple::__constructible_from_tuple_like): Define for C++23. (tuple::__convertible_from_tuple_like): Define for C++23. (tuple::tuple): Define overloads taking a tuple-like type for C++23 as per P2165R4. (tuple::__assignable_from_tuple_like): Define for C++23. (tuple::__const_assignable_from_tuple_like): Define for C++23. (tuple::operator=): Define overloads taking a tuple-like type for C++23 as per P2165R4. (tuple::__tuple_like_common_comparison_category): Define for C++23. (tuple::operator<=>): Define overload taking a tuple-like type for C++23 as per P2165R4. (array, get): Forward declarations moved to . (tuple_cat): Constrain with __tuple_like for C++23 as per P2165R4. (apply): Likewise. (make_from_tuple): Likewise. (__tuple_like_common_reference): Define for C++23. (basic_common_reference): Adjust as per P2165R4. (__tuple_like_common_type): Define for C++23. (common_type): Adjust as per P2165R4. * include/std/unordered_map (__cpp_lib_tuple_like): Define for C++23. * include/std/utility (__cpp_lib_tuple_like): Define for C++23. * testsuite/std/ranges/zip/1.cc (test01): Adjust to handle pair and 2-tuple interchangeably. * testsuite/20_util/pair/p2165r4.cc: New test. * testsuite/20_util/tuple/p2165r4.cc: New test. --- libstdc++-v3/include/bits/ranges_util.h | 17 +- libstdc++-v3/include/bits/stl_iterator.h | 16 +- libstdc++-v3/include/bits/stl_pair.h | 167 +++++++++ libstdc++-v3/include/bits/utility.h | 8 + libstdc++-v3/include/bits/version.def | 8 + libstdc++-v3/include/bits/version.h | 11 + libstdc++-v3/include/std/concepts | 11 +- libstdc++-v3/include/std/map | 1 + libstdc++-v3/include/std/ranges | 48 +-- libstdc++-v3/include/std/tuple | 299 +++++++++++++--- libstdc++-v3/include/std/unordered_map | 1 + libstdc++-v3/include/std/utility | 1 + .../testsuite/20_util/pair/p2165r4.cc | 169 ++++++++++ .../testsuite/20_util/tuple/p2165r4.cc | 319 ++++++++++++++++++ libstdc++-v3/testsuite/std/ranges/zip/1.cc | 4 +- 15 files changed, 997 insertions(+), 83 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/pair/p2165r4.cc create mode 100644 libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index bb04c49f044..9b79c3a229d 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -224,6 +224,10 @@ namespace ranges && !__uses_nonqualification_pointer_conversion, decay_t<_To>>; +#if __glibcxx_tuple_like // >= C++23 + // P2165R4 version of __pair_like is defined in . +#else + // C++20 version of __pair_like from P2321R2. template concept __pair_like = !is_reference_v<_Tp> && requires(_Tp __t) @@ -235,10 +239,11 @@ namespace ranges { get<0>(__t) } -> convertible_to&>; { get<1>(__t) } -> convertible_to&>; }; +#endif template concept __pair_like_convertible_from - = !range<_Tp> && __pair_like<_Tp> + = !range<_Tp> && !is_reference_v<_Vp> && __pair_like<_Tp> && constructible_from<_Tp, _Up, _Vp> && __convertible_to_non_slicing<_Up, tuple_element_t<0, _Tp>> && convertible_to<_Vp, tuple_element_t<1, _Tp>>; @@ -463,8 +468,18 @@ namespace ranges using borrowed_subrange_t = __conditional_t, subrange>, dangling>; + + // __is_subrange is defined in . + template + inline constexpr bool __detail::__is_subrange> = true; } // namespace ranges +#if __glibcxx_tuple_like // >= C++23 + // __is_tuple_like_v is defined in . + template + inline constexpr bool __is_tuple_like_v> = true; +#endif + // The following ranges algorithms are used by , and are defined here // so that can avoid including all of . namespace ranges diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index d71a793e10d..560a10a7abe 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -78,6 +78,10 @@ # include #endif +#if __glibcxx_tuple_like // >= C++23 +# include // for tuple_element_t +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -95,10 +99,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using __clamp_iter_cat = __conditional_t, _Limit, _Otherwise>; - - template - concept __different_from - = !same_as, remove_cvref_t<_Up>>; } #endif @@ -2983,11 +2983,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // of associative containers. template using __iter_key_t = remove_const_t< +#if __glibcxx_tuple_like // >= C++23 + tuple_element_t<0, typename iterator_traits<_InputIterator>::value_type>>; +#else typename iterator_traits<_InputIterator>::value_type::first_type>; +#endif template using __iter_val_t +#if __glibcxx_tuple_like // >= C++23 + = tuple_element_t<1, typename iterator_traits<_InputIterator>::value_type>; +#else = typename iterator_traits<_InputIterator>::value_type::second_type; +#endif template struct pair; diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index b81b479ad43..a9b20fbe7ca 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -85,12 +85,70 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @cond undocumented // Forward declarations. + template + struct pair; + template class tuple; + // Declarations of std::array and its std::get overloads, so that + // std::tuple_cat can use them if is included before . + // We also declare the other std::get overloads here so that they're + // visible to the P2165R4 tuple-like constructors of pair and tuple. + template + struct array; + template struct _Index_tuple; + template + constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type& + get(pair<_Tp1, _Tp2>& __in) noexcept; + + template + constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&& + get(pair<_Tp1, _Tp2>&& __in) noexcept; + + template + constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type& + get(const pair<_Tp1, _Tp2>& __in) noexcept; + + template + constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&& + get(const pair<_Tp1, _Tp2>&& __in) noexcept; + + template + constexpr __tuple_element_t<__i, tuple<_Elements...>>& + get(tuple<_Elements...>& __t) noexcept; + + template + constexpr const __tuple_element_t<__i, tuple<_Elements...>>& + get(const tuple<_Elements...>& __t) noexcept; + + template + constexpr __tuple_element_t<__i, tuple<_Elements...>>&& + get(tuple<_Elements...>&& __t) noexcept; + + template + constexpr const __tuple_element_t<__i, tuple<_Elements...>>&& + get(const tuple<_Elements...>&& __t) noexcept; + + template + constexpr _Tp& + get(array<_Tp, _Nm>&) noexcept; + + template + constexpr _Tp&& + get(array<_Tp, _Nm>&&) noexcept; + + template + constexpr const _Tp& + get(const array<_Tp, _Nm>&) noexcept; + + template + constexpr const _Tp&& + get(const array<_Tp, _Nm>&&) noexcept; + #if ! __cpp_lib_concepts // Concept utility functions, reused in conditionally-explicit // constructors. @@ -159,6 +217,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // lib concepts #endif // C++11 +#if __glibcxx_tuple_like // >= C++23 + template + inline constexpr bool __is_tuple_v = false; + + template + inline constexpr bool __is_tuple_v> = true; + + // TODO: Reuse __is_tuple_like from ? + template + inline constexpr bool __is_tuple_like_v = false; + + template + inline constexpr bool __is_tuple_like_v> = true; + + template + inline constexpr bool __is_tuple_like_v> = true; + + template + inline constexpr bool __is_tuple_like_v> = true; + + // __is_tuple_like_v is defined in . + + template + concept __tuple_like = __is_tuple_like_v>; + + template + concept __pair_like = __tuple_like<_Tp> && tuple_size_v> == 2; + + template + concept __eligible_tuple_like + = __detail::__different_from<_Tp, _Tuple> && __tuple_like<_Tp> + && (tuple_size_v> == tuple_size_v<_Tuple>) + && !ranges::__detail::__is_subrange>; + + template + concept __eligible_pair_like + = __detail::__different_from<_Tp, _Pair> && __pair_like<_Tp> + && !ranges::__detail::__is_subrange>; +#endif // C++23 + template class __pair_base { #if __cplusplus >= 201103L && ! __cpp_lib_concepts @@ -295,6 +393,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return false; #endif } + +#if __glibcxx_tuple_like // >= C++23 + template + static constexpr bool + _S_constructible_from_pair_like() + { + return _S_constructible(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } + + template + static constexpr bool + _S_convertible_from_pair_like() + { + return _S_convertible(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } +#endif // C++23 /// @endcond public: @@ -393,6 +509,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION pair(const pair<_U1, _U2>&&) = delete; #endif // C++23 +#if __glibcxx_tuple_like // >= C++23 + template<__eligible_pair_like _UPair> + requires (_S_constructible_from_pair_like<_UPair>()) + constexpr explicit(!_S_convertible_from_pair_like<_UPair>()) + pair(_UPair&& __p) + : first(std::get<0>(std::forward<_UPair>(__p))), + second(std::get<1>(std::forward<_UPair>(__p))) + { } +#endif // C++23 + private: /// @cond undocumented template @@ -421,6 +547,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return is_nothrow_assignable_v<_T2&, _U2>; return false; } + +#if __glibcxx_tuple_like // >= C++23 + template + static constexpr bool + _S_assignable_from_tuple_like() + { + return _S_assignable(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } + + template + static constexpr bool + _S_const_assignable_from_tuple_like() + { + return _S_const_assignable(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } +#endif // C++23 /// @endcond public: @@ -516,6 +660,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } #endif // C++23 + +#if __glibcxx_tuple_like // >= C++23 + template<__eligible_pair_like _UPair> + requires (_S_assignable_from_tuple_like<_UPair>()) + constexpr pair& + operator=(_UPair&& __p) + { + first = std::get<0>(std::forward<_UPair>(__p)); + second = std::get<1>(std::forward<_UPair>(__p)); + return *this; + } + + template<__eligible_pair_like _UPair> + requires (_S_const_assignable_from_tuple_like<_UPair>()) + constexpr const pair& + operator=(_UPair&& __p) const + { + first = std::get<0>(std::forward<_UPair>(__p)); + second = std::get<1>(std::forward<_UPair>(__p)); + return *this; + } +#endif // C++23 + #else // !__cpp_lib_concepts // C++11/14/17 implementation using enable_if, partially constexpr. diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h index d8a5fb960fe..2a741bf7000 100644 --- a/libstdc++-v3/include/bits/utility.h +++ b/libstdc++-v3/include/bits/utility.h @@ -266,6 +266,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #endif +#if __glibcxx_ranges + namespace ranges::__detail + { + template + inline constexpr bool __is_subrange = false; + } // namespace __detail +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 8fb8a2877ee..502961eb269 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1780,6 +1780,14 @@ ftms = { }; }; +ftms = { + name = tuple_like; + values = { + v = 202207; + cxxmin = 23; + }; +}; + // Standard test specifications. stds[97] = ">= 199711L"; stds[03] = ">= 199711L"; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 9ba99deeda6..511030bde47 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2169,4 +2169,15 @@ #endif /* !defined(__cpp_lib_generator) && defined(__glibcxx_want_generator) */ #undef __glibcxx_want_generator +// from version.def line 1774 +#if !defined(__cpp_lib_tuple_like) +# if (__cplusplus >= 202100L) +# define __glibcxx_tuple_like 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_tuple_like) +# define __cpp_lib_tuple_like 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_tuple_like) && defined(__glibcxx_want_tuple_like) */ +#undef __glibcxx_want_tuple_like + #undef __glibcxx_want_all diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts index 66ed3714b25..4f3e059b051 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -62,6 +62,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION concept same_as = __detail::__same_as<_Tp, _Up> && __detail::__same_as<_Up, _Tp>; + namespace __detail + { + template + concept __different_from + = !same_as, remove_cvref_t<_Up>>; + } // namespace __detail + /// [concept.derived], concept derived_from template concept derived_from = __is_base_of(_Base, _Derived) @@ -185,8 +192,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template concept __adl_swap - = (__detail::__class_or_enum> - || __detail::__class_or_enum>) + = (std::__detail::__class_or_enum> + || std::__detail::__class_or_enum>) && requires(_Tp&& __t, _Up&& __u) { swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }; diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map index dcfd222d173..4a96e59a5bc 100644 --- a/libstdc++-v3/include/std/map +++ b/libstdc++-v3/include/std/map @@ -74,6 +74,7 @@ #define __glibcxx_want_map_try_emplace #define __glibcxx_want_node_extract #define __glibcxx_want_nonmember_container_access +#define __glibcxx_want_tuple_like #include #if __cplusplus >= 201703L diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index f2413badd9c..7d739852677 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -2389,11 +2389,7 @@ namespace views::__adaptor inline constexpr bool __is_basic_string_view> = true; - template - inline constexpr bool __is_subrange = false; - - template - inline constexpr bool __is_subrange> = true; + using ranges::__detail::__is_subrange; template inline constexpr bool __is_iota_view = false; @@ -4166,6 +4162,10 @@ namespace views::__adaptor namespace __detail { +#if __cpp_lib_tuple_like // >= C++23 + template + concept __has_tuple_element = __tuple_like<_Tp> && _Nm < tuple_size_v<_Tp>; +#else template concept __has_tuple_element = requires(_Tp __t) { @@ -4175,6 +4175,7 @@ namespace views::__adaptor { std::get<_Nm>(__t) } -> convertible_to&>; }; +#endif template concept __returnable_element @@ -4559,23 +4560,12 @@ namespace views::__adaptor || (!(bidirectional_range<_Rs> && ...) && (common_range<_Rs> && ...)) || ((random_access_range<_Rs> && ...) && (sized_range<_Rs> && ...)); - template - struct __tuple_or_pair - { using type = std::tuple<_Ts...>; }; - - template - struct __tuple_or_pair<_Tp, _Up> - { using type = pair<_Tp, _Up>; }; - - template - using __tuple_or_pair_t = typename __tuple_or_pair<_Ts...>::type; - template constexpr auto __tuple_transform(_Fp&& __f, _Tuple&& __tuple) { return std::apply([&](_Ts&&... __elts) { - return __tuple_or_pair_t...> + return tuple...> (std::__invoke(__f, std::forward<_Ts>(__elts))...); }, std::forward<_Tuple>(__tuple)); } @@ -4696,7 +4686,7 @@ namespace views::__adaptor #ifdef __clang__ // LLVM-61763 workaround public: #endif - __detail::__tuple_or_pair_t>...> _M_current; + tuple>...> _M_current; constexpr explicit _Iterator(decltype(_M_current) __current) @@ -4728,7 +4718,7 @@ namespace views::__adaptor // iterator_category defined in __zip_view_iter_cat using iterator_concept = decltype(_S_iter_concept()); using value_type - = __detail::__tuple_or_pair_t>...>; + = tuple>...>; using difference_type = common_type_t>...>; @@ -4900,7 +4890,7 @@ namespace views::__adaptor template class zip_view<_Vs...>::_Sentinel { - __detail::__tuple_or_pair_t>...> _M_end; + tuple>...> _M_end; constexpr explicit _Sentinel(decltype(_M_end) __end) @@ -8325,8 +8315,7 @@ namespace views::__adaptor && __detail::__cartesian_product_is_common<_First, _Vs...>) { auto __its = [this](index_sequence<_Is...>) { - using _Ret = __detail::__tuple_or_pair_t, - iterator_t<_Vs>...>; + using _Ret = tuple, iterator_t<_Vs>...>; bool __empty_tail = (ranges::empty(std::get<1 + _Is>(_M_bases)) || ...); auto& __first = std::get<0>(_M_bases); return _Ret{(__empty_tail @@ -8342,8 +8331,7 @@ namespace views::__adaptor end() const requires __detail::__cartesian_product_is_common { auto __its = [this](index_sequence<_Is...>) { - using _Ret = __detail::__tuple_or_pair_t, - iterator_t...>; + using _Ret = tuple, iterator_t...>; bool __empty_tail = (ranges::empty(std::get<1 + _Is>(_M_bases)) || ...); auto& __first = std::get<0>(_M_bases); return _Ret{(__empty_tail @@ -8416,8 +8404,8 @@ namespace views::__adaptor { using _Parent = __maybe_const_t<_Const, cartesian_product_view>; _Parent* _M_parent = nullptr; - __detail::__tuple_or_pair_t>, - iterator_t<__maybe_const_t<_Const, _Vs>>...> _M_current; + tuple>, + iterator_t<__maybe_const_t<_Const, _Vs>>...> _M_current; constexpr _Iterator(_Parent& __parent, decltype(_M_current) __current) @@ -8444,11 +8432,11 @@ namespace views::__adaptor using iterator_category = input_iterator_tag; using iterator_concept = decltype(_S_iter_concept()); using value_type - = __detail::__tuple_or_pair_t>, - range_value_t<__maybe_const_t<_Const, _Vs>>...>; + = tuple>, + range_value_t<__maybe_const_t<_Const, _Vs>>...>; using reference - = __detail::__tuple_or_pair_t>, - range_reference_t<__maybe_const_t<_Const, _Vs>>...>; + = tuple>, + range_reference_t<__maybe_const_t<_Const, _Vs>>...>; using difference_type = decltype(cartesian_product_view::_S_difference_type()); _Iterator() = default; diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index be92f1eb973..182f3cc5e6a 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -50,6 +50,7 @@ #define __glibcxx_want_apply #define __glibcxx_want_make_from_tuple #define __glibcxx_want_ranges_zip +#define __glibcxx_want_tuple_like #include namespace std _GLIBCXX_VISIBILITY(default) @@ -246,6 +247,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Head _M_head_impl; }; +#if __cpp_lib_tuple_like // >= C++23 + struct __tuple_like_tag_t { explicit __tuple_like_tag_t() = default; }; + + // Forward declared for use by the operator<=> overload for tuple-like types. + 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...>); +#endif // C++23 + /** * Contains the actual implementation of the @c tuple template, stored * as a recursive inheritance hierarchy from the first element (most @@ -342,6 +358,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template + constexpr + _Tuple_impl(__tuple_like_tag_t, _UTuple&& __u, index_sequence<_Is...>) + : _Tuple_impl(std::get<_Is>(std::forward<_UTuple>(__u))...) + { } +#endif // C++23 + template _GLIBCXX20_CONSTEXPR _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) @@ -428,6 +452,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template + constexpr + _Tuple_impl(__tuple_like_tag_t, allocator_arg_t __tag, const _Alloc& __a, + _UTuple&& __u, index_sequence<_Is...>) + : _Tuple_impl(__tag, __a, std::get<_Is>(std::forward<_UTuple>(__u))...) + { } +#endif // C++23 + template _GLIBCXX20_CONSTEXPR void @@ -470,6 +503,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template + constexpr void + _M_assign(__tuple_like_tag_t __tag, _UTuple&& __u) + { + _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); + _M_tail(*this)._M_assign(__tag, std::forward<_UTuple>(__u)); + } + + template + constexpr void + _M_assign(__tuple_like_tag_t __tag, _UTuple&& __u) const + { + _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); + _M_tail(*this)._M_assign(__tag, std::forward<_UTuple>(__u)); + } +#endif // C++23 + protected: _GLIBCXX20_CONSTEXPR void @@ -563,6 +614,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template + constexpr + _Tuple_impl(__tuple_like_tag_t, _UTuple&& __u, index_sequence<0>) + : _Tuple_impl(std::get<0>(std::forward<_UTuple>(__u))) + { } +#endif // C++23 + template _GLIBCXX20_CONSTEXPR _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) @@ -633,6 +692,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template + constexpr + _Tuple_impl(__tuple_like_tag_t, allocator_arg_t __tag, const _Alloc& __a, + _UTuple&& __u, index_sequence<0>) + : _Tuple_impl(__tag, __a, std::get<0>(std::forward<_UTuple>(__u))) + { } +#endif // C++23 + template _GLIBCXX20_CONSTEXPR void @@ -667,6 +735,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template + constexpr void + _M_assign(__tuple_like_tag_t, _UTuple&& __u) + { _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); } + + template + constexpr void + _M_assign(__tuple_like_tag_t, _UTuple&& __u) const + { _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); } +#endif // C++23 + protected: _GLIBCXX20_CONSTEXPR void @@ -846,6 +926,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif } +#if __cpp_lib_tuple_like // >= C++23 + template + static consteval bool + __constructible_from_tuple_like() + { + return [](index_sequence<_Is...>) { + return __constructible(std::declval<_UTuple>()))...>(); + }(make_index_sequence{}); + } + + template + static consteval bool + __convertible_from_tuple_like() + { + return [](index_sequence<_Is...>) { + return __convertible(std::declval<_UTuple>()))...>(); + }(make_index_sequence{}); + } +#endif // C++23 + public: constexpr explicit(!(__is_implicitly_default_constructible_v<_Elements> && ...)) @@ -1016,10 +1116,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(const pair<_U1, _U2>&&) = delete; #endif // C++23 -#if 0 && __cpp_lib_tuple_like // >= C++23 - template<__tuple_like _UTuple> - constexpr explicit(...) - tuple(_UTuple&& __u); +#if __cpp_lib_tuple_like // >= C++23 + template<__eligible_tuple_like _UTuple> + requires (__constructible_from_tuple_like<_UTuple>()) + && (!__use_other_ctor<_UTuple>()) + constexpr explicit(!__convertible_from_tuple_like<_UTuple>()) + tuple(_UTuple&& __u) + : _Inherited(__tuple_like_tag_t{}, + std::forward<_UTuple>(__u), + make_index_sequence{}) + { } #endif // C++23 // Allocator-extended constructors. @@ -1202,10 +1308,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(allocator_arg_t, const _Alloc&, const pair<_U1, _U2>&&) = delete; #endif // C++23 -#if 0 && __cpp_lib_tuple_like // >= C++23 - template - constexpr explicit(...) - tuple(allocator_arg_t __tag, const _Alloc& __a, _UTuple&& __u); +#if __cpp_lib_tuple_like // >= C++23 + template _UTuple> + requires (__constructible_from_tuple_like<_UTuple>()) + && (!__use_other_ctor<_UTuple>()) + constexpr explicit(!__convertible_from_tuple_like<_UTuple>()) + tuple(allocator_arg_t __tag, const _Alloc& __a, _UTuple&& __u) + : _Inherited(__tuple_like_tag_t{}, + __tag, __a, std::forward<_UTuple>(__u), + make_index_sequence{}) + { } #endif // C++23 #else // !(concepts && conditional_explicit) @@ -1539,6 +1651,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template + static consteval bool + __assignable_from_tuple_like() + { + return [](index_sequence<_Is...>) { + return __assignable(std::declval<_UTuple>()))...>(); + }(make_index_sequence{}); + } + + template + static consteval bool + __const_assignable_from_tuple_like() + { + return [](index_sequence<_Is...>) { + return __const_assignable(std::declval<_UTuple>()))...>(); + }(make_index_sequence{}); + } +#endif // C++23 + public: tuple& operator=(const tuple& __u) = delete; @@ -1661,14 +1793,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 -#if 0 && __cpp_lib_tuple_like // >= C++23 - template<__tuple_like _UTuple> +#if __cpp_lib_tuple_like // >= C++23 + template<__eligible_tuple_like _UTuple> + requires (__assignable_from_tuple_like<_UTuple>()) constexpr tuple& - operator=(_UTuple&& __u); + operator=(_UTuple&& __u) + { + this->_M_assign(__tuple_like_tag_t{}, std::forward<_UTuple>(__u)); + return *this; + } + + template<__eligible_tuple_like _UTuple> + requires (__const_assignable_from_tuple_like<_UTuple>()) + constexpr const tuple& + operator=(_UTuple&& __u) const + { + this->_M_assign(__tuple_like_tag_t{}, std::forward<_UTuple>(__u)); + return *this; + } template<__tuple_like _UTuple> - constexpr tuple& - operator=(_UTuple&& __u) const; + requires (!__is_tuple_v<_UTuple>) + friend constexpr bool + operator==(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."); + return [&](index_sequence<_Is...>) { + return (bool(std::get<_Is>(__t) == std::get<_Is>(__u)) + && ...); + }(make_index_sequence{}); + } + + template<__tuple_like _UTuple, + typename = make_index_sequence>> + struct __tuple_like_common_comparison_category; + + template<__tuple_like _UTuple, size_t... _Is> + requires requires + { typename void_t<__detail::__synth3way_t<_Elements, tuple_element_t<_Is, _UTuple>>...>; } + struct __tuple_like_common_comparison_category<_UTuple, index_sequence<_Is...>> + { + using type = common_comparison_category_t + <__detail::__synth3way_t<_Elements, tuple_element_t<_Is, _UTuple>>...>; + }; + + template<__tuple_like _UTuple> + requires (!__is_tuple_v<_UTuple>) + friend constexpr typename __tuple_like_common_comparison_category<_UTuple>::type + operator<=>(const tuple& __t, const _UTuple& __u) + { + using _Cat = typename __tuple_like_common_comparison_category<_UTuple>::type; + return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Elements...>()); + } #endif // C++23 #else // ! (concepts && consteval) @@ -2433,27 +2610,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION forward_as_tuple(_Elements&&... __args) noexcept { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); } - // Declarations of std::array and its std::get overloads, so that - // std::tuple_cat can use them if is included before . - - template struct array; - - template - constexpr _Tp& - get(array<_Tp, _Nm>&) noexcept; - - template - constexpr _Tp&& - get(array<_Tp, _Nm>&&) noexcept; - - template - constexpr const _Tp& - get(const array<_Tp, _Nm>&) noexcept; - - template - constexpr const _Tp&& - get(const array<_Tp, _Nm>&&) noexcept; - /// @cond undocumented template struct __make_tuple_impl; @@ -2569,8 +2725,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @endcond /// Create a `tuple` containing all elements from multiple tuple-like objects +#if __cpp_lib_tuple_like // >= C++23 + template<__tuple_like... _Tpls> +#else template...>::value>::type> +#endif constexpr auto tuple_cat(_Tpls&&... __tpls) -> typename __tuple_cat_result<_Tpls...>::__type @@ -2722,7 +2882,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::get<_Idx>(std::forward<_Tuple>(__t))...); } +#if __cpp_lib_tuple_like // >= C++23 + template +#else template +#endif constexpr decltype(auto) apply(_Fn&& __f, _Tuple&& __t) noexcept(__unpack_std_tuple) @@ -2741,7 +2905,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } +#if __cpp_lib_tuple_like // >= C++23 + template +#else template +#endif constexpr _Tp make_from_tuple(_Tuple&& __t) noexcept(__unpack_std_tuple) @@ -2759,17 +2927,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif -#if __cpp_lib_ranges_zip // >= C++23 - template= C++23 + template<__tuple_like _TTuple, __tuple_like _UTuple, + template class _TQual, template class _UQual, + typename = make_index_sequence>> + struct __tuple_like_common_reference; + + template<__tuple_like _TTuple, __tuple_like _UTuple, + template class _TQual, template class _UQual, + size_t... _Is> + requires requires + { typename tuple>, + _UQual>>...>; } + struct __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual, index_sequence<_Is...>> + { + using type = tuple>, + _UQual>>...>; + }; + + template<__tuple_like _TTuple, __tuple_like _UTuple, template class _TQual, template class _UQual> - requires requires { typename tuple, _UQual<_UTypes>>...>; } - struct basic_common_reference, tuple<_UTypes...>, _TQual, _UQual> - { using type = tuple, _UQual<_UTypes>>...>; }; - - template - requires requires { typename tuple...>; } - struct common_type, tuple<_UTypes...>> - { using type = tuple...>; }; + requires (__is_tuple_v<_TTuple> || __is_tuple_v<_UTuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> + && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; } + struct basic_common_reference<_TTuple, _UTuple, _TQual, _UQual> + { + using type = typename __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; + }; + + template<__tuple_like _TTuple, __tuple_like _UTuple, + typename = make_index_sequence>> + struct __tuple_like_common_type; + + template<__tuple_like _TTuple, __tuple_like _UTuple, size_t... _Is> + requires requires + { typename tuple, + tuple_element_t<_Is, _UTuple>>...>; } + struct __tuple_like_common_type<_TTuple, _UTuple, index_sequence<_Is...>> + { + using type = tuple, + tuple_element_t<_Is, _UTuple>>...>; + }; + + template<__tuple_like _TTuple, __tuple_like _UTuple> + requires (__is_tuple_v<_TTuple> || __is_tuple_v<_UTuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> + && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename __tuple_like_common_type<_TTuple, _UTuple>::type; } + struct common_type<_TTuple, _UTuple> + { + using type = typename __tuple_like_common_type<_TTuple, _UTuple>::type; + }; #endif // C++23 /// @} diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/include/std/unordered_map index efad0cef584..ea6129d6494 100644 --- a/libstdc++-v3/include/std/unordered_map +++ b/libstdc++-v3/include/std/unordered_map @@ -51,6 +51,7 @@ #define __glibcxx_want_node_extract #define __glibcxx_want_nonmember_container_access #define __glibcxx_want_unordered_map_try_emplace +#define __glibcxx_want_tuple_like #include #if __cplusplus >= 201703L diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index f113d572e59..212513f6f48 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -92,6 +92,7 @@ #define __glibcxx_want_tuple_element_t #define __glibcxx_want_tuples_by_type #define __glibcxx_want_unreachable +#define __glibcxx_want_tuple_like #include namespace std _GLIBCXX_VISIBILITY(default) diff --git a/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc new file mode 100644 index 00000000000..e9b34a4366f --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc @@ -0,0 +1,169 @@ +// Verify P2165R4 enhancements to std::pair. +// { dg-do run { target c++23 } } + +#include +#include +#include +#include + +using std::array; +using std::pair; +using std::tuple; + +struct A { }; + +template class pair_like_t> +constexpr bool +test01() +{ + struct B { + int m; + constexpr B(A&) : m(0) { } + constexpr B(A&&) : m(1) { } + constexpr B(const A&) : m(2) { } + constexpr B(const A&&) : m(3) { } + }; + + // template + // constexpr explicit(false) pair(UPair&&); + + pair_like_t pair_like; + + [&] { + pair p2b = pair_like; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + }(); + [&] { + pair p2b = std::move(pair_like); + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + }(); + [&] { + pair p2b = std::as_const(pair_like); + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + }(); + [&] { + pair p2b = std::move(std::as_const(pair_like)); + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + }(); + + return true; +} + +template class pair_like_t> +constexpr bool +test02() +{ + struct B { + int m; + constexpr explicit B(A&) : m(0) { } + constexpr explicit B(A&&) : m(1) { } + constexpr explicit B(const A&) : m(2) { } + constexpr explicit B(const A&&) : m(3) { } + }; + + // template + // constexpr explicit(true) pair(UPair&&); + + static_assert( !std::is_convertible_v, pair> ); + + pair_like_t pair_like; + + [&] { + pair p2b{pair_like}; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + }(); + [&] { + pair p2b{std::move(pair_like)}; + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + }(); + [&] { + pair p2b{std::as_const(pair_like)}; + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + }(); + [&] { + pair p2b{std::move(std::as_const(pair_like))}; + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + }(); + + return true; +} + +template class pair_like_t> +constexpr bool +test03() +{ + struct B { + int m; + constexpr B& operator=(A&) { m = 0; return *this; } + constexpr B& operator=(A&&) { m = 1; return *this; } + constexpr B& operator=(const A&) { m = 2; return *this; } + constexpr B& operator=(const A&&) { m = 3; return *this; } + }; + + // template + // constexpr pair& operator=(UPair&&); + + pair_like_t pair_like; + + pair p2b; + p2b = pair_like; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + p2b = std::move(pair_like); + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + p2b = std::as_const(pair_like); + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + p2b = std::move(std::as_const(pair_like)); + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + + return true; +} + +template class pair_like_t> +constexpr bool +test04() +{ + struct B { + mutable int m; + constexpr const B& operator=(A&) const { m = 0; return *this; } + constexpr const B& operator=(A&&) const { m = 1; return *this; } + constexpr const B& operator=(const A&) const { m = 2; return *this; } + constexpr const B& operator=(const A&&) const { m = 3; return *this; } + }; + + // template + // constexpr const pair& operator=(UPair&&) const; + + pair_like_t pair_like; + + const pair p2b; + p2b = pair_like; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + p2b = std::move(pair_like); + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + p2b = std::as_const(pair_like); + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + p2b = std::move(std::as_const(pair_like)); + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + + return true; +} + +template +using pair_like_array = array; + +template +using pair_like_tuple = tuple; + +int +main() +{ + static_assert( test01() ); + static_assert( test02() ); + static_assert( test03() ); + static_assert( test04() ); + + static_assert( test01() ); + static_assert( test02() ); + static_assert( test03() ); + static_assert( test04() ); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc new file mode 100644 index 00000000000..931dd8916c8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc @@ -0,0 +1,319 @@ +// Verify P2165R4 enhancements to std::tuple. +// { dg-do run { target c++23 } } + +#include +#include +#include +#include +#include + +using std::array; +using std::pair; +using std::tuple; +using std::allocator; +using std::allocator_arg_t; +using std::allocator_arg; + +namespace alloc { + struct B01; + struct B02; +} + +template<> struct std::uses_allocator> : std::true_type { }; +template<> struct std::uses_allocator> : std::true_type { }; + +struct A { }; + +template class tuple_like_t> +constexpr bool +test01() +{ + struct B { + int m; + constexpr B(A&) : m(0) { } + constexpr B(A&&) : m(1) { } + constexpr B(const A&) : m(2) { } + constexpr B(const A&&) : m(3) { } + }; + + // template + // constexpr explicit(false) tuple(UTuple&&); + + tuple_like_t tuple_like; + + [&] { + tuple t3b = tuple_like; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple t3b = std::move(tuple_like); + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple t3b = std::as_const(tuple_like); + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple t3b = std::move(std::as_const(tuple_like)); + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + return true; +} + +namespace alloc +{ + struct B01 { + int m; + B01(A&); + B01(A&&); + B01(const A&); + B01(const A&&); + constexpr B01(allocator_arg_t, allocator, A&) : m(0) { } + constexpr B01(allocator_arg_t, allocator, A&&) : m(1) { } + constexpr B01(allocator_arg_t, allocator, const A&) : m(2) { } + constexpr B01(allocator_arg_t, allocator, const A&&) : m(3) { } + }; + + template class tuple_like_t> + constexpr bool + test01() + { + using B = B01; + + // template + // constexpr explicit(false) tuple(allocator_arg_t, const Alloc&, UTuple&&); + + tuple_like_t tuple_like; + + [&] { + tuple t3b = {allocator_arg, allocator{}, tuple_like}; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple t3b = {allocator_arg, allocator{}, std::move(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple t3b = {allocator_arg, allocator{}, std::as_const(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple t3b = {allocator_arg, allocator{}, std::move(std::as_const(tuple_like))}; + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + return true; + } +} + +template class tuple_like_t> +constexpr bool +test02() +{ + struct B { + int m; + constexpr explicit B(A&) : m(0) { } + constexpr explicit B(A&&) : m(1) { } + constexpr explicit B(const A&) : m(2) { } + constexpr explicit B(const A&&) : m(3) { } + }; + + // template + // constexpr explicit(true) tuple(UTuple&&); + + static_assert( !std::is_convertible_v, tuple> ); + + tuple_like_t tuple_like; + + [&] { + tuple t3b{tuple_like}; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple t3b{std::move(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple t3b{std::as_const(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple t3b{std::move(std::as_const(tuple_like))}; + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + return true; +} + +namespace alloc +{ + struct B02 { + int m; + explicit B02(A&); + explicit B02(A&&); + explicit B02(const A&); + explicit B02(const A&&); + explicit constexpr B02(allocator_arg_t, allocator, A&) : m(0) { } + explicit constexpr B02(allocator_arg_t, allocator, A&&) : m(1) { } + explicit constexpr B02(allocator_arg_t, allocator, const A&) : m(2) { } + explicit constexpr B02(allocator_arg_t, allocator, const A&&) : m(3) { } + }; + + template class tuple_like_t> + constexpr bool + test02() + { + using B = B02; + + // template + // constexpr explicit(true) tuple(allocator_arg_t, const Alloc&, UTuple&&); + + static_assert( !std::is_convertible_v, tuple> ); + + tuple_like_t tuple_like; + + [&] { + tuple t3b{allocator_arg, allocator{}, tuple_like}; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple t3b{allocator_arg, allocator{}, std::move(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple t3b{allocator_arg, allocator{}, std::as_const(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple t3b{allocator_arg, allocator{}, std::move(std::as_const(tuple_like))}; + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + return true; + } +} + + +template class tuple_like_t> +constexpr bool +test03() +{ + struct B { + int m; + constexpr B& operator=(A&) { m = 0; return *this; } + constexpr B& operator=(A&&) { m = 1; return *this; } + constexpr B& operator=(const A&) { m = 2; return *this; } + constexpr B& operator=(const A&&) { m = 3; return *this; } + }; + + // template + // constexpr tuple& operator=(UTuple&&); + + tuple_like_t tuple_like; + + tuple t3b; + t3b = tuple_like; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + t3b = std::move(tuple_like); + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + t3b = std::as_const(tuple_like); + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + t3b = std::move(std::as_const(tuple_like)); + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + + return true; +} + +template class tuple_like_t> +constexpr bool +test04() +{ + struct B { + mutable int m; + constexpr const B& operator=(A&) const { m = 0; return *this; } + constexpr const B& operator=(A&&) const { m = 1; return *this; } + constexpr const B& operator=(const A&) const { m = 2; return *this; } + constexpr const B& operator=(const A&&) const { m = 3; return *this; } + }; + + // template + // constexpr const tuple& operator=(UTuple&&) const; + + tuple_like_t tuple_like; + + const tuple t3b; + t3b = tuple_like; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + t3b = std::move(tuple_like); + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + t3b = std::as_const(tuple_like); + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + t3b = std::move(std::as_const(tuple_like)); + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + + return true; +} + +template class tuple_like_t> +constexpr bool +test05() +{ + // template + // constexpr bool operator==(const tuple&, const UTuple&); + + static_assert( tuple{1, 2, 3} == tuple_like_t{1, 2, 3} ); + static_assert( tuple{1, 2, 4} != tuple_like_t{1, 2, 3} ); + static_assert( tuple_like_t{1, 2, 3} == tuple{1, 2, 3} ); + static_assert( tuple_like_t{1, 2, 3} != tuple{1, 2, 4} ); + + // template + // constexpr bool operator<=>const tuple&, const UTuple&); + + static_assert( (tuple{1, 2, 3} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::equal ); + static_assert( (tuple{1, 2, 4} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::greater ); + static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 3}) == std::strong_ordering::equal ); + static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 4}) == std::strong_ordering::less ); + + static_assert( tuple{1, 2, 4} > tuple_like_t{1, 2, 3} ); + static_assert( tuple_like_t{1, 2, 3} < tuple{1, 2, 4} ); + + // template + // struct basic_common_reference; + + static_assert( std::same_as, + tuple>, + tuple> ); + + static_assert( std::same_as, + tuple_like_t>, + tuple> ); + + // template + // struct common_type; + + static_assert( std::same_as, + tuple>, + tuple> ); + + static_assert( std::same_as, + tuple_like_t>, + tuple> ); + + return true; +} + +template +using tuple_like_array = array; + +int +main() +{ + static_assert( test01() ); + static_assert( alloc::test01() ); + static_assert( test02() ); + static_assert( alloc::test02() ); + static_assert( test03() ); + static_assert( test04() ); + static_assert( test05() ); +} diff --git a/libstdc++-v3/testsuite/std/ranges/zip/1.cc b/libstdc++-v3/testsuite/std/ranges/zip/1.cc index b7717aed92c..672a8c356d9 100644 --- a/libstdc++-v3/testsuite/std/ranges/zip/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/zip/1.cc @@ -41,8 +41,8 @@ test01() VERIFY( i2 == z2.end() ); VERIFY( ranges::size(z2) == 2 ); VERIFY( ranges::size(std::as_const(z2)) == 2 ); - VERIFY( z2[0].first == 1 && z2[0].second == 3 ); - VERIFY( z2[1].first == 2 && z2[1].second == 4 ); + VERIFY( std::get<0>(z2[0]) == 1 && std::get<1>(z2[0]) == 3 ); + VERIFY( std::get<0>(z2[1]) == 2 && std::get<1>(z2[1]) == 4 ); for (const auto [x, y] : z2) { VERIFY( y - x == 2 );