mirror of git://gcc.gnu.org/git/gcc.git
libstdc++: Fix std::get<T> for std::pair with reference members [PR121745]
Make the std::get<T> overloads for rvalues use std::forward<T>(p.first) not std::move(p.first), so that lvalue reference members are not incorrectly converted to rvalues. It might appear that std::move(p).first would also work, but the language rules say that for std::pair<T&&, U> that would produce T& rather than the expected T&& (see the discussion in P2445R1 §8.2). Additional tests are added to verify all combinations of reference members, value categories, and const-qualification. libstdc++-v3/ChangeLog: PR libstdc++/121745 * include/bits/stl_pair.h (get): Use forward instead of move in std::get<T> overloads for rvalue pairs. * testsuite/20_util/pair/astuple/get_by_type.cc: Check all value categories and cv-qualification. Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
parent
dd6fe9f557
commit
c8a24f60b6
|
@ -1315,12 +1315,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
template <typename _Tp, typename _Up>
|
||||
constexpr _Tp&&
|
||||
get(pair<_Tp, _Up>&& __p) noexcept
|
||||
{ return std::move(__p.first); }
|
||||
{ return std::forward<_Tp>(__p.first); }
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
constexpr const _Tp&&
|
||||
get(const pair<_Tp, _Up>&& __p) noexcept
|
||||
{ return std::move(__p.first); }
|
||||
{ return std::forward<const _Tp>(__p.first); }
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
constexpr _Tp&
|
||||
|
@ -1335,12 +1335,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
template <typename _Tp, typename _Up>
|
||||
constexpr _Tp&&
|
||||
get(pair<_Up, _Tp>&& __p) noexcept
|
||||
{ return std::move(__p.second); }
|
||||
{ return std::forward<_Tp>(__p.second); }
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
constexpr const _Tp&&
|
||||
get(const pair<_Up, _Tp>&& __p) noexcept
|
||||
{ return std::move(__p.second); }
|
||||
{ return std::forward<const _Tp>(__p.second); }
|
||||
#endif // __glibcxx_tuples_by_type
|
||||
|
||||
|
||||
|
|
|
@ -33,3 +33,55 @@ void test01()
|
|||
const int&& cpsecond __attribute__((unused)) =
|
||||
std::get<int>(std::move(cp));
|
||||
}
|
||||
|
||||
// PR libstdc++/121745 return of get(pair<_Up, _Tp>&& __p) may be ill-formed
|
||||
void
|
||||
test_pr121745(std::pair<float&, int&> p)
|
||||
{
|
||||
float& pfirst = std::get<float&>(std::move(p));
|
||||
int& psecond = std::get<int&>(std::move(p));
|
||||
|
||||
const auto& p2 = p;
|
||||
float& p2first = std::get<float&>(std::move(p2));
|
||||
int& p2second = std::get<int&>(std::move(p2));
|
||||
}
|
||||
|
||||
template<typename T, typename Pair>
|
||||
using get_t = decltype(std::get<T>(std::declval<Pair>()));
|
||||
|
||||
// Check that get<T>(Pair) returns Ret
|
||||
template<typename T, typename Pair, typename Ret>
|
||||
constexpr bool verify = std::is_same<get_t<T, Pair>, Ret>::value;
|
||||
|
||||
template<typename T1, typename T2>
|
||||
void
|
||||
check()
|
||||
{
|
||||
// Overloads for accessing first member
|
||||
static_assert( verify<T1, std::pair<T1, T2>&, T1&>,
|
||||
"T1& get(pair<T1, T2>&)" );
|
||||
static_assert( verify<T1, const std::pair<T1, T2>&, const T1&>,
|
||||
"const T1& get(const pair<T1, T2>&)" );
|
||||
static_assert( verify<T1, std::pair<T1, T2>&&, T1&&>,
|
||||
"T1&& get(pair<T1, T2>&&)" );
|
||||
static_assert( verify<T1, const std::pair<T1, T2>&&, const T1&&>,
|
||||
"const T1&& get(const pair<T1, T2>&&)" );
|
||||
|
||||
// Overloads for accessing second member
|
||||
static_assert( verify<T2, std::pair<T1, T2>&, T2&>,
|
||||
"T2& get(pair<T1, T2>&)" );
|
||||
static_assert( verify<T2, const std::pair<T1, T2>&, const T2&>,
|
||||
"const T2& get(const pair<T1, T2>&)" );
|
||||
static_assert( verify<T2, std::pair<T1, T2>&&, T2&&>,
|
||||
"T2&& get(pair<T1, T2>&&)" );
|
||||
static_assert( verify<T2, const std::pair<T1, T2>&&, const T2&&>,
|
||||
"const T2&& get(const pair<T1, T2>&&)" );
|
||||
}
|
||||
|
||||
void
|
||||
test_all()
|
||||
{
|
||||
check<float, int>();
|
||||
check<float&, int&>();
|
||||
check<float&&, int&&>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue