Index: llvm/trunk/include/llvm/Support/FormatAdapters.h =================================================================== --- llvm/trunk/include/llvm/Support/FormatAdapters.h +++ llvm/trunk/include/llvm/Support/FormatAdapters.h @@ -12,6 +12,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FormatCommon.h" #include "llvm/Support/FormatVariadicDetails.h" #include "llvm/Support/raw_ostream.h" @@ -19,7 +20,7 @@ namespace llvm { template class FormatAdapter : public detail::format_adapter { protected: - explicit FormatAdapter(T &&Item) : Item(Item) {} + explicit FormatAdapter(T &&Item) : Item(std::forward(Item)) {} T Item; }; @@ -71,6 +72,14 @@ } } }; + +class ErrorAdapter : public FormatAdapter { +public: + ErrorAdapter(Error &&Item) : FormatAdapter(std::move(Item)) {} + ErrorAdapter(ErrorAdapter &&) = default; + ~ErrorAdapter() { consumeError(std::move(Item)); } + void format(llvm::raw_ostream &Stream, StringRef Style) { Stream << Item; } +}; } template @@ -88,6 +97,13 @@ detail::RepeatAdapter fmt_repeat(T &&Item, size_t Count) { return detail::RepeatAdapter(std::forward(Item), Count); } + +// llvm::Error values must be consumed before being destroyed. +// Wrapping an error in fmt_consume explicitly indicates that the formatv_object +// should take ownership and consume it. +inline detail::ErrorAdapter fmt_consume(Error &&Item) { + return detail::ErrorAdapter(std::move(Item)); +} } #endif Index: llvm/trunk/include/llvm/Support/FormatVariadicDetails.h =================================================================== --- llvm/trunk/include/llvm/Support/FormatVariadicDetails.h +++ llvm/trunk/include/llvm/Support/FormatVariadicDetails.h @@ -17,6 +17,7 @@ namespace llvm { template struct format_provider {}; +class Error; namespace detail { class format_adapter { @@ -141,6 +142,12 @@ typename std::enable_if::value, stream_operator_format_adapter>::type build_format_adapter(T &&Item) { + // If the caller passed an Error by value, then stream_operator_format_adapter + // would be responsible for consuming it. + // Make the caller opt into this by calling fmt_consume(). + static_assert( + !std::is_same::type>::value, + "llvm::Error-by-value must be wrapped in fmt_consume() for formatv"); return stream_operator_format_adapter(std::forward(Item)); } Index: llvm/trunk/unittests/Support/FormatVariadicTest.cpp =================================================================== --- llvm/trunk/unittests/Support/FormatVariadicTest.cpp +++ llvm/trunk/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}", fmt_consume(std::move(E1))).str()); + EXPECT_FALSE(E1.isA()); // consumed +}