From a5f2fb1ff1742685a91dfdf78da871fd4d3292e5 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 1 May 2020 14:27:25 +0100 Subject: [PATCH] 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. That helper trait can then also be used in other places that currently check the return type of ranges::iter_move (iter_rvalue_reference_t and indirectly_readable). 2020-05-01 Jonathan Wakely Patrick Palka 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. --- libstdc++-v3/ChangeLog | 15 +++++ libstdc++-v3/include/bits/iterator_concepts.h | 42 ++++++++++---- .../customization_points/92894.cc | 52 ++++++++++++++++++ .../24_iterators/indirect_callable/92894.cc | 55 +++++++++++++++++++ 4 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 libstdc++-v3/testsuite/24_iterators/customization_points/92894.cc create mode 100644 libstdc++-v3/testsuite/24_iterators/indirect_callable/92894.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f699a1bc59e..152c69f843f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2020-05-01 Jonathan Wakely + Patrick Palka + + 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 PR libstdc++/94901 diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index b598532089e..e221ec70367 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -89,6 +89,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct _IMove { private: + template + struct __result + { using type = iter_reference_t<_Tp>; }; + + template + requires __adl_imove<_Tp> + struct __result<_Tp> + { using type = decltype(iter_move(std::declval<_Tp>())); }; + + template + requires (!__adl_imove<_Tp>) + && is_lvalue_reference_v> + struct __result<_Tp> + { using type = remove_reference_t>&&; }; + template static constexpr bool _S_noexcept() @@ -100,16 +115,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } public: - template - requires __adl_imove<_Tp> || requires(_Tp& __e) { *__e; } - constexpr decltype(auto) + // The result type of iter_move(std::declval<_Tp>()) + template + using __type = typename __result<_Tp>::type; + + template + 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>) - return std::move(*__e); + else if constexpr (is_lvalue_reference_v>) + return static_cast<__type<_Tp>>(*__e); else return *__e; } @@ -123,10 +141,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // namespace ranges template<__detail::__dereferenceable _Tp> - requires requires(_Tp& __t) - { { ranges::iter_move(__t) } -> __detail::__can_reference; } + requires __detail:: + __can_reference> using iter_rvalue_reference_t - = decltype(ranges::iter_move(std::declval<_Tp&>())); + = ranges::__cust_imove::_IMove::__type<_Tp&>; template struct incrementable_traits { }; @@ -443,13 +461,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __iter_concept = typename __iter_concept_impl<_Iter>::type; template - 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>; - { ranges::iter_move(__in) } -> same_as>; + requires same_as, + iter_reference_t<_In>>; + requires same_as, + iter_rvalue_reference_t<_In>>; } && common_reference_with&&, iter_value_t<_In>&> && common_reference_with&&, diff --git a/libstdc++-v3/testsuite/24_iterators/customization_points/92894.cc b/libstdc++-v3/testsuite/24_iterators/customization_points/92894.cc new file mode 100644 index 00000000000..197268fe5e3 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/customization_points/92894.cc @@ -0,0 +1,52 @@ +// 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +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 +// no longer uses iter_move. +template +concept indirectly_readable_impl + = requires(const In in) + { + typename iter_value_t; + typename iter_reference_t; + typename iter_rvalue_reference_t; + { *in } -> same_as>; + { ranges::iter_move(in) } -> same_as>; + }; + +template requires indirectly_readable_impl> + void algo(T) + { } + +void +test01() +{ + // PR libstdc++/92894 + // Verify that the use of range::iter_move above doesn't cause odr-use of + // projected::operator* (which is not defined). + struct X { }; + X a; + algo(a); +} diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/92894.cc b/libstdc++-v3/testsuite/24_iterators/indirect_callable/92894.cc new file mode 100644 index 00000000000..3408c76bde1 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/92894.cc @@ -0,0 +1,55 @@ +// 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +using std::projected; +using std::identity; +using std::indirect_unary_predicate; + +template> Pred> + constexpr void + all_of(T*, Pred) + { } + +void +test01() +{ + // PR libstdc++/92894 + struct X { }; + X x; + all_of(&x, [](X&) { return false; }); +} + +template> 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; }); +} -- 2.30.2