llvm.org GIT mirror llvm / ee39f0b
[Support] Require llvm::Error passed to formatv() to be wrapped in fmt_consume() Summary: Someone must be responsible for handling an Error. When formatv takes ownership of an Error, the formatv_object destructor must take care of this. Passing an error by value to formatv() is not considered explicit enough to mark the error as handled (see D49013), so we require callers to use a format adapter to confirm this intent. Reviewers: zturner Subscribers: llvm-commits, lhames Differential Revision: https://reviews.llvm.org/D49170 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336888 91177308-0d34-0410-b5e6-96231b3b80d8 Sam McCall 1 year, 3 months ago
3 changed file(s) with 33 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
1111
1212 #include "llvm/ADT/SmallString.h"
1313 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/Error.h"
1415 #include "llvm/Support/FormatCommon.h"
1516 #include "llvm/Support/FormatVariadicDetails.h"
1617 #include "llvm/Support/raw_ostream.h"
1819 namespace llvm {
1920 template class FormatAdapter : public detail::format_adapter {
2021 protected:
21 explicit FormatAdapter(T &&Item) : Item(Item) {}
22 explicit FormatAdapter(T &&Item) : Item(std::forward(Item)) {}
2223
2324 T Item;
2425 };
7071 }
7172 }
7273 };
74
75 class ErrorAdapter : public FormatAdapter {
76 public:
77 ErrorAdapter(Error &&Item) : FormatAdapter(std::move(Item)) {}
78 ErrorAdapter(ErrorAdapter &&) = default;
79 ~ErrorAdapter() { consumeError(std::move(Item)); }
80 void format(llvm::raw_ostream &Stream, StringRef Style) { Stream << Item; }
81 };
7382 }
7483
7584 template
8796 detail::RepeatAdapter fmt_repeat(T &&Item, size_t Count) {
8897 return detail::RepeatAdapter(std::forward(Item), Count);
8998 }
99
100 // llvm::Error values must be consumed before being destroyed.
101 // Wrapping an error in fmt_consume explicitly indicates that the formatv_object
102 // should take ownership and consume it.
103 inline detail::ErrorAdapter fmt_consume(Error &&Item) {
104 return detail::ErrorAdapter(std::move(Item));
105 }
90106 }
91107
92108 #endif
1616
1717 namespace llvm {
1818 template struct format_provider {};
19 class Error;
1920
2021 namespace detail {
2122 class format_adapter {
140141 typename std::enable_if::value,
141142 stream_operator_format_adapter>::type
142143 build_format_adapter(T &&Item) {
144 // If the caller passed an Error by value, then stream_operator_format_adapter
145 // would be responsible for consuming it.
146 // Make the caller opt into this by calling fmt_consume().
147 static_assert(
148 !std::is_same::type>::value,
149 "llvm::Error-by-value must be wrapped in fmt_consume() for formatv");
143150 return stream_operator_format_adapter(std::forward(Item));
144151 }
145152
77 //===----------------------------------------------------------------------===//
88
99 #include "llvm/Support/FormatVariadic.h"
10 #include "llvm/Support/Error.h"
1011 #include "llvm/Support/FormatAdapters.h"
1112 #include "gtest/gtest.h"
1213
679680 adl::X X;
680681 EXPECT_EQ("X", formatv("{0}", X).str());
681682 }
683
684 TEST(FormatVariadicTest, FormatError) {
685 auto E1 = make_error("X", inconvertibleErrorCode());
686 EXPECT_EQ("X", formatv("{0}", E1).str());
687 EXPECT_TRUE(E1.isA()); // not consumed
688 EXPECT_EQ("X", formatv("{0}", fmt_consume(std::move(E1))).str());
689 EXPECT_FALSE(E1.isA()); // consumed
690 }