| 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
|
|
|