diff --git a/stl/inc/variant b/stl/inc/variant index 7ebf3b6cf60..f27bddbc911 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -378,7 +378,11 @@ public: _Variant_storage<_Rest...> _Tail; }; - _CONSTEXPR20 ~_Variant_storage_() noexcept { + _CONSTEXPR20 ~_Variant_storage_() +#ifndef __clang__ // TRANSITION, LLVM-59854 + noexcept +#endif // ^^^ no workaround ^^^ + { // explicitly non-trivial destructor (which would otherwise be defined as deleted // since the class has a variant member with a non-trivial destructor) } diff --git a/tests/std/tests/P0088R3_variant_msvc/test.cpp b/tests/std/tests/P0088R3_variant_msvc/test.cpp index adcb2967aee..412d93d68e4 100644 --- a/tests/std/tests/P0088R3_variant_msvc/test.cpp +++ b/tests/std/tests/P0088R3_variant_msvc/test.cpp @@ -741,6 +741,89 @@ namespace msvc { } } // namespace gh2770 + namespace gh4901 { +#if _HAS_CXX20 +#define CONSTEXPR20 constexpr +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define CONSTEXPR20 inline +#endif // ^^^ !_HAS_CXX20 ^^^ + struct X { + CONSTEXPR20 ~X() {} + }; + + struct Y { + X _; + }; + + struct ZA { + std::variant z; + }; + + struct ZB { + std::variant z; + }; + +#if _HAS_CXX20 + static_assert(ZA{0}.z.index() == 1); + static_assert(ZA{Y{}}.z.index() == 0); + static_assert(ZB{0}.z.index() == 0); + static_assert(ZB{Y{}}.z.index() == 1); +#endif // _HAS_CXX20 + + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v); + + // Verify that variant::~variant is noexcept even when an alternative has a potentially-throwing destructor, + // per N4988 [res.on.exception.handling]/3. + struct X2 { + CONSTEXPR20 ~X2() noexcept(false) {} + }; + + struct Y2 { + X2 _; + }; + + struct ZA2 { + std::variant z; + }; + + struct ZB2 { + std::variant z; + }; + +#if _HAS_CXX20 + static_assert(ZA2{0}.z.index() == 1); + static_assert(ZA2{Y2{}}.z.index() == 0); + static_assert(ZB2{0}.z.index() == 0); + static_assert(ZB2{Y2{}}.z.index() == 1); +#endif // _HAS_CXX20 + + static_assert(!std::is_nothrow_destructible_v); + static_assert(!std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v); + static_assert(std::is_nothrow_destructible_v); + + struct ZC { + std::variant z; + }; + +#if _HAS_CXX20 + static_assert(ZC{Y{}}.z.index() == 0); + static_assert(ZC{0}.z.index() == 1); + static_assert(ZC{Y2{}}.z.index() == 2); +#endif // _HAS_CXX20 + + static_assert(std::is_nothrow_destructible_v>); + static_assert(std::is_nothrow_destructible_v); +#undef CONSTEXPR20 + } // namespace gh4901 + namespace assign_cv { template struct TypeIdentityImpl {