aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2021-04-28 17:46:01 +0100
committerJonathan Wakely <jwakely@redhat.com>2021-04-28 17:56:51 +0100
commite1543e694dadf1ea70eb72325219bc0cdc914a35 (patch)
tree36e3876b1d3f5e82b548f7906df902ee1198d902
parentd96db15967e78d7cecea3b1cf3169ceb924678ac (diff)
downloadgcc-e1543e694dadf1ea70eb72325219bc0cdc914a35.zip
gcc-e1543e694dadf1ea70eb72325219bc0cdc914a35.tar.gz
gcc-e1543e694dadf1ea70eb72325219bc0cdc914a35.tar.bz2
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.
-rw-r--r--libstdc++-v3/include/bits/stl_pair.h221
-rw-r--r--libstdc++-v3/testsuite/20_util/pair/cons/99957.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc8
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 883d744..c89f377 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,11 +560,7 @@ _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&
+ pair&
operator=(typename conditional<
__and_<is_copy_assignable<_T1>,
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<_T1>,
is_move_assignable<_T2>>::value,
@@ -411,7 +585,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _U1, typename _U2>
- _GLIBCXX20_CONSTEXPR
typename enable_if<__and_<is_assignable<_T1&, const _U1&>,
is_assignable<_T2&, const _U2&>>::value,
pair&>::type
@@ -423,7 +596,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _U1, typename _U2>
- _GLIBCXX20_CONSTEXPR
typename enable_if<__and_<is_assignable<_T1&, _U1&&>,
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<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 d75ff21..150bcd5 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 <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 508ca32..ecd5acf 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>{});
}