Skip to content

Commit b322e34

Browse files
committed
[libc++][type_traits] Implements "A type trait to detect reference binding to temporary"
Implements partially: P2255R2: A type trait to detect reference binding to temporary llvm#105180 https://eel.is/c++draft/meta.type.synop https://eel.is/c++draft/meta.unary.prop Implented type traits: - [x] `reference_constructs_from_temporary` - [x] `reference_converts_from_temporary`
1 parent a4656bb commit b322e34

File tree

9 files changed

+360
-5
lines changed

9 files changed

+360
-5
lines changed

libcxx/docs/Status/Cxx23Papers.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"`P0627R6 <https://wg21.link/P0627R6>`__","Function to mark unreachable code","2022-02 (Virtual)","|Complete|","15",""
4444
"`P1206R7 <https://wg21.link/P1206R7>`__","``ranges::to``: A function to convert any range to a container","2022-02 (Virtual)","|Complete|","17",""
4545
"`P1413R3 <https://wg21.link/P1413R3>`__","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","2022-02 (Virtual)","|Complete|","","``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but clang doesn't issue a diagnostic for deprecated using template declarations."
46-
"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","","",""
46+
"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","Implemented the type traits only."
4747
"`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16",""
4848
"`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19",""
4949
"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","","",""

libcxx/include/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,8 @@ set(files
867867
__type_traits/negation.h
868868
__type_traits/promote.h
869869
__type_traits/rank.h
870+
__type_traits/reference_constructs_from_temporary.h
871+
__type_traits/reference_converts_from_temporary.h
870872
__type_traits/remove_all_extents.h
871873
__type_traits/remove_const.h
872874
__type_traits/remove_const_ref.h
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARARY_H
10+
#define _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARARY_H
11+
12+
#include <__config>
13+
#include <__type_traits/integral_constant.h>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
_LIBCPP_BEGIN_NAMESPACE_STD
20+
21+
template <class _Tp, class _Up>
22+
inline constexpr bool __reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Tp, _Up);
23+
24+
#if _LIBCPP_STD_VER >= 23
25+
26+
template <class _Tp, class _Up>
27+
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_constructs_from_temporary
28+
: public bool_constant<__reference_constructs_from_temporary(_Tp, _Up)> {};
29+
30+
template <class _Tp, class _Up>
31+
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_constructs_from_temporary_v =
32+
__reference_constructs_from_temporary_v<_Tp, _Up>;
33+
34+
#endif
35+
36+
_LIBCPP_END_NAMESPACE_STD
37+
38+
#endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARARY_H
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARARY_H
10+
#define _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARARY_H
11+
12+
#include <__config>
13+
#include <__type_traits/integral_constant.h>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
_LIBCPP_BEGIN_NAMESPACE_STD
20+
21+
#if __has_builtin(__reference_converts_from_temporary)
22+
23+
template <class _Tp, class _Up>
24+
inline constexpr bool __reference_converts_from_temporary_v = __reference_converts_from_temporary(_Tp, _Up);
25+
26+
# if _LIBCPP_STD_VER >= 23
27+
28+
template <class _Tp, class _Up>
29+
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_converts_from_temporary
30+
: public bool_constant<__reference_converts_from_temporary(_Tp, _Up)> {};
31+
32+
template <class _Tp, class _Up>
33+
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_converts_from_temporary_v =
34+
__reference_converts_from_temporary_v<_Tp, _Up>;
35+
36+
# endif
37+
38+
#endif
39+
40+
_LIBCPP_END_NAMESPACE_STD
41+
42+
#endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARARY_H

libcxx/include/module.modulemap

+8
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,14 @@ module std_core [system] {
369369
module negation { header "__type_traits/negation.h" }
370370
module promote { header "__type_traits/promote.h" }
371371
module rank { header "__type_traits/rank.h" }
372+
module reference_constructs_from_temporary {
373+
header "__type_traits/reference_constructs_from_temporary.h"
374+
export std_core.type_traits.integral_constant
375+
}
376+
module reference_converts_from_temporary {
377+
header "__type_traits/reference_converts_from_temporary.h"
378+
export std_core.type_traits.integral_constant
379+
}
372380
module remove_all_extents { header "__type_traits/remove_all_extents.h" }
373381
module remove_const_ref { header "__type_traits/remove_const_ref.h" }
374382
module remove_const { header "__type_traits/remove_const.h" }

libcxx/include/type_traits

+12
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ namespace std
143143
144144
template<class T> struct has_unique_object_representations; // C++17
145145
146+
template<class T, class U> struct reference_constructs_from_temporary; // Since C++23
147+
template<class T, class U> struct reference_converts_from_temporary; // Since C++23
148+
146149
// Relationships between types:
147150
template <class T, class U> struct is_same;
148151
template <class Base, class Derived> struct is_base_of;
@@ -382,6 +385,12 @@ namespace std
382385
= has_virtual_destructor<T>::value; // C++17
383386
template<class T> inline constexpr bool has_unique_object_representations_v // C++17
384387
= has_unique_object_representations<T>::value;
388+
template<class T, class U>
389+
constexpr bool reference_constructs_from_temporary_v
390+
= reference_constructs_from_temporary<T, U>::value; // Since C++23
391+
template<class T, class U>
392+
constexpr bool reference_converts_from_temporary_v
393+
= reference_converts_from_temporary<T, U>::value; // Since C++23
385394
386395
// See C++14 20.10.5, type property queries
387396
template <class T> inline constexpr size_t alignment_of_v
@@ -524,6 +533,9 @@ namespace std
524533
# if _LIBCPP_STD_VER >= 23
525534
# include <__type_traits/is_implicit_lifetime.h>
526535
# endif
536+
// C++23 but private viariables available in earlier Standards.
537+
# include <__type_traits/reference_constructs_from_temporary.h>
538+
# include <__type_traits/reference_converts_from_temporary.h>
527539

528540
# include <version>
529541

libcxx/modules/std/type_traits.inc

+12-4
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,12 @@ export namespace std {
106106

107107
using std::has_unique_object_representations;
108108

109-
// using std::reference_constructs_from_temporary;
110-
// using std::reference_converts_from_temporary;
109+
#if _LIBCPP_STD_VER >= 23
110+
using std::reference_constructs_from_temporary;
111+
# if __has_builtin(__reference_converts_from_temporary)
112+
using std::reference_converts_from_temporary;
113+
# endif
114+
#endif
111115

112116
// [meta.unary.prop.query], type property queries
113117
using std::alignment_of;
@@ -284,8 +288,12 @@ export namespace std {
284288
using std::is_unbounded_array_v;
285289
using std::is_unsigned_v;
286290
using std::is_volatile_v;
287-
// using std::reference_constructs_from_temporary_v;
288-
// using std::reference_converts_from_temporary_v;
291+
#if _LIBCPP_STD_VER >= 23
292+
using std::reference_constructs_from_temporary_v;
293+
# if __has_builtin(__reference_converts_from_temporary)
294+
using std::reference_converts_from_temporary_v;
295+
# endif
296+
#endif
289297

290298
// [meta.unary.prop.query], type property queries
291299
using std::alignment_of_v;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: std-at-least-23
10+
11+
// <type_traits>
12+
13+
// template<class T, class U> struct reference_constructs_from_temporary;
14+
15+
// template<class T, class U>
16+
// constexpr bool reference_constructs_from_temporary_v
17+
// = reference_constructs_from_temporary<T, U>::value;
18+
19+
#include <cassert>
20+
#include <type_traits>
21+
22+
struct NonPOD {
23+
NonPOD(int);
24+
};
25+
enum Enum { EV };
26+
struct POD {
27+
Enum e;
28+
int i;
29+
float f;
30+
NonPOD* p;
31+
};
32+
// Not PODs
33+
struct Derives : POD {};
34+
35+
template <class T, class RefType = T&>
36+
struct ConvertsToRef {
37+
operator RefType() const { return static_cast<RefType>(obj); }
38+
mutable T obj = 42;
39+
};
40+
template <class T, class RefType = T&>
41+
class ConvertsToRefPrivate {
42+
operator RefType() const { return static_cast<RefType>(obj); }
43+
mutable T obj = 42;
44+
};
45+
46+
struct ExplicitConversionRvalueRef {
47+
operator int();
48+
explicit operator int&&();
49+
};
50+
51+
struct ExplicitConversionRef {
52+
operator int();
53+
explicit operator int&();
54+
};
55+
56+
template <typename T, typename U, bool Expected>
57+
constexpr void test_reference_constructs_from_temporary() {
58+
assert((std::reference_constructs_from_temporary<T, U>::value == Expected));
59+
assert((std::reference_constructs_from_temporary_v<T, U> == Expected));
60+
}
61+
62+
constexpr bool test() {
63+
test_reference_constructs_from_temporary<int&, int&, false>();
64+
test_reference_constructs_from_temporary<int&, int&, false>();
65+
test_reference_constructs_from_temporary<int&, int&&, false>();
66+
67+
test_reference_constructs_from_temporary<const int&, int&, false>();
68+
test_reference_constructs_from_temporary<const int&, const int&, false>();
69+
test_reference_constructs_from_temporary<const int&, int&&, false>();
70+
71+
test_reference_constructs_from_temporary<int&, long&, false>(); // doesn't construct
72+
73+
test_reference_constructs_from_temporary<const int&, long&, true>();
74+
test_reference_constructs_from_temporary<const int&, long&&, true>();
75+
test_reference_constructs_from_temporary<int&&, long&, true>();
76+
77+
using LRef = ConvertsToRef<int, int&>;
78+
using RRef = ConvertsToRef<int, int&&>;
79+
using CLRef = ConvertsToRef<int, const int&>;
80+
using LongRef = ConvertsToRef<long, long&>;
81+
82+
assert((std::is_constructible_v<int&, LRef>));
83+
test_reference_constructs_from_temporary<int&, LRef, false>();
84+
85+
assert((std::is_constructible_v<int&&, RRef>));
86+
test_reference_constructs_from_temporary<int&&, RRef, false>();
87+
88+
assert((std::is_constructible_v<const int&, CLRef>));
89+
test_reference_constructs_from_temporary<int&&, CLRef, false>();
90+
91+
assert((std::is_constructible_v<const int&, LongRef>));
92+
test_reference_constructs_from_temporary<const int&, LongRef, true>();
93+
test_reference_constructs_from_temporary<const int&, ConvertsToRefPrivate<long, long&>, false>();
94+
95+
// Test that it doesn't accept non-reference types as input.
96+
test_reference_constructs_from_temporary<int, long, false>();
97+
98+
test_reference_constructs_from_temporary<const int&, long, true>();
99+
100+
// Additional checks
101+
test_reference_constructs_from_temporary<POD const&, Derives, true>();
102+
test_reference_constructs_from_temporary<int&&, int, true>();
103+
test_reference_constructs_from_temporary<const int&, int, true>();
104+
test_reference_constructs_from_temporary<int&&, int&&, false>();
105+
test_reference_constructs_from_temporary<const int&, int&&, false>();
106+
test_reference_constructs_from_temporary<int&&, long&&, true>();
107+
test_reference_constructs_from_temporary<int&&, long, true>();
108+
109+
test_reference_constructs_from_temporary<int&, ExplicitConversionRef, false>();
110+
test_reference_constructs_from_temporary<const int&, ExplicitConversionRef, false>();
111+
test_reference_constructs_from_temporary<int&&, ExplicitConversionRvalueRef, false>();
112+
113+
return true;
114+
}
115+
116+
int main(int, char**) {
117+
test();
118+
static_assert(test());
119+
120+
return 0;
121+
}

0 commit comments

Comments
 (0)