Author: Benjamin Kramer Date: 2022-12-20T01:01:46+01:00 New Revision: 2916b99182752b1aece8cc4479d8d6a20b5e02da
URL: https://github.com/llvm/llvm-project/commit/2916b99182752b1aece8cc4479d8d6a20b5e02da DIFF: https://github.com/llvm/llvm-project/commit/2916b99182752b1aece8cc4479d8d6a20b5e02da.diff LOG: [ADT] Alias llvm::Optional to std::optional This avoids the continuous API churn when upgrading things to use std::optional and makes trivial string replace upgrades possible. I tested this with GCC 7.5, the oldest supported GCC I had around. Differential Revision: https://reviews.llvm.org/D140332 Added: Modified: clang/include/clang/Basic/LLVM.h clang/lib/StaticAnalyzer/Core/ExprEngine.cpp flang/include/flang/Lower/Runtime.h lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp lldb/source/Symbol/Type.cpp llvm/include/llvm/ADT/Optional.h llvm/include/llvm/ADT/STLForwardCompat.h llvm/include/llvm/Support/raw_ostream.h llvm/include/llvm/Testing/Support/SupportHelpers.h llvm/lib/CodeGen/RegAllocGreedy.h llvm/unittests/ADT/CMakeLists.txt llvm/unittests/Support/TypeTraitsTest.cpp mlir/include/mlir/Bindings/Python/PybindAdaptors.h mlir/include/mlir/Support/LLVM.h mlir/lib/Bindings/Python/PybindUtils.h mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp Removed: llvm/unittests/ADT/OptionalTest.cpp ################################################################################ diff --git a/clang/include/clang/Basic/LLVM.h b/clang/include/clang/Basic/LLVM.h index 5d4d72630970b..7ffc4c403473b 100644 --- a/clang/include/clang/Basic/LLVM.h +++ b/clang/include/clang/Basic/LLVM.h @@ -37,7 +37,7 @@ namespace llvm { template<unsigned InternalLen> class SmallString; template<typename T, unsigned N> class SmallVector; template<typename T> class SmallVectorImpl; - template <typename T> class Optional; + template <typename T> using Optional = std::optional<T>; template <class T> class Expected; template<typename T> diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 7ced94a7dc371..f9e76d85efdde 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -481,7 +481,7 @@ Optional<unsigned> ExprEngine::getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E, const LocationContext *LCtx) { const unsigned *V = State->get<PendingInitLoop>({E, LCtx->getStackFrame()}); - return V ? Optional(*V) : std::nullopt; + return V ? std::make_optional(*V) : std::nullopt; } ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State, @@ -510,7 +510,7 @@ ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State, const LocationContext *LCtx) { const unsigned *V = State->get<IndexOfElementToConstruct>({E, LCtx->getStackFrame()}); - return V ? Optional(*V) : std::nullopt; + return V ? std::make_optional(*V) : std::nullopt; } ProgramStateRef @@ -530,7 +530,7 @@ ExprEngine::getPendingArrayDestruction(ProgramStateRef State, const unsigned *V = State->get<PendingArrayDestruction>(LCtx->getStackFrame()); - return V ? Optional(*V) : std::nullopt; + return V ? std::make_optional(*V) : std::nullopt; } ProgramStateRef ExprEngine::setPendingArrayDestruction( @@ -600,7 +600,7 @@ ExprEngine::getObjectUnderConstruction(ProgramStateRef State, const LocationContext *LC) { ConstructedObjectKey Key(Item, LC->getStackFrame()); const SVal *V = State->get<ObjectsUnderConstruction>(Key); - return V ? Optional(*V) : std::nullopt; + return V ? std::make_optional(*V) : std::nullopt; } ProgramStateRef diff --git a/flang/include/flang/Lower/Runtime.h b/flang/include/flang/Lower/Runtime.h index 64e9a16fd7988..da01d1a87cccd 100644 --- a/flang/include/flang/Lower/Runtime.h +++ b/flang/include/flang/Lower/Runtime.h @@ -16,9 +16,10 @@ #ifndef FORTRAN_LOWER_RUNTIME_H #define FORTRAN_LOWER_RUNTIME_H +#include <optional> + namespace llvm { -template <typename T> -class Optional; +template <typename T> using Optional = std::optional<T>; } namespace mlir { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index 4efb5a2029e85..32960c2102eda 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -190,7 +190,7 @@ static FormSize g_form_sizes[] = { llvm::Optional<uint8_t> DWARFFormValue::GetFixedSize(dw_form_t form, const DWARFUnit *u) { if (form <= DW_FORM_ref_sig8 && g_form_sizes[form].valid) - return g_form_sizes[form].size; + return static_cast<uint8_t>(g_form_sizes[form].size); if (form == DW_FORM_addr && u) return u->GetAddressByteSize(); return std::nullopt; diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index da9eeadc0ecd2..048e37fb1db2f 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -343,7 +343,7 @@ Type *Type::GetEncodingType() { llvm::Optional<uint64_t> Type::GetByteSize(ExecutionContextScope *exe_scope) { if (m_byte_size_has_value) - return m_byte_size; + return static_cast<uint64_t>(m_byte_size); switch (m_encoding_uid_type) { case eEncodingInvalid: @@ -360,14 +360,14 @@ llvm::Optional<uint64_t> Type::GetByteSize(ExecutionContextScope *exe_scope) { if (llvm::Optional<uint64_t> size = encoding_type->GetByteSize(exe_scope)) { m_byte_size = *size; m_byte_size_has_value = true; - return m_byte_size; + return static_cast<uint64_t>(m_byte_size); } if (llvm::Optional<uint64_t> size = GetLayoutCompilerType().GetByteSize(exe_scope)) { m_byte_size = *size; m_byte_size_has_value = true; - return m_byte_size; + return static_cast<uint64_t>(m_byte_size); } } break; @@ -378,7 +378,7 @@ llvm::Optional<uint64_t> Type::GetByteSize(ExecutionContextScope *exe_scope) { if (ArchSpec arch = m_symbol_file->GetObjectFile()->GetArchitecture()) { m_byte_size = arch.GetAddressByteSize(); m_byte_size_has_value = true; - return m_byte_size; + return static_cast<uint64_t>(m_byte_size); } } break; } diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index a458ccf61c717..c3382837c0aea 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -16,446 +16,12 @@ #ifndef LLVM_ADT_OPTIONAL_H #define LLVM_ADT_OPTIONAL_H -#include "llvm/ADT/Hashing.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/type_traits.h" -#include <cassert> -#include <new> -#include <utility> +#include <optional> namespace llvm { - -namespace optional_detail { - -/// Storage for any type. -// -// The specialization condition intentionally uses -// llvm::is_trivially_{copy/move}_constructible instead of -// std::is_trivially_{copy/move}_constructible. GCC versions prior to 7.4 may -// instantiate the copy/move constructor of `T` when -// std::is_trivially_{copy/move}_constructible is instantiated. This causes -// compilation to fail if we query the trivially copy/move constructible -// property of a class which is not copy/move constructible. -// -// The current implementation of OptionalStorage insists that in order to use -// the trivial specialization, the value_type must be trivially copy -// constructible and trivially copy assignable due to =default implementations -// of the copy/move constructor/assignment. It does not follow that this is -// necessarily the case std::is_trivially_copyable is true (hence the expanded -// specialization condition). -// -// The move constructible / assignable conditions emulate the remaining behavior -// of std::is_trivially_copyable. -template <typename T, - bool = (llvm::is_trivially_copy_constructible<T>::value && - std::is_trivially_copy_assignable<T>::value && - (llvm::is_trivially_move_constructible<T>::value || - !std::is_move_constructible<T>::value) && - (std::is_trivially_move_assignable<T>::value || - !std::is_move_assignable<T>::value))> -class OptionalStorage { - union { - char empty; - T val; - }; - bool hasVal = false; - -public: - ~OptionalStorage() { reset(); } - - constexpr OptionalStorage() noexcept : empty() {} - - constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() { - if (other.has_value()) { - emplace(other.val); - } - } - constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() { - if (other.has_value()) { - emplace(std::move(other.val)); - } - } - - template <class... Args> - constexpr explicit OptionalStorage(std::in_place_t, Args &&...args) - : val(std::forward<Args>(args)...), hasVal(true) {} - - void reset() noexcept { - if (hasVal) { - val.~T(); - hasVal = false; - } - } - - constexpr bool has_value() const noexcept { return hasVal; } - - T &value() &noexcept { - assert(hasVal); - return val; - } - constexpr T const &value() const &noexcept { - assert(hasVal); - return val; - } - T &&value() &&noexcept { - assert(hasVal); - return std::move(val); - } - - template <class... Args> void emplace(Args &&...args) { - reset(); - ::new ((void *)std::addressof(val)) T(std::forward<Args>(args)...); - hasVal = true; - } - - OptionalStorage &operator=(T const &y) { - if (has_value()) { - val = y; - } else { - ::new ((void *)std::addressof(val)) T(y); - hasVal = true; - } - return *this; - } - OptionalStorage &operator=(T &&y) { - if (has_value()) { - val = std::move(y); - } else { - ::new ((void *)std::addressof(val)) T(std::move(y)); - hasVal = true; - } - return *this; - } - - OptionalStorage &operator=(OptionalStorage const &other) { - if (other.has_value()) { - if (has_value()) { - val = other.val; - } else { - ::new ((void *)std::addressof(val)) T(other.val); - hasVal = true; - } - } else { - reset(); - } - return *this; - } - - OptionalStorage &operator=(OptionalStorage &&other) { - if (other.has_value()) { - if (has_value()) { - val = std::move(other.val); - } else { - ::new ((void *)std::addressof(val)) T(std::move(other.val)); - hasVal = true; - } - } else { - reset(); - } - return *this; - } -}; - -template <typename T> class OptionalStorage<T, true> { - union { - char empty; - T val; - }; - bool hasVal = false; - -public: - ~OptionalStorage() = default; - - constexpr OptionalStorage() noexcept : empty{} {} - - constexpr OptionalStorage(OptionalStorage const &other) = default; - constexpr OptionalStorage(OptionalStorage &&other) = default; - - OptionalStorage &operator=(OptionalStorage const &other) = default; - OptionalStorage &operator=(OptionalStorage &&other) = default; - - template <class... Args> - constexpr explicit OptionalStorage(std::in_place_t, Args &&...args) - : val(std::forward<Args>(args)...), hasVal(true) {} - - void reset() noexcept { - if (hasVal) { - val.~T(); - hasVal = false; - } - } - - constexpr bool has_value() const noexcept { return hasVal; } - - T &value() &noexcept { - assert(hasVal); - return val; - } - constexpr T const &value() const &noexcept { - assert(hasVal); - return val; - } - T &&value() &&noexcept { - assert(hasVal); - return std::move(val); - } - - template <class... Args> void emplace(Args &&...args) { - reset(); - ::new ((void *)std::addressof(val)) T(std::forward<Args>(args)...); - hasVal = true; - } - - OptionalStorage &operator=(T const &y) { - if (has_value()) { - val = y; - } else { - ::new ((void *)std::addressof(val)) T(y); - hasVal = true; - } - return *this; - } - OptionalStorage &operator=(T &&y) { - if (has_value()) { - val = std::move(y); - } else { - ::new ((void *)std::addressof(val)) T(std::move(y)); - hasVal = true; - } - return *this; - } -}; - -} // namespace optional_detail - -template <typename T> class Optional { - optional_detail::OptionalStorage<T> Storage; - -public: - using value_type = T; - - constexpr Optional() = default; - constexpr Optional(std::nullopt_t) {} - - constexpr Optional(const T &y) : Storage(std::in_place, y) {} - constexpr Optional(const Optional &O) = default; - - constexpr Optional(T &&y) : Storage(std::in_place, std::move(y)) {} - constexpr Optional(Optional &&O) = default; - - template <typename... ArgTypes> - constexpr Optional(std::in_place_t, ArgTypes &&...Args) - : Storage(std::in_place, std::forward<ArgTypes>(Args)...) {} - - Optional &operator=(T &&y) { - Storage = std::move(y); - return *this; - } - Optional &operator=(Optional &&O) = default; - - /// Create a new object by constructing it in place with the given arguments. - template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { - Storage.emplace(std::forward<ArgTypes>(Args)...); - } - - Optional &operator=(const T &y) { - Storage = y; - return *this; - } - Optional &operator=(const Optional &O) = default; - - void reset() { Storage.reset(); } - - LLVM_DEPRECATED("Use &*X instead.", "&*X") - constexpr const T *getPointer() const { return &Storage.value(); } - LLVM_DEPRECATED("Use &*X instead.", "&*X") - T *getPointer() { return &Storage.value(); } - LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X") - constexpr const T &value() const & { return Storage.value(); } - LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X") - T &value() & { return Storage.value(); } - - constexpr explicit operator bool() const { return has_value(); } - constexpr bool has_value() const { return Storage.has_value(); } - constexpr const T *operator->() const { return &Storage.value(); } - T *operator->() { return &Storage.value(); } - constexpr const T &operator*() const & { return Storage.value(); } - T &operator*() & { return Storage.value(); } - - template <typename U> constexpr T value_or(U &&alt) const & { - return has_value() ? operator*() : std::forward<U>(alt); - } - - LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X") - T &&value() && { return std::move(Storage.value()); } - T &&operator*() && { return std::move(Storage.value()); } - - template <typename U> T value_or(U &&alt) && { - return has_value() ? std::move(operator*()) : std::forward<U>(alt); - } -}; - -template<typename T> -Optional(const T&) -> Optional<T>; - -template <class T> llvm::hash_code hash_value(const Optional<T> &O) { - return O ? hash_combine(true, *O) : hash_value(false); -} - -template <typename T, typename U> -constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) { - if (X && Y) - return *X == *Y; - return X.has_value() == Y.has_value(); -} - -template <typename T, typename U> -constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) { - return !(X == Y); -} - -template <typename T, typename U> -constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) { - if (X && Y) - return *X < *Y; - return X.has_value() < Y.has_value(); -} - -template <typename T, typename U> -constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) { - return !(Y < X); -} - -template <typename T, typename U> -constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) { - return Y < X; -} - -template <typename T, typename U> -constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) { - return !(X < Y); -} - -template <typename T> -constexpr bool operator==(const Optional<T> &X, std::nullopt_t) { - return !X; -} - -template <typename T> -constexpr bool operator==(std::nullopt_t, const Optional<T> &X) { - return X == std::nullopt; -} - -template <typename T> -constexpr bool operator!=(const Optional<T> &X, std::nullopt_t) { - return !(X == std::nullopt); -} - -template <typename T> -constexpr bool operator!=(std::nullopt_t, const Optional<T> &X) { - return X != std::nullopt; -} - -template <typename T> -constexpr bool operator<(const Optional<T> &, std::nullopt_t) { - return false; -} - -template <typename T> -constexpr bool operator<(std::nullopt_t, const Optional<T> &X) { - return X.has_value(); -} - -template <typename T> -constexpr bool operator<=(const Optional<T> &X, std::nullopt_t) { - return !(std::nullopt < X); -} - -template <typename T> -constexpr bool operator<=(std::nullopt_t, const Optional<T> &X) { - return !(X < std::nullopt); -} - -template <typename T> -constexpr bool operator>(const Optional<T> &X, std::nullopt_t) { - return std::nullopt < X; -} - -template <typename T> -constexpr bool operator>(std::nullopt_t, const Optional<T> &X) { - return X < std::nullopt; -} - -template <typename T> -constexpr bool operator>=(const Optional<T> &X, std::nullopt_t) { - return std::nullopt <= X; -} - -template <typename T> -constexpr bool operator>=(std::nullopt_t, const Optional<T> &X) { - return X <= std::nullopt; -} - -template <typename T> -constexpr bool operator==(const Optional<T> &X, const T &Y) { - return X && *X == Y; -} - -template <typename T> -constexpr bool operator==(const T &X, const Optional<T> &Y) { - return Y && X == *Y; -} - -template <typename T> -constexpr bool operator!=(const Optional<T> &X, const T &Y) { - return !(X == Y); -} - -template <typename T> -constexpr bool operator!=(const T &X, const Optional<T> &Y) { - return !(X == Y); -} - -template <typename T> -constexpr bool operator<(const Optional<T> &X, const T &Y) { - return !X || *X < Y; -} - -template <typename T> -constexpr bool operator<(const T &X, const Optional<T> &Y) { - return Y && X < *Y; -} - -template <typename T> -constexpr bool operator<=(const Optional<T> &X, const T &Y) { - return !(Y < X); -} - -template <typename T> -constexpr bool operator<=(const T &X, const Optional<T> &Y) { - return !(Y < X); -} - -template <typename T> -constexpr bool operator>(const Optional<T> &X, const T &Y) { - return Y < X; -} - -template <typename T> -constexpr bool operator>(const T &X, const Optional<T> &Y) { - return Y < X; -} - -template <typename T> -constexpr bool operator>=(const Optional<T> &X, const T &Y) { - return !(X < Y); -} - -template <typename T> -constexpr bool operator>=(const T &X, const Optional<T> &Y) { - return !(X < Y); -} - -} // end namespace llvm +// Legacy alias of llvm::Optional to std::optional. +// FIXME: Remove this after LLVM 16. +template <class T> using Optional = std::optional<T>; +} // namespace llvm #endif // LLVM_ADT_OPTIONAL_H diff --git a/llvm/include/llvm/ADT/STLForwardCompat.h b/llvm/include/llvm/ADT/STLForwardCompat.h index 51748c7c0ea28..b2fe9bc753f63 100644 --- a/llvm/include/llvm/ADT/STLForwardCompat.h +++ b/llvm/include/llvm/ADT/STLForwardCompat.h @@ -61,26 +61,6 @@ auto transformOptional(std::optional<T> &&O, const Function &F) return std::nullopt; } -// TODO: Remove this once the migration from llvm::Optional to std::optional is -// complete. -template <typename T, typename Function> -auto transformOptional(const Optional<T> &O, const Function &F) - -> Optional<decltype(F(*O))> { - if (O) - return F(*O); - return std::nullopt; -} - -// TODO: Remove this once the migration from llvm::Optional to std::optional is -// complete. -template <typename T, typename Function> -auto transformOptional(Optional<T> &&O, const Function &F) - -> Optional<decltype(F(*std::move(O)))> { - if (O) - return F(*std::move(O)); - return std::nullopt; -} - } // namespace llvm #endif // LLVM_ADT_STLFORWARDCOMPAT_H diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h index b5c3e463d69dc..73c703c7f8732 100644 --- a/llvm/include/llvm/Support/raw_ostream.h +++ b/llvm/include/llvm/Support/raw_ostream.h @@ -743,16 +743,6 @@ Error writeToOutput(StringRef OutputFileName, raw_ostream &operator<<(raw_ostream &OS, std::nullopt_t); -template <typename T, typename = decltype(std::declval<raw_ostream &>() - << std::declval<const T &>())> -raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) { - if (O) - OS << *O; - else - OS << std::nullopt; - return OS; -} - template <typename T, typename = decltype(std::declval<raw_ostream &>() << std::declval<const T &>())> raw_ostream &operator<<(raw_ostream &OS, const std::optional<T> &O) { diff --git a/llvm/include/llvm/Testing/Support/SupportHelpers.h b/llvm/include/llvm/Testing/Support/SupportHelpers.h index afcad6f9ba307..f9aa136f7a0ac 100644 --- a/llvm/include/llvm/Testing/Support/SupportHelpers.h +++ b/llvm/include/llvm/Testing/Support/SupportHelpers.h @@ -69,12 +69,6 @@ template <class InnerMatcher> class ValueIsMatcher { new Impl<T>(::testing::SafeMatcherCast<T>(ValueMatcher))); } - template <class T> - operator ::testing::Matcher<const Optional<T> &>() const { - return ::testing::MakeMatcher( - new Impl<T, Optional<T>>(::testing::SafeMatcherCast<T>(ValueMatcher))); - } - template <class T, class O = std::optional<T>> class Impl : public ::testing::MatcherInterface<const O &> { public: diff --git a/llvm/lib/CodeGen/RegAllocGreedy.h b/llvm/lib/CodeGen/RegAllocGreedy.h index e199772b14069..188cc5664d5d9 100644 --- a/llvm/lib/CodeGen/RegAllocGreedy.h +++ b/llvm/lib/CodeGen/RegAllocGreedy.h @@ -80,7 +80,7 @@ class LLVM_LIBRARY_VISIBILITY RAGreedy : public MachineFunctionPass, unsigned NextCascade = 1; public: - ExtraRegInfo() = default; + ExtraRegInfo() {} ExtraRegInfo(const ExtraRegInfo &) = delete; LiveRangeStage getStage(Register Reg) const { return Info[Reg].Stage; } diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt index 8cddaa50341f8..5a918892ff8e4 100644 --- a/llvm/unittests/ADT/CMakeLists.txt +++ b/llvm/unittests/ADT/CMakeLists.txt @@ -49,7 +49,6 @@ add_llvm_unittest(ADTTests MappedIteratorTest.cpp MapVectorTest.cpp MoveOnly.cpp - OptionalTest.cpp PackedVectorTest.cpp PointerEmbeddedIntTest.cpp PointerIntPairTest.cpp diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp deleted file mode 100644 index af4cf2ec46610..0000000000000 --- a/llvm/unittests/ADT/OptionalTest.cpp +++ /dev/null @@ -1,803 +0,0 @@ -//===- llvm/unittest/ADT/OptionalTest.cpp - Optional unit tests -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Support/raw_ostream.h" -#include "MoveOnly.h" -#include "gtest/gtest-spi.h" -#include "gtest/gtest.h" - -#include <array> -#include <utility> - -using namespace llvm; - -static_assert(std::is_trivially_copyable_v<Optional<int>>, - "trivially copyable"); - -static_assert(std::is_trivially_copyable_v<Optional<std::array<int, 3>>>, - "trivially copyable"); - -void OptionalWorksInConstexpr() { - constexpr auto x1 = Optional<int>(); - constexpr Optional<int> x2{}; - static_assert(!x1.has_value() && !x2.has_value(), - "Default construction and hasValue() are contexpr"); - static_assert(!x1.has_value() && !x2.has_value(), - "Default construction and hasValue() are contexpr"); - constexpr auto y1 = Optional<int>(3); - constexpr Optional<int> y2{3}; - static_assert(*y1 == *y2 && *y1 == 3, - "Construction with value and getValue() are constexpr"); - static_assert(*y1 == *y2 && *y1 == 3, - "Construction with value and getValue() are constexpr"); - static_assert(Optional<int>{3} >= 2 && Optional<int>{1} < Optional<int>{2}, - "Comparisons work in constexpr"); -} - -namespace { - -struct NonDefaultConstructible { - static unsigned CopyConstructions; - static unsigned Destructions; - static unsigned CopyAssignments; - explicit NonDefaultConstructible(int) { - } - NonDefaultConstructible(const NonDefaultConstructible&) { - ++CopyConstructions; - } - NonDefaultConstructible &operator=(const NonDefaultConstructible&) { - ++CopyAssignments; - return *this; - } - ~NonDefaultConstructible() { - ++Destructions; - } - static void ResetCounts() { - CopyConstructions = 0; - Destructions = 0; - CopyAssignments = 0; - } -}; - -unsigned NonDefaultConstructible::CopyConstructions = 0; -unsigned NonDefaultConstructible::Destructions = 0; -unsigned NonDefaultConstructible::CopyAssignments = 0; - -static_assert(!std::is_trivially_copyable_v<Optional<NonDefaultConstructible>>, - "not trivially copyable"); - -TEST(OptionalTest, NonDefaultConstructibleTest) { - Optional<NonDefaultConstructible> O; - EXPECT_FALSE(O); -} - -TEST(OptionalTest, ResetTest) { - NonDefaultConstructible::ResetCounts(); - Optional<NonDefaultConstructible> O(NonDefaultConstructible(3)); - EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(1u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - O.reset(); - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(1u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, InitializationLeakTest) { - NonDefaultConstructible::ResetCounts(); - Optional<NonDefaultConstructible>(NonDefaultConstructible(3)); - EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(2u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, CopyConstructionTest) { - NonDefaultConstructible::ResetCounts(); - { - Optional<NonDefaultConstructible> A(NonDefaultConstructible(3)); - EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(1u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - Optional<NonDefaultConstructible> B(A); - EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(0u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - } - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(2u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, ConstructingCopyAssignmentTest) { - NonDefaultConstructible::ResetCounts(); - { - Optional<NonDefaultConstructible> A(NonDefaultConstructible(3)); - Optional<NonDefaultConstructible> B; - EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(1u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - B = A; - EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(0u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - } - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(2u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, CopyingCopyAssignmentTest) { - NonDefaultConstructible::ResetCounts(); - { - Optional<NonDefaultConstructible> A(NonDefaultConstructible(3)); - Optional<NonDefaultConstructible> B(NonDefaultConstructible(4)); - EXPECT_EQ(2u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(2u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - B = A; - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(1u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(0u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - } - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(2u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, DeletingCopyAssignmentTest) { - NonDefaultConstructible::ResetCounts(); - { - Optional<NonDefaultConstructible> A; - Optional<NonDefaultConstructible> B(NonDefaultConstructible(3)); - EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(1u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - B = A; - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(1u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - } - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(0u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, NullCopyConstructionTest) { - NonDefaultConstructible::ResetCounts(); - { - Optional<NonDefaultConstructible> A; - Optional<NonDefaultConstructible> B; - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(0u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - B = A; - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(0u, NonDefaultConstructible::Destructions); - NonDefaultConstructible::ResetCounts(); - } - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(0u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, InPlaceConstructionNonDefaultConstructibleTest) { - NonDefaultConstructible::ResetCounts(); - { Optional<NonDefaultConstructible> A{std::in_place, 1}; } - EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions); - EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments); - EXPECT_EQ(1u, NonDefaultConstructible::Destructions); -} - -TEST(OptionalTest, GetValueOr) { - Optional<int> A; - EXPECT_EQ(42, A.value_or(42)); - - A = 5; - EXPECT_EQ(5, A.value_or(42)); -} - -struct MultiArgConstructor { - int x, y; - MultiArgConstructor(int x, int y) : x(x), y(y) {} - explicit MultiArgConstructor(int x, bool positive) - : x(x), y(positive ? x : -x) {} - - MultiArgConstructor(const MultiArgConstructor &) = delete; - MultiArgConstructor(MultiArgConstructor &&) = delete; - MultiArgConstructor &operator=(const MultiArgConstructor &) = delete; - MultiArgConstructor &operator=(MultiArgConstructor &&) = delete; - - friend bool operator==(const MultiArgConstructor &LHS, - const MultiArgConstructor &RHS) { - return LHS.x == RHS.x && LHS.y == RHS.y; - } - - static unsigned Destructions; - ~MultiArgConstructor() { - ++Destructions; - } - static void ResetCounts() { - Destructions = 0; - } -}; -unsigned MultiArgConstructor::Destructions = 0; - -static_assert(!std::is_trivially_copyable_v<Optional<MultiArgConstructor>>, - "not trivially copyable"); - -TEST(OptionalTest, Emplace) { - MultiArgConstructor::ResetCounts(); - Optional<MultiArgConstructor> A; - - A.emplace(1, 2); - EXPECT_TRUE(A.has_value()); - EXPECT_TRUE(A.has_value()); - EXPECT_EQ(1, A->x); - EXPECT_EQ(2, A->y); - EXPECT_EQ(0u, MultiArgConstructor::Destructions); - - A.emplace(5, false); - EXPECT_TRUE(A.has_value()); - EXPECT_TRUE(A.has_value()); - EXPECT_EQ(5, A->x); - EXPECT_EQ(-5, A->y); - EXPECT_EQ(1u, MultiArgConstructor::Destructions); -} - -TEST(OptionalTest, InPlaceConstructionMultiArgConstructorTest) { - MultiArgConstructor::ResetCounts(); - { - Optional<MultiArgConstructor> A{std::in_place, 1, 2}; - EXPECT_TRUE(A.has_value()); - EXPECT_TRUE(A.has_value()); - EXPECT_EQ(1, A->x); - EXPECT_EQ(2, A->y); - Optional<MultiArgConstructor> B{std::in_place, 5, false}; - EXPECT_TRUE(B.has_value()); - EXPECT_TRUE(B.has_value()); - EXPECT_EQ(5, B->x); - EXPECT_EQ(-5, B->y); - EXPECT_EQ(0u, MultiArgConstructor::Destructions); - } - EXPECT_EQ(2u, MultiArgConstructor::Destructions); -} - -TEST(OptionalTest, InPlaceConstructionAndEmplaceEquivalentTest) { - MultiArgConstructor::ResetCounts(); - { - Optional<MultiArgConstructor> A{std::in_place, 1, 2}; - Optional<MultiArgConstructor> B; - B.emplace(1, 2); - EXPECT_EQ(0u, MultiArgConstructor::Destructions); - ASSERT_EQ(A, B); - } - EXPECT_EQ(2u, MultiArgConstructor::Destructions); -} - -static_assert(!std::is_trivially_copyable_v<Optional<MoveOnly>>, - "not trivially copyable"); - -TEST(OptionalTest, MoveOnlyNull) { - MoveOnly::ResetCounts(); - Optional<MoveOnly> O; - EXPECT_EQ(0u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(0u, MoveOnly::Destructions); -} - -TEST(OptionalTest, MoveOnlyConstruction) { - MoveOnly::ResetCounts(); - Optional<MoveOnly> O(MoveOnly(3)); - EXPECT_TRUE((bool)O); - EXPECT_EQ(3, O->val); - EXPECT_EQ(1u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(1u, MoveOnly::Destructions); -} - -TEST(OptionalTest, MoveOnlyMoveConstruction) { - Optional<MoveOnly> A(MoveOnly(3)); - MoveOnly::ResetCounts(); - Optional<MoveOnly> B(std::move(A)); - EXPECT_TRUE((bool)A); - EXPECT_TRUE((bool)B); - EXPECT_EQ(3, B->val); - EXPECT_EQ(1u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(0u, MoveOnly::Destructions); -} - -TEST(OptionalTest, MoveOnlyAssignment) { - MoveOnly::ResetCounts(); - Optional<MoveOnly> O; - O = MoveOnly(3); - EXPECT_TRUE((bool)O); - EXPECT_EQ(3, O->val); - EXPECT_EQ(1u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(1u, MoveOnly::Destructions); -} - -TEST(OptionalTest, MoveOnlyInitializingAssignment) { - Optional<MoveOnly> A(MoveOnly(3)); - Optional<MoveOnly> B; - MoveOnly::ResetCounts(); - B = std::move(A); - EXPECT_TRUE((bool)A); - EXPECT_TRUE((bool)B); - EXPECT_EQ(3, B->val); - EXPECT_EQ(1u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(0u, MoveOnly::Destructions); -} - -TEST(OptionalTest, MoveOnlyNullingAssignment) { - Optional<MoveOnly> A; - Optional<MoveOnly> B(MoveOnly(3)); - MoveOnly::ResetCounts(); - B = std::move(A); - EXPECT_FALSE((bool)A); - EXPECT_FALSE((bool)B); - EXPECT_EQ(0u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(1u, MoveOnly::Destructions); -} - -TEST(OptionalTest, MoveOnlyAssigningAssignment) { - Optional<MoveOnly> A(MoveOnly(3)); - Optional<MoveOnly> B(MoveOnly(4)); - MoveOnly::ResetCounts(); - B = std::move(A); - EXPECT_TRUE((bool)A); - EXPECT_TRUE((bool)B); - EXPECT_EQ(3, B->val); - EXPECT_EQ(0u, MoveOnly::MoveConstructions); - EXPECT_EQ(1u, MoveOnly::MoveAssignments); - EXPECT_EQ(0u, MoveOnly::Destructions); -} - -struct Immovable { - static unsigned Constructions; - static unsigned Destructions; - int val; - explicit Immovable(int val) : val(val) { - ++Constructions; - } - ~Immovable() { - ++Destructions; - } - static void ResetCounts() { - Constructions = 0; - Destructions = 0; - } -private: - // This should disable all move/copy operations. - Immovable(Immovable&& other) = delete; -}; - -unsigned Immovable::Constructions = 0; -unsigned Immovable::Destructions = 0; - -static_assert(!std::is_trivially_copyable_v<Optional<Immovable>>, - "not trivially copyable"); - -TEST(OptionalTest, ImmovableEmplace) { - Optional<Immovable> A; - Immovable::ResetCounts(); - A.emplace(4); - EXPECT_TRUE((bool)A); - EXPECT_EQ(4, A->val); - EXPECT_EQ(1u, Immovable::Constructions); - EXPECT_EQ(0u, Immovable::Destructions); -} - -TEST(OptionalTest, ImmovableInPlaceConstruction) { - Immovable::ResetCounts(); - Optional<Immovable> A{std::in_place, 4}; - EXPECT_TRUE((bool)A); - EXPECT_EQ(4, A->val); - EXPECT_EQ(1u, Immovable::Constructions); - EXPECT_EQ(0u, Immovable::Destructions); -} - -// Craft a class which is_trivially_copyable, but not -// is_trivially_copy_constructible. -struct NonTCopy { - NonTCopy() = default; - - // Delete the volatile copy constructor to engage the "rule of 3" and delete - // any unspecified copy assignment or constructor. - NonTCopy(volatile NonTCopy const &) = delete; - - // Leave the non-volatile default copy constructor unspecified (deleted by - // rule of 3) - - // This template can serve as the copy constructor, but isn't chosen - // by =default in a class with a 'NonTCopy' member. - template <typename Self = NonTCopy> - NonTCopy(Self const &Other) : Val(Other.Val) {} - - NonTCopy &operator=(NonTCopy const &) = default; - - int Val{0}; -}; - -#if defined(_MSC_VER) && _MSC_VER >= 1927 && !defined(__clang__) -// Currently only true on recent MSVC releases. -static_assert(std::is_trivially_copyable<NonTCopy>::value, - "Expect NonTCopy to be trivially copyable"); - -static_assert(!std::is_trivially_copy_constructible<NonTCopy>::value, - "Expect NonTCopy not to be trivially copy constructible."); -#endif // defined(_MSC_VER) && _MSC_VER >= 1927 - -TEST(OptionalTest, DeletedCopyConstructor) { - - // Expect compile to fail if 'trivial' version of - // optional_detail::OptionalStorage is chosen. - using NonTCopyOptT = Optional<NonTCopy>; - NonTCopyOptT NonTCopy1; - - // Check that the Optional can be copy constructed. - NonTCopyOptT NonTCopy2{NonTCopy1}; - - // Check that the Optional can be copy assigned. - NonTCopy1 = NonTCopy2; -} - -// Craft a class which is_trivially_copyable, but not -// is_trivially_copy_assignable. -class NonTAssign { -public: - NonTAssign() = default; - NonTAssign(NonTAssign const &) = default; - - // Delete the volatile copy assignment to engage the "rule of 3" and delete - // any unspecified copy assignment or constructor. - NonTAssign &operator=(volatile NonTAssign const &) = delete; - - // Leave the non-volatile default copy assignment unspecified (deleted by rule - // of 3). - - // This template can serve as the copy assignment, but isn't chosen - // by =default in a class with a 'NonTAssign' member. - template <typename Self = NonTAssign> - NonTAssign &operator=(Self const &Other) { - A = Other.A; - return *this; - } - - int A{0}; -}; - -#if defined(_MSC_VER) && _MSC_VER >= 1927 && !defined(__clang__) -// Currently only true on recent MSVC releases. -static_assert(std::is_trivially_copyable<NonTAssign>::value, - "Expect NonTAssign to be trivially copyable"); - -static_assert(!std::is_trivially_copy_assignable<NonTAssign>::value, - "Expect NonTAssign not to be trivially assignable."); -#endif // defined(_MSC_VER) && _MSC_VER >= 1927 - -TEST(OptionalTest, DeletedCopyAssignment) { - - // Expect compile to fail if 'trivial' version of - // optional_detail::OptionalStorage is chosen. - using NonTAssignOptT = Optional<NonTAssign>; - NonTAssignOptT NonTAssign1; - - // Check that the Optional can be copy constructed. - NonTAssignOptT NonTAssign2{NonTAssign1}; - - // Check that the Optional can be copy assigned. - NonTAssign1 = NonTAssign2; -} - -struct NoTMove { - NoTMove() = default; - NoTMove(NoTMove const &) = default; - NoTMove &operator=(NoTMove const &) = default; - - // Delete move constructor / assignment. Compiler should fall-back to the - // trivial copy constructor / assignment in the trivial OptionalStorage - // specialization. - NoTMove(NoTMove &&) = delete; - NoTMove &operator=(NoTMove &&) = delete; - - int Val{0}; -}; - -TEST(OptionalTest, DeletedMoveConstructor) { - using NoTMoveOptT = Optional<NoTMove>; - - NoTMoveOptT NonTMove1; - NoTMoveOptT NonTMove2{std::move(NonTMove1)}; - - NonTMove1 = std::move(NonTMove2); - - static_assert( - std::is_trivially_copyable_v<NoTMoveOptT>, - "Expect Optional<NoTMove> to still use the trivial specialization " - "of OptionalStorage despite the deleted move constructor / assignment."); -} - -class NoCopyStringMap { -public: - NoCopyStringMap() = default; - -private: - llvm::StringMap<std::unique_ptr<int>> Map; -}; - -TEST(OptionalTest, DeletedCopyStringMap) { - // Old versions of gcc (7.3 and prior) instantiate the copy constructor when - // std::is_trivially_copyable is instantiated. This test will fail - // compilation if std::is_trivially_copyable is used in the OptionalStorage - // specialization condition by gcc <= 7.3. - Optional<NoCopyStringMap> TestInstantiation; -} - -TEST(OptionalTest, MoveValueOr) { - Optional<MoveOnly> A; - - MoveOnly::ResetCounts(); - EXPECT_EQ(42, std::move(A).value_or(MoveOnly(42)).val); - EXPECT_EQ(1u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(2u, MoveOnly::Destructions); - - A = MoveOnly(5); - MoveOnly::ResetCounts(); - EXPECT_EQ(5, std::move(A).value_or(MoveOnly(42)).val); - EXPECT_EQ(1u, MoveOnly::MoveConstructions); - EXPECT_EQ(0u, MoveOnly::MoveAssignments); - EXPECT_EQ(2u, MoveOnly::Destructions); -} - -struct EqualTo { - template <typename T, typename U> static bool apply(const T &X, const U &Y) { - return X == Y; - } -}; - -struct NotEqualTo { - template <typename T, typename U> static bool apply(const T &X, const U &Y) { - return X != Y; - } -}; - -struct Less { - template <typename T, typename U> static bool apply(const T &X, const U &Y) { - return X < Y; - } -}; - -struct Greater { - template <typename T, typename U> static bool apply(const T &X, const U &Y) { - return X > Y; - } -}; - -struct LessEqual { - template <typename T, typename U> static bool apply(const T &X, const U &Y) { - return X <= Y; - } -}; - -struct GreaterEqual { - template <typename T, typename U> static bool apply(const T &X, const U &Y) { - return X >= Y; - } -}; - -template <typename OperatorT, typename T> -void CheckRelation(const Optional<T> &Lhs, const Optional<T> &Rhs, - bool Expected) { - EXPECT_EQ(Expected, OperatorT::apply(Lhs, Rhs)); - - if (Lhs) - EXPECT_EQ(Expected, OperatorT::apply(*Lhs, Rhs)); - else - EXPECT_EQ(Expected, OperatorT::apply(std::nullopt, Rhs)); - - if (Rhs) - EXPECT_EQ(Expected, OperatorT::apply(Lhs, *Rhs)); - else - EXPECT_EQ(Expected, OperatorT::apply(Lhs, std::nullopt)); -} - -struct EqualityMock {}; -const Optional<EqualityMock> NoneEq, EqualityLhs((EqualityMock())), - EqualityRhs((EqualityMock())); -bool IsEqual; - -bool operator==(const EqualityMock &Lhs, const EqualityMock &Rhs) { - EXPECT_EQ(&*EqualityLhs, &Lhs); - EXPECT_EQ(&*EqualityRhs, &Rhs); - return IsEqual; -} - -TEST(OptionalTest, OperatorEqual) { - CheckRelation<EqualTo>(NoneEq, NoneEq, true); - CheckRelation<EqualTo>(NoneEq, EqualityRhs, false); - CheckRelation<EqualTo>(EqualityLhs, NoneEq, false); - - IsEqual = false; - CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual); - IsEqual = true; - CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual); -} - -TEST(OptionalTest, OperatorNotEqual) { - CheckRelation<NotEqualTo>(NoneEq, NoneEq, false); - CheckRelation<NotEqualTo>(NoneEq, EqualityRhs, true); - CheckRelation<NotEqualTo>(EqualityLhs, NoneEq, true); - - IsEqual = false; - CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual); - IsEqual = true; - CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual); -} - -struct InequalityMock {}; -const Optional<InequalityMock> NoneIneq, InequalityLhs((InequalityMock())), - InequalityRhs((InequalityMock())); -bool IsLess; - -bool operator<(const InequalityMock &Lhs, const InequalityMock &Rhs) { - EXPECT_EQ(&*InequalityLhs, &Lhs); - EXPECT_EQ(&*InequalityRhs, &Rhs); - return IsLess; -} - -TEST(OptionalTest, OperatorLess) { - CheckRelation<Less>(NoneIneq, NoneIneq, false); - CheckRelation<Less>(NoneIneq, InequalityRhs, true); - CheckRelation<Less>(InequalityLhs, NoneIneq, false); - - IsLess = false; - CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess); - IsLess = true; - CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess); -} - -TEST(OptionalTest, OperatorGreater) { - CheckRelation<Greater>(NoneIneq, NoneIneq, false); - CheckRelation<Greater>(NoneIneq, InequalityRhs, false); - CheckRelation<Greater>(InequalityLhs, NoneIneq, true); - - IsLess = false; - CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess); - IsLess = true; - CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess); -} - -TEST(OptionalTest, OperatorLessEqual) { - CheckRelation<LessEqual>(NoneIneq, NoneIneq, true); - CheckRelation<LessEqual>(NoneIneq, InequalityRhs, true); - CheckRelation<LessEqual>(InequalityLhs, NoneIneq, false); - - IsLess = false; - CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess); - IsLess = true; - CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess); -} - -TEST(OptionalTest, OperatorGreaterEqual) { - CheckRelation<GreaterEqual>(NoneIneq, NoneIneq, true); - CheckRelation<GreaterEqual>(NoneIneq, InequalityRhs, false); - CheckRelation<GreaterEqual>(InequalityLhs, NoneIneq, true); - - IsLess = false; - CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess); - IsLess = true; - CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess); -} - -struct ComparableAndStreamable { - friend bool operator==(ComparableAndStreamable, - ComparableAndStreamable) LLVM_ATTRIBUTE_USED { - return true; - } - - friend raw_ostream &operator<<(raw_ostream &OS, ComparableAndStreamable) { - return OS << "ComparableAndStreamable"; - } - - static Optional<ComparableAndStreamable> get() { - return ComparableAndStreamable(); - } -}; - -TEST(OptionalTest, StreamOperator) { - auto to_string = [](Optional<ComparableAndStreamable> O) { - SmallString<16> S; - raw_svector_ostream OS(S); - OS << O; - return S; - }; - EXPECT_EQ("ComparableAndStreamable", - to_string(ComparableAndStreamable::get())); - EXPECT_EQ("None", to_string(std::nullopt)); -} - -struct Comparable { - friend bool operator==(Comparable, Comparable) LLVM_ATTRIBUTE_USED { - return true; - } - static Optional<Comparable> get() { return Comparable(); } -}; - -TEST(OptionalTest, UseInUnitTests) { - // Test that we invoke the streaming operators when pretty-printing values in - // EXPECT macros. - EXPECT_NONFATAL_FAILURE( - EXPECT_EQ(std::nullopt, ComparableAndStreamable::get()), - "Expected equality of these values:\n" - " std::nullopt\n" - " Which is: None\n" - " ComparableAndStreamable::get()\n" - " Which is: ComparableAndStreamable"); - - // Test that it is still possible to compare objects which do not have a - // custom streaming operator. - EXPECT_NONFATAL_FAILURE(EXPECT_EQ(std::nullopt, Comparable::get()), "object"); -} - -TEST(OptionalTest, HashValue) { - // Check that None, false, and true all hash diff erently. - Optional<bool> B, B0 = false, B1 = true; - EXPECT_NE(hash_value(B0), hash_value(B)); - EXPECT_NE(hash_value(B1), hash_value(B)); - EXPECT_NE(hash_value(B1), hash_value(B0)); - - // Check that None, 0, and 1 all hash diff erently. - Optional<int> I, I0 = 0, I1 = 1; - EXPECT_NE(hash_value(I0), hash_value(I)); - EXPECT_NE(hash_value(I1), hash_value(I)); - EXPECT_NE(hash_value(I1), hash_value(I0)); - - // Check None hash the same way regardless of type. - EXPECT_EQ(hash_value(B), hash_value(I)); -} - -struct NotTriviallyCopyable { - NotTriviallyCopyable(); // Constructor out-of-line. - virtual ~NotTriviallyCopyable() = default; - Optional<MoveOnly> MO; -}; - -TEST(OptionalTest, GCCIsTriviallyMoveConstructibleCompat) { - Optional<NotTriviallyCopyable> V; - EXPECT_FALSE(V); -} - -TEST(OptionalTest, DeductionGuide) { - Optional V = MoveOnly(1); - EXPECT_TRUE(V); - EXPECT_EQ(V->val, 1); -} - -static_assert( - std::is_same_v<Optional<MoveOnly>, decltype(Optional(MoveOnly(1)))>); - -} // end anonymous namespace diff --git a/llvm/unittests/Support/TypeTraitsTest.cpp b/llvm/unittests/Support/TypeTraitsTest.cpp index 734e50afa2db3..845c38d21182b 100644 --- a/llvm/unittests/Support/TypeTraitsTest.cpp +++ b/llvm/unittests/Support/TypeTraitsTest.cpp @@ -118,7 +118,10 @@ TEST(Triviality, ADT) { TrivialityTester<llvm::StringRef, true, true>(); TrivialityTester<llvm::ArrayRef<int>, true, true>(); TrivialityTester<llvm::PointerIntPair<int *, 2>, true, true>(); +#if defined(_LIBCPP_VERSION) || \ + (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 8) TrivialityTester<llvm::Optional<int>, true, true>(); +#endif } } // namespace triviality diff --git a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h index 564425b9beb2c..38c547078bfcd 100644 --- a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h +++ b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h @@ -35,9 +35,6 @@ namespace py = pybind11; namespace pybind11 { namespace detail { -template <typename T> -struct type_caster<llvm::Optional<T>> : optional_caster<llvm::Optional<T>> {}; - /// Helper to convert a presumed MLIR API object to a capsule, accepting either /// an explicit Capsule (which can happen when two C APIs are communicating /// directly via Python) or indirectly by querying the MLIR_PYTHON_CAPI_PTR_ATTR diff --git a/mlir/include/mlir/Support/LLVM.h b/mlir/include/mlir/Support/LLVM.h index a389392301a00..7acf97b5a2531 100644 --- a/mlir/include/mlir/Support/LLVM.h +++ b/mlir/include/mlir/Support/LLVM.h @@ -58,8 +58,7 @@ class DenseSet; class MallocAllocator; template <typename T> class MutableArrayRef; -template <typename T> -class Optional; +template <typename T> using Optional = std::optional<T>; template <typename... PT> class PointerUnion; template <typename T, typename Vector, typename Set> diff --git a/mlir/lib/Bindings/Python/PybindUtils.h b/mlir/lib/Bindings/Python/PybindUtils.h index 5356cbd54ff48..d039a8acdca39 100644 --- a/mlir/lib/Bindings/Python/PybindUtils.h +++ b/mlir/lib/Bindings/Python/PybindUtils.h @@ -94,9 +94,6 @@ struct MlirDefaultingCaster { return pybind11::cast(src, policy); } }; - -template <typename T> -struct type_caster<llvm::Optional<T>> : optional_caster<llvm::Optional<T>> {}; } // namespace detail } // namespace pybind11 diff --git a/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp b/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp index 860d5d7d60800..692c1e8fb3bf4 100644 --- a/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp +++ b/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp @@ -179,7 +179,7 @@ SerializeToHsacoPass::loadLibraries(SmallVectorImpl<char> &path, ret.push_back(std::move(library)); } - return ret; + return std::move(ret); } std::unique_ptr<llvm::Module> _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits