Index: llvm/trunk/include/llvm/ADT/Optional.h =================================================================== --- llvm/trunk/include/llvm/ADT/Optional.h +++ llvm/trunk/include/llvm/ADT/Optional.h @@ -27,6 +27,8 @@ namespace llvm { +class raw_ostream; + namespace optional_detail { /// Storage for any type. template ::value> struct OptionalStorage { @@ -323,6 +325,18 @@ return !(X < Y); } +raw_ostream &operator<<(raw_ostream &OS, NoneType); + +template () + << std::declval())> +raw_ostream &operator<<(raw_ostream &OS, const Optional &O) { + if (O) + OS << *O; + else + OS << None; + return OS; +} + } // end namespace llvm #endif // LLVM_ADT_OPTIONAL_H Index: llvm/trunk/lib/Support/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Support/CMakeLists.txt +++ llvm/trunk/lib/Support/CMakeLists.txt @@ -106,6 +106,7 @@ MemoryBuffer.cpp MD5.cpp NativeFormatting.cpp + Optional.cpp Options.cpp Parallel.cpp PluginLoader.cpp Index: llvm/trunk/lib/Support/Optional.cpp =================================================================== --- llvm/trunk/lib/Support/Optional.cpp +++ llvm/trunk/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"; +} Index: llvm/trunk/unittests/ADT/OptionalTest.cpp =================================================================== --- llvm/trunk/unittests/ADT/OptionalTest.cpp +++ llvm/trunk/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 @@ CheckRelation(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 get() { + return ComparableAndStreamable(); + } +}; + +TEST_F(OptionalTest, StreamOperator) { + auto to_string = [](Optional 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 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 Index: llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h =================================================================== --- llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h +++ llvm/trunk/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h @@ -42,8 +42,9 @@ // 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 namespace llvm_gtest { @@ -68,6 +69,18 @@ << ConvertibleTo()))> { static const RawStreamProxy 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 +struct StreamSwitch, + decltype((void)(std::declval() + << std::declval>()))> { + static const RawStreamProxy> + printable(const llvm::Optional &V) { + return {V}; + } +}; } // namespace llvm_gtest #endif // !GTEST_NO_LLVM_RAW_OSTREAM