Skip to content

Commit f69fb88

Browse files
committed
[libc++] Introduce __core_convertible_to and make this paper as a C++26 feature
Signed-off-by: yronglin <[email protected]>
1 parent a8aacd4 commit f69fb88

File tree

10 files changed

+71
-10
lines changed

10 files changed

+71
-10
lines changed

libcxx/include/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ set(files
307307
__concepts/constructible.h
308308
__concepts/convertible_to.h
309309
__concepts/copyable.h
310+
__concepts/core_convertible_to.h
310311
__concepts/derived_from.h
311312
__concepts/destructible.h
312313
__concepts/different_from.h
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef _LIBCPP___CONCEPTS_CORE_CONVERTIBLE_TO_H
2+
#define _LIBCPP___CONCEPTS_CORE_CONVERTIBLE_TO_H
3+
4+
#include <__config>
5+
6+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
7+
# pragma GCC system_header
8+
#endif
9+
10+
_LIBCPP_BEGIN_NAMESPACE_STD
11+
12+
#if _LIBCPP_STD_VER >= 20
13+
14+
// [conv.general]/3 says "E is convertible to T" whenever "T t=E;" is well-formed.
15+
// We can't test for that, but we can test implicit convertibility by passing it
16+
// to a function. Unlike std::convertible_to, __core_convertible_to doesn't test
17+
// static_cast or handle cv void, while accepting move-only types.
18+
//
19+
// This is a conceptual __is_core_convertible.
20+
template <class _Tp, class _Up>
21+
concept __core_convertible_to = requires {
22+
// rejects function and array types which are adjusted to pointer types in parameter lists
23+
static_cast<_Up (*)()>(nullptr)();
24+
static_cast<void (*)(_Up)>(nullptr)(static_cast<_Tp (*)()>(nullptr)());
25+
};
26+
27+
#endif
28+
29+
_LIBCPP_END_NAMESPACE_STD
30+
31+
#endif // _LIBCPP___CONCEPTS_CORE_CONVERTIBLE_TO_H

libcxx/include/__cxx03/module.modulemap

+1
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ module cxx03_std_private_concepts_constructible [system] {
11901190
}
11911191
module cxx03_std_private_concepts_convertible_to [system] { header "__concepts/convertible_to.h" }
11921192
module cxx03_std_private_concepts_copyable [system] { header "__concepts/copyable.h" }
1193+
module cxx03_std_private_concepts_core_convertible_to [system] { header "__concepts/core_convertible_to.h" }
11931194
module cxx03_std_private_concepts_derived_from [system] { header "__concepts/derived_from.h" }
11941195
module cxx03_std_private_concepts_destructible [system] {
11951196
header "__concepts/destructible.h"

libcxx/include/__expected/expected.h

+22-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#define _LIBCPP___EXPECTED_EXPECTED_H
1111

1212
#include <__assert>
13-
#include <__concepts/boolean_testable.h>
13+
#include <__concepts/core_convertible_to.h>
1414
#include <__config>
1515
#include <__expected/bad_expected_access.h>
1616
#include <__expected/unexpect.h>
@@ -1141,10 +1141,13 @@ class expected : private __expected_base<_Tp, _Err> {
11411141
// [expected.object.eq], equality operators
11421142
template <class _T2, class _E2>
11431143
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y)
1144-
requires(!is_void_v<_T2>) && requires {
1145-
{ *__x == *__y } -> __boolean_testable;
1146-
{ __x.error() == __y.error() } -> __boolean_testable;
1147-
}
1144+
requires(!is_void_v<_T2>)
1145+
# if _LIBCPP_STD_VER >= 26
1146+
&& requires {
1147+
{ *__x == *__y } -> __core_convertible_to<bool>;
1148+
{ __x.error() == __y.error() } -> __core_convertible_to<bool>;
1149+
}
1150+
# endif
11481151
{
11491152
if (__x.__has_val() != __y.__has_val()) {
11501153
return false;
@@ -1159,18 +1162,22 @@ class expected : private __expected_base<_Tp, _Err> {
11591162

11601163
template <class _T2>
11611164
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v)
1165+
# if _LIBCPP_STD_VER >= 26
11621166
requires(!__is_std_expected<_T2>::value) && requires {
1163-
{ *__x == __v } -> __boolean_testable;
1167+
{ *__x == __v } -> __core_convertible_to<bool>;
11641168
}
1169+
# endif
11651170
{
11661171
return __x.__has_val() && static_cast<bool>(__x.__val() == __v);
11671172
}
11681173

11691174
template <class _E2>
11701175
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e)
1176+
# if _LIBCPP_STD_VER >= 26
11711177
requires requires {
1172-
{ __x.error() == __e.error() } -> __boolean_testable;
1178+
{ __x.error() == __e.error() } -> __core_convertible_to<bool>;
11731179
}
1180+
# endif
11741181
{
11751182
return !__x.__has_val() && static_cast<bool>(__x.__unex() == __e.error());
11761183
}
@@ -1865,9 +1872,12 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
18651872
template <class _T2, class _E2>
18661873
requires is_void_v<_T2>
18671874
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y)
1875+
# if _LIBCPP_STD_VER >= 26
1876+
18681877
requires requires {
1869-
{ __x.error() == __y.error() } -> __boolean_testable;
1878+
{ __x.error() == __y.error() } -> __core_convertible_to<bool>;
18701879
}
1880+
# endif
18711881
{
18721882
if (__x.__has_val() != __y.__has_val()) {
18731883
return false;
@@ -1878,9 +1888,12 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
18781888

18791889
template <class _E2>
18801890
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y)
1891+
# if _LIBCPP_STD_VER >= 26
1892+
18811893
requires requires {
1882-
{ __x.error() == __y.error() } -> __boolean_testable;
1894+
{ __x.error() == __y.error() } -> __core_convertible_to<bool>;
18831895
}
1896+
# endif
18841897
{
18851898
return !__x.__has_val() && static_cast<bool>(__x.__unex() == __y.error());
18861899
}

libcxx/include/module.modulemap.in

+1
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ module std [system] {
10751075
module constructible { header "__concepts/constructible.h" }
10761076
module convertible_to { header "__concepts/convertible_to.h" }
10771077
module copyable { header "__concepts/copyable.h" }
1078+
module core_convertible_to { header "__concepts/core_convertible_to.h" }
10781079
module derived_from { header "__concepts/derived_from.h" }
10791080
module destructible { header "__concepts/destructible.h" }
10801081
module different_from { header "__concepts/different_from.h" }

libcxx/test/std/utilities/expected/expected.expected/equality/equality.T2.pass.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
#include "test_macros.h"
2020
#include "../../types.h"
2121

22+
#if TEST_STD_VER >= 26
2223
// https://wg21.link/P3379R0
2324
static_assert(CanCompare<std::expected<int, int>, int>);
2425
static_assert(CanCompare<std::expected<int, int>, EqualityComparable>);
2526
static_assert(!CanCompare<std::expected<int, int>, NonComparable>);
27+
#endif
2628

2729
constexpr bool test() {
2830
// x.has_value()

libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,18 @@ static_assert(!CanCompare<NonComparable, NonComparable>);
2626
static_assert(CanCompare<std::expected<int, int>, std::expected<int, int>>);
2727
static_assert(CanCompare<std::expected<int, int>, std::expected<short, short>>);
2828

29+
#if TEST_STD_VER >= 26
2930
// https://wg21.link/P3379R0
3031
static_assert(!CanCompare<std::expected<int, int>, std::expected<void, int>>);
3132
static_assert(CanCompare<std::expected<int, int>, std::expected<int, int>>);
3233
static_assert(!CanCompare<std::expected<NonComparable, int>, std::expected<NonComparable, int>>);
3334
static_assert(!CanCompare<std::expected<int, NonComparable>, std::expected<int, NonComparable>>);
3435
static_assert(!CanCompare<std::expected<NonComparable, int>, std::expected<int, NonComparable>>);
3536
static_assert(!CanCompare<std::expected<int, NonComparable>, std::expected<NonComparable, int>>);
36-
37+
#else
38+
// Note this is true because other overloads in expected<non-void> are unconstrained
39+
static_assert(CanCompare<std::expected<void, int>, std::expected<int, int>>);
40+
#endif
3741
constexpr bool test() {
3842
// x.has_value() && y.has_value()
3943
{

libcxx/test/std/utilities/expected/expected.expected/equality/equality.unexpected.pass.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
#include "test_macros.h"
2020
#include "../../types.h"
2121

22+
#if TEST_STD_VER >= 26
2223
// https://wg21.link/P3379R0
2324
static_assert(CanCompare<std::expected<EqualityComparable, EqualityComparable>, std::unexpected<int>>);
2425
static_assert(CanCompare<std::expected<EqualityComparable, int>, std::unexpected<EqualityComparable>>);
2526
static_assert(!CanCompare<std::expected<EqualityComparable, NonComparable>, std::unexpected<int>>);
27+
#endif
2628

2729
constexpr bool test() {
2830
// x.has_value()

libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,18 @@ static_assert(!CanCompare<Foo, Foo>);
2626
static_assert(CanCompare<std::expected<void, int>, std::expected<void, int>>);
2727
static_assert(CanCompare<std::expected<void, int>, std::expected<void, short>>);
2828

29+
#if TEST_STD_VER >= 26
2930
// https://wg21.link/P3379R0
3031
static_assert(!CanCompare<std::expected<void, int>, std::expected<int, int>>);
3132
static_assert(CanCompare<std::expected<void, int>, std::expected<void, int>>);
3233
static_assert(CanCompare<std::expected<void, int>, std::expected<void, int>>);
3334
static_assert(!CanCompare<std::expected<void, NonComparable>, std::expected<void, NonComparable>>);
3435
static_assert(!CanCompare<std::expected<void, int>, std::expected<void, NonComparable>>);
3536
static_assert(!CanCompare<std::expected<void, NonComparable>, std::expected<void, int>>);
37+
#else
38+
// Note this is true because other overloads in expected<non-void> are unconstrained
39+
static_assert(CanCompare<std::expected<void, int>, std::expected<int, int>>);
40+
#endif
3641

3742
constexpr bool test() {
3843
// x.has_value() && y.has_value()

llvm/utils/gn/secondary/libcxx/include/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ if (current_toolchain == default_toolchain) {
382382
"__concepts/constructible.h",
383383
"__concepts/convertible_to.h",
384384
"__concepts/copyable.h",
385+
"__concepts/core_convertible_to.h",
385386
"__concepts/derived_from.h",
386387
"__concepts/destructible.h",
387388
"__concepts/different_from.h",

0 commit comments

Comments
 (0)