diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst index c28a5b73f7ec6..f9e0bdee3176a 100644 --- a/libcxx/docs/ReleaseNotes/18.rst +++ b/libcxx/docs/ReleaseNotes/18.rst @@ -81,6 +81,12 @@ Deprecations and Removals - The non-conforming constructor ``std::future_error(std::error_code)`` has been removed. Please use the ``std::future_error(std::future_errc)`` constructor provided in C++17 instead. +- `P1957 ` has been implemented in Clang and libc++ removed a code path that led to + narrowing conversions in ``std::variant`` behaving in a non-standard way. This may change how some uses of + ``std::variant``'s constructor behave in user code. The ``_LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT`` + macro is provided to restore the previous behavior, and it will be supported in the LLVM 18 release only. + In LLVM 19 and beyond, ``_LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT`` will not be honored anymore. + Upcoming Deprecations and Removals ---------------------------------- diff --git a/libcxx/include/variant b/libcxx/include/variant index d89c0596b1db0..8f31de6da01ac 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1252,6 +1252,25 @@ struct __overload { auto operator()(_Tp, _Up&&) const -> __check_for_narrowing<_Tp, _Up>; }; +// TODO(LLVM-19): Remove all occurrences of this macro. +#ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT +template +struct __overload_bool { + template > + auto operator()(bool, _Up&&) const + -> enable_if_t, __type_identity<_Tp>>; +}; + +template +struct __overload : __overload_bool {}; +template +struct __overload : __overload_bool {}; +template +struct __overload : __overload_bool {}; +template +struct __overload : __overload_bool {}; +#endif + template struct __all_overloads : _Bases... { void operator()() const; diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp index c63626090c2fe..b3fc2021a6b22 100644 --- a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -146,8 +146,10 @@ void test_T_assignment_sfinae() { }; static_assert(!std::is_assignable::value, "no boolean conversion in operator="); +#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT static_assert(std::is_assignable::value, "converted to bool in operator="); +#endif } { struct X {}; @@ -297,11 +299,13 @@ void test_T_assignment_performs_assignment() { } void test_T_assignment_vector_bool() { +#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT std::vector vec = {true}; std::variant v; v = vec[0]; assert(v.index() == 0); assert(std::get<0>(v) == true); +#endif } int main(int, char**) { diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp index d93d429e262c0..246309c01b4d7 100644 --- a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp @@ -34,7 +34,9 @@ int main(int, char**) static_assert(!std::is_assignable, decltype("meow")>::value, ""); static_assert(!std::is_assignable, decltype("meow")>::value, ""); +#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT static_assert(std::is_assignable, std::true_type>::value, ""); +#endif static_assert(!std::is_assignable, std::unique_ptr >::value, ""); static_assert(!std::is_assignable, decltype(nullptr)>::value, ""); diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp index 04329f4f412b0..89fd646878eec 100644 --- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp @@ -80,8 +80,10 @@ void test_T_ctor_sfinae() { }; static_assert(!std::is_constructible::value, "no boolean conversion in constructor"); +#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT static_assert(std::is_constructible::value, "converted to bool in constructor"); +#endif } { struct X {}; @@ -200,10 +202,12 @@ void test_construction_with_repeated_types() { } void test_vector_bool() { +#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT std::vector vec = {true}; std::variant v = vec[0]; assert(v.index() == 0); assert(std::get<0>(v) == true); +#endif } int main(int, char**) { diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp index 7a4c68b5dacca..7fb44ff407653 100644 --- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp @@ -33,7 +33,9 @@ int main(int, char**) static_assert(!std::is_constructible, decltype("meow")>::value, ""); static_assert(!std::is_constructible, decltype("meow")>::value, ""); +#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT static_assert(std::is_constructible, std::true_type>::value, ""); +#endif static_assert(!std::is_constructible, std::unique_ptr >::value, ""); static_assert(!std::is_constructible, decltype(nullptr)>::value, ""); diff --git a/libcxx/test/support/variant_test_helpers.h b/libcxx/test/support/variant_test_helpers.h index 78b3978dde484..c174cba328401 100644 --- a/libcxx/test/support/variant_test_helpers.h +++ b/libcxx/test/support/variant_test_helpers.h @@ -23,10 +23,11 @@ // FIXME: Currently the variant tests are disabled using this macro. #define TEST_VARIANT_HAS_NO_REFERENCES + +// TODO(LLVM-19): Remove TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS #ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT # define TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS #endif - #ifdef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS constexpr bool VariantAllowsNarrowingConversions = true; #else