diff --git a/libcxx/include/tuple b/libcxx/include/tuple index b046e2aed43e2..8cc061c70b891 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -516,6 +516,7 @@ struct __tuple_impl; struct __forward_args {}; struct __value_init {}; +struct __from_tuple {}; template struct _LIBCPP_DECLSPEC_EMPTY_BASES @@ -538,7 +539,7 @@ struct _LIBCPP_DECLSPEC_EMPTY_BASES : __tuple_leaf<_Indx, _Tp>(__uses_alloc_ctor<_Tp, _Alloc, _Args>(), __alloc, std::forward<_Args>(__args))... {} template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(_Tuple&& __t) noexcept( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(__from_tuple, _Tuple&& __t) noexcept( (__all::type>::type>::value...>::value)) @@ -547,7 +548,8 @@ struct _LIBCPP_DECLSPEC_EMPTY_BASES std::get<_Indx>(__t)))... {} template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(allocator_arg_t, const _Alloc& __a, _Tuple&& __t) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 + __tuple_impl(allocator_arg_t, const _Alloc& __a, __from_tuple, _Tuple&& __t) : __tuple_leaf<_Indx, _Tp>( __uses_alloc_ctor<_Tp, _Alloc, @@ -673,13 +675,13 @@ public: template class _And = _And, __enable_if_t< _And...>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple(allocator_arg_t, const _Alloc& __alloc, const tuple& __t) - : __base_(allocator_arg_t(), __alloc, __t) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), __t) {} template class _And = _And, __enable_if_t< _And...>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple(allocator_arg_t, const _Alloc& __alloc, tuple&& __t) - : __base_(allocator_arg_t(), __alloc, std::move(__t)) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__t)) {} // tuple(const tuple&) constructors (including allocator_arg_t variants) @@ -712,7 +714,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible...> >::value) tuple(const tuple<_Up...>& __t) noexcept(_And...>::value) - : __base_(__t) {} + : __base_(__from_tuple(), __t) {} template ...> >::value) tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t) - : __base_(allocator_arg_t(), __a, __t) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), __t) {} # if _LIBCPP_STD_VER >= 23 // tuple(tuple&) constructors (including allocator_arg_t variants) template &>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>& __t) - : __base_(__t) {} + : __base_(__from_tuple(), __t) {} template &>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible<_Up&, _Tp>...>::value) tuple(allocator_arg_t, const _Alloc& __alloc, tuple<_Up...>& __t) - : __base_(allocator_arg_t(), __alloc, __t) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), __t) {} # endif // _LIBCPP_STD_VER >= 23 // tuple(tuple&&) constructors (including allocator_arg_t variants) template &&> >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value) tuple(tuple<_Up...>&& __t) noexcept(_And...>::value) - : __base_(std::move(__t)) {} + : __base_(__from_tuple(), std::move(__t)) {} template &&> >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value) tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t) - : __base_(allocator_arg_t(), __a, std::move(__t)) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__t)) {} # if _LIBCPP_STD_VER >= 23 // tuple(const tuple&&) constructors (including allocator_arg_t variants) @@ -754,14 +756,14 @@ public: template &&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible...>::value) tuple(const tuple<_Up...>&& __t) - : __base_(std::move(__t)) {} + : __base_(__from_tuple(), std::move(__t)) {} template &&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible...>::value) tuple(allocator_arg_t, const _Alloc& __alloc, const tuple<_Up...>&& __t) - : __base_(allocator_arg_t(), __alloc, std::move(__t)) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__t)) {} # endif // _LIBCPP_STD_VER >= 23 // tuple(const pair&) constructors (including allocator_arg_t variants) @@ -796,7 +798,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible&> >::value) tuple(const pair<_Up1, _Up2>& __p) noexcept(_NothrowConstructibleFromPair&>::value) - : __base_(__p) {} + : __base_(__from_tuple(), __p) {} template &> >::value) tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p) - : __base_(allocator_arg_t(), __a, __p) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), __p) {} # if _LIBCPP_STD_VER >= 23 // tuple(pair&) constructors (including allocator_arg_t variants) @@ -814,7 +816,7 @@ public: template &>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible&>::value) tuple(pair<_U1, _U2>& __p) - : __base_(__p) {} + : __base_(__from_tuple(), __p) {} template &>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible&>::value) tuple(allocator_arg_t, const _Alloc& __alloc, pair<_U1, _U2>& __p) - : __base_(allocator_arg_t(), __alloc, __p) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), __p) {} # endif // tuple(pair&&) constructors (including allocator_arg_t variants) @@ -834,7 +836,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible&&> >::value) tuple(pair<_Up1, _Up2>&& __p) noexcept(_NothrowConstructibleFromPair&&>::value) - : __base_(std::move(__p)) {} + : __base_(__from_tuple(), std::move(__p)) {} template &&> >::value) tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p) - : __base_(allocator_arg_t(), __a, std::move(__p)) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__p)) {} # if _LIBCPP_STD_VER >= 23 // tuple(const pair&&) constructors (including allocator_arg_t variants) @@ -852,7 +854,7 @@ public: template &&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible&&>::value) tuple(const pair<_U1, _U2>&& __p) - : __base_(std::move(__p)) {} + : __base_(__from_tuple(), std::move(__p)) {} template &&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible&&>::value) tuple(allocator_arg_t, const _Alloc& __alloc, const pair<_U1, _U2>&& __p) - : __base_(allocator_arg_t(), __alloc, std::move(__p)) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__p)) {} # endif // _LIBCPP_STD_VER >= 23 // [tuple.assign] diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/move_ctor_sfinae.compile.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/move_ctor_sfinae.compile.pass.cpp new file mode 100644 index 0000000000000..dc50385b4654c --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/move_ctor_sfinae.compile.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that tuple's move constructor properly SFINAES. +// This is a regression test for https://github.com/llvm/llvm-project/pull/151654#issuecomment-3205410955 + +// UNSUPPORTED: c++03, c++11, c++14 + +#include +#include +#include + +struct S { + S(const S&) = delete; + S& operator=(const S&) = delete; + S(S&&) = default; + S& operator=(S&&) = default; +}; + +using T = std::tuple>; + +void func() { (void)std::is_trivially_move_constructible::value; }