Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -3475,6 +3475,11 @@ public:
}

_NODISCARD _CONSTEXPR23 add_lvalue_reference_t<_Ty> operator*() const noexcept(noexcept(*_STD declval<pointer>())) {
#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
static_assert(
!reference_converts_from_temporary_v<add_lvalue_reference_t<_Ty>, decltype(*_STD declval<pointer>())>,
"it is disallowed to bind a temporary object to the result of unique_ptr<T, D>::operator*");
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
return *_Mypair._Myval2;
}

Expand Down
182 changes: 182 additions & 0 deletions stl/inc/tuple

Large diffs are not rendered by default.

52 changes: 51 additions & 1 deletion stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,47 @@ struct has_unique_object_representations : bool_constant<__has_unique_object_rep
_EXPORT_STD template <class _Ty>
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 <class _Ty>
struct _Adjust_ref_binding_source {
using type = _Ty;
};
template <class _Ty>
requires is_scalar_v<_Ty> || is_void_v<_Ty>
struct _Adjust_ref_binding_source<_Ty> {
using type = remove_cv_t<_Ty>;
};
template <class _Ty>
requires is_function_v<_Ty> && requires { typename void_t<_Ty&>; }
struct _Adjust_ref_binding_source<_Ty> {
using type = _Ty&;
};

template <class _Ty>
using _Adjust_ref_binding_source_t = _Adjust_ref_binding_source<_Ty>::type;
#else // ^^^ workaround / no workaround vvv
template <class _Ty>
using _Adjust_ref_binding_source_t = _Ty;
#endif // ^^^ no workaround ^^^

_EXPORT_STD template <class _Ty, class _Uty>
struct reference_constructs_from_temporary
: bool_constant<__reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {};

_EXPORT_STD template <class _Ty, class _Uty>
constexpr bool reference_constructs_from_temporary_v =
__reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>);

_EXPORT_STD template <class _Ty, class _Uty>
struct reference_converts_from_temporary
: bool_constant<__reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {};

_EXPORT_STD template <class _Ty, class _Uty>
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 <class _Ty>
struct _Is_aggregate_impl : bool_constant<__is_aggregate(_Ty)> {};
Expand Down Expand Up @@ -1739,9 +1780,18 @@ struct is_nothrow_convertible : bool_constant<_Is_nothrow_convertible_v<_From, _
template <class _From, class _To, class = void>
struct _Invoke_convertible : false_type {};

#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
template <class _From, class _To>
using _Not_reference_converts_from_temporary = bool_constant<!reference_converts_from_temporary_v<_To, _From>>;
#else // ^^^ _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS / !_HAS_CXX23 ||
// !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS vvv
template <class _From, class _To>
using _Not_reference_converts_from_temporary = true_type;
#endif // ^^^ !_HAS_CXX23 || !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS ^^^

template <class _From, class _To>
struct _Invoke_convertible<_From, _To, void_t<decltype(_STD _Fake_copy_init<_To>(_STD _Returns_exactly<_From>()))>>
: true_type {};
: _Not_reference_converts_from_temporary<_From, _To> {};

template <class _From, class _To>
struct _Invoke_nothrow_convertible
Expand Down
50 changes: 50 additions & 0 deletions stl/inc/utility
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class _Other1 = _Ty1, class _Other2 = _Ty2,
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, 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<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>)
pair(_Other1&&, _Other2&&) = delete;
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS

pair(const pair&) = default;
pair(pair&&) = default;
Expand All @@ -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 <class _Other1, class _Other2>
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<_Other1&, _Ty1>, is_convertible<_Other2&, _Ty2>>)
pair(pair<_Other1, _Other2>&) = delete;
#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
#endif // _HAS_CXX23

template <class _Other1, class _Other2,
Expand All @@ -294,13 +310,30 @@ struct pair { // store a pair of values
noexcept(is_nothrow_constructible_v<_Ty1, const _Other1&>
&& is_nothrow_constructible_v<_Ty2, const _Other2&>) // strengthened
: first(_Right.first), second(_Right.second) {}
#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
template <class _Other1, class _Other2,
enable_if_t<conjunction_v<is_constructible<_Ty1, const _Other1&>, 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<const _Other1&, _Ty1>, is_convertible<const _Other2&, _Ty2>>)
pair(const pair<_Other1, _Other2>&) = delete;
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS

template <class _Other1, class _Other2,
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0>
constexpr explicit(!conjunction_v<is_convertible<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>)
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 <class _Other1, class _Other2,
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, 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<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>)
pair(pair<_Other1, _Other2>&&) = delete;
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS

#if _HAS_CXX23
template <class _Other1, class _Other2>
Expand All @@ -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<const _Other1>(_Right.first)), second(_STD forward<const _Other2>(_Right.second)) {}
#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
template <class _Other1, class _Other2>
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<const _Other1, _Ty1>, is_convertible<const _Other2, _Ty2>>)
pair(const pair<_Other1, _Other2>&&) = delete;
#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS

#ifdef __EDG__ // TRANSITION, VSO-1900279
template <class _Other, enable_if_t<_Can_construct_from_pair_like<_Other, _Ty1, _Ty2>, int> = 0>
Expand All @@ -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<is_constructible<_Ty1, decltype(_STD get<0>(_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<is_convertible<decltype(_STD get<0>(_STD declval<_Other>())), _Ty1>,
is_convertible<decltype(_STD get<1>(_STD declval<_Other>())), _Ty2>>) pair(_Other&&) = delete;
#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
#endif // _HAS_CXX23

template <class... _Types1, class... _Types2>
Expand Down
31 changes: 23 additions & 8 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,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
Expand Down Expand Up @@ -941,6 +943,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"

Expand Down Expand Up @@ -1823,14 +1832,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
Expand Down
11 changes: 9 additions & 2 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,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
Expand Down Expand Up @@ -554,9 +558,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
std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp:0 FAIL
std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp:1 FAIL

Expand Down
4 changes: 4 additions & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,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
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P2255R2_invocation/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_latest_matrix.lst
64 changes: 64 additions & 0 deletions tests/std/tests/P2255R2_invocation/test.compile.pass.cpp
Original file line number Diff line number Diff line change
@@ -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 <functional>
#include <type_traits>

using namespace std;

struct LvalueTempFunctor {
int operator()() const& noexcept;
const int& operator()() const&& noexcept;
};

static_assert(is_invocable_r_v<const int&, int& (*) ()>);
static_assert(!is_invocable_r_v<const int&, short& (*) ()>);
static_assert(!is_invocable_r_v<const int&, int (*)()>);
static_assert(!is_invocable_r_v<int&&, int (*)()>);
static_assert(is_invocable_r_v<int, int (*)()>);
static_assert(is_invocable_r_v<const int&, LvalueTempFunctor>);
static_assert(!is_invocable_r_v<const int&, LvalueTempFunctor&>);

static_assert(is_constructible_v<function<const int&()>, int& (*) ()>);
static_assert(!is_constructible_v<function<const int&()>, short& (*) ()>);
static_assert(!is_constructible_v<function<const int&()>, int (*)()>);
static_assert(!is_constructible_v<function<const int&()>, LvalueTempFunctor>);

static_assert(is_constructible_v<move_only_function<const int&()>, int& (*) ()>);
static_assert(!is_constructible_v<move_only_function<const int&()>, short& (*) ()>);
static_assert(!is_constructible_v<move_only_function<const int&()>, int (*)()>);

static_assert(is_constructible_v<move_only_function<const int&() const>, int& (*) ()>);
static_assert(!is_constructible_v<move_only_function<const int&() const>, short& (*) ()>);
static_assert(!is_constructible_v<move_only_function<const int&() const>, int (*)()>);

static_assert(!is_constructible_v<move_only_function<const int&() &>, LvalueTempFunctor>);
static_assert(!is_constructible_v<move_only_function<const int&() const&>, LvalueTempFunctor>);
static_assert(is_constructible_v<move_only_function<const int&() &&>, LvalueTempFunctor>);
static_assert(is_constructible_v<move_only_function<const int&() const&&>, LvalueTempFunctor>);

#ifdef __cpp_noexcept_function_type
static_assert(is_nothrow_invocable_r_v<const int&, int& (*) () noexcept>);
static_assert(!is_nothrow_invocable_r_v<const int&, short& (*) () noexcept>);
static_assert(!is_nothrow_invocable_r_v<const int&, int (*)() noexcept>);
static_assert(!is_nothrow_invocable_r_v<int&&, int (*)() noexcept>);
static_assert(is_nothrow_invocable_r_v<int, int (*)() noexcept>);
static_assert(is_nothrow_invocable_r_v<const int&, LvalueTempFunctor>);
static_assert(!is_nothrow_invocable_r_v<const int&, LvalueTempFunctor&>);

static_assert(is_constructible_v<move_only_function<const int&() noexcept>, int& (*) () noexcept>);
static_assert(!is_constructible_v<move_only_function<const int&() noexcept>, short& (*) () noexcept>);
static_assert(!is_constructible_v<move_only_function<const int&() noexcept>, int (*)() noexcept>);

static_assert(is_constructible_v<move_only_function<const int&() const noexcept>, int& (*) () noexcept>);
static_assert(!is_constructible_v<move_only_function<const int&() const noexcept>, short& (*) () noexcept>);
static_assert(!is_constructible_v<move_only_function<const int&() const noexcept>, int (*)() noexcept>);

static_assert(!is_constructible_v<move_only_function<const int&() & noexcept>, LvalueTempFunctor>);
static_assert(!is_constructible_v<move_only_function<const int&() const & noexcept>, LvalueTempFunctor>);
static_assert(is_constructible_v<move_only_function<const int&() && noexcept>, LvalueTempFunctor>);
static_assert(is_constructible_v<move_only_function<const int&() const && noexcept>, LvalueTempFunctor>);
#endif // defined(__cpp_noexcept_function_type)
#endif // ^^^ no workaround ^^^
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_latest_matrix.lst
Loading