Tested on x86_64-pc-linux-gnu, does this look OK for trunk only? This doesn't seem worth backporting since there should be no behavior change.
-- >8 -- This implements the library changes in P0849R8 "auto(x): decay-copy in the language" which consist of replacing most uses of the exposition-only function decay-copy with auto(x) throughout the library wording. Note the main difference between the two is that decay-copy materializes its argument whereas auto(x) doesn't, and so the latter is a no-op when its argument is a prvalue. Effectively the former could introduce an unnecessary move constructor call in some contexts. In C++20 and earlier we could emulate auto(x) with decay_t<decltype((x))>(x). After this paper the only remaining uses of decay-copy in the library are in the specification of some range adaptors. In our implementation of those range adaptors I believe decay-copy is already implied which is why we don't mirror the wording and use __decay_copy explicitly. So since it's apparently no longer needed this patch goes ahead and removes __decay_copy. libstdc++-v3/ChangeLog: * c++config (_GLIBCXX_AUTO_CAST): Define. * include/bits/iterator_concepts.h (_Decay_copy, __decay_copy): Remove. (__member_begin, __adl_begin): Use _GLIBCXX_AUTO_CAST instead of __decay_copy as per P0849R8. * include/bits/ranges_base.h (_Begin): Likewise. (__member_end, __adl_end, _End): Likewise. (__member_rbegin, __adl_rbegin, _RBegin): Likewise. (__member_rend, __adl_rend, _Rend): Likewise. (__member_size, __adl_size, _Size): Likewise. (_Data): Likewise. --- libstdc++-v3/include/bits/c++config | 6 +++ libstdc++-v3/include/bits/iterator_concepts.h | 13 +----- libstdc++-v3/include/bits/ranges_base.h | 40 +++++++++---------- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 29d795f687c..fdbf90e28fc 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -265,6 +265,12 @@ #define _GLIBCXX_NOEXCEPT_QUAL #endif +#if __cpp_auto_cast +# define _GLIBCXX_AUTO_CAST(X) auto(X) +#else +# define _GLIBCXX_AUTO_CAST(X) ::std::__decay_t<decltype((X))>(X) +#endif + // Macro for extern template, ie controlling template linkage via use // of extern keyword on template declaration. As documented in the g++ // manual, it inhibits all implicit instantiations and is used diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 490a362cdf1..0fcfed56737 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -1003,19 +1003,10 @@ namespace ranges { using std::__detail::__class_or_enum; - struct _Decay_copy final - { - template<typename _Tp> - constexpr decay_t<_Tp> - operator()(_Tp&& __t) const - noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>) - { return std::forward<_Tp>(__t); } - } inline constexpr __decay_copy{}; - template<typename _Tp> concept __member_begin = requires(_Tp& __t) { - { __decay_copy(__t.begin()) } -> input_or_output_iterator; + { _GLIBCXX_AUTO_CAST(__t.begin()) } -> input_or_output_iterator; }; // Poison pill so that unqualified lookup doesn't find std::begin. @@ -1025,7 +1016,7 @@ namespace ranges concept __adl_begin = __class_or_enum<remove_reference_t<_Tp>> && requires(_Tp& __t) { - { __decay_copy(begin(__t)) } -> input_or_output_iterator; + { _GLIBCXX_AUTO_CAST(begin(__t)) } -> input_or_output_iterator; }; // Simplified version of std::ranges::begin that only supports lvalues, diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index cb2eba1f841..80ff1e300ce 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -115,9 +115,9 @@ namespace ranges if constexpr (is_array_v<remove_reference_t<_Tp>>) return true; else if constexpr (__member_begin<_Tp>) - return noexcept(__decay_copy(std::declval<_Tp&>().begin())); + return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin())); else - return noexcept(__decay_copy(begin(std::declval<_Tp&>()))); + return noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>()))); } public: @@ -142,7 +142,7 @@ namespace ranges template<typename _Tp> concept __member_end = requires(_Tp& __t) { - { __decay_copy(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>; + { _GLIBCXX_AUTO_CAST(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>; }; // Poison pill so that unqualified lookup doesn't find std::end. @@ -152,7 +152,7 @@ namespace ranges concept __adl_end = __class_or_enum<remove_reference_t<_Tp>> && requires(_Tp& __t) { - { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>; + { _GLIBCXX_AUTO_CAST(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>; }; struct _End @@ -165,9 +165,9 @@ namespace ranges if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>) return true; else if constexpr (__member_end<_Tp>) - return noexcept(__decay_copy(std::declval<_Tp&>().end())); + return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().end())); else - return noexcept(__decay_copy(end(std::declval<_Tp&>()))); + return noexcept(_GLIBCXX_AUTO_CAST(end(std::declval<_Tp&>()))); } public: @@ -192,7 +192,7 @@ namespace ranges template<typename _Tp> concept __member_rbegin = requires(_Tp& __t) { - { __decay_copy(__t.rbegin()) } -> input_or_output_iterator; + { _GLIBCXX_AUTO_CAST(__t.rbegin()) } -> input_or_output_iterator; }; void rbegin() = delete; @@ -201,7 +201,7 @@ namespace ranges concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>> && requires(_Tp& __t) { - { __decay_copy(rbegin(__t)) } -> input_or_output_iterator; + { _GLIBCXX_AUTO_CAST(rbegin(__t)) } -> input_or_output_iterator; }; template<typename _Tp> @@ -219,9 +219,9 @@ namespace ranges _S_noexcept() { if constexpr (__member_rbegin<_Tp>) - return noexcept(__decay_copy(std::declval<_Tp&>().rbegin())); + return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rbegin())); else if constexpr (__adl_rbegin<_Tp>) - return noexcept(__decay_copy(rbegin(std::declval<_Tp&>()))); + return noexcept(_GLIBCXX_AUTO_CAST(rbegin(std::declval<_Tp&>()))); else { if constexpr (noexcept(_End{}(std::declval<_Tp&>()))) @@ -254,7 +254,7 @@ namespace ranges template<typename _Tp> concept __member_rend = requires(_Tp& __t) { - { __decay_copy(__t.rend()) } + { _GLIBCXX_AUTO_CAST(__t.rend()) } -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>; }; @@ -264,7 +264,7 @@ namespace ranges concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>> && requires(_Tp& __t) { - { __decay_copy(rend(__t)) } + { _GLIBCXX_AUTO_CAST(rend(__t)) } -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>; }; @@ -276,9 +276,9 @@ namespace ranges _S_noexcept() { if constexpr (__member_rend<_Tp>) - return noexcept(__decay_copy(std::declval<_Tp&>().rend())); + return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rend())); else if constexpr (__adl_rend<_Tp>) - return noexcept(__decay_copy(rend(std::declval<_Tp&>()))); + return noexcept(_GLIBCXX_AUTO_CAST(rend(std::declval<_Tp&>()))); else { if constexpr (noexcept(_Begin{}(std::declval<_Tp&>()))) @@ -312,7 +312,7 @@ namespace ranges concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>> && requires(_Tp& __t) { - { __decay_copy(__t.size()) } -> __detail::__is_integer_like; + { _GLIBCXX_AUTO_CAST(__t.size()) } -> __detail::__is_integer_like; }; void size() = delete; @@ -322,7 +322,7 @@ namespace ranges && !disable_sized_range<remove_cvref_t<_Tp>> && requires(_Tp& __t) { - { __decay_copy(size(__t)) } -> __detail::__is_integer_like; + { _GLIBCXX_AUTO_CAST(size(__t)) } -> __detail::__is_integer_like; }; template<typename _Tp> @@ -347,9 +347,9 @@ namespace ranges if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>) return true; else if constexpr (__member_size<_Tp>) - return noexcept(__decay_copy(std::declval<_Tp&>().size())); + return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().size())); else if constexpr (__adl_size<_Tp>) - return noexcept(__decay_copy(size(std::declval<_Tp&>()))); + return noexcept(_GLIBCXX_AUTO_CAST(size(std::declval<_Tp&>()))); else if constexpr (__sentinel_size<_Tp>) return noexcept(_End{}(std::declval<_Tp&>()) - _Begin{}(std::declval<_Tp&>())); @@ -459,7 +459,7 @@ namespace ranges template<typename _Tp> concept __member_data = requires(_Tp& __t) { - { __decay_copy(__t.data()) } -> __pointer_to_object; + { _GLIBCXX_AUTO_CAST(__t.data()) } -> __pointer_to_object; }; template<typename _Tp> @@ -473,7 +473,7 @@ namespace ranges _S_noexcept() { if constexpr (__member_data<_Tp>) - return noexcept(__decay_copy(std::declval<_Tp&>().data())); + return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().data())); else return noexcept(_Begin{}(std::declval<_Tp&>())); } -- 2.47.0.rc1.33.g90fe3800b9