+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.
+ (iter_rvalue_reference_t): Use _IMove::__type instead of checking
+ the result of ranges::iter_move.
+ (__detail::__indirectly_readable_impl): Use iter_rvalue_reference_t
+ instead of checking the result of ranges::iter_move.
+ * testsuite/24_iterators/customization_points/92894.cc: New test.
+ * testsuite/24_iterators/indirect_callable/92894.cc: New test.
+
2020-05-01 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/94901
struct _IMove
{
private:
+ 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
_S_noexcept()
}
public:
- template<typename _Tp>
- requires __adl_imove<_Tp> || requires(_Tp& __e) { *__e; }
- constexpr decltype(auto)
+ // The result type of iter_move(std::declval<_Tp>())
+ template<std::__detail::__dereferenceable _Tp>
+ using __type = typename __result<_Tp>::type;
+
+ template<std::__detail::__dereferenceable _Tp>
+ constexpr __type<_Tp>
operator()(_Tp&& __e) const
noexcept(_S_noexcept<_Tp>())
{
if constexpr (__adl_imove<_Tp>)
return iter_move(static_cast<_Tp&&>(__e));
- else if constexpr (is_reference_v<iter_reference_t<_Tp>>)
- return std::move(*__e);
+ else if constexpr (is_lvalue_reference_v<iter_reference_t<_Tp>>)
+ return static_cast<__type<_Tp>>(*__e);
else
return *__e;
}
} // namespace ranges
template<__detail::__dereferenceable _Tp>
- requires requires(_Tp& __t)
- { { ranges::iter_move(__t) } -> __detail::__can_reference; }
+ requires __detail::
+ __can_reference<ranges::__cust_imove::_IMove::__type<_Tp&>>
using iter_rvalue_reference_t
- = decltype(ranges::iter_move(std::declval<_Tp&>()));
+ = ranges::__cust_imove::_IMove::__type<_Tp&>;
template<typename> struct incrementable_traits { };
using __iter_concept = typename __iter_concept_impl<_Iter>::type;
template<typename _In>
- concept __indirectly_readable_impl = requires(const _In __in)
+ concept __indirectly_readable_impl = requires
{
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>>;
+ requires same_as<iter_reference_t<const _In>,
+ iter_reference_t<_In>>;
+ requires same_as<iter_rvalue_reference_t<const _In>,
+ iter_rvalue_reference_t<_In>>;
}
&& common_reference_with<iter_reference_t<_In>&&, iter_value_t<_In>&>
&& common_reference_with<iter_reference_t<_In>&&,
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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; });
+}