Skip to content

Commit 75d3e6c

Browse files
<variant>: Workaround for LLVM-59854 in the case of destructor of variant (#4903)
Co-authored-by: Casey Carter <[email protected]>
1 parent c2ab040 commit 75d3e6c

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

stl/inc/variant

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,11 @@ public:
378378
_Variant_storage<_Rest...> _Tail;
379379
};
380380

381-
_CONSTEXPR20 ~_Variant_storage_() noexcept {
381+
_CONSTEXPR20 ~_Variant_storage_()
382+
#ifndef __clang__ // TRANSITION, LLVM-59854
383+
noexcept
384+
#endif // ^^^ no workaround ^^^
385+
{
382386
// explicitly non-trivial destructor (which would otherwise be defined as deleted
383387
// since the class has a variant member with a non-trivial destructor)
384388
}

tests/std/tests/P0088R3_variant_msvc/test.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,89 @@ namespace msvc {
741741
}
742742
} // namespace gh2770
743743

744+
namespace gh4901 {
745+
#if _HAS_CXX20
746+
#define CONSTEXPR20 constexpr
747+
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
748+
#define CONSTEXPR20 inline
749+
#endif // ^^^ !_HAS_CXX20 ^^^
750+
struct X {
751+
CONSTEXPR20 ~X() {}
752+
};
753+
754+
struct Y {
755+
X _;
756+
};
757+
758+
struct ZA {
759+
std::variant<Y, int> z;
760+
};
761+
762+
struct ZB {
763+
std::variant<int, Y> z;
764+
};
765+
766+
#if _HAS_CXX20
767+
static_assert(ZA{0}.z.index() == 1);
768+
static_assert(ZA{Y{}}.z.index() == 0);
769+
static_assert(ZB{0}.z.index() == 0);
770+
static_assert(ZB{Y{}}.z.index() == 1);
771+
#endif // _HAS_CXX20
772+
773+
static_assert(std::is_nothrow_destructible_v<X>);
774+
static_assert(std::is_nothrow_destructible_v<Y>);
775+
static_assert(std::is_nothrow_destructible_v<std::variant<Y, int>>);
776+
static_assert(std::is_nothrow_destructible_v<std::variant<int, Y>>);
777+
static_assert(std::is_nothrow_destructible_v<ZA>);
778+
static_assert(std::is_nothrow_destructible_v<ZB>);
779+
780+
// Verify that variant::~variant is noexcept even when an alternative has a potentially-throwing destructor,
781+
// per N4988 [res.on.exception.handling]/3.
782+
struct X2 {
783+
CONSTEXPR20 ~X2() noexcept(false) {}
784+
};
785+
786+
struct Y2 {
787+
X2 _;
788+
};
789+
790+
struct ZA2 {
791+
std::variant<Y2, int> z;
792+
};
793+
794+
struct ZB2 {
795+
std::variant<int, Y2> z;
796+
};
797+
798+
#if _HAS_CXX20
799+
static_assert(ZA2{0}.z.index() == 1);
800+
static_assert(ZA2{Y2{}}.z.index() == 0);
801+
static_assert(ZB2{0}.z.index() == 0);
802+
static_assert(ZB2{Y2{}}.z.index() == 1);
803+
#endif // _HAS_CXX20
804+
805+
static_assert(!std::is_nothrow_destructible_v<X2>);
806+
static_assert(!std::is_nothrow_destructible_v<Y2>);
807+
static_assert(std::is_nothrow_destructible_v<std::variant<Y2, int>>);
808+
static_assert(std::is_nothrow_destructible_v<std::variant<int, Y2>>);
809+
static_assert(std::is_nothrow_destructible_v<ZA2>);
810+
static_assert(std::is_nothrow_destructible_v<ZB2>);
811+
812+
struct ZC {
813+
std::variant<Y, int, Y2> z;
814+
};
815+
816+
#if _HAS_CXX20
817+
static_assert(ZC{Y{}}.z.index() == 0);
818+
static_assert(ZC{0}.z.index() == 1);
819+
static_assert(ZC{Y2{}}.z.index() == 2);
820+
#endif // _HAS_CXX20
821+
822+
static_assert(std::is_nothrow_destructible_v<std::variant<Y, int, Y2>>);
823+
static_assert(std::is_nothrow_destructible_v<ZC>);
824+
#undef CONSTEXPR20
825+
} // namespace gh4901
826+
744827
namespace assign_cv {
745828
template <class T>
746829
struct TypeIdentityImpl {

0 commit comments

Comments
 (0)