mirror of git://gcc.gnu.org/git/gcc.git
libstdc++: Fix construction function_ref from nontype<&S::x> and reference_wrapper [PR121858]
To reduce instantiation count, function_ref(nontype<&S::x>, r) previously reused the invoker from function_ref(nontype<&S::x>, &r). This assumed r was always a reference to S or a derived class. However, this constructor is also valid for lvalues (but not rvalues) of reference_wrapper specializations. This patch fixes this by limiting above optimization only to situations, when argument is not specialization of reference_wrapper. This is achieved bu comparing __inv_unwrap<_Td>::type with _Td. We use __inv_unwrap because unwrap_reference_t does not handle cv-qualified types. PR libstdc++/121858 libstdc++-v3/ChangeLog: * include/bits/funcref_impl.h (function_ref::function_ref(nontype<__fn>, _Up&&)): Handle. reference_wrapper. * testsuite/20_util/function_ref/call.cc: Call and update test05(). Add new test06() for reference_wrapper. Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
parent
594dc80c8e
commit
ac45382d0c
|
|
@ -138,13 +138,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
|
||||
static_assert(__fn != nullptr);
|
||||
|
||||
using _Tr = _Td _GLIBCXX_MOF_CV&;
|
||||
if constexpr (is_member_pointer_v<_Fn> && is_lvalue_reference_v<_Tr>)
|
||||
if constexpr (is_member_pointer_v<_Fn>
|
||||
&& same_as<_Td, typename __inv_unwrap<_Td>::type>)
|
||||
// N.B. invoking member pointer on lvalue produces the same effects,
|
||||
// as invoking it on pointer to that lvalue.
|
||||
_M_invoke = &_Invoker::template _S_bind_ptr<__fn, _Td _GLIBCXX_MOF_CV>;
|
||||
else
|
||||
_M_invoke = &_Invoker::template _S_bind_ref<__fn, _Tr>;
|
||||
_M_invoke = &_Invoker::template _S_bind_ref<__fn, _Td _GLIBCXX_MOF_CV&>;
|
||||
_M_init(std::addressof(__ref));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ int callback_ref(ftype& f, int x) { return f(x); }
|
|||
void
|
||||
test05()
|
||||
{
|
||||
|
||||
function_ref<int(int)> r1(nontype<&callback_ptr>, &twice);
|
||||
VERIFY( r1(2) == 4 );
|
||||
function_ref<int(int)> r2(nontype<&callback_ptr>, cube);
|
||||
|
|
@ -140,27 +139,103 @@ test05()
|
|||
VERIFY( r3(3) == 6 );
|
||||
function_ref<int(int)> r4(nontype<&callback_ref>, cube);
|
||||
VERIFY( r4(3) == 27 );
|
||||
}
|
||||
|
||||
// Checks if distinction between reference and pointer
|
||||
// is preserved.
|
||||
struct F
|
||||
{
|
||||
static
|
||||
int operator()(ftype* f, int x)
|
||||
{ return f(x) + 1000; }
|
||||
void
|
||||
test06()
|
||||
{
|
||||
struct S {
|
||||
int v;
|
||||
int& m() { return v; }
|
||||
const int& c() const { return v; }
|
||||
|
||||
static
|
||||
int operator()(ftype& f, int x)
|
||||
{ return f(x) + 2000; }
|
||||
int& operator()(int) { return v; }
|
||||
int const& operator()(int, int) const { return v; }
|
||||
};
|
||||
function_ref<int(int)> r5(nontype<F{}>, &twice);
|
||||
VERIFY( r5(2) == 1004 );
|
||||
function_ref<int(int)> r6(nontype<F{}>, twice);
|
||||
VERIFY( r6(2) == 2008 );
|
||||
function_ref<int(int)> r7(nontype<F{}>, &cube);
|
||||
VERIFY( r7(3) == 1006 );
|
||||
function_ref<int(int)> r8(nontype<F{}>, cube);
|
||||
VERIFY( r8(3) == 2027 );
|
||||
S s{10};
|
||||
std::reference_wrapper<S> sr(s);
|
||||
std::reference_wrapper<const S> csr(s);
|
||||
|
||||
std::function_ref<int&(int)> e1(sr);
|
||||
VERIFY( &e1(0) == &s.v );
|
||||
std::function_ref<int&(int) const> e2(sr);
|
||||
VERIFY( &e2(0) == &s.v );
|
||||
std::function_ref<int&(int) const> e3(std::as_const(sr));
|
||||
VERIFY( &e3(0) == &s.v );
|
||||
|
||||
std::function_ref<const int&(int, int)> e4(sr);
|
||||
VERIFY( &e4(0, 0) == &s.v );
|
||||
std::function_ref<const int&(int, int) const> e5(sr);
|
||||
VERIFY( &e5(0, 0) == &s.v );
|
||||
std::function_ref<const int&(int, int)> e6(csr);
|
||||
VERIFY( &e6(0, 0) == &s.v );
|
||||
std::function_ref<const int&(int, int) const> e7(csr);
|
||||
VERIFY( &e7(0, 0) == &s.v );
|
||||
std::function_ref<const int&(int, int) const> e8(std::as_const(csr));
|
||||
VERIFY( &e8(0, 0) == &s.v );
|
||||
|
||||
std::function_ref<int&()> f1(std::nontype<&S::v>, sr);
|
||||
VERIFY( &f1() == &s.v );
|
||||
std::function_ref<const int&()> f2(std::nontype<&S::v>, sr);
|
||||
VERIFY( &f2() == &s.v );
|
||||
std::function_ref<int&()> f3(std::nontype<&S::m>, sr);
|
||||
VERIFY( &f3() == &s.v );
|
||||
std::function_ref<const int&()> f4(std::nontype<&S::c>, sr);
|
||||
VERIFY( &f4() == &s.v );
|
||||
|
||||
std::function_ref<const int&()> f5(std::nontype<&S::v>, csr);
|
||||
VERIFY( &f5() == &s.v );
|
||||
std::function_ref<const int&()> f6(std::nontype<&S::c>, sr);
|
||||
VERIFY( &f6() == &s.v );
|
||||
static_assert( !std::is_constructible_v<
|
||||
std::function_ref<int&()>,
|
||||
std::nontype_t<&S::c>, std::reference_wrapper<S>&>
|
||||
);
|
||||
|
||||
std::function_ref<int&()> f7(std::nontype<&S::v>, std::as_const(sr));
|
||||
VERIFY( &f7() == &s.v );
|
||||
std::function_ref<const int&()> f8(std::nontype<&S::m>, std::as_const(sr));
|
||||
VERIFY( &f8() == &s.v );
|
||||
|
||||
// No rvalue reference_wrapper support
|
||||
static_assert( !std::is_constructible_v<
|
||||
std::function_ref<int&()>,
|
||||
std::nontype_t<&S::v>, std::reference_wrapper<S>>
|
||||
);
|
||||
static_assert( !std::is_constructible_v<
|
||||
std::function_ref<int&()>,
|
||||
std::nontype_t<&S::v>, std::reference_wrapper<const S>>
|
||||
);
|
||||
|
||||
// reference to reference_wrapper are bound, so mutation are visible
|
||||
S s2{20};
|
||||
sr = s2;
|
||||
csr = s2;
|
||||
VERIFY( &e1(0) == &s2.v );
|
||||
VERIFY( &e2(0) == &s2.v );
|
||||
VERIFY( &e3(0) == &s2.v );
|
||||
VERIFY( &e4(0, 0) == &s2.v );
|
||||
VERIFY( &e5(0, 0) == &s2.v );
|
||||
VERIFY( &e6(0, 0) == &s2.v );
|
||||
VERIFY( &e7(0, 0) == &s2.v );
|
||||
VERIFY( &e8(0, 0) == &s2.v );
|
||||
VERIFY( &f1() == &s2.v );
|
||||
VERIFY( &f2() == &s2.v );
|
||||
VERIFY( &f3() == &s2.v );
|
||||
VERIFY( &f4() == &s2.v );
|
||||
VERIFY( &f5() == &s2.v );
|
||||
VERIFY( &f6() == &s2.v );
|
||||
VERIFY( &f7() == &s2.v );
|
||||
VERIFY( &f8() == &s2.v );
|
||||
|
||||
constexpr auto id = []<typename T>(const std::reference_wrapper<T>& x)
|
||||
{ return &x; };
|
||||
|
||||
// identity of reference_wrapper is preserved
|
||||
std::function_ref<const std::reference_wrapper<S>*()> g1(std::nontype<id>, sr);
|
||||
VERIFY( g1() == &sr );
|
||||
std::function_ref<const std::reference_wrapper<const S>*()> g2(std::nontype<id>, csr);
|
||||
VERIFY( g2() == &csr );
|
||||
}
|
||||
|
||||
struct Incomplete;
|
||||
|
|
@ -182,5 +257,7 @@ int main()
|
|||
test02();
|
||||
test03();
|
||||
test04();
|
||||
test05();
|
||||
test06();
|
||||
test_params();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue