https://gcc.gnu.org/g:140aab25a4865433d987d73c57f4ddf11fdac1e2
commit r14-10654-g140aab25a4865433d987d73c57f4ddf11fdac1e2 Author: Patrick Palka <ppa...@redhat.com> Date: Sat Aug 3 09:05:05 2024 -0400 libstdc++: use concrete return type for std::forward_like Inspired by https://github.com/llvm/llvm-project/issues/101614 this inverts the relationship between forward_like and __like_t so that forward_like is defined in terms of __like_t and with a concrete return type. __like_t in turn is defined via partial specializations that pattern match on the const- and reference-ness of T. This turns out to be more SFINAE friendly and significantly cheaper to compile than the previous implementation. libstdc++-v3/ChangeLog: * include/bits/move.h (__like_impl): New metafunction. (__like_t): Redefine in terms of __like_impl. (forward_like): Redefine in terms of __like_t. * testsuite/20_util/forward_like/2_neg.cc: Don't expect error outside the immediate context anymore. Reviewed-by: Jonathan Wakely <jwak...@redhat.com> (cherry picked from commit 8256d5c0097dff00f9bdf9ee0c9d53bd7cec2802) Diff: --- libstdc++-v3/include/bits/move.h | 47 +++++++++++----------- .../testsuite/20_util/forward_like/2_neg.cc | 6 +-- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/libstdc++-v3/include/bits/move.h b/libstdc++-v3/include/bits/move.h index bb200c95964a..8397a01b6323 100644 --- a/libstdc++-v3/include/bits/move.h +++ b/libstdc++-v3/include/bits/move.h @@ -88,31 +88,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __glibcxx_forward_like // C++ >= 23 template<typename _Tp, typename _Up> - [[nodiscard]] - constexpr decltype(auto) - forward_like(_Up&& __x) noexcept - { - constexpr bool __as_rval = is_rvalue_reference_v<_Tp&&>; - - if constexpr (is_const_v<remove_reference_t<_Tp>>) - { - using _Up2 = remove_reference_t<_Up>; - if constexpr (__as_rval) - return static_cast<const _Up2&&>(__x); - else - return static_cast<const _Up2&>(__x); - } - else - { - if constexpr (__as_rval) - return static_cast<remove_reference_t<_Up>&&>(__x); - else - return static_cast<_Up&>(__x); - } - } + struct __like_impl; // _Tp must be a reference and _Up an lvalue reference + + template<typename _Tp, typename _Up> + struct __like_impl<_Tp&, _Up&> + { using type = _Up&; }; + + template<typename _Tp, typename _Up> + struct __like_impl<const _Tp&, _Up&> + { using type = const _Up&; }; + + template<typename _Tp, typename _Up> + struct __like_impl<_Tp&&, _Up&> + { using type = _Up&&; }; + + template<typename _Tp, typename _Up> + struct __like_impl<const _Tp&&, _Up&> + { using type = const _Up&&; }; template<typename _Tp, typename _Up> - using __like_t = decltype(std::forward_like<_Tp>(std::declval<_Up>())); + using __like_t = typename __like_impl<_Tp&&, _Up&>::type; + + template<typename _Tp, typename _Up> + [[nodiscard]] + constexpr __like_t<_Tp, _Up> + forward_like(_Up&& __x) noexcept + { return static_cast<__like_t<_Tp, _Up>>(__x); } #endif /** diff --git a/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc b/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc index ff835af19151..5dafa419a7ea 100644 --- a/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc +++ b/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc @@ -2,9 +2,7 @@ #include <utility> -auto x1 = std::forward_like<void>(1); // { dg-error "here" } +auto x1 = std::forward_like<void>(1); // { dg-error "no match" } // { dg-error "forming reference to void" "" { target *-*-* } 0 } -auto x2 = std::forward_like<void()const>(1); // { dg-error "here" } +auto x2 = std::forward_like<void()const>(1); // { dg-error "no match" } // { dg-error "forming reference to qualified function" "" { target *-*-* } 0 } - -// { dg-prune-output "inconsistent deduction for auto return type" } // PR111484