diff --git a/libcxx/include/__tuple b/libcxx/include/__tuple --- a/libcxx/include/__tuple +++ b/libcxx/include/__tuple @@ -485,6 +485,10 @@ template static constexpr bool __enable_implicit() { return false; } template + static constexpr bool __delete_explicit() { return false; } + template + static constexpr bool __delete_implicit() { return false; } + template static constexpr bool __enable_assign() { return false; } }; #endif // !defined(_LIBCPP_CXX03_LANG) @@ -546,6 +550,15 @@ }; #endif // _LIBCPP_STD_VER > 14 +template +struct reference_constructs_from_temporary +#if __has_keyword(__reference_binds_to_temporary) + : integral_constant +#else + : false_type +#endif +{}; + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TUPLE diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -88,7 +88,7 @@ } template - static constexpr bool __enable_explicit() { + static constexpr bool __enable_explicit_base() { return is_constructible::value && is_constructible::value && (!is_convertible<_U1, first_type>::value @@ -96,12 +96,36 @@ } template - static constexpr bool __enable_implicit() { + static constexpr bool __binds_to_temporary() { + return reference_constructs_from_temporary::value + || reference_constructs_from_temporary::value; + } + + template + static constexpr bool __enable_explicit() { + return __enable_explicit_base<_U1, _U2>() && !__binds_to_temporary<_U1, _U2>(); + } + + template + static constexpr bool __delete_explicit() { + return __enable_explicit_base<_U1, _U2>() && __binds_to_temporary<_U1, _U2>(); + } + template + static constexpr bool __enable_implicit_base() { return is_constructible::value && is_constructible::value && is_convertible<_U1, first_type>::value && is_convertible<_U2, second_type>::value; } + template + static constexpr bool __enable_implicit() { + return __enable_implicit_base<_U1, _U2>() && !__binds_to_temporary<_U1, _U2>(); + } + + template + static constexpr bool __delete_implicit() { + return __enable_implicit_base<_U1, _U2>() && __binds_to_temporary<_U1, _U2>(); + } }; template @@ -182,6 +206,16 @@ is_nothrow_constructible::value)) : first(_VSTD::forward<_U1>(__u1)), second(_VSTD::forward<_U2>(__u2)) {} + template < +#if _LIBCPP_STD_VER > 20 // http://wg21.link/P1951 + class _U1 = _T1, class _U2 = _T2, +#else + class _U1, class _U2, +#endif + typename enable_if<_CheckArgs::template __delete_explicit<_U1, _U2>()>::type* = nullptr + > + explicit pair(_U1&&, _U2&&) = delete; + template < #if _LIBCPP_STD_VER > 20 // http://wg21.link/P1951 class _U1 = _T1, class _U2 = _T2, @@ -196,35 +230,88 @@ is_nothrow_constructible::value)) : first(_VSTD::forward<_U1>(__u1)), second(_VSTD::forward<_U2>(__u2)) {} + template < +#if _LIBCPP_STD_VER > 20 // http://wg21.link/P1951 + class _U1 = _T1, class _U2 = _T2, +#else + class _U1, class _U2, +#endif + typename enable_if<_CheckArgs::template __delete_implicit<_U1, _U2>()>::type* = nullptr + > + pair(_U1&&, _U2&&) = delete; + + template() + >::type* = nullptr> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit pair(pair<_U1, _U2>& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) + : first(__p.first), second(__p.second) {} + template() + _CheckArgs::template __delete_explicit<_U1&, _U2&>() + >::type* = nullptr> + explicit pair(pair<_U1, _U2>& __p) = delete; + + template() >::type* = nullptr> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - explicit pair(pair<_U1, _U2> const& __p) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + pair(pair<_U1, _U2>& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) : first(__p.first), second(__p.second) {} template() + _CheckArgs::template __delete_implicit<_U1&, _U2&>() + >::type* = nullptr> + pair(pair<_U1, _U2>&) = delete; + + template() >::type* = nullptr> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - pair(pair<_U1, _U2> const& __p) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + explicit pair(const pair<_U1, _U2>& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) : first(__p.first), second(__p.second) {} template() + _CheckArgs::template __delete_explicit() + >::type* = nullptr> + explicit pair(const pair<_U1, _U2>& __p) = delete; + + template() >::type* = nullptr> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - explicit pair(pair<_U1, _U2>&&__p) + pair(const pair<_U1, _U2>& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) + : first(__p.first), second(__p.second) {} + + template() + >::type* = nullptr> + pair(const pair<_U1, _U2>&) = delete; + + template() + >::type* = nullptr> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit pair(pair<_U1, _U2>&& __p) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(_VSTD::forward<_U1>(__p.first)), second(_VSTD::forward<_U2>(__p.second)) {} template() + _CheckArgs::template __delete_explicit<_U1&&, _U2&&>() + >::type* = nullptr> + explicit pair(pair<_U1, _U2>&& __p) = delete; + + template() >::type* = nullptr> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 pair(pair<_U1, _U2>&& __p) @@ -232,6 +319,39 @@ is_nothrow_constructible::value)) : first(_VSTD::forward<_U1>(__p.first)), second(_VSTD::forward<_U2>(__p.second)) {} + template() + >::type* = nullptr> + pair(pair<_U1, _U2>&&) = delete; + + template() + >::type* = nullptr> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit pair(const pair<_U1, _U2>&& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) + : first(_VSTD::forward(__p.first)), second(_VSTD::forward(__p.second)) {} + + template() + >::type* = nullptr> + explicit pair(const pair<_U1, _U2>&& __p) = delete; + + template() + >::type* = nullptr> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + pair(const pair<_U1, _U2>&& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) + : first(_VSTD::forward(__p.first)), second(_VSTD::forward(__p.second)) {} + + template() + >::type* = nullptr> + pair(const pair<_U1, _U2>&&) = delete; + template::template __enable_explicit<_Tuple>() >::type* = nullptr> diff --git a/libcxx/include/tuple b/libcxx/include/tuple --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -594,17 +594,33 @@ template struct _IsThisTuple : false_type { }; template struct _IsThisTuple<_Up> : is_same<__uncvref_t<_Up>, tuple> { }; + template struct _CheckAllocatorArg : false_type { }; + template + struct _CheckAllocatorArg, _U0, _Tail...> + : integral_constant, allocator_arg_t>::value && + !is_same<__uncvref_t<_T0>, allocator_arg_t>::value> + { }; + template struct _EnableUTypesCtor : _And< _BoolConstant= 1>, _Not<_IsThisTuple<_Up...> >, // extension to allow mis-behaved user constructors + _Not<_CheckAllocatorArg>, is_constructible<_Tp, _Up>... > { }; + template + struct _BindsReferenceToTemporary : + _Not<_And<_Not>...>> + { }; + template , _EnableUTypesCtor<_Up...>, + _Not<_BindsReferenceToTemporary<_Up...>>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -621,6 +637,17 @@ _And< _BoolConstant, _EnableUTypesCtor<_Up...>, + _BindsReferenceToTemporary<_Up...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + tuple(_Up&&...) = delete; + + template , + _EnableUTypesCtor<_Up...>, + _Not<_BindsReferenceToTemporary<_Up...>>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -633,10 +660,21 @@ typename __make_tuple_types::type(), _VSTD::forward<_Up>(__u)...) {} + template , + _EnableUTypesCtor<_Up...>, + _BindsReferenceToTemporary<_Up...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + explicit tuple(_Up&&...) = delete; + template , _EnableUTypesCtor<_Up...>, + _Not<_BindsReferenceToTemporary<_Up...>>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -653,6 +691,17 @@ _And< _BoolConstant, _EnableUTypesCtor<_Up...>, + _BindsReferenceToTemporary<_Up...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc&, _Up&&...) = delete; + + template , + _EnableUTypesCtor<_Up...>, + _Not<_BindsReferenceToTemporary<_Up...>>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -665,6 +714,16 @@ typename __make_tuple_types::type(), _VSTD::forward<_Up>(__u)...) {} + template , + _EnableUTypesCtor<_Up...>, + _BindsReferenceToTemporary<_Up...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc&, _Up&&...) = delete; + // Copy and move constructors (including the allocator_arg_t variants) tuple(const tuple&) = default; tuple(tuple&&) = default; @@ -683,26 +742,128 @@ : __base_(allocator_arg_t(), __alloc, _VSTD::move(__t)) { } - // tuple(const tuple&) constructors (including allocator_arg_t variants) - template - struct _EnableCopyFromOtherTuple : _And< + template using _Lref = _Up&; + template using _Rref = _Up&&; + template using _Clref = _Up const&; + template using _Crref = _Up const&&; + + // tuple(tuple&) constructors (including allocator_arg_t variants) + template class _Ref, class ..._Up> + struct _EnableConstructFromOtherTuple : _And< _Not, tuple<_Up...> > >, _Lazy<_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&, _Tp> >..., - _Not&> >... + _Not>, _Tp> >..., + _Not>> >... > >, - is_constructible<_Tp, const _Up&>... + is_constructible<_Tp, _Ref<_Up>>... > { }; template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _Not<_BindsReferenceToTemporary<_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_(__t) + { } + + template , + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _BindsReferenceToTemporary<_Up&...>, + is_convertible<_Up&, _Tp>... // explicit check + >::value + , int> = 0> + tuple(tuple<_Up...>&) = delete; + + template , + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _Not<_BindsReferenceToTemporary<_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_(__t) + { } + + template , + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _BindsReferenceToTemporary<_Up&...>, + _Not<_Lazy<_And, is_convertible<_Up&, _Tp>...> > // explicit check + >::value + , int> = 0> + explicit tuple(tuple<_Up...>&) = delete; + + template , + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _Not<_BindsReferenceToTemporary<_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, __t) + { } + + template , + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _BindsReferenceToTemporary< _Up&...>, + is_convertible<_Up&, _Tp>... // explicit check + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&) = delete; + + template , + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _Not<_BindsReferenceToTemporary<_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, __t) + { } + + template , + _EnableConstructFromOtherTuple<_Lref, _Up...>, + _BindsReferenceToTemporary<_Up&...>, + _Not<_Lazy<_And, is_convertible<_Up&, _Tp>...> > // explicit check + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&) = delete; + + // tuple(const tuple&) constructors (including allocator_arg_t variants) + + template , + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _Not<_BindsReferenceToTemporary>, is_convertible... // explicit check >::value , int> = 0> @@ -715,7 +876,18 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _BindsReferenceToTemporary, + is_convertible... // explicit check + >::value + , int> = 0> + tuple(const tuple<_Up...>&) = delete; + + template , + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _Not<_BindsReferenceToTemporary>, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -725,10 +897,21 @@ : __base_(__t) { } + template , + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _BindsReferenceToTemporary, + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> + explicit tuple(const tuple<_Up...>&) = delete; + template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _Not<_BindsReferenceToTemporary>, is_convertible... // explicit check >::value , int> = 0> @@ -740,7 +923,18 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _BindsReferenceToTemporary, + is_convertible... // explicit check + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&) = delete; + + template , + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _Not<_BindsReferenceToTemporary>, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -749,26 +943,22 @@ : __base_(allocator_arg_t(), __a, __t) { } - // tuple(tuple&&) constructors (including allocator_arg_t variants) - template - struct _EnableMoveFromOtherTuple : _And< - _Not, tuple<_Up...> > >, - _Lazy<_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, _Tp> >..., - _Not > >... - > - >, - is_constructible<_Tp, _Up>... - > { }; + template , + _EnableConstructFromOtherTuple<_Clref, _Up...>, + _BindsReferenceToTemporary, + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&) = delete; + // tuple(tuple&&) constructors (including allocator_arg_t variants) template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _Not<_BindsReferenceToTemporary<_Up&&...>>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -781,7 +971,18 @@ template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _BindsReferenceToTemporary<_Up&&...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + tuple(tuple<_Up...>&&) = delete; + + template , + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _Not<_BindsReferenceToTemporary<_Up&&...>>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -791,10 +992,21 @@ : __base_(_VSTD::move(__t)) { } - template , + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _BindsReferenceToTemporary<_Up&&...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + explicit tuple(tuple<_Up...>&&) = delete; + + template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _Not<_BindsReferenceToTemporary<_Up&&...>>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -803,10 +1015,21 @@ : __base_(allocator_arg_t(), __a, _VSTD::move(__t)) { } - template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _BindsReferenceToTemporary<_Up&&...>, + is_convertible<_Up, _Tp>... // explicit check + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&&) = delete; + + template , + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _Not<_BindsReferenceToTemporary<_Up&&...>>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -815,27 +1038,226 @@ : __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 , + _EnableConstructFromOtherTuple<_Rref, _Up...>, + _BindsReferenceToTemporary<_Up&&...>, + _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&&) = delete; + + // tuple(const tuple&&) constructors (including allocator_arg_t variants) + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _Not<_BindsReferenceToTemporary >, + is_convertible... // explicit check + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + tuple(const tuple<_Up...>&& __t) + _NOEXCEPT_((_And...>::value)) + : __base_(_VSTD::move(__t)) + { } + + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _BindsReferenceToTemporary, + is_convertible... // explicit check + >::value + , int> = 0> + tuple(const tuple<_Up...>&&) = delete; + + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _Not<_BindsReferenceToTemporary>, + _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_(_VSTD::move(__t)) + { } + + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _BindsReferenceToTemporary, + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> + explicit tuple(const tuple<_Up...>&&) = delete; + + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _Not<_BindsReferenceToTemporary>, + 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, _VSTD::move(__t)) + { } + + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _BindsReferenceToTemporary, + is_convertible... // explicit check + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&&) = delete; + + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _Not<_BindsReferenceToTemporary>, + _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, _VSTD::move(__t)) + { } + + template , + _EnableConstructFromOtherTuple<_Crref, _Up...>, + _BindsReferenceToTemporary, + _Not<_Lazy<_And, is_convertible...> > // explicit check + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&&) = delete; + + // tuple(pair&) constructors (including allocator_arg_t variants) + template class _Ref, class _Up1, class _Up2, class ..._DependentTp> + struct _EnableImplicitConstructFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, _Ref<_Up1> >, + is_constructible<_SecondType<_DependentTp...>, _Ref<_Up2> >, + is_convertible<_Ref<_Up1>, _FirstType<_DependentTp...> >, // explicit check + is_convertible<_Ref<_Up2>, _SecondType<_DependentTp...> > > { }; - template - struct _EnableExplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - _Not > >, // explicit check - _Not > > + template class _Ref, class _Up1, class _Up2, class ..._DependentTp> + struct _EnableExplicitConstructFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, _Ref<_Up1> >, + is_constructible<_SecondType<_DependentTp...>, _Ref<_Up2> >, + _Not, _FirstType<_DependentTp...> > >, // explicit check + _Not, _SecondType<_DependentTp...> > > > { }; template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&, _Up2&>> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + tuple(pair<_Up1, _Up2>& __p) + _NOEXCEPT_((_And< + is_nothrow_constructible<_FirstType<_Tp...>, _Up1&>, + is_nothrow_constructible<_SecondType<_Tp...>, _Up2&> + >::value)) + : __base_(__p) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&, _Up2&> + >::value + , int> = 0> + tuple(pair<_Up1, _Up2>& __p) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&, _Up2&>> + >::value + , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + explicit tuple(pair<_Up1, _Up2>& __p) + _NOEXCEPT_((_And< + is_nothrow_constructible<_FirstType<_Tp...>, _Up1&>, + is_nothrow_constructible<_SecondType<_Tp...>, _Up2&> + >::value)) + : __base_(__p) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&, _Up2&> + >::value + , int> = 0> + explicit tuple(pair<_Up1, _Up2>& __p) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&, _Up2&>> + >::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, __p) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&, _Up2&> + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>& __p) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&, _Up2&>> + >::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, __p) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Lref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&, _Up2&> + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>& __p) = delete; + + // tuple(const pair&) constructors (including allocator_arg_t variants) + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -850,7 +1272,17 @@ template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + tuple(const pair<_Up1, _Up2>& __p) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -862,10 +1294,20 @@ : __base_(__p) { } + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + explicit tuple(const pair<_Up1, _Up2>& __p) = delete; + template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -876,7 +1318,17 @@ template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -884,34 +1336,28 @@ : __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, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Clref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p) = delete; + // tuple(pair&&) constructors (including allocator_arg_t variants) template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&&, _Up2&&>> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 tuple(pair<_Up1, _Up2>&& __p) _NOEXCEPT_((_And< - is_nothrow_constructible<_FirstType<_Tp...>, _Up1>, - is_nothrow_constructible<_SecondType<_Tp...>, _Up2> + is_nothrow_constructible<_FirstType<_Tp...>, _Up1&&>, + is_nothrow_constructible<_SecondType<_Tp...>, _Up2&&> >::value)) : __base_(_VSTD::move(__p)) { } @@ -919,22 +1365,42 @@ template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&&, _Up2&&> + >::value + , int> = 0> + tuple(pair<_Up1, _Up2>&&) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&&, _Up2&&>> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 explicit tuple(pair<_Up1, _Up2>&& __p) _NOEXCEPT_((_And< - is_nothrow_constructible<_FirstType<_Tp...>, _Up1>, - is_nothrow_constructible<_SecondType<_Tp...>, _Up2> + is_nothrow_constructible<_FirstType<_Tp...>, _Up1&&>, + is_nothrow_constructible<_SecondType<_Tp...>, _Up2&&> >::value)) : __base_(_VSTD::move(__p)) { } + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&&, _Up2&&> + >::value + , int> = 0> + explicit tuple(pair<_Up1, _Up2>&&) = delete; + template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&&, _Up2&&>> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -945,7 +1411,17 @@ template class _And = _And, __enable_if_t< _And< _BoolConstant, - _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableImplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&&, _Up2&&> + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc&, pair<_Up1, _Up2>&&) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary<_Up1&&, _Up2&&>> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -953,6 +1429,109 @@ : __base_(allocator_arg_t(), __a, _VSTD::move(__p)) { } + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Rref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary<_Up1&&, _Up2&&> + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc&, pair<_Up1, _Up2>&&) = delete; + + // tuple(const pair&&) constructors (including allocator_arg_t variants) + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> + >::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_(_VSTD::move(__p)) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + tuple(const pair<_Up1, _Up2>&&) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> + >::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_(_VSTD::move(__p)) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + explicit tuple(const pair<_Up1, _Up2>&&) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> + >::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, _VSTD::move(__p)) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableImplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + tuple(allocator_arg_t, const _Alloc&, const pair<_Up1, _Up2>&&) = delete; + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _Not<_BindsReferenceToTemporary> + >::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, _VSTD::move(__p)) + { } + + template class _And = _And, __enable_if_t< + _And< + _BoolConstant, + _EnableExplicitConstructFromPair<_Crref, _Up1, _Up2, _Tp...>, + _BindsReferenceToTemporary + >::value + , int> = 0> + explicit tuple(allocator_arg_t, const _Alloc&, const pair<_Up1, _Up2>&&) = delete; + // [tuple.assign] _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple& operator=(_If<_And...>::value, tuple, __nat> const& __tuple) diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp --- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp +++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp @@ -44,37 +44,31 @@ int main(int, char**) { #if TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary) - // Test that we emit our diagnostic from the library. - // expected-error@tuple:* 8 {{"Attempted construction of reference element binds to a temporary whose lifetime has ended"}} - - // Good news everybody! Clang now diagnoses this for us! - // expected-error@tuple:* 0+ {{reference member '__value_' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}} - { - F(std::make_tuple(1, "abc")); // expected-note 1 {{requested here}} + F(std::make_tuple(1, "abc")); // expected-error-re {{conversion function from {{.*}} invokes a deleted function}} } { - std::tuple t(1, "a"); // expected-note 1 {{requested here}} + std::tuple t(1, "a"); // expected-error {{call to deleted constructor}} } { - F(std::tuple(1, "abc")); // expected-note 1 {{requested here}} + F(std::tuple(1, "abc")); // expected-error {{call to deleted constructor}} } { ConvertsTo ct; - std::tuple t(ct, 42); // expected-note {{requested here}} + std::tuple t(ct, 42); // expected-error {{call to deleted constructor}} } { ConvertsTo ct; - std::tuple t(ct, nullptr); // expected-note {{requested here}} + std::tuple t(ct, nullptr); // expected-error {{call to deleted constructor}} } { ConvertsTo ct; - std::tuple t(ct, 42); // expected-note {{requested here}} + std::tuple t(ct, 42); // expected-error {{call to deleted constructor}} } { std::allocator alloc; - std::tuple t2("hello"); // expected-note {{requested here}} - std::tuple t3(std::allocator_arg, alloc, "hello"); // expected-note {{requested here}} + std::tuple t2("hello"); // expected-error {{call to deleted constructor}} + std::tuple t3(std::allocator_arg, alloc, "hello"); // expected-error {{call to deleted constructor}} } #else #error force failure diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/binding_to_temporary.compile.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/binding_to_temporary.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/binding_to_temporary.compile.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// Verify that various attempts to bind a reference to temporary fail in a +// trait-friendly manner + +#include +#include +#include + +#include "test_macros.h" + +constexpr bool expecting_deleted = TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary); + +using std::tuple; +using std::pair; + +struct ConvertsToInt { operator int() const; }; + +static_assert(std::is_constructible, ConvertsToInt>::value, "!"); +#define CHECK(X, tquals) \ +static_assert(std::is_constructible, X>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, X, X>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, X, int>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, tuple tquals>::value, "!"); \ +static_assert(std::is_constructible, tuple tquals>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, tuple tquals>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, tuple tquals>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, pair tquals>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, pair tquals>::value == !expecting_deleted, "!"); + +#define CHECK_ALL_TQUALS(X) CHECK(X, &) CHECK(X, const&) CHECK(X, &&) CHECK(X, const&&) +#define CHECK_ALL(X) CHECK_ALL_TQUALS(X&) CHECK_ALL_TQUALS(X const&) CHECK_ALL_TQUALS(X&&) CHECK_ALL_TQUALS(X const&&) +CHECK_ALL(ConvertsToInt); diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/binding_to_temporary.compile.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/binding_to_temporary.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/binding_to_temporary.compile.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// Verify that various attempts to bind a reference to temporary fail in a +// trait-friendly manner + +#include +#include + +#include "test_macros.h" + +constexpr bool expecting_deleted = TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary); + +using std::pair; + +struct ConvertsToInt { operator int() const; }; + +static_assert(std::is_constructible, ConvertsToInt, ConvertsToInt>::value, "!"); +#define CHECK(X, tquals) \ +static_assert(std::is_constructible, X, X>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, X, int>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, pair tquals>::value == !expecting_deleted, "!"); \ +static_assert(std::is_constructible, pair tquals>::value == !expecting_deleted, "!"); + +#define CHECK_ALL_TQUALS(X) CHECK(X, &) CHECK(X, const&) CHECK(X, &&) CHECK(X, const&&) +#define CHECK_ALL(X) CHECK_ALL_TQUALS(X&) CHECK_ALL_TQUALS(X const&) CHECK_ALL_TQUALS(X&&) CHECK_ALL_TQUALS(X const&&) +CHECK_ALL(ConvertsToInt);