Index: base/logging.h |
diff --git a/base/logging.h b/base/logging.h |
index ea096d19f729cb9043b0a6fcaea7a935e0d943aa..1ed65f59f7832a24710a138fc0b609feaec88a5d 100644 |
--- a/base/logging.h |
+++ b/base/logging.h |
@@ -480,16 +480,35 @@ const LogSeverity LOG_0 = LOG_ERROR; |
#endif // _PREFAST_ |
+// Captures the result of a CHECK_EQ (for example) and facilitates testing as a |
+// boolean. |
+class CheckOpResult { |
+ public: |
+ // |message| must be null if and only if the check failed. |
+ CheckOpResult(std::string* message) : message_(message) {} |
+ // Returns true if the check succeeded. |
+ operator bool() const { return !message_; } |
+ // Returns the message. |
+ std::string* message() { return message_; } |
+ |
+ private: |
+ std::string* message_; |
+}; |
+ |
// Helper macro for binary operators. |
// Don't use this macro directly in your code, use CHECK_EQ et al below. |
-// |
-// TODO(akalin): Rewrite this so that constructs like if (...) |
-// CHECK_EQ(...) else { ... } work properly. |
-#define CHECK_OP(name, op, val1, val2) \ |
- if (std::string* _result = \ |
- logging::Check##name##Impl((val1), (val2), \ |
- #val1 " " #op " " #val2)) \ |
- logging::LogMessage(__FILE__, __LINE__, _result).stream() |
+// The 'switch' is used to prevent the 'else' from being ambiguous when the |
+// macro is used in an 'if' clause such as: |
+// if (a == 1) |
+// CHECK_EQ(2, a); |
+#define CHECK_OP(name, op, val1, val2) \ |
+ switch (0) case 0: default: \ |
+ if (logging::CheckOpResult true_if_passed = \ |
+ logging::Check##name##Impl((val1), (val2), \ |
+ #val1 " " #op " " #val2)) \ |
+ ; \ |
+ else \ |
+ logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream() |
#endif |
@@ -665,12 +684,20 @@ const LogSeverity LOG_DCHECK = LOG_INFO; |
// Helper macro for binary operators. |
// Don't use this macro directly in your code, use DCHECK_EQ et al below. |
-#define DCHECK_OP(name, op, val1, val2) \ |
- if (DCHECK_IS_ON()) \ |
- if (std::string* _result = logging::Check##name##Impl( \ |
- (val1), (val2), #val1 " " #op " " #val2)) \ |
- logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, _result) \ |
- .stream() |
+// The 'switch' is used to prevent the 'else' from being ambiguous when the |
+// macro is used in an 'if' clause such as: |
+// if (a == 1) |
+// DCHECK_EQ(2, a); |
+#define DCHECK_OP(name, op, val1, val2) \ |
+ switch (0) case 0: default: \ |
+ if (logging::CheckOpResult true_if_passed = \ |
+ DCHECK_IS_ON() ? \ |
+ logging::Check##name##Impl((val1), (val2), \ |
+ #val1 " " #op " " #val2) : nullptr) \ |
+ ; \ |
+ else \ |
+ logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \ |
+ true_if_passed.message()).stream() |
// Equality/Inequality checks - compare two values, and log a |
// LOG_DCHECK message including the two values when the result is not |