Commit c195e902 authored by Hans Wennborg's avatar Hans Wennborg Committed by Commit Bot

[base] Move the CHECK and CHECK_op macros to more light-weight headers

This provides cheaper (in terms of compile time) alternatives for code
that just wants to do a few simple CHECKs without pulling in the full
weight of logging.h. On Linux, the preprocessed size of check.h and
check_op.h are 2% and 62% of logging.h, respectively.

Splitting the CHECK and CHECK_op macros out to separate files also
reduces the complexity of logging.h which has become very complicated.

As a bonus, the new implementation is leaner, causing a 3% local
compile-time reduction for the chrome target on Linux even though no
includes have been changed yet.

Bug: 1031540
Change-Id: If7aca321f077110bea0907e487d2e8d29a8c50fd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2128112
Commit-Queue: Nico Weber <thakis@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#758287}
parent b93a4d89
...@@ -195,6 +195,10 @@ jumbo_component("base") { ...@@ -195,6 +195,10 @@ jumbo_component("base") {
"callback_internal.h", "callback_internal.h",
"callback_list.h", "callback_list.h",
"cancelable_callback.h", "cancelable_callback.h",
"check.cc",
"check.h",
"check_op.cc",
"check_op.h",
"command_line.cc", "command_line.cc",
"command_line.h", "command_line.h",
"compiler_specific.h", "compiler_specific.h",
......
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/check.h"
// check.h is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 17000
#endif
#include "base/logging.h"
#include "build/build_config.h"
namespace logging {
CheckError CheckError::Check(const char* file,
int line,
const char* condition) {
CheckError check_error(new LogMessage(file, line, condition));
return check_error;
}
CheckError CheckError::CheckOp(const char* file,
int line,
CheckOpResult* check_op_result) {
CheckError check_error(new LogMessage(file, line, check_op_result->message_));
free(check_op_result->message_);
check_op_result->message_ = nullptr;
return check_error;
}
CheckError CheckError::DCheck(const char* file,
int line,
const char* condition) {
CheckError check_error(new LogMessage(file, line, LOG_DCHECK));
check_error.stream() << "Check failed: " << condition << ". ";
return check_error;
}
CheckError CheckError::DCheckOp(const char* file,
int line,
CheckOpResult* check_op_result) {
CheckError check_error(new LogMessage(file, line, LOG_DCHECK));
check_error.stream() << "Check failed: " << check_op_result->message_ << ". ";
free(check_op_result->message_);
check_op_result->message_ = nullptr;
return check_error;
}
CheckError CheckError::PCheck(const char* file,
int line,
const char* condition) {
SystemErrorCode err_code = logging::GetLastSystemErrorCode();
#if defined(OS_WIN)
CheckError check_error(
new Win32ErrorLogMessage(file, line, LOG_FATAL, err_code));
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
CheckError check_error(new ErrnoLogMessage(file, line, LOG_FATAL, err_code));
#endif
check_error.stream() << "Check failed: " << condition << ". ";
return check_error;
}
CheckError CheckError::PCheck(const char* file, int line) {
return PCheck(file, line, "");
}
CheckError CheckError::DPCheck(const char* file,
int line,
const char* condition) {
SystemErrorCode err_code = logging::GetLastSystemErrorCode();
#if defined(OS_WIN)
CheckError check_error(
new Win32ErrorLogMessage(file, line, LOG_DCHECK, err_code));
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
CheckError check_error(new ErrnoLogMessage(file, line, LOG_DCHECK, err_code));
#endif
check_error.stream() << "Check failed: " << condition << ". ";
return check_error;
}
std::ostream& CheckError::stream() {
return log_message_->stream();
}
CheckError::~CheckError() {
delete log_message_;
}
CheckError::CheckError(LogMessage* log_message) : log_message_(log_message) {}
void RawCheck(const char* message) {
RawLog(LOG_FATAL, message);
}
} // namespace logging
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CHECK_H_
#define BASE_CHECK_H_
#include <iosfwd>
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/immediate_crash.h"
// This header defines the CHECK, DCHECK, and DPCHECK macros.
//
// CHECK dies with a fatal error if its condition is not true. It is not
// controlled by NDEBUG, so the check will be executed regardless of compilation
// mode.
//
// DCHECK, the "debug mode" check, is enabled depending on NDEBUG and
// DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE.
//
// (D)PCHECK is like (D)CHECK, but includes the system error code (c.f.
// perror(3)).
//
// Additional information can be streamed to these macros and will be included
// in the log output if the condition doesn't hold (you may need to include
// <ostream>):
//
// CHECK(condition) << "Additional info.";
//
// The condition is evaluated exactly once. Even in build modes where e.g.
// DCHECK is disabled, the condition and any stream arguments are still
// referenced to avoid warnings about unused variables and functions.
//
// For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header
// is *significantly* larger than check.h, so try to avoid including it in
// header files.
namespace logging {
// Class used to explicitly ignore an ostream, and optionally a boolean value.
class VoidifyStream {
public:
VoidifyStream() = default;
explicit VoidifyStream(bool ignored) {}
// This operator has lower precedence than << but higher than ?:
void operator&(std::ostream&) {}
};
// Helper macro which avoids evaluating the arguents to a stream if the
// condition is false.
#define LAZY_CHECK_STREAM(stream, condition) \
!(condition) ? (void)0 : ::logging::VoidifyStream() & (stream)
// Macro which uses but does not evaluate expr and any stream parameters.
#define EAT_CHECK_STREAM_PARAMS(expr) \
true ? (void)0 \
: ::logging::VoidifyStream(expr) & (*::logging::g_swallow_stream)
BASE_EXPORT extern std::ostream* g_swallow_stream;
class CheckOpResult;
class LogMessage;
// Class used for raising a check error upon destruction.
class BASE_EXPORT CheckError {
public:
static CheckError Check(const char* file, int line, const char* condition);
static CheckError CheckOp(const char* file, int line, CheckOpResult* result);
static CheckError DCheck(const char* file, int line, const char* condition);
static CheckError DCheckOp(const char* file, int line, CheckOpResult* result);
static CheckError PCheck(const char* file, int line, const char* condition);
static CheckError PCheck(const char* file, int line);
static CheckError DPCheck(const char* file, int line, const char* condition);
// Stream for adding optional details to the error message.
std::ostream& stream();
~CheckError();
// Move-only.
CheckError(const CheckError& other) = delete;
CheckError& operator=(const CheckError& other) = delete;
CheckError(CheckError&& other) = default;
CheckError& operator=(CheckError&& other) = default;
private:
explicit CheckError(LogMessage* log_message);
LogMessage* log_message_;
};
#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
// Discard log strings to reduce code bloat.
//
// 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) \
UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_CHECK_STREAM_PARAMS()
#define PCHECK(condition) \
LAZY_CHECK_STREAM( \
::logging::CheckError::PCheck(__FILE__, __LINE__).stream(), \
UNLIKELY(!(condition)))
#else
#define CHECK(condition) \
LAZY_CHECK_STREAM( \
::logging::CheckError::Check(__FILE__, __LINE__, #condition).stream(), \
!ANALYZER_ASSUME_TRUE(condition))
#define PCHECK(condition) \
LAZY_CHECK_STREAM( \
::logging::CheckError::PCheck(__FILE__, __LINE__, #condition).stream(), \
!ANALYZER_ASSUME_TRUE(condition))
#endif
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
#define DCHECK_IS_ON() false
#else
#define DCHECK_IS_ON() true
#endif
#if DCHECK_IS_ON()
#define DCHECK(condition) \
LAZY_CHECK_STREAM( \
::logging::CheckError::DCheck(__FILE__, __LINE__, #condition).stream(), \
!ANALYZER_ASSUME_TRUE(condition))
#define DPCHECK(condition) \
LAZY_CHECK_STREAM( \
::logging::CheckError::DPCheck(__FILE__, __LINE__, #condition).stream(), \
!ANALYZER_ASSUME_TRUE(condition))
#else
#define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
#define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
#endif
// Async signal safe checking mechanism.
BASE_EXPORT void RawCheck(const char* message);
#define RAW_CHECK(condition) \
do { \
if (!(condition)) \
::logging::RawCheck("Check failed: " #condition "\n"); \
} while (0)
} // namespace logging
#endif // BASE_CHECK_H_
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/check_op.h"
// check_op.h is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 230000
#endif
#include <cstdio>
#include <sstream>
namespace logging {
char* CheckOpValueStr(int v) {
char buf[50];
snprintf(buf, sizeof(buf), "%d", v);
return strdup(buf);
}
char* CheckOpValueStr(unsigned v) {
char buf[50];
snprintf(buf, sizeof(buf), "%u", v);
return strdup(buf);
}
char* CheckOpValueStr(unsigned long v) {
char buf[50];
snprintf(buf, sizeof(buf), "%lu", v);
return strdup(buf);
}
char* CheckOpValueStr(const void* v) {
char buf[50];
snprintf(buf, sizeof(buf), "%p", v);
return strdup(buf);
}
char* CheckOpValueStr(std::nullptr_t v) {
return strdup("nullptr");
}
char* CheckOpValueStr(double v) {
char buf[50];
snprintf(buf, sizeof(buf), "%.6lf", v);
return strdup(buf);
}
char* StreamValToStr(const void* v,
void (*stream_func)(std::ostream&, const void*)) {
std::stringstream ss;
stream_func(ss, v);
return strdup(ss.str().c_str());
}
CheckOpResult::CheckOpResult(const char* expr_str, char* v1_str, char* v2_str) {
std::ostringstream ss;
ss << expr_str << " (" << v1_str << " vs. " << v2_str << ")";
message_ = strdup(ss.str().c_str());
free(v1_str);
free(v2_str);
}
} // namespace logging
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CHECK_OP_H_
#define BASE_CHECK_OP_H_
#include <cstddef>
#include <type_traits>
#include "base/check.h"
#include "base/template_util.h"
// This header defines the (DP)CHECK_EQ etc. macros.
//
// (DP)CHECK_EQ(x, y) is similar to (DP)CHECK(x == y) but will also log the
// values of x and y if the condition doesn't old. This works for basic types
// and types with an operator<< or .ToString() method.
//
// The operands are evaluated exactly once, and even in build modes where e.g.
// DCHECK is disabled, the operands and their stringification methods are still
// referenced to avoid warnings about unused variables or functions.
//
// To support the stringification of the check operands, this header is
// *significantly* larger than base/check.h, so it should be avoided in common
// headers.
namespace logging {
// Functions for turning check operand values into strings.
// Caller takes ownership of the returned string.
BASE_EXPORT char* CheckOpValueStr(int v);
BASE_EXPORT char* CheckOpValueStr(unsigned v);
BASE_EXPORT char* CheckOpValueStr(unsigned long v);
BASE_EXPORT char* CheckOpValueStr(const void* v);
BASE_EXPORT char* CheckOpValueStr(std::nullptr_t v);
BASE_EXPORT char* CheckOpValueStr(double v);
// Convert a streamable value to string out-of-line to avoid <sstream>.
BASE_EXPORT char* StreamValToStr(const void* v,
void (*stream_func)(std::ostream&,
const void*));
template <typename T>
inline typename std::enable_if<
base::internal::SupportsOstreamOperator<const T&>::value &&
!std::is_function<typename std::remove_pointer<T>::type>::value,
char*>::type
CheckOpValueStr(const T& v) {
auto f = [](std::ostream& s, const void* p) {
s << *reinterpret_cast<const T*>(p);
};
// operator& might be overloaded, so do the std::addressof dance.
// __builtin_addressof is preferred since it also handles Obj-C ARC pointers.
// Some casting is still needed, because T might be volatile.
#if defined(__has_builtin) && __has_builtin(__builtin_addressof)
const void* vp = const_cast<const void*>(
reinterpret_cast<const volatile void*>(__builtin_addressof(v)));
#else
const void* vp = reinterpret_cast<const void*>(
const_cast<const char*>(&reinterpret_cast<const volatile char&>(v)));
#endif
return StreamValToStr(vp, f);
}
// Overload for types that have no operator<< but do have .ToString() defined.
template <typename T>
inline typename std::enable_if<
!base::internal::SupportsOstreamOperator<const T&>::value &&
base::internal::SupportsToString<const T&>::value,
char*>::type
CheckOpValueStr(const T& v) {
return strdup(v.ToString().c_str());
}
// 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,
char*>::type
CheckOpValueStr(const T& v) {
return CheckOpValueStr(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,
char*>::type
CheckOpValueStr(const T& v) {
return CheckOpValueStr(
static_cast<typename std::underlying_type<T>::type>(v));
}
// Captures the result of a CHECK_op and facilitates testing as a boolean.
class CheckOpResult {
public:
// An empty result signals success.
constexpr CheckOpResult() : message_(nullptr) {}
// A non-success result. expr_str is something like "foo != bar". v1_str and
// v2_str are the stringified run-time values of foo and bar. Takes ownership
// of v1_str and v2_str.
BASE_EXPORT CheckOpResult(const char* expr_str, char* v1_str, char* v2_str);
// Returns true if the check succeeded.
constexpr explicit operator bool() const { return !message_; }
friend class CheckError;
private:
char* message_;
};
#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
// Discard log strings to reduce code bloat.
#define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))
#else
// Helper macro for binary operators.
// 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::CheckError::CheckOp(__FILE__, __LINE__, &true_if_passed) \
.stream()
#endif
// The int-int overload avoids address-taking static int members.
#define DEFINE_CHECK_OP_IMPL(name, op) \
template <typename T, typename U> \
constexpr ::logging::CheckOpResult Check##name##Impl( \
const T& v1, const U& v2, const char* expr_str) { \
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
return ::logging::CheckOpResult(); \
else \
return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1), \
CheckOpValueStr(v2)); \
} \
constexpr ::logging::CheckOpResult Check##name##Impl(int v1, int v2, \
const char* expr_str) { \
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
return ::logging::CheckOpResult(); \
else \
return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1), \
CheckOpValueStr(v2)); \
}
// clang-format off
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)
// clang-format on
#if DCHECK_IS_ON()
#define DCHECK_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::CheckError::DCheckOp(__FILE__, __LINE__, &true_if_passed) \
.stream()
#else
// Don't do any evaluation but still reference the same stuff as when enabled.
#define DCHECK_OP(name, op, val1, val2) \
EAT_CHECK_STREAM_PARAMS((::logging::CheckOpValueStr(val1), \
::logging::CheckOpValueStr(val2), (val1)op(val2)))
#endif
// clang-format off
#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
// clang-format on
} // namespace logging
#endif // BASE_CHECK_OP_H_
...@@ -87,9 +87,10 @@ TEST_F(CheckTest, Basics) { ...@@ -87,9 +87,10 @@ TEST_F(CheckTest, Basics) {
EXPECT_CHECK("Check failed: false. foo", CHECK(false) << "foo"); EXPECT_CHECK("Check failed: false. foo", CHECK(false) << "foo");
double a = 2, b = 1; double a = 2, b = 1;
EXPECT_CHECK("Check failed: a < b (2 vs. 1)", CHECK_LT(a, b)); EXPECT_CHECK("Check failed: a < b (2.000000 vs. 1.000000). ", CHECK_LT(a, b));
EXPECT_CHECK("Check failed: a < b (2 vs. 1)foo", CHECK_LT(a, b) << "foo"); EXPECT_CHECK("Check failed: a < b (2.000000 vs. 1.000000). foo",
CHECK_LT(a, b) << "foo");
} }
TEST_F(CheckTest, PCheck) { TEST_F(CheckTest, PCheck) {
...@@ -126,19 +127,19 @@ TEST_F(CheckTest, PCheck) { ...@@ -126,19 +127,19 @@ TEST_F(CheckTest, PCheck) {
TEST_F(CheckTest, CheckOp) { TEST_F(CheckTest, CheckOp) {
int a = 1, b = 2; int a = 1, b = 2;
// clang-format off // clang-format off
EXPECT_CHECK("Check failed: a == b (1 vs. 2)", CHECK_EQ(a, b)); EXPECT_CHECK("Check failed: a == b (1 vs. 2). ", CHECK_EQ(a, b));
EXPECT_CHECK("Check failed: a != a (1 vs. 1)", CHECK_NE(a, a)); EXPECT_CHECK("Check failed: a != a (1 vs. 1). ", CHECK_NE(a, a));
EXPECT_CHECK("Check failed: b <= a (2 vs. 1)", CHECK_LE(b, a)); EXPECT_CHECK("Check failed: b <= a (2 vs. 1). ", CHECK_LE(b, a));
EXPECT_CHECK("Check failed: b < a (2 vs. 1)", CHECK_LT(b, a)); EXPECT_CHECK("Check failed: b < a (2 vs. 1). ", CHECK_LT(b, a));
EXPECT_CHECK("Check failed: a >= b (1 vs. 2)", CHECK_GE(a, b)); EXPECT_CHECK("Check failed: a >= b (1 vs. 2). ", CHECK_GE(a, b));
EXPECT_CHECK("Check failed: a > b (1 vs. 2)", CHECK_GT(a, b)); EXPECT_CHECK("Check failed: a > b (1 vs. 2). ", CHECK_GT(a, b));
EXPECT_DCHECK("Check failed: a == b (1 vs. 2)", DCHECK_EQ(a, b)); EXPECT_DCHECK("Check failed: a == b (1 vs. 2). ", DCHECK_EQ(a, b));
EXPECT_DCHECK("Check failed: a != a (1 vs. 1)", DCHECK_NE(a, a)); EXPECT_DCHECK("Check failed: a != a (1 vs. 1). ", DCHECK_NE(a, a));
EXPECT_DCHECK("Check failed: b <= a (2 vs. 1)", DCHECK_LE(b, a)); EXPECT_DCHECK("Check failed: b <= a (2 vs. 1). ", DCHECK_LE(b, a));
EXPECT_DCHECK("Check failed: b < a (2 vs. 1)", DCHECK_LT(b, a)); EXPECT_DCHECK("Check failed: b < a (2 vs. 1). ", DCHECK_LT(b, a));
EXPECT_DCHECK("Check failed: a >= b (1 vs. 2)", DCHECK_GE(a, b)); EXPECT_DCHECK("Check failed: a >= b (1 vs. 2). ", DCHECK_GE(a, b));
EXPECT_DCHECK("Check failed: a > b (1 vs. 2)", DCHECK_GT(a, b)); EXPECT_DCHECK("Check failed: a > b (1 vs. 2). ", DCHECK_GT(a, b));
// clang-format on // clang-format on
} }
...@@ -226,7 +227,7 @@ TEST_F(CheckTest, MAYBE_Dcheck) { ...@@ -226,7 +227,7 @@ TEST_F(CheckTest, MAYBE_Dcheck) {
std::string err = std::string err =
logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode()); logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
EXPECT_DCHECK("Check failed: false. : " + err, DPCHECK(false)); EXPECT_DCHECK("Check failed: false. : " + err, DPCHECK(false));
EXPECT_DCHECK("Check failed: 0 == 1 (0 vs. 1)", DCHECK_EQ(0, 1)); EXPECT_DCHECK("Check failed: 0 == 1 (0 vs. 1). ", DCHECK_EQ(0, 1));
// Test DCHECK on std::nullptr_t // Test DCHECK on std::nullptr_t
const void* p_null = nullptr; const void* p_null = nullptr;
...@@ -239,7 +240,7 @@ TEST_F(CheckTest, MAYBE_Dcheck) { ...@@ -239,7 +240,7 @@ TEST_F(CheckTest, MAYBE_Dcheck) {
// Test DCHECK on a scoped enum. // Test DCHECK on a scoped enum.
enum class Animal { DOG, CAT }; enum class Animal { DOG, CAT };
DCHECK_EQ(Animal::DOG, Animal::DOG); DCHECK_EQ(Animal::DOG, Animal::DOG);
EXPECT_DCHECK("Check failed: Animal::DOG == Animal::CAT (0 vs. 1)", EXPECT_DCHECK("Check failed: Animal::DOG == Animal::CAT (0 vs. 1). ",
DCHECK_EQ(Animal::DOG, Animal::CAT)); DCHECK_EQ(Animal::DOG, Animal::CAT));
// Test DCHECK on functions and function pointers. // Test DCHECK on functions and function pointers.
...@@ -258,10 +259,10 @@ TEST_F(CheckTest, MAYBE_Dcheck) { ...@@ -258,10 +259,10 @@ TEST_F(CheckTest, MAYBE_Dcheck) {
DCHECK_EQ(fp1, fp3); DCHECK_EQ(fp1, fp3);
DCHECK_EQ(mp1, &MemberFunctions::MemberFunction1); DCHECK_EQ(mp1, &MemberFunctions::MemberFunction1);
DCHECK_EQ(mp2, &MemberFunctions::MemberFunction2); DCHECK_EQ(mp2, &MemberFunctions::MemberFunction2);
EXPECT_DCHECK("=~Check failed: fp1 == fp2 \\(\\w+ vs. \\w+\\)", EXPECT_DCHECK("=~Check failed: fp1 == fp2 \\(\\w+ vs. \\w+\\). ",
DCHECK_EQ(fp1, fp2)); DCHECK_EQ(fp1, fp2));
EXPECT_DCHECK( EXPECT_DCHECK(
"Check failed: mp2 == &MemberFunctions::MemberFunction1 (1 vs. 1)", "Check failed: mp2 == &MemberFunctions::MemberFunction1 (1 vs. 1). ",
DCHECK_EQ(mp2, &MemberFunctions::MemberFunction1)); DCHECK_EQ(mp2, &MemberFunctions::MemberFunction1));
} }
...@@ -376,13 +377,14 @@ std::ostream& operator<<(std::ostream& out, ...@@ -376,13 +377,14 @@ std::ostream& operator<<(std::ostream& out,
TEST_F(CheckTest, OstreamVsToString) { TEST_F(CheckTest, OstreamVsToString) {
StructWithOstream a, b; StructWithOstream a, b;
EXPECT_CHECK("Check failed: a == b (ostream vs. ostream)", CHECK_EQ(a, b)); EXPECT_CHECK("Check failed: a == b (ostream vs. ostream). ", CHECK_EQ(a, b));
StructWithToString c, d; StructWithToString c, d;
EXPECT_CHECK("Check failed: c == d (ToString vs. ToString)", CHECK_EQ(c, d)); EXPECT_CHECK("Check failed: c == d (ToString vs. ToString). ",
CHECK_EQ(c, d));
StructWithToStringAndOstream e, f; StructWithToStringAndOstream e, f;
EXPECT_CHECK("Check failed: e == f (ostream vs. ostream)", CHECK_EQ(e, f)); EXPECT_CHECK("Check failed: e == f (ostream vs. ostream). ", CHECK_EQ(e, f));
} }
} // namespace } // namespace
...@@ -247,4 +247,36 @@ ...@@ -247,4 +247,36 @@
#define STACK_UNINITIALIZED #define STACK_UNINITIALIZED
#endif #endif
// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints
// to Clang which control what code paths are statically analyzed,
// and is meant to be used in conjunction with assert & assert-like functions.
// The expression is passed straight through if analysis isn't enabled.
//
// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current
// codepath and any other branching codepaths that might follow.
#if defined(__clang_analyzer__)
inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
return false;
}
inline constexpr bool AnalyzerAssumeTrue(bool arg) {
// AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is
// false.
return arg || AnalyzerNoReturn();
}
#define ANALYZER_ASSUME_TRUE(arg) logging::AnalyzerAssumeTrue(!!(arg))
#define ANALYZER_SKIP_THIS_PATH() \
static_cast<void>(::logging::AnalyzerNoReturn())
#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
#else // !defined(__clang_analyzer__)
#define ANALYZER_ASSUME_TRUE(arg) (arg)
#define ANALYZER_SKIP_THIS_PATH()
#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
#endif // defined(__clang_analyzer__)
#endif // BASE_COMPILER_SPECIFIC_H_ #endif // BASE_COMPILER_SPECIFIC_H_
...@@ -24,7 +24,7 @@ class BASE_EXPORT ZxLogMessage : public logging::LogMessage { ...@@ -24,7 +24,7 @@ class BASE_EXPORT ZxLogMessage : public logging::LogMessage {
int line, int line,
LogSeverity severity, LogSeverity severity,
zx_status_t zx_err); zx_status_t zx_err);
~ZxLogMessage(); ~ZxLogMessage() override;
private: private:
zx_status_t zx_err_; zx_status_t zx_err_;
......
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
#include "base/logging.h" #include "base/logging.h"
// logging.h is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 370000
#endif // NACL_TC_REV
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
...@@ -551,22 +558,6 @@ LogMessageHandlerFunction GetLogMessageHandler() { ...@@ -551,22 +558,6 @@ LogMessageHandlerFunction GetLogMessageHandler() {
return log_message_handler; return log_message_handler;
} }
// Explicit instantiations for commonly used comparisons.
template std::string* MakeCheckOpString<int, int>(
const int&, const int&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
const unsigned long&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
const unsigned long&, const unsigned int&, const char* names);
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
const unsigned int&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<std::string, std::string>(
const std::string&, const std::string&, const char* name);
void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p) {
(*os) << "nullptr";
}
#if !defined(NDEBUG) #if !defined(NDEBUG)
// Displays a message box to the user with the error message in it. // Displays a message box to the user with the error message in it.
// Used for fatal messages, where we close the app simultaneously. // Used for fatal messages, where we close the app simultaneously.
...@@ -1066,9 +1057,7 @@ Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, ...@@ -1066,9 +1057,7 @@ Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
int line, int line,
LogSeverity severity, LogSeverity severity,
SystemErrorCode err) SystemErrorCode err)
: err_(err), : LogMessage(file, line, severity), err_(err) {}
log_message_(file, line, severity) {
}
Win32ErrorLogMessage::~Win32ErrorLogMessage() { Win32ErrorLogMessage::~Win32ErrorLogMessage() {
stream() << ": " << SystemErrorCodeToString(err_); stream() << ": " << SystemErrorCodeToString(err_);
...@@ -1082,9 +1071,7 @@ ErrnoLogMessage::ErrnoLogMessage(const char* file, ...@@ -1082,9 +1071,7 @@ ErrnoLogMessage::ErrnoLogMessage(const char* file,
int line, int line,
LogSeverity severity, LogSeverity severity,
SystemErrorCode err) SystemErrorCode err)
: err_(err), : LogMessage(file, line, severity), err_(err) {}
log_message_(file, line, severity) {
}
ErrnoLogMessage::~ErrnoLogMessage() { ErrnoLogMessage::~ErrnoLogMessage() {
stream() << ": " << SystemErrorCodeToString(err_); stream() << ": " << SystemErrorCodeToString(err_);
......
This diff is collapsed.
...@@ -38,7 +38,7 @@ class BASE_EXPORT OSStatusLogMessage : public logging::LogMessage { ...@@ -38,7 +38,7 @@ class BASE_EXPORT OSStatusLogMessage : public logging::LogMessage {
int line, int line,
LogSeverity severity, LogSeverity severity,
OSStatus status); OSStatus status);
~OSStatusLogMessage(); ~OSStatusLogMessage() override;
private: private:
OSStatus status_; OSStatus status_;
......
...@@ -39,7 +39,7 @@ class BASE_EXPORT MachLogMessage : public logging::LogMessage { ...@@ -39,7 +39,7 @@ class BASE_EXPORT MachLogMessage : public logging::LogMessage {
int line, int line,
LogSeverity severity, LogSeverity severity,
mach_error_t mach_err); mach_error_t mach_err);
~MachLogMessage(); ~MachLogMessage() override;
private: private:
mach_error_t mach_err_; mach_error_t mach_err_;
...@@ -106,7 +106,7 @@ class BASE_EXPORT BootstrapLogMessage : public logging::LogMessage { ...@@ -106,7 +106,7 @@ class BASE_EXPORT BootstrapLogMessage : public logging::LogMessage {
int line, int line,
LogSeverity severity, LogSeverity severity,
kern_return_t bootstrap_err); kern_return_t bootstrap_err);
~BootstrapLogMessage(); ~BootstrapLogMessage() override;
private: private:
kern_return_t bootstrap_err_; kern_return_t bootstrap_err_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment