check_op.h (10988B)
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. 4 5 #ifndef BASE_CHECK_OP_H_ 6 #define BASE_CHECK_OP_H_ 7 8 #include <cstddef> 9 #include <string> 10 #include <string_view> 11 #include <type_traits> 12 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" 19 20 // This header defines the (DP)CHECK_EQ etc. macros. 21 // 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. 25 // 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. 29 // 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 32 // headers. 33 // 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. 37 38 namespace logging { 39 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> 56 // versions here too. 57 BASE_EXPORT char* CheckOpValueStr(const std::string& v); 58 BASE_EXPORT char* CheckOpValueStr(std::string_view v); 59 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&, 63 const void*)); 64 65 #ifdef __has_builtin 66 #define SUPPORTS_BUILTIN_ADDRESSOF (__has_builtin(__builtin_addressof)) 67 #else 68 #define SUPPORTS_BUILTIN_ADDRESSOF 0 69 #endif 70 71 template <typename T> 72 inline std::enable_if_t< 73 base::internal::SupportsOstreamOperator<const T&>::value && 74 !std::is_function_v<typename std::remove_pointer<T>::type>, 75 char*> 76 CheckOpValueStr(const T& v) { 77 auto f = [](std::ostream& s, const void* p) { 78 s << *reinterpret_cast<const T*>(p); 79 }; 80 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))); 87 #else 88 const void* vp = reinterpret_cast<const void*>( 89 const_cast<const char*>(&reinterpret_cast<const volatile char&>(v))); 90 #endif 91 return StreamValToStr(vp, f); 92 } 93 94 #undef SUPPORTS_BUILTIN_ADDRESSOF 95 96 // Overload for types that have no operator<< but do have .ToString() defined. 97 template <typename T> 98 inline std::enable_if_t< 99 !base::internal::SupportsOstreamOperator<const T&>::value && 100 base::internal::SupportsToString<const T&>::value, 101 char*> 102 CheckOpValueStr(const T& v) { 103 // .ToString() may not return a std::string, e.g. blink::WTF::String. 104 return CheckOpValueStr(v.ToString()); 105 } 106 107 // Provide an overload for functions and function pointers. Function pointers 108 // don't implicitly convert to void* but do implicitly convert to bool, so 109 // without this function pointers are always printed as 1 or 0. (MSVC isn't 110 // standards-conforming here and converts function pointers to regular 111 // pointers, so this is a no-op for MSVC.) 112 template <typename T> 113 inline std::enable_if_t< 114 std::is_function_v<typename std::remove_pointer<T>::type>, 115 char*> 116 CheckOpValueStr(const T& v) { 117 return CheckOpValueStr(reinterpret_cast<const void*>(v)); 118 } 119 120 // We need overloads for enums that don't support operator<<. 121 // (i.e. scoped enums where no operator<< overload was declared). 122 template <typename T> 123 inline std::enable_if_t< 124 !base::internal::SupportsOstreamOperator<const T&>::value && 125 std::is_enum_v<T>, 126 char*> 127 CheckOpValueStr(const T& v) { 128 return CheckOpValueStr( 129 static_cast<typename std::underlying_type<T>::type>(v)); 130 } 131 132 // Takes ownership of `v1_str` and `v2_str`, destroying them with free(). For 133 // use with CheckOpValueStr() which allocates these strings using strdup(). 134 // Returns allocated string (with strdup) for passing into 135 // ::logging::CheckError::(D)CheckOp methods. 136 // TODO(pbos): Annotate this ABSL_ATTRIBUTE_RETURNS_NONNULL after solving 137 // compile failure. 138 BASE_EXPORT char* CreateCheckOpLogMessageString(const char* expr_str, 139 char* v1_str, 140 char* v2_str); 141 142 // Helper macro for binary operators. 143 // The 'switch' is used to prevent the 'else' from being ambiguous when the 144 // macro is used in an 'if' clause such as: 145 // if (a == 1) 146 // CHECK_EQ(2, a); 147 #define CHECK_OP_FUNCTION_IMPL(check_failure_function, name, op, val1, val2) \ 148 switch (0) \ 149 case 0: \ 150 default: \ 151 if (char* const message_on_fail = ::logging::Check##name##Impl( \ 152 (val1), (val2), #val1 " " #op " " #val2); \ 153 !message_on_fail) \ 154 ; \ 155 else \ 156 check_failure_function(message_on_fail) 157 158 #if !CHECK_WILL_STREAM() 159 160 // Discard log strings to reduce code bloat. 161 #define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2)) 162 163 #else 164 165 #define CHECK_OP(name, op, val1, val2) \ 166 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, val1, val2) 167 168 #endif 169 170 // The second overload avoids address-taking of static members for 171 // fundamental types. 172 #define DEFINE_CHECK_OP_IMPL(name, op) \ 173 template < \ 174 typename T, typename U, \ 175 std::enable_if_t<!std::is_fundamental_v<T> || !std::is_fundamental_v<U>, \ 176 int> = 0> \ 177 constexpr char* Check##name##Impl(const T& v1, const U& v2, \ 178 const char* expr_str) { \ 179 if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2))) \ 180 return nullptr; \ 181 return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1), \ 182 CheckOpValueStr(v2)); \ 183 } \ 184 template < \ 185 typename T, typename U, \ 186 std::enable_if_t<std::is_fundamental_v<T> && std::is_fundamental_v<U>, \ 187 int> = 0> \ 188 constexpr char* Check##name##Impl(T v1, U v2, const char* expr_str) { \ 189 if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2))) \ 190 return nullptr; \ 191 return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1), \ 192 CheckOpValueStr(v2)); \ 193 } 194 195 // clang-format off 196 DEFINE_CHECK_OP_IMPL(EQ, ==) 197 DEFINE_CHECK_OP_IMPL(NE, !=) 198 DEFINE_CHECK_OP_IMPL(LE, <=) 199 DEFINE_CHECK_OP_IMPL(LT, < ) 200 DEFINE_CHECK_OP_IMPL(GE, >=) 201 DEFINE_CHECK_OP_IMPL(GT, > ) 202 #undef DEFINE_CHECK_OP_IMPL 203 #define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2) 204 #define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2) 205 #define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2) 206 #define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2) 207 #define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2) 208 #define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2) 209 // clang-format on 210 211 #if DCHECK_IS_ON() 212 213 #define DCHECK_OP(name, op, val1, val2) \ 214 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DCheckOp, name, op, val1, val2) 215 216 #else 217 218 // Don't do any evaluation but still reference the same stuff as when enabled. 219 #define DCHECK_OP(name, op, val1, val2) \ 220 EAT_CHECK_STREAM_PARAMS((::logging::CheckOpValueStr(val1), \ 221 ::logging::CheckOpValueStr(val2), (val1)op(val2))) 222 223 #endif 224 225 // clang-format off 226 #define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2) 227 #define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2) 228 #define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2) 229 #define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2) 230 #define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2) 231 #define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2) 232 // clang-format on 233 234 #define DUMP_WILL_BE_CHECK_OP(name, op, val1, val2) \ 235 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DumpWillBeCheckOp, name, op, \ 236 val1, val2) 237 238 #define DUMP_WILL_BE_CHECK_EQ(val1, val2) \ 239 DUMP_WILL_BE_CHECK_OP(EQ, ==, val1, val2) 240 #define DUMP_WILL_BE_CHECK_NE(val1, val2) \ 241 DUMP_WILL_BE_CHECK_OP(NE, !=, val1, val2) 242 #define DUMP_WILL_BE_CHECK_LE(val1, val2) \ 243 DUMP_WILL_BE_CHECK_OP(LE, <=, val1, val2) 244 #define DUMP_WILL_BE_CHECK_LT(val1, val2) \ 245 DUMP_WILL_BE_CHECK_OP(LT, <, val1, val2) 246 #define DUMP_WILL_BE_CHECK_GE(val1, val2) \ 247 DUMP_WILL_BE_CHECK_OP(GE, >=, val1, val2) 248 #define DUMP_WILL_BE_CHECK_GT(val1, val2) \ 249 DUMP_WILL_BE_CHECK_OP(GT, >, val1, val2) 250 251 } // namespace logging 252 253 #endif // BASE_CHECK_OP_H_