@@ -137,10 +137,9 @@ struct relops_visitor;
137137template <class ... Ts>
138138struct rvariant_base
139139{
140- private :
140+ protected :
141141 static constexpr bool need_destructor_call = !std::conjunction_v<std::is_trivially_destructible<Ts>...>;
142142
143- protected:
144143 using storage_type = make_variadic_union_t <Ts...>;
145144 static constexpr bool never_valueless = storage_type::never_valueless;
146145
@@ -663,16 +662,48 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN
663662 constexpr std::size_t j = no_narrowing_resolution<T, Ts...>::index;
664663 static_assert (j != std::variant_npos);
665664
665+ // TC(noexcept) && MC(throw) => A maybe valueless if | never |
666+ // TC(noexcept) && MC(noexcept) => A maybe valueless if | never |
667+ // TC(throw) && MC(throw) => A maybe valueless if | TC throws => yes | MC throws => yes |
668+ // TC(throw) && MC(noexcept) => B maybe valueless if | never |
669+ if constexpr (!base_type::need_destructor_call) {
670+ // Nothing needs to be destroyed, so a comparison of the index replaces the visit
671+ if (this ->index_ == j) {
672+ detail::raw_get<j>(this ->storage_ ) = std::forward<T>(t);
673+
674+ } else if constexpr (std::is_nothrow_constructible_v<Tj, T> || !std::is_nothrow_move_constructible_v<Tj>) {
675+ #ifndef NDEBUG
676+ // Self-assign on non-valueless instance ALWAYS leads to UB.
677+ // For details, see the comments on `emplace`.
678+ assert (
679+ (this ->index_ == detail::variant_npos<sizeof ...(Ts)> || (
680+ static_cast <void const *>(std::addressof (t)) != static_cast <void const *>(this ) &&
681+ static_cast <void const *>(std::addressof (t)) != static_cast <void const *>(std::addressof (this ->storage_ ))
682+ )) &&
683+ " Self-assigning `variant` will lead to undefined behavior because the standard specifies `emplace` to destruct the contained object *before* emplacing the new value ([variant.mod])."
684+ );
685+ #endif
686+ static_assert (std::is_nothrow_constructible_v<Tj, T> || !base_type::never_valueless);
687+ if constexpr (!std::is_nothrow_constructible_v<Tj, T>) {
688+ this ->index_ = detail::variant_npos<sizeof ...(Ts)>;
689+ }
690+ detail::alternative_constructor<j>::construct (this ->storage_ , std::forward<T>(t));
691+ this ->index_ = j;
692+
693+ } else {
694+ Tj tmp (std::forward<T>(t));
695+ detail::alternative_constructor<j>::construct (this ->storage_ , std::move (tmp)); // B
696+ this ->index_ = j;
697+ }
698+ return *this ;
699+ }
700+
666701 this ->raw_visit ([this , &t]<std::size_t i, class Ti >(std::in_place_index_t <i>, [[maybe_unused]] Ti& ti)
667702 noexcept (detail::variant_nothrow_assignable<Tj, T>::value)
668703 {
669704 if constexpr (i == j) {
670705 ti = std::forward<T>(t);
671706 } else {
672- // TC(noexcept) && MC(throw) => A maybe valueless if | never |
673- // TC(noexcept) && MC(noexcept) => A maybe valueless if | never |
674- // TC(throw) && MC(throw) => A maybe valueless if | TC throws => yes | MC throws => yes |
675- // TC(throw) && MC(noexcept) => B maybe valueless if | never |
676707 if constexpr (std::is_nothrow_constructible_v<Tj, T> || !std::is_nothrow_move_constructible_v<Tj>) {
677708#ifndef NDEBUG
678709 // Self-assign on non-valueless instance ALWAYS leads to UB.
0 commit comments