diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -43,4 +43,15 @@ API Changes ----------- -- ... +- There has been several changes in the tuple constructors provided by libc++. + Those changes were made as part of an effort to regularize libc++'s tuple + implementation, which contained several subtle bugs due to these extensions. + If you notice a build breakage when initializing a tuple, make sure you + properly initialize all the tuple elements - this is probably the culprit. + + In particular, the extension allowing tuples to be constructed from fewer + elements than the number of elements in the tuple (in which case the remaining + elements would be default-constructed) has been removed. See https://godbolt.org/z/sqozjd. + + Also, the extension allowing a tuple to be constructed from an array has been + removed. See https://godbolt.org/z/5esqbW. diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -165,33 +165,6 @@ headers. The intended use case is for clients who wish to use the libc++ headers without taking a dependency on the libc++ library itself. -**_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION**: - This macro is used to re-enable an extension in `std::tuple` which allowed - it to be implicitly constructed from fewer initializers than contained - elements. Elements without an initializer are default constructed. For example: - - .. code-block:: cpp - - std::tuple foo() { - return {"hello world", 42}; // default constructs error_code - } - - - Since libc++ 4.0 this extension has been disabled by default. This macro - may be defined to re-enable it in order to support existing code that depends - on the extension. New use of this extension should be discouraged. - See `PR 27374 `_ for more information. - - Note: The "reduced-arity-initialization" extension is still offered but only - for explicit conversions. Example: - - .. code-block:: cpp - - auto foo() { - using Tup = std::tuple; - return Tup{"hello world", 42}; // explicit constructor called. OK. - } - **_LIBCPP_DISABLE_ADDITIONAL_DIAGNOSTICS**: This macro disables the additional diagnostics generated by libc++ using the `diagnose_if` attribute. These additional diagnostics include checks for: diff --git a/libcxx/include/tuple b/libcxx/include/tuple --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -448,165 +448,6 @@ _BaseT __base_; -#if defined(_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION) - static constexpr bool _EnableImplicitReducedArityExtension = true; -#else - static constexpr bool _EnableImplicitReducedArityExtension = false; -#endif - - template - struct _PackExpandsToThisTuple : false_type {}; - - template - struct _PackExpandsToThisTuple<_Arg> - : is_same::type, tuple> {}; - - template - struct _CheckArgsConstructor : __check_tuple_constructor_fail {}; - - template - struct _CheckArgsConstructor - { - template - static constexpr bool __enable_implicit_default() { - return __all<__is_implicitly_default_constructible<_Tp>::value... >::value; - } - - template - static constexpr bool __enable_explicit_default() { - return - __all::value...>::value && - !__enable_implicit_default< >(); - } - - - template - static constexpr bool __enable_explicit() { - return - __tuple_constructible< - tuple<_Args...>, - typename __make_tuple_types::type - >::value && - !__tuple_convertible< - tuple<_Args...>, - typename __make_tuple_types::type - >::value && - __all_default_constructible< - typename __make_tuple_types::type - >::value; - } - - template - static constexpr bool __enable_implicit() { - return - __tuple_constructible< - tuple<_Args...>, - typename __make_tuple_types::type - >::value && - __tuple_convertible< - tuple<_Args...>, - typename __make_tuple_types::type - >::value && - __all_default_constructible< - typename __make_tuple_types::type - >::value; - } - }; - - template - struct _CheckTupleLikeConstructor : __check_tuple_constructor_fail {}; - - template - struct _CheckTupleLikeConstructor - { - template - static constexpr bool __enable_implicit() { - return __tuple_constructible<_Tuple, tuple>::value - && __tuple_convertible<_Tuple, tuple>::value; - } - - template - static constexpr bool __enable_explicit() { - return __tuple_constructible<_Tuple, tuple>::value - && !__tuple_convertible<_Tuple, tuple>::value; - } - }; - - template - struct _CheckTupleLikeConstructor - { - // This trait is used to disable the tuple-like constructor when - // the UTypes... constructor should be selected instead. - // See LWG issue #2549. - template - using _PreferTupleLikeConstructor = _Or< - // Don't attempt the two checks below if the tuple we are given - // has the same type as this tuple. - _IsSame<__uncvref_t<_Tuple>, tuple>, - _Lazy<_And, - _Not>, - _Not> - > - >; - - template - static constexpr bool __enable_implicit() { - return _And< - __tuple_constructible<_Tuple, tuple>, - __tuple_convertible<_Tuple, tuple>, - _PreferTupleLikeConstructor<_Tuple> - >::value; - } - - template - static constexpr bool __enable_explicit() { - return _And< - __tuple_constructible<_Tuple, tuple>, - _PreferTupleLikeConstructor<_Tuple>, - _Not<__tuple_convertible<_Tuple, tuple>> - >::value; - } - }; - - template - using _EnableImplicitTupleLikeConstructor = _EnableIf< - _CheckTupleLikeConstructor< - __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value - && !_PackExpandsToThisTuple<_Tuple>::value - && (!is_lvalue_reference<_Tuple>::value || !_DisableIfLValue) - >::template __enable_implicit<_Tuple>(), - bool - >; - - template - using _EnableExplicitTupleLikeConstructor = _EnableIf< - _CheckTupleLikeConstructor< - __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value - && !_PackExpandsToThisTuple<_Tuple>::value - && (!is_lvalue_reference<_Tuple>::value || !_DisableIfLValue) - >::template __enable_explicit<_Tuple>(), - bool - >; template friend _LIBCPP_CONSTEXPR_AFTER_CXX11 typename tuple_element<_Jp, tuple<_Up...> >::type& get(tuple<_Up...>&) _NOEXCEPT; template friend _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -616,57 +457,69 @@ template friend _LIBCPP_CONSTEXPR_AFTER_CXX11 const typename tuple_element<_Jp, tuple<_Up...> >::type&& get(const tuple<_Up...>&&) _NOEXCEPT; public: + // [tuple.cnstr] - template ::__enable_implicit_default() - , void*> = nullptr> + // tuple() constructors (including allocator_arg_t variants) + template class _IsImpDefault = __is_implicitly_default_constructible, _EnableIf< + _And< + _IsImpDefault<_Tp>... // explicit check + >::value + , int> = 0> _LIBCPP_INLINE_VISIBILITY constexpr tuple() - _NOEXCEPT_(__all::value...>::value) {} - - template ::__enable_explicit_default() - , void*> = nullptr> - explicit _LIBCPP_INLINE_VISIBILITY constexpr - tuple() - _NOEXCEPT_(__all::value...>::value) {} + _NOEXCEPT_(_And...>::value) + { } - tuple(tuple const&) = default; - tuple(tuple&&) = default; + template class _IsImpDefault = __is_implicitly_default_constructible, + template class _IsDefault = is_default_constructible, _EnableIf< + _And< + _IsDefault<_Tp>..., + _Not<_Lazy<_And, _IsImpDefault<_Tp>...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR + explicit tuple() + _NOEXCEPT_(_And...>::value) + { } - template ::value >::__enable_implicit_default() - , void*> = nullptr - > + template class _IsImpDefault = __is_implicitly_default_constructible, _EnableIf< + _And< + _IsImpDefault<_Tp>... // explicit check + >::value + , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - tuple(_AllocArgT, _Alloc const& __a) + tuple(allocator_arg_t, _Alloc const& __a) : __base_(allocator_arg_t(), __a, __tuple_indices<>(), __tuple_types<>(), typename __make_tuple_indices::type(), __tuple_types<_Tp...>()) {} - template ::value>::__enable_explicit_default() - , void*> = nullptr - > - explicit _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - tuple(_AllocArgT, _Alloc const& __a) + template class _IsImpDefault = __is_implicitly_default_constructible, + template class _IsDefault = is_default_constructible, _EnableIf< + _And< + _IsDefault<_Tp>..., + _Not<_Lazy<_And, _IsImpDefault<_Tp>...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + explicit tuple(allocator_arg_t, _Alloc const& __a) : __base_(allocator_arg_t(), __a, __tuple_indices<>(), __tuple_types<>(), typename __make_tuple_indices::type(), __tuple_types<_Tp...>()) {} - template ::template __enable_implicit<_Tp const&...>(), - bool - >::type = false - > + // tuple(const T&...) constructors (including allocator_arg_t variants) + template class _And = _And, _EnableIf< + _And< + _BoolConstant= 1>, + is_copy_constructible<_Tp>..., + is_convertible... // explicit check + >::value + , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - tuple(const _Tp& ... __t) _NOEXCEPT_((__all::value...>::value)) + tuple(const _Tp& ... __t) + _NOEXCEPT_(_And...>::value) : __base_(typename __make_tuple_indices::type(), typename __make_tuple_types::type(), typename __make_tuple_indices<0>::type(), @@ -674,17 +527,16 @@ __t... ) {} - template ::template __enable_explicit<_Tp const&...>(), - bool - >::type = false - > + template class _And = _And, _EnableIf< + _And< + _BoolConstant= 1>, + is_copy_constructible<_Tp>..., + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - explicit tuple(const _Tp& ... __t) _NOEXCEPT_((__all::value...>::value)) + explicit tuple(const _Tp& ... __t) + _NOEXCEPT_(_And...>::value) : __base_(typename __make_tuple_indices::type(), typename __make_tuple_types::type(), typename __make_tuple_indices<0>::type(), @@ -692,17 +544,15 @@ __t... ) {} - template ::template __enable_implicit<_Tp const&...>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t) + template class _And = _And, _EnableIf< + _And< + _BoolConstant= 1>, + is_copy_constructible<_Tp>..., + is_convertible... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t) : __base_(allocator_arg_t(), __a, typename __make_tuple_indices::type(), typename __make_tuple_types::type(), @@ -711,18 +561,15 @@ __t... ) {} - template ::template __enable_explicit<_Tp const&...>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - explicit - tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t) + template class _And = _And, _EnableIf< + _And< + _BoolConstant= 1>, + is_copy_constructible<_Tp>..., + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + explicit tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t) : __base_(allocator_arg_t(), __a, typename __make_tuple_indices::type(), typename __make_tuple_types::type(), @@ -731,158 +578,368 @@ __t... ) {} - template ::value, - typename enable_if - < - _CheckArgsConstructor< - sizeof...(_Up) == sizeof...(_Tp) - && !_PackIsTuple - >::template __enable_implicit<_Up...>() || - _CheckArgsConstructor< - _EnableImplicitReducedArityExtension - && sizeof...(_Up) < sizeof...(_Tp) - && !_PackIsTuple - >::template __enable_implicit<_Up...>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - tuple(_Up&&... __u) - _NOEXCEPT_(( - is_nothrow_constructible<_BaseT, - typename __make_tuple_indices::type, - typename __make_tuple_types::type, - typename __make_tuple_indices::type, - typename __make_tuple_types::type, - _Up... - >::value - )) - : __base_(typename __make_tuple_indices::type(), + // tuple(U&& ...) constructors (including allocator_arg_t variants) + template struct _IsThisTuple : false_type { }; + template struct _IsThisTuple<_Up> : is_same<__uncvref_t<_Up>, tuple> { }; + + template + struct _EnableUTypesCtor : _And< + _BoolConstant= 1>, + _Not<_IsThisTuple<_Up...> >, // extension to allow mis-behaved user constructors + is_constructible<_Tp, _Up>... + > { }; + + template , + _EnableUTypesCtor<_Up...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + tuple(_Up&&... __u) + _NOEXCEPT_((_And...>::value)) + : __base_(typename __make_tuple_indices::type(), typename __make_tuple_types::type(), typename __make_tuple_indices::type(), typename __make_tuple_types::type(), _VSTD::forward<_Up>(__u)...) {} - template ::value - >::template __enable_explicit<_Up...>() || - _CheckArgsConstructor< - !_EnableImplicitReducedArityExtension - && sizeof...(_Up) < sizeof...(_Tp) - && !_PackExpandsToThisTuple<_Up...>::value - >::template __enable_implicit<_Up...>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - explicit - tuple(_Up&&... __u) - _NOEXCEPT_(( - is_nothrow_constructible<_BaseT, - typename __make_tuple_indices::type, - typename __make_tuple_types::type, - typename __make_tuple_indices::type, - typename __make_tuple_types::type, - _Up... - >::value - )) - : __base_(typename __make_tuple_indices::type(), + template , + _EnableUTypesCtor<_Up...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit tuple(_Up&&... __u) + _NOEXCEPT_((_And...>::value)) + : __base_(typename __make_tuple_indices::type(), typename __make_tuple_types::type(), typename __make_tuple_indices::type(), typename __make_tuple_types::type(), _VSTD::forward<_Up>(__u)...) {} - template ::value - >::template __enable_implicit<_Up...>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u) - : __base_(allocator_arg_t(), __a, + template , + _EnableUTypesCtor<_Up...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u) + : __base_(allocator_arg_t(), __a, typename __make_tuple_indices::type(), typename __make_tuple_types::type(), typename __make_tuple_indices::type(), typename __make_tuple_types::type(), _VSTD::forward<_Up>(__u)...) {} - template ::value - >::template __enable_explicit<_Up...>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - explicit - tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u) - : __base_(allocator_arg_t(), __a, + template , + _EnableUTypesCtor<_Up...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + explicit tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u) + : __base_(allocator_arg_t(), __a, typename __make_tuple_indices::type(), typename __make_tuple_types::type(), typename __make_tuple_indices::type(), typename __make_tuple_types::type(), _VSTD::forward<_Up>(__u)...) {} - template = false> - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value)) - : __base_(_VSTD::forward<_Tuple>(__t)) {} + // Copy and move constructors (including the allocator_arg_t variants) + tuple(const tuple&) = default; + tuple(tuple&&) = default; - template = false> - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - tuple(const _Tuple& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, const _Tuple&>::value)) - : __base_(__t) {} - template = false> - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - explicit - tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value)) - : __base_(_VSTD::forward<_Tuple>(__t)) {} + template class _And = _And, _EnableIf< + _And...>::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc& __alloc, const tuple& __t) + : __base_(allocator_arg_t(), __alloc, __t) + { } + + template class _And = _And, _EnableIf< + _And...>::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc& __alloc, tuple&& __t) + : __base_(allocator_arg_t(), __alloc, _VSTD::move(__t)) + { } + + // tuple(const tuple&) constructors (including allocator_arg_t variants) + template + struct _EnableCopyFromOtherTuple : _And< + _Or< + _BoolConstant, + // _Tp and _Up are 1-element packs - the pack expansions look + // weird to avoid tripping up the type traits in degenerate cases + _Lazy<_And, + _Not >..., + _Not&, _Tp> >..., + _Not&> >... + > + >, + is_constructible<_Tp, const _Up&>... + > { }; - template = false> - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - explicit - tuple(const _Tuple& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, const _Tuple&>::value)) - : __base_(__t) {} + template , + _EnableCopyFromOtherTuple<_Up...>, + is_convertible... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + tuple(const tuple<_Up...>& __t) + _NOEXCEPT_((_And...>::value)) + : __base_(__t) + { } - template ::value - >::template __enable_implicit<_Tuple>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t) - : __base_(allocator_arg_t(), __a, _VSTD::forward<_Tuple>(__t)) {} + template , + _EnableCopyFromOtherTuple<_Up...>, + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit tuple(const tuple<_Up...>& __t) + _NOEXCEPT_((_And...>::value)) + : __base_(__t) + { } - template ::value - >::template __enable_explicit<_Tuple>(), - bool - >::type = false - > - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - explicit - tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t) - : __base_(allocator_arg_t(), __a, _VSTD::forward<_Tuple>(__t)) {} + template , + _EnableCopyFromOtherTuple<_Up...>, + is_convertible... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t) + : __base_(allocator_arg_t(), __a, __t) + { } + + template , + _EnableCopyFromOtherTuple<_Up...>, + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + explicit tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t) + : __base_(allocator_arg_t(), __a, __t) + { } + + // tuple(tuple&&) constructors (including allocator_arg_t variants) + template + struct _EnableMoveFromOtherTuple : _And< + _Or< + _BoolConstant, + // _Tp and _Up are 1-element packs - the pack expansions look + // weird to avoid tripping up the type traits in degenerate cases + _Lazy<_And, + _Not >..., + _Not, _Tp> >..., + _Not > >... + > + >, + is_constructible<_Tp, _Up>... + > { }; + + template , + _EnableMoveFromOtherTuple<_Up...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + tuple(tuple<_Up...>&& __t) + _NOEXCEPT_((_And...>::value)) + : __base_(_VSTD::move(__t)) + { } + + template , + _EnableMoveFromOtherTuple<_Up...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit tuple(tuple<_Up...>&& __t) + _NOEXCEPT_((_And...>::value)) + : __base_(_VSTD::move(__t)) + { } + + template , + _EnableMoveFromOtherTuple<_Up...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t) + : __base_(allocator_arg_t(), __a, _VSTD::move(__t)) + { } + + template , + _EnableMoveFromOtherTuple<_Up...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + explicit tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t) + : __base_(allocator_arg_t(), __a, _VSTD::move(__t)) + { } + + // tuple(const pair&) constructors (including allocator_arg_t variants) + template + struct _EnableImplicitCopyFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, const _Up1&>, + is_constructible<_SecondType<_DependentTp...>, const _Up2&>, + is_convertible >, // explicit check + is_convertible > + > { }; + + template + struct _EnableExplicitCopyFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, const _Up1&>, + is_constructible<_SecondType<_DependentTp...>, const _Up2&>, + _Not > >, // explicit check + _Not > > + > { }; + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + tuple(const pair<_Up1, _Up2>& __p) + _NOEXCEPT_((_And< + is_nothrow_constructible<_FirstType<_Tp...>, const _Up1&>, + is_nothrow_constructible<_SecondType<_Tp...>, const _Up2&> + >::value)) + : __base_(__p) + { } + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit tuple(const pair<_Up1, _Up2>& __p) + _NOEXCEPT_((_And< + is_nothrow_constructible<_FirstType<_Tp...>, const _Up1&>, + is_nothrow_constructible<_SecondType<_Tp...>, const _Up2&> + >::value)) + : __base_(__p) + { } + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p) + : __base_(allocator_arg_t(), __a, __p) + { } + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + explicit tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p) + : __base_(allocator_arg_t(), __a, __p) + { } + + // tuple(pair&&) constructors (including allocator_arg_t variants) + template + struct _EnableImplicitMoveFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, _Up1>, + is_constructible<_SecondType<_DependentTp...>, _Up2>, + is_convertible<_Up1, _FirstType<_DependentTp...> >, // explicit check + is_convertible<_Up2, _SecondType<_DependentTp...> > + > { }; + + template + struct _EnableExplicitMoveFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, _Up1>, + is_constructible<_SecondType<_DependentTp...>, _Up2>, + _Not > >, // explicit check + _Not > > + > { }; + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY + tuple(pair<_Up1, _Up2>&& __p) + _NOEXCEPT_((_And< + is_nothrow_constructible<_FirstType<_Tp...>, _Up1>, + is_nothrow_constructible<_SecondType<_Tp...>, _Up2> + >::value)) + : __base_(_VSTD::move(__p)) + { } + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY + explicit tuple(pair<_Up1, _Up2>&& __p) + _NOEXCEPT_((_And< + is_nothrow_constructible<_FirstType<_Tp...>, _Up1>, + is_nothrow_constructible<_SecondType<_Tp...>, _Up2> + >::value)) + : __base_(_VSTD::move(__p)) + { } + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p) + : __base_(allocator_arg_t(), __a, _VSTD::move(__p)) + { } + + template class _And = _And, _EnableIf< + _And< + _BoolConstant, + _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + explicit tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p) + : __base_(allocator_arg_t(), __a, _VSTD::move(__p)) + { } // [tuple.assign] _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -3206,18 +3206,18 @@ template void __test_implicit_default_constructible(_Tp); -template ::value> +template ::type> struct __is_implicitly_default_constructible : false_type { }; template -struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), true> +struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), true_type> : true_type { }; template -struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), false> +struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), false_type> : false_type { }; #endif // !C++03 diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/disable_reduced_arity_initialization_extension.pass.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/disable_reduced_arity_initialization_extension.pass.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/disable_reduced_arity_initialization_extension.pass.cpp +++ /dev/null @@ -1,109 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// - -// template class tuple; - -// template -// explicit tuple(UTypes&&... u); - -// UNSUPPORTED: c++03 - -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "test_convertible.h" -#include "MoveOnly.h" - -#if defined(_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION) -#error This macro should not be defined by default -#endif - -struct NoDefault { NoDefault() = delete; }; - - -// Make sure the _Up... constructor SFINAEs out when the types that -// are not explicitly initialized are not all default constructible. -// Otherwise, std::is_constructible would return true but instantiating -// the constructor would fail. -void test_default_constructible_extension_sfinae() -{ - typedef MoveOnly MO; - typedef NoDefault ND; - { - typedef std::tuple Tuple; - static_assert(!std::is_constructible::value, ""); - static_assert(std::is_constructible::value, ""); - static_assert(test_convertible(), ""); - } - { - typedef std::tuple Tuple; - static_assert(!std::is_constructible::value, ""); - static_assert(std::is_constructible::value, ""); - static_assert(test_convertible(), ""); - } - { - // Same idea as above but with a nested tuple type. - typedef std::tuple Tuple; - typedef std::tuple NestedTuple; - - static_assert(!std::is_constructible< - NestedTuple, MO, MO, MO, MO>::value, ""); - static_assert(std::is_constructible< - NestedTuple, MO, Tuple, MO, MO>::value, ""); - } -} - -using ExplicitTup = std::tuple; -ExplicitTup doc_example() { - return ExplicitTup{"hello world", 42}; // explicit constructor called. OK. -} - -// Test that the example given in UsingLibcxx.rst actually works. -void test_example_from_docs() { - auto tup = doc_example(); - assert(std::get<0>(tup) == "hello world"); - assert(std::get<1>(tup) == 42); - assert(std::get<2>(tup) == std::error_code{}); -} - -int main(int, char**) -{ - { - using E = MoveOnly; - using Tup = std::tuple; - // Test that the reduced arity initialization extension is only - // allowed on the explicit constructor. - static_assert(test_convertible(), ""); - - Tup t(E(0), E(1)); - static_assert(std::is_constructible::value, ""); - static_assert(!test_convertible(), ""); - assert(std::get<0>(t) == E(0)); - assert(std::get<1>(t) == E(1)); - assert(std::get<2>(t) == E()); - - Tup t2(E(0)); - static_assert(std::is_constructible::value, ""); - static_assert(!test_convertible(), ""); - assert(std::get<0>(t2) == E(0)); - assert(std::get<1>(t2) == E()); - assert(std::get<2>(t2) == E()); - } - // Check that SFINAE is properly applied with the default reduced arity - // constructor extensions. - test_default_constructible_extension_sfinae(); - test_example_from_docs(); - - return 0; -} diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/enable_reduced_arity_initialization_extension.pass.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/enable_reduced_arity_initialization_extension.pass.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/enable_reduced_arity_initialization_extension.pass.cpp +++ /dev/null @@ -1,118 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// - -// template class tuple; - -// template -// explicit tuple(UTypes&&... u); - -// UNSUPPORTED: c++03 - -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION - -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "test_convertible.h" -#include "MoveOnly.h" - - -struct NoDefault { NoDefault() = delete; }; - - -// Make sure the _Up... constructor SFINAEs out when the types that -// are not explicitly initialized are not all default constructible. -// Otherwise, std::is_constructible would return true but instantiating -// the constructor would fail. -void test_default_constructible_extension_sfinae() -{ - typedef MoveOnly MO; - typedef NoDefault ND; - { - typedef std::tuple Tuple; - static_assert(!std::is_constructible::value, ""); - static_assert(std::is_constructible::value, ""); - static_assert(test_convertible(), ""); - } - { - typedef std::tuple Tuple; - static_assert(!std::is_constructible::value, ""); - static_assert(std::is_constructible::value, ""); - static_assert(test_convertible(), ""); - } - { - // Same idea as above but with a nested tuple type. - typedef std::tuple Tuple; - typedef std::tuple NestedTuple; - - static_assert(!std::is_constructible< - NestedTuple, MO, MO, MO, MO>::value, ""); - static_assert(std::is_constructible< - NestedTuple, MO, Tuple, MO, MO>::value, ""); - } - { - typedef std::tuple Tuple; - typedef std::tuple NestedTuple; - - static_assert(std::is_constructible< - NestedTuple, MO, MO, MO, MO>::value, ""); - static_assert(test_convertible< - NestedTuple, MO, MO, MO, MO>(), ""); - - static_assert(std::is_constructible< - NestedTuple, MO, Tuple, MO, MO>::value, ""); - static_assert(test_convertible< - NestedTuple, MO, Tuple, MO, MO>(), ""); - } -} - -std::tuple doc_example() { - return {"hello world", 42}; -} - -// Test that the example given in UsingLibcxx.rst actually works. -void test_example_from_docs() { - auto tup = doc_example(); - assert(std::get<0>(tup) == "hello world"); - assert(std::get<1>(tup) == 42); - assert(std::get<2>(tup) == std::error_code{}); -} - -int main(int, char**) -{ - - { - using E = MoveOnly; - using Tup = std::tuple; - static_assert(test_convertible(), ""); - - Tup t = {E(0), E(1)}; - static_assert(test_convertible(), ""); - assert(std::get<0>(t) == E(0)); - assert(std::get<1>(t) == E(1)); - assert(std::get<2>(t) == E()); - - Tup t2 = {E(0)}; - static_assert(test_convertible(), ""); - assert(std::get<0>(t2) == E(0)); - assert(std::get<1>(t2) == E()); - assert(std::get<2>(t2) == E()); - } - // Check that SFINAE is properly applied with the default reduced arity - // constructor extensions. - test_default_constructible_extension_sfinae(); - test_example_from_docs(); - - return 0; -} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp @@ -11,7 +11,7 @@ // -// See llvm.org/PR20855 +// See https://llvm.org/PR20855. #include #include diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp @@ -12,13 +12,10 @@ // template class tuple; -// template -// tuple(TupleLike&&); -// template -// tuple(std::allocator_arg_t, Alloc const&, TupleLike&&); - // Check that the tuple-like ctors are properly disabled when the UTypes... -// constructor should be selected. See PR22806. +// constructor should be selected. +// +// See https://llvm.org/PR22806. #include #include diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp @@ -16,9 +16,11 @@ // EXPLICIT(...) tuple(UTypes&&...) // Check that the UTypes... ctor is properly disabled before evaluating any -// SFINAE when the tuple-like copy/move ctor should *clearly* be selected +// SFINAE when the copy/move ctor from another tuple should clearly be selected // instead. This happens 'sizeof...(UTypes) == 1' and the first element of -// 'UTypes...' is an instance of the tuple itself. See PR23256. +// 'UTypes...' is an instance of the tuple itself. +// +// See https://llvm.org/PR23256. #include #include diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp @@ -14,11 +14,7 @@ // template tuple(allocator_arg_t, Alloc const&) -// Libc++ has to deduce the 'allocator_arg_t' parameter for this constructor -// as 'AllocArgT'. Previously libc++ has tried to support tags derived from -// 'allocator_arg_t' by using 'is_base_of'. -// However this breaks whenever a 2-tuple contains a reference to an incomplete -// type as its first parameter. See PR27684. +// See https://llvm.org/PR27684. #include #include diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp @@ -9,11 +9,8 @@ // UNSUPPORTED: c++03 -// +// See https://llvm.org/PR31384. -// template tuple(TupleLike&&); // libc++ extension - -// See llvm.org/PR31384 #include #include @@ -50,42 +47,51 @@ { std::tuple foo = Derived{42}; ((void)foo); assert(count == 1); - std::tuple bar(Derived{42}); ((void)bar); + Derived d{42}; + std::tuple bar(std::move(d)); ((void)bar); +#if TEST_STD_VER < 17 + assert(count == 1); +#else assert(count == 2); +#endif } count = 0; { std::tuple foo = Derived{42}; ((void)foo); assert(count == 1); - std::tuple bar(Derived{42}); ((void)bar); + Derived d{42}; + std::tuple bar(std::move(d)); ((void)bar); +#if TEST_STD_VER < 17 + assert(count == 1); +#else assert(count == 2); +#endif } count = 0; { - static_assert(!std::is_convertible< - ExplicitDerived, std::tuple>::value, ""); - std::tuple bar(ExplicitDerived{42}); ((void)bar); + static_assert(!std::is_convertible, std::tuple>::value, ""); + ExplicitDerived d{42}; + std::tuple bar(std::move(d)); ((void)bar); +#if TEST_STD_VER < 17 + assert(count == 0); +#else assert(count == 1); +#endif } count = 0; { - // FIXME: Libc++ incorrectly rejects this code. -#ifndef _LIBCPP_VERSION std::tuple foo = ExplicitDerived{42}; ((void)foo); - static_assert(std::is_convertible< - ExplicitDerived, std::tuple>::value, - "correct STLs accept this"); -#else - static_assert(!std::is_convertible< - ExplicitDerived, std::tuple>::value, - "libc++ incorrectly rejects this"); -#endif + static_assert(std::is_convertible, std::tuple>::value, ""); assert(count == 0); - std::tuple bar(ExplicitDerived{42}); ((void)bar); + ExplicitDerived d{42}; + std::tuple bar(std::move(d)); ((void)bar); +#if TEST_STD_VER < 17 + assert(count == 0); +#else assert(count == 1); +#endif } count = 0; - return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp @@ -36,11 +36,9 @@ struct NoDefault { NoDefault() = delete; }; -// Make sure the _Up... constructor SFINAEs out when the types that -// are not explicitly initialized are not all default constructible. -// Otherwise, std::is_constructible would return true but instantiating -// the constructor would fail. -void test_default_constructible_extension_sfinae() +// Make sure the _Up... constructor SFINAEs out when there are fewer +// constructor arguments than tuple elements. +void test_sfinae_missing_elements() { { typedef std::tuple Tuple; @@ -83,23 +81,6 @@ MoveOnly, Tuple, MoveOnly, MoveOnly >::value, ""); } - // testing extensions -#ifdef _LIBCPP_VERSION - { - typedef std::tuple Tuple; - typedef std::tuple NestedTuple; - - static_assert(std::is_constructible< - NestedTuple, - MoveOnly, MoveOnly, MoveOnly, MoveOnly - >::value, ""); - - static_assert(std::is_constructible< - NestedTuple, - MoveOnly, Tuple, MoveOnly, MoveOnly - >::value, ""); - } -#endif } int main(int, char**) @@ -121,28 +102,6 @@ assert(std::get<1>(t) == 1); assert(std::get<2>(t) == 2); } - // extensions -#ifdef _LIBCPP_VERSION - { - using E = MoveOnly; - using Tup = std::tuple; - // Test that the reduced arity initialization extension is only - // allowed on the explicit constructor. - static_assert(test_convertible(), ""); - - Tup t(E(0), E(1)); - static_assert(!test_convertible(), ""); - assert(std::get<0>(t) == E(0)); - assert(std::get<1>(t) == E(1)); - assert(std::get<2>(t) == E()); - - Tup t2(E(0)); - static_assert(!test_convertible(), ""); - assert(std::get<0>(t2) == E(0)); - assert(std::get<1>(t2) == E()); - assert(std::get<2>(t2) == E()); - } -#endif #if TEST_STD_VER > 11 { constexpr std::tuple t0{Empty()}; @@ -153,9 +112,8 @@ static_assert(std::get<0>(t).id_ == 3, ""); } #endif - // Check that SFINAE is properly applied with the default reduced arity - // constructor extensions. - test_default_constructible_extension_sfinae(); + + test_sfinae_missing_elements(); return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp @@ -15,10 +15,6 @@ // template // explicit(see-below) tuple(allocator_arg_t, const Alloc& a); -// NOTE: this constructor does not currently support tags derived from -// allocator_arg_t because libc++ has to deduce the parameter as a template -// argument. See PR27684 (https://llvm.org/PR27684) - #include #include @@ -94,6 +90,14 @@ assert(!alloc_last::allocator_constructed); assert(std::get<2>(t) == alloc_last()); } + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::tuple<> t1(derived, A1()); + std::tuple t2(derived, A1()); + std::tuple t3(derived, A1()); + } { // Test that the uses-allocator default constructor does not evaluate // its SFINAE when it otherwise shouldn't be selected. Do this by diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp @@ -95,6 +95,14 @@ assert(!alloc_last::allocator_constructed); assert(std::get<2>(t) == alloc_last(3)); } + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::tuple<> t1(derived, A1()); + std::tuple t2(derived, A1(), 1); + std::tuple t3(derived, A1(), 1, 2); + } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_pair.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_pair.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_pair.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_pair.pass.cpp @@ -56,6 +56,13 @@ assert(std::get<0>(t1) == 2); assert(std::get<1>(t1) == 3); } + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::pair p(1, 2); + std::tuple t(derived, A1(), p); + } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp @@ -87,6 +87,13 @@ std::tuple t2 = {std::allocator_arg, std::allocator{}, t1}; assert(std::get<0>(t2).value == 42); } + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::tuple from(3l); + std::tuple t0(derived, A1(), from); + } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp @@ -101,6 +101,13 @@ std::tuple t2 = {std::allocator_arg, std::allocator{}, std::move(t1)}; assert(std::get<0>(t2).value == 42); } + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::tuple from(3l); + std::tuple t0(derived, A1(), std::move(from)); + } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp @@ -52,8 +52,6 @@ assert(alloc_last::allocator_constructed); assert(std::get<0>(t) == 2); } -// testing extensions -#ifdef _LIBCPP_VERSION { typedef std::tuple T; T t0(2, 3); @@ -77,7 +75,13 @@ assert(std::get<1>(t) == 2); assert(std::get<2>(t) == 3); } -#endif + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::tuple from(3); + std::tuple t0(derived, A1(), from); + } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp @@ -53,8 +53,6 @@ assert(alloc_last::allocator_constructed); assert(std::get<0>(t) == 1); } -// testing extensions -#ifdef _LIBCPP_VERSION { typedef std::tuple T; T t0(0 ,1); @@ -76,7 +74,13 @@ assert(std::get<1>(t) == 2); assert(std::get<2>(t) == 3); } -#endif + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::tuple from(3); + std::tuple t0(derived, A1(), std::move(from)); + } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move_pair.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move_pair.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move_pair.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move_pair.pass.cpp @@ -52,6 +52,13 @@ assert(std::get<0>(t1) == 2); assert(std::get<1>(t1)->id_ == 3); } + { + // Test that we can use a tag derived from allocator_arg_t + struct DerivedFromAllocatorArgT : std::allocator_arg_t { }; + DerivedFromAllocatorArgT derived; + std::pair from(1, 2); + std::tuple t0(derived, A1(), std::move(from)); + } - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp @@ -137,28 +137,6 @@ assert(std::get<2>(t) == 2); assert(std::get<3>(t) == 3); } -// extensions -#ifdef _LIBCPP_VERSION - { - std::tuple t(2); - assert(std::get<0>(t) == 2); - assert(std::get<1>(t) == nullptr); - assert(std::get<2>(t) == ""); - } - { - std::tuple t(2, nullptr); - assert(std::get<0>(t) == 2); - assert(std::get<1>(t) == nullptr); - assert(std::get<2>(t) == ""); - } - { - std::tuple t(2, nullptr, "text"); - assert(std::get<0>(t) == 2); - assert(std::get<1>(t) == nullptr); - assert(std::get<2>(t) == "text"); - assert(std::get<3>(t) == 0.0); - } -#endif return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp @@ -13,7 +13,7 @@ // GCC's implementation of class template deduction is still immature and runs // into issues with libc++. However GCC accepts this code when compiling // against libstdc++. -// XFAIL: gcc-5, gcc-6, gcc-7 +// XFAIL: gcc-5, gcc-6, gcc-7, gcc-8, gcc-9, gcc-10 // diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.lazy.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.lazy.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.lazy.verify.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This test makes sure that we don't evaluate `is_default_constructible` +// too early in std::tuple's default constructor. + +// UNSUPPORTED: c++03 + +#include + +#include "test_macros.h" + +struct Outer { + template + struct Inner { + bool foo = false; + }; + std::tuple> tup; +}; + +Outer x; // expected-no-diagnostics diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp @@ -12,61 +12,18 @@ // UNSUPPORTED: c++03 +// Test the following constructors: +// (1) tuple(Types const&...) +// (2) tuple(UTypes&&...) +// Test that (1) short circuits before evaluating the copy constructor of the +// second argument. Constructor (2) should be selected. + #include #include #include #include "test_macros.h" -template -struct ConstructibleFromT { - ConstructibleFromT() = default; - ConstructibleFromT(ConstructFrom v) : value(v) {} - ConstructFrom value; -}; - -template -struct CtorAssertsT { - bool defaulted; - CtorAssertsT() : defaulted(true) {} - template - constexpr CtorAssertsT(T) : defaulted(false) { - static_assert(!std::is_same::value, ""); - } -}; - -template -struct AllowAssertT { - AllowAssertT() = default; - AllowAssertT(AllowT) {} - template - constexpr AllowAssertT(U) { - static_assert(!std::is_same::value, ""); - } -}; - -// Construct a tuple from pair where T1 and T2 -// are not constructible from ints but T1 is constructible from std::pair. -// This considers the following constructors: -// (1) tuple(TupleLike) -> checks is_constructible -// (2) tuple(UTypes...) -> checks is_constructible> -// and is_default_constructible -// The point of this test is to ensure that the consideration of (1) -// short circuits before evaluating is_constructible, which -// will cause a static assertion. -void test_tuple_like_lazy_sfinae() { -#if defined(_LIBCPP_VERSION) - // This test requires libc++'s reduced arity initialization. - using T1 = ConstructibleFromT>; - using T2 = CtorAssertsT; - std::pair p(42, 100); - std::tuple t(p); - assert(std::get<0>(t).value == p); - assert(std::get<1>(t).defaulted); -#endif -} - - struct NonConstCopyable { NonConstCopyable() = default; explicit NonConstCopyable(int v) : value(v) {} @@ -84,22 +41,11 @@ BlowsUpOnConstCopy(BlowsUpOnConstCopy&) = default; }; -// Test the following constructors: -// (1) tuple(Types const&...) -// (2) tuple(UTypes&&...) -// Test that (1) short circuits before evaluating the copy constructor of the -// second argument. Constructor (2) should be selected. -void test_const_Types_lazy_sfinae() -{ - NonConstCopyable v(42); - BlowsUpOnConstCopy b; - std::tuple> t(v, b); - assert(std::get<0>(t).value == 42); -} - int main(int, char**) { - test_tuple_like_lazy_sfinae(); - test_const_Types_lazy_sfinae(); + NonConstCopyable v(42); + BlowsUpOnConstCopy b; + std::tuple> t(v, b); + assert(std::get<0>(t).value == 42); return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03 - -// - -// template class tuple; - -// template > -// tuple(Tuple &&); -// -// template > -// tuple(Tuple &&); - -// This test checks that we do not evaluate __make_tuple_types -// on the array. - -#include -#include - -#include "test_macros.h" - -// Use 1256 to try and blow the template instantiation depth for all compilers. -typedef std::array array_t; -typedef std::tuple tuple_t; - -int main(int, char**) -{ - array_t arr; - tuple_t tup(arr); - - return 0; -}