check_op.h (23849B)
1 // Copyright 2022 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // ----------------------------------------------------------------------------- 16 // File: log/internal/check_op.h 17 // ----------------------------------------------------------------------------- 18 // 19 // This file declares helpers routines and macros used to implement `CHECK` 20 // macros. 21 22 #ifndef ABSL_LOG_INTERNAL_CHECK_OP_H_ 23 #define ABSL_LOG_INTERNAL_CHECK_OP_H_ 24 25 #include <stdint.h> 26 27 #include <cstddef> 28 #include <ostream> 29 #include <sstream> 30 #include <string> 31 #include <type_traits> 32 #include <utility> 33 34 #include "absl/base/attributes.h" 35 #include "absl/base/casts.h" 36 #include "absl/base/config.h" 37 #include "absl/base/nullability.h" 38 #include "absl/base/optimization.h" 39 #include "absl/log/internal/nullguard.h" 40 #include "absl/log/internal/nullstream.h" 41 #include "absl/log/internal/strip.h" 42 #include "absl/strings/has_absl_stringify.h" 43 #include "absl/strings/string_view.h" 44 45 // `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that 46 // should be stripped when `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`. 47 #ifdef ABSL_MIN_LOG_LEVEL 48 #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) \ 49 (::absl::LogSeverity::kFatal >= \ 50 static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \ 51 ? (literal) \ 52 : "") 53 #else 54 #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) (literal) 55 #endif 56 57 #ifdef NDEBUG 58 // `NDEBUG` is defined, so `DCHECK_EQ(x, y)` and so on do nothing. However, we 59 // still want the compiler to parse `x` and `y`, because we don't want to lose 60 // potentially useful errors and warnings. 61 #define ABSL_LOG_INTERNAL_DCHECK_NOP(x, y) \ 62 while (false && ((void)(x), (void)(y), 0)) \ 63 ::absl::log_internal::NullStream().InternalStream() 64 #endif 65 66 #define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val1_text, val2, val2_text) \ 67 while (absl::Nullable<const char*> absl_log_internal_check_op_result \ 68 [[maybe_unused]] = \ 69 ::absl::log_internal::name##Impl( \ 70 ::absl::log_internal::GetReferenceableValue(val1), \ 71 ::absl::log_internal::GetReferenceableValue(val2), \ 72 ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \ 73 val1_text " " #op " " val2_text))) \ 74 ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ 75 ABSL_LOG_INTERNAL_CHECK(absl::implicit_cast<absl::Nonnull<const char*>>( \ 76 absl_log_internal_check_op_result)) \ 77 .InternalStream() 78 #define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \ 79 val2_text) \ 80 while (absl::Nullable<const char*> absl_log_internal_qcheck_op_result = \ 81 ::absl::log_internal::name##Impl( \ 82 ::absl::log_internal::GetReferenceableValue(val1), \ 83 ::absl::log_internal::GetReferenceableValue(val2), \ 84 ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \ 85 val1_text " " #op " " val2_text))) \ 86 ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ 87 ABSL_LOG_INTERNAL_QCHECK(absl::implicit_cast<absl::Nonnull<const char*>>( \ 88 absl_log_internal_qcheck_op_result)) \ 89 .InternalStream() 90 #define ABSL_LOG_INTERNAL_CHECK_STROP(func, op, expected, s1, s1_text, s2, \ 91 s2_text) \ 92 while (absl::Nullable<const char*> absl_log_internal_check_strop_result = \ 93 ::absl::log_internal::Check##func##expected##Impl( \ 94 (s1), (s2), \ 95 ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ 96 " " s2_text))) \ 97 ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ 98 ABSL_LOG_INTERNAL_CHECK(absl::implicit_cast<absl::Nonnull<const char*>>( \ 99 absl_log_internal_check_strop_result)) \ 100 .InternalStream() 101 #define ABSL_LOG_INTERNAL_QCHECK_STROP(func, op, expected, s1, s1_text, s2, \ 102 s2_text) \ 103 while (absl::Nullable<const char*> absl_log_internal_qcheck_strop_result = \ 104 ::absl::log_internal::Check##func##expected##Impl( \ 105 (s1), (s2), \ 106 ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ 107 " " s2_text))) \ 108 ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ 109 ABSL_LOG_INTERNAL_QCHECK(absl::implicit_cast<absl::Nonnull<const char*>>( \ 110 absl_log_internal_qcheck_strop_result)) \ 111 .InternalStream() 112 113 // This one is tricky: 114 // * We must evaluate `val` exactly once, yet we need to do two things with it: 115 // evaluate `.ok()` and (sometimes) `.ToString()`. 116 // * `val` might be an `absl::Status` or some `absl::StatusOr<T>`. 117 // * `val` might be e.g. `ATemporary().GetStatus()`, which may return a 118 // reference to a member of `ATemporary` that is only valid until the end of 119 // the full expression. 120 // * We don't want this file to depend on `absl::Status` `#include`s or linkage, 121 // nor do we want to move the definition to status and introduce a dependency 122 // in the other direction. We can be assured that callers must already have a 123 // `Status` and the necessary `#include`s and linkage. 124 // * Callsites should be small and fast (at least when `val.ok()`): one branch, 125 // minimal stack footprint. 126 // * In particular, the string concat stuff should be out-of-line and emitted 127 // in only one TU to save linker input size 128 // * We want the `val.ok()` check inline so static analyzers and optimizers can 129 // see it. 130 // * As usual, no braces so we can stream into the expansion with `operator<<`. 131 // * Also as usual, it must expand to a single (partial) statement with no 132 // ambiguous-else problems. 133 // * When stripped by `ABSL_MIN_LOG_LEVEL`, we must discard the `<expr> is OK` 134 // string literal and abort without doing any streaming. We don't need to 135 // strip the call to stringify the non-ok `Status` as long as we don't log it; 136 // dropping the `Status`'s message text is out of scope. 137 #define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text) \ 138 for (::std::pair<absl::Nonnull<const ::absl::Status*>, \ 139 absl::Nullable<const char*>> \ 140 absl_log_internal_check_ok_goo; \ 141 absl_log_internal_check_ok_goo.first = \ 142 ::absl::log_internal::AsStatus(val), \ 143 absl_log_internal_check_ok_goo.second = \ 144 ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \ 145 ? nullptr \ 146 : ::absl::status_internal::MakeCheckFailString( \ 147 absl_log_internal_check_ok_goo.first, \ 148 ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ 149 " is OK")), \ 150 !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \ 151 ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ 152 ABSL_LOG_INTERNAL_CHECK(absl::implicit_cast<absl::Nonnull<const char*>>( \ 153 absl_log_internal_check_ok_goo.second)) \ 154 .InternalStream() 155 #define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text) \ 156 for (::std::pair<absl::Nonnull<const ::absl::Status*>, \ 157 absl::Nullable<const char*>> \ 158 absl_log_internal_qcheck_ok_goo; \ 159 absl_log_internal_qcheck_ok_goo.first = \ 160 ::absl::log_internal::AsStatus(val), \ 161 absl_log_internal_qcheck_ok_goo.second = \ 162 ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok()) \ 163 ? nullptr \ 164 : ::absl::status_internal::MakeCheckFailString( \ 165 absl_log_internal_qcheck_ok_goo.first, \ 166 ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ 167 " is OK")), \ 168 !ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok());) \ 169 ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ 170 ABSL_LOG_INTERNAL_QCHECK(absl::implicit_cast<absl::Nonnull<const char*>>( \ 171 absl_log_internal_qcheck_ok_goo.second)) \ 172 .InternalStream() 173 174 namespace absl { 175 ABSL_NAMESPACE_BEGIN 176 177 class Status; 178 template <typename T> 179 class StatusOr; 180 181 namespace status_internal { 182 ABSL_ATTRIBUTE_PURE_FUNCTION absl::Nonnull<const char*> MakeCheckFailString( 183 absl::Nonnull<const absl::Status*> status, 184 absl::Nonnull<const char*> prefix); 185 } // namespace status_internal 186 187 namespace log_internal { 188 189 // Convert a Status or a StatusOr to its underlying status value. 190 // 191 // (This implementation does not require a dep on absl::Status to work.) 192 inline absl::Nonnull<const absl::Status*> AsStatus(const absl::Status& s) { 193 return &s; 194 } 195 template <typename T> 196 absl::Nonnull<const absl::Status*> AsStatus(const absl::StatusOr<T>& s) { 197 return &s.status(); 198 } 199 200 // A helper class for formatting `expr (V1 vs. V2)` in a `CHECK_XX` statement. 201 // See `MakeCheckOpString` for sample usage. 202 class CheckOpMessageBuilder final { 203 public: 204 // Inserts `exprtext` and ` (` to the stream. 205 explicit CheckOpMessageBuilder(absl::Nonnull<const char*> exprtext); 206 ~CheckOpMessageBuilder() = default; 207 // For inserting the first variable. 208 std::ostream& ForVar1() { return stream_; } 209 // For inserting the second variable (adds an intermediate ` vs. `). 210 std::ostream& ForVar2(); 211 // Get the result (inserts the closing `)`). 212 absl::Nonnull<const char*> NewString(); 213 214 private: 215 std::ostringstream stream_; 216 }; 217 218 // This formats a value for a failing `CHECK_XX` statement. Ordinarily, it uses 219 // the definition for `operator<<`, with a few special cases below. 220 template <typename T> 221 inline void MakeCheckOpValueString(std::ostream& os, const T& v) { 222 os << log_internal::NullGuard<T>::Guard(v); 223 } 224 225 // Overloads for char types provide readable values for unprintable characters. 226 void MakeCheckOpValueString(std::ostream& os, char v); 227 void MakeCheckOpValueString(std::ostream& os, signed char v); 228 void MakeCheckOpValueString(std::ostream& os, unsigned char v); 229 void MakeCheckOpValueString(std::ostream& os, const void* p); 230 231 namespace detect_specialization { 232 233 // MakeCheckOpString is being specialized for every T and U pair that is being 234 // passed to the CHECK_op macros. However, there is a lot of redundancy in these 235 // specializations that creates unnecessary library and binary bloat. 236 // The number of instantiations tends to be O(n^2) because we have two 237 // independent inputs. This technique works by reducing `n`. 238 // 239 // Most user-defined types being passed to CHECK_op end up being printed as a 240 // builtin type. For example, enums tend to be implicitly converted to its 241 // underlying type when calling operator<<, and pointers are printed with the 242 // `const void*` overload. 243 // To reduce the number of instantiations we coerce these values before calling 244 // MakeCheckOpString instead of inside it. 245 // 246 // To detect if this coercion is needed, we duplicate all the relevant 247 // operator<< overloads as specified in the standard, just in a different 248 // namespace. If the call to `stream << value` becomes ambiguous, it means that 249 // one of these overloads is the one selected by overload resolution. We then 250 // do overload resolution again just with our overload set to see which one gets 251 // selected. That tells us which type to coerce to. 252 // If the augmented call was not ambiguous, it means that none of these were 253 // selected and we can't coerce the input. 254 // 255 // As a secondary step to reduce code duplication, we promote integral types to 256 // their 64-bit variant. This does not change the printed value, but reduces the 257 // number of instantiations even further. Promoting an integer is very cheap at 258 // the call site. 259 int64_t operator<<(std::ostream&, short value); // NOLINT 260 int64_t operator<<(std::ostream&, unsigned short value); // NOLINT 261 int64_t operator<<(std::ostream&, int value); 262 int64_t operator<<(std::ostream&, unsigned int value); 263 int64_t operator<<(std::ostream&, long value); // NOLINT 264 uint64_t operator<<(std::ostream&, unsigned long value); // NOLINT 265 int64_t operator<<(std::ostream&, long long value); // NOLINT 266 uint64_t operator<<(std::ostream&, unsigned long long value); // NOLINT 267 float operator<<(std::ostream&, float value); 268 double operator<<(std::ostream&, double value); 269 long double operator<<(std::ostream&, long double value); 270 bool operator<<(std::ostream&, bool value); 271 const void* operator<<(std::ostream&, const void* value); 272 const void* operator<<(std::ostream&, std::nullptr_t); 273 274 // These `char` overloads are specified like this in the standard, so we have to 275 // write them exactly the same to ensure the call is ambiguous. 276 // If we wrote it in a different way (eg taking std::ostream instead of the 277 // template) then one call might have a higher rank than the other and it would 278 // not be ambiguous. 279 template <typename Traits> 280 char operator<<(std::basic_ostream<char, Traits>&, char); 281 template <typename Traits> 282 signed char operator<<(std::basic_ostream<char, Traits>&, signed char); 283 template <typename Traits> 284 unsigned char operator<<(std::basic_ostream<char, Traits>&, unsigned char); 285 template <typename Traits> 286 const char* operator<<(std::basic_ostream<char, Traits>&, const char*); 287 template <typename Traits> 288 const signed char* operator<<(std::basic_ostream<char, Traits>&, 289 const signed char*); 290 template <typename Traits> 291 const unsigned char* operator<<(std::basic_ostream<char, Traits>&, 292 const unsigned char*); 293 294 // This overload triggers when the call is not ambiguous. 295 // It means that T is being printed with some overload not on this list. 296 // We keep the value as `const T&`. 297 template <typename T, typename = decltype(std::declval<std::ostream&>() 298 << std::declval<const T&>())> 299 const T& Detect(int); 300 301 // This overload triggers when the call is ambiguous. 302 // It means that T is either one from this list or printed as one from this 303 // list. Eg an enum that decays to `int` for printing. 304 // We ask the overload set to give us the type we want to convert it to. 305 template <typename T> 306 decltype(detect_specialization::operator<<(std::declval<std::ostream&>(), 307 std::declval<const T&>())) 308 Detect(char); 309 310 // A sink for AbslStringify which redirects everything to a std::ostream. 311 class StringifySink { 312 public: 313 explicit StringifySink(std::ostream& os ABSL_ATTRIBUTE_LIFETIME_BOUND); 314 315 void Append(absl::string_view text); 316 void Append(size_t length, char ch); 317 friend void AbslFormatFlush(StringifySink* sink, absl::string_view text); 318 319 private: 320 std::ostream& os_; 321 }; 322 323 // Wraps a type implementing AbslStringify, and implements operator<<. 324 template <typename T> 325 class StringifyToStreamWrapper { 326 public: 327 explicit StringifyToStreamWrapper(const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND) 328 : v_(v) {} 329 330 friend std::ostream& operator<<(std::ostream& os, 331 const StringifyToStreamWrapper& wrapper) { 332 StringifySink sink(os); 333 AbslStringify(sink, wrapper.v_); 334 return os; 335 } 336 337 private: 338 const T& v_; 339 }; 340 341 // This overload triggers when T implements AbslStringify. 342 // StringifyToStreamWrapper is used to allow MakeCheckOpString to use 343 // operator<<. 344 template <typename T> 345 std::enable_if_t<HasAbslStringify<T>::value, 346 StringifyToStreamWrapper<T>> 347 Detect(...); // Ellipsis has lowest preference when int passed. 348 } // namespace detect_specialization 349 350 template <typename T> 351 using CheckOpStreamType = decltype(detect_specialization::Detect<T>(0)); 352 353 // Build the error message string. Specify no inlining for code size. 354 template <typename T1, typename T2> 355 ABSL_ATTRIBUTE_RETURNS_NONNULL absl::Nonnull<const char*> MakeCheckOpString( 356 T1 v1, T2 v2, absl::Nonnull<const char*> exprtext) ABSL_ATTRIBUTE_NOINLINE; 357 358 template <typename T1, typename T2> 359 absl::Nonnull<const char*> MakeCheckOpString( 360 T1 v1, T2 v2, absl::Nonnull<const char*> exprtext) { 361 CheckOpMessageBuilder comb(exprtext); 362 MakeCheckOpValueString(comb.ForVar1(), v1); 363 MakeCheckOpValueString(comb.ForVar2(), v2); 364 return comb.NewString(); 365 } 366 367 // Add a few commonly used instantiations as extern to reduce size of objects 368 // files. 369 #define ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(x) \ 370 extern template absl::Nonnull<const char*> MakeCheckOpString( \ 371 x, x, absl::Nonnull<const char*>) 372 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(bool); 373 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(int64_t); 374 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(uint64_t); 375 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(float); 376 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(double); 377 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(char); 378 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(unsigned char); 379 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const std::string&); 380 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const absl::string_view&); 381 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char*); 382 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const signed char*); 383 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const unsigned char*); 384 ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void*); 385 #undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN 386 387 // `ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT` skips formatting the Check_OP result 388 // string iff `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`, instead returning an empty 389 // string. 390 #ifdef ABSL_MIN_LOG_LEVEL 391 #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \ 392 ((::absl::LogSeverity::kFatal >= \ 393 static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) \ 394 ? MakeCheckOpString<U1, U2>(v1, v2, exprtext) \ 395 : "") 396 #else 397 #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \ 398 MakeCheckOpString<U1, U2>(v1, v2, exprtext) 399 #endif 400 401 // Helper functions for `ABSL_LOG_INTERNAL_CHECK_OP` macro family. The 402 // `(int, int)` override works around the issue that the compiler will not 403 // instantiate the template version of the function on values of unnamed enum 404 // type. 405 #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ 406 template <typename T1, typename T2> \ 407 inline constexpr absl::Nullable<const char*> name##Impl( \ 408 const T1& v1, const T2& v2, absl::Nonnull<const char*> exprtext) { \ 409 using U1 = CheckOpStreamType<T1>; \ 410 using U2 = CheckOpStreamType<T2>; \ 411 return ABSL_PREDICT_TRUE(v1 op v2) \ 412 ? nullptr \ 413 : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1), \ 414 U2(v2), exprtext); \ 415 } \ 416 inline constexpr absl::Nullable<const char*> name##Impl( \ 417 int v1, int v2, absl::Nonnull<const char*> exprtext) { \ 418 return name##Impl<int, int>(v1, v2, exprtext); \ 419 } 420 421 ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_EQ, ==) 422 ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_NE, !=) 423 ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LE, <=) 424 ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LT, <) 425 ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GE, >=) 426 ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GT, >) 427 #undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT 428 #undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL 429 430 absl::Nullable<const char*> CheckstrcmptrueImpl( 431 absl::Nullable<const char*> s1, absl::Nullable<const char*> s2, 432 absl::Nonnull<const char*> exprtext); 433 absl::Nullable<const char*> CheckstrcmpfalseImpl( 434 absl::Nullable<const char*> s1, absl::Nullable<const char*> s2, 435 absl::Nonnull<const char*> exprtext); 436 absl::Nullable<const char*> CheckstrcasecmptrueImpl( 437 absl::Nullable<const char*> s1, absl::Nullable<const char*> s2, 438 absl::Nonnull<const char*> exprtext); 439 absl::Nullable<const char*> CheckstrcasecmpfalseImpl( 440 absl::Nullable<const char*> s1, absl::Nullable<const char*> s2, 441 absl::Nonnull<const char*> exprtext); 442 443 // `CHECK_EQ` and friends want to pass their arguments by reference, however 444 // this winds up exposing lots of cases where people have defined and 445 // initialized static const data members but never declared them (i.e. in a .cc 446 // file), meaning they are not referenceable. This function avoids that problem 447 // for integers (the most common cases) by overloading for every primitive 448 // integer type, even the ones we discourage, and returning them by value. 449 // NOLINTBEGIN(runtime/int) 450 // NOLINTBEGIN(google-runtime-int) 451 template <typename T> 452 inline constexpr const T& GetReferenceableValue(const T& t) { 453 return t; 454 } 455 inline constexpr char GetReferenceableValue(char t) { return t; } 456 inline constexpr unsigned char GetReferenceableValue(unsigned char t) { 457 return t; 458 } 459 inline constexpr signed char GetReferenceableValue(signed char t) { return t; } 460 inline constexpr short GetReferenceableValue(short t) { return t; } 461 inline constexpr unsigned short GetReferenceableValue(unsigned short t) { 462 return t; 463 } 464 inline constexpr int GetReferenceableValue(int t) { return t; } 465 inline constexpr unsigned int GetReferenceableValue(unsigned int t) { 466 return t; 467 } 468 inline constexpr long GetReferenceableValue(long t) { return t; } 469 inline constexpr unsigned long GetReferenceableValue(unsigned long t) { 470 return t; 471 } 472 inline constexpr long long GetReferenceableValue(long long t) { return t; } 473 inline constexpr unsigned long long GetReferenceableValue( 474 unsigned long long t) { 475 return t; 476 } 477 // NOLINTEND(google-runtime-int) 478 // NOLINTEND(runtime/int) 479 480 } // namespace log_internal 481 ABSL_NAMESPACE_END 482 } // namespace absl 483 484 #endif // ABSL_LOG_INTERNAL_CHECK_OP_H_