diff options
author | Serge Guelton <sguelton@redhat.com> | 2019-02-18 12:07:12 +0000 |
---|---|---|
committer | Serge Guelton <sguelton@redhat.com> | 2019-02-18 12:07:12 +0000 |
commit | 6e0b562bf6e0e94e3ea6a755a9917b2725fd604d (patch) | |
tree | 5c1a6690c80fbcd1c43ae9d9ebdc21191f762f04 /llvm/include | |
parent | 515e7cdec04a4f77defecbc9453e11159b635ddf (diff) | |
download | bcm5719-llvm-6e0b562bf6e0e94e3ea6a755a9917b2725fd604d.tar.gz bcm5719-llvm-6e0b562bf6e0e94e3ea6a755a9917b2725fd604d.zip |
[NFC] Make Optional<T> trivially copyable when T is trivially copyable
This is a follow-up to r354246 and a reimplementation of https://reviews.llvm.org/D57097?id=186600
that should not trigger any UB thanks to the use of an union.
This may still be subject to the problem solved by std::launder, but I'm unsure how it interacts whith union.
/me plans to revert if this triggers any relevant bot failure. At least this validates in Release mode with
clang 6.0.1 and gcc 4.8.5.
llvm-svn: 354264
Diffstat (limited to 'llvm/include')
-rw-r--r-- | llvm/include/llvm/ADT/Optional.h | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index f135bb8f36a..1eb84c735d2 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -139,6 +139,78 @@ public: } }; +template <typename T> class OptionalStorage<T, true> { + union { + char empty; + T value; + }; + bool hasVal = false; + +public: + ~OptionalStorage() = default; + + OptionalStorage() noexcept : empty{} {} + + OptionalStorage(OptionalStorage const &other) = default; + OptionalStorage(OptionalStorage &&other) = default; + + OptionalStorage &operator=(OptionalStorage const &other) = default; + OptionalStorage &operator=(OptionalStorage &&other) = default; + + template <class... Args> + explicit OptionalStorage(in_place_t, Args &&... args) + : value(std::forward<Args>(args)...), hasVal(true) {} + + void reset() noexcept { + if (hasVal) { + value.~T(); + hasVal = false; + } + } + + bool hasValue() const noexcept { return hasVal; } + + T &getValue() LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } + T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } +#if LLVM_HAS_RVALUE_REFERENCE_THIS + T &&getValue() && noexcept { + assert(hasVal); + return std::move(value); + } +#endif + + template <class... Args> void emplace(Args &&... args) { + reset(); + ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); + hasVal = true; + } + + OptionalStorage &operator=(T const &y) { + if (hasValue()) { + value = y; + } else { + ::new ((void *)std::addressof(value)) T(y); + hasVal = true; + } + return *this; + } + OptionalStorage &operator=(T &&y) { + if (hasValue()) { + value = std::move(y); + } else { + ::new ((void *)std::addressof(value)) T(std::move(y)); + hasVal = true; + } + return *this; + } +}; + } // namespace optional_detail template <typename T> class Optional { |