Index: include/llvm/Support/Error.h =================================================================== --- include/llvm/Support/Error.h +++ include/llvm/Support/Error.h @@ -952,6 +952,7 @@ /// Write all error messages (if any) in E to a string. The newline character /// is used to separate error messages. +/// DEPRECATED: prefer llvm::to_string(E) from ScopedPrinter.h inline std::string toString(Error E) { SmallVector Errors; handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) { @@ -971,6 +972,13 @@ handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {}); } +/// Sending an rvalue error to a raw_ostream prints its message and consumes it. +inline raw_ostream &operator<<(raw_ostream &OS, Error &&E) { + OS << static_cast(E); + consumeError(std::move(E)); + return OS; +} + /// Helper for converting an Error to a bool. /// /// This method returns true if Err is in an error state, or false if it is Index: include/llvm/Support/FormatVariadicDetails.h =================================================================== --- include/llvm/Support/FormatVariadicDetails.h +++ include/llvm/Support/FormatVariadicDetails.h @@ -46,7 +46,9 @@ explicit stream_operator_format_adapter(T &&Item) : Item(std::forward(Item)) {} - void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; } + void format(llvm::raw_ostream &S, StringRef Options) override { + S << std::forward(Item); + } }; template class missing_format_adapter; Index: include/llvm/Support/ScopedPrinter.h =================================================================== --- include/llvm/Support/ScopedPrinter.h +++ include/llvm/Support/ScopedPrinter.h @@ -59,10 +59,10 @@ raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value); const std::string to_hexString(uint64_t Value, bool UpperCase = true); -template const std::string to_string(const T &Value) { +template const std::string to_string(T &&Value) { std::string number; llvm::raw_string_ostream stream(number); - stream << Value; + stream << std::forward(Value); return stream.str(); } Index: unittests/Support/ErrorTest.cpp =================================================================== --- unittests/Support/ErrorTest.cpp +++ unittests/Support/ErrorTest.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest-spi.h" #include "gtest/gtest.h" @@ -700,20 +701,28 @@ // Test that error messages work. TEST(Error, ErrorMessage) { EXPECT_EQ(toString(Error::success()).compare(""), 0); + EXPECT_EQ(to_string(Error::success()), "success"); - Error E1 = make_error(0); - EXPECT_EQ(toString(std::move(E1)).compare("CustomError {0}"), 0); + Error E1A = make_error(0), E1B = make_error(0); + EXPECT_EQ(to_string(E1A), "CustomError {0}"); + EXPECT_EQ(toString(std::move(E1A)).compare("CustomError {0}"), 0); + EXPECT_EQ(to_string(std::move(E1B)).compare("CustomError {0}"), 0); Error E2 = make_error(0); handleAllErrors(std::move(E2), [](const CustomError &CE) { EXPECT_EQ(CE.message().compare("CustomError {0}"), 0); }); - Error E3 = joinErrors(make_error(0), make_error(1)); - EXPECT_EQ(toString(std::move(E3)) + Error E3A = + joinErrors(make_error(0), make_error(1)), + E3B = + joinErrors(make_error(0), make_error(1)); + EXPECT_EQ(toString(std::move(E3A)) .compare("CustomError {0}\n" "CustomError {1}"), 0); + EXPECT_EQ(to_string(std::move(E3B)), + "Multiple errors:\nCustomError {0}\nCustomError {1}\n"); } TEST(Error, Stream) { Index: unittests/Support/FormatVariadicTest.cpp =================================================================== --- unittests/Support/FormatVariadicTest.cpp +++ unittests/Support/FormatVariadicTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FormatAdapters.h" #include "gtest/gtest.h" @@ -680,3 +681,11 @@ adl::X X; EXPECT_EQ("X", formatv("{0}", X).str()); } + +TEST(FormatVariadicTest, FormatError) { + auto E1 = make_error("X", inconvertibleErrorCode()); + EXPECT_EQ("X", formatv("{0}", E1).str()); + EXPECT_TRUE(E1.isA()); // not consumed + EXPECT_EQ("X", formatv("{0}", std::move(E1)).str()); + EXPECT_FALSE(E1.isA()); // consumed +}