This isn't properly tested so I'm not pushing it, but I'm sharing it now
for comment.

-- >8 --

Inspired by https://github.com/llvm/llvm-project/issues/101614 this
replaces the deduced return type of std::forward_like with a type trait
to compute that type.

libstdc++-v3/ChangeLog:

        * include/bits/move.h (__forward_like_impl): New metafunction to
        compute the return type of std::forward_like.
        (forward_like, __like_t): Use it.
        * testsuite/20_util/forward_like/2_neg.cc: Adjust expected
        errors.
---
 libstdc++-v3/include/bits/move.h              | 45 +++++++++----------
 .../testsuite/20_util/forward_like/2_neg.cc   |  2 +-
 2 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/libstdc++-v3/include/bits/move.h b/libstdc++-v3/include/bits/move.h
index bb200c95964..15b7cd07fce 100644
--- a/libstdc++-v3/include/bits/move.h
+++ b/libstdc++-v3/include/bits/move.h
@@ -88,31 +88,30 @@ _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 __forward_like_impl
+    {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_reference)
+      template<typename _Xp> using __remove_ref_t = __remove_reference(_Xp);
+#else
+      template<typename _Xp> using __remove_ref_t = remove_reference_t<_Xp>;
+#endif
+      template<typename _Xp, typename _Yp>
+       using _Copy_const = __conditional_t<is_const_v<_Xp>, const _Yp, _Yp>;
+      template<typename _Xp, typename _Yp>
+       using _Override_ref = __conditional_t<is_rvalue_reference_v<_Xp>,
+                                             __remove_ref_t<_Yp>&&, _Yp&>;
+      using type = _Override_ref<_Tp&&, _Copy_const<__remove_ref_t<_Tp>,
+                                                   __remove_ref_t<_Up>>>;
+    };
 
   template<typename _Tp, typename _Up>
-    using __like_t = decltype(std::forward_like<_Tp>(std::declval<_Up>()));
+    using __like_t = typename __forward_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 ff835af1915..f6e98420a9a 100644
--- a/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
@@ -7,4 +7,4 @@ auto x1 = std::forward_like<void>(1); // { dg-error "here" }
 auto x2 = std::forward_like<void()const>(1); // { dg-error "here" }
 // { dg-error "forming reference to qualified function" "" { target *-*-* } 0 }
 
-// { dg-prune-output "inconsistent deduction for auto return type" } // 
PR111484
+// { dg-prune-output "no matching function" }
-- 
2.45.2

Reply via email to