blob: 4f10d1aee7218f88bddd4c8f7c690c5e2f1a8354 [file] [log] [blame]
Hans Wennborg12aea3e2020-04-14 15:29:001// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_CHECK_H_
6#define BASE_CHECK_H_
7
8#include <iosfwd>
9
10#include "base/base_export.h"
11#include "base/compiler_specific.h"
12#include "base/immediate_crash.h"
13
14// This header defines the CHECK, DCHECK, and DPCHECK macros.
15//
16// CHECK dies with a fatal error if its condition is not true. It is not
17// controlled by NDEBUG, so the check will be executed regardless of compilation
18// mode.
19//
20// DCHECK, the "debug mode" check, is enabled depending on NDEBUG and
21// DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE.
22//
23// (D)PCHECK is like (D)CHECK, but includes the system error code (c.f.
24// perror(3)).
25//
26// Additional information can be streamed to these macros and will be included
27// in the log output if the condition doesn't hold (you may need to include
28// <ostream>):
29//
30// CHECK(condition) << "Additional info.";
31//
32// The condition is evaluated exactly once. Even in build modes where e.g.
33// DCHECK is disabled, the condition and any stream arguments are still
34// referenced to avoid warnings about unused variables and functions.
35//
36// For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header
37// is *significantly* larger than check.h, so try to avoid including it in
38// header files.
39
40namespace logging {
41
42// Class used to explicitly ignore an ostream, and optionally a boolean value.
43class VoidifyStream {
44 public:
45 VoidifyStream() = default;
46 explicit VoidifyStream(bool ignored) {}
47
48 // This operator has lower precedence than << but higher than ?:
49 void operator&(std::ostream&) {}
50};
51
52// Helper macro which avoids evaluating the arguents to a stream if the
53// condition is false.
54#define LAZY_CHECK_STREAM(stream, condition) \
55 !(condition) ? (void)0 : ::logging::VoidifyStream() & (stream)
56
57// Macro which uses but does not evaluate expr and any stream parameters.
58#define EAT_CHECK_STREAM_PARAMS(expr) \
59 true ? (void)0 \
60 : ::logging::VoidifyStream(expr) & (*::logging::g_swallow_stream)
61BASE_EXPORT extern std::ostream* g_swallow_stream;
62
63class CheckOpResult;
64class LogMessage;
65
66// Class used for raising a check error upon destruction.
67class BASE_EXPORT CheckError {
68 public:
69 static CheckError Check(const char* file, int line, const char* condition);
70 static CheckError CheckOp(const char* file, int line, CheckOpResult* result);
71
72 static CheckError DCheck(const char* file, int line, const char* condition);
73 static CheckError DCheckOp(const char* file, int line, CheckOpResult* result);
74
75 static CheckError PCheck(const char* file, int line, const char* condition);
76 static CheckError PCheck(const char* file, int line);
77
78 static CheckError DPCheck(const char* file, int line, const char* condition);
79
80 // Stream for adding optional details to the error message.
81 std::ostream& stream();
82
83 ~CheckError();
84
85 CheckError(const CheckError& other) = delete;
86 CheckError& operator=(const CheckError& other) = delete;
87 CheckError(CheckError&& other) = default;
88 CheckError& operator=(CheckError&& other) = default;
89
90 private:
91 explicit CheckError(LogMessage* log_message);
92
93 LogMessage* log_message_;
94};
95
96#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
97
98// Discard log strings to reduce code bloat.
99//
100// This is not calling BreakDebugger since this is called frequently, and
101// calling an out-of-line function instead of a noreturn inline macro prevents
102// compiler optimizations.
103#define CHECK(condition) \
104 UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_CHECK_STREAM_PARAMS()
105
106#define PCHECK(condition) \
107 LAZY_CHECK_STREAM( \
108 ::logging::CheckError::PCheck(__FILE__, __LINE__).stream(), \
109 UNLIKELY(!(condition)))
110
111#else
112
113#define CHECK(condition) \
114 LAZY_CHECK_STREAM( \
115 ::logging::CheckError::Check(__FILE__, __LINE__, #condition).stream(), \
116 !ANALYZER_ASSUME_TRUE(condition))
117
118#define PCHECK(condition) \
119 LAZY_CHECK_STREAM( \
120 ::logging::CheckError::PCheck(__FILE__, __LINE__, #condition).stream(), \
121 !ANALYZER_ASSUME_TRUE(condition))
122
123#endif
124
125#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
126#define DCHECK_IS_ON() false
127#else
128#define DCHECK_IS_ON() true
129#endif
130
131#if DCHECK_IS_ON()
132
133#define DCHECK(condition) \
134 LAZY_CHECK_STREAM( \
135 ::logging::CheckError::DCheck(__FILE__, __LINE__, #condition).stream(), \
136 !ANALYZER_ASSUME_TRUE(condition))
137
138#define DPCHECK(condition) \
139 LAZY_CHECK_STREAM( \
140 ::logging::CheckError::DPCheck(__FILE__, __LINE__, #condition).stream(), \
141 !ANALYZER_ASSUME_TRUE(condition))
142
143#else
144
145#define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
146#define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
147
148#endif
149
150// Async signal safe checking mechanism.
151BASE_EXPORT void RawCheck(const char* message);
152#define RAW_CHECK(condition) \
153 do { \
154 if (!(condition)) \
155 ::logging::RawCheck("Check failed: " #condition "\n"); \
156 } while (0)
157
158} // namespace logging
159
160#endif // BASE_CHECK_H_