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