summaryrefslogtreecommitdiff
path: root/base/logging.h
diff options
context:
space:
mode:
authorJay Civelli <jcivelli@google.com>2017-03-22 17:31:44 -0700
committerTreehugger Robot <treehugger-gerrit@google.com>2017-07-26 01:47:45 +0000
commit0601274935e7f632eb0d6ce0fd223b744349d20b (patch)
tree09642629eabdbeccfd68e6338253228465088c57 /base/logging.h
parentf320c0cf71af274e34404746d4303e6a2452e2d6 (diff)
downloadlibchrome-0601274935e7f632eb0d6ce0fd223b744349d20b.tar.gz
libchrome: Uprev the library to r456626 from Chromium
Pulled the latest and greatest version of libchrome from Chromium. The merge was done against r456626 which corresponds to git commit 08266b3fca707804065a2cfd60331722ade41969 of Mar 14, 2017 Notable changes are: - FOR_EACH_OBSERVER macro removed (replaced by use of C++ 11 range-base for loop) - base::Values no more FundamentalValue - stl_util moved to base namespace - some scoped pointers removed in crypto/ in favor of BoringSSL UniquePtr. - path() accessor renamed to GetPath() in ScopedTempDir (and other classes) - introduction of base::CallbackOnce Test: All unit-tests should still pass. Change-Id: I5c2cb41ea4c037fe69fbb425e711b1399d55d591
Diffstat (limited to 'base/logging.h')
-rw-r--r--base/logging.h402
1 files changed, 270 insertions, 132 deletions
diff --git a/base/logging.h b/base/logging.h
index 2bfc972601..7ca018e227 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -15,6 +15,7 @@
#include <utility>
#include "base/base_export.h"
+#include "base/compiler_specific.h"
#include "base/debug/debugger.h"
#include "base/macros.h"
#include "base/template_util.h"
@@ -140,34 +141,6 @@
// There is the special severity of DFATAL, which logs FATAL in debug mode,
// ERROR in normal mode.
-// Note that "The behavior of a C++ program is undefined if it adds declarations
-// or definitions to namespace std or to a namespace within namespace std unless
-// otherwise specified." --C++11[namespace.std]
-//
-// We've checked that this particular definition has the intended behavior on
-// our implementations, but it's prone to breaking in the future, and please
-// don't imitate this in your own definitions without checking with some
-// standard library experts.
-namespace std {
-// These functions are provided as a convenience for logging, which is where we
-// use streams (it is against Google style to use streams in other places). It
-// is designed to allow you to emit non-ASCII Unicode strings to the log file,
-// which is normally ASCII. It is relatively slow, so try not to use it for
-// common cases. Non-ASCII characters will be converted to UTF-8 by these
-// operators.
-BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
-inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
- return out << wstr.c_str();
-}
-
-template<typename T>
-typename std::enable_if<std::is_enum<T>::value, std::ostream&>::type operator<<(
- std::ostream& out, T value) {
- return out << static_cast<typename std::underlying_type<T>::type>(value);
-}
-
-} // namespace std
-
namespace logging {
// TODO(avi): do we want to do a unification of character types here?
@@ -337,15 +310,16 @@ const LogSeverity LOG_DFATAL = LOG_FATAL;
// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
// better to have compact code for these operations.
#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
- logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__)
-#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
- logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_INFO, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_WARNING, \
+ ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
- logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_ERROR, ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
- logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_FATAL, ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
- logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__)
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_DFATAL, ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_INFO \
COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
@@ -406,7 +380,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
// The VLOG macros log with negative verbosities.
#define VLOG_STREAM(verbose_level) \
- logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+ ::logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
#define VLOG(verbose_level) \
LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
@@ -417,11 +391,11 @@ const LogSeverity LOG_0 = LOG_ERROR;
#if defined (OS_WIN)
#define VPLOG_STREAM(verbose_level) \
- logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
::logging::GetLastSystemErrorCode()).stream()
#elif defined(OS_POSIX)
#define VPLOG_STREAM(verbose_level) \
- logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
::logging::GetLastSystemErrorCode()).stream()
#endif
@@ -434,7 +408,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
-#define LOG_ASSERT(condition) \
+#define LOG_ASSERT(condition) \
LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
#if defined(OS_WIN)
@@ -453,9 +427,23 @@ const LogSeverity LOG_0 = LOG_ERROR;
#define PLOG_IF(severity, condition) \
LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
-// The actual stream used isn't important.
-#define EAT_STREAM_PARAMETERS \
- true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+BASE_EXPORT extern std::ostream* g_swallow_stream;
+
+// Note that g_swallow_stream is used instead of an arbitrary LOG() stream to
+// avoid the creation of an object with a non-trivial destructor (LogMessage).
+// On MSVC x86 (checked on 2015 Update 3), this causes a few additional
+// pointless instructions to be emitted even at full optimization level, even
+// though the : arm of the ternary operator is clearly never executed. Using a
+// simpler object to be &'d with Voidify() avoids these extra instructions.
+// Using a simpler POD object with a templated operator<< also works to avoid
+// these instructions. However, this causes warnings on statically defined
+// implementations of operator<<(std::ostream, ...) in some .cc files, because
+// they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an
+// ostream* also is not suitable, because some compilers warn of undefined
+// behavior.
+#define EAT_STREAM_PARAMETERS \
+ true ? (void)0 \
+ : ::logging::LogMessageVoidify() & (*::logging::g_swallow_stream)
// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
// boolean.
@@ -472,6 +460,84 @@ class CheckOpResult {
std::string* message_;
};
+// Crashes in the fastest possible way with no attempt at logging.
+// There are different constraints to satisfy here, see http://crbug.com/664209
+// for more context:
+// - The trap instructions, and hence the PC value at crash time, have to be
+// distinct and not get folded into the same opcode by the compiler.
+// On Linux/Android this is tricky because GCC still folds identical
+// asm volatile blocks. The workaround is generating distinct opcodes for
+// each CHECK using the __COUNTER__ macro.
+// - The debug info for the trap instruction has to be attributed to the source
+// line that has the CHECK(), to make crash reports actionable. This rules
+// out the ability of using a inline function, at least as long as clang
+// doesn't support attribute(artificial).
+// - Failed CHECKs should produce a signal that is distinguishable from an
+// invalid memory access, to improve the actionability of crash reports.
+// - The compiler should treat the CHECK as no-return instructions, so that the
+// trap code can be efficiently packed in the prologue of the function and
+// doesn't interfere with the main execution flow.
+// - When debugging, developers shouldn't be able to accidentally step over a
+// CHECK. This is achieved by putting opcodes that will cause a non
+// continuable exception after the actual trap instruction.
+// - Don't cause too much binary bloat.
+#if defined(COMPILER_GCC)
+
+#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL)
+// int 3 will generate a SIGTRAP.
+#define TRAP_SEQUENCE() \
+ asm volatile( \
+ "int3; ud2; push %0;" ::"i"(static_cast<unsigned char>(__COUNTER__)))
+
+#elif defined(ARCH_CPU_ARMEL) && !defined(OS_NACL)
+// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running
+// as a 32 bit userspace app on arm64. There doesn't seem to be any way to
+// cause a SIGTRAP from userspace without using a syscall (which would be a
+// problem for sandboxing).
+#define TRAP_SEQUENCE() \
+ asm volatile("bkpt #0; udf %0;" ::"i"(__COUNTER__ % 256))
+
+#elif defined(ARCH_CPU_ARM64) && !defined(OS_NACL)
+// This will always generate a SIGTRAP on arm64.
+#define TRAP_SEQUENCE() \
+ asm volatile("brk #0; hlt %0;" ::"i"(__COUNTER__ % 65536))
+
+#else
+// Crash report accuracy will not be guaranteed on other architectures, but at
+// least this will crash as expected.
+#define TRAP_SEQUENCE() __builtin_trap()
+#endif // ARCH_CPU_*
+
+#define IMMEDIATE_CRASH() \
+ ({ \
+ TRAP_SEQUENCE(); \
+ __builtin_unreachable(); \
+ })
+
+#elif defined(COMPILER_MSVC)
+
+// Clang is cleverer about coalescing int3s, so we need to add a unique-ish
+// instruction following the __debugbreak() to have it emit distinct locations
+// for CHECKs rather than collapsing them all together. It would be nice to use
+// a short intrinsic to do this (and perhaps have only one implementation for
+// both clang and MSVC), however clang-cl currently does not support intrinsics.
+// On the flip side, MSVC x64 doesn't support inline asm. So, we have to have
+// two implementations. Normally clang-cl's version will be 5 bytes (1 for
+// `int3`, 2 for `ud2`, 2 for `push byte imm`, however, TODO(scottmg):
+// https://crbug.com/694670 clang-cl doesn't currently support %'ing
+// __COUNTER__, so eventually it will emit the dword form of push.
+// TODO(scottmg): Reinvestigate a short sequence that will work on both
+// compilers once clang supports more intrinsics. See https://crbug.com/693713.
+#if defined(__clang__)
+#define IMMEDIATE_CRASH() ({__asm int 3 __asm ud2 __asm push __COUNTER__})
+#else
+#define IMMEDIATE_CRASH() __debugbreak()
+#endif // __clang__
+
+#else
+#error Port
+#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.
@@ -481,20 +547,14 @@ class CheckOpResult {
#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.
-
-#if defined(COMPILER_GCC) || __clang__
-#define LOGGING_CRASH() __builtin_trap()
-#else
-#define LOGGING_CRASH() ((void)(*(volatile char*)0 = 0))
-#endif
-
+// 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) ? LOGGING_CRASH() : EAT_STREAM_PARAMETERS
+#define CHECK(condition) \
+ UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_STREAM_PARAMETERS
#define PCHECK(condition) CHECK(condition)
@@ -510,26 +570,26 @@ class CheckOpResult {
// __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 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 ". "
+#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(), \
+#define CHECK(condition) \
+ LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
!(condition))
#define PCHECK(condition) \
LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
- << "Check failed: " #condition ". "
+ << "Check failed: " #condition ". "
#endif // _PREFAST_
@@ -541,12 +601,12 @@ class CheckOpResult {
// 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)) \
+ 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()
+ ::logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
#endif // !(OFFICIAL_BUILD && NDEBUG)
@@ -554,12 +614,26 @@ class CheckOpResult {
// 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,
+ 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>
@@ -611,16 +685,20 @@ std::string* MakeCheckOpString<std::string, std::string>(
// 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 MakeCheckOpString(v1, v2, names); \
- } \
+#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 MakeCheckOpString(v1, v2, names); \
+ if (v1 op v2) \
+ return NULL; \
+ else \
+ return ::logging::MakeCheckOpString(v1, v2, names); \
}
DEFINE_CHECK_OP_IMPL(EQ, ==)
DEFINE_CHECK_OP_IMPL(NE, !=)
@@ -638,12 +716,6 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
-#define ENABLE_DLOG 0
-#else
-#define ENABLE_DLOG 1
-#endif
-
-#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
#define DCHECK_IS_ON() 0
#else
#define DCHECK_IS_ON() 1
@@ -651,7 +723,7 @@ DEFINE_CHECK_OP_IMPL(GT, > )
// Definitions for DLOG et al.
-#if ENABLE_DLOG
+#if DCHECK_IS_ON()
#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
@@ -660,12 +732,11 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
-#else // ENABLE_DLOG
+#else // DCHECK_IS_ON()
-// If ENABLE_DLOG is off, we want to avoid emitting any references to
-// |condition| (which may reference a variable defined only if NDEBUG
-// is not defined). Contrast this with DCHECK et al., which has
-// different behavior.
+// If !DCHECK_IS_ON(), we want to avoid emitting any references to |condition|
+// (which may reference a variable defined only if DCHECK_IS_ON()).
+// Contrast this with DCHECK et al., which has different behavior.
#define DLOG_IS_ON(severity) false
#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
@@ -674,19 +745,7 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
-#endif // ENABLE_DLOG
-
-// DEBUG_MODE is for uses like
-// if (DEBUG_MODE) foo.CheckThatFoo();
-// instead of
-// #ifndef NDEBUG
-// foo.CheckThatFoo();
-// #endif
-//
-// We tie its state to ENABLE_DLOG.
-enum { DEBUG_MODE = ENABLE_DLOG };
-
-#undef ENABLE_DLOG
+#endif // DCHECK_IS_ON()
#define DLOG(severity) \
LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
@@ -721,31 +780,63 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// whether DCHECKs are enabled; this is so that we don't get unused
// variable warnings if the only use of a variable is in a DCHECK.
// This behavior is different from DLOG_IF et al.
+//
+// Note that the definition of the DCHECK macros depends on whether or not
+// DCHECK_IS_ON() is true. When DCHECK_IS_ON() is false, the macros use
+// EAT_STREAM_PARAMETERS to avoid expressions that would create temporaries.
#if defined(_PREFAST_) && defined(OS_WIN)
// See comments on the previous use of __analysis_assume.
-#define DCHECK(condition) \
- __analysis_assume(!!(condition)), \
- LAZY_STREAM(LOG_STREAM(DCHECK), false) \
- << "Check failed: " #condition ". "
+#define DCHECK(condition) \
+ __analysis_assume(!!(condition)), \
+ LAZY_STREAM(LOG_STREAM(DCHECK), false) \
+ << "Check failed: " #condition ". "
-#define DPCHECK(condition) \
- __analysis_assume(!!(condition)), \
- LAZY_STREAM(PLOG_STREAM(DCHECK), false) \
- << "Check failed: " #condition ". "
+#define DPCHECK(condition) \
+ __analysis_assume(!!(condition)), \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), false) \
+ << "Check failed: " #condition ". "
-#else // _PREFAST_
+#elif defined(__clang_analyzer__)
+
+// Keeps the static analyzer from proceeding along the current codepath,
+// otherwise false positive errors may be generated by null pointer checks.
+inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
+ return false;
+}
-#define DCHECK(condition) \
- LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+#define DCHECK(condition) \
+ LAZY_STREAM( \
+ LOG_STREAM(DCHECK), \
+ DCHECK_IS_ON() ? (logging::AnalyzerNoReturn() || !(condition)) : false) \
<< "Check failed: " #condition ". "
-#define DPCHECK(condition) \
- LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+#define DPCHECK(condition) \
+ LAZY_STREAM( \
+ PLOG_STREAM(DCHECK), \
+ DCHECK_IS_ON() ? (logging::AnalyzerNoReturn() || !(condition)) : false) \
<< "Check failed: " #condition ". "
-#endif // _PREFAST_
+#else
+
+#if DCHECK_IS_ON()
+
+#define DCHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(DCHECK), !(condition)) \
+ << "Check failed: " #condition ". "
+#define DPCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), !(condition)) \
+ << "Check failed: " #condition ". "
+
+#else // DCHECK_IS_ON()
+
+#define DCHECK(condition) EAT_STREAM_PARAMETERS << !(condition)
+#define DPCHECK(condition) EAT_STREAM_PARAMETERS << !(condition)
+
+#endif // DCHECK_IS_ON()
+
+#endif
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
@@ -753,16 +844,37 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// 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()
+#if DCHECK_IS_ON()
+
+#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()
+
+#else // DCHECK_IS_ON()
+
+// When DCHECKs aren't enabled, DCHECK_OP still needs to reference operator<<
+// overloads for |val1| and |val2| to avoid potential compiler warnings about
+// unused functions. For the same reason, it also compares |val1| and |val2|
+// using |op|.
+//
+// Note that the contract of DCHECK_EQ, etc is that arguments are only evaluated
+// once. Even though |val1| and |val2| appear twice in this version of the macro
+// expansion, this is OK, since the expression is never actually evaluated.
+#define DCHECK_OP(name, op, val1, val2) \
+ EAT_STREAM_PARAMETERS << (::logging::MakeCheckOpValueString( \
+ ::logging::g_swallow_stream, val1), \
+ ::logging::MakeCheckOpValueString( \
+ ::logging::g_swallow_stream, val2), \
+ (val1)op(val2))
+
+#endif // DCHECK_IS_ON()
// Equality/Inequality checks - compare two values, and log a
// LOG_DCHECK message including the two values when the result is not
@@ -770,7 +882,7 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// defined.
//
// You may append to the error message like so:
-// DCHECK_NE(1, 2) << ": The world must be ending!";
+// DCHECK_NE(1, 2) << "The world must be ending!";
//
// We are very careful to ensure that each argument is evaluated exactly
// once, and that anything which is legal to pass as a function argument is
@@ -834,6 +946,9 @@ class BASE_EXPORT LogMessage {
std::ostream& stream() { return stream_; }
+ LogSeverity severity() { return severity_; }
+ std::string str() { return stream_.str(); }
+
private:
void Init(const char* file, int line);
@@ -941,12 +1056,14 @@ BASE_EXPORT void CloseLogFile();
// Async signal safe logging mechanism.
BASE_EXPORT void RawLog(int level, const char* message);
-#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message)
+#define RAW_LOG(level, message) \
+ ::logging::RawLog(::logging::LOG_##level, message)
-#define RAW_CHECK(condition) \
- do { \
- if (!(condition)) \
- logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \
+#define RAW_CHECK(condition) \
+ do { \
+ if (!(condition)) \
+ ::logging::RawLog(::logging::LOG_FATAL, \
+ "Check failed: " #condition "\n"); \
} while (0)
#if defined(OS_WIN)
@@ -959,6 +1076,27 @@ BASE_EXPORT std::wstring GetLogFileFullPath();
} // namespace logging
+// Note that "The behavior of a C++ program is undefined if it adds declarations
+// or definitions to namespace std or to a namespace within namespace std unless
+// otherwise specified." --C++11[namespace.std]
+//
+// We've checked that this particular definition has the intended behavior on
+// our implementations, but it's prone to breaking in the future, and please
+// don't imitate this in your own definitions without checking with some
+// standard library experts.
+namespace std {
+// These functions are provided as a convenience for logging, which is where we
+// use streams (it is against Google style to use streams in other places). It
+// is designed to allow you to emit non-ASCII Unicode strings to the log file,
+// which is normally ASCII. It is relatively slow, so try not to use it for
+// common cases. Non-ASCII characters will be converted to UTF-8 by these
+// operators.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
+inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
+ return out << wstr.c_str();
+}
+} // namespace std
+
// The NOTIMPLEMENTED() macro annotates codepaths which have
// not been implemented yet.
//