From 6e0b562bf6e0e94e3ea6a755a9917b2725fd604d Mon Sep 17 00:00:00 2001 From: Serge Guelton Date: Mon, 18 Feb 2019 12:07:12 +0000 Subject: [NFC] Make Optional 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 --- llvm/include/llvm/ADT/Optional.h | 72 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'llvm/include') 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 class OptionalStorage { + 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 + explicit OptionalStorage(in_place_t, Args &&... args) + : value(std::forward(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 void emplace(Args &&... args) { + reset(); + ::new ((void *)std::addressof(value)) T(std::forward(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 class Optional { -- cgit v1.2.3