diff --git a/libcxx/docs/Cxx2bStatusPaperStatus.csv b/libcxx/docs/Cxx2bStatusPaperStatus.csv --- a/libcxx/docs/Cxx2bStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2bStatusPaperStatus.csv @@ -5,7 +5,7 @@ "`P1679R3 `__","LWG","string contains function","Autumn 2020","|Complete|","12.0" "","","","","","" "`P1682R3 `__","LWG","std::to_underlying for enumerations","February 2021","","" -"`P2162R2 `__","LWG","Inheriting from std::variant","February 2021","","" +"`P2162R2 `__","LWG","Inheriting from std::variant","February 2021","|Complete|","13.0" "`P2212R2 `__","LWG","Relax Requirements for time_point::clock","February 2021","","" "`P2259R1 `__","LWG","Repairing input range adaptors and counted_iterator","February 2021","","" "","","","","","" diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -301,5 +301,7 @@ ``__cpp_lib_stdatomic_h`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_string_contains`` ``202011L`` + ------------------------------------------------- ----------------- + ``__cpp_lib_variant`` ``202102L`` ================================================= ================= diff --git a/libcxx/include/variant b/libcxx/include/variant --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -318,6 +318,33 @@ template constexpr _IndexType __variant_npos = static_cast<_IndexType>(-1); +template +class _LIBCPP_TEMPLATE_VIS variant; + +template +inline _LIBCPP_INLINE_VISIBILITY constexpr variant<_Types...>& +__as_variant(variant<_Types...>& __vs) noexcept { + return __vs; +} + +template +inline _LIBCPP_INLINE_VISIBILITY constexpr const variant<_Types...>& +__as_variant(const variant<_Types...>& __vs) noexcept { + return __vs; +} + +template +inline _LIBCPP_INLINE_VISIBILITY constexpr const variant<_Types...>&& +__as_variant(const variant<_Types...>&& __vs) noexcept { + return _VSTD::move(__vs); +} + +template +inline _LIBCPP_INLINE_VISIBILITY constexpr variant<_Types...>&& +__as_variant(variant<_Types...>&& __vs) noexcept { + return _VSTD::move(__vs); +} + namespace __find_detail { template @@ -565,7 +592,7 @@ static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, _Vs&&... __vs) { return __base::__visit_alt(_VSTD::forward<_Visitor>(__visitor), - _VSTD::forward<_Vs>(__vs).__impl...); + _VSTD::__as_variant(_VSTD::forward<_Vs>(__vs)).__impl...); } template @@ -1635,11 +1662,18 @@ __lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } +template +inline _LIBCPP_INLINE_VISIBILITY +constexpr bool __valueless_by_exception(const variant<_Types...>& __vs) noexcept +{ + return __vs.valueless_by_exception(); +} + template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) { - const bool __valueless = (... || __vs.valueless_by_exception()); + const bool __valueless = (... || _VSTD::__valueless_by_exception(__vs)); if (__valueless) { __throw_bad_variant_access(); } diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -159,7 +159,8 @@ __cpp_lib_uncaught_exceptions 201411L __cpp_lib_unordered_map_try_emplace 201411L __cpp_lib_unwrap_ref 201811L -__cpp_lib_variant 201606L +__cpp_lib_variant 202102L + 201606L // C++17 __cpp_lib_void_t 201411L */ @@ -365,6 +366,8 @@ // # define __cpp_lib_stacktrace 202011L // # define __cpp_lib_stdatomic_h 202011L # define __cpp_lib_string_contains 202011L +# undef __cpp_lib_variant +# define __cpp_lib_variant 202102L #endif // clang-format on diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/variant.version.pass.cpp @@ -17,6 +17,7 @@ /* Constant Value __cpp_lib_variant 201606L [C++17] + 202102L [C++2b] */ #include @@ -57,8 +58,8 @@ # ifndef __cpp_lib_variant # error "__cpp_lib_variant should be defined in c++2b" # endif -# if __cpp_lib_variant != 201606L -# error "__cpp_lib_variant should have the value 201606L in c++2b" +# if __cpp_lib_variant != 202102L +# error "__cpp_lib_variant should have the value 202102L in c++2b" # endif #endif // TEST_STD_VER > 20 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -150,6 +150,7 @@ __cpp_lib_unordered_map_try_emplace 201411L [C++17] __cpp_lib_unwrap_ref 201811L [C++20] __cpp_lib_variant 201606L [C++17] + 202102L [C++2b] __cpp_lib_void_t 201411L [C++17] */ @@ -4527,8 +4528,8 @@ # ifndef __cpp_lib_variant # error "__cpp_lib_variant should be defined in c++2b" # endif -# if __cpp_lib_variant != 201606L -# error "__cpp_lib_variant should have the value 201606L in c++2b" +# if __cpp_lib_variant != 202102L +# error "__cpp_lib_variant should have the value 202102L in c++2b" # endif # ifndef __cpp_lib_void_t diff --git a/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp b/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp --- a/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp @@ -269,9 +269,42 @@ #endif } +template +void test_comparisons() { + using xEq = decltype(std::declval() == std::declval()); + using xNe = decltype(std::declval() != std::declval()); + using xLt = decltype(std::declval() < std::declval()); + using xGt = decltype(std::declval() > std::declval()); + using xLe = decltype(std::declval() <= std::declval()); + using xGe = decltype(std::declval() >= std::declval()); +} + +void test_derived_from_variant() { + struct EvilVariantBase { + int index; + char valueless_by_exception; + }; + + struct EvilVariant1 : std::variant, EvilVariantBase {}; + + assert(EvilVariant1{12} == EvilVariant1{12}); + assert(EvilVariant1{12} != EvilVariant1{12.3}); + test_comparisons(); + + struct EvilVariant2 : std::variant, std::type_info {}; + + test_comparisons(); + test_comparisons(); + test_comparisons(); + test_comparisons(); + test_comparisons(); + test_comparisons(); +} + int main(int, char**) { test_equality(); test_relational(); + test_derived_from_variant(); return 0; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -348,6 +348,40 @@ std::visit(Visitor{}, v); } +struct visitor_of_everything { + template + void operator()(T&&) {} +}; + +void test_derived_from_variant() { + struct EvilVariantBase { + int index; + char valueless_by_exception; + }; + + struct EvilVariant1 : std::variant, + std::tuple, + EvilVariantBase {}; + + std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); + + struct EvilVariant2 : std::variant, std::type_info {}; + + using xT = decltype( + std::visit(visitor_of_everything{}, std::declval())); + using xTref = decltype( + std::visit(visitor_of_everything{}, std::declval())); + using xTrefref = decltype( + std::visit(visitor_of_everything{}, std::declval())); + using xTconst = decltype( + std::visit(visitor_of_everything{}, std::declval())); + using xTconstref = decltype( + std::visit(visitor_of_everything{}, std::declval())); + using xTconstrefref = decltype(std::visit( + visitor_of_everything{}, std::declval())); +} + int main(int, char**) { test_call_operator_forwarding(); test_argument_forwarding(); @@ -355,6 +389,7 @@ test_constexpr(); test_exceptions(); test_caller_accepts_nonconst(); + test_derived_from_variant(); return 0; } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -628,7 +628,7 @@ "headers": ["functional"], }, { "name": "__cpp_lib_variant", - "values": { "c++17": 201606 }, + "values": { "c++17": 201606, "c++2b": 202102 }, "headers": ["variant"], }, { "name": "__cpp_lib_void_t",