From 0bcc6f7e78969bfc61768d43085df176f2820c88 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 6 Jun 2025 11:39:48 +0800 Subject: [PATCH 1/2] Speculatively implement LWG-4270 --- stl/inc/xutility | 31 +++++++++++++++++-- tests/libcxx/expected_results.txt | 9 ------ .../test.cpp | 12 ------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 46c9bef18b1..9efe93f0cac 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -866,8 +866,33 @@ namespace ranges { template concept _Can_deref = requires(_Ty&& __t) { *static_cast<_Ty&&>(__t); }; + struct _Must_have_ADL_found_iter_move_or_be_dereferenceable {}; + class _Cpo { private: + template + _NODISCARD static auto _Choose_return_type() { + if constexpr (_Has_ADL<_Ty>) { + return type_identity()))>{}; // intentional ADL + } else if constexpr (_Can_deref<_Ty>) { + using _Ref = decltype(*_STD declval<_Ty>()); + if constexpr (is_function_v>) { + // TRANSITION, VSO-1008447, VSO-2066340 + // Fuse this into the type_identity<_Ref>{} branch once MSVC is fixed. + return type_identity<_Ref&>{}; + } else if constexpr (is_lvalue_reference_v<_Ref>) { + return type_identity&&>{}; + } else { + return type_identity<_Ref>{}; + } + } else { + return _Must_have_ADL_found_iter_move_or_be_dereferenceable{}; + } + } + + template + using _Return_type = decltype(_Choose_return_type<_Ty>())::type; + enum class _St { _None, _Custom, _Fallback }; template @@ -886,8 +911,7 @@ namespace ranges { public: template - requires (_Choice<_Ty>._Strategy != _St::_None) - _NODISCARD _STATIC_CALL_OPERATOR constexpr decltype(auto) operator()(_Ty&& _Val) _CONST_CALL_OPERATOR + _NODISCARD _STATIC_CALL_OPERATOR constexpr _Return_type<_Ty> operator()(_Ty&& _Val) _CONST_CALL_OPERATOR noexcept(_Choice<_Ty>._No_throw) { constexpr _St _Strat = _Choice<_Ty>._Strategy; @@ -1121,7 +1145,8 @@ struct _Projected_impl { using value_type = remove_cvref_t>; [[noreturn]] indirect_result_t<_Proj&, _It> operator*() const { - _CSTD abort(); // shouldn't be called, see GH-3888 + static_assert( + false, "std::projected::operator*() can't be instantiated (N5008 [projected] as modified by LWG-4270)"); } }; }; diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index ed1781f9b1a..f85c146b129 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -1172,12 +1172,6 @@ std/containers/sequences/vector.bool/vector_bool.pass.cpp FAIL # Not analyzed. Inspecting shift operators for quoted(). std/input.output/iostream.format/quoted.manip/quoted_traits.compile.pass.cpp FAIL -# Not analyzed. -# MSVC warning C5046: 'test_undefined_internal::A::operator *': Symbol involving type with internal linkage not defined -# Clang error: function 'test_undefined_internal()::A::operator*' has internal linkage but is not defined [-Werror,-Wundefined-internal] -std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_rvalue_reference_t.compile.pass.cpp FAIL -std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_spaceship.pass.cpp FAIL - # Not analyzed. Failing assert(arr[0].moves() == 1 && arr[1].moves() == 3). std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp FAIL @@ -1526,9 +1520,6 @@ std/algorithms/alg.sorting/alg.set.operations/set.intersection/set_intersection_ # Clang assertion: std::hermite(n, +inf) == inf std/numerics/c.math/hermite.pass.cpp FAIL -# Not analyzed. Test coverage for LLVM-104496 uses span. -std/containers/views/views.span/span.cons/copy.pass.cpp FAIL - # Not analyzed. These tests disable or limit allocations, which interferes with our proxy objects. std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp FAIL std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cpp FAIL diff --git a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp index abc1699c201..aa4834cdeb3 100644 --- a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp @@ -1073,15 +1073,7 @@ namespace iterator_cust_move_test { static_assert(noexcept(ranges::iter_move(static_cast(&some_ints[2])))); static_assert(same_as, int&&>); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1008447 static_assert(same_as, int (&)(int)>); -#else // ^^^ no workaround / workaround vvv -#ifdef _MSVC_INTERNAL_TESTING // TRANSITION, assertion will fire once VSO-2066340 ships. - static_assert(same_as, int (&&)(int)>); -#else // ^^^ defined(_MSVC_INTERNAL_TESTING) / !defined(_MSVC_INTERNAL_TESTING) vvv - static_assert(same_as, int (*)(int)>); -#endif // ^^^ !defined(_MSVC_INTERNAL_TESTING) -#endif // ^^^ workaround ^^^ static_assert(same_as, int&&>); static_assert(ranges::iter_move(some_ints) == 0); @@ -1090,11 +1082,7 @@ namespace iterator_cust_move_test { constexpr int f(int i) noexcept { return i + 1; } -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1008447 static_assert(same_as, int (&)(int)>); -#else // ^^^ no workaround / workaround vvv - static_assert(same_as, int (&&)(int)>); -#endif // ^^^ workaround ^^^ static_assert(ranges::iter_move(&f)(42) == 43); static_assert(noexcept(ranges::iter_move(&f))); From 7831af3e74eb8226281c9fb2d1ff215946bddbeb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 23 Jul 2025 15:30:58 -0700 Subject: [PATCH 2/2] Follow our workaround convention. --- stl/inc/xutility | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index ea9cd3c4f27..5805b9012a6 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -876,14 +876,17 @@ namespace ranges { return type_identity()))>{}; // intentional ADL } else if constexpr (_Can_deref<_Ty>) { using _Ref = decltype(*_STD declval<_Ty>()); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1008447, VSO-2066340 if constexpr (is_function_v>) { - // TRANSITION, VSO-1008447, VSO-2066340 - // Fuse this into the type_identity<_Ref>{} branch once MSVC is fixed. return type_identity<_Ref&>{}; - } else if constexpr (is_lvalue_reference_v<_Ref>) { - return type_identity&&>{}; - } else { - return type_identity<_Ref>{}; + } else +#endif // ^^^ workaround ^^^ + { + if constexpr (is_lvalue_reference_v<_Ref>) { + return type_identity&&>{}; + } else { + return type_identity<_Ref>{}; + } } } else { return _Must_have_ADL_found_iter_move_or_be_dereferenceable{};