| // Copyright 2026 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: status_macros.h |
| // ----------------------------------------------------------------------------- |
| // |
| // Helper macros and methods to return and propagate errors with `absl::Status`. |
| |
| #ifndef ABSL_STATUS_STATUS_MACROS_H_ |
| #define ABSL_STATUS_STATUS_MACROS_H_ |
| |
| #include <cstddef> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| #include "absl/status/status.h" |
| #include "absl/status/status_builder.h" // IWYU pragma: export |
| #include "absl/status/statusor.h" |
| #include "absl/types/source_location.h" |
| |
| // Evaluates an expression that produces a `absl::Status`. If the status is not |
| // ok, returns it from the current function. |
| // |
| // For example: |
| // absl::Status MultiStepFunction() { |
| // ABSL_RETURN_IF_ERROR(Function(args...)); |
| // ABSL_RETURN_IF_ERROR(foo.Method(args...)); |
| // return absl::OkStatus(); |
| // } |
| // |
| // The macro ends with a `absl::StatusBuilder` which allows the returned status |
| // to be extended with more details. Any chained expressions after the macro |
| // will not be evaluated unless there is an error. |
| // |
| // For example: |
| // absl::Status MultiStepFunction() { |
| // ABSL_RETURN_IF_ERROR(Function(args...)) << "in MultiStepFunction"; |
| // ABSL_RETURN_IF_ERROR(foo.Method(args...)).Log(absl::LogSeverity::kError) |
| // << "while processing query: " << query.DebugString(); |
| // return absl::OkStatus(); |
| // } |
| // |
| // `absl::StatusBuilder` supports adapting the builder chain using a `With` |
| // method and a functor. This allows for powerful extensions to the macro. |
| // |
| // For example, teams can define local policies to use across their code: |
| // |
| // StatusBuilder TeamPolicy(StatusBuilder builder) { |
| // return std::move(builder.Log(absl::LogSeverity::kWarning).Attach(...)); |
| // } |
| // |
| // ABSL_RETURN_IF_ERROR(foo()).With(TeamPolicy); |
| // ABSL_RETURN_IF_ERROR(bar()).With(TeamPolicy); |
| // |
| // Changing the return type allows the macro to be used with Task and Rpc |
| // interfaces. See `util::TaskReturn` and `rpc::RpcSetStatus` for details. |
| // |
| // void Read(StringPiece name, util::Task* task) { |
| // int64 id; |
| // ABSL_RETURN_IF_ERROR(GetIdForName(name, &id)).With(TaskReturn(task)); |
| // ABSL_RETURN_IF_ERROR(ReadForId(id)).With(TaskReturn(task)); |
| // task->Return(); |
| // } |
| // |
| // If using this macro inside a lambda, you need to annotate the return type |
| // to avoid confusion between a `absl::StatusBuilder` and a `absl::Status` type. |
| // E.g. |
| // |
| // []() -> absl::Status { |
| // ABSL_RETURN_IF_ERROR(Function(args...)); |
| // ABSL_RETURN_IF_ERROR(foo.Method(args...)); |
| // return absl::OkStatus(); |
| // } |
| #define ABSL_RETURN_IF_ERROR(expr) \ |
| ABSL_INTERNAL_STATUS_MACROS_RETURN_IF_ERROR_IMPL_(return, expr) |
| |
| // Executes an expression `rexpr` that returns an `absl::StatusOr<T>`. On OK, |
| // moves its value into the variable defined by `lhs`, otherwise returns |
| // from the current function. By default the error status is returned |
| // unchanged, but it may be modified by an `error_expression`. If there is an |
| // error, `lhs` is not evaluated; thus any side effects that `lhs` may have |
| // only occur in the success case. |
| // |
| // Interface: |
| // |
| // ABSL_ASSIGN_OR_RETURN(lhs, rexpr) |
| // ABSL_ASSIGN_OR_RETURN(lhs, rexpr, error_expression); |
| // |
| // WARNING: if lhs is parenthesized, the parentheses are removed. See examples |
| // for more details. |
| // |
| // WARNING: expands into multiple statements; it cannot be used in a single |
| // statement (e.g. as the body of an if statement without {})! |
| // |
| // Example: Declaring and initializing a new variable (ValueType can be anything |
| // that can be initialized with assignment--including a const |
| // reference, although that's discouraged by go/totw/107): |
| // ABSL_ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(arg)); |
| // |
| // Example: Assigning to an existing variable: |
| // ValueType value; |
| // ABSL_ASSIGN_OR_RETURN(value, MaybeGetValue(arg)); |
| // |
| // Example: Assigning to an expression with side effects: |
| // MyProto data; |
| // ABSL_ASSIGN_OR_RETURN(*data.mutable_str(), MaybeGetValue(arg)); |
| // // No field "str" is added on error. |
| // |
| // Example: Initializing a `std::unique_ptr`. |
| // ABSL_ASSIGN_OR_RETURN(std::unique_ptr<T> ptr, MaybeGetPtr(arg)); |
| // |
| // Example: Initializing a map. Because of C++ preprocessor limitations, |
| // the type used in ABSL_ASSIGN_OR_RETURN cannot contain commas, so wrap the |
| // lhs in parentheses: |
| // ABSL_ASSIGN_OR_RETURN((absl::flat_hash_map<Foo, Bar> my_map), GetMap()); |
| // Or use `auto` if the type is obvious enough: |
| // ABSL_ASSIGN_OR_RETURN(auto my_map, GetMap()); |
| // |
| // Example: Assigning to structured bindings (go/totw/169). The same situation |
| // with comma as in map, so wrap the statement in parentheses. |
| // ABSL_ASSIGN_OR_RETURN((auto [first, second]), GetPair()); |
| // |
| // If passed, the `error_expression` is evaluated to produce the return |
| // value. The expression may reference any variable visible in scope, as |
| // well as a `absl::StatusBuilder` object populated with the error and |
| // named by a single underscore `_`. The expression typically uses the |
| // builder to modify the status and is returned directly in manner similar |
| // to ABSL_RETURN_IF_ERROR. The expression may, however, evaluate to any type |
| // returnable by the function, including (void). For example: |
| // |
| // Example: Adjusting the error message. |
| // ABSL_ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query), |
| // _ << "while processing query " << query.DebugString()); |
| // |
| // Example: Logging the error on failure. |
| // ABSL_ASSIGN_OR_RETURN(ValueType value, MaybeGetValue(query), _.LogError()); |
| // |
| #define ABSL_ASSIGN_OR_RETURN(...) \ |
| ABSL_INTERNAL_STATUS_MACROS_ASSIGN_OR_RETURN_IMPL_(return, __VA_ARGS__) |
| |
| // ================================================================= |
| // == Implementation details, do not rely on anything below here. == |
| // ================================================================= |
| |
| #define ABSL_INTERNAL_STATUS_MACROS_RETURN_IF_ERROR_IMPL_(return_keyword, \ |
| expr) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ |
| if (auto status_macro_internal_adaptor = \ |
| absl::status_macro_internal::MacroAdaptor( \ |
| (expr), absl::SourceLocation::current())) { \ |
| } else /* NOLINT */ \ |
| return_keyword status_macro_internal_adaptor.Consume() |
| |
| #define ABSL_INTERNAL_STATUS_MACROS_ASSIGN_OR_RETURN_IMPL_(return_keyword, \ |
| ...) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_GET_VARIADIC_( \ |
| (return_keyword, __VA_ARGS__, \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_3_, \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_2_)) \ |
| (return_keyword, __VA_ARGS__) |
| |
| constexpr bool HasPotentialConditionalOperator(const char* lhs, int size) { |
| for (int i = 0; i < size; ++i) { |
| if (lhs[i] == '?') { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| template <std::size_t N> |
| constexpr bool IsEnclosedByParentheses(const char (&lhs)[N]) { |
| if (N < 2) { |
| return false; |
| } |
| return lhs[0] == '(' && lhs[N - 2] == ')'; |
| } |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace status_macro_internal { |
| |
| template <typename T, typename EnableIf = void> |
| struct IsAllowedStatusOrMacroType : std::false_type {}; |
| |
| template <typename T> |
| struct IsAllowedStatusOrMacroType< |
| T, std::enable_if_t<std::is_convertible_v< |
| T*, typename absl::StatusOr<typename T::value_type>*>>> |
| : std::true_type {}; |
| |
| } // namespace status_macro_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // MSVC incorrectly expands variadic macros, splice together a macro call to |
| // work around the bug. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_GET_VARIADIC_HELPER_(_1, _2, _3, _4, \ |
| NAME, ...) \ |
| NAME |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_GET_VARIADIC_(args) \ |
| /* NOLINTNEXTLINE(clang-diagnostic-pre-c++20-compat) */ \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_GET_VARIADIC_HELPER_ args |
| |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_2_(return_keyword, \ |
| lhs, rexpr) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), \ |
| lhs, rexpr, \ |
| return_keyword absl::Status( \ |
| std::move(ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, \ |
| __LINE__)) \ |
| .status(), \ |
| absl::SourceLocation::current())) |
| |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_3_( \ |
| return_keyword, lhs, rexpr, error_expression) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), \ |
| lhs, rexpr, /* NOLINTNEXTLINE(misc-const-correctness) */ \ |
| absl::StatusBuilder _( \ |
| std::move(ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, \ |
| __LINE__)) \ |
| .status(), \ |
| absl::SourceLocation::current()); \ |
| (void)_; /* error_expression is allowed to not use this variable */ \ |
| return_keyword(error_expression)) |
| |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \ |
| statusor, lhs, rexpr, error_expression) \ |
| auto statusor = (rexpr); \ |
| if (ABSL_PREDICT_FALSE(!statusor.ok())) { \ |
| error_expression; \ |
| } \ |
| { \ |
| static_assert( \ |
| !IsEnclosedByParentheses(#lhs) || \ |
| !HasPotentialConditionalOperator(#lhs, sizeof(#lhs) - 2), \ |
| "Identified potential conditional operator, consider not " \ |
| "using ABSL_ASSIGN_OR_RETURN"); \ |
| } \ |
| { \ |
| static_assert( \ |
| absl::status_macro_internal::IsAllowedStatusOrMacroType< \ |
| typename std::remove_const<decltype(statusor)>::type>(), \ |
| "ABSL_ASSIGN_OR_RETURN should only be used with absl::StatusOr<>"); \ |
| } \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED(lhs) = \ |
| (*std::move(statusor)) |
| |
| // Internal helpers for macro expansion. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_EAT(...) |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_REM(...) __VA_ARGS__ |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_COMMA(...) , |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_ARG_3(a, b, c, ...) c |
| |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_HAS_COMMA(...) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_REM( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_ARG_3(__VA_ARGS__, 1, 10)) |
| |
| // Concatenates five macro arguments. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_5(a, b, c, d, e) a##b##c##d##e |
| |
| // Identifies (below) the case where all arguments are empty, except the last. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_IS_EMPTY_CASE_1010101 , |
| |
| // Evaluates to 1 if the arguments concatenate to 1010101, and 10 otherwise. |
| #define ABSL_INTERNAL_STATUS_MACROS_1_IF_1010101_ELSE_10(a, b, c, d) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_HAS_COMMA( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_5( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_IS_EMPTY_CASE_, a, b, c, d)) |
| |
| // Evaluates to 1 if __VA_OPT__ is supported and the argument list is non-empty, |
| // and 0 otherwise. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_HAVE_VA_OPT(...) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_ARG_3(__VA_OPT__(, ), 1, 0, ) |
| |
| #if ABSL_INTERNAL_STATUS_MACROS_IMPL_HAVE_VA_OPT(.) |
| // Evaluates to 1 if the argument list is empty, and 10 otherwise. |
| #define ABSL_INTERNAL_STATUS_MACROS_1_IF_EMPTY_ELSE_10(...) 1##__VA_OPT__(0) |
| #else |
| #define ABSL_INTERNAL_STATUS_MACROS_1_IF_EMPTY_ELSE_10(...) \ |
| ABSL_INTERNAL_STATUS_MACROS_1_IF_1010101_ELSE_10( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_HAS_COMMA(__VA_ARGS__), \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_HAS_COMMA( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_COMMA __VA_ARGS__), \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_HAS_COMMA(__VA_ARGS__()), \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_HAS_COMMA( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_COMMA __VA_ARGS__())) |
| |
| #endif |
| |
| // Parenthesized case: strips the initial pair of parentheses from the input. |
| // |
| // Note that this may not result in an equivalent expression. For example, |
| // (*a)[b] would evaluate to a[b]. The caller below is required to ensure |
| // this is only called when the input is fully parenthesized to avoid this |
| // issue. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED_1(x) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_REM x |
| |
| // Unparenthesized case: evaluates to the argument list as-is. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED_10(x) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_REM(x) |
| |
| // If the input is parenthesized, removes the parentheses. Otherwise expands to |
| // the input unchanged. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED(...) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_REM( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED_, \ |
| ABSL_INTERNAL_STATUS_MACROS_1_IF_EMPTY_ELSE_10( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_EAT __VA_ARGS__))( \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_REM(__VA_ARGS__))) |
| |
| // Internal helper for concatenating macro values. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y) x##y |
| |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_(x, y) \ |
| ABSL_INTERNAL_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y) |
| |
| // The GNU compiler emits a warning for code like: |
| // |
| // if (foo) |
| // if (bar) { } else baz; |
| // |
| // because it thinks you might want the else to bind to the first if. This |
| // leads to problems with code like: |
| // |
| // if (do_expr) ABSL_RETURN_IF_ERROR(expr) << "Some message"; |
| // |
| // The "switch (0) case 0:" idiom is used to suppress this. |
| #define ABSL_INTERNAL_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ |
| switch (0) \ |
| case 0: \ |
| default: // NOLINT |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace status_macro_internal { |
| |
| // Provides a conversion to bool so that it can be used inside an if statement |
| // that declares a variable. |
| class StatusAdaptorForMacros { |
| public: |
| StatusAdaptorForMacros( |
| const absl::Status& status, |
| absl::SourceLocation loc = absl::SourceLocation::current()) |
| : builder_(status, loc) {} |
| |
| StatusAdaptorForMacros( |
| absl::Status&& status, |
| absl::SourceLocation loc = absl::SourceLocation::current()) |
| : builder_(std::move(status), loc) {} |
| |
| StatusAdaptorForMacros(const StatusBuilder& builder, |
| absl::SourceLocation = absl::SourceLocation()) |
| : builder_(builder) {} |
| |
| StatusAdaptorForMacros(StatusBuilder&& builder, |
| absl::SourceLocation = absl::SourceLocation()) |
| : builder_(std::move(builder)) {} |
| |
| StatusAdaptorForMacros(const StatusAdaptorForMacros&) = delete; |
| StatusAdaptorForMacros& operator=(const StatusAdaptorForMacros&) = delete; |
| |
| explicit operator bool() const { return ABSL_PREDICT_TRUE(builder_.ok()); } |
| |
| StatusBuilder&& Consume() { return std::move(builder_); } |
| |
| private: |
| StatusBuilder builder_; |
| }; |
| |
| // Special adaptor for use by ABSL_RETURN_IF_ERROR for absl::Status arguments. |
| // This one avoids constructing a StatusBuilder on the fast path. |
| // |
| // REQUIRES: Only used by ABSL_RETURN_IF_ERROR implementation. |
| class ReturnIfErrorAdaptor { |
| public: |
| explicit ReturnIfErrorAdaptor( |
| const absl::Status& status, |
| absl::SourceLocation loc = absl::SourceLocation::current()) |
| : status_(status), loc_(loc) {} |
| |
| explicit ReturnIfErrorAdaptor( |
| absl::Status&& status, |
| absl::SourceLocation loc = absl::SourceLocation::current()) |
| : status_(std::move(status)), loc_(loc) {} |
| |
| ~ReturnIfErrorAdaptor() { |
| // WARNING! WARNING! WARNING! |
| // |
| // We play fast and loose here and avoid destroying status_. This should be |
| // safe because status_ will never own memory at destruction time. The two |
| // cases to consider are: |
| // (1) OK: OkStatus() representation needs no cleanup |
| // (2) Not-OK: we take the else branch in ABSL_RETURN_IF_ERROR and move |
| // status_ into StatusBuilder which leaves status_ with a MovedFromRep |
| // that needs no cleanup. |
| // If the absl::Status implementation changes, leaks should be caught by |
| // the various tests we have when run under lsan or debug leak checker. |
| } |
| |
| explicit operator bool() const { return ABSL_PREDICT_TRUE(status_.ok()); } |
| |
| StatusBuilder Consume() { return StatusBuilder(std::move(status_), loc_); } |
| |
| private: |
| // Place the status inside a union so we can avoid generating unnecessary code |
| // to call the Status destructor. |
| union { |
| absl::Status status_; |
| char nothing_[1]; |
| }; |
| absl::SourceLocation loc_; |
| }; |
| |
| // Overloads of MacroAdaptor that pick the right adaptor class |
| // for each argument type. |
| // |
| // TODO(b/501387693): Replace these with deduction guides of template |
| // specializations once the bug is fixed. (See prior file revision.) |
| inline ReturnIfErrorAdaptor MacroAdaptor(const absl::Status& s, |
| absl::SourceLocation loc) { |
| return ReturnIfErrorAdaptor(s, loc); |
| } |
| inline ReturnIfErrorAdaptor MacroAdaptor(absl::Status&& s, |
| absl::SourceLocation loc) { |
| return ReturnIfErrorAdaptor(std::move(s), loc); |
| } |
| inline StatusAdaptorForMacros MacroAdaptor(const StatusBuilder& s, |
| absl::SourceLocation loc) { |
| return StatusAdaptorForMacros(s, loc); |
| } |
| inline StatusAdaptorForMacros MacroAdaptor(StatusBuilder&& s, |
| absl::SourceLocation loc) { |
| return StatusAdaptorForMacros(std::move(s), loc); |
| } |
| |
| } // namespace status_macro_internal |
| |
| // By defining ABSL_DEFINE_UNQUALIFIED_STATUS_MACROS, this library also provides |
| // unqualified versions of its macros. |
| // |
| // Unqualified macro names are likely to collide with those in other projects, |
| // and so are not recommended. Furthermore, this is true for any transitive |
| // dependencies of Abseil: it is impossible to be confident that downstream |
| // libraries will neither define these macros themselves nor depend on a |
| // different library that also defines them. |
| // |
| // To enable unqualified names despite the caveats, define |
| // `ABSL_DEFINE_UNQUALIFIED_STATUS_MACROS` preferably at the command line, e.g. |
| // `-DABSL_DEFINE_UNQUALIFIED_STATUS_MACROS`, or `local_defines = |
| // ["ABSL_DEFINE_UNQUALIFIED_STATUS_MACROS"]` if using Bazel. |
| // |
| // These are turned on by default inside Google's internal codebase where their |
| // use is historically ubiquitous. Other OSS Google projects should use the |
| // qualified versions. |
| // |
| #ifdef ABSL_DEFINE_UNQUALIFIED_STATUS_MACROS |
| #define ASSIGN_OR_RETURN(...) ABSL_ASSIGN_OR_RETURN(__VA_ARGS__) |
| #define RETURN_IF_ERROR(...) ABSL_RETURN_IF_ERROR(__VA_ARGS__) |
| #endif // ABSL_DEFINE_UNQUALIFIED_STATUS_MACROS |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STATUS_STATUS_MACROS_H_ |