[llvm] r336412 - [Support] Make support types more easily printable.
Sam McCall via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 5 22:45:45 PDT 2018
Author: sammccall
Date: Thu Jul 5 22:45:45 2018
New Revision: 336412
URL: http://llvm.org/viewvc/llvm-project?rev=336412&view=rev
Log:
[Support] Make support types more easily printable.
Summary:
Error's new operator<< is the first way to print an error without consuming it.
formatv() can now print objects with an operator<< that works with raw_ostream.
Reviewers: bkramer
Subscribers: mgorny, llvm-commits
Differential Revision: https://reviews.llvm.org/D48966
Modified:
llvm/trunk/include/llvm/Support/Error.h
llvm/trunk/include/llvm/Support/FormatVariadic.h
llvm/trunk/include/llvm/Support/FormatVariadicDetails.h
llvm/trunk/unittests/Support/ErrorTest.cpp
llvm/trunk/unittests/Support/FormatVariadicTest.cpp
Modified: llvm/trunk/include/llvm/Support/Error.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Error.h?rev=336412&r1=336411&r2=336412&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Error.h (original)
+++ llvm/trunk/include/llvm/Support/Error.h Thu Jul 5 22:45:45 2018
@@ -302,6 +302,14 @@ private:
return Tmp;
}
+ friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) {
+ if (auto P = E.getPtr())
+ P->log(OS);
+ else
+ OS << "success";
+ return OS;
+ }
+
ErrorInfoBase *Payload = nullptr;
};
Modified: llvm/trunk/include/llvm/Support/FormatVariadic.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FormatVariadic.h?rev=336412&r1=336411&r2=336412&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FormatVariadic.h (original)
+++ llvm/trunk/include/llvm/Support/FormatVariadic.h Thu Jul 5 22:45:45 2018
@@ -237,6 +237,8 @@ public:
// for type T containing a method whose signature is:
// void format(const T &Obj, raw_ostream &Stream, StringRef Options)
// Then this method is invoked as described in Step 1.
+// 3. If an appropriate operator<< for raw_ostream exists, it will be used.
+// For this to work, (raw_ostream& << const T&) must return raw_ostream&.
//
// If a match cannot be found through either of the above methods, a compiler
// error is generated.
@@ -258,13 +260,6 @@ inline auto formatv(const char *Fmt, Ts
std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...));
}
-// Allow a formatv_object to be formatted (no options supported).
-template <typename T> struct format_provider<formatv_object<T>> {
- static void format(const formatv_object<T> &V, raw_ostream &OS, StringRef) {
- OS << V;
- }
-};
-
} // end namespace llvm
#endif // LLVM_SUPPORT_FORMATVARIADIC_H
Modified: llvm/trunk/include/llvm/Support/FormatVariadicDetails.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FormatVariadicDetails.h?rev=336412&r1=336411&r2=336412&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FormatVariadicDetails.h (original)
+++ llvm/trunk/include/llvm/Support/FormatVariadicDetails.h Thu Jul 5 22:45:45 2018
@@ -38,6 +38,17 @@ public:
}
};
+template <typename T>
+class stream_operator_format_adapter : public format_adapter {
+ T Item;
+
+public:
+ explicit stream_operator_format_adapter(T &&Item)
+ : Item(std::forward<T>(Item)) {}
+
+ void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; }
+};
+
template <typename T> class missing_format_adapter;
// Test if format_provider<T> is defined on T and contains a member function
@@ -59,6 +70,23 @@ public:
(sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1);
};
+// Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
+template <class T> class has_StreamOperator {
+public:
+ using ConstRefT = const typename std::decay<T>::type &;
+
+ template <typename U>
+ static char test(typename std::enable_if<
+ std::is_same<decltype(std::declval<llvm::raw_ostream &>()
+ << std::declval<U>()),
+ llvm::raw_ostream &>::value,
+ int *>::type);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1);
+};
+
// Simple template that decides whether a type T should use the member-function
// based format() invocation.
template <typename T>
@@ -77,15 +105,24 @@ struct uses_format_provider
bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> {
};
+// Simple template that decides whether a type T should use the operator<<
+// based format() invocation. This takes last priority.
+template <typename T>
+struct uses_stream_operator
+ : public std::integral_constant<bool, !uses_format_member<T>::value &&
+ !uses_format_provider<T>::value &&
+ has_StreamOperator<T>::value> {};
+
// Simple template that decides whether a type T has neither a member-function
// nor format_provider based implementation that it can use. Mostly used so
// that the compiler spits out a nice diagnostic when a type with no format
// implementation can be located.
template <typename T>
struct uses_missing_provider
- : public std::integral_constant<bool,
- !uses_format_member<T>::value &&
- !uses_format_provider<T>::value> {};
+ : public std::integral_constant<bool, !uses_format_member<T>::value &&
+ !uses_format_provider<T>::value &&
+ !uses_stream_operator<T>::value> {
+};
template <typename T>
typename std::enable_if<uses_format_member<T>::value, T>::type
@@ -101,6 +138,13 @@ build_format_adapter(T &&Item) {
}
template <typename T>
+typename std::enable_if<uses_stream_operator<T>::value,
+ stream_operator_format_adapter<T>>::type
+build_format_adapter(T &&Item) {
+ return stream_operator_format_adapter<T>(std::forward<T>(Item));
+}
+
+template <typename T>
typename std::enable_if<uses_missing_provider<T>::value,
missing_format_adapter<T>>::type
build_format_adapter(T &&Item) {
Modified: llvm/trunk/unittests/Support/ErrorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorTest.cpp?rev=336412&r1=336411&r2=336412&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/ErrorTest.cpp (original)
+++ llvm/trunk/unittests/Support/ErrorTest.cpp Thu Jul 5 22:45:45 2018
@@ -32,7 +32,7 @@ public:
// Log this error to a stream.
void log(raw_ostream &OS) const override {
- OS << "CustomError { " << getInfo() << "}";
+ OS << "CustomError {" << getInfo() << "}";
}
std::error_code convertToErrorCode() const override {
@@ -702,25 +702,44 @@ TEST(Error, ErrorMessage) {
EXPECT_EQ(toString(Error::success()).compare(""), 0);
Error E1 = make_error<CustomError>(0);
- EXPECT_EQ(toString(std::move(E1)).compare("CustomError { 0}"), 0);
+ EXPECT_EQ(toString(std::move(E1)).compare("CustomError {0}"), 0);
Error E2 = make_error<CustomError>(0);
handleAllErrors(std::move(E2), [](const CustomError &CE) {
- EXPECT_EQ(CE.message().compare("CustomError { 0}"), 0);
+ EXPECT_EQ(CE.message().compare("CustomError {0}"), 0);
});
Error E3 = joinErrors(make_error<CustomError>(0), make_error<CustomError>(1));
EXPECT_EQ(toString(std::move(E3))
- .compare("CustomError { 0}\n"
- "CustomError { 1}"),
+ .compare("CustomError {0}\n"
+ "CustomError {1}"),
0);
}
+TEST(Error, Stream) {
+ {
+ Error OK = Error::success();
+ std::string Buf;
+ llvm::raw_string_ostream S(Buf);
+ S << OK;
+ EXPECT_EQ("success", S.str());
+ consumeError(std::move(OK));
+ }
+ {
+ Error E1 = make_error<CustomError>(0);
+ std::string Buf;
+ llvm::raw_string_ostream S(Buf);
+ S << E1;
+ EXPECT_EQ("CustomError {0}", S.str());
+ consumeError(std::move(E1));
+ }
+}
+
TEST(Error, ErrorMatchers) {
EXPECT_THAT_ERROR(Error::success(), Succeeded());
EXPECT_NONFATAL_FAILURE(
EXPECT_THAT_ERROR(make_error<CustomError>(0), Succeeded()),
- "Expected: succeeded\n Actual: failed (CustomError { 0})");
+ "Expected: succeeded\n Actual: failed (CustomError {0})");
EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed());
EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()),
@@ -748,14 +767,14 @@ TEST(Error, ErrorMatchers) {
Failed<CustomError>(testing::Property(&CustomError::getInfo, 1))),
"Expected: failed with Error of given type and the error is an object "
"whose given property is equal to 1\n"
- " Actual: failed (CustomError { 0})");
+ " Actual: failed (CustomError {0})");
EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<ErrorInfoBase>());
EXPECT_THAT_EXPECTED(Expected<int>(0), Succeeded());
EXPECT_NONFATAL_FAILURE(
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
Succeeded()),
- "Expected: succeeded\n Actual: failed (CustomError { 0})");
+ "Expected: succeeded\n Actual: failed (CustomError {0})");
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), Failed());
EXPECT_NONFATAL_FAILURE(
@@ -767,7 +786,7 @@ TEST(Error, ErrorMatchers) {
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
HasValue(0)),
"Expected: succeeded with value (is equal to 0)\n"
- " Actual: failed (CustomError { 0})");
+ " Actual: failed (CustomError {0})");
EXPECT_NONFATAL_FAILURE(
EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(0)),
"Expected: succeeded with value (is equal to 0)\n"
@@ -787,7 +806,7 @@ TEST(Error, ErrorMatchers) {
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
HasValue(testing::Gt(1))),
"Expected: succeeded with value (is > 1)\n"
- " Actual: failed (CustomError { 0})");
+ " Actual: failed (CustomError {0})");
}
} // end anon namespace
Modified: llvm/trunk/unittests/Support/FormatVariadicTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/FormatVariadicTest.cpp?rev=336412&r1=336411&r2=336412&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/FormatVariadicTest.cpp (original)
+++ llvm/trunk/unittests/Support/FormatVariadicTest.cpp Thu Jul 5 22:45:45 2018
@@ -671,3 +671,12 @@ TEST(FormatVariadicTest, CopiesAndMoves)
EXPECT_EQ(0, R.Copied);
EXPECT_EQ(0, R.Moved);
}
+
+namespace adl {
+struct X {};
+raw_ostream &operator<<(raw_ostream &OS, const X &) { return OS << "X"; }
+} // namespace adl
+TEST(FormatVariadicTest, FormatStreamable) {
+ adl::X X;
+ EXPECT_EQ("X", formatv("{0}", X).str());
+}
More information about the llvm-commits
mailing list