From 3b8a0cbfe5216e47abdf58dbebb6c496affd83ac Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 24 May 2025 16:16:43 +0800 Subject: [PATCH 01/12] Implement P2255R2 for Clang --- stl/inc/memory | 5 + stl/inc/tuple | 182 ++++++++++++++++ stl/inc/type_traits | 52 ++++- stl/inc/utility | 50 +++++ stl/inc/yvals_core.h | 31 ++- tests/libcxx/expected_results.txt | 11 +- tests/std/test.lst | 4 + tests/std/tests/P2255R2_invocation/env.lst | 4 + .../P2255R2_invocation/test.compile.pass.cpp | 64 ++++++ .../env.lst | 4 + .../test.compile.pass.cpp | 204 +++++++++++++++++ .../env.lst | 4 + .../test.compile.pass.cpp | 206 ++++++++++++++++++ .../P2255R2_tuple_pair_construction/env.lst | 4 + .../test.compile.pass.cpp | 90 ++++++++ .../test.compile.pass.cpp | 6 + 16 files changed, 910 insertions(+), 11 deletions(-) create mode 100644 tests/std/tests/P2255R2_invocation/env.lst create mode 100644 tests/std/tests/P2255R2_invocation/test.compile.pass.cpp create mode 100644 tests/std/tests/P2255R2_reference_constructs_from_temporary/env.lst create mode 100644 tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp create mode 100644 tests/std/tests/P2255R2_reference_converts_from_temporary/env.lst create mode 100644 tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp create mode 100644 tests/std/tests/P2255R2_tuple_pair_construction/env.lst create mode 100644 tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp diff --git a/stl/inc/memory b/stl/inc/memory index e959623f7b4..9768ff718d4 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3467,6 +3467,11 @@ public: } _NODISCARD _CONSTEXPR23 add_lvalue_reference_t<_Ty> operator*() const noexcept(noexcept(*_STD declval())) { +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + static_assert( + !reference_converts_from_temporary_v, decltype(*_STD declval())>, + "it is disallowed to bind a temporary object to the result of unique_ptr::operator*"); +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS return *_Mypair._Myval2; } diff --git a/stl/inc/tuple b/stl/inc/tuple index 5eb1453bd7b..0601ea7e0af 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -204,6 +204,31 @@ using _Three_way_comparison_result_with_tuple_like_t = template concept _Tuple_like_non_tuple = !_Is_specialization_v<_Ty, tuple> && _Tuple_like<_Ty>; + +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +template +constexpr bool _Tuple_reference_constructs_from_temporary = false; +template +constexpr bool _Tuple_reference_constructs_from_temporary, _Args...> = + (reference_constructs_from_temporary_v<_TupleTypes, _Args> || ...); + +template +constexpr bool _Tuple_reference_constructs_from_temporary_for_tuple_like_impl = false; +template +constexpr bool + _Tuple_reference_constructs_from_temporary_for_tuple_like_impl<_Tuple, _TupleLike, index_sequence<_Indices...>> = + (reference_constructs_from_temporary_v, + decltype(_STD get<_Indices>(_STD declval<_TupleLike>()))> + || ...); + +template +constexpr bool _Tuple_reference_constructs_from_temporary_for_tuple_like = false; +template + requires (tuple_size_v<_Tuple> == tuple_size_v>) +constexpr bool _Tuple_reference_constructs_from_temporary_for_tuple_like<_Tuple, _TupleLike> = + _Tuple_reference_constructs_from_temporary_for_tuple_like_impl<_Tuple, _TupleLike, + make_index_sequence>>; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template <> @@ -347,6 +372,14 @@ public: tuple(_This2&& _This_arg, _Rest2&&... _Rest_arg) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Exact_args_t{}, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_constructible_val>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) tuple(_This2&&, _Rest2&&...) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS tuple(const tuple&) = default; tuple(tuple&&) = default; @@ -358,6 +391,13 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val&, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template , @@ -366,6 +406,13 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val&, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , _STD _Tuple_convert_val, _Other...>>, @@ -373,6 +420,13 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #if _HAS_CXX23 template , @@ -381,11 +435,23 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template & _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(const pair<_First, _Second>& _Right) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>&&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #if _HAS_CXX23 template && _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(const pair<_First, _Second>&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template > static constexpr bool _Is_tuple_like_constructor_explicit_v = false; @@ -427,6 +512,15 @@ public: constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(_Other&& _Right) : tuple(_Unpack_tuple_t{}, _STD forward<_Other>(_Right)) { } +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template <_Different_from _Other> + requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) + && _Can_construct_values_from_tuple_like_v + && (sizeof...(_Rest) != 0 + || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) + && _Tuple_reference_constructs_from_temporary_for_tuple_like + explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(_Other&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_constructible_val>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, _This2&&, _Rest2&&...) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , int> = 0> @@ -468,6 +571,15 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val&, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, tuple<_Other...>&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val&, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, const tuple<_Other...>&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , @@ -485,6 +606,15 @@ public: _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, tuple<_Other...>&&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #if _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , + _STD _Tuple_convert_val, _Other...>>, + int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, const tuple<_Other...>&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, pair<_First, _Second>&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, const pair<_First, _Second>&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, pair<_First, _Second>&&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #if _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , int> = 0> + requires _Tuple_reference_constructs_from_temporary + explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc&, const pair<_First, _Second>&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #ifdef __EDG__ // TRANSITION, VSO-1900279 template , int> = 0> @@ -533,6 +700,15 @@ public: tuple(allocator_arg_t, const _Alloc& _Al, _Other&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD forward<_Other>(_Right)) { } +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template _Other> + requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) + && _Can_construct_values_from_tuple_like_v + && (sizeof...(_Rest) != 0 + || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) + && _Tuple_reference_constructs_from_temporary_for_tuple_like + explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(allocator_arg_t, const _Alloc&, _Other&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 tuple& operator=(const volatile tuple&) = delete; @@ -1093,6 +1269,12 @@ template #endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) /* strengthened */ { +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + if constexpr (tuple_size_v> == 1) { + static_assert(!reference_constructs_from_temporary_v<_Ty, decltype(_STD get<0>(_STD forward<_Tuple>(_Tpl)))>, + "Cannot bind a temporary to the returned reference which will always be dangling (N4993 [tuple.apply]/3)."); + } +#endif //_HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS // construct _Ty from the elements of _Tpl return _STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}); diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 9c8e1d740dd..726ae8fa4f3 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -699,6 +699,47 @@ struct has_unique_object_representations : bool_constant<__has_unique_object_rep _EXPORT_STD template constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Ty); +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __clang__ // TRANSITION, LLVM-114344 +template +struct _Adjust_ref_binding_source { + using type = _Ty; +}; +template + requires is_scalar_v<_Ty> || is_void_v<_Ty> +struct _Adjust_ref_binding_source<_Ty> { + using type = remove_cv_t<_Ty>; +}; +template + requires is_function_v<_Ty> && requires { typename void_t<_Ty&>; } +struct _Adjust_ref_binding_source<_Ty> { + using type = _Ty&; +}; + +template +using _Adjust_ref_binding_source_t = _Adjust_ref_binding_source<_Ty>::type; +#else // ^^^ workaround / no workaround vvv +template +using _Adjust_ref_binding_source_t = _Ty; +#endif // ^^^ no workaround ^^^ + +_EXPORT_STD template +struct reference_constructs_from_temporary + : bool_constant<__reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {}; + +_EXPORT_STD template +constexpr bool reference_constructs_from_temporary_v = + __reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>); + +_EXPORT_STD template +struct reference_converts_from_temporary + : bool_constant<__reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {}; + +_EXPORT_STD template +constexpr bool reference_converts_from_temporary_v = + __reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>); +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + #ifdef __EDG__ // TRANSITION, VSO-1690654 template struct _Is_aggregate_impl : bool_constant<__is_aggregate(_Ty)> {}; @@ -1739,9 +1780,18 @@ struct is_nothrow_convertible : bool_constant<_Is_nothrow_convertible_v<_From, _ template struct _Invoke_convertible : false_type {}; +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +template +using _Not_reference_converts_from_temporary = bool_constant>; +#else // ^^^ _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS / !_HAS_CXX23 || + // !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS vvv +template +using _Not_reference_converts_from_temporary = true_type; +#endif // ^^^ !_HAS_CXX23 || !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS ^^^ + template struct _Invoke_convertible<_From, _To, void_t(_STD _Returns_exactly<_From>()))>> - : true_type {}; + : _Not_reference_converts_from_temporary<_From, _To> {}; template struct _Invoke_nothrow_convertible diff --git a/stl/inc/utility b/stl/inc/utility index 4570a7bb790..e4c50f04ec7 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -273,6 +273,14 @@ struct pair { // store a pair of values is_nothrow_constructible_v<_Ty1, _Other1> && is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened : first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) { } +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , is_constructible<_Ty2, _Other2>>, int> = 0> + requires reference_constructs_from_temporary_v<_Ty1, _Other1&&> + || reference_constructs_from_temporary_v<_Ty2, _Other2&&> + explicit(!conjunction_v, is_convertible<_Other2, _Ty2>>) + pair(_Other1&&, _Other2&&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS pair(const pair&) = default; pair(pair&&) = default; @@ -284,6 +292,14 @@ struct pair { // store a pair of values pair(pair<_Other1, _Other2>& _Right) noexcept( is_nothrow_constructible_v<_Ty1, _Other1&> && is_nothrow_constructible_v<_Ty2, _Other2&>) // strengthened : first(_Right.first), second(_Right.second) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template + requires is_constructible_v<_Ty1, _Other1&> && is_constructible_v<_Ty2, _Other2&> + && (reference_constructs_from_temporary_v<_Ty1, _Other1&> + || reference_constructs_from_temporary_v<_Ty2, _Other2&>) + explicit(!conjunction_v, is_convertible<_Other2&, _Ty2>>) + pair(pair<_Other1, _Other2>&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template && is_nothrow_constructible_v<_Ty2, const _Other2&>) // strengthened : first(_Right.first), second(_Right.second) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , is_constructible<_Ty2, const _Other2&>>, + int> = 0> + requires reference_constructs_from_temporary_v<_Ty1, const _Other1&> + || reference_constructs_from_temporary_v<_Ty2, const _Other2&> + explicit(!conjunction_v, is_convertible>) + pair(const pair<_Other1, _Other2>&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS template , is_constructible<_Ty2, _Other2>>, int> = 0> @@ -301,6 +326,14 @@ struct pair { // store a pair of values pair(pair<_Other1, _Other2>&& _Right) noexcept( is_nothrow_constructible_v<_Ty1, _Other1> && is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened : first(_STD forward<_Other1>(_Right.first)), second(_STD forward<_Other2>(_Right.second)) {} +#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template , is_constructible<_Ty2, _Other2>>, int> = 0> + requires reference_constructs_from_temporary_v<_Ty1, _Other1&&> + || reference_constructs_from_temporary_v<_Ty2, _Other2&&> + explicit(!conjunction_v, is_convertible<_Other2, _Ty2>>) + pair(pair<_Other1, _Other2>&&) = delete; +#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #if _HAS_CXX23 template @@ -310,6 +343,14 @@ struct pair { // store a pair of values noexcept(is_nothrow_constructible_v<_Ty1, const _Other1> && is_nothrow_constructible_v<_Ty2, const _Other2>) // strengthened : first(_STD forward(_Right.first)), second(_STD forward(_Right.second)) {} +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template + requires is_constructible_v<_Ty1, const _Other1> && is_constructible_v<_Ty2, const _Other2> + && (reference_constructs_from_temporary_v<_Ty1, const _Other1 &&> + || reference_constructs_from_temporary_v<_Ty2, const _Other2 &&>) + explicit(!conjunction_v, is_convertible>) + pair(const pair<_Other1, _Other2>&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #ifdef __EDG__ // TRANSITION, VSO-1900279 template , int> = 0> @@ -324,6 +365,15 @@ struct pair { // store a pair of values && is_nothrow_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>) // strengthened : first(_STD get<0>(_STD forward<_Other>(_Right))), second(_STD get<1>(_STD forward<_Other>(_Right))) { } +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS + template <_Pair_like_non_subrange _Other> + requires conjunction_v(_STD declval<_Other>()))>, + is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>> + && (reference_constructs_from_temporary_v<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))> + || reference_constructs_from_temporary_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>) + explicit(!conjunction_v(_STD declval<_Other>())), _Ty1>, + is_convertible(_STD declval<_Other>())), _Ty2>>) pair(_Other&&) = delete; +#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS #endif // _HAS_CXX23 template diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 1ed0b04bf1a..476635cc163 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -363,6 +363,8 @@ // P2165R4 Compatibility Between tuple, pair, And tuple-like Objects // P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr // P2186R2 Removing Garbage Collection Support +// P2255R2 Type Traits To Detect References Binding To Temporaries +// (for Clang only) // P2273R3 constexpr unique_ptr // P2278R4 cbegin Should Always Return A Constant Iterator // P2286R8 Formatting Ranges @@ -937,6 +939,13 @@ _EMIT_STL_ERROR(STL1001, "Unexpected compiler version, expected MSVC 19.44 or ne #error /GR implies _HAS_STATIC_RTTI. #endif // defined(_CPPRTTI) && !_HAS_STATIC_RTTI +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#if defined(__clang__) && !defined(__EDG__) +#define _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS (__clang_major__ >= 19) +#else // ^^^ defined(__clang__) && !defined(__EDG__) / !defined(__clang__) || defined(__EDG__) vvv +#define _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS 0 +#endif // !defined(__clang__) || defined(__EDG__) + // N4950 [dcl.constexpr]/1: "A function or static data member declared with the // constexpr or consteval specifier is implicitly an inline function or variable" @@ -1819,14 +1828,20 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_ranges_stride 202207L #define __cpp_lib_ranges_to_container 202202L #define __cpp_lib_ranges_zip 202110L -#define __cpp_lib_spanstream 202106L -#define __cpp_lib_stacktrace 202011L -#define __cpp_lib_stdatomic_h 202011L -#define __cpp_lib_string_contains 202011L -#define __cpp_lib_string_resize_and_overwrite 202110L -#define __cpp_lib_to_underlying 202102L -#define __cpp_lib_tuple_like 202207L -#define __cpp_lib_unreachable 202202L + +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#define __cpp_lib_reference_from_temporary 202202L +#endif // ^^^ no workaround ^^^ + +#define __cpp_lib_spanstream 202106L +#define __cpp_lib_stacktrace 202011L +#define __cpp_lib_stdatomic_h 202011L +#define __cpp_lib_string_contains 202011L +#define __cpp_lib_string_resize_and_overwrite 202110L +#define __cpp_lib_to_underlying 202102L +#define __cpp_lib_tuple_like 202207L +#define __cpp_lib_unreachable 202202L #endif // _HAS_CXX23 // macros with language mode sensitivity diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index ed1781f9b1a..4be5c403b24 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -156,6 +156,10 @@ std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate.pass std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate_overaligned_request.pass.cpp FAIL std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_matches_allocate.pass.cpp FAIL +# libc++ hasn't completely implemented P2255R2 "Type Traits To Detect References Binding To Temporaries" +std/utilities/meta/meta.rel/is_invocable_r.compile.pass.cpp:2 FAIL +std/utilities/meta/meta.rel/is_invocable_r_v.compile.pass.cpp:2 FAIL + # libc++ is missing various Ranges DRs std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp FAIL std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp FAIL @@ -561,9 +565,12 @@ std/containers/container.adaptors/flat.set/types.compile.pass.cpp FAIL std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp FAIL # P2255R2 "Type Traits To Detect References Binding To Temporaries" +# (type_traits.version.compile.pass.cpp still fails for Clang due to LLVM-48860) std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp FAIL -std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp FAIL -std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp FAIL +std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp:0 FAIL +std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp:1 FAIL +std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp:0 FAIL +std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp:1 FAIL # P2674R1 is_implicit_lifetime std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp FAIL diff --git a/tests/std/test.lst b/tests/std/test.lst index 4c7c40603d1..9203971d18e 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -631,6 +631,10 @@ tests\P2165R4_tuple_like_pair tests\P2165R4_tuple_like_relational_operators tests\P2165R4_tuple_like_tuple_members tests\P2231R1_complete_constexpr_optional_variant +tests\P2255R2_invocation +tests\P2255R2_reference_constructs_from_temporary +tests\P2255R2_reference_converts_from_temporary +tests\P2255R2_tuple_pair_construction tests\P2273R3_constexpr_unique_ptr tests\P2278R4_basic_const_iterator tests\P2278R4_const_span diff --git a/tests/std/tests/P2255R2_invocation/env.lst b/tests/std/tests/P2255R2_invocation/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P2255R2_invocation/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2255R2_invocation/test.compile.pass.cpp b/tests/std/tests/P2255R2_invocation/test.compile.pass.cpp new file mode 100644 index 00000000000..775cc89a962 --- /dev/null +++ b/tests/std/tests/P2255R2_invocation/test.compile.pass.cpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#if defined(__clang__) && !defined(__EDG__) +#include +#include + +using namespace std; + +struct LvalueTempFunctor { + int operator()() const& noexcept; + const int& operator()() const&& noexcept; +}; + +static_assert(is_invocable_r_v); +static_assert(!is_invocable_r_v); +static_assert(!is_invocable_r_v); +static_assert(!is_invocable_r_v); +static_assert(is_invocable_r_v); +static_assert(is_invocable_r_v); +static_assert(!is_invocable_r_v); + +static_assert(is_constructible_v, int& (*) ()>); +static_assert(!is_constructible_v, short& (*) ()>); +static_assert(!is_constructible_v, int (*)()>); +static_assert(!is_constructible_v, LvalueTempFunctor>); + +static_assert(is_constructible_v, int& (*) ()>); +static_assert(!is_constructible_v, short& (*) ()>); +static_assert(!is_constructible_v, int (*)()>); + +static_assert(is_constructible_v, int& (*) ()>); +static_assert(!is_constructible_v, short& (*) ()>); +static_assert(!is_constructible_v, int (*)()>); + +static_assert(!is_constructible_v, LvalueTempFunctor>); +static_assert(!is_constructible_v, LvalueTempFunctor>); +static_assert(is_constructible_v, LvalueTempFunctor>); +static_assert(is_constructible_v, LvalueTempFunctor>); + +#ifdef __cpp_noexcept_function_type +static_assert(is_nothrow_invocable_r_v); +static_assert(!is_nothrow_invocable_r_v); +static_assert(!is_nothrow_invocable_r_v); +static_assert(!is_nothrow_invocable_r_v); +static_assert(is_nothrow_invocable_r_v); +static_assert(is_nothrow_invocable_r_v); +static_assert(!is_nothrow_invocable_r_v); + +static_assert(is_constructible_v, int& (*) () noexcept>); +static_assert(!is_constructible_v, short& (*) () noexcept>); +static_assert(!is_constructible_v, int (*)() noexcept>); + +static_assert(is_constructible_v, int& (*) () noexcept>); +static_assert(!is_constructible_v, short& (*) () noexcept>); +static_assert(!is_constructible_v, int (*)() noexcept>); + +static_assert(!is_constructible_v, LvalueTempFunctor>); +static_assert(!is_constructible_v, LvalueTempFunctor>); +static_assert(is_constructible_v, LvalueTempFunctor>); +static_assert(is_constructible_v, LvalueTempFunctor>); +#endif // defined(__cpp_noexcept_function_type) +#endif // ^^^ no workaround ^^^ diff --git a/tests/std/tests/P2255R2_reference_constructs_from_temporary/env.lst b/tests/std/tests/P2255R2_reference_constructs_from_temporary/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P2255R2_reference_constructs_from_temporary/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp new file mode 100644 index 00000000000..d856697c760 --- /dev/null +++ b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#if defined(__clang__) && !defined(__EDG__) +#include + +using namespace std; + +enum class conv_explicity : bool { + no, + yes, +}; + +template +struct to_int_lvalue { + explicit(static_cast(Explicity)) operator int&() const; +}; + +template +struct to_int_xvalue { + explicit(static_cast(Explicity)) operator int&&() const; +}; + +template +struct to_int_prvalue { + explicit(static_cast(Explicity)) operator int() const; +}; + +template +void test_one_non_temporary_bindable_type() { + static_assert(!reference_constructs_from_temporary::value); + + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + + static_assert(!reference_constructs_from_temporary_v); + + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); +} + +void test_non_temporary_bindable_types() { + test_one_non_temporary_bindable_type(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type>(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type&>(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type&>(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type(); +} + +template +void test_one_cvref_to_object() { + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + static_assert(!reference_constructs_from_temporary::value); + + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value == is_scalar_v); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value); + static_assert(reference_constructs_from_temporary::value); + + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + static_assert(!reference_constructs_from_temporary_v); + + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v == is_scalar_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v); + static_assert(reference_constructs_from_temporary_v); +} + +void test_object_types() { + test_one_cvref_to_object(); + test_one_cvref_to_object(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); +} + +template +void test_to_int_ref() { // COMPILE-ONLY + static_assert(!reference_constructs_from_temporary>::value); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value + == !static_cast(Explicity)); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value + == !static_cast(Explicity)); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value + == !static_cast(Explicity)); + + static_assert(!reference_constructs_from_temporary_v>); + static_assert(!reference_constructs_from_temporary_v>); + static_assert( + reference_constructs_from_temporary_v> == !static_cast(Explicity)); + static_assert(!reference_constructs_from_temporary_v>); + static_assert(!reference_constructs_from_temporary_v>); + static_assert( + reference_constructs_from_temporary_v> == !static_cast(Explicity)); + + static_assert(!reference_constructs_from_temporary_v>); + static_assert(reference_constructs_from_temporary_v>); + static_assert( + reference_constructs_from_temporary_v> == !static_cast(Explicity)); +} + +void test_to_int_ref_all() { // COMPILE-ONLY + test_to_int_ref(); + test_to_int_ref(); +} +#endif // ^^^ no workaround ^^^ diff --git a/tests/std/tests/P2255R2_reference_converts_from_temporary/env.lst b/tests/std/tests/P2255R2_reference_converts_from_temporary/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P2255R2_reference_converts_from_temporary/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp new file mode 100644 index 00000000000..a5534d96653 --- /dev/null +++ b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#if defined(__clang__) && !defined(__EDG__) +#include + +using namespace std; + +enum class conv_explicity : bool { + no, + yes, +}; + +template +struct to_int_lvalue { + explicit(static_cast(Explicity)) operator int&() const; +}; + +template +struct to_int_xvalue { + explicit(static_cast(Explicity)) operator int&&() const; +}; + +template +struct to_int_prvalue { + explicit(static_cast(Explicity)) operator int() const; +}; + +template +void test_one_non_temporary_bindable_type() { + static_assert(!reference_converts_from_temporary::value); + + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + + static_assert(!reference_converts_from_temporary_v); + + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); +} + +void test_non_temporary_bindable_types() { + test_one_non_temporary_bindable_type(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type>(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type&>(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type&>(); + + test_one_non_temporary_bindable_type(); + test_one_non_temporary_bindable_type(); +} + +template +void test_one_cvref_to_object() { + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + static_assert(!reference_converts_from_temporary::value); + + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value == is_scalar_v); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value); + static_assert(reference_converts_from_temporary::value); + + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + static_assert(!reference_converts_from_temporary_v); + + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v == is_scalar_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v); + static_assert(reference_converts_from_temporary_v); +} + +void test_object_types() { + test_one_cvref_to_object(); + test_one_cvref_to_object(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); +} + +template +void test_to_int_ref() { // COMPILE-ONLY + static_assert(!reference_converts_from_temporary>::value); + static_assert(!reference_converts_from_temporary>::value); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicity)); + static_assert(!reference_converts_from_temporary>::value); + static_assert(!reference_converts_from_temporary>::value); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicity)); + static_assert(!reference_converts_from_temporary>::value); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicity)); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicity)); + + static_assert(!reference_converts_from_temporary_v>); + static_assert(!reference_converts_from_temporary_v>); + static_assert( + reference_converts_from_temporary_v> == !static_cast(Explicity)); + static_assert(!reference_converts_from_temporary_v>); + static_assert(!reference_converts_from_temporary_v>); + static_assert( + reference_converts_from_temporary_v> == !static_cast(Explicity)); + + static_assert(!reference_converts_from_temporary_v>); + static_assert( + reference_converts_from_temporary_v> == !static_cast(Explicity)); + static_assert( + reference_converts_from_temporary_v> == !static_cast(Explicity)); +} + +void test_to_int_ref_all() { // COMPILE-ONLY + test_to_int_ref(); + test_to_int_ref(); +} +#endif // ^^^ no workaround ^^^ diff --git a/tests/std/tests/P2255R2_tuple_pair_construction/env.lst b/tests/std/tests/P2255R2_tuple_pair_construction/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P2255R2_tuple_pair_construction/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp new file mode 100644 index 00000000000..3eba0acd4b4 --- /dev/null +++ b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#if defined(__clang__) && !defined(__EDG__) +#include +#include +#include + +using namespace std; + +template +void assert_constref_constructible_single() { // COMPILE-ONLY + static_assert(is_constructible_v == Expected); + static_assert(is_constructible_v == Expected); + static_assert(is_constructible_v == Expected); + static_assert(is_constructible_v == Expected); + if constexpr (sizeof...(Args) == 2) { + static_assert(is_constructible_v&> == Expected); + static_assert(is_constructible_v&> == Expected); + static_assert(is_constructible_v> == Expected); + static_assert(is_constructible_v> == Expected); + } + static_assert(is_constructible_v&> == Expected); + static_assert(is_constructible_v&> == Expected); + static_assert(is_constructible_v> == Expected); + static_assert(is_constructible_v> == Expected); +} + +template +void assert_mutref_constructible_single() { // COMPILE-ONLY + static_assert(is_constructible_v == Expected); + if constexpr (sizeof...(Args) == 2) { + static_assert(is_constructible_v> == Expected); + } + static_assert(is_constructible_v> == Expected); +} + +void assert_normal_constructible() { // COMPILE-ONLY + assert_constref_constructible_single, int>(); + assert_constref_constructible_single, long>(); + + assert_constref_constructible_single, int, int>(); + assert_constref_constructible_single, long, int>(); + assert_constref_constructible_single, long, long>(); + + assert_constref_constructible_single, int, int>(); + assert_constref_constructible_single, long, int>(); + assert_constref_constructible_single, int, long>(); + + assert_mutref_constructible_single, int>(); + assert_mutref_constructible_single, long>(); + + assert_mutref_constructible_single, int, int>(); + assert_mutref_constructible_single, long, int>(); + assert_mutref_constructible_single, long, long>(); + + assert_mutref_constructible_single, int, int>(); + assert_mutref_constructible_single, long, int>(); + assert_mutref_constructible_single, int, long>(); +} + +struct LvalueTempConverter { + operator int() &; + operator int&&() &&; + operator const int&() &&; +}; + +template +void assert_lvalue_temp_converter_single() { // COMPILE-ONLY + static_assert(!is_constructible_v); + static_assert(is_constructible_v); + if constexpr (sizeof...(Args) == 1) { + static_assert(!is_constructible_v>); + static_assert(is_constructible_v>); + } + static_assert(!is_constructible_v>); + static_assert(is_constructible_v>); +} + +void assert_lvalue_temp_converter() { // COMPILE-ONLY + assert_lvalue_temp_converter_single>(); + assert_lvalue_temp_converter_single>(); + + assert_lvalue_temp_converter_single, const int&>(); + assert_lvalue_temp_converter_single, int&&>(); + + assert_lvalue_temp_converter_single, const int&>(); + assert_lvalue_temp_converter_single, int&&>(); +} +#endif // ^^^ no workaround ^^^ diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 028d8d68a3a..c6d130f64fb 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -831,6 +831,12 @@ STATIC_ASSERT(__cpp_lib_raw_memory_algorithms == 201606L); #error __cpp_lib_raw_memory_algorithms is defined #endif +#if _HAS_CXX23 && defined(__clang__) // TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +STATIC_ASSERT(__cpp_lib_reference_from_temporary == 202202L); +#elif defined(__cpp_lib_reference_from_temporary) +#error __cpp_lib_reference_from_temporary is defined +#endif + #if _HAS_CXX20 STATIC_ASSERT(__cpp_lib_remove_cvref == 201711L); #elif defined(__cpp_lib_remove_cvref) From eb981b2267314e8d67025dace9777ea5e6bd06b8 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 05:14:45 -0700 Subject: [PATCH 02/12] Use `_NO_SPECIALIZATIONS_OF_TYPE_TRAITS`. --- stl/inc/type_traits | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 1df5ba113ec..fc930c089be 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -773,19 +773,19 @@ using _Adjust_ref_binding_source_t = _Ty; #endif // ^^^ no workaround ^^^ _EXPORT_STD template -struct reference_constructs_from_temporary +struct _NO_SPECIALIZATIONS_OF_TYPE_TRAITS reference_constructs_from_temporary : bool_constant<__reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {}; _EXPORT_STD template -constexpr bool reference_constructs_from_temporary_v = +_NO_SPECIALIZATIONS_OF_TYPE_TRAITS constexpr bool reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>); _EXPORT_STD template -struct reference_converts_from_temporary +struct _NO_SPECIALIZATIONS_OF_TYPE_TRAITS reference_converts_from_temporary : bool_constant<__reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {}; _EXPORT_STD template -constexpr bool reference_converts_from_temporary_v = +_NO_SPECIALIZATIONS_OF_TYPE_TRAITS constexpr bool reference_converts_from_temporary_v = __reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>); #endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS From 52f71ffdf7c535db5bc7dde1b71a8049c29f3019 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 05:30:54 -0700 Subject: [PATCH 03/12] Avoid `// COMPILE-ONLY` in test.compile.pass.cpp. --- .../test.compile.pass.cpp | 4 ++-- .../test.compile.pass.cpp | 4 ++-- .../test.compile.pass.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp index d856697c760..12f48766380 100644 --- a/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp @@ -168,7 +168,7 @@ void test_object_types() { } template -void test_to_int_ref() { // COMPILE-ONLY +void test_to_int_ref() { static_assert(!reference_constructs_from_temporary>::value); static_assert(!reference_constructs_from_temporary>::value); static_assert(reference_constructs_from_temporary>::value @@ -197,7 +197,7 @@ void test_to_int_ref() { // COMPILE-ONLY reference_constructs_from_temporary_v> == !static_cast(Explicity)); } -void test_to_int_ref_all() { // COMPILE-ONLY +void test_to_int_ref_all() { test_to_int_ref(); test_to_int_ref(); } diff --git a/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp index a5534d96653..0a456d9c1e5 100644 --- a/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp @@ -168,7 +168,7 @@ void test_object_types() { } template -void test_to_int_ref() { // COMPILE-ONLY +void test_to_int_ref() { static_assert(!reference_converts_from_temporary>::value); static_assert(!reference_converts_from_temporary>::value); static_assert(reference_converts_from_temporary>::value @@ -199,7 +199,7 @@ void test_to_int_ref() { // COMPILE-ONLY reference_converts_from_temporary_v> == !static_cast(Explicity)); } -void test_to_int_ref_all() { // COMPILE-ONLY +void test_to_int_ref_all() { test_to_int_ref(); test_to_int_ref(); } diff --git a/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp index 3eba0acd4b4..963256c685c 100644 --- a/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp @@ -9,7 +9,7 @@ using namespace std; template -void assert_constref_constructible_single() { // COMPILE-ONLY +void assert_constref_constructible_single() { static_assert(is_constructible_v == Expected); static_assert(is_constructible_v == Expected); static_assert(is_constructible_v == Expected); @@ -27,7 +27,7 @@ void assert_constref_constructible_single() { // COMPILE-ONLY } template -void assert_mutref_constructible_single() { // COMPILE-ONLY +void assert_mutref_constructible_single() { static_assert(is_constructible_v == Expected); if constexpr (sizeof...(Args) == 2) { static_assert(is_constructible_v> == Expected); @@ -35,7 +35,7 @@ void assert_mutref_constructible_single() { // COMPILE-ONLY static_assert(is_constructible_v> == Expected); } -void assert_normal_constructible() { // COMPILE-ONLY +void assert_normal_constructible() { assert_constref_constructible_single, int>(); assert_constref_constructible_single, long>(); @@ -66,7 +66,7 @@ struct LvalueTempConverter { }; template -void assert_lvalue_temp_converter_single() { // COMPILE-ONLY +void assert_lvalue_temp_converter_single() { static_assert(!is_constructible_v); static_assert(is_constructible_v); if constexpr (sizeof...(Args) == 1) { @@ -77,7 +77,7 @@ void assert_lvalue_temp_converter_single() { // COMPILE-ONLY static_assert(is_constructible_v>); } -void assert_lvalue_temp_converter() { // COMPILE-ONLY +void assert_lvalue_temp_converter() { assert_lvalue_temp_converter_single>(); assert_lvalue_temp_converter_single>(); From 010761088de2547495eabbc1cd148b9ef0805f4d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 05:32:51 -0700 Subject: [PATCH 04/12] explicity => explicitly (preserve case, 100% mechanical) --- .../test.compile.pass.cpp | 86 +++++++++---------- .../test.compile.pass.cpp | 80 ++++++++--------- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp index 12f48766380..dedbba1fda1 100644 --- a/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp @@ -7,24 +7,24 @@ using namespace std; -enum class conv_explicity : bool { +enum class conv_explicitly : bool { no, yes, }; -template +template struct to_int_lvalue { - explicit(static_cast(Explicity)) operator int&() const; + explicit(static_cast(Explicitly)) operator int&() const; }; -template +template struct to_int_xvalue { - explicit(static_cast(Explicity)) operator int&&() const; + explicit(static_cast(Explicitly)) operator int&&() const; }; -template +template struct to_int_prvalue { - explicit(static_cast(Explicity)) operator int() const; + explicit(static_cast(Explicitly)) operator int() const; }; template @@ -75,13 +75,13 @@ void test_non_temporary_bindable_types() { test_one_non_temporary_bindable_type(); test_one_non_temporary_bindable_type(); - test_one_non_temporary_bindable_type>(); + test_one_non_temporary_bindable_type>(); test_one_non_temporary_bindable_type(); - test_one_non_temporary_bindable_type&>(); + test_one_non_temporary_bindable_type&>(); test_one_non_temporary_bindable_type(); - test_one_non_temporary_bindable_type&>(); + test_one_non_temporary_bindable_type&>(); test_one_non_temporary_bindable_type(); test_one_non_temporary_bindable_type(); @@ -161,44 +161,44 @@ void test_one_cvref_to_object() { void test_object_types() { test_one_cvref_to_object(); test_one_cvref_to_object(); - test_one_cvref_to_object>(); - test_one_cvref_to_object>(); - test_one_cvref_to_object>(); - test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); } -template +template void test_to_int_ref() { - static_assert(!reference_constructs_from_temporary>::value); - static_assert(!reference_constructs_from_temporary>::value); - static_assert(reference_constructs_from_temporary>::value - == !static_cast(Explicity)); - static_assert(!reference_constructs_from_temporary>::value); - static_assert(!reference_constructs_from_temporary>::value); - static_assert(reference_constructs_from_temporary>::value - == !static_cast(Explicity)); - static_assert(!reference_constructs_from_temporary>::value); - static_assert(reference_constructs_from_temporary>::value); - static_assert(reference_constructs_from_temporary>::value - == !static_cast(Explicity)); - - static_assert(!reference_constructs_from_temporary_v>); - static_assert(!reference_constructs_from_temporary_v>); - static_assert( - reference_constructs_from_temporary_v> == !static_cast(Explicity)); - static_assert(!reference_constructs_from_temporary_v>); - static_assert(!reference_constructs_from_temporary_v>); - static_assert( - reference_constructs_from_temporary_v> == !static_cast(Explicity)); - - static_assert(!reference_constructs_from_temporary_v>); - static_assert(reference_constructs_from_temporary_v>); - static_assert( - reference_constructs_from_temporary_v> == !static_cast(Explicity)); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value + == !static_cast(Explicitly)); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value + == !static_cast(Explicitly)); + static_assert(!reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value); + static_assert(reference_constructs_from_temporary>::value + == !static_cast(Explicitly)); + + static_assert(!reference_constructs_from_temporary_v>); + static_assert(!reference_constructs_from_temporary_v>); + static_assert(reference_constructs_from_temporary_v> + == !static_cast(Explicitly)); + static_assert(!reference_constructs_from_temporary_v>); + static_assert(!reference_constructs_from_temporary_v>); + static_assert(reference_constructs_from_temporary_v> + == !static_cast(Explicitly)); + + static_assert(!reference_constructs_from_temporary_v>); + static_assert(reference_constructs_from_temporary_v>); + static_assert(reference_constructs_from_temporary_v> + == !static_cast(Explicitly)); } void test_to_int_ref_all() { - test_to_int_ref(); - test_to_int_ref(); + test_to_int_ref(); + test_to_int_ref(); } #endif // ^^^ no workaround ^^^ diff --git a/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp index 0a456d9c1e5..6292b7c679c 100644 --- a/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp @@ -7,24 +7,24 @@ using namespace std; -enum class conv_explicity : bool { +enum class conv_explicitly : bool { no, yes, }; -template +template struct to_int_lvalue { - explicit(static_cast(Explicity)) operator int&() const; + explicit(static_cast(Explicitly)) operator int&() const; }; -template +template struct to_int_xvalue { - explicit(static_cast(Explicity)) operator int&&() const; + explicit(static_cast(Explicitly)) operator int&&() const; }; -template +template struct to_int_prvalue { - explicit(static_cast(Explicity)) operator int() const; + explicit(static_cast(Explicitly)) operator int() const; }; template @@ -75,13 +75,13 @@ void test_non_temporary_bindable_types() { test_one_non_temporary_bindable_type(); test_one_non_temporary_bindable_type(); - test_one_non_temporary_bindable_type>(); + test_one_non_temporary_bindable_type>(); test_one_non_temporary_bindable_type(); - test_one_non_temporary_bindable_type&>(); + test_one_non_temporary_bindable_type&>(); test_one_non_temporary_bindable_type(); - test_one_non_temporary_bindable_type&>(); + test_one_non_temporary_bindable_type&>(); test_one_non_temporary_bindable_type(); test_one_non_temporary_bindable_type(); @@ -161,46 +161,46 @@ void test_one_cvref_to_object() { void test_object_types() { test_one_cvref_to_object(); test_one_cvref_to_object(); - test_one_cvref_to_object>(); - test_one_cvref_to_object>(); - test_one_cvref_to_object>(); - test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); + test_one_cvref_to_object>(); } -template +template void test_to_int_ref() { - static_assert(!reference_converts_from_temporary>::value); - static_assert(!reference_converts_from_temporary>::value); - static_assert(reference_converts_from_temporary>::value - == !static_cast(Explicity)); - static_assert(!reference_converts_from_temporary>::value); - static_assert(!reference_converts_from_temporary>::value); - static_assert(reference_converts_from_temporary>::value - == !static_cast(Explicity)); - static_assert(!reference_converts_from_temporary>::value); - static_assert(reference_converts_from_temporary>::value - == !static_cast(Explicity)); - static_assert(reference_converts_from_temporary>::value - == !static_cast(Explicity)); - - static_assert(!reference_converts_from_temporary_v>); - static_assert(!reference_converts_from_temporary_v>); + static_assert(!reference_converts_from_temporary>::value); + static_assert(!reference_converts_from_temporary>::value); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicitly)); + static_assert(!reference_converts_from_temporary>::value); + static_assert(!reference_converts_from_temporary>::value); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicitly)); + static_assert(!reference_converts_from_temporary>::value); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicitly)); + static_assert(reference_converts_from_temporary>::value + == !static_cast(Explicitly)); + + static_assert(!reference_converts_from_temporary_v>); + static_assert(!reference_converts_from_temporary_v>); static_assert( - reference_converts_from_temporary_v> == !static_cast(Explicity)); - static_assert(!reference_converts_from_temporary_v>); - static_assert(!reference_converts_from_temporary_v>); + reference_converts_from_temporary_v> == !static_cast(Explicitly)); + static_assert(!reference_converts_from_temporary_v>); + static_assert(!reference_converts_from_temporary_v>); static_assert( - reference_converts_from_temporary_v> == !static_cast(Explicity)); + reference_converts_from_temporary_v> == !static_cast(Explicitly)); - static_assert(!reference_converts_from_temporary_v>); + static_assert(!reference_converts_from_temporary_v>); static_assert( - reference_converts_from_temporary_v> == !static_cast(Explicity)); + reference_converts_from_temporary_v> == !static_cast(Explicitly)); static_assert( - reference_converts_from_temporary_v> == !static_cast(Explicity)); + reference_converts_from_temporary_v> == !static_cast(Explicitly)); } void test_to_int_ref_all() { - test_to_int_ref(); - test_to_int_ref(); + test_to_int_ref(); + test_to_int_ref(); } #endif // ^^^ no workaround ^^^ From 093a628967e762d93b093b180e7ff4e45c0279e4 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 05:35:35 -0700 Subject: [PATCH 05/12] Add missing TRANSITION comment. --- .../tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp index 963256c685c..2c0d7daa55d 100644 --- a/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. #if defined(__clang__) && !defined(__EDG__) #include #include From 94cbbba84e3465cf42f15ec1da59a35dd52d08f5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 06:01:52 -0700 Subject: [PATCH 06/12] Activate test coverage by inspecting the feature-test macro. --- tests/std/tests/P2255R2_invocation/test.compile.pass.cpp | 4 ++-- .../test.compile.pass.cpp | 4 ++-- .../test.compile.pass.cpp | 4 ++-- .../P2255R2_tuple_pair_construction/test.compile.pass.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/std/tests/P2255R2_invocation/test.compile.pass.cpp b/tests/std/tests/P2255R2_invocation/test.compile.pass.cpp index 775cc89a962..caf1e348283 100644 --- a/tests/std/tests/P2255R2_invocation/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_invocation/test.compile.pass.cpp @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. -#if defined(__clang__) && !defined(__EDG__) #include #include using namespace std; +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#ifdef __cpp_lib_reference_from_temporary struct LvalueTempFunctor { int operator()() const& noexcept; const int& operator()() const&& noexcept; diff --git a/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp index dedbba1fda1..1e2d1fa4a19 100644 --- a/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_reference_constructs_from_temporary/test.compile.pass.cpp @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. -#if defined(__clang__) && !defined(__EDG__) #include using namespace std; +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#ifdef __cpp_lib_reference_from_temporary enum class conv_explicitly : bool { no, yes, diff --git a/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp index 6292b7c679c..bd6e916c64f 100644 --- a/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_reference_converts_from_temporary/test.compile.pass.cpp @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. -#if defined(__clang__) && !defined(__EDG__) #include using namespace std; +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#ifdef __cpp_lib_reference_from_temporary enum class conv_explicitly : bool { no, yes, diff --git a/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp index 2c0d7daa55d..4e19495b8c5 100644 --- a/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp +++ b/tests/std/tests/P2255R2_tuple_pair_construction/test.compile.pass.cpp @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. -#if defined(__clang__) && !defined(__EDG__) #include #include #include using namespace std; +// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. +#ifdef __cpp_lib_reference_from_temporary template void assert_constref_constructible_single() { static_assert(is_constructible_v == Expected); From 2702fcad4bddcf9fd73d38ed219d016a00588be7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 06:21:15 -0700 Subject: [PATCH 07/12] Drop `_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS`, part 1. Also drop the `__clang_major__ >= 19` guard. --- stl/inc/yvals_core.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 7e6c4c95f9d..3c47c895c05 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -966,13 +966,6 @@ _EMIT_STL_ERROR(STL1001, "Unexpected compiler version, expected MSVC Compiler 19 #error /GR implies _HAS_STATIC_RTTI. #endif // defined(_CPPRTTI) && !_HAS_STATIC_RTTI -// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. -#if defined(__clang__) && !defined(__EDG__) -#define _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS (__clang_major__ >= 19) -#else // ^^^ defined(__clang__) && !defined(__EDG__) / !defined(__clang__) || defined(__EDG__) vvv -#define _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS 0 -#endif // !defined(__clang__) || defined(__EDG__) - // N4950 [dcl.constexpr]/1: "A function or static data member declared with the // constexpr or consteval specifier is implicitly an inline function or variable" @@ -1862,7 +1855,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_ranges_zip 202110L // TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2. -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#if defined(__clang__) && !defined(__EDG__) #define __cpp_lib_reference_from_temporary 202202L #endif // ^^^ no workaround ^^^ From aa51091a986caac366f3ed43976d37d2d0a7b46c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 06:48:41 -0700 Subject: [PATCH 08/12] Drop `_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS`, part 2. We now always inspect the feature-test macro. (This will change to `_HAS_CXX23` in the future, at which point we'll elide/fuse redundant guards, as we've done many times in the past.) --- stl/inc/memory | 4 +-- stl/inc/tuple | 88 ++++++++++++++++++++++----------------------- stl/inc/type_traits | 11 +++--- stl/inc/utility | 24 ++++++------- 4 files changed, 63 insertions(+), 64 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index dc291e616fe..b4940f3fb75 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3475,11 +3475,11 @@ public: } _NODISCARD _CONSTEXPR23 add_lvalue_reference_t<_Ty> operator*() const noexcept(noexcept(*_STD declval())) { -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary static_assert( !reference_converts_from_temporary_v, decltype(*_STD declval())>, "it is disallowed to bind a temporary object to the result of unique_ptr::operator*"); -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ return *_Mypair._Myval2; } diff --git a/stl/inc/tuple b/stl/inc/tuple index 1ce9ee94a37..b8fa24ba626 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -205,7 +205,7 @@ using _Three_way_comparison_result_with_tuple_like_t = template concept _Tuple_like_non_tuple = !_Is_specialization_v<_Ty, tuple> && _Tuple_like<_Ty>; -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template constexpr bool _Tuple_reference_constructs_from_temporary = false; template @@ -228,7 +228,7 @@ template constexpr bool _Tuple_reference_constructs_from_temporary_for_tuple_like<_Tuple, _TupleLike> = _Tuple_reference_constructs_from_temporary_for_tuple_like_impl<_Tuple, _TupleLike, make_index_sequence>>; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template <> @@ -372,14 +372,14 @@ public: tuple(_This2&& _This_arg, _Rest2&&... _Rest_arg) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Exact_args_t{}, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_constructible_val>, int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(_This2&&, _Rest2&&...) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ tuple(const tuple&) = default; tuple(tuple&&) = default; @@ -391,13 +391,13 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val&, _Other...>>, int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template , @@ -406,13 +406,13 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val&, _Other...>>, int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , _STD _Tuple_convert_val, _Other...>>, @@ -420,13 +420,13 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val, _Other...>>, int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #if _HAS_CXX23 template , @@ -435,23 +435,23 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val, _Other...>>, int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template & _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(const pair<_First, _Second>& _Right) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>&&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #if _HAS_CXX23 template && _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(const pair<_First, _Second>&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template > static constexpr bool _Is_tuple_like_constructor_explicit_v = false; @@ -512,7 +512,7 @@ public: constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(_Other&& _Right) : tuple(_Unpack_tuple_t{}, _STD forward<_Other>(_Right)) { } -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template <_Different_from _Other> requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) && _Can_construct_values_from_tuple_like_v @@ -520,7 +520,7 @@ public: || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) && _Tuple_reference_constructs_from_temporary_for_tuple_like explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(_Other&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_constructible_val>, @@ -552,7 +552,7 @@ public: requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, _This2&&, _Rest2&&...) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , int> = 0> @@ -571,7 +571,7 @@ public: constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val&, _Other...>>, @@ -579,7 +579,7 @@ public: requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, tuple<_Other...>&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val&, _Other...>>, @@ -597,7 +597,7 @@ public: requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, const tuple<_Other...>&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , @@ -606,7 +606,7 @@ public: _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val, _Other...>>, @@ -614,7 +614,7 @@ public: requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, tuple<_Other...>&&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #if _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , _STD _Tuple_convert_val, _Other...>>, @@ -632,20 +632,20 @@ public: requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, const tuple<_Other...>&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, pair<_First, _Second>&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, const pair<_First, _Second>&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, pair<_First, _Second>&&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #if _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc&, const pair<_First, _Second>&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #ifdef __EDG__ // TRANSITION, VSO-1900279 template , int> = 0> @@ -700,7 +700,7 @@ public: tuple(allocator_arg_t, const _Alloc& _Al, _Other&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD forward<_Other>(_Right)) { } -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template _Other> requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) && _Can_construct_values_from_tuple_like_v @@ -708,7 +708,7 @@ public: || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) && _Tuple_reference_constructs_from_temporary_for_tuple_like explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(allocator_arg_t, const _Alloc&, _Other&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 tuple& operator=(const volatile tuple&) = delete; @@ -1269,12 +1269,12 @@ template #endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) /* strengthened */ { -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary if constexpr (tuple_size_v> == 1) { static_assert(!reference_constructs_from_temporary_v<_Ty, decltype(_STD get<0>(_STD forward<_Tuple>(_Tpl)))>, "Cannot bind a temporary to the returned reference which will always be dangling (N4993 [tuple.apply]/3)."); } -#endif //_HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ // construct _Ty from the elements of _Tpl return _STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}); diff --git a/stl/inc/type_traits b/stl/inc/type_traits index fc930c089be..53ece0d84ee 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -748,7 +748,7 @@ _EXPORT_STD template _NO_SPECIALIZATIONS_OF_TYPE_TRAITS constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Ty); -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary #ifdef __clang__ // TRANSITION, LLVM-114344 template struct _Adjust_ref_binding_source { @@ -787,7 +787,7 @@ struct _NO_SPECIALIZATIONS_OF_TYPE_TRAITS reference_converts_from_temporary _EXPORT_STD template _NO_SPECIALIZATIONS_OF_TYPE_TRAITS constexpr bool reference_converts_from_temporary_v = __reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>); -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #ifdef __EDG__ // TRANSITION, VSO-1690654 template @@ -1864,14 +1864,13 @@ struct _NO_SPECIALIZATIONS_OF_TYPE_TRAITS is_nothrow_convertible template struct _Invoke_convertible : false_type {}; -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template using _Not_reference_converts_from_temporary = bool_constant>; -#else // ^^^ _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS / !_HAS_CXX23 || - // !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS vvv +#else // ^^^ defined(__cpp_lib_reference_from_temporary) / !defined(__cpp_lib_reference_from_temporary) vvv template using _Not_reference_converts_from_temporary = true_type; -#endif // ^^^ !_HAS_CXX23 || !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS ^^^ +#endif // ^^^ !defined(__cpp_lib_reference_from_temporary) ^^^ template struct _Invoke_convertible<_From, _To, void_t(_STD _Returns_exactly<_From>()))>> diff --git a/stl/inc/utility b/stl/inc/utility index bf2f87490a4..6c2ec4336cd 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -275,14 +275,14 @@ struct pair { // store a pair of values is_nothrow_constructible_v<_Ty1, _Other1> && is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened : first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) { } -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , is_constructible<_Ty2, _Other2>>, int> = 0> requires reference_constructs_from_temporary_v<_Ty1, _Other1&&> || reference_constructs_from_temporary_v<_Ty2, _Other2&&> explicit(!conjunction_v, is_convertible<_Other2, _Ty2>>) pair(_Other1&&, _Other2&&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ pair(const pair&) = default; pair(pair&&) = default; @@ -294,14 +294,14 @@ struct pair { // store a pair of values pair(pair<_Other1, _Other2>& _Right) noexcept( is_nothrow_constructible_v<_Ty1, _Other1&> && is_nothrow_constructible_v<_Ty2, _Other2&>) // strengthened : first(_Right.first), second(_Right.second) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template requires is_constructible_v<_Ty1, _Other1&> && is_constructible_v<_Ty2, _Other2&> && (reference_constructs_from_temporary_v<_Ty1, _Other1&> || reference_constructs_from_temporary_v<_Ty2, _Other2&>) explicit(!conjunction_v, is_convertible<_Other2&, _Ty2>>) pair(pair<_Other1, _Other2>&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template && is_nothrow_constructible_v<_Ty2, const _Other2&>) // strengthened : first(_Right.first), second(_Right.second) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , is_constructible<_Ty2, const _Other2&>>, int> = 0> @@ -320,7 +320,7 @@ struct pair { // store a pair of values || reference_constructs_from_temporary_v<_Ty2, const _Other2&> explicit(!conjunction_v, is_convertible>) pair(const pair<_Other1, _Other2>&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , is_constructible<_Ty2, _Other2>>, int> = 0> @@ -328,14 +328,14 @@ struct pair { // store a pair of values pair(pair<_Other1, _Other2>&& _Right) noexcept( is_nothrow_constructible_v<_Ty1, _Other1> && is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened : first(_STD forward<_Other1>(_Right.first)), second(_STD forward<_Other2>(_Right.second)) {} -#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template , is_constructible<_Ty2, _Other2>>, int> = 0> requires reference_constructs_from_temporary_v<_Ty1, _Other1&&> || reference_constructs_from_temporary_v<_Ty2, _Other2&&> explicit(!conjunction_v, is_convertible<_Other2, _Ty2>>) pair(pair<_Other1, _Other2>&&) = delete; -#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #if _HAS_CXX23 template @@ -345,14 +345,14 @@ struct pair { // store a pair of values noexcept(is_nothrow_constructible_v<_Ty1, const _Other1> && is_nothrow_constructible_v<_Ty2, const _Other2>) // strengthened : first(_STD forward(_Right.first)), second(_STD forward(_Right.second)) {} -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template requires is_constructible_v<_Ty1, const _Other1> && is_constructible_v<_Ty2, const _Other2> && (reference_constructs_from_temporary_v<_Ty1, const _Other1 &&> || reference_constructs_from_temporary_v<_Ty2, const _Other2 &&>) explicit(!conjunction_v, is_convertible>) pair(const pair<_Other1, _Other2>&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #ifdef __EDG__ // TRANSITION, VSO-1900279 template , int> = 0> @@ -367,7 +367,7 @@ struct pair { // store a pair of values && is_nothrow_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>) // strengthened : first(_STD get<0>(_STD forward<_Other>(_Right))), second(_STD get<1>(_STD forward<_Other>(_Right))) { } -#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#ifdef __cpp_lib_reference_from_temporary template <_Pair_like_non_subrange _Other> requires conjunction_v(_STD declval<_Other>()))>, is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>> @@ -375,7 +375,7 @@ struct pair { // store a pair of values || reference_constructs_from_temporary_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>) explicit(!conjunction_v(_STD declval<_Other>())), _Ty1>, is_convertible(_STD declval<_Other>())), _Ty2>>) pair(_Other&&) = delete; -#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS +#endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 template From fbdf2a9e182f5c2361b3e710abd17a586c2bb123 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 07:11:36 -0700 Subject: [PATCH 09/12] Avoid confusion by consistently following `_To, _From` parameter order. --- stl/inc/type_traits | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 53ece0d84ee..57d105c40dd 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1865,16 +1865,16 @@ template struct _Invoke_convertible : false_type {}; #ifdef __cpp_lib_reference_from_temporary -template +template using _Not_reference_converts_from_temporary = bool_constant>; #else // ^^^ defined(__cpp_lib_reference_from_temporary) / !defined(__cpp_lib_reference_from_temporary) vvv -template +template using _Not_reference_converts_from_temporary = true_type; #endif // ^^^ !defined(__cpp_lib_reference_from_temporary) ^^^ template struct _Invoke_convertible<_From, _To, void_t(_STD _Returns_exactly<_From>()))>> - : _Not_reference_converts_from_temporary<_From, _To> {}; + : _Not_reference_converts_from_temporary<_To, _From> {}; template struct _Invoke_nothrow_convertible From 287cad37fae746d490c505946f71e1ffb78123d7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 12:07:43 -0700 Subject: [PATCH 10/12] Simplify `_Tuple_reference_constructs_from_temporary_for_tuple_like`. --- stl/inc/tuple | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index b8fa24ba626..0f190e566ec 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -212,22 +212,13 @@ template constexpr bool _Tuple_reference_constructs_from_temporary, _Args...> = (reference_constructs_from_temporary_v<_TupleTypes, _Args> || ...); -template -constexpr bool _Tuple_reference_constructs_from_temporary_for_tuple_like_impl = false; -template -constexpr bool - _Tuple_reference_constructs_from_temporary_for_tuple_like_impl<_Tuple, _TupleLike, index_sequence<_Indices...>> = - (reference_constructs_from_temporary_v, - decltype(_STD get<_Indices>(_STD declval<_TupleLike>()))> - || ...); - -template +template >> constexpr bool _Tuple_reference_constructs_from_temporary_for_tuple_like = false; -template +template requires (tuple_size_v<_Tuple> == tuple_size_v>) -constexpr bool _Tuple_reference_constructs_from_temporary_for_tuple_like<_Tuple, _TupleLike> = - _Tuple_reference_constructs_from_temporary_for_tuple_like_impl<_Tuple, _TupleLike, - make_index_sequence>>; +constexpr bool + _Tuple_reference_constructs_from_temporary_for_tuple_like<_Tuple, _TupleLike, index_sequence<_Indices...>> = + _Tuple_reference_constructs_from_temporary<_Tuple, decltype(_STD get<_Indices>(_STD declval<_TupleLike>()))...>; #endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ #endif // _HAS_CXX23 From 9f1fe770c41b15d14bdebf7151ea4d8e4350a2f3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 12:22:58 -0700 Subject: [PATCH 11/12] Add/update Standard citations. --- stl/inc/memory | 2 +- stl/inc/tuple | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index b4940f3fb75..531faba69f6 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3478,7 +3478,7 @@ public: #ifdef __cpp_lib_reference_from_temporary static_assert( !reference_converts_from_temporary_v, decltype(*_STD declval())>, - "it is disallowed to bind a temporary object to the result of unique_ptr::operator*"); + "Can't return a temporary object from unique_ptr::operator*(). (N5014 [unique.ptr.single.observers]/1)"); #endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ return *_Mypair._Myval2; } diff --git a/stl/inc/tuple b/stl/inc/tuple index 0f190e566ec..533d2ae882a 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -1263,7 +1263,7 @@ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_STD _ #ifdef __cpp_lib_reference_from_temporary if constexpr (tuple_size_v> == 1) { static_assert(!reference_constructs_from_temporary_v<_Ty, decltype(_STD get<0>(_STD forward<_Tuple>(_Tpl)))>, - "Cannot bind a temporary to the returned reference which will always be dangling (N4993 [tuple.apply]/3)."); + "Cannot bind a temporary to the returned reference which will always be dangling (N5014 [tuple.apply]/2)."); } #endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ // construct _Ty from the elements of _Tpl From 1679a75a8f0d7f8271cb71183318eed54e0be82c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Oct 2025 15:13:37 -0700 Subject: [PATCH 12/12] Drop parameter name for deleted function. --- stl/inc/tuple | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index 533d2ae882a..f46ad59a7d9 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -456,7 +456,7 @@ public: enable_if_t<_Tuple_constructible_v, int> = 0> requires _Tuple_reference_constructs_from_temporary explicit(_Tuple_conditional_explicit_v) - tuple(const pair<_First, _Second>& _Right) = delete; + tuple(const pair<_First, _Second>&) = delete; #endif // ^^^ defined(__cpp_lib_reference_from_temporary) ^^^ template , int> = 0>