Skip to content

Commit 5d73c7d

Browse files
bgra8Bogdan Graurldionne
authored
[libc++] Re-introduce special support for narrowing conversions to bool in variant (#73121)
This patch re-introduces special support for narrowing conversions to bool in std::variant, which was removed in 170810f in order to make libc++ Standards-conforming. The special support is gated by the `_LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT` macro and will be supported for LLVM 18 only as a courtesy to help large code bases migrate over to the Standard behavior. --------- Co-authored-by: Bogdan Graur <[email protected]> Co-authored-by: Louis Dionne <[email protected]>
1 parent 12bcd63 commit 5d73c7d

File tree

7 files changed

+39
-1
lines changed

7 files changed

+39
-1
lines changed

libcxx/docs/ReleaseNotes/18.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ Deprecations and Removals
8181
- The non-conforming constructor ``std::future_error(std::error_code)`` has been removed. Please use the
8282
``std::future_error(std::future_errc)`` constructor provided in C++17 instead.
8383

84+
- `P1957 <https://wg21.link/P1957>` has been implemented in Clang and libc++ removed a code path that led to
85+
narrowing conversions in ``std::variant`` behaving in a non-standard way. This may change how some uses of
86+
``std::variant``'s constructor behave in user code. The ``_LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT``
87+
macro is provided to restore the previous behavior, and it will be supported in the LLVM 18 release only.
88+
In LLVM 19 and beyond, ``_LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT`` will not be honored anymore.
89+
8490
Upcoming Deprecations and Removals
8591
----------------------------------
8692

libcxx/include/variant

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,25 @@ struct __overload {
12521252
auto operator()(_Tp, _Up&&) const -> __check_for_narrowing<_Tp, _Up>;
12531253
};
12541254

1255+
// TODO(LLVM-19): Remove all occurrences of this macro.
1256+
#ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
1257+
template <class _Tp, size_t>
1258+
struct __overload_bool {
1259+
template <class _Up, class _Ap = __remove_cvref_t<_Up>>
1260+
auto operator()(bool, _Up&&) const
1261+
-> enable_if_t<is_same_v<_Ap, bool>, __type_identity<_Tp>>;
1262+
};
1263+
1264+
template <size_t _Idx>
1265+
struct __overload<bool, _Idx> : __overload_bool<bool, _Idx> {};
1266+
template <size_t _Idx>
1267+
struct __overload<bool const, _Idx> : __overload_bool<bool const, _Idx> {};
1268+
template <size_t _Idx>
1269+
struct __overload<bool volatile, _Idx> : __overload_bool<bool volatile, _Idx> {};
1270+
template <size_t _Idx>
1271+
struct __overload<bool const volatile, _Idx> : __overload_bool<bool const volatile, _Idx> {};
1272+
#endif
1273+
12551274
template <class ..._Bases>
12561275
struct __all_overloads : _Bases... {
12571276
void operator()() const;

libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,10 @@ void test_T_assignment_sfinae() {
146146
};
147147
static_assert(!std::is_assignable<V, X>::value,
148148
"no boolean conversion in operator=");
149+
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
149150
static_assert(std::is_assignable<V, std::false_type>::value,
150151
"converted to bool in operator=");
152+
#endif
151153
}
152154
{
153155
struct X {};
@@ -297,11 +299,13 @@ void test_T_assignment_performs_assignment() {
297299
}
298300

299301
void test_T_assignment_vector_bool() {
302+
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
300303
std::vector<bool> vec = {true};
301304
std::variant<bool, int> v;
302305
v = vec[0];
303306
assert(v.index() == 0);
304307
assert(std::get<0>(v) == true);
308+
#endif
305309
}
306310

307311
int main(int, char**) {

libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ int main(int, char**)
3434
static_assert(!std::is_assignable<std::variant<int, bool>, decltype("meow")>::value, "");
3535
static_assert(!std::is_assignable<std::variant<int, const bool>, decltype("meow")>::value, "");
3636

37+
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
3738
static_assert(std::is_assignable<std::variant<bool>, std::true_type>::value, "");
39+
#endif
3840
static_assert(!std::is_assignable<std::variant<bool>, std::unique_ptr<char> >::value, "");
3941
static_assert(!std::is_assignable<std::variant<bool>, decltype(nullptr)>::value, "");
4042

libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,10 @@ void test_T_ctor_sfinae() {
8080
};
8181
static_assert(!std::is_constructible<V, X>::value,
8282
"no boolean conversion in constructor");
83+
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
8384
static_assert(std::is_constructible<V, std::false_type>::value,
8485
"converted to bool in constructor");
86+
#endif
8587
}
8688
{
8789
struct X {};
@@ -200,10 +202,12 @@ void test_construction_with_repeated_types() {
200202
}
201203

202204
void test_vector_bool() {
205+
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
203206
std::vector<bool> vec = {true};
204207
std::variant<bool, int> v = vec[0];
205208
assert(v.index() == 0);
206209
assert(std::get<0>(v) == true);
210+
#endif
207211
}
208212

209213
int main(int, char**) {

libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ int main(int, char**)
3333
static_assert(!std::is_constructible<std::variant<int, bool>, decltype("meow")>::value, "");
3434
static_assert(!std::is_constructible<std::variant<int, const bool>, decltype("meow")>::value, "");
3535

36+
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
3637
static_assert(std::is_constructible<std::variant<bool>, std::true_type>::value, "");
38+
#endif
3739
static_assert(!std::is_constructible<std::variant<bool>, std::unique_ptr<char> >::value, "");
3840
static_assert(!std::is_constructible<std::variant<bool>, decltype(nullptr)>::value, "");
3941

libcxx/test/support/variant_test_helpers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@
2323

2424
// FIXME: Currently the variant<T&> tests are disabled using this macro.
2525
#define TEST_VARIANT_HAS_NO_REFERENCES
26+
27+
// TODO(LLVM-19): Remove TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
2628
#ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
2729
# define TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
2830
#endif
29-
3031
#ifdef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
3132
constexpr bool VariantAllowsNarrowingConversions = true;
3233
#else

0 commit comments

Comments
 (0)