summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/ADT/Optional.h14
-rw-r--r--llvm/lib/Support/CMakeLists.txt1
-rw-r--r--llvm/lib/Support/Optional.cpp15
-rw-r--r--llvm/unittests/ADT/OptionalTest.cpp52
-rw-r--r--llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h15
5 files changed, 95 insertions, 2 deletions
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h
index 76937d632ae..56eafb156e8 100644
--- a/llvm/include/llvm/ADT/Optional.h
+++ b/llvm/include/llvm/ADT/Optional.h
@@ -27,6 +27,8 @@
namespace llvm {
+class raw_ostream;
+
namespace optional_detail {
/// Storage for any type.
template <typename T, bool = isPodLike<T>::value> struct OptionalStorage {
@@ -323,6 +325,18 @@ template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
return !(X < Y);
}
+raw_ostream &operator<<(raw_ostream &OS, NoneType);
+
+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 << None;
+ return OS;
+}
+
} // end namespace llvm
#endif // LLVM_ADT_OPTIONAL_H
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 2a6810672b1..7e791594587 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -106,6 +106,7 @@ add_llvm_library(LLVMSupport
MemoryBuffer.cpp
MD5.cpp
NativeFormatting.cpp
+ Optional.cpp
Options.cpp
Parallel.cpp
PluginLoader.cpp
diff --git a/llvm/lib/Support/Optional.cpp b/llvm/lib/Support/Optional.cpp
new file mode 100644
index 00000000000..765b25df13d
--- /dev/null
+++ b/llvm/lib/Support/Optional.cpp
@@ -0,0 +1,15 @@
+//===- Optional.cpp - Optional values ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+llvm::raw_ostream &llvm::operator<<(raw_ostream &OS, NoneType) {
+ return OS << "None";
+}
diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp
index 20bc9da4d59..e6997ef8be7 100644
--- a/llvm/unittests/ADT/OptionalTest.cpp
+++ b/llvm/unittests/ADT/OptionalTest.cpp
@@ -8,6 +8,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest-spi.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -518,5 +521,52 @@ TEST_F(OptionalTest, OperatorGreaterEqual) {
CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
}
-} // end anonymous namespace
+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_F(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(None));
+}
+
+struct Comparable {
+ friend bool operator==(Comparable, Comparable) LLVM_ATTRIBUTE_USED {
+ return true;
+ }
+ static Optional<Comparable> get() { return Comparable(); }
+};
+
+TEST_F(OptionalTest, UseInUnitTests) {
+ // Test that we invoke the streaming operators when pretty-printing values in
+ // EXPECT macros.
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(llvm::None, ComparableAndStreamable::get()),
+ R"(Expected: llvm::None
+ Which is: None
+To be equal to: ComparableAndStreamable::get()
+ 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(llvm::None, Comparable::get()), "object");
+}
+
+} // end anonymous namespace
diff --git a/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h b/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h
index fd993db1602..f4430f8de47 100644
--- a/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h
+++ b/llvm/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h
@@ -42,8 +42,9 @@ auto printable(const T &V) -> decltype(StreamSwitch<T>::printable(V)) {
// If raw_ostream support is enabled, we specialize for types with operator<<
// that takes a raw_ostream.
#if !GTEST_NO_LLVM_RAW_OSTREAM
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/raw_ostream.h"
#include <ostream>
namespace llvm_gtest {
@@ -68,6 +69,18 @@ struct StreamSwitch<T, decltype((void)(std::declval<llvm::raw_ostream &>()
<< ConvertibleTo<const T &>()))> {
static const RawStreamProxy<T> printable(const T &V) { return {V}; }
};
+
+// llvm::Optional has a template operator<<, which means it will not accept any
+// implicit conversions, so we need to special-case it here.
+template <typename T>
+struct StreamSwitch<llvm::Optional<T>,
+ decltype((void)(std::declval<llvm::raw_ostream &>()
+ << std::declval<llvm::Optional<T>>()))> {
+ static const RawStreamProxy<llvm::Optional<T>>
+ printable(const llvm::Optional<T> &V) {
+ return {V};
+ }
+};
} // namespace llvm_gtest
#endif // !GTEST_NO_LLVM_RAW_OSTREAM
OpenPOWER on IntegriCloud