Commit 6fedf28c by Jonathan Wakely

libstdc++: Replace deduced return type in ranges::iter_move (PR 92894)

The deduced return type causes the instantiation of the function body,
which can then require the instantiation of std::projected::operator*
which is intentionally not defined.

This patch uses a helper trait to define the return type, so that the
function body doesn't need to be instantiated.

Unlike on the master branch, this backport to gcc-10 does not change the
iter_rvalue_reference_t alias template and __indirectly_readable_impl
concept to use the new trait.

Backport from mainline
2020-05-01  Jonathan Wakely  <jwakely@redhat.com>
	    Patrick Palka  <ppalka@redhat.com>

	PR libstdc++/92894
	* include/bits/iterator_concepts.h (ranges::__cust_imove::_IMove):
	Add trait to determine return type and an alias for it.
	(ranges::__cust_imove::_IMove::operator()): Use __result instead of
	deduced return type.
	* testsuite/24_iterators/customization_points/92894.cc: New test.
	* testsuite/24_iterators/indirect_callable/92894.cc: New test.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
parent e5613c55
2020-05-07 Jonathan Wakely <jwakely@redhat.com>
Backport from mainline
2020-05-01 Jonathan Wakely <jwakely@redhat.com>
Patrick Palka <ppalka@redhat.com>
PR libstdc++/92894
* include/bits/iterator_concepts.h (ranges::__cust_imove::_IMove):
Add trait to determine return type and an alias for it.
(ranges::__cust_imove::_IMove::operator()): Use __result instead of
deduced return type.
* testsuite/24_iterators/customization_points/92894.cc: New test.
* testsuite/24_iterators/indirect_callable/92894.cc: New test.
2020-05-07 Release Manager 2020-05-07 Release Manager
* GCC 10.1.0 released. * GCC 10.1.0 released.
......
...@@ -90,6 +90,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -90,6 +90,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ {
private: private:
template<typename _Tp> template<typename _Tp>
struct __result
{ using type = iter_reference_t<_Tp>; };
template<typename _Tp>
requires __adl_imove<_Tp>
struct __result<_Tp>
{ using type = decltype(iter_move(std::declval<_Tp>())); };
template<typename _Tp>
requires (!__adl_imove<_Tp>)
&& is_lvalue_reference_v<iter_reference_t<_Tp>>
struct __result<_Tp>
{ using type = remove_reference_t<iter_reference_t<_Tp>>&&; };
template<typename _Tp>
static constexpr bool static constexpr bool
_S_noexcept() _S_noexcept()
{ {
...@@ -100,16 +115,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -100,16 +115,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
public: public:
template<typename _Tp> // The result type of iter_move(std::declval<_Tp>())
requires __adl_imove<_Tp> || requires(_Tp& __e) { *__e; } template<std::__detail::__dereferenceable _Tp>
constexpr decltype(auto) using __type = typename __result<_Tp>::type;
template<std::__detail::__dereferenceable _Tp>
constexpr __type<_Tp>
operator()(_Tp&& __e) const operator()(_Tp&& __e) const
noexcept(_S_noexcept<_Tp>()) noexcept(_S_noexcept<_Tp>())
{ {
if constexpr (__adl_imove<_Tp>) if constexpr (__adl_imove<_Tp>)
return iter_move(static_cast<_Tp&&>(__e)); return iter_move(static_cast<_Tp&&>(__e));
else if constexpr (is_reference_v<iter_reference_t<_Tp>>) else if constexpr (is_lvalue_reference_v<iter_reference_t<_Tp>>)
return std::move(*__e); return static_cast<__type<_Tp>>(*__e);
else else
return *__e; return *__e;
} }
......
// Copyright (C) 2020 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 "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <iterator>
using namespace std;
// Define our own of version of indirectly_readable_impl here,
// to check the use of iter_move even if the real concept in
// <bits/iterator_concepts.h> no longer uses iter_move.
template<class In>
concept indirectly_readable_impl
= requires(const In in)
{
typename iter_value_t<In>;
typename iter_reference_t<In>;
typename iter_rvalue_reference_t<In>;
{ *in } -> same_as<iter_reference_t<In>>;
{ ranges::iter_move(in) } -> same_as<iter_rvalue_reference_t<In>>;
};
template<class T> requires indirectly_readable_impl<projected<T*, identity>>
void algo(T)
{ }
void
test01()
{
// PR libstdc++/92894
// Verify that the use of range::iter_move above doesn't cause odr-use of
// projected<local-class-type, identity>::operator* (which is not defined).
struct X { };
X a;
algo(a);
}
// Copyright (C) 2020 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 "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <iterator>
using std::projected;
using std::identity;
using std::indirect_unary_predicate;
template<typename T,
indirect_unary_predicate<projected<T*, identity>> Pred>
constexpr void
all_of(T*, Pred)
{ }
void
test01()
{
// PR libstdc++/92894
struct X { };
X x;
all_of(&x, [](X&) { return false; });
}
template<class R, class Proj = identity,
indirect_unary_predicate<projected<R, Proj>> Pred>
constexpr void
find_if(R, Pred, Proj = {})
{ }
void
test02()
{
// PR 94241
struct s { int m; };
s r[] = { s{0}, s{1}, s{2}, s{3} };
find_if(r, [](auto const) { return true; });
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment