[llvm] r354264 - [NFC] Make Optional<T> trivially copyable when T is trivially copyable
Serge Guelton via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 18 04:07:13 PST 2019
Author: serge_sans_paille
Date: Mon Feb 18 04:07:12 2019
New Revision: 354264
URL: http://llvm.org/viewvc/llvm-project?rev=354264&view=rev
Log:
[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.
Modified:
llvm/trunk/include/llvm/ADT/Optional.h
llvm/trunk/unittests/ADT/OptionalTest.cpp
Modified: llvm/trunk/include/llvm/ADT/Optional.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Optional.h?rev=354264&r1=354263&r2=354264&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/Optional.h (original)
+++ llvm/trunk/include/llvm/ADT/Optional.h Mon Feb 18 04:07:12 2019
@@ -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 {
Modified: llvm/trunk/unittests/ADT/OptionalTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/OptionalTest.cpp?rev=354264&r1=354263&r2=354264&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/OptionalTest.cpp (original)
+++ llvm/trunk/unittests/ADT/OptionalTest.cpp Mon Feb 18 04:07:12 2019
@@ -14,8 +14,15 @@
#include <array>
+
using namespace llvm;
+static_assert(is_trivially_copyable<Optional<int>>::value,
+ "trivially copyable");
+
+static_assert(is_trivially_copyable<Optional<std::array<int, 3>>>::value,
+ "trivially copyable");
+
namespace {
struct NonDefaultConstructible {
@@ -45,6 +52,10 @@ unsigned NonDefaultConstructible::CopyCo
unsigned NonDefaultConstructible::Destructions = 0;
unsigned NonDefaultConstructible::CopyAssignments = 0;
+static_assert(
+ !is_trivially_copyable<Optional<NonDefaultConstructible>>::value,
+ "not trivially copyable");
+
// Test fixture
class OptionalTest : public testing::Test {
};
@@ -203,6 +214,10 @@ struct MultiArgConstructor {
};
unsigned MultiArgConstructor::Destructions = 0;
+static_assert(
+ !is_trivially_copyable<Optional<MultiArgConstructor>>::value,
+ "not trivially copyable");
+
TEST_F(OptionalTest, Emplace) {
MultiArgConstructor::ResetCounts();
Optional<MultiArgConstructor> A;
@@ -250,6 +265,9 @@ unsigned MoveOnly::MoveConstructions = 0
unsigned MoveOnly::Destructions = 0;
unsigned MoveOnly::MoveAssignments = 0;
+static_assert(!is_trivially_copyable<Optional<MoveOnly>>::value,
+ "not trivially copyable");
+
TEST_F(OptionalTest, MoveOnlyNull) {
MoveOnly::ResetCounts();
Optional<MoveOnly> O;
@@ -351,6 +369,9 @@ private:
unsigned Immovable::Constructions = 0;
unsigned Immovable::Destructions = 0;
+static_assert(!is_trivially_copyable<Optional<Immovable>>::value,
+ "not trivially copyable");
+
TEST_F(OptionalTest, ImmovableEmplace) {
Optional<Immovable> A;
Immovable::ResetCounts();
More information about the llvm-commits
mailing list