https://gcc.gnu.org/g:c71767a088991174fd7197a3eb29eee6bc35bdec

commit r16-8935-gc71767a088991174fd7197a3eb29eee6bc35bdec
Author: Jonathan Wakely <[email protected]>
Date:   Wed Apr 22 15:37:16 2026 +0100

    libstdc++: Constrain tuple(tuple&&) [PR78302]
    
    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.
    
    Reviewed-by: Tomasz KamiƄski <[email protected]>
    (cherry picked from commit 5154144864a669c722fbb2170e79416c3ae5ff50)

Diff:
---
 libstdc++-v3/include/std/tuple                     |  4 +++-
 libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc | 17 +++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index f7caa79cda04..b236ca7c6eea 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -993,7 +993,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..6998a9e418a9
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc
@@ -0,0 +1,17 @@
+// { 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_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&>>);

Reply via email to