1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef BASE_CHECK_OP_H_
6 #define BASE_CHECK_OP_H_
10 #include <string_view>
11 #include <type_traits>
13 #include "base/base_export.h"
14 #include "base/check.h"
15 #include "base/dcheck_is_on.h"
16 #include "base/memory/raw_ptr_exclusion.h"
17 #include "base/strings/to_string.h"
18 #include "base/types/supports_ostream_operator.h"
20 // This header defines the (DP)CHECK_EQ etc. macros.
22 // (DP)CHECK_EQ(x, y) is similar to (DP)CHECK(x == y) but will also log the
23 // values of x and y if the condition doesn't hold. This works for basic types
24 // and types with an operator<< or .ToString() method.
26 // The operands are evaluated exactly once, and even in build modes where e.g.
27 // DCHECK is disabled, the operands and their stringification methods are still
28 // referenced to avoid warnings about unused variables or functions.
30 // To support the stringification of the check operands, this header is
31 // *significantly* larger than base/check.h, so it should be avoided in common
34 // This header also provides the (DP)CHECK macros (by including check.h), so if
35 // you use e.g. both CHECK_EQ and CHECK, including this header is enough. If you
36 // only use CHECK however, please include the smaller check.h instead.
40 // Functions for turning check operand values into NUL-terminated C strings.
41 // Caller takes ownership of the result and must release it with `free`.
42 // This would normally be defined by <ostream>, but this header tries to avoid
43 // including <ostream> to reduce compile-time. See https://crrev.com/c/2128112.
44 BASE_EXPORT char* CheckOpValueStr(int v);
45 BASE_EXPORT char* CheckOpValueStr(unsigned v);
46 BASE_EXPORT char* CheckOpValueStr(long v);
47 BASE_EXPORT char* CheckOpValueStr(unsigned long v);
48 BASE_EXPORT char* CheckOpValueStr(long long v);
49 BASE_EXPORT char* CheckOpValueStr(unsigned long long v);
50 BASE_EXPORT char* CheckOpValueStr(const void* v);
51 BASE_EXPORT char* CheckOpValueStr(std::nullptr_t v);
52 BASE_EXPORT char* CheckOpValueStr(double v);
53 // Although the standard defines operator<< for std::string and std::string_view
54 // in their respective headers, libc++ requires <ostream> for them. See
55 // https://github.com/llvm/llvm-project/issues/61070. So we define non-<ostream>
57 BASE_EXPORT char* CheckOpValueStr(const std::string& v);
58 BASE_EXPORT char* CheckOpValueStr(std::string_view v);
60 // Convert a streamable value to string out-of-line to avoid <sstream>.
61 BASE_EXPORT char* StreamValToStr(const void* v,
62 void (*stream_func)(std::ostream&,
66 #define SUPPORTS_BUILTIN_ADDRESSOF (__has_builtin(__builtin_addressof))
68 #define SUPPORTS_BUILTIN_ADDRESSOF 0
72 inline std::enable_if_t<
73 base::internal::SupportsOstreamOperator<const T&> &&
74 !std::is_function_v<typename std::remove_pointer<T>::type>,
76 CheckOpValueStr(const T& v) {
77 auto f = [](std::ostream& s, const void* p) {
78 s << *reinterpret_cast<const T*>(p);
81 // operator& might be overloaded, so do the std::addressof dance.
82 // __builtin_addressof is preferred since it also handles Obj-C ARC pointers.
83 // Some casting is still needed, because T might be volatile.
84 #if SUPPORTS_BUILTIN_ADDRESSOF
85 const void* vp = const_cast<const void*>(
86 reinterpret_cast<const volatile void*>(__builtin_addressof(v)));
88 const void* vp = reinterpret_cast<const void*>(
89 const_cast<const char*>(&reinterpret_cast<const volatile char&>(v)));
91 return StreamValToStr(vp, f);
94 #undef SUPPORTS_BUILTIN_ADDRESSOF
96 // Overload for types that have no operator<< but do have .ToString() defined.
98 inline std::enable_if_t<!base::internal::SupportsOstreamOperator<const T&> &&
99 base::internal::SupportsToString<const T&>,
101 CheckOpValueStr(const T& v) {
102 // .ToString() may not return a std::string, e.g. blink::WTF::String.
103 return CheckOpValueStr(v.ToString());
106 // Provide an overload for functions and function pointers. Function pointers
107 // don't implicitly convert to void* but do implicitly convert to bool, so
108 // without this function pointers are always printed as 1 or 0. (MSVC isn't
109 // standards-conforming here and converts function pointers to regular
110 // pointers, so this is a no-op for MSVC.)
111 template <typename T>
112 inline std::enable_if_t<
113 std::is_function_v<typename std::remove_pointer<T>::type>,
115 CheckOpValueStr(const T& v) {
116 return CheckOpValueStr(reinterpret_cast<const void*>(v));
119 // We need overloads for enums that don't support operator<<.
120 // (i.e. scoped enums where no operator<< overload was declared).
121 template <typename T>
122 inline std::enable_if_t<!base::internal::SupportsOstreamOperator<const T&> &&
125 CheckOpValueStr(const T& v) {
126 return CheckOpValueStr(
127 static_cast<typename std::underlying_type<T>::type>(v));
130 // Takes ownership of `v1_str` and `v2_str`, destroying them with free(). For
131 // use with CheckOpValueStr() which allocates these strings using strdup().
132 // Returns allocated string (with strdup) for passing into
133 // ::logging::CheckError::(D)CheckOp methods.
134 // TODO(pbos): Annotate this ABSL_ATTRIBUTE_RETURNS_NONNULL after solving
136 BASE_EXPORT char* CreateCheckOpLogMessageString(const char* expr_str,
140 // Helper macro for binary operators.
141 // The 'switch' is used to prevent the 'else' from being ambiguous when the
142 // macro is used in an 'if' clause such as:
145 #define CHECK_OP_FUNCTION_IMPL(check_failure_function, name, op, val1, val2) \
149 if (char* const message_on_fail = ::logging::Check##name##Impl( \
150 (val1), (val2), #val1 " " #op " " #val2); \
154 check_failure_function(message_on_fail)
156 #if !CHECK_WILL_STREAM()
158 // Discard log strings to reduce code bloat.
159 #define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))
163 #define CHECK_OP(name, op, val1, val2) \
164 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, val1, val2)
168 // The second overload avoids address-taking of static members for
169 // fundamental types.
170 #define DEFINE_CHECK_OP_IMPL(name, op) \
172 typename T, typename U, \
173 std::enable_if_t<!std::is_fundamental_v<T> || !std::is_fundamental_v<U>, \
175 constexpr char* Check##name##Impl(const T& v1, const U& v2, \
176 const char* expr_str) { \
177 if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2))) \
179 return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1), \
180 CheckOpValueStr(v2)); \
183 typename T, typename U, \
184 std::enable_if_t<std::is_fundamental_v<T> && std::is_fundamental_v<U>, \
186 constexpr char* Check##name##Impl(T v1, U v2, const char* expr_str) { \
187 if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2))) \
189 return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1), \
190 CheckOpValueStr(v2)); \
194 DEFINE_CHECK_OP_IMPL(EQ, ==)
195 DEFINE_CHECK_OP_IMPL(NE, !=)
196 DEFINE_CHECK_OP_IMPL(LE, <=)
197 DEFINE_CHECK_OP_IMPL(LT, < )
198 DEFINE_CHECK_OP_IMPL(GE, >=)
199 DEFINE_CHECK_OP_IMPL(GT, > )
200 #undef DEFINE_CHECK_OP_IMPL
201 #define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
202 #define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
203 #define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
204 #define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
205 #define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
206 #define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
211 #define DCHECK_OP(name, op, val1, val2) \
212 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DCheckOp, name, op, val1, val2)
216 // Don't do any evaluation but still reference the same stuff as when enabled.
217 #define DCHECK_OP(name, op, val1, val2) \
218 EAT_CHECK_STREAM_PARAMS((::logging::CheckOpValueStr(val1), \
219 ::logging::CheckOpValueStr(val2), (val1)op(val2)))
224 #define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
225 #define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
226 #define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
227 #define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
228 #define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
229 #define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
232 #define DUMP_WILL_BE_CHECK_OP(name, op, val1, val2) \
233 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DumpWillBeCheckOp, name, op, \
236 #define DUMP_WILL_BE_CHECK_EQ(val1, val2) \
237 DUMP_WILL_BE_CHECK_OP(EQ, ==, val1, val2)
238 #define DUMP_WILL_BE_CHECK_NE(val1, val2) \
239 DUMP_WILL_BE_CHECK_OP(NE, !=, val1, val2)
240 #define DUMP_WILL_BE_CHECK_LE(val1, val2) \
241 DUMP_WILL_BE_CHECK_OP(LE, <=, val1, val2)
242 #define DUMP_WILL_BE_CHECK_LT(val1, val2) \
243 DUMP_WILL_BE_CHECK_OP(LT, <, val1, val2)
244 #define DUMP_WILL_BE_CHECK_GE(val1, val2) \
245 DUMP_WILL_BE_CHECK_OP(GE, >=, val1, val2)
246 #define DUMP_WILL_BE_CHECK_GT(val1, val2) \
247 DUMP_WILL_BE_CHECK_OP(GT, >, val1, val2)
249 } // namespace logging
251 #endif // BASE_CHECK_OP_H_