commit e20794c814c5961f0f33381a8eb3dff4fc741b5a Author: Jonathan Wakely Date: Wed Apr 7 17:20:43 2021 libstdc++: Deprecate non-standard std::pair constructors [PR 99957] This deprecates the non-standard std::pair constructors that support construction from an rvalue and a literal zero used as a null pointer constant. We can't just add the deprecated attribute to those constructors, because they're currently used by correct code when they are a better match than the constructors required by the standard e.g. int i = 0; const int j = 0; std::pair p(i, j); // uses pair(U1&&, const int&) This patch adjusts the parameter types and constraints of those constructors so that they only get used for literal zeros, and the pair(U1&&, U2&&) constructor gets used otherwise. Once they're only used for initializations that should be ill-formed we can add the deprecated attribute. The deprecated attribute is used to suggest that the user code uses nullptr, which avoids the problem of 0 deducing as int instead of a null pointer constant. libstdc++-v3/ChangeLog: PR libstdc++/99957 * include/bits/stl_pair.h (_PCC::_MoveCopyPair, _PCC::_CopyMovePair): Combine and replace with ... (_PCC::_DeprConsPair): New SFINAE helper function. (pair): Merge preprocessor blocks so that all C++03 members are defined together at the end. (pair::pair(const _T1&, _U2&&), pair::pair(_U1&&, const _T2&)): Replace _T1 and _T2 parameters with __null_ptr_constant and adjust constraints. * testsuite/20_util/pair/40925.cc: Use nullptr instead of 0. * testsuite/20_util/pair/cons/explicit_construct.cc: Likewise. * testsuite/20_util/pair/cons/99957.cc: New test. diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 70262f9508f..883d7441b3d 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -128,34 +128,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION is_convertible<_U2&&, _T2>>::value; } - template - static constexpr bool _CopyMovePair() - { - using __do_converts = __and_, - is_convertible<_U2&&, _T2>>; - using __converts = typename conditional<__implicit, - __do_converts, - __not_<__do_converts>>::type; - return __and_, - is_constructible<_T2, _U2&&>, - __converts - >::value; - } template - static constexpr bool _MoveCopyPair() + static constexpr bool _DeprConsPair() { using __do_converts = __and_, - is_convertible>; + is_convertible<_U2&&, _T2>>; using __converts = typename conditional<__implicit, - __do_converts, - __not_<__do_converts>>::type; + __do_converts, + __not_<__do_converts>>::type; return __and_, - is_constructible<_T2, const _U2&&>, + is_constructible<_T2, _U2&&>, __converts - >::value; + >::value; } - }; + }; template struct _PCC @@ -183,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return false; } - }; + }; #endif // C++11 template class __pair_base @@ -217,22 +204,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _T1 first; ///< The first member _T2 second; ///< The second member - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 265. std::pair::pair() effects overly restrictive +#if __cplusplus >= 201103L + // C++11 (and later) implementation. + /** The default constructor creates @c first and @c second using their * respective default constructors. */ -#if __cplusplus >= 201103L template , __is_implicitly_default_constructible<_U2>> ::value, bool>::type = true> -#endif - _GLIBCXX_CONSTEXPR pair() + constexpr pair() : first(), second() { } -#if __cplusplus >= 201103L template ::type = false> explicit constexpr pair() : first(), second() { } -#endif -#if __cplusplus < 201103L - /// Two objects may be passed to a @c pair constructor to be copied. - pair(const _T1& __a, const _T2& __b) - : first(__a), second(__b) { } -#else // Shortcut for constraining the templates that don't take pairs. /// @cond undocumented using _PCCP = _PCC; @@ -275,14 +254,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool>::type=false> explicit constexpr pair(const _T1& __a, const _T2& __b) : first(__a), second(__b) { } -#endif -#if __cplusplus < 201103L - /// There is also a templated constructor to convert from other pairs. - template - pair(const pair<_U1, _U2>& __p) - : first(__p.first), second(__p.second) { } -#else // Shortcut for constraining the templates that take pairs. /// @cond undocumented template @@ -308,40 +280,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool>::type=false> explicit constexpr pair(const pair<_U1, _U2>& __p) : first(__p.first), second(__p.second) { } -#endif -#if __cplusplus >= 201103L constexpr pair(const pair&) = default; ///< Copy constructor constexpr pair(pair&&) = default; ///< Move constructor - // DR 811. - template(), - bool>::type=true> - constexpr pair(_U1&& __x, const _T2& __y) - : first(std::forward<_U1>(__x)), second(__y) { } +#if _GLIBCXX_USE_DEPRECATED + private: + /// @cond undocumented - template(), - bool>::type=false> - explicit constexpr pair(_U1&& __x, const _T2& __y) - : first(std::forward<_U1>(__x)), second(__y) { } + // A type which can be constructed from literal zero, but not nullptr + struct __null_ptr_constant + { + __null_ptr_constant(int __null_ptr_constant::*) { } + template::value>> + __null_ptr_constant(_Tp) = delete; + }; - template(), - bool>::type=true> - constexpr pair(const _T1& __x, _U2&& __y) - : first(__x), second(std::forward<_U2>(__y)) { } + // True if type _Up is one of _Tp& or const _Tp& + template + using __is_lvalue_of + = __or_, is_same<_Up, _Tp&>>; - template(), - bool>::type=false> - explicit pair(const _T1& __x, _U2&& __y) - : first(__x), second(std::forward<_U2>(__y)) { } + /// @endcond + public: + + // Deprecated extensions to DR 811. + template::value + && _PCCP::template + _DeprConsPair(), + bool> = true> + _GLIBCXX_DEPRECATED_SUGGEST("nullptr") + constexpr pair(_U1&& __x, __null_ptr_constant) + : first(std::forward<_U1>(__x)), second(nullptr) { } + + template::value + && _PCCP::template + _DeprConsPair(), + bool> = false> + _GLIBCXX_DEPRECATED_SUGGEST("nullptr") + explicit constexpr pair(_U1&& __x, __null_ptr_constant) + : first(std::forward<_U1>(__x)), second(nullptr) { } + + template::value + && _PCCP::template + _DeprConsPair(), + bool> = true> + _GLIBCXX_DEPRECATED_SUGGEST("nullptr") + constexpr pair(__null_ptr_constant, _U2&& __y) + : first(nullptr), second(std::forward<_U2>(__y)) { } + + template::value + && _PCCP::template + _DeprConsPair(), + bool> = false> + _GLIBCXX_DEPRECATED_SUGGEST("nullptr") + explicit pair(__null_ptr_constant, _U2&& __y) + : first(nullptr), second(std::forward<_U2>(__y)) { } +#endif // _GLIBCXX_USE_DEPRECATED template&, tuple<_Args2...>&, _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>); +#else + // C++03 implementation + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 265. std::pair::pair() effects overly restrictive + /** The default constructor creates @c first and @c second using their + * respective default constructors. */ + pair() : first(), second() { } + + /// Two objects may be passed to a `pair` constructor to be copied. + pair(const _T1& __a, const _T2& __b) + : first(__a), second(__b) { } + + /// Templated constructor to convert from other pairs. + template + pair(const pair<_U1, _U2>& __p) + : first(__p.first), second(__p.second) { } #endif // C++11 }; diff --git a/libstdc++-v3/testsuite/20_util/pair/40925.cc b/libstdc++-v3/testsuite/20_util/pair/40925.cc index 157bef621be..c95cb380b18 100644 --- a/libstdc++-v3/testsuite/20_util/pair/40925.cc +++ b/libstdc++-v3/testsuite/20_util/pair/40925.cc @@ -20,7 +20,7 @@ #include struct X -{ +{ explicit X(int, int) { } private: @@ -36,7 +36,7 @@ private: move_only(const move_only&) = delete; }; -// libstdc++/40925 +// libstdc++/40925 and LWG 811 void test01() { int *ip = 0; @@ -52,10 +52,12 @@ void test01() std::pair p7(0, mp); std::pair p8(mp, mp); - std::pair p9(0, move_only()); - std::pair p10(0, move_only()); - std::pair p11(move_only(), 0); - std::pair p12(move_only(), 0); + // LWG 811 resolution doesn't support move-only types, + // so we have to use nullptr here not a literal 0. + std::pair p9(nullptr, move_only()); + std::pair p10(nullptr, move_only()); + std::pair p11(move_only(), nullptr); + std::pair p12(move_only(), nullptr); std::pair p13(ip, move_only()); std::pair p14(mp, move_only()); diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc new file mode 100644 index 00000000000..b3114131a9d --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc @@ -0,0 +1,45 @@ +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-Wdeprecated" } +// { dg-do compile { target { c++11 } } } + +#include + +using std::pair; + +struct MoveOnly +{ + MoveOnly() = default; + MoveOnly(MoveOnly&&) {} +}; + +struct ExplicitMoveOnly +{ + ExplicitMoveOnly() = default; + ExplicitMoveOnly(ExplicitMoveOnly&&) {} + explicit ExplicitMoveOnly(MoveOnly&&) {} +}; + +// PR libstdc++/99957 +// check non-standard constructors are deprecated + +pair v14{0, MoveOnly{}}; // { dg-warning "deprecated" } +pair v15{MoveOnly{}, 0}; // { dg-warning "deprecated" } + +pair v16 = {0, MoveOnly{}}; // { dg-warning "deprecated" } +pair v17 = {MoveOnly{}, 0}; // { dg-warning "deprecated" } diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc index 3d75e6dbb91..508ca32ecb7 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc @@ -126,10 +126,10 @@ struct ExplicitMoveOnly explicit ExplicitMoveOnly(MoveOnly&&) {} }; -std::pair v14{0, MoveOnly{}}; -std::pair v15{MoveOnly{}, 0}; +std::pair v14{nullptr, MoveOnly{}}; +std::pair v15{MoveOnly{}, nullptr}; std::pair v16 = - {0, MoveOnly{}}; // { dg-error "could not convert" } + {nullptr, MoveOnly{}}; // { dg-error "could not convert" } std::pair v17 = - {MoveOnly{}, 0}; // { dg-error "could not convert" } + {MoveOnly{}, nullptr}; // { dg-error "could not convert" }