Short-circuit some `variant` constraints (#4966)

This commit is contained in:
Casey Carter 2024-09-28 12:45:12 -07:00 коммит произвёл GitHub
Родитель 1e312b38db
Коммит f8f9f7aff1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 41 добавлений и 10 удалений

Просмотреть файл

@ -934,12 +934,13 @@ public:
: _Mybase(in_place_index<0>) {} // value-initialize alternative 0
template <class _Ty,
enable_if_t<sizeof...(_Types) != 0 //
&& !is_same_v<_Remove_cvref_t<_Ty>, variant> //
&& !_Is_specialization_v<_Remove_cvref_t<_Ty>, in_place_type_t> //
&& !_Is_in_place_index_specialization<_Remove_cvref_t<_Ty>> //
&& is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>, //
int> = 0>
enable_if_t<sizeof...(_Types) != 0 && !is_same_v<_Remove_cvref_t<_Ty>, variant>
&& !_Is_specialization_v<_Remove_cvref_t<_Ty>, in_place_type_t>
&& !_Is_in_place_index_specialization<_Remove_cvref_t<_Ty>>,
int> = 0,
// These enable_if_t constraints are distinct to enable short-circuiting and avoid
// substitution into _Variant_init_type when the first constraint is not satisfied.
enable_if_t<is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>, int> = 0>
constexpr variant(_Ty&& _Obj) noexcept(is_nothrow_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>)
: _Mybase(in_place_index<_Variant_init_index<_Ty, _Types...>::value>, static_cast<_Ty&&>(_Obj)) {
// initialize to the type selected by passing _Obj to the overload set f(Types)...
@ -976,10 +977,12 @@ public:
// initialize alternative _Idx from _Ilist and _Args...
}
template <class _Ty, enable_if_t<!is_same_v<_Remove_cvref_t<_Ty>, variant>
&& is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>
&& is_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>,
int> = 0>
template <class _Ty, enable_if_t<!is_same_v<_Remove_cvref_t<_Ty>, variant>, int> = 0,
// These enable_if_t constraints are distinct to enable short-circuiting and avoid
// substitution into _Variant_init_type when the first constraint is not satisfied.
enable_if_t<is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>
&& is_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>,
int> = 0>
_CONSTEXPR20 variant& operator=(_Ty&& _Obj)
noexcept(is_nothrow_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>
&& is_nothrow_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>) {

Просмотреть файл

@ -11,6 +11,7 @@
#include <functional>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <utility>
@ -909,6 +910,33 @@ namespace msvc {
}
}
} // namespace assign_cv
namespace gh4959 {
// Test GH-4959 "P0608R3 breaks flang build with Clang"
// Constraints on variant's converting constructor and assignment operator templates reject arguments of the
// variant's type, but did not short-circuit to avoid evaluating the constructibility constraint. For this
// program, the constructibility constraint is ill-formed outside the immediate context when determining if
// variant<optional<GenericSpec>> can be initialized from an rvalue of the same type.
template <typename... RvRef>
using NoLvalue = std::enable_if_t<(... && !std::is_lvalue_reference_v<RvRef>)>;
struct Name {};
struct GenericSpec {
template <typename A, typename = NoLvalue<A>>
GenericSpec(A&& x) : u(std::move(x)) {}
GenericSpec(GenericSpec&&) = default;
std::variant<Name> u;
};
struct InterfaceStmt {
template <typename A, typename = NoLvalue<A>>
InterfaceStmt(A&& x) : u(std::move(x)) {}
InterfaceStmt(InterfaceStmt&&) = default;
std::variant<std::optional<GenericSpec>> u;
};
} // namespace gh4959
} // namespace msvc
int main() {