* [RFC] Deprecate non-standard constructors in std::pair @ 2021-04-07 12:30 Jonathan Wakely 2021-04-07 12:41 ` Ville Voutilainen 0 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-07 12:30 UTC (permalink / raw) To: libstdc++ This variation on the example in https://wg21.link/lwg811 is supposed to be ill-formed: pair<char*, unique_ptr<int>> p(0, std::make_unique<int>(0)); This cannot use the pair(U1&&, U2&&) constructor because it deduces int for U1, which isn't convertible to char*. But it also cannot use the pair(const first_type&, const second_type&) constructor, because second_type is move-only. It works in libstdc++ because extra non-standard constructors were added by https://gcc.gnu.org/PR40925 when implementing LWG 811: template<typename U1, /* constraints */> explicit(/*...*/) pair(U1&&, const second_type&); template<typename U2, /* constraints */> explicit(/*...*/) pair(const first_type&, U2&&); I think we should deprecate these extra constructors. Unless I'm mistaken, those non-standard constructors have two uses: - Support literal 0 as a constructor argument for a pointer type. Such code should use nullptr instead. It exists to solve the problem of 0 not deducing as a pointer type. - Support {} as a constructor argument for a move-only type. I don't think this was an intentional design choice (we don't test for it) but it does work. Adopting https://wg21.link/p1951 for C++23 will make that work anyway. I propose that we deprecate the constructors for C++11/14/17/20 in stage 1, and do not support them at all in C++23 mode once P1951 is supported. I have a patch which I'll send in stage 1 (it also uses C++20 concepts to simplify std::pair and fix PR 97930). After a period of deprecation we could remove them, and support P1951 for -std=gnu++11/14/17/20 too so that {} continues to work. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 12:30 [RFC] Deprecate non-standard constructors in std::pair Jonathan Wakely @ 2021-04-07 12:41 ` Ville Voutilainen 2021-04-07 12:46 ` Jonathan Wakely 0 siblings, 1 reply; 14+ messages in thread From: Ville Voutilainen @ 2021-04-07 12:41 UTC (permalink / raw) To: Jonathan Wakely; +Cc: libstdc++ On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ <libstdc++@gcc.gnu.org> wrote: > I propose that we deprecate the constructors for C++11/14/17/20 in > stage 1, and do not support them at all in C++23 mode once P1951 is > supported. I have a patch which I'll send in stage 1 (it also uses > C++20 concepts to simplify std::pair and fix PR 97930). > > After a period of deprecation we could remove them, and support P1951 > for -std=gnu++11/14/17/20 too so that {} continues to work. The proposal sounds good to me. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 12:41 ` Ville Voutilainen @ 2021-04-07 12:46 ` Jonathan Wakely 2021-04-07 16:59 ` Jonathan Wakely 0 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-07 12:46 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++ On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ ><libstdc++@gcc.gnu.org> wrote: >> I propose that we deprecate the constructors for C++11/14/17/20 in >> stage 1, and do not support them at all in C++23 mode once P1951 is >> supported. I have a patch which I'll send in stage 1 (it also uses >> C++20 concepts to simplify std::pair and fix PR 97930). >> >> After a period of deprecation we could remove them, and support P1951 >> for -std=gnu++11/14/17/20 too so that {} continues to work. > >The proposal sounds good to me. Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 12:46 ` Jonathan Wakely @ 2021-04-07 16:59 ` Jonathan Wakely 2021-04-07 17:18 ` Jonathan Wakely ` (2 more replies) 0 siblings, 3 replies; 14+ messages in thread From: Jonathan Wakely @ 2021-04-07 16:59 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++ [-- Attachment #1: Type: text/plain, Size: 1815 bytes --] On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >><libstdc++@gcc.gnu.org> wrote: >>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>supported. I have a patch which I'll send in stage 1 (it also uses >>>C++20 concepts to simplify std::pair and fix PR 97930). >>> >>>After a period of deprecation we could remove them, and support P1951 >>>for -std=gnu++11/14/17/20 too so that {} continues to work. >> >>The proposal sounds good to me. > >Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. Here's a patch to implement it, for stage 1. 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<int, int> 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. [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 14435 bytes --] commit e20794c814c5961f0f33381a8eb3dff4fc741b5a Author: Jonathan Wakely <jwakely@redhat.com> 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<int, int> 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 <bool __implicit, typename _U1, typename _U2> - static constexpr bool _CopyMovePair() - { - using __do_converts = __and_<is_convertible<const _U1&, _T1>, - is_convertible<_U2&&, _T2>>; - using __converts = typename conditional<__implicit, - __do_converts, - __not_<__do_converts>>::type; - return __and_<is_constructible<_T1, const _U1&>, - is_constructible<_T2, _U2&&>, - __converts - >::value; - } template <bool __implicit, typename _U1, typename _U2> - static constexpr bool _MoveCopyPair() + static constexpr bool _DeprConsPair() { using __do_converts = __and_<is_convertible<_U1&&, _T1>, - is_convertible<const _U2&, _T2>>; + 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<_T1, _U1&&>, - is_constructible<_T2, const _U2&&>, + is_constructible<_T2, _U2&&>, __converts - >::value; + >::value; } - }; + }; template <typename _T1, typename _T2> struct _PCC<false, _T1, _T2> @@ -183,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return false; } - }; + }; #endif // C++11 template<typename _U1, typename _U2> 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 <typename _U1 = _T1, typename _U2 = _T2, typename enable_if<__and_< __is_implicitly_default_constructible<_U1>, __is_implicitly_default_constructible<_U2>> ::value, bool>::type = true> -#endif - _GLIBCXX_CONSTEXPR pair() + constexpr pair() : first(), second() { } -#if __cplusplus >= 201103L template <typename _U1 = _T1, typename _U2 = _T2, typename enable_if<__and_< @@ -244,13 +229,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ::value, bool>::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<true, _T1, _T2>; @@ -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<typename _U1, typename _U2> - pair(const pair<_U1, _U2>& __p) - : first(__p.first), second(__p.second) { } -#else // Shortcut for constraining the templates that take pairs. /// @cond undocumented template <typename _U1, typename _U2> @@ -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<typename _U1, typename - enable_if<_PCCP::template - _MoveCopyPair<true, _U1, _T2>(), - 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<typename _U1, typename - enable_if<_PCCP::template - _MoveCopyPair<false, _U1, _T2>(), - 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<typename _Tp, + typename = __enable_if_t<is_null_pointer<_Tp>::value>> + __null_ptr_constant(_Tp) = delete; + }; - template<typename _U2, typename - enable_if<_PCCP::template - _CopyMovePair<true, _T1, _U2>(), - 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<typename _Up, typename _Tp> + using __is_lvalue_of + = __or_<is_same<_Up, const _Tp&>, is_same<_Up, _Tp&>>; - template<typename _U2, typename - enable_if<_PCCP::template - _CopyMovePair<false, _T1, _U2>(), - 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<typename _U1, + __enable_if_t<!__is_lvalue_of<_U1, _T1>::value + && _PCCP::template + _DeprConsPair<true, _U1, nullptr_t>(), + bool> = true> + _GLIBCXX_DEPRECATED_SUGGEST("nullptr") + constexpr pair(_U1&& __x, __null_ptr_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>(), + bool> = false> + _GLIBCXX_DEPRECATED_SUGGEST("nullptr") + explicit constexpr pair(_U1&& __x, __null_ptr_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>(), + bool> = true> + _GLIBCXX_DEPRECATED_SUGGEST("nullptr") + constexpr pair(__null_ptr_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>(), + 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<typename _U1, typename _U2, typename enable_if<_PCCP::template @@ -451,6 +451,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX20_CONSTEXPR pair(tuple<_Args1...>&, 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<typename _U1, typename _U2> + 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 <utility> 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<int X::*, int X::*> p7(0, mp); std::pair<int X::*, int X::*> p8(mp, mp); - std::pair<int*, move_only> p9(0, move_only()); - std::pair<int X::*, move_only> p10(0, move_only()); - std::pair<move_only, int*> p11(move_only(), 0); - std::pair<move_only, int X::*> 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<int*, move_only> p9(nullptr, move_only()); + std::pair<int X::*, move_only> p10(nullptr, move_only()); + std::pair<move_only, int*> p11(move_only(), nullptr); + std::pair<move_only, int X::*> p12(move_only(), nullptr); std::pair<int*, move_only> p13(ip, move_only()); std::pair<int X::*, move_only> 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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-Wdeprecated" } +// { dg-do compile { target { c++11 } } } + +#include <utility> + +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<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" } 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<int*, ExplicitMoveOnly> v14{0, MoveOnly{}}; -std::pair<ExplicitMoveOnly, int*> v15{MoveOnly{}, 0}; +std::pair<int*, ExplicitMoveOnly> v14{nullptr, MoveOnly{}}; +std::pair<ExplicitMoveOnly, int*> v15{MoveOnly{}, nullptr}; std::pair<int*, ExplicitMoveOnly> v16 = - {0, MoveOnly{}}; // { dg-error "could not convert" } + {nullptr, MoveOnly{}}; // { dg-error "could not convert" } std::pair<ExplicitMoveOnly, int*> v17 = - {MoveOnly{}, 0}; // { dg-error "could not convert" } + {MoveOnly{}, nullptr}; // { dg-error "could not convert" } ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 16:59 ` Jonathan Wakely @ 2021-04-07 17:18 ` Jonathan Wakely 2021-04-28 16:57 ` Jonathan Wakely 2021-04-07 18:00 ` Jonathan Wakely 2021-04-28 16:57 ` Jonathan Wakely 2 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-07 17:18 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++ [-- Attachment #1: Type: text/plain, Size: 947 bytes --] On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>><libstdc++@gcc.gnu.org> wrote: >>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>> >>>>After a period of deprecation we could remove them, and support P1951 >>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>> >>>The proposal sounds good to me. >> >>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. > >Here's a patch to implement it, for stage 1. And here's a patch to simplify the std::pair constraints using concepts, also for consideration in stage 1. [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 11226 bytes --] commit 9e184c70f6a8e8ed8e34d8ffcb9c98e079dd3c31 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Apr 7 18:12:08 2021 libstdc++: Simplify std::pair constraints using concepts This re-implements the constraints on the std::pair constructors and assignment operators in C++20 mode, to use concepts. The non-standard constructors deprecated for PR 99957 are no longer supported in C++20 mode, which requires some minor testsuite changes. Otherwise all tests pass in C++20 mode. libstdc++-v3/ChangeLog: * include/bits/stl_pair.h (pair): * testsuite/20_util/pair/cons/99957.cc: Disable for C++20 and later. * testsuite/20_util/pair/cons/explicit_construct.cc: Adjust expected error messages to also match C++20 errors. diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 883d7441b3d..bd3f911abb9 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -92,6 +92,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<size_t...> struct _Index_tuple; +#if ! __cpp_lib_concepts // Concept utility functions, reused in conditionally-explicit // constructors. // See PR 70437, don't look at is_constructible or @@ -171,11 +172,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return false; } }; +#endif // lib concepts #endif // C++11 template<typename _U1, typename _U2> class __pair_base { -#if __cplusplus >= 201103L +#if __cplusplus >= 201103L && ! __cpp_lib_concepts template<typename _T1, typename _T2> friend struct pair; __pair_base() = default; ~__pair_base() = default; @@ -196,7 +198,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template<typename _T1, typename _T2> struct pair - : private __pair_base<_T1, _T2> + : public __pair_base<_T1, _T2> { typedef _T1 first_type; ///< The type of the `first` member typedef _T2 second_type; ///< The type of the `second` member @@ -205,7 +207,186 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _T2 second; ///< The second member #if __cplusplus >= 201103L - // C++11 (and later) implementation. + constexpr pair(const pair&) = default; ///< Copy constructor + constexpr pair(pair&&) = default; ///< Move constructor + + template<typename... _Args1, typename... _Args2> + _GLIBCXX20_CONSTEXPR + pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); + + /// Swap the first members and then the second members. + _GLIBCXX20_CONSTEXPR void + swap(pair& __p) + noexcept(__and_<__is_nothrow_swappable<_T1>, + __is_nothrow_swappable<_T2>>::value) + { + using std::swap; + swap(first, __p.first); + swap(second, __p.second); + } + + private: + template<typename... _Args1, size_t... _Indexes1, + typename... _Args2, size_t... _Indexes2> + _GLIBCXX20_CONSTEXPR + pair(tuple<_Args1...>&, tuple<_Args2...>&, + _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>); + public: + +#if __cpp_lib_concepts + // C++20 implementation using concepts, explicit(bool), fully constexpr. + + /// Default constructor + constexpr + explicit(__not_<__and_<__is_implicitly_default_constructible<_T1>, + __is_implicitly_default_constructible<_T2>>>()) + pair() + requires is_default_constructible_v<_T1> + && is_default_constructible_v<_T2> + : first(), second() + { } + + private: + + /// @cond undocumented + template<typename _U1, typename _U2> + static constexpr bool + _S_constructible() + { + if constexpr (is_constructible_v<_T1, _U1>) + return is_constructible_v<_T2, _U2>; + return false; + } + + template<typename _U1, typename _U2> + static constexpr bool + _S_nothrow_constructible() + { + if constexpr (is_nothrow_constructible_v<_T1, _U1>) + return is_nothrow_constructible_v<_T2, _U2>; + return false; + } + + template<typename _U1, typename _U2> + static constexpr bool + _S_convertible() + { + if constexpr (is_convertible_v<_U1, _T1>) + return is_convertible_v<_U2, _T2>; + return false; + } + /// @endcond + + public: + + /// Constructor accepting lvalues of `first_type` and `second_type` + constexpr explicit(!_S_convertible<const _T1&, const _T2&>()) + pair(const _T1& __x, const _T2& __y) + noexcept(_S_nothrow_constructible<const _T1&, const _T2&>()) + requires (_S_constructible<const _T1&, const _T2&>()) + : first(__x), second(__y) + { } + + /// Constructor accepting two values of arbitrary types + template<typename _U1, typename _U2> + requires (_S_constructible<_U1, _U2>()) + constexpr explicit(!_S_convertible<_U1, _U2>()) + pair(_U1&& __x, _U2&& __y) + noexcept(_S_nothrow_constructible<_U1, _U2>()) + : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) + { } + + /// Converting constructor from a `pair<U1, U2>` lvalue + template<typename _U1, typename _U2> + requires (_S_constructible<const _U1&, const _U2&>()) + constexpr explicit(!_S_convertible<const _U1&, const _U2&>()) + pair(const pair<_U1, _U2>& __p) + noexcept(_S_nothrow_constructible<const _U1&, const _U2&>()) + : first(__p.first), second(__p.second) + { } + + /// Converting constructor from a `pair<U1, U2>` rvalue + template<typename _U1, typename _U2> + requires (_S_constructible<_U1, _U2>()) + constexpr explicit(!_S_convertible<_U1, _U2>()) + pair(pair<_U1, _U2>&& __p) + noexcept(_S_nothrow_constructible<_U1, _U2>()) + : first(std::forward<_U1>(__p.first)), + second(std::forward<_U2>(__p.second)) + { } + + private: + /// @cond undocumented + template<typename _U1, typename _U2> + static constexpr bool + _S_assignable() + { + if constexpr (is_assignable_v<_T1&, _U1>) + return is_assignable_v<_T2&, _U2>; + return false; + } + + template<typename _U1, typename _U2> + static constexpr bool + _S_nothrow_assignable() + { + if constexpr (is_nothrow_assignable_v<_T1&, _U1>) + return is_nothrow_assignable_v<_T2&, _U2>; + return false; + } + /// @endcond + + public: + + pair& operator=(const pair&) = delete; + + /// Copy assignment operator + constexpr pair& + operator=(const pair& __p) + noexcept(_S_nothrow_assignable<const _T1&, const _T2&>()) + requires (_S_assignable<const _T1&, const _T2&>()) + { + first = __p.first; + second = __p.second; + return *this; + } + + /// Move assignment operator + constexpr pair& + operator=(pair&& __p) + noexcept(_S_nothrow_assignable<_T1, _T2>()) + requires (_S_assignable<_T1, _T2>()) + { + first = std::forward<first_type>(__p.first); + second = std::forward<second_type>(__p.second); + return *this; + } + + /// Converting assignment from a `pair<U1, U2>` lvalue + template<typename _U1, typename _U2> + constexpr pair& + operator=(const pair<_U1, _U2>& __p) + noexcept(_S_nothrow_assignable<const _U1&, const _U2&>()) + requires (_S_assignable<const _U1&, const _U2&>()) + { + first = __p.first; + second = __p.second; + return *this; + } + + /// Converting assignment from a `pair<U1, U2>` rvalue + template<typename _U1, typename _U2> + constexpr pair& + operator=(pair<_U1, _U2>&& __p) + noexcept(_S_nothrow_assignable<_U1, _U2>()) + requires (_S_assignable<_U1, _U2>()) + { + first = std::forward<_U1>(__p.first); + second = std::forward<_U2>(__p.second); + return *this; + } +#else + // C++11/14/17 implementation using enable_if, partially constexpr. /** The default constructor creates @c first and @c second using their * respective default constructors. */ @@ -281,9 +462,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit constexpr pair(const pair<_U1, _U2>& __p) : first(__p.first), second(__p.second) { } - constexpr pair(const pair&) = default; ///< Copy constructor - constexpr pair(pair&&) = default; ///< Move constructor - #if _GLIBCXX_USE_DEPRECATED private: /// @cond undocumented @@ -341,7 +519,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_DEPRECATED_SUGGEST("nullptr") explicit pair(__null_ptr_constant, _U2&& __y) : first(nullptr), second(std::forward<_U2>(__y)) { } -#endif // _GLIBCXX_USE_DEPRECATED +#endif template<typename _U1, typename _U2, typename enable_if<_PCCP::template @@ -382,10 +560,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) { } - template<typename... _Args1, typename... _Args2> - _GLIBCXX20_CONSTEXPR - pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); - _GLIBCXX20_CONSTEXPR pair& operator=(typename conditional< __and_<is_copy_assignable<_T1>, @@ -433,24 +607,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION second = std::forward<_U2>(__p.second); return *this; } - - /// Swap the first members and then the second members. - _GLIBCXX20_CONSTEXPR void - swap(pair& __p) - noexcept(__and_<__is_nothrow_swappable<_T1>, - __is_nothrow_swappable<_T2>>::value) - { - using std::swap; - swap(first, __p.first); - swap(second, __p.second); - } - - private: - template<typename... _Args1, size_t... _Indexes1, - typename... _Args2, size_t... _Indexes2> - _GLIBCXX20_CONSTEXPR - pair(tuple<_Args1...>&, tuple<_Args2...>&, - _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>); +#endif // lib concepts #else // C++03 implementation diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc index d300292b463..a3e6a452583 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc @@ -16,7 +16,7 @@ // <http://www.gnu.org/licenses/>. // { dg-options "-Wdeprecated" } -// { dg-do compile { target c++11 } } +// { dg-do compile { target { c++11 && { ! c++20 } } } } #include <utility> 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 508ca32ecb7..ecd5acf9375 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc @@ -83,12 +83,12 @@ void f7(std::pair<long, long>) {} std::pair<ExplicitDefault, int> f8() { - return {}; // { dg-error "could not convert" } + return {}; // { dg-error "convert" } } std::pair<ExplicitDefaultDefault, int> f9() { - return {}; // { dg-error "could not convert" } + return {}; // { dg-error "convert" } } void f10(std::pair<ExplicitDefault, int>) {} @@ -107,8 +107,8 @@ void test_arg_passing() f7({1,2}); f7(std::pair<int, int>{}); f7(std::pair<long, long>{}); - f10({}); // { dg-error "could not convert" } - f11({}); // { dg-error "could not convert" } + f10({}); // { dg-error "convert" } + f11({}); // { dg-error "convert" } f10(std::pair<ExplicitDefault, int>{}); f11(std::pair<ExplicitDefaultDefault, int>{}); } ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 17:18 ` Jonathan Wakely @ 2021-04-28 16:57 ` Jonathan Wakely 2021-04-28 17:19 ` Jonathan Wakely 0 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-28 16:57 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++, gcc-patches On 07/04/21 18:18 +0100, Jonathan Wakely wrote: >On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >>On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>>><libstdc++@gcc.gnu.org> wrote: >>>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>>> >>>>>After a period of deprecation we could remove them, and support P1951 >>>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>>> >>>>The proposal sounds good to me. >>> >>>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. >> >>Here's a patch to implement it, for stage 1. > >And here's a patch to simplify the std::pair constraints using >concepts, also for consideration in stage 1. I've pushed this to trunk too, after testing on powerpc64le-linux. >commit 9e184c70f6a8e8ed8e34d8ffcb9c98e079dd3c31 >Author: Jonathan Wakely <jwakely@redhat.com> >Date: Wed Apr 7 18:12:08 2021 > > libstdc++: Simplify std::pair constraints using concepts > > This re-implements the constraints on the std::pair constructors and > assignment operators in C++20 mode, to use concepts. > > The non-standard constructors deprecated for PR 99957 are no longer > supported in C++20 mode, which requires some minor testsuite changes. > Otherwise all tests pass in C++20 mode. > > libstdc++-v3/ChangeLog: > > * include/bits/stl_pair.h (pair): > * testsuite/20_util/pair/cons/99957.cc: Disable for C++20 and > later. > * testsuite/20_util/pair/cons/explicit_construct.cc: Adjust > expected error messages to also match C++20 errors. > >diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h >index 883d7441b3d..bd3f911abb9 100644 >--- a/libstdc++-v3/include/bits/stl_pair.h >+++ b/libstdc++-v3/include/bits/stl_pair.h >@@ -92,6 +92,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > template<size_t...> > struct _Index_tuple; > >+#if ! __cpp_lib_concepts > // Concept utility functions, reused in conditionally-explicit > // constructors. > // See PR 70437, don't look at is_constructible or >@@ -171,11 +172,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > return false; > } > }; >+#endif // lib concepts > #endif // C++11 > > template<typename _U1, typename _U2> class __pair_base > { >-#if __cplusplus >= 201103L >+#if __cplusplus >= 201103L && ! __cpp_lib_concepts > template<typename _T1, typename _T2> friend struct pair; > __pair_base() = default; > ~__pair_base() = default; >@@ -196,7 +198,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > */ > template<typename _T1, typename _T2> > struct pair >- : private __pair_base<_T1, _T2> >+ : public __pair_base<_T1, _T2> > { > typedef _T1 first_type; ///< The type of the `first` member > typedef _T2 second_type; ///< The type of the `second` member >@@ -205,7 +207,186 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > _T2 second; ///< The second member > > #if __cplusplus >= 201103L >- // C++11 (and later) implementation. >+ constexpr pair(const pair&) = default; ///< Copy constructor >+ constexpr pair(pair&&) = default; ///< Move constructor >+ >+ template<typename... _Args1, typename... _Args2> >+ _GLIBCXX20_CONSTEXPR >+ pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); >+ >+ /// Swap the first members and then the second members. >+ _GLIBCXX20_CONSTEXPR void >+ swap(pair& __p) >+ noexcept(__and_<__is_nothrow_swappable<_T1>, >+ __is_nothrow_swappable<_T2>>::value) >+ { >+ using std::swap; >+ swap(first, __p.first); >+ swap(second, __p.second); >+ } >+ >+ private: >+ template<typename... _Args1, size_t... _Indexes1, >+ typename... _Args2, size_t... _Indexes2> >+ _GLIBCXX20_CONSTEXPR >+ pair(tuple<_Args1...>&, tuple<_Args2...>&, >+ _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>); >+ public: >+ >+#if __cpp_lib_concepts >+ // C++20 implementation using concepts, explicit(bool), fully constexpr. >+ >+ /// Default constructor >+ constexpr >+ explicit(__not_<__and_<__is_implicitly_default_constructible<_T1>, >+ __is_implicitly_default_constructible<_T2>>>()) >+ pair() >+ requires is_default_constructible_v<_T1> >+ && is_default_constructible_v<_T2> >+ : first(), second() >+ { } >+ >+ private: >+ >+ /// @cond undocumented >+ template<typename _U1, typename _U2> >+ static constexpr bool >+ _S_constructible() >+ { >+ if constexpr (is_constructible_v<_T1, _U1>) >+ return is_constructible_v<_T2, _U2>; >+ return false; >+ } >+ >+ template<typename _U1, typename _U2> >+ static constexpr bool >+ _S_nothrow_constructible() >+ { >+ if constexpr (is_nothrow_constructible_v<_T1, _U1>) >+ return is_nothrow_constructible_v<_T2, _U2>; >+ return false; >+ } >+ >+ template<typename _U1, typename _U2> >+ static constexpr bool >+ _S_convertible() >+ { >+ if constexpr (is_convertible_v<_U1, _T1>) >+ return is_convertible_v<_U2, _T2>; >+ return false; >+ } >+ /// @endcond >+ >+ public: >+ >+ /// Constructor accepting lvalues of `first_type` and `second_type` >+ constexpr explicit(!_S_convertible<const _T1&, const _T2&>()) >+ pair(const _T1& __x, const _T2& __y) >+ noexcept(_S_nothrow_constructible<const _T1&, const _T2&>()) >+ requires (_S_constructible<const _T1&, const _T2&>()) >+ : first(__x), second(__y) >+ { } >+ >+ /// Constructor accepting two values of arbitrary types >+ template<typename _U1, typename _U2> >+ requires (_S_constructible<_U1, _U2>()) >+ constexpr explicit(!_S_convertible<_U1, _U2>()) >+ pair(_U1&& __x, _U2&& __y) >+ noexcept(_S_nothrow_constructible<_U1, _U2>()) >+ : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) >+ { } >+ >+ /// Converting constructor from a `pair<U1, U2>` lvalue >+ template<typename _U1, typename _U2> >+ requires (_S_constructible<const _U1&, const _U2&>()) >+ constexpr explicit(!_S_convertible<const _U1&, const _U2&>()) >+ pair(const pair<_U1, _U2>& __p) >+ noexcept(_S_nothrow_constructible<const _U1&, const _U2&>()) >+ : first(__p.first), second(__p.second) >+ { } >+ >+ /// Converting constructor from a `pair<U1, U2>` rvalue >+ template<typename _U1, typename _U2> >+ requires (_S_constructible<_U1, _U2>()) >+ constexpr explicit(!_S_convertible<_U1, _U2>()) >+ pair(pair<_U1, _U2>&& __p) >+ noexcept(_S_nothrow_constructible<_U1, _U2>()) >+ : first(std::forward<_U1>(__p.first)), >+ second(std::forward<_U2>(__p.second)) >+ { } >+ >+ private: >+ /// @cond undocumented >+ template<typename _U1, typename _U2> >+ static constexpr bool >+ _S_assignable() >+ { >+ if constexpr (is_assignable_v<_T1&, _U1>) >+ return is_assignable_v<_T2&, _U2>; >+ return false; >+ } >+ >+ template<typename _U1, typename _U2> >+ static constexpr bool >+ _S_nothrow_assignable() >+ { >+ if constexpr (is_nothrow_assignable_v<_T1&, _U1>) >+ return is_nothrow_assignable_v<_T2&, _U2>; >+ return false; >+ } >+ /// @endcond >+ >+ public: >+ >+ pair& operator=(const pair&) = delete; >+ >+ /// Copy assignment operator >+ constexpr pair& >+ operator=(const pair& __p) >+ noexcept(_S_nothrow_assignable<const _T1&, const _T2&>()) >+ requires (_S_assignable<const _T1&, const _T2&>()) >+ { >+ first = __p.first; >+ second = __p.second; >+ return *this; >+ } >+ >+ /// Move assignment operator >+ constexpr pair& >+ operator=(pair&& __p) >+ noexcept(_S_nothrow_assignable<_T1, _T2>()) >+ requires (_S_assignable<_T1, _T2>()) >+ { >+ first = std::forward<first_type>(__p.first); >+ second = std::forward<second_type>(__p.second); >+ return *this; >+ } >+ >+ /// Converting assignment from a `pair<U1, U2>` lvalue >+ template<typename _U1, typename _U2> >+ constexpr pair& >+ operator=(const pair<_U1, _U2>& __p) >+ noexcept(_S_nothrow_assignable<const _U1&, const _U2&>()) >+ requires (_S_assignable<const _U1&, const _U2&>()) >+ { >+ first = __p.first; >+ second = __p.second; >+ return *this; >+ } >+ >+ /// Converting assignment from a `pair<U1, U2>` rvalue >+ template<typename _U1, typename _U2> >+ constexpr pair& >+ operator=(pair<_U1, _U2>&& __p) >+ noexcept(_S_nothrow_assignable<_U1, _U2>()) >+ requires (_S_assignable<_U1, _U2>()) >+ { >+ first = std::forward<_U1>(__p.first); >+ second = std::forward<_U2>(__p.second); >+ return *this; >+ } >+#else >+ // C++11/14/17 implementation using enable_if, partially constexpr. > > /** The default constructor creates @c first and @c second using their > * respective default constructors. */ >@@ -281,9 +462,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > explicit constexpr pair(const pair<_U1, _U2>& __p) > : first(__p.first), second(__p.second) { } > >- constexpr pair(const pair&) = default; ///< Copy constructor >- constexpr pair(pair&&) = default; ///< Move constructor >- > #if _GLIBCXX_USE_DEPRECATED > private: > /// @cond undocumented >@@ -341,7 +519,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > _GLIBCXX_DEPRECATED_SUGGEST("nullptr") > explicit pair(__null_ptr_constant, _U2&& __y) > : first(nullptr), second(std::forward<_U2>(__y)) { } >-#endif // _GLIBCXX_USE_DEPRECATED >+#endif > > template<typename _U1, typename _U2, typename > enable_if<_PCCP::template >@@ -382,10 +560,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > : first(std::forward<_U1>(__p.first)), > second(std::forward<_U2>(__p.second)) { } > >- template<typename... _Args1, typename... _Args2> >- _GLIBCXX20_CONSTEXPR >- pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); >- > _GLIBCXX20_CONSTEXPR pair& > operator=(typename conditional< > __and_<is_copy_assignable<_T1>, >@@ -433,24 +607,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > second = std::forward<_U2>(__p.second); > return *this; > } >- >- /// Swap the first members and then the second members. >- _GLIBCXX20_CONSTEXPR void >- swap(pair& __p) >- noexcept(__and_<__is_nothrow_swappable<_T1>, >- __is_nothrow_swappable<_T2>>::value) >- { >- using std::swap; >- swap(first, __p.first); >- swap(second, __p.second); >- } >- >- private: >- template<typename... _Args1, size_t... _Indexes1, >- typename... _Args2, size_t... _Indexes2> >- _GLIBCXX20_CONSTEXPR >- pair(tuple<_Args1...>&, tuple<_Args2...>&, >- _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>); >+#endif // lib concepts > #else > // C++03 implementation > >diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc >index d300292b463..a3e6a452583 100644 >--- a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc >+++ b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc >@@ -16,7 +16,7 @@ > // <http://www.gnu.org/licenses/>. > > // { dg-options "-Wdeprecated" } >-// { dg-do compile { target c++11 } } >+// { dg-do compile { target { c++11 && { ! c++20 } } } } > > #include <utility> > >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 508ca32ecb7..ecd5acf9375 100644 >--- a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc >+++ b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc >@@ -83,12 +83,12 @@ void f7(std::pair<long, long>) {} > > std::pair<ExplicitDefault, int> f8() > { >- return {}; // { dg-error "could not convert" } >+ return {}; // { dg-error "convert" } > } > > std::pair<ExplicitDefaultDefault, int> f9() > { >- return {}; // { dg-error "could not convert" } >+ return {}; // { dg-error "convert" } > } > > void f10(std::pair<ExplicitDefault, int>) {} >@@ -107,8 +107,8 @@ void test_arg_passing() > f7({1,2}); > f7(std::pair<int, int>{}); > f7(std::pair<long, long>{}); >- f10({}); // { dg-error "could not convert" } >- f11({}); // { dg-error "could not convert" } >+ f10({}); // { dg-error "convert" } >+ f11({}); // { dg-error "convert" } > f10(std::pair<ExplicitDefault, int>{}); > f11(std::pair<ExplicitDefaultDefault, int>{}); > } ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-28 16:57 ` Jonathan Wakely @ 2021-04-28 17:19 ` Jonathan Wakely 0 siblings, 0 replies; 14+ messages in thread From: Jonathan Wakely @ 2021-04-28 17:19 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++, gcc-patches [-- Attachment #1: Type: text/plain, Size: 1318 bytes --] On 28/04/21 17:57 +0100, Jonathan Wakely wrote: >On 07/04/21 18:18 +0100, Jonathan Wakely wrote: >>On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >>>On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>>>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>>>><libstdc++@gcc.gnu.org> wrote: >>>>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>>>> >>>>>>After a period of deprecation we could remove them, and support P1951 >>>>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>>>> >>>>>The proposal sounds good to me. >>>> >>>>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. >>> >>>Here's a patch to implement it, for stage 1. >> >>And here's a patch to simplify the std::pair constraints using >>concepts, also for consideration in stage 1. > >I've pushed this to trunk too, after testing on powerpc64le-linux. And this adds a testcase to verify that the simplified version using concepts actually fixes PR 97930, as claimed above. Tested x86_64- linux, pushed to trunk. [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 1066 bytes --] commit c8767ee9f9355a63bfeb8318df32bc39c5b0f3ad Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Apr 28 18:14:05 2021 libstdc++: Add testcase for std::pair as a structural type [PR 97930] This PR was fixed by r12-221-ge1543e694dadf1ea70eb72325219bc0cdc914a35 (for compilers that support C++20 Concepts) so this adds the testcase. libstdc++-v3/ChangeLog: PR libstdc++/97930 * testsuite/20_util/pair/requirements/structural.cc: New test. diff --git a/libstdc++-v3/testsuite/20_util/pair/requirements/structural.cc b/libstdc++-v3/testsuite/20_util/pair/requirements/structural.cc new file mode 100644 index 00000000000..d4df20197ee --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/requirements/structural.cc @@ -0,0 +1,9 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } + +#include <utility> + +// C++20 20.4.2 [pairs.pair] +// pair<T, U> is a structural type (13.2) if T and U are both structural types. + +template<std::pair<int, int>> struct S; // PR libstdc++/97930 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 16:59 ` Jonathan Wakely 2021-04-07 17:18 ` Jonathan Wakely @ 2021-04-07 18:00 ` Jonathan Wakely 2021-04-07 18:17 ` Jonathan Wakely 2021-04-28 16:57 ` Jonathan Wakely 2 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-07 18:00 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++ On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>><libstdc++@gcc.gnu.org> wrote: >>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>> >>>>After a period of deprecation we could remove them, and support P1951 >>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>> >>>The proposal sounds good to me. >> >>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. > >Here's a patch to implement it, for stage 1. >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 <bool __implicit, typename _U1, typename _U2> >- static constexpr bool _CopyMovePair() >- { >- using __do_converts = __and_<is_convertible<const _U1&, _T1>, >- is_convertible<_U2&&, _T2>>; >- using __converts = typename conditional<__implicit, >- __do_converts, >- __not_<__do_converts>>::type; >- return __and_<is_constructible<_T1, const _U1&>, >- is_constructible<_T2, _U2&&>, >- __converts >- >::value; >- } > > template <bool __implicit, typename _U1, typename _U2> >- static constexpr bool _MoveCopyPair() >+ static constexpr bool _DeprConsPair() > { > using __do_converts = __and_<is_convertible<_U1&&, _T1>, >- is_convertible<const _U2&, _T2>>; >+ 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<_T1, _U1&&>, >- is_constructible<_T2, const _U2&&>, >+ is_constructible<_T2, _U2&&>, N.B. this fixes a bug in the line above, where const _U2&& is used in place of const _U2&. I'll create a testcase that tickles the bug and report it to bugzilla tomorrow. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 18:00 ` Jonathan Wakely @ 2021-04-07 18:17 ` Jonathan Wakely 2021-04-07 18:25 ` Ville Voutilainen 0 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-07 18:17 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++ On 07/04/21 19:00 +0100, Jonathan Wakely wrote: >On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >>On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>>><libstdc++@gcc.gnu.org> wrote: >>>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>>> >>>>>After a period of deprecation we could remove them, and support P1951 >>>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>>> >>>>The proposal sounds good to me. >>> >>>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. >> >>Here's a patch to implement it, for stage 1. > > >>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 <bool __implicit, typename _U1, typename _U2> >>- static constexpr bool _CopyMovePair() >>- { >>- using __do_converts = __and_<is_convertible<const _U1&, _T1>, >>- is_convertible<_U2&&, _T2>>; >>- using __converts = typename conditional<__implicit, >>- __do_converts, >>- __not_<__do_converts>>::type; >>- return __and_<is_constructible<_T1, const _U1&>, >>- is_constructible<_T2, _U2&&>, >>- __converts >>- >::value; >>- } >> >> template <bool __implicit, typename _U1, typename _U2> >>- static constexpr bool _MoveCopyPair() >>+ static constexpr bool _DeprConsPair() >> { >> using __do_converts = __and_<is_convertible<_U1&&, _T1>, >>- is_convertible<const _U2&, _T2>>; >>+ 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<_T1, _U1&&>, >>- is_constructible<_T2, const _U2&&>, >>+ is_constructible<_T2, _U2&&>, > >N.B. this fixes a bug in the line above, where const _U2&& is used in >place of const _U2&. > >I'll create a testcase that tickles the bug and report it to bugzilla >tomorrow. This fails to compile because of that bug: #include <utility> struct X { X(void* = 0) { } X(const X&) = default; X(const X&&) = delete; }; struct move_only { move_only() = default; move_only(move_only&&) = default; }; std::pair<move_only, X> p0(move_only(), 0); std::pair<move_only, X> p1(move_only(), {}); The pair(U1&&, const T2&) constructor should be viable, but it fails the _MoveCopyPair constraint check because X(const X&&) is deleted. I'm not sure I care about this though. It would only work because of those non-standard constructors which we're talking about deprecating. I'm not very motivated to fix them so they accept this, when we're going to deprecate them anyway. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 18:17 ` Jonathan Wakely @ 2021-04-07 18:25 ` Ville Voutilainen 2021-04-07 18:26 ` Ville Voutilainen 0 siblings, 1 reply; 14+ messages in thread From: Ville Voutilainen @ 2021-04-07 18:25 UTC (permalink / raw) To: Jonathan Wakely; +Cc: libstdc++ On Wed, 7 Apr 2021 at 21:17, Jonathan Wakely <jwakely@redhat.com> wrote: > This fails to compile because of that bug: > > #include <utility> > > struct X { > X(void* = 0) { } > X(const X&) = default; > X(const X&&) = delete; > }; > > struct move_only { > move_only() = default; > move_only(move_only&&) = default; > }; > > std::pair<move_only, X> p0(move_only(), 0); > std::pair<move_only, X> p1(move_only(), {}); > > The pair(U1&&, const T2&) constructor should be viable, but it fails > the _MoveCopyPair constraint check because X(const X&&) is deleted. > > I'm not sure I care about this though. It would only work because of > those non-standard constructors which we're talking about deprecating. > I'm not very motivated to fix them so they accept this, when we're > going to deprecate them anyway. Nah, let's not bother. The type X has an explicitly deleted move constructor, which the library doesn't go to heroic extents to support. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 18:25 ` Ville Voutilainen @ 2021-04-07 18:26 ` Ville Voutilainen 0 siblings, 0 replies; 14+ messages in thread From: Ville Voutilainen @ 2021-04-07 18:26 UTC (permalink / raw) To: Jonathan Wakely; +Cc: libstdc++ On Wed, 7 Apr 2021 at 21:25, Ville Voutilainen <ville.voutilainen@gmail.com> wrote: > > On Wed, 7 Apr 2021 at 21:17, Jonathan Wakely <jwakely@redhat.com> wrote: > > This fails to compile because of that bug: > > > > #include <utility> > > > > struct X { > > X(void* = 0) { } > > X(const X&) = default; > > X(const X&&) = delete; > > }; > > > > struct move_only { > > move_only() = default; > > move_only(move_only&&) = default; > > }; > > > > std::pair<move_only, X> p0(move_only(), 0); > > std::pair<move_only, X> p1(move_only(), {}); > > > > The pair(U1&&, const T2&) constructor should be viable, but it fails > > the _MoveCopyPair constraint check because X(const X&&) is deleted. > > > > I'm not sure I care about this though. It would only work because of > > those non-standard constructors which we're talking about deprecating. > > I'm not very motivated to fix them so they accept this, when we're > > going to deprecate them anyway. > > Nah, let's not bother. The type X has an explicitly deleted move > constructor, which the library > doesn't go to heroic extents to support. And more than that, it's trying to be a "copy-only" type, which the library doesn't try to support at all, quite the contrary. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-07 16:59 ` Jonathan Wakely 2021-04-07 17:18 ` Jonathan Wakely 2021-04-07 18:00 ` Jonathan Wakely @ 2021-04-28 16:57 ` Jonathan Wakely 2021-04-28 17:00 ` Jonathan Wakely 2 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-28 16:57 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++, gcc-patches On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>><libstdc++@gcc.gnu.org> wrote: >>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>> >>>>After a period of deprecation we could remove them, and support P1951 >>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>> >>>The proposal sounds good to me. >> >>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. > >Here's a patch to implement it, for stage 1. > > 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<int, int> 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. I've pushed this to trunk, after testing on powerpc64le-linux. >commit e20794c814c5961f0f33381a8eb3dff4fc741b5a >Author: Jonathan Wakely <jwakely@redhat.com> >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<int, int> 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 <bool __implicit, typename _U1, typename _U2> >- static constexpr bool _CopyMovePair() >- { >- using __do_converts = __and_<is_convertible<const _U1&, _T1>, >- is_convertible<_U2&&, _T2>>; >- using __converts = typename conditional<__implicit, >- __do_converts, >- __not_<__do_converts>>::type; >- return __and_<is_constructible<_T1, const _U1&>, >- is_constructible<_T2, _U2&&>, >- __converts >- >::value; >- } > > template <bool __implicit, typename _U1, typename _U2> >- static constexpr bool _MoveCopyPair() >+ static constexpr bool _DeprConsPair() > { > using __do_converts = __and_<is_convertible<_U1&&, _T1>, >- is_convertible<const _U2&, _T2>>; >+ 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<_T1, _U1&&>, >- is_constructible<_T2, const _U2&&>, >+ is_constructible<_T2, _U2&&>, > __converts >- >::value; >+ >::value; > } >- }; >+ }; > > template <typename _T1, typename _T2> > struct _PCC<false, _T1, _T2> >@@ -183,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > { > return false; > } >- }; >+ }; > #endif // C++11 > > template<typename _U1, typename _U2> 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 <typename _U1 = _T1, > typename _U2 = _T2, > typename enable_if<__and_< > __is_implicitly_default_constructible<_U1>, > __is_implicitly_default_constructible<_U2>> > ::value, bool>::type = true> >-#endif >- _GLIBCXX_CONSTEXPR pair() >+ constexpr pair() > : first(), second() { } > >-#if __cplusplus >= 201103L > template <typename _U1 = _T1, > typename _U2 = _T2, > typename enable_if<__and_< >@@ -244,13 +229,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > ::value, bool>::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<true, _T1, _T2>; >@@ -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<typename _U1, typename _U2> >- pair(const pair<_U1, _U2>& __p) >- : first(__p.first), second(__p.second) { } >-#else > // Shortcut for constraining the templates that take pairs. > /// @cond undocumented > template <typename _U1, typename _U2> >@@ -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<typename _U1, typename >- enable_if<_PCCP::template >- _MoveCopyPair<true, _U1, _T2>(), >- 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<typename _U1, typename >- enable_if<_PCCP::template >- _MoveCopyPair<false, _U1, _T2>(), >- 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<typename _Tp, >+ typename = __enable_if_t<is_null_pointer<_Tp>::value>> >+ __null_ptr_constant(_Tp) = delete; >+ }; > >- template<typename _U2, typename >- enable_if<_PCCP::template >- _CopyMovePair<true, _T1, _U2>(), >- 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<typename _Up, typename _Tp> >+ using __is_lvalue_of >+ = __or_<is_same<_Up, const _Tp&>, is_same<_Up, _Tp&>>; > >- template<typename _U2, typename >- enable_if<_PCCP::template >- _CopyMovePair<false, _T1, _U2>(), >- 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<typename _U1, >+ __enable_if_t<!__is_lvalue_of<_U1, _T1>::value >+ && _PCCP::template >+ _DeprConsPair<true, _U1, nullptr_t>(), >+ bool> = true> >+ _GLIBCXX_DEPRECATED_SUGGEST("nullptr") >+ constexpr pair(_U1&& __x, __null_ptr_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>(), >+ bool> = false> >+ _GLIBCXX_DEPRECATED_SUGGEST("nullptr") >+ explicit constexpr pair(_U1&& __x, __null_ptr_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>(), >+ bool> = true> >+ _GLIBCXX_DEPRECATED_SUGGEST("nullptr") >+ constexpr pair(__null_ptr_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>(), >+ 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<typename _U1, typename _U2, typename > enable_if<_PCCP::template >@@ -451,6 +451,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > _GLIBCXX20_CONSTEXPR > pair(tuple<_Args1...>&, 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<typename _U1, typename _U2> >+ 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 <utility> > > 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<int X::*, int X::*> p7(0, mp); > std::pair<int X::*, int X::*> p8(mp, mp); > >- std::pair<int*, move_only> p9(0, move_only()); >- std::pair<int X::*, move_only> p10(0, move_only()); >- std::pair<move_only, int*> p11(move_only(), 0); >- std::pair<move_only, int X::*> 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<int*, move_only> p9(nullptr, move_only()); >+ std::pair<int X::*, move_only> p10(nullptr, move_only()); >+ std::pair<move_only, int*> p11(move_only(), nullptr); >+ std::pair<move_only, int X::*> p12(move_only(), nullptr); > > std::pair<int*, move_only> p13(ip, move_only()); > std::pair<int X::*, move_only> 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 >+// <http://www.gnu.org/licenses/>. >+ >+// { dg-options "-Wdeprecated" } >+// { dg-do compile { target { c++11 } } } >+ >+#include <utility> >+ >+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<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" } >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<int*, ExplicitMoveOnly> v14{0, MoveOnly{}}; >-std::pair<ExplicitMoveOnly, int*> v15{MoveOnly{}, 0}; >+std::pair<int*, ExplicitMoveOnly> v14{nullptr, MoveOnly{}}; >+std::pair<ExplicitMoveOnly, int*> v15{MoveOnly{}, nullptr}; > > std::pair<int*, ExplicitMoveOnly> v16 = >- {0, MoveOnly{}}; // { dg-error "could not convert" } >+ {nullptr, MoveOnly{}}; // { dg-error "could not convert" } > std::pair<ExplicitMoveOnly, int*> v17 = >- {MoveOnly{}, 0}; // { dg-error "could not convert" } >+ {MoveOnly{}, nullptr}; // { dg-error "could not convert" } ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-28 16:57 ` Jonathan Wakely @ 2021-04-28 17:00 ` Jonathan Wakely 2021-04-28 17:11 ` Jonathan Wakely 0 siblings, 1 reply; 14+ messages in thread From: Jonathan Wakely @ 2021-04-28 17:00 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++, gcc-patches [-- Attachment #1: Type: text/plain, Size: 2100 bytes --] On 28/04/21 17:57 +0100, Jonathan Wakely wrote: >On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >>On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>>><libstdc++@gcc.gnu.org> wrote: >>>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>>> >>>>>After a period of deprecation we could remove them, and support P1951 >>>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>>> >>>>The proposal sounds good to me. >>> >>>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. >> >>Here's a patch to implement it, for stage 1. >> >> 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<int, int> 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. > > >I've pushed this to trunk, after testing on powerpc64le-linux. And here's the wwwdocs patch announcing the deprecation. Pushed to wwwdocs. [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 941 bytes --] commit 24151c175c08222c268d9c37cc8fa255e2b2384c Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Apr 28 17:59:50 2021 +0100 Document deprecation of non-standard std::pair constructors for GCC 12 diff --git a/htdocs/gcc-12/changes.html b/htdocs/gcc-12/changes.html index e0ac986e..912fc59b 100644 --- a/htdocs/gcc-12/changes.html +++ b/htdocs/gcc-12/changes.html @@ -30,6 +30,13 @@ a work-in-progress.</p> <!-- .................................................................. --> <h2>Caveats</h2> <ul> + <li> + Two non-standard <tt>std::pair</tt> constructors have been deprecated. + These allowed the use of an rvalue and a literal <tt>0</tt> to construct + a pair containing a move-only type and a pointer. The <tt>nullptr</tt> + keyword should be used to initialize the pointer member instead of a + literal <tt>0</tt>, as this is portable to other C++ implementations. + </li> <li>...</li> </ul> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] Deprecate non-standard constructors in std::pair 2021-04-28 17:00 ` Jonathan Wakely @ 2021-04-28 17:11 ` Jonathan Wakely 0 siblings, 0 replies; 14+ messages in thread From: Jonathan Wakely @ 2021-04-28 17:11 UTC (permalink / raw) To: Ville Voutilainen; +Cc: libstdc++, gcc-patches [-- Attachment #1: Type: text/plain, Size: 2219 bytes --] On 28/04/21 18:00 +0100, Jonathan Wakely wrote: >On 28/04/21 17:57 +0100, Jonathan Wakely wrote: >>On 07/04/21 17:59 +0100, Jonathan Wakely wrote: >>>On 07/04/21 13:46 +0100, Jonathan Wakely wrote: >>>>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote: >>>>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++ >>>>><libstdc++@gcc.gnu.org> wrote: >>>>>>I propose that we deprecate the constructors for C++11/14/17/20 in >>>>>>stage 1, and do not support them at all in C++23 mode once P1951 is >>>>>>supported. I have a patch which I'll send in stage 1 (it also uses >>>>>>C++20 concepts to simplify std::pair and fix PR 97930). >>>>>> >>>>>>After a period of deprecation we could remove them, and support P1951 >>>>>>for -std=gnu++11/14/17/20 too so that {} continues to work. >>>>> >>>>>The proposal sounds good to me. >>>> >>>>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget. >>> >>>Here's a patch to implement it, for stage 1. >>> >>> 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<int, int> 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. >> >> >>I've pushed this to trunk, after testing on powerpc64le-linux. > >And here's the wwwdocs patch announcing the deprecation. And the inevitable html validation fix. Pushed to wwwdocs. [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 1250 bytes --] commit b04fd89cb8bc48bad63fb59c91400bbf70e1f510 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Apr 28 18:08:33 2021 +0100 Replace <tt> elements with <code> for HTML5 compatibility diff --git a/htdocs/gcc-12/changes.html b/htdocs/gcc-12/changes.html index 912fc59b..23f71411 100644 --- a/htdocs/gcc-12/changes.html +++ b/htdocs/gcc-12/changes.html @@ -31,11 +31,12 @@ a work-in-progress.</p> <h2>Caveats</h2> <ul> <li> - Two non-standard <tt>std::pair</tt> constructors have been deprecated. - These allowed the use of an rvalue and a literal <tt>0</tt> to construct - a pair containing a move-only type and a pointer. The <tt>nullptr</tt> - keyword should be used to initialize the pointer member instead of a - literal <tt>0</tt>, as this is portable to other C++ implementations. + Two non-standard <code>std::pair</code> constructors have been deprecated. + These allowed the use of an rvalue and a literal <code>0</code> to + construct a pair containing a move-only type and a pointer. + The <code>nullptr</code> keyword should be used to initialize the pointer + member instead of a literal <code>0</code>, as this is portable to other + C++ implementations. </li> <li>...</li> </ul> ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2021-04-28 17:19 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-04-07 12:30 [RFC] Deprecate non-standard constructors in std::pair Jonathan Wakely 2021-04-07 12:41 ` Ville Voutilainen 2021-04-07 12:46 ` Jonathan Wakely 2021-04-07 16:59 ` Jonathan Wakely 2021-04-07 17:18 ` Jonathan Wakely 2021-04-28 16:57 ` Jonathan Wakely 2021-04-28 17:19 ` Jonathan Wakely 2021-04-07 18:00 ` Jonathan Wakely 2021-04-07 18:17 ` Jonathan Wakely 2021-04-07 18:25 ` Ville Voutilainen 2021-04-07 18:26 ` Ville Voutilainen 2021-04-28 16:57 ` Jonathan Wakely 2021-04-28 17:00 ` Jonathan Wakely 2021-04-28 17:11 ` Jonathan Wakely
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).