Tested powerpc64le-linux, pushed to trunk.
The deprecated non-standard std::pair constructors that allow constructing std::pair<move-only-type, pointer-type> from an rvalue and a literal zero where not sufficiently constrained. They were viable when constructing std::pair<copyable-type, pointer-type>, and that case should work fine using the standard constructors. Replace the constraints on the non-standard constructors so they are only viable in cases that should actually be ill-formed according to the standard. Also rename __null_ptr_constant to __zero_as_null_pointer_constant so it matches the name of the -Wzero-as-null-pointer-constant warning. Also make the text of the deprecated warning describe the problem in more detail. libstdc++-v3/ChangeLog: PR libstdc++/101124 * include/bits/stl_pair.h (pair): Adjust constraints on deprecated constructors accepting literal zero as null pointer constant. Improve wording of deprecated attribute. * testsuite/20_util/pair/cons/99957.cc: Check that deprecated constructors do not cause ambiguities for copyable types. --- libstdc++-v3/include/bits/stl_pair.h | 85 ++++++++++++------- .../testsuite/20_util/pair/cons/99957.cc | 12 ++- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index abf2120b590..8564fd1ae9e 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -462,62 +462,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : first(__p.first), second(__p.second) { } #if _GLIBCXX_USE_DEPRECATED +#if defined(__DEPRECATED) +# define _GLIBCXX_DEPRECATED_PAIR_CTOR \ + __attribute__ ((__deprecated__ ("use 'nullptr' instead of '0' to " \ + "initialize std::pair of move-only " \ + "type and pointer"))) +#else +# define _GLIBCXX_DEPRECATED_PAIR_CTOR +#endif + private: /// @cond undocumented // A type which can be constructed from literal zero, but not nullptr - struct __null_ptr_constant + struct __zero_as_null_pointer_constant { - __null_ptr_constant(int __null_ptr_constant::*) { } + __zero_as_null_pointer_constant(int __zero_as_null_pointer_constant::*) + { } template<typename _Tp, typename = __enable_if_t<is_null_pointer<_Tp>::value>> - __null_ptr_constant(_Tp) = delete; + __zero_as_null_pointer_constant(_Tp) = delete; }; - - // True if type _Up is one of _Tp& or const _Tp& - template<typename _Up, typename _Tp> - using __is_lvalue_of - = __or_<is_same<_Up, const _Tp&>, is_same<_Up, _Tp&>>; - /// @endcond public: // Deprecated extensions to DR 811. + // These allow construction from an rvalue and a literal zero, + // in cases where the standard says the zero should be deduced as int template<typename _U1, - __enable_if_t<!__is_lvalue_of<_U1, _T1>::value - && _PCCP::template - _DeprConsPair<true, _U1, nullptr_t>(), + __enable_if_t<__and_<__not_<is_reference<_U1>>, + is_pointer<_T2>, + is_constructible<_T1, _U1>, + __not_<is_constructible<_T1, const _U1&>>, + is_convertible<_U1, _T1>>::value, bool> = true> - _GLIBCXX_DEPRECATED_SUGGEST("nullptr") - constexpr pair(_U1&& __x, __null_ptr_constant) - : first(std::forward<_U1>(__x)), second(nullptr) { } + _GLIBCXX_DEPRECATED_PAIR_CTOR + constexpr + pair(_U1&& __x, __zero_as_null_pointer_constant, ...) + : first(std::forward<_U1>(__x)), second(nullptr) { } template<typename _U1, - __enable_if_t<!__is_lvalue_of<_U1, _T1>::value - && _PCCP::template - _DeprConsPair<false, _U1, nullptr_t>(), + __enable_if_t<__and_<__not_<is_reference<_U1>>, + is_pointer<_T2>, + is_constructible<_T1, _U1>, + __not_<is_constructible<_T1, const _U1&>>, + __not_<is_convertible<_U1, _T1>>>::value, bool> = false> - _GLIBCXX_DEPRECATED_SUGGEST("nullptr") - explicit constexpr pair(_U1&& __x, __null_ptr_constant) - : first(std::forward<_U1>(__x)), second(nullptr) { } + _GLIBCXX_DEPRECATED_PAIR_CTOR + explicit constexpr + pair(_U1&& __x, __zero_as_null_pointer_constant, ...) + : first(std::forward<_U1>(__x)), second(nullptr) { } template<typename _U2, - __enable_if_t<!__is_lvalue_of<_U2, _T2>::value - && _PCCP::template - _DeprConsPair<true, nullptr_t, _U2>(), + __enable_if_t<__and_<is_pointer<_T1>, + __not_<is_reference<_U2>>, + is_constructible<_T2, _U2>, + __not_<is_constructible<_T2, const _U2&>>, + is_convertible<_U2, _T2>>::value, bool> = true> - _GLIBCXX_DEPRECATED_SUGGEST("nullptr") - constexpr pair(__null_ptr_constant, _U2&& __y) - : first(nullptr), second(std::forward<_U2>(__y)) { } + _GLIBCXX_DEPRECATED_PAIR_CTOR + constexpr + pair(__zero_as_null_pointer_constant, _U2&& __y, ...) + : first(nullptr), second(std::forward<_U2>(__y)) { } template<typename _U2, - __enable_if_t<!__is_lvalue_of<_U2, _T2>::value - && _PCCP::template - _DeprConsPair<false, nullptr_t, _U2>(), + __enable_if_t<__and_<is_pointer<_T1>, + __not_<is_reference<_U2>>, + is_constructible<_T2, _U2>, + __not_<is_constructible<_T2, const _U2&>>, + __not_<is_convertible<_U2, _T2>>>::value, bool> = false> - _GLIBCXX_DEPRECATED_SUGGEST("nullptr") - explicit pair(__null_ptr_constant, _U2&& __y) - : first(nullptr), second(std::forward<_U2>(__y)) { } + _GLIBCXX_DEPRECATED_PAIR_CTOR + explicit constexpr + pair(__zero_as_null_pointer_constant, _U2&& __y, ...) + : first(nullptr), second(std::forward<_U2>(__y)) { } +#undef _GLIBCXX_DEPRECATED_PAIR_CTOR #endif template<typename _U1, typename _U2, typename diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc index 82ec54ca1d8..8432856d0b0 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc @@ -22,8 +22,16 @@ struct ExplicitMoveOnly // PR libstdc++/99957 // check non-standard constructors are deprecated -pair<int*, ExplicitMoveOnly> v14{0, MoveOnly{}}; // { dg-warning "deprecated" } -pair<ExplicitMoveOnly, int*> v15{MoveOnly{}, 0}; // { dg-warning "deprecated" } +pair<int*, ExplicitMoveOnly> v14(0, MoveOnly{}); // { dg-warning "deprecated" } +pair<ExplicitMoveOnly, int*> v15(MoveOnly{}, 0); // { dg-warning "deprecated" } pair<int*, MoveOnly> v16 = {0, MoveOnly{}}; // { dg-warning "deprecated" } pair<MoveOnly, int*> v17 = {MoveOnly{}, 0}; // { dg-warning "deprecated" } + +// PR libstdc++/101124 +// check deprecated constructors don't cause unwanted ambiguities + +std::pair<long*, int> p(0, 0); // { dg-bogus "ambiguous" } + +struct X { } x; +std::pair<const X, void*> p2(x, 0); // { dg-bogus "ambiguous" } -- 2.31.1