From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 20F9E3AA981B; Wed, 28 Apr 2021 16:57:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 20F9E3AA981B MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-221] libstdc++: Simplify std::pair constraints using concepts X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: d96db15967e78d7cecea3b1cf3169ceb924678ac X-Git-Newrev: e1543e694dadf1ea70eb72325219bc0cdc914a35 Message-Id: <20210428165706.20F9E3AA981B@sourceware.org> Date: Wed, 28 Apr 2021 16:57:06 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Apr 2021 16:57:06 -0000 https://gcc.gnu.org/g:e1543e694dadf1ea70eb72325219bc0cdc914a35 commit r12-221-ge1543e694dadf1ea70eb72325219bc0cdc914a35 Author: Jonathan Wakely Date: Wed Apr 28 17:46:01 2021 +0100 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) [__cplusplus > 202002]: Add new definitions for constructors and assignment operators using concepts for constraints. * 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: --- libstdc++-v3/include/bits/stl_pair.h | 221 ++++++++++++++++++--- libstdc++-v3/testsuite/20_util/pair/cons/99957.cc | 2 +- .../20_util/pair/cons/explicit_construct.cc | 8 +- 3 files changed, 193 insertions(+), 38 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 883d7441b3d..c89f377fddc 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 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 class __pair_base { -#if __cplusplus >= 201103L +#if __cplusplus >= 201103L && ! __cpp_lib_concepts template friend struct pair; __pair_base() = default; ~__pair_base() = default; @@ -196,7 +198,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template 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 + _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 + _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 + static constexpr bool + _S_constructible() + { + if constexpr (is_constructible_v<_T1, _U1>) + return is_constructible_v<_T2, _U2>; + return false; + } + + template + static constexpr bool + _S_nothrow_constructible() + { + if constexpr (is_nothrow_constructible_v<_T1, _U1>) + return is_nothrow_constructible_v<_T2, _U2>; + return false; + } + + template + 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()) + pair(const _T1& __x, const _T2& __y) + noexcept(_S_nothrow_constructible()) + requires (_S_constructible()) + : first(__x), second(__y) + { } + + /// Constructor accepting two values of arbitrary types + template + 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` lvalue + template + requires (_S_constructible()) + constexpr explicit(!_S_convertible()) + pair(const pair<_U1, _U2>& __p) + noexcept(_S_nothrow_constructible()) + : first(__p.first), second(__p.second) + { } + + /// Converting constructor from a `pair` rvalue + template + 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 + static constexpr bool + _S_assignable() + { + if constexpr (is_assignable_v<_T1&, _U1>) + return is_assignable_v<_T2&, _U2>; + return false; + } + + template + 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()) + requires (_S_assignable()) + { + 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(__p.first); + second = std::forward(__p.second); + return *this; + } + + /// Converting assignment from a `pair` lvalue + template + constexpr pair& + operator=(const pair<_U1, _U2>& __p) + noexcept(_S_nothrow_assignable()) + requires (_S_assignable()) + { + first = __p.first; + second = __p.second; + return *this; + } + + /// Converting assignment from a `pair` rvalue + template + 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(__p.first)), second(std::forward<_U2>(__p.second)) { } - template - _GLIBCXX20_CONSTEXPR - pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); - - _GLIBCXX20_CONSTEXPR pair& + pair& operator=(typename conditional< __and_, is_copy_assignable<_T2>>::value, @@ -397,7 +571,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - _GLIBCXX20_CONSTEXPR pair& + pair& operator=(typename conditional< __and_, is_move_assignable<_T2>>::value, @@ -411,7 +585,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - _GLIBCXX20_CONSTEXPR typename enable_if<__and_, is_assignable<_T2&, const _U2&>>::value, pair&>::type @@ -423,7 +596,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - _GLIBCXX20_CONSTEXPR typename enable_if<__and_, is_assignable<_T2&, _U2&&>>::value, pair&>::type @@ -433,24 +605,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 - _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 d75ff21da60..150bcd57c9a 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc @@ -1,5 +1,5 @@ // { dg-options "-Wdeprecated" } -// { dg-do compile { target c++11 } } +// { dg-do compile { target { c++11 && { ! c++20 } } } } #include 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) {} std::pair f8() { - return {}; // { dg-error "could not convert" } + return {}; // { dg-error "convert" } } std::pair f9() { - return {}; // { dg-error "could not convert" } + return {}; // { dg-error "convert" } } void f10(std::pair) {} @@ -107,8 +107,8 @@ void test_arg_passing() f7({1,2}); f7(std::pair{}); f7(std::pair{}); - f10({}); // { dg-error "could not convert" } - f11({}); // { dg-error "could not convert" } + f10({}); // { dg-error "convert" } + f11({}); // { dg-error "convert" } f10(std::pair{}); f11(std::pair{}); }