| Message ID | 20260506141443.399248-1-jwakely@redhat.com |
|---|---|
| State | New |
| Headers |
Return-Path: <gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E0A6D4BA23C9 for <patchwork@sourceware.org>; Wed, 6 May 2026 14:16:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E0A6D4BA23C9 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=AqFTBj/0 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 ESMTP id 6A36E4BA23EF for <gcc-patches@gcc.gnu.org>; Wed, 6 May 2026 14:14:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6A36E4BA23EF Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 6A36E4BA23EF Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778076892; cv=none; b=NOL2Te9sTaND6sMOLg5lCKPf4GHZ7XG5obypHWQ0L29Y30wHFN8mQZyf4irzJ93kUR53v90ROr/EQpMxF75oVIw2Fwg1f9Pl7VAl8ym8MRr5ZEhdV66kjy0nTPmeXT9fS9InXxL3ldq19KYp8qh95nw3jTJzLk7hhxf+qbFD6Fs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778076892; c=relaxed/simple; bh=2CptHJID34+PkQm+bDAhD8DmVGmjuwNquT9p6ei9AB8=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=juA+m7yTWxm0dRxlJp2RXTFVJE06hyICLwvL+JDGulHQRjXTv6ncUN5QLTVRwBcKr52uK2EL2lzvC+bGYoskrajKGLpfcJqSRjPw6XozrOaLZvWIcj4nl6wmYw7VPSSIbNqgGhFgKZnCkfIDiaVVoofGo2ZSSwL4kd0lpfVLVpo= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=AqFTBj/0 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6A36E4BA23EF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778076892; 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=szUdRuYlFZF8e34IHoL6kqTJRMZApPLFDsA7CxynAss=; b=AqFTBj/02SQvedPVusXxUtMFVxt8nk1UYmAgA5TzrhlvRlUfByk7felV9n8nH6ImLZRux0 nrQE8KhyTutYqQ/ilLufUL02tY7f6/kYNEbjle0ktbeNf+hmxVCma65Buh22X+AwZ+ppnK c5KpPAIg2PJLp1MNfKfMY6FuelpeJ+g= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-27-NyxrKCaQPUWRNyy6a0cQbQ-1; Wed, 06 May 2026 10:14:46 -0400 X-MC-Unique: NyxrKCaQPUWRNyy6a0cQbQ-1 X-Mimecast-MFC-AGG-ID: NyxrKCaQPUWRNyy6a0cQbQ_1778076886 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D2524195606F; Wed, 6 May 2026 14:14:45 +0000 (UTC) Received: from zen.kayari.org (unknown [10.44.32.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A5CF618001CC; Wed, 6 May 2026 14:14:44 +0000 (UTC) From: Jonathan Wakely <jwakely@redhat.com> To: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org Subject: [PATCH] libstdc++: Constrain tuple(tuple&&) [PR78302] Date: Wed, 6 May 2026 15:14:35 +0100 Message-ID: <20260506141443.399248-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: gfNrYlznm_TmAvY90j0qIoHUuHdXrce9M54xwUPxfs8_1778076886 X-Mimecast-Originator: redhat.com Content-Type: text/plain Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.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_BLOCKED, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org |
| Series |
libstdc++: Constrain tuple(tuple&&) [PR78302]
|
|
Commit Message
Jonathan Wakely
May 6, 2026, 2:14 p.m. UTC
Since C++20 the std::tuple move constructor should be constrained (as modified by LWG 2899). We already define the move constructor as defaulted, but it's not implicitly defined as deleted for non-move-constructible element types because the _Tuple_impl(_Tuple_impl&&) constructor is user-provided and unconstrained. For C++20 and later we use a requires-clause to constrain the defaulted tuple(tuple&&) constructor. Ideally we'd make this change pre-C++20 as well, but that's harder to do without using a requires-clause, so this change is only for C++20 and later. I think that's OK, but if we need to change it for pre-C++20 later we can consider inheriting from _Enable_copy_move<..., tuple> to make the defaulted move constructor defined as deleted. libstdc++-v3/ChangeLog: PR libstdc++/78302 PR libstdc++/71301 * include/std/tuple [C++20] (tuple(tuple&&)): Add requires-clause. * testsuite/20_util/tuple/cons/78302.cc: New test. --- Tested x86_64-linux. libstdc++-v3/include/std/tuple | 4 +++- libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc
Comments
On Wed, May 6, 2026 at 4:16 PM Jonathan Wakely <jwakely@redhat.com> wrote: > Since C++20 the std::tuple move constructor should be constrained (as > modified by LWG 2899). > > We already define the move constructor as defaulted, but it's not > implicitly defined as deleted for non-move-constructible element types > because the _Tuple_impl(_Tuple_impl&&) constructor is user-provided and > unconstrained. For C++20 and later we use a requires-clause to constrain > the defaulted tuple(tuple&&) constructor. > > Ideally we'd make this change pre-C++20 as well, but that's harder to do > without using a requires-clause, so this change is only for C++20 and > later. I think that's OK, but if we need to change it for pre-C++20 > later we can consider inheriting from _Enable_copy_move<..., tuple> to > make the defaulted move constructor defined as deleted. > > libstdc++-v3/ChangeLog: > > PR libstdc++/78302 > PR libstdc++/71301 > * include/std/tuple [C++20] (tuple(tuple&&)): Add > requires-clause. > * testsuite/20_util/tuple/cons/78302.cc: New test. > --- > > Tested x86_64-linux. > > libstdc++-v3/include/std/tuple | 4 +++- > libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc | 11 +++++++++++ > 2 files changed, 14 insertions(+), 1 deletion(-) > create mode 100644 libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > > diff --git a/libstdc++-v3/include/std/tuple > b/libstdc++-v3/include/std/tuple > index cbacd5a3c977..64b96fe4f599 100644 > --- a/libstdc++-v3/include/std/tuple > +++ b/libstdc++-v3/include/std/tuple > @@ -954,7 +954,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > constexpr tuple(const tuple&) = default; > > - constexpr tuple(tuple&&) = default; > + constexpr > + tuple(tuple&&) requires (is_move_constructible_v<_Elements> && ...) > Could you add test for tuple of references (lvalue and rvalue)? I think the traits gives correct result, but I am not sure. > + = default; > > template<typename... _UTypes> > requires (__constructible<const _UTypes&...>()) > diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > new file mode 100644 > index 000000000000..b3c6bd67fd27 > --- /dev/null > +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > @@ -0,0 +1,11 @@ > +// { dg-do compile { target c++20 } } > + > +// Bug 78302 is_move_constructible_v<tuple<nonmovable>> should be false > +// LWG 2899. is_(nothrow_)move_constructible and tuple, optional and > unique_ptr > + > +#include <tuple> > +#include <type_traits> > + > +struct NotMovable { NotMovable(NotMovable&&) = delete; }; > +static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); > +static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>); > -- > 2.54.0 > >
On Wed, 6 May 2026 at 15:49, Tomasz Kaminski <tkaminsk@redhat.com> wrote: > > > > On Wed, May 6, 2026 at 4:16 PM Jonathan Wakely <jwakely@redhat.com> wrote: >> >> Since C++20 the std::tuple move constructor should be constrained (as >> modified by LWG 2899). >> >> We already define the move constructor as defaulted, but it's not >> implicitly defined as deleted for non-move-constructible element types >> because the _Tuple_impl(_Tuple_impl&&) constructor is user-provided and >> unconstrained. For C++20 and later we use a requires-clause to constrain >> the defaulted tuple(tuple&&) constructor. >> >> Ideally we'd make this change pre-C++20 as well, but that's harder to do >> without using a requires-clause, so this change is only for C++20 and >> later. I think that's OK, but if we need to change it for pre-C++20 >> later we can consider inheriting from _Enable_copy_move<..., tuple> to >> make the defaulted move constructor defined as deleted. >> >> libstdc++-v3/ChangeLog: >> >> PR libstdc++/78302 >> PR libstdc++/71301 >> * include/std/tuple [C++20] (tuple(tuple&&)): Add >> requires-clause. >> * testsuite/20_util/tuple/cons/78302.cc: New test. >> --- >> >> Tested x86_64-linux. >> >> libstdc++-v3/include/std/tuple | 4 +++- >> libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc | 11 +++++++++++ >> 2 files changed, 14 insertions(+), 1 deletion(-) >> create mode 100644 libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc >> >> diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple >> index cbacd5a3c977..64b96fe4f599 100644 >> --- a/libstdc++-v3/include/std/tuple >> +++ b/libstdc++-v3/include/std/tuple >> @@ -954,7 +954,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> constexpr tuple(const tuple&) = default; >> >> - constexpr tuple(tuple&&) = default; >> + constexpr >> + tuple(tuple&&) requires (is_move_constructible_v<_Elements> && ...) > > Could you add test for tuple of references (lvalue and rvalue)? I think the traits > gives correct result, but I am not sure. >> >> + = default; >> >> template<typename... _UTypes> >> requires (__constructible<const _UTypes&...>()) >> diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc >> new file mode 100644 >> index 000000000000..b3c6bd67fd27 >> --- /dev/null >> +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc >> @@ -0,0 +1,11 @@ >> +// { dg-do compile { target c++20 } } >> + >> +// Bug 78302 is_move_constructible_v<tuple<nonmovable>> should be false >> +// LWG 2899. is_(nothrow_)move_constructible and tuple, optional and unique_ptr >> + >> +#include <tuple> >> +#include <type_traits> >> + >> +struct NotMovable { NotMovable(NotMovable&&) = delete; }; >> +static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); >> +static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>); Is this good enough? #include <tuple> #include <type_traits> struct NotMovable { NotMovable(NotMovable&&) = delete; }; static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); static_assert(!std::is_move_constructible_v<std::tuple<int, NotMovable>>); static_assert(!std::is_move_constructible_v<std::tuple<int&, NotMovable>>); static_assert(!std::is_move_constructible_v<std::tuple<int&&, NotMovable>>); static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>); static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&>>); static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&>>); static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&, int&>>); (It passes)
On Wed, May 6, 2026 at 10:10 PM Jonathan Wakely <jwakely@redhat.com> wrote: > On Wed, 6 May 2026 at 15:49, Tomasz Kaminski <tkaminsk@redhat.com> wrote: > > > > > > > > On Wed, May 6, 2026 at 4:16 PM Jonathan Wakely <jwakely@redhat.com> > wrote: > >> > >> Since C++20 the std::tuple move constructor should be constrained (as > >> modified by LWG 2899). > >> > >> We already define the move constructor as defaulted, but it's not > >> implicitly defined as deleted for non-move-constructible element types > >> because the _Tuple_impl(_Tuple_impl&&) constructor is user-provided and > >> unconstrained. For C++20 and later we use a requires-clause to constrain > >> the defaulted tuple(tuple&&) constructor. > >> > >> Ideally we'd make this change pre-C++20 as well, but that's harder to do > >> without using a requires-clause, so this change is only for C++20 and > >> later. I think that's OK, but if we need to change it for pre-C++20 > >> later we can consider inheriting from _Enable_copy_move<..., tuple> to > >> make the defaulted move constructor defined as deleted. > >> > >> libstdc++-v3/ChangeLog: > >> > >> PR libstdc++/78302 > >> PR libstdc++/71301 > >> * include/std/tuple [C++20] (tuple(tuple&&)): Add > >> requires-clause. > >> * testsuite/20_util/tuple/cons/78302.cc: New test. > >> --- > >> > >> Tested x86_64-linux. > >> > >> libstdc++-v3/include/std/tuple | 4 +++- > >> libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc | 11 +++++++++++ > >> 2 files changed, 14 insertions(+), 1 deletion(-) > >> create mode 100644 libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > >> > >> diff --git a/libstdc++-v3/include/std/tuple > b/libstdc++-v3/include/std/tuple > >> index cbacd5a3c977..64b96fe4f599 100644 > >> --- a/libstdc++-v3/include/std/tuple > >> +++ b/libstdc++-v3/include/std/tuple > >> @@ -954,7 +954,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >> > >> constexpr tuple(const tuple&) = default; > >> > >> - constexpr tuple(tuple&&) = default; > >> + constexpr > >> + tuple(tuple&&) requires (is_move_constructible_v<_Elements> && > ...) > > > > Could you add test for tuple of references (lvalue and rvalue)? I think > the traits > > gives correct result, but I am not sure. > >> > >> + = default; > >> > >> template<typename... _UTypes> > >> requires (__constructible<const _UTypes&...>()) > >> diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > >> new file mode 100644 > >> index 000000000000..b3c6bd67fd27 > >> --- /dev/null > >> +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc > >> @@ -0,0 +1,11 @@ > >> +// { dg-do compile { target c++20 } } > >> + > >> +// Bug 78302 is_move_constructible_v<tuple<nonmovable>> should be false > >> +// LWG 2899. is_(nothrow_)move_constructible and tuple, optional and > unique_ptr > >> + > >> +#include <tuple> > >> +#include <type_traits> > >> + > >> +struct NotMovable { NotMovable(NotMovable&&) = delete; }; > >> +static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); > >> +static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>); > > Is this good enough? > > > #include <tuple> > #include <type_traits> > > struct NotMovable { NotMovable(NotMovable&&) = delete; }; > static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); > static_assert(!std::is_move_constructible_v<std::tuple<int, NotMovable>>); > static_assert(!std::is_move_constructible_v<std::tuple<int&, NotMovable>>); > static_assert(!std::is_move_constructible_v<std::tuple<int&&, > NotMovable>>); > static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>); > static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&>>); > static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&>>); > static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&, > int&>>); > Add them to test file, so I do not need to check is_move_constructible_v on reference, when looking at it. LGTM with that. > > (It passes) > >
On Thu, 7 May 2026 at 06:39, Tomasz Kaminski <tkaminsk@redhat.com> wrote: > > > > On Wed, May 6, 2026 at 10:10 PM Jonathan Wakely <jwakely@redhat.com> wrote: >> >> On Wed, 6 May 2026 at 15:49, Tomasz Kaminski <tkaminsk@redhat.com> wrote: >> > >> > >> > >> > On Wed, May 6, 2026 at 4:16 PM Jonathan Wakely <jwakely@redhat.com> wrote: >> >> >> >> Since C++20 the std::tuple move constructor should be constrained (as >> >> modified by LWG 2899). >> >> >> >> We already define the move constructor as defaulted, but it's not >> >> implicitly defined as deleted for non-move-constructible element types >> >> because the _Tuple_impl(_Tuple_impl&&) constructor is user-provided and >> >> unconstrained. For C++20 and later we use a requires-clause to constrain >> >> the defaulted tuple(tuple&&) constructor. >> >> >> >> Ideally we'd make this change pre-C++20 as well, but that's harder to do >> >> without using a requires-clause, so this change is only for C++20 and >> >> later. I think that's OK, but if we need to change it for pre-C++20 >> >> later we can consider inheriting from _Enable_copy_move<..., tuple> to >> >> make the defaulted move constructor defined as deleted. >> >> >> >> libstdc++-v3/ChangeLog: >> >> >> >> PR libstdc++/78302 >> >> PR libstdc++/71301 >> >> * include/std/tuple [C++20] (tuple(tuple&&)): Add >> >> requires-clause. >> >> * testsuite/20_util/tuple/cons/78302.cc: New test. >> >> --- >> >> >> >> Tested x86_64-linux. >> >> >> >> libstdc++-v3/include/std/tuple | 4 +++- >> >> libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc | 11 +++++++++++ >> >> 2 files changed, 14 insertions(+), 1 deletion(-) >> >> create mode 100644 libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc >> >> >> >> diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple >> >> index cbacd5a3c977..64b96fe4f599 100644 >> >> --- a/libstdc++-v3/include/std/tuple >> >> +++ b/libstdc++-v3/include/std/tuple >> >> @@ -954,7 +954,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> >> >> constexpr tuple(const tuple&) = default; >> >> >> >> - constexpr tuple(tuple&&) = default; >> >> + constexpr >> >> + tuple(tuple&&) requires (is_move_constructible_v<_Elements> && ...) >> > >> > Could you add test for tuple of references (lvalue and rvalue)? I think the traits >> > gives correct result, but I am not sure. >> >> >> >> + = default; >> >> >> >> template<typename... _UTypes> >> >> requires (__constructible<const _UTypes&...>()) >> >> diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc >> >> new file mode 100644 >> >> index 000000000000..b3c6bd67fd27 >> >> --- /dev/null >> >> +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc >> >> @@ -0,0 +1,11 @@ >> >> +// { dg-do compile { target c++20 } } >> >> + >> >> +// Bug 78302 is_move_constructible_v<tuple<nonmovable>> should be false >> >> +// LWG 2899. is_(nothrow_)move_constructible and tuple, optional and unique_ptr >> >> + >> >> +#include <tuple> >> >> +#include <type_traits> >> >> + >> >> +struct NotMovable { NotMovable(NotMovable&&) = delete; }; >> >> +static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); >> >> +static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>); >> >> Is this good enough? >> >> >> #include <tuple> >> #include <type_traits> >> >> struct NotMovable { NotMovable(NotMovable&&) = delete; }; >> static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); >> static_assert(!std::is_move_constructible_v<std::tuple<int, NotMovable>>); >> static_assert(!std::is_move_constructible_v<std::tuple<int&, NotMovable>>); >> static_assert(!std::is_move_constructible_v<std::tuple<int&&, NotMovable>>); >> static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>); >> static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&>>); >> static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&>>); >> static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&, int&>>); > > Add them to test file, so I do not need to check is_move_constructible_v on reference, Yes, what I pasted above is what is in the test file in my local tree. I've pushed it to trunk and will backport it after waiting a while. > when looking at it. LGTM with that. >> >> >> (It passes) >>
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index cbacd5a3c977..64b96fe4f599 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -954,7 +954,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr tuple(const tuple&) = default; - constexpr tuple(tuple&&) = default; + constexpr + tuple(tuple&&) requires (is_move_constructible_v<_Elements> && ...) + = default; template<typename... _UTypes> requires (__constructible<const _UTypes&...>()) diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc new file mode 100644 index 000000000000..b3c6bd67fd27 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc @@ -0,0 +1,11 @@ +// { dg-do compile { target c++20 } } + +// Bug 78302 is_move_constructible_v<tuple<nonmovable>> should be false +// LWG 2899. is_(nothrow_)move_constructible and tuple, optional and unique_ptr + +#include <tuple> +#include <type_traits> + +struct NotMovable { NotMovable(NotMovable&&) = delete; }; +static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>); +static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>);