mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-18 03:42:44 +08:00
Revert "maybe_t: make maybe_t<T> trivially copyable if T is"
This reverts commit9d303a74e3
. This reverts commit0305c842e6
.9d303a7
broke 32-bit armhf builds for unknown reasons, specifically in settings where a trivial copy of `maybe_t<int>` was performed. A caller would pass a literal int in the place of a `maybe_t<int>` parameter and the callee would see a populated `maybe_t` but with a value of `0` rather than the actual value that was passed in. It was too painful to debug to a resolution under qemu.
This commit is contained in:
parent
8d7662335e
commit
1c92d4c5db
57
src/maybe.h
57
src/maybe.h
|
@ -7,11 +7,10 @@
|
|||
#include <utility>
|
||||
|
||||
namespace maybe_detail {
|
||||
// Template magic to make maybe_t<T> (trivially) copyable iff T is.
|
||||
|
||||
// This is an unsafe implementation: it is always trivially copyable.
|
||||
// Template magic to make maybe_t<T> copyable iff T is copyable.
|
||||
// maybe_impl_t is the "too aggressive" implementation: it is always copyable.
|
||||
template <typename T>
|
||||
struct maybe_impl_trivially_copyable_t {
|
||||
struct maybe_impl_t {
|
||||
alignas(T) char storage[sizeof(T)];
|
||||
bool filled = false;
|
||||
|
||||
|
@ -39,13 +38,11 @@ struct maybe_impl_trivially_copyable_t {
|
|||
return res;
|
||||
}
|
||||
|
||||
maybe_impl_trivially_copyable_t() = default;
|
||||
maybe_impl_t() = default;
|
||||
|
||||
// Move construction/assignment from a T.
|
||||
explicit maybe_impl_trivially_copyable_t(T &&v) : filled(true) {
|
||||
new (storage) T(std::forward<T>(v));
|
||||
}
|
||||
maybe_impl_trivially_copyable_t &operator=(T &&v) {
|
||||
explicit maybe_impl_t(T &&v) : filled(true) { new (storage) T(std::forward<T>(v)); }
|
||||
maybe_impl_t &operator=(T &&v) {
|
||||
if (filled) {
|
||||
value() = std::move(v);
|
||||
} else {
|
||||
|
@ -56,8 +53,8 @@ struct maybe_impl_trivially_copyable_t {
|
|||
}
|
||||
|
||||
// Copy construction/assignment from a T.
|
||||
explicit maybe_impl_trivially_copyable_t(const T &v) : filled(true) { new (storage) T(v); }
|
||||
maybe_impl_trivially_copyable_t &operator=(const T &v) {
|
||||
explicit maybe_impl_t(const T &v) : filled(true) { new (storage) T(v); }
|
||||
maybe_impl_t &operator=(const T &v) {
|
||||
if (filled) {
|
||||
value() = v;
|
||||
} else {
|
||||
|
@ -66,27 +63,15 @@ struct maybe_impl_trivially_copyable_t {
|
|||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// This is an unsafe implementation: it is always copyable.
|
||||
template <typename T>
|
||||
struct maybe_impl_not_trivially_copyable_t : public maybe_impl_trivially_copyable_t<T> {
|
||||
using base_t = maybe_impl_trivially_copyable_t<T>;
|
||||
using base_t::maybe_impl_trivially_copyable_t;
|
||||
using base_t::operator=;
|
||||
using base_t::filled;
|
||||
using base_t::reset;
|
||||
using base_t::storage;
|
||||
|
||||
// Move construction/assignment from another instance.
|
||||
maybe_impl_not_trivially_copyable_t(maybe_impl_not_trivially_copyable_t &&v) {
|
||||
filled = v.filled;
|
||||
// Move construction/assignment from a maybe_impl.
|
||||
maybe_impl_t(maybe_impl_t &&v) : filled(v.filled) {
|
||||
if (filled) {
|
||||
new (storage) T(std::move(v.value()));
|
||||
}
|
||||
}
|
||||
|
||||
maybe_impl_not_trivially_copyable_t &operator=(maybe_impl_not_trivially_copyable_t &&v) {
|
||||
maybe_impl_t &operator=(maybe_impl_t &&v) {
|
||||
if (!v.filled) {
|
||||
reset();
|
||||
} else {
|
||||
|
@ -95,15 +80,14 @@ struct maybe_impl_not_trivially_copyable_t : public maybe_impl_trivially_copyabl
|
|||
return *this;
|
||||
}
|
||||
|
||||
// Copy construction/assignment from another instance.
|
||||
maybe_impl_not_trivially_copyable_t(const maybe_impl_not_trivially_copyable_t &v) : base_t() {
|
||||
filled = v.filled;
|
||||
// Copy construction/assignment from a maybe_impl.
|
||||
maybe_impl_t(const maybe_impl_t &v) : filled(v.filled) {
|
||||
if (v.filled) {
|
||||
new (storage) T(v.value());
|
||||
}
|
||||
}
|
||||
|
||||
maybe_impl_not_trivially_copyable_t &operator=(const maybe_impl_not_trivially_copyable_t &v) {
|
||||
maybe_impl_t &operator=(const maybe_impl_t &v) {
|
||||
if (&v == this) return *this;
|
||||
if (!v.filled) {
|
||||
reset();
|
||||
|
@ -113,8 +97,7 @@ struct maybe_impl_not_trivially_copyable_t : public maybe_impl_trivially_copyabl
|
|||
return *this;
|
||||
}
|
||||
|
||||
maybe_impl_not_trivially_copyable_t() = default;
|
||||
~maybe_impl_not_trivially_copyable_t() { reset(); }
|
||||
~maybe_impl_t() { reset(); }
|
||||
};
|
||||
|
||||
struct copyable_t {};
|
||||
|
@ -147,15 +130,7 @@ inline constexpr none_t none() { return none_t::none; }
|
|||
// This is a value-type class that stores a value of T in aligned storage.
|
||||
template <typename T>
|
||||
class maybe_t : private maybe_detail::conditionally_copyable_t<T> {
|
||||
#if __GNUG__ && __GNUC__ < 5
|
||||
using maybe_impl_t = maybe_detail::maybe_impl_not_trivially_copyable_t<T>;
|
||||
#else
|
||||
using maybe_impl_t =
|
||||
typename std::conditional<std::is_trivially_copyable<T>::value,
|
||||
maybe_detail::maybe_impl_trivially_copyable_t<T>,
|
||||
maybe_detail::maybe_impl_not_trivially_copyable_t<T> >::type;
|
||||
#endif
|
||||
maybe_impl_t impl_;
|
||||
maybe_detail::maybe_impl_t<T> impl_;
|
||||
|
||||
public:
|
||||
// return whether the receiver contains a value.
|
||||
|
|
Loading…
Reference in New Issue
Block a user