diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -43,21 +43,21 @@ public: ~OptionalStorage() { reset(); } - OptionalStorage() noexcept : empty(), hasVal(false) {} + constexpr OptionalStorage() noexcept : empty(), hasVal(false) {} - OptionalStorage(OptionalStorage const &other) : OptionalStorage() { + constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() { if (other.hasValue()) { emplace(other.value); } } - OptionalStorage(OptionalStorage &&other) : OptionalStorage() { + constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() { if (other.hasValue()) { emplace(std::move(other.value)); } } template - explicit OptionalStorage(in_place_t, Args &&... args) + constexpr explicit OptionalStorage(in_place_t, Args &&... args) : value(std::forward(args)...), hasVal(true) {} void reset() noexcept { @@ -67,13 +67,13 @@ } } - bool hasValue() const noexcept { return hasVal; } + constexpr bool hasValue() const noexcept { return hasVal; } T &getValue() LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } - T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { + constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } @@ -148,16 +148,16 @@ public: ~OptionalStorage() = default; - OptionalStorage() noexcept : empty{} {} + constexpr OptionalStorage() noexcept : empty{} {} - OptionalStorage(OptionalStorage const &other) = default; - OptionalStorage(OptionalStorage &&other) = default; + constexpr OptionalStorage(OptionalStorage const &other) = default; + constexpr OptionalStorage(OptionalStorage &&other) = default; OptionalStorage &operator=(OptionalStorage const &other) = default; OptionalStorage &operator=(OptionalStorage &&other) = default; template - explicit OptionalStorage(in_place_t, Args &&... args) + constexpr explicit OptionalStorage(in_place_t, Args &&... args) : value(std::forward(args)...), hasVal(true) {} void reset() noexcept { @@ -167,13 +167,13 @@ } } - bool hasValue() const noexcept { return hasVal; } + constexpr bool hasValue() const noexcept { return hasVal; } T &getValue() LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } - T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { + constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } @@ -221,11 +221,12 @@ constexpr Optional() {} constexpr Optional(NoneType) {} - Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {} - Optional(const Optional &O) = default; + constexpr Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {} + constexpr Optional(const Optional &O) = default; - Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {} - Optional(Optional &&O) = default; + constexpr Optional(T &&y) + : Storage(optional_detail::in_place_t{}, std::move(y)) {} + constexpr Optional(Optional &&O) = default; Optional &operator=(T &&y) { Storage = std::move(y); @@ -238,7 +239,7 @@ Storage.emplace(std::forward(Args)...); } - static inline Optional create(const T *y) { + static constexpr Optional create(const T *y) { return y ? Optional(*y) : Optional(); } @@ -250,16 +251,20 @@ void reset() { Storage.reset(); } - const T *getPointer() const { return &Storage.getValue(); } + constexpr const T *getPointer() const { return &Storage.getValue(); } T *getPointer() { return &Storage.getValue(); } - const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); } + constexpr const T &getValue() const LLVM_LVALUE_FUNCTION { + return Storage.getValue(); + } T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } - explicit operator bool() const { return hasValue(); } - bool hasValue() const { return Storage.hasValue(); } - const T *operator->() const { return getPointer(); } + constexpr explicit operator bool() const { return hasValue(); } + constexpr bool hasValue() const { return Storage.hasValue(); } + constexpr const T *operator->() const { return getPointer(); } T *operator->() { return getPointer(); } - const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); } + constexpr const T &operator*() const LLVM_LVALUE_FUNCTION { + return getValue(); + } T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); } template @@ -295,136 +300,152 @@ }; template -bool operator==(const Optional &X, const Optional &Y) { +constexpr bool operator==(const Optional &X, const Optional &Y) { if (X && Y) return *X == *Y; return X.hasValue() == Y.hasValue(); } template -bool operator!=(const Optional &X, const Optional &Y) { +constexpr bool operator!=(const Optional &X, const Optional &Y) { return !(X == Y); } template -bool operator<(const Optional &X, const Optional &Y) { +constexpr bool operator<(const Optional &X, const Optional &Y) { if (X && Y) return *X < *Y; return X.hasValue() < Y.hasValue(); } template -bool operator<=(const Optional &X, const Optional &Y) { +constexpr bool operator<=(const Optional &X, const Optional &Y) { return !(Y < X); } template -bool operator>(const Optional &X, const Optional &Y) { +constexpr bool operator>(const Optional &X, const Optional &Y) { return Y < X; } template -bool operator>=(const Optional &X, const Optional &Y) { +constexpr bool operator>=(const Optional &X, const Optional &Y) { return !(X < Y); } -template -bool operator==(const Optional &X, NoneType) { +template +constexpr bool operator==(const Optional &X, NoneType) { return !X; } -template -bool operator==(NoneType, const Optional &X) { +template +constexpr bool operator==(NoneType, const Optional &X) { return X == None; } -template -bool operator!=(const Optional &X, NoneType) { +template +constexpr bool operator!=(const Optional &X, NoneType) { return !(X == None); } -template -bool operator!=(NoneType, const Optional &X) { +template +constexpr bool operator!=(NoneType, const Optional &X) { return X != None; } -template bool operator<(const Optional &X, NoneType) { +template constexpr bool operator<(const Optional &X, NoneType) { return false; } -template bool operator<(NoneType, const Optional &X) { +template constexpr bool operator<(NoneType, const Optional &X) { return X.hasValue(); } -template bool operator<=(const Optional &X, NoneType) { +template +constexpr bool operator<=(const Optional &X, NoneType) { return !(None < X); } -template bool operator<=(NoneType, const Optional &X) { +template +constexpr bool operator<=(NoneType, const Optional &X) { return !(X < None); } -template bool operator>(const Optional &X, NoneType) { +template constexpr bool operator>(const Optional &X, NoneType) { return None < X; } -template bool operator>(NoneType, const Optional &X) { +template constexpr bool operator>(NoneType, const Optional &X) { return X < None; } -template bool operator>=(const Optional &X, NoneType) { +template +constexpr bool operator>=(const Optional &X, NoneType) { return None <= X; } -template bool operator>=(NoneType, const Optional &X) { +template +constexpr bool operator>=(NoneType, const Optional &X) { return X <= None; } -template bool operator==(const Optional &X, const T &Y) { +template +constexpr bool operator==(const Optional &X, const T &Y) { return X && *X == Y; } -template bool operator==(const T &X, const Optional &Y) { +template +constexpr bool operator==(const T &X, const Optional &Y) { return Y && X == *Y; } -template bool operator!=(const Optional &X, const T &Y) { +template +constexpr bool operator!=(const Optional &X, const T &Y) { return !(X == Y); } -template bool operator!=(const T &X, const Optional &Y) { +template +constexpr bool operator!=(const T &X, const Optional &Y) { return !(X == Y); } -template bool operator<(const Optional &X, const T &Y) { +template +constexpr bool operator<(const Optional &X, const T &Y) { return !X || *X < Y; } -template bool operator<(const T &X, const Optional &Y) { +template +constexpr bool operator<(const T &X, const Optional &Y) { return Y && X < *Y; } -template bool operator<=(const Optional &X, const T &Y) { +template +constexpr bool operator<=(const Optional &X, const T &Y) { return !(Y < X); } -template bool operator<=(const T &X, const Optional &Y) { +template +constexpr bool operator<=(const T &X, const Optional &Y) { return !(Y < X); } -template bool operator>(const Optional &X, const T &Y) { +template +constexpr bool operator>(const Optional &X, const T &Y) { return Y < X; } -template bool operator>(const T &X, const Optional &Y) { +template +constexpr bool operator>(const T &X, const Optional &Y) { return Y < X; } -template bool operator>=(const Optional &X, const T &Y) { +template +constexpr bool operator>=(const Optional &X, const T &Y) { return !(X < Y); } -template bool operator>=(const T &X, const Optional &Y) { +template +constexpr bool operator>=(const T &X, const Optional &Y) { return !(X < Y); } diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp --- a/llvm/unittests/ADT/OptionalTest.cpp +++ b/llvm/unittests/ADT/OptionalTest.cpp @@ -23,6 +23,19 @@ static_assert(is_trivially_copyable>>::value, "trivially copyable"); +void OptionalWorksInConstexpr() { + constexpr auto x1 = Optional(); + constexpr Optional x2{}; + static_assert(!x1.hasValue() && !x2.hasValue(), + "Default construction and hasValue() are contexpr"); + constexpr auto y1 = Optional(3); + constexpr Optional y2{3}; + static_assert(y1.getValue() == y2.getValue() && y1.getValue() == 3, + "Construction with value and getValue() are constexpr"); + static_assert(Optional{3} >= 2 && Optional{1} < Optional{2}, + "Comparisons work in constexpr"); +} + namespace { struct NonDefaultConstructible {