Skip to content

Commit 37ec87a

Browse files
Implement P2255R2 for Clang
1 parent 41ec195 commit 37ec87a

File tree

16 files changed

+907
-12
lines changed

16 files changed

+907
-12
lines changed

stl/inc/memory

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3467,6 +3467,11 @@ public:
34673467
}
34683468

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

stl/inc/tuple

Lines changed: 182 additions & 0 deletions
Large diffs are not rendered by default.

stl/inc/type_traits

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,47 @@ struct has_unique_object_representations : bool_constant<__has_unique_object_rep
699699
_EXPORT_STD template <class _Ty>
700700
constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Ty);
701701

702+
#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
703+
#ifdef __clang__ // TRANSITION, LLVM-114344
704+
template <class _Ty>
705+
struct _Adjust_ref_binding_source {
706+
using type = _Ty;
707+
};
708+
template <class _Ty>
709+
requires is_scalar_v<_Ty> || is_void_v<_Ty>
710+
struct _Adjust_ref_binding_source<_Ty> {
711+
using type = remove_cv_t<_Ty>;
712+
};
713+
template <class _Ty>
714+
requires is_function_v<_Ty> && requires { typename void_t<_Ty&>; }
715+
struct _Adjust_ref_binding_source<_Ty> {
716+
using type = _Ty&;
717+
};
718+
719+
template <class _Ty>
720+
using _Adjust_ref_binding_source_t = _Adjust_ref_binding_source<_Ty>::type;
721+
#else // ^^^ workaround / no workaround vvv
722+
template <class _Ty>
723+
using _Adjust_ref_binding_source_t = _Ty;
724+
#endif // ^^^ no workaround ^^^
725+
726+
_EXPORT_STD template <class _Ty, class _Uty>
727+
struct reference_constructs_from_temporary
728+
: bool_constant<__reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {};
729+
730+
_EXPORT_STD template <class _Ty, class _Uty>
731+
constexpr bool reference_constructs_from_temporary_v =
732+
__reference_constructs_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>);
733+
734+
_EXPORT_STD template <class _Ty, class _Uty>
735+
struct reference_converts_from_temporary
736+
: bool_constant<__reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>)> {};
737+
738+
_EXPORT_STD template <class _Ty, class _Uty>
739+
constexpr bool reference_converts_from_temporary_v =
740+
__reference_converts_from_temporary(_Ty, _Adjust_ref_binding_source_t<_Uty>);
741+
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
742+
702743
#ifdef __EDG__ // TRANSITION, VSO-1690654
703744
template <class _Ty>
704745
struct _Is_aggregate_impl : bool_constant<__is_aggregate(_Ty)> {};
@@ -1739,9 +1780,18 @@ struct is_nothrow_convertible : bool_constant<_Is_nothrow_convertible_v<_From, _
17391780
template <class _From, class _To, class = void>
17401781
struct _Invoke_convertible : false_type {};
17411782

1783+
#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
1784+
template <class _From, class _To>
1785+
using _Not_reference_converts_from_temporary = bool_constant<!reference_converts_from_temporary_v<_To, _From>>;
1786+
#else // ^^^ _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS / !_HAS_CXX23 ||
1787+
// !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS vvv
1788+
template <class _From, class _To>
1789+
using _Not_reference_converts_from_temporary = true_type;
1790+
#endif // ^^^ !_HAS_CXX23 || !_HAS_REFERENCE_BINDING_TRAITS_INTRINSICS ^^^
1791+
17421792
template <class _From, class _To>
17431793
struct _Invoke_convertible<_From, _To, void_t<decltype(_STD _Fake_copy_init<_To>(_STD _Returns_exactly<_From>()))>>
1744-
: true_type {};
1794+
: _Not_reference_converts_from_temporary<_From, _To> {};
17451795

17461796
template <class _From, class _To>
17471797
struct _Invoke_nothrow_convertible

stl/inc/utility

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,14 @@ struct pair { // store a pair of values
273273
is_nothrow_constructible_v<_Ty1, _Other1> && is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened
274274
: first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) {
275275
}
276+
#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
277+
template <class _Other1 = _Ty1, class _Other2 = _Ty2,
278+
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0>
279+
requires reference_constructs_from_temporary_v<_Ty1, _Other1&&>
280+
|| reference_constructs_from_temporary_v<_Ty2, _Other2&&>
281+
explicit(!conjunction_v<is_convertible<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>)
282+
pair(_Other1&&, _Other2&&) = delete;
283+
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
276284

277285
pair(const pair&) = default;
278286
pair(pair&&) = default;
@@ -284,6 +292,14 @@ struct pair { // store a pair of values
284292
pair(pair<_Other1, _Other2>& _Right) noexcept(
285293
is_nothrow_constructible_v<_Ty1, _Other1&> && is_nothrow_constructible_v<_Ty2, _Other2&>) // strengthened
286294
: first(_Right.first), second(_Right.second) {}
295+
#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
296+
template <class _Other1, class _Other2>
297+
requires is_constructible_v<_Ty1, _Other1&> && is_constructible_v<_Ty2, _Other2&>
298+
&& (reference_constructs_from_temporary_v<_Ty1, _Other1&>
299+
|| reference_constructs_from_temporary_v<_Ty2, _Other2&>)
300+
explicit(!conjunction_v<is_convertible<_Other1&, _Ty1>, is_convertible<_Other2&, _Ty2>>)
301+
pair(pair<_Other1, _Other2>&) = delete;
302+
#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
287303
#endif // _HAS_CXX23
288304

289305
template <class _Other1, class _Other2,
@@ -294,13 +310,30 @@ struct pair { // store a pair of values
294310
noexcept(is_nothrow_constructible_v<_Ty1, const _Other1&>
295311
&& is_nothrow_constructible_v<_Ty2, const _Other2&>) // strengthened
296312
: first(_Right.first), second(_Right.second) {}
313+
#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
314+
template <class _Other1, class _Other2,
315+
enable_if_t<conjunction_v<is_constructible<_Ty1, const _Other1&>, is_constructible<_Ty2, const _Other2&>>,
316+
int> = 0>
317+
requires reference_constructs_from_temporary_v<_Ty1, const _Other1&>
318+
|| reference_constructs_from_temporary_v<_Ty2, const _Other2&>
319+
explicit(!conjunction_v<is_convertible<const _Other1&, _Ty1>, is_convertible<const _Other2&, _Ty2>>)
320+
pair(const pair<_Other1, _Other2>&) = delete;
321+
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
297322

298323
template <class _Other1, class _Other2,
299324
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0>
300325
constexpr explicit(!conjunction_v<is_convertible<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>)
301326
pair(pair<_Other1, _Other2>&& _Right) noexcept(
302327
is_nothrow_constructible_v<_Ty1, _Other1> && is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened
303328
: first(_STD forward<_Other1>(_Right.first)), second(_STD forward<_Other2>(_Right.second)) {}
329+
#if _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
330+
template <class _Other1, class _Other2,
331+
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0>
332+
requires reference_constructs_from_temporary_v<_Ty1, _Other1&&>
333+
|| reference_constructs_from_temporary_v<_Ty2, _Other2&&>
334+
explicit(!conjunction_v<is_convertible<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>)
335+
pair(pair<_Other1, _Other2>&&) = delete;
336+
#endif // _HAS_CXX23 && _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
304337

305338
#if _HAS_CXX23
306339
template <class _Other1, class _Other2>
@@ -310,6 +343,14 @@ struct pair { // store a pair of values
310343
noexcept(is_nothrow_constructible_v<_Ty1, const _Other1>
311344
&& is_nothrow_constructible_v<_Ty2, const _Other2>) // strengthened
312345
: first(_STD forward<const _Other1>(_Right.first)), second(_STD forward<const _Other2>(_Right.second)) {}
346+
#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
347+
template <class _Other1, class _Other2>
348+
requires is_constructible_v<_Ty1, const _Other1> && is_constructible_v<_Ty2, const _Other2>
349+
&& (reference_constructs_from_temporary_v<_Ty1, const _Other1 &&>
350+
|| reference_constructs_from_temporary_v<_Ty2, const _Other2 &&>)
351+
explicit(!conjunction_v<is_convertible<const _Other1, _Ty1>, is_convertible<const _Other2, _Ty2>>)
352+
pair(const pair<_Other1, _Other2>&&) = delete;
353+
#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
313354

314355
#ifdef __EDG__ // TRANSITION, VSO-1900279
315356
template <class _Other, enable_if_t<_Can_construct_from_pair_like<_Other, _Ty1, _Ty2>, int> = 0>
@@ -324,6 +365,15 @@ struct pair { // store a pair of values
324365
&& is_nothrow_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>) // strengthened
325366
: first(_STD get<0>(_STD forward<_Other>(_Right))), second(_STD get<1>(_STD forward<_Other>(_Right))) {
326367
}
368+
#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
369+
template <_Pair_like_non_subrange _Other>
370+
requires conjunction_v<is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>,
371+
is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>>
372+
&& (reference_constructs_from_temporary_v<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>
373+
|| reference_constructs_from_temporary_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>)
374+
explicit(!conjunction_v<is_convertible<decltype(_STD get<0>(_STD declval<_Other>())), _Ty1>,
375+
is_convertible<decltype(_STD get<1>(_STD declval<_Other>())), _Ty2>>) pair(_Other&&) = delete;
376+
#endif // _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
327377
#endif // _HAS_CXX23
328378

329379
template <class... _Types1, class... _Types2>

stl/inc/yvals_core.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@
363363
// P2165R4 Compatibility Between tuple, pair, And tuple-like Objects
364364
// P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr
365365
// P2186R2 Removing Garbage Collection Support
366+
// P2255R2 Type Traits To Detect References Binding To Temporaries
367+
// (for Clang only)
366368
// P2273R3 constexpr unique_ptr
367369
// P2278R4 cbegin Should Always Return A Constant Iterator
368370
// P2286R8 Formatting Ranges
@@ -937,6 +939,13 @@ _EMIT_STL_ERROR(STL1001, "Unexpected compiler version, expected MSVC 19.44 or ne
937939
#error /GR implies _HAS_STATIC_RTTI.
938940
#endif // defined(_CPPRTTI) && !_HAS_STATIC_RTTI
939941

942+
// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2.
943+
#if defined(__clang__) && !defined(__EDG__)
944+
#define _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS (__clang_major__ >= 19)
945+
#else // ^^^ defined(__clang__) && !defined(__EDG__) / !defined(__clang__) || defined(__EDG__) vvv
946+
#define _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS 0
947+
#endif // !defined(__clang__) || defined(__EDG__)
948+
940949
// N4950 [dcl.constexpr]/1: "A function or static data member declared with the
941950
// constexpr or consteval specifier is implicitly an inline function or variable"
942951

@@ -1819,14 +1828,20 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
18191828
#define __cpp_lib_ranges_stride 202207L
18201829
#define __cpp_lib_ranges_to_container 202202L
18211830
#define __cpp_lib_ranges_zip 202110L
1822-
#define __cpp_lib_spanstream 202106L
1823-
#define __cpp_lib_stacktrace 202011L
1824-
#define __cpp_lib_stdatomic_h 202011L
1825-
#define __cpp_lib_string_contains 202011L
1826-
#define __cpp_lib_string_resize_and_overwrite 202110L
1827-
#define __cpp_lib_to_underlying 202102L
1828-
#define __cpp_lib_tuple_like 202207L
1829-
#define __cpp_lib_unreachable 202202L
1831+
1832+
// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2.
1833+
#if _HAS_REFERENCE_BINDING_TRAITS_INTRINSICS
1834+
#define __cpp_lib_reference_from_temporary 202202L
1835+
#endif // ^^^ no workaround ^^^
1836+
1837+
#define __cpp_lib_spanstream 202106L
1838+
#define __cpp_lib_stacktrace 202011L
1839+
#define __cpp_lib_stdatomic_h 202011L
1840+
#define __cpp_lib_string_contains 202011L
1841+
#define __cpp_lib_string_resize_and_overwrite 202110L
1842+
#define __cpp_lib_to_underlying 202102L
1843+
#define __cpp_lib_tuple_like 202207L
1844+
#define __cpp_lib_unreachable 202202L
18301845
#endif // _HAS_CXX23
18311846

18321847
// macros with language mode sensitivity

tests/libcxx/expected_results.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,9 +561,12 @@ std/containers/container.adaptors/flat.set/types.compile.pass.cpp FAIL
561561
std/language.support/support.limits/support.limits.general/flat_set.version.compile.pass.cpp FAIL
562562

563563
# P2255R2 "Type Traits To Detect References Binding To Temporaries"
564-
std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp FAIL
565-
std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp FAIL
566-
std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp FAIL
564+
std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp:0 FAIL
565+
std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp:1 FAIL
566+
std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp:0 FAIL
567+
std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp:1 FAIL
568+
std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp:0 FAIL
569+
std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp:1 FAIL
567570

568571
# P2674R1 is_implicit_lifetime
569572
std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp FAIL

tests/std/test.lst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,10 @@ tests\P2165R4_tuple_like_pair
631631
tests\P2165R4_tuple_like_relational_operators
632632
tests\P2165R4_tuple_like_tuple_members
633633
tests\P2231R1_complete_constexpr_optional_variant
634+
tests\P2255R2_invocation
635+
tests\P2255R2_reference_constructs_from_temporary
636+
tests\P2255R2_reference_converts_from_temporary
637+
tests\P2255R2_tuple_pair_construction
634638
tests\P2273R3_constexpr_unique_ptr
635639
tests\P2278R4_basic_const_iterator
636640
tests\P2278R4_const_span
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\usual_latest_matrix.lst
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
// TRANSITION, MSVC and EDG haven't implemented intrinsics needed for P2255R2.
5+
#if defined(__clang__) && !defined(__EDG__)
6+
#include <functional>
7+
#include <type_traits>
8+
9+
using namespace std;
10+
11+
struct LvalueTempFunctor {
12+
int operator()() const& noexcept;
13+
const int& operator()() const&& noexcept;
14+
};
15+
16+
static_assert(is_invocable_r_v<const int&, int& (*) ()>);
17+
static_assert(!is_invocable_r_v<const int&, short& (*) ()>);
18+
static_assert(!is_invocable_r_v<const int&, int (*)()>);
19+
static_assert(!is_invocable_r_v<int&&, int (*)()>);
20+
static_assert(is_invocable_r_v<int, int (*)()>);
21+
static_assert(is_invocable_r_v<const int&, LvalueTempFunctor>);
22+
static_assert(!is_invocable_r_v<const int&, LvalueTempFunctor&>);
23+
24+
static_assert(is_constructible_v<function<const int&()>, int& (*) ()>);
25+
static_assert(!is_constructible_v<function<const int&()>, short& (*) ()>);
26+
static_assert(!is_constructible_v<function<const int&()>, int (*)()>);
27+
static_assert(!is_constructible_v<function<const int&()>, LvalueTempFunctor>);
28+
29+
static_assert(is_constructible_v<move_only_function<const int&()>, int& (*) ()>);
30+
static_assert(!is_constructible_v<move_only_function<const int&()>, short& (*) ()>);
31+
static_assert(!is_constructible_v<move_only_function<const int&()>, int (*)()>);
32+
33+
static_assert(is_constructible_v<move_only_function<const int&() const>, int& (*) ()>);
34+
static_assert(!is_constructible_v<move_only_function<const int&() const>, short& (*) ()>);
35+
static_assert(!is_constructible_v<move_only_function<const int&() const>, int (*)()>);
36+
37+
static_assert(!is_constructible_v<move_only_function<const int&() &>, LvalueTempFunctor>);
38+
static_assert(!is_constructible_v<move_only_function<const int&() const&>, LvalueTempFunctor>);
39+
static_assert(is_constructible_v<move_only_function<const int&() &&>, LvalueTempFunctor>);
40+
static_assert(is_constructible_v<move_only_function<const int&() const&&>, LvalueTempFunctor>);
41+
42+
#ifdef __cpp_noexcept_function_type
43+
static_assert(is_nothrow_invocable_r_v<const int&, int& (*) () noexcept>);
44+
static_assert(!is_nothrow_invocable_r_v<const int&, short& (*) () noexcept>);
45+
static_assert(!is_nothrow_invocable_r_v<const int&, int (*)() noexcept>);
46+
static_assert(!is_nothrow_invocable_r_v<int&&, int (*)() noexcept>);
47+
static_assert(is_nothrow_invocable_r_v<int, int (*)() noexcept>);
48+
static_assert(is_nothrow_invocable_r_v<const int&, LvalueTempFunctor>);
49+
static_assert(!is_nothrow_invocable_r_v<const int&, LvalueTempFunctor&>);
50+
51+
static_assert(is_constructible_v<move_only_function<const int&() noexcept>, int& (*) () noexcept>);
52+
static_assert(!is_constructible_v<move_only_function<const int&() noexcept>, short& (*) () noexcept>);
53+
static_assert(!is_constructible_v<move_only_function<const int&() noexcept>, int (*)() noexcept>);
54+
55+
static_assert(is_constructible_v<move_only_function<const int&() const noexcept>, int& (*) () noexcept>);
56+
static_assert(!is_constructible_v<move_only_function<const int&() const noexcept>, short& (*) () noexcept>);
57+
static_assert(!is_constructible_v<move_only_function<const int&() const noexcept>, int (*)() noexcept>);
58+
59+
static_assert(!is_constructible_v<move_only_function<const int&() & noexcept>, LvalueTempFunctor>);
60+
static_assert(!is_constructible_v<move_only_function<const int&() const & noexcept>, LvalueTempFunctor>);
61+
static_assert(is_constructible_v<move_only_function<const int&() && noexcept>, LvalueTempFunctor>);
62+
static_assert(is_constructible_v<move_only_function<const int&() const && noexcept>, LvalueTempFunctor>);
63+
#endif // defined(__cpp_noexcept_function_type)
64+
#endif // ^^^ no workaround ^^^
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\usual_latest_matrix.lst

0 commit comments

Comments
 (0)