Merge pull request #42047 from rjmccall/extended-existential-type-metadata

Add type metadata for extended existential types
This commit is contained in:
John McCall
2022-03-27 23:03:05 -04:00
committed by GitHub
18 changed files with 2428 additions and 19 deletions

View File

@@ -70,6 +70,17 @@ struct ExternalUnionMembers {
// (private to the implementation)
using Info = ExternalUnionImpl::MembersHelper<Members...>;
enum : bool {
is_copy_constructible = Info::is_copy_constructible,
is_nothrow_copy_constructible = Info::is_nothrow_copy_constructible,
is_move_constructible = Info::is_move_constructible,
is_nothrow_move_constructible = Info::is_nothrow_move_constructible,
is_copy_assignable = Info::is_copy_assignable,
is_nothrow_copy_assignable = Info::is_nothrow_copy_assignable,
is_move_assignable = Info::is_move_assignable,
is_nothrow_move_assignable = Info::is_nothrow_move_assignable,
};
/// The type of indices into the union member type list.
enum Index : unsigned {};
@@ -429,7 +440,15 @@ namespace ExternalUnionImpl {
template <>
struct MembersHelper<> {
enum : bool {
is_trivially_copyable = true
is_trivially_copyable = true,
is_copy_constructible = true,
is_nothrow_copy_constructible = true,
is_move_constructible = true,
is_nothrow_move_constructible = true,
is_copy_assignable = true,
is_nothrow_copy_assignable = true,
is_move_assignable = true,
is_nothrow_move_assignable = true,
};
enum : size_t {
@@ -476,7 +495,32 @@ private:
public:
enum : bool {
is_trivially_copyable =
Member::is_trivially_copyable && Others::is_trivially_copyable
Member::is_trivially_copyable &&
Others::is_trivially_copyable,
is_copy_constructible =
Member::is_copy_constructible &&
Others::is_copy_constructible,
is_nothrow_copy_constructible =
Member::is_nothrow_copy_constructible &&
Others::is_nothrow_copy_constructible,
is_move_constructible =
Member::is_move_constructible &&
Others::is_move_constructible,
is_nothrow_move_constructible =
Member::is_nothrow_move_constructible &&
Others::is_nothrow_move_constructible,
is_copy_assignable =
Member::is_copy_assignable &&
Others::is_copy_assignable,
is_nothrow_copy_assignable =
Member::is_nothrow_copy_assignable &&
Others::is_nothrow_copy_assignable,
is_move_assignable =
Member::is_move_assignable &&
Others::is_move_assignable,
is_nothrow_move_assignable =
Member::is_nothrow_move_assignable &&
Others::is_nothrow_move_assignable,
};
enum : size_t {
@@ -536,7 +580,19 @@ public:
template <class T>
struct UnionMemberInfo {
enum : bool {
is_trivially_copyable = IsTriviallyCopyable<T>::value
is_trivially_copyable = IsTriviallyCopyable<T>::value,
is_copy_constructible = std::is_copy_constructible<T>::value,
is_nothrow_copy_constructible =
std::is_nothrow_copy_constructible<T>::value,
is_move_constructible = std::is_move_constructible<T>::value,
is_nothrow_move_constructible =
std::is_nothrow_move_constructible<T>::value,
is_copy_assignable = std::is_copy_assignable<T>::value,
is_nothrow_copy_assignable =
std::is_nothrow_copy_assignable<T>::value,
is_move_assignable = std::is_move_assignable<T>::value,
is_nothrow_move_assignable =
std::is_nothrow_move_assignable<T>::value,
};
enum : size_t {
@@ -575,7 +631,15 @@ struct UnionMemberInfo {
template <>
struct UnionMemberInfo<void> {
enum : bool {
is_trivially_copyable = true
is_trivially_copyable = true,
is_copy_constructible = true,
is_nothrow_copy_constructible = true,
is_move_constructible = true,
is_nothrow_move_constructible = true,
is_copy_assignable = true,
is_nothrow_copy_assignable = true,
is_move_assignable = true,
is_nothrow_move_assignable = true,
};
enum : size_t {

View File

@@ -769,6 +769,20 @@ erase_if(std::unordered_set<Key, Hash, KeyEqual, Alloc> &c, Pred pred) {
return startingSize - c.size();
}
/// Call \c vector.emplace_back with each of the other arguments
/// to this function, in order. Constructing an intermediate
/// \c std::initializer_list can be inefficient; more problematically,
/// types such as \c std::vector copy out of the \c initializer_list
/// instead of move.
template <class VectorType, class ValueType, class... ValueTypes>
void emplace_back_all(VectorType &vector, ValueType &&value,
ValueTypes &&...values) {
vector.emplace_back(std::forward<ValueType>(value));
emplace_back_all(vector, std::forward<ValueTypes>(values)...);
}
template <class VectorType>
void emplace_back_all(VectorType &vector) {}
} // end namespace swift
#endif // SWIFT_BASIC_INTERLEAVE_H

View File

@@ -163,26 +163,60 @@ public:
TaggedUnionImpl::Empty>::type = {})
: super(std::forward<T>(value)) {}
TaggedUnionBase(const TaggedUnionBase &other) : super(other.TheKind) {
// We want to either define or delete all the special members.
// C++ does not provide a direct way to conditionally delete a
// function. enable_if doesn't work, for several reasons: you can't
// make an enable_if condition depend only on a property of the
// enclosing class template (because all member function signatures
// must successfully instantiate as part of instantiating the class
// template; this is not covered by SFINAE), and you can't make the
// special member itself a template (because then it's not a special
// member anymore). static_assert within the member also doesn't work.
// But we *can* make template substitution decide whether something
// turns into a special member, then declare it both ways.
template <bool condition>
using self_if = typename std::conditional<condition,
TaggedUnionBase,
TaggedUnionImpl::Empty>::type;
TaggedUnionBase(const self_if<Members::is_copy_constructible> &other)
noexcept(Members::is_nothrow_copy_constructible)
: super(other.TheKind) {
Storage.copyConstruct(other.TheKind, other.Storage);
}
TaggedUnionBase(TaggedUnionBase &&other) : super(other.TheKind) {
TaggedUnionBase(const self_if<!Members::is_copy_constructible> &other)
= delete;
TaggedUnionBase(self_if<Members::is_move_constructible> &&other)
noexcept(Members::is_nothrow_move_constructible)
: super(other.TheKind) {
Storage.moveConstruct(other.TheKind, std::move(other.Storage));
}
TaggedUnionBase &operator=(const TaggedUnionBase &other) {
TaggedUnionBase(self_if<!Members::is_move_constructible> &&other)
= delete;
TaggedUnionBase &operator=(const self_if<Members::is_copy_assignable> &other)
noexcept(Members::is_nothrow_copy_assignable) {
Storage.copyAssign(TheKind, other.TheKind, other.Storage);
TheKind = other.TheKind;
return *this;
}
TaggedUnionBase &operator=(TaggedUnionBase &&other) {
TaggedUnionBase &operator=(const self_if<!Members::is_copy_assignable> &other)
= delete;
TaggedUnionBase &operator=(self_if<Members::is_move_assignable> &&other)
noexcept(Members::is_nothrow_move_assignable) {
Storage.moveAssign(TheKind, other.TheKind, std::move(other.Storage));
TheKind = other.TheKind;
return *this;
}
TaggedUnionBase &operator=(self_if<!Members::is_move_assignable> &&other)
= delete;
~TaggedUnionBase() {
Storage.destruct(TheKind);
}
@@ -250,10 +284,16 @@ public:
/// empty state and provides a default constructor as well as `empty()`
/// and `reset()` methods.
template <class... Members>
using TaggedUnion =
TaggedUnionBase<ExternalUnionImpl::OptimalKindTypeHelper<sizeof...(Members)>,
ExternalUnionMembers<Members...>>;
class TaggedUnion :
public TaggedUnionBase<ExternalUnionImpl::OptimalKindTypeHelper<sizeof...(Members)>,
ExternalUnionMembers<Members...>> {
using super =
TaggedUnionBase<ExternalUnionImpl::OptimalKindTypeHelper<sizeof...(Members)>,
ExternalUnionMembers<Members...>>;
public:
using super::super;
};
}
} // end namespace swift
#endif