diff options
author | Serge Guelton <sguelton@redhat.com> | 2019-02-14 19:17:00 +0000 |
---|---|---|
committer | Serge Guelton <sguelton@redhat.com> | 2019-02-14 19:17:00 +0000 |
commit | 4d0934c48f361367edf249f8982e59a90105fb40 (patch) | |
tree | 0e61708992610b3381076a57b7c2f3ae5ffb234c | |
parent | 257fcd9b17119455a02f965b95200a286435e942 (diff) | |
download | bcm5719-llvm-4d0934c48f361367edf249f8982e59a90105fb40.tar.gz bcm5719-llvm-4d0934c48f361367edf249f8982e59a90105fb40.zip |
Recommit Optional specialization for trivially copyable types
Unfortunately the original code gets misscompiled by GCC (at least 8.1),
this is a tentative workaround using std::memcpy instead of inplace new
for trivially copyable types. I'll revert if it breaks.
Original revision: https://reviews.llvm.org/D57097
llvm-svn: 354051
-rw-r--r-- | llvm/include/llvm/ADT/Optional.h | 43 | ||||
-rw-r--r-- | llvm/unittests/ADT/OptionalTest.cpp | 20 |
2 files changed, 63 insertions, 0 deletions
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index 25a3185064f..c628df9d711 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -21,6 +21,7 @@ #include "llvm/Support/type_traits.h" #include <algorithm> #include <cassert> +#include <cstring> #include <new> #include <utility> @@ -109,6 +110,48 @@ template <typename T, bool = is_trivially_copyable<T>::value> struct OptionalSto } }; +template <typename T> struct OptionalStorage<T, true> { + AlignedCharArrayUnion<T> storage; + bool hasVal = false; + + OptionalStorage() = default; + + OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); } + OptionalStorage(const OptionalStorage &O) = default; + OptionalStorage(T &&y) : hasVal(true) { + std::memcpy(storage.buffer, reinterpret_cast<char*>(&y), sizeof(T)); + } + + OptionalStorage(OptionalStorage &&O) = default; + + OptionalStorage &operator=(T &&y) { + hasVal = true; + std::memcpy(storage.buffer, reinterpret_cast<char*>(&y), sizeof(T)); + return *this; + } + OptionalStorage &operator=(OptionalStorage &&O) = default; + + OptionalStorage &operator=(const T &y) { + hasVal = true; + std::memcpy(storage.buffer, reinterpret_cast<char const*>(&y), sizeof(T)); + return *this; + } + OptionalStorage &operator=(const OptionalStorage &O) = default; + + ~OptionalStorage() = default; + + T *getPointer() { + assert(hasVal); + return reinterpret_cast<T *>(storage.buffer); + } + const T *getPointer() const { + assert(hasVal); + return reinterpret_cast<const T *>(storage.buffer); + } + + void reset() { hasVal = false; } +}; + } // namespace optional_detail template <typename T> class Optional { diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp index 98adaccca96..c39b6727cd5 100644 --- a/llvm/unittests/ADT/OptionalTest.cpp +++ b/llvm/unittests/ADT/OptionalTest.cpp @@ -18,6 +18,12 @@ using namespace llvm; namespace { +static_assert(llvm::is_trivially_copyable<Optional<int>>::value, + "trivially copyable"); + +static_assert(llvm::is_trivially_copyable<Optional<std::array<int, 3>>>::value, + "trivially copyable"); + struct NonDefaultConstructible { static unsigned CopyConstructions; static unsigned Destructions; @@ -45,6 +51,10 @@ unsigned NonDefaultConstructible::CopyConstructions = 0; unsigned NonDefaultConstructible::Destructions = 0; unsigned NonDefaultConstructible::CopyAssignments = 0; +static_assert( + !llvm::is_trivially_copyable<Optional<NonDefaultConstructible>>::value, + "not trivially copyable"); + // Test fixture class OptionalTest : public testing::Test { }; @@ -203,6 +213,10 @@ struct MultiArgConstructor { }; unsigned MultiArgConstructor::Destructions = 0; +static_assert( + !llvm::is_trivially_copyable<Optional<MultiArgConstructor>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, Emplace) { MultiArgConstructor::ResetCounts(); Optional<MultiArgConstructor> A; @@ -250,6 +264,9 @@ unsigned MoveOnly::MoveConstructions = 0; unsigned MoveOnly::Destructions = 0; unsigned MoveOnly::MoveAssignments = 0; +static_assert(!llvm::is_trivially_copyable<Optional<MoveOnly>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, MoveOnlyNull) { MoveOnly::ResetCounts(); Optional<MoveOnly> O; @@ -351,6 +368,9 @@ private: unsigned Immovable::Constructions = 0; unsigned Immovable::Destructions = 0; +static_assert(!llvm::is_trivially_copyable<Optional<Immovable>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, ImmovableEmplace) { Optional<Immovable> A; Immovable::ResetCounts(); |