From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 138CF3858432 for ; Wed, 24 Jan 2024 12:01:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 138CF3858432 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 138CF3858432 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=1706097703; cv=none; b=BKeRCE4ZMaDccqXncDa1eSFfjAfIKfOOHrmVFC+Tm6wLA+1LIlITy4bgBca3jWci2BqHJ2n0sgiBIfwQ8h3dcMTkq8gGQ0EC6/VuWh99E49avrR+ytPcSeyUDlqvpnQBn5oFKrbve5vy98n5aC2Ve6WVIV/NegMdaa9gv7/aHbQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706097703; c=relaxed/simple; bh=zaE/rWaP2Ub6iTyl8LNP/EhLj4J5n7FJUAPESVk8XDE=; h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To; b=N1J2ZVgG7k2U3/Fdb7nXfm4Hf7iofMosyQAbUXd0jcUFeQLFNWkcAOtstC43DdoNf1JLahSSc/9dk9C1N7lHTxTvYbjjujhZibFTSWAA0F7HRhyg+PrjQPP4gNGL050mRYbdGbrZO6CPSL1JBf8LgZZP6hEuNreaA8WJ3YV/Tvs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1706097700; 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: in-reply-to:in-reply-to:references:references; bh=KP3zkqqb6DRmld6fCgfexWDUrzzTFnsNcuSeNNwYpJ4=; b=WC99GT2ozwzWW/Jc1yaE2jnhBkYTn0bR7OJAOGEkTIZJJLKxbeyIOUkL3mlDPyKtHvyz0F aSf2AhqDOfrInaUskyofrREsrOUUY2KR6b7UhiqNHUhv59Rc1u/jDjupCbS1+vRSM4wpwT KS8QoKW4cktK29Y46X01rrd4RqUl1NQ= Received: from mail-yw1-f197.google.com (mail-yw1-f197.google.com [209.85.128.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-561-3btTGibaM72evR1dyTQDiQ-1; Wed, 24 Jan 2024 07:01:38 -0500 X-MC-Unique: 3btTGibaM72evR1dyTQDiQ-1 Received: by mail-yw1-f197.google.com with SMTP id 00721157ae682-5fc6463b0edso89221687b3.0 for ; Wed, 24 Jan 2024 04:01:38 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706097698; x=1706702498; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=KP3zkqqb6DRmld6fCgfexWDUrzzTFnsNcuSeNNwYpJ4=; b=KAYxGYXLmMZh0zwTvVURUwdvPAlLiYQEiE2Dy0yWyFAr0F5U2rJ1HIlr3/8PAC9G6H j3ry1QTkSOOO55sTOd0unWrl3j9zu+vltoWzXHw8BJA7PNju4lFgDvkN9oZWcWyFXsqz u7IUcKiLBn4EXkFWAsoz/ddxVXIUndkFeorHmLAeZsd2mCHatNdO7NUqdGWGlXpvhKry jPO/wON9ra8tisqm3RYkjCdbFjpl+cmNAzU7x3tfLYWEWf/z9PgkFJEXoFp1Blb1k3o9 2JLHoAEPeDvtuamd7kpf2wJE41eV5f7EB1NF6G3hNgcR79zuJwpu3vhTBzVAxtvBWPmX 1aHw== X-Gm-Message-State: AOJu0YwhXk1iquyu33yUnUHeiGiolkhKRhuJQQf7NYFAxfUrPO2Wug3R JKtrJbzKDfZCm6nPMLYmD7Tdf4Ga6yOtLGhygRZCW7cuMcJ5VJyEcOGZCZKR+Wep+KAgRnfW1yE ofV2c0FOvDhrQR9p48nKu4QPx4kd+3jtzBoVG1SIXfj3a3fwZ4nI5P5/skYPtwXZgkW8Env2Zju JupbMfGkE3kD9JrBK9ccSXoPWVLMH0Hw== X-Received: by 2002:a25:f212:0:b0:dbd:4c4d:240d with SMTP id i18-20020a25f212000000b00dbd4c4d240dmr449915ybe.59.1706097698270; Wed, 24 Jan 2024 04:01:38 -0800 (PST) X-Google-Smtp-Source: AGHT+IFXcTujDz3W4Qnk1GPnDgFKr1uHcMKGPSbvFzqIKDgcR/jKkEVk4Gy3a8CPQHpboobNJ7XM4sZEmZgoTa6JIN8= X-Received: by 2002:a25:f212:0:b0:dbd:4c4d:240d with SMTP id i18-20020a25f212000000b00dbd4c4d240dmr449899ybe.59.1706097697903; Wed, 24 Jan 2024 04:01:37 -0800 (PST) MIME-Version: 1.0 References: <20240123235303.1540890-1-ppalka@redhat.com> <20240123235303.1540890-2-ppalka@redhat.com> In-Reply-To: <20240123235303.1540890-2-ppalka@redhat.com> From: Jonathan Wakely Date: Wed, 24 Jan 2024 12:01:21 +0000 Message-ID: Subject: Re: [PATCH 2/2] libstdc++: Implement P2165R4 changes to std::pair/tuple/etc To: Patrick Palka Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-13.3 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,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 List-Id: On Tue, 23 Jan 2024 at 23:54, Patrick Palka wrote: > 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; We have a compiler bug where a forward declaration without template parameter names causes bad diagnostics later. The compiler seems to try to use the parameter names from the first decl it sees, so we end up with things like even when there's a name available at the site of the actual error. So I think we should name these _T1 and _T2 here. > + > 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 I think this needs to be constrained with !_S_dangles<...>() and we need a deleted overload with the same constraints, except for _S_dangles being true. And that should be covered by a test. > 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 + size_t _Idx0, size_t... _Idxs> > + 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{}); These new functions can use index_sequence_for<_Elements...>{} here, so you don't need the sizeof.... That applies several times below as well. I think it's semantically identical, just a little shorter. I don't know if there's any compilation speed benefit either way. Maybe sizeof...(_Elements) is cheaper than expanding the pack into the index_sequence_for alias template? > + } > +#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 For some reason these two new constructors aren't deleted if they create dangling refs. I don't know why.