Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Unified Diff: base/logging.h

Issue 1193873004: Make CHECK_EQ and friends work properly in an if/else structure without braces. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add commentary. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | base/logging_unittest.cc » ('j') | base/logging_unittest.cc » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/logging.h
diff --git a/base/logging.h b/base/logging.h
index ea096d19f729cb9043b0a6fcaea7a935e0d943aa..bd1e7fb59502f99ee06e28dedcdfcc466bc2a567 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -480,16 +480,37 @@ 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_;
+};
Nico 2015/07/06 22:41:52 why is this needed?
erikwright (departed) 2015/07/07 17:25:08 It allows us to both store the result of logging::
+
// 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 'if' from being ambiguous when the macro
+// is used in an 'else' clause such as:
+// if (a == 1)
+// statement;
+// else
+// DCHECK_EQ(2, a);
danakj 2015/07/06 22:38:26 But else if works fine, what is ambiguous?
Nico 2015/07/07 16:59:43 I think the example is wrong and it's supposed to
erikwright (departed) 2015/07/07 17:25:08 You're correct, the example is wrong. I'm updating
+#define CHECK_OP(name, op, val1, val2) \
Nico 2015/07/06 22:41:52 isn't the usual pattern for this do { /* stuff
danakj 2015/07/06 22:43:27 Ya, that's what I've seen elsewhere too.
erikwright (departed) 2015/07/07 17:25:08 That doesn't work because you need the possible '<
+ switch (0) case 0: default: \
+ if (logging::CheckOpResult _result = \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2)) \
+ ; \
+ else \
+ logging::LogMessage(__FILE__, __LINE__, _result.message()).stream()
#endif
@@ -665,12 +686,22 @@ 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 'if' from being ambiguous when the macro
+// is used in an 'else' clause such as:
+// if (a == 1)
+// statement;
+// else
+// DCHECK_EQ(2, a);
+#define DCHECK_OP(name, op, val1, val2) \
+ switch (0) case 0: default: \
+ if (logging::CheckOpResult _result = \
+ DCHECK_IS_ON() ? \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2) : nullptr) \
+ ; \
+ else \
+ logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \
+ _result.message()).stream()
// Equality/Inequality checks - compare two values, and log a
// LOG_DCHECK message including the two values when the result is not
« no previous file with comments | « no previous file | base/logging_unittest.cc » ('j') | base/logging_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698