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

Unified Diff: base/logging.h

Issue 2561963002: base: Remove the string logging from CHECK(). (Closed)
Patch Set: checkstring: rebase Created 4 years 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
Index: base/logging.h
diff --git a/base/logging.h b/base/logging.h
index ce87a5351f7877245f673fb1b255986be95a5bda..8bafc48d9aaa4f2fec7ffa610a114bfee4ab2402 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -57,9 +57,8 @@
//
// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
//
-// The CHECK(condition) macro is active in both debug and release builds and
-// effectively performs a LOG(FATAL) which terminates the process and
-// generates a crashdump unless a debugger is attached.
+// LOG(FATAL) acts like a CHECK(condition) with additional logging info, though
+// this comes at a cost to binary size and codegen.
//
// There are also "debug mode" logging macros like the ones above:
//
@@ -125,7 +124,6 @@
// DPLOG(ERROR) << "Couldn't do foo";
// PLOG_IF(ERROR, cond) << "Couldn't do foo";
// DPLOG_IF(ERROR, cond) << "Couldn't do foo";
-// PCHECK(condition) << "Couldn't do foo";
// DPCHECK(condition) << "Couldn't do foo";
//
// which append the last system error to the message in string form (taken from
@@ -346,8 +344,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
#endif
// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
-// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
-// always fire if they fail.
+// LOG_IS_ON(DFATAL) always holds in debug mode.
#define LOG_IS_ON(severity) \
(::logging::ShouldCreateLogMessage(::logging::LOG_##severity))
@@ -464,178 +461,51 @@ class CheckOpResult {
#define OOM_CRASH() IMMEDIATE_CRASH()
#endif
-// CHECK dies with a fatal error if condition is not true. It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
-// compilation mode.
+// CHECK dies with a fatal error if condition is not true. It is always
+// enabled in every compilation mode, unlike DCHECK which is conditionally
+// disabled in release builds.
//
// We make sure CHECK et al. always evaluates their arguments, as
// doing CHECK(FunctionWithSideEffect()) is a common idiom.
-#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
-
-// Make all CHECK functions discard their log strings to reduce code bloat, and
-// improve performance, for official release builds.
-//
-// This is not calling BreakDebugger since this is called frequently, and
-// calling an out-of-line function instead of a noreturn inline macro prevents
-// compiler optimizations.
-#define CHECK(condition) \
- !(condition) ? IMMEDIATE_CRASH() : EAT_STREAM_PARAMETERS
-
-#define PCHECK(condition) CHECK(condition)
-
-#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
-
-#else // !(OFFICIAL_BUILD && NDEBUG)
-
+// _PREFAST_ is true when the code is being analyzed bythe PREfast analysis
+// tool.
#if defined(_PREFAST_) && defined(OS_WIN)
// Use __analysis_assume to tell the VC++ static analysis engine that
-// assert conditions are true, to suppress warnings. The LAZY_STREAM
-// parameter doesn't reference 'condition' in /analyze builds because
-// this evaluation confuses /analyze. The !! before condition is because
-// __analysis_assume gets confused on some conditions:
+// assert conditions are true, to suppress warnings. The !! before condition is
+// because __analysis_assume gets confused on some conditions:
// http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/
-#define CHECK(condition) \
- __analysis_assume(!!(condition)), \
- LAZY_STREAM(LOG_STREAM(FATAL), false) \
- << "Check failed: " #condition ". "
-
-#define PCHECK(condition) \
- __analysis_assume(!!(condition)), \
- LAZY_STREAM(PLOG_STREAM(FATAL), false) \
- << "Check failed: " #condition ". "
-
-#else // _PREFAST_
-
-// Do as much work as possible out of line to reduce inline code size.
-#define CHECK(condition) \
- LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
- !(condition))
+#define CHECK(condition) \
+ __analysis_assume(!!(condition)), ((condition ? (void)0 : (void)0)
-#define PCHECK(condition) \
- LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
- << "Check failed: " #condition ". "
+#define PCHECK(condition) \
+ __analysis_assume(!!(condition)), ((condition) ? (void)0 : (void)0)
-#endif // _PREFAST_
+#else
-// Helper macro for binary operators.
-// Don't use this macro directly in your code, use CHECK_EQ et al below.
-// 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 // !(OFFICIAL_BUILD && NDEBUG)
-
-// This formats a value for a failing CHECK_XX statement. Ordinarily,
-// it uses the definition for operator<<, with a few special cases below.
-template <typename T>
-inline typename std::enable_if<
- base::internal::SupportsOstreamOperator<const T&>::value &&
- !std::is_function<typename std::remove_pointer<T>::type>::value,
- void>::type
-MakeCheckOpValueString(std::ostream* os, const T& v) {
- (*os) << v;
-}
+// Unlike DCHECK(), the CHECK() command does not accept a logging string, as
+// doing so causes poorer codegen on MSVC (see
+// https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/TL0NkNXIT1w/mbMCKqymBQAJ
+// for more details).
+//
+// This is not calling BreakDebugger since this is called frequently, and
+// calling an out-of-line function instead of a noreturn inline macro prevents
+// compiler optimizations.
+#define CHECK(condition) (!(condition) ? IMMEDIATE_CRASH() : (void)0)
-// Provide an overload for functions and function pointers. Function pointers
-// don't implicitly convert to void* but do implicitly convert to bool, so
-// without this function pointers are always printed as 1 or 0. (MSVC isn't
-// standards-conforming here and converts function pointers to regular
-// pointers, so this is a no-op for MSVC.)
-template <typename T>
-inline typename std::enable_if<
- std::is_function<typename std::remove_pointer<T>::type>::value,
- void>::type
-MakeCheckOpValueString(std::ostream* os, const T& v) {
- (*os) << reinterpret_cast<const void*>(v);
-}
+#define PCHECK(condition) CHECK(condition)
-// We need overloads for enums that don't support operator<<.
-// (i.e. scoped enums where no operator<< overload was declared).
-template <typename T>
-inline typename std::enable_if<
- !base::internal::SupportsOstreamOperator<const T&>::value &&
- std::is_enum<T>::value,
- void>::type
-MakeCheckOpValueString(std::ostream* os, const T& v) {
- (*os) << static_cast<typename base::underlying_type<T>::type>(v);
-}
+#endif // !(_PREFAST_ && OS_WIN)
-// We need an explicit overload for std::nullptr_t.
-BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p);
-
-// Build the error message string. This is separate from the "Impl"
-// function template because it is not performance critical and so can
-// be out of line, while the "Impl" code should be inline. Caller
-// takes ownership of the returned string.
-template<class t1, class t2>
-std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
- std::ostringstream ss;
- ss << names << " (";
- MakeCheckOpValueString(&ss, v1);
- ss << " vs. ";
- MakeCheckOpValueString(&ss, v2);
- ss << ")";
- std::string* msg = new std::string(ss.str());
- return msg;
-}
-
-// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
-// in logging.cc.
-extern template BASE_EXPORT std::string* MakeCheckOpString<int, int>(
- const int&, const int&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<unsigned long, unsigned long>(
- const unsigned long&, const unsigned long&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<unsigned long, unsigned int>(
- const unsigned long&, const unsigned int&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<unsigned int, unsigned long>(
- const unsigned int&, const unsigned long&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<std::string, std::string>(
- const std::string&, const std::string&, const char* name);
-
-// Helper functions for CHECK_OP macro.
-// The (int, int) specialization works around the issue that the compiler
-// will not instantiate the template version of the function on values of
-// unnamed enum type - see comment below.
-#define DEFINE_CHECK_OP_IMPL(name, op) \
- template <class t1, class t2> \
- inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
- const char* names) { \
- if (v1 op v2) return NULL; \
- else return ::logging::MakeCheckOpString(v1, v2, names); \
- } \
- inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
- if (v1 op v2) return NULL; \
- else return ::logging::MakeCheckOpString(v1, v2, names); \
- }
-DEFINE_CHECK_OP_IMPL(EQ, ==)
-DEFINE_CHECK_OP_IMPL(NE, !=)
-DEFINE_CHECK_OP_IMPL(LE, <=)
-DEFINE_CHECK_OP_IMPL(LT, < )
-DEFINE_CHECK_OP_IMPL(GE, >=)
-DEFINE_CHECK_OP_IMPL(GT, > )
-#undef DEFINE_CHECK_OP_IMPL
-
-#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
-#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
-#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
-#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
-#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
-#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
+// These exist for symmetry with DCHECK, though they also do not produce any
+// string output.
+#define CHECK_EQ(val1, val2) CHECK((val1) == (val2))
+#define CHECK_NE(val1, val2) CHECK((val1) != (val2))
+#define CHECK_LE(val1, val2) CHECK((val1) <= (val2))
+#define CHECK_LT(val1, val2) CHECK((val1) < (val2))
+#define CHECK_GE(val1, val2) CHECK((val1) >= (val2))
+#define CHECK_GT(val1, val2) CHECK((val1) > (val2))
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
#define DCHECK_IS_ON() 0
@@ -735,6 +605,111 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
#endif // _PREFAST_
+// We need an explicit overload for std::nullptr_t.
+BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p);
+
+// This formats a value for a failing DCHECK_XX statement. Ordinarily,
+// it uses the definition for operator<<, with a few special cases below.
+template <typename T>
+inline typename std::enable_if<
+ base::internal::SupportsOstreamOperator<const T&>::value &&
+ !std::is_function<typename std::remove_pointer<T>::type>::value,
+ void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << v;
+}
+
+// Provide an overload for functions and function pointers. Function pointers
+// don't implicitly convert to void* but do implicitly convert to bool, so
+// without this function pointers are always printed as 1 or 0. (MSVC isn't
+// standards-conforming here and converts function pointers to regular
+// pointers, so this is a no-op for MSVC.)
+template <typename T>
+inline typename std::enable_if<
+ std::is_function<typename std::remove_pointer<T>::type>::value,
+ void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << reinterpret_cast<const void*>(v);
+}
+
+// We need overloads for enums that don't support operator<<.
+// (i.e. scoped enums where no operator<< overload was declared).
+template <typename T>
+inline typename std::enable_if<
+ !base::internal::SupportsOstreamOperator<const T&>::value &&
+ std::is_enum<T>::value,
+ void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << static_cast<typename base::underlying_type<T>::type>(v);
+}
+
+// We need an explicit overload for std::nullptr_t.
+BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p);
+
+// Build the error message string. This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline. Caller
+// takes ownership of the returned string.
+template <class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+ std::ostringstream ss;
+ ss << names << " (";
+ MakeCheckOpValueString(&ss, v1);
+ ss << " vs. ";
+ MakeCheckOpValueString(&ss, v2);
+ ss << ")";
+ std::string* msg = new std::string(ss.str());
+ return msg;
+}
+
+// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
+// in logging.cc.
+extern template BASE_EXPORT std::string*
+MakeCheckOpString<int, int>(const int&, const int&, const char* names);
+extern template BASE_EXPORT std::string*
+MakeCheckOpString<unsigned long, unsigned long>(const unsigned long&,
+ const unsigned long&,
+ const char* names);
+extern template BASE_EXPORT std::string*
+MakeCheckOpString<unsigned long, unsigned int>(const unsigned long&,
+ const unsigned int&,
+ const char* names);
+extern template BASE_EXPORT std::string*
+MakeCheckOpString<unsigned int, unsigned long>(const unsigned int&,
+ const unsigned long&,
+ const char* names);
+extern template BASE_EXPORT std::string*
+MakeCheckOpString<std::string, std::string>(const std::string&,
+ const std::string&,
+ const char* name);
+
+// Helper functions for DCHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_DCHECK_OP_IMPL(name, op) \
+ template <class t1, class t2> \
+ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+ const char* names) { \
+ if (v1 op v2) \
+ return NULL; \
+ else \
+ return ::logging::MakeCheckOpString(v1, v2, names); \
+ } \
+ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+ if (v1 op v2) \
+ return NULL; \
+ else \
+ return ::logging::MakeCheckOpString(v1, v2, names); \
+ }
+DEFINE_DCHECK_OP_IMPL(EQ, ==)
+DEFINE_DCHECK_OP_IMPL(NE, !=)
+DEFINE_DCHECK_OP_IMPL(LE, <=)
+DEFINE_DCHECK_OP_IMPL(LT, <)
+DEFINE_DCHECK_OP_IMPL(GE, >=)
+DEFINE_DCHECK_OP_IMPL(GT, >)
+#undef DEFINE_DCHECK_OP_IMPL
+
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
// The 'switch' is used to prevent the 'else' from being ambiguous when the

Powered by Google App Engine
This is Rietveld 408576698