aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2022-01-18 15:10:06 +0000
committerJonathan Wakely <jwakely@redhat.com>2022-01-18 16:31:03 +0000
commit302343d8dd30e34516f74a61ec758d80a6c4d1db (patch)
tree651b3cfb3b599910fcee4742cdb186d1aae2cac5
parent50bc6e463b5f0696bc3cb9edd743d09b17309370 (diff)
downloadgcc-302343d8dd30e34516f74a61ec758d80a6c4d1db.zip
gcc-302343d8dd30e34516f74a61ec758d80a6c4d1db.tar.gz
gcc-302343d8dd30e34516f74a61ec758d80a6c4d1db.tar.bz2
libstdc++: Fix ambiguous std::pair constructors [PR101124]
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.
-rw-r--r--libstdc++-v3/include/bits/stl_pair.h85
-rw-r--r--libstdc++-v3/testsuite/20_util/pair/cons/99957.cc12
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 abf2120..8564fd1 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 82ec54c..8432856 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" }