Refactor error factories to propagate static knowledge to the compiler, where supported. This allows the compiler to optimize conversions to StatusOr since it can assume the Status is !ok instead of having to check again. PiperOrigin-RevId: 896110150 Change-Id: I0dc167906b761339aaac5934764fe2bd6deb1624
diff --git a/absl/status/status.cc b/absl/status/status.cc index 8cd0a84..3ef4a27 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc
@@ -158,75 +158,35 @@ return os; } -Status AbortedError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kAborted, message, loc); +namespace status_internal { +// We use an int in the template parameter to shorten mangled names. +template <int error_code> +Status MakeErrorImpl(string_view message, SourceLocation loc) { + return Status(static_cast<StatusCode>(error_code), message, loc); } -Status AlreadyExistsError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kAlreadyExists, message, loc); -} - -Status CancelledError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kCancelled, message, loc); -} - -Status DataLossError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kDataLoss, message, loc); -} - -Status DeadlineExceededError(absl::string_view message, - absl::SourceLocation loc) { - return Status(absl::StatusCode::kDeadlineExceeded, message, loc); -} - -Status FailedPreconditionError(absl::string_view message, - absl::SourceLocation loc) { - return Status(absl::StatusCode::kFailedPrecondition, message, loc); -} - -Status InternalError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kInternal, message, loc); -} - -Status InvalidArgumentError(absl::string_view message, - absl::SourceLocation loc) { - return Status(absl::StatusCode::kInvalidArgument, message, loc); -} - -Status NotFoundError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kNotFound, message, loc); -} - -Status OutOfRangeError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kOutOfRange, message, loc); -} - -Status PermissionDeniedError(absl::string_view message, - absl::SourceLocation loc) { - return Status(absl::StatusCode::kPermissionDenied, message, loc); -} - -Status ResourceExhaustedError(absl::string_view message, - absl::SourceLocation loc) { - return Status(absl::StatusCode::kResourceExhausted, message, loc); -} - -Status UnauthenticatedError(absl::string_view message, - absl::SourceLocation loc) { - return Status(absl::StatusCode::kUnauthenticated, message, loc); -} - -Status UnavailableError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kUnavailable, message, loc); -} - -Status UnimplementedError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kUnimplemented, message, loc); -} - -Status UnknownError(absl::string_view message, absl::SourceLocation loc) { - return Status(absl::StatusCode::kUnknown, message, loc); -} +// Explicit instantiation for all the error codes. +// If we add more error code, we need to add their values on this list. +// Using ints here instead of static_cast<int>(StatusCode::kFoo) makes it easier +// to see that the list is complete. +template Status MakeErrorImpl<0>(string_view, SourceLocation); +template Status MakeErrorImpl<1>(string_view, SourceLocation); +template Status MakeErrorImpl<2>(string_view, SourceLocation); +template Status MakeErrorImpl<3>(string_view, SourceLocation); +template Status MakeErrorImpl<4>(string_view, SourceLocation); +template Status MakeErrorImpl<5>(string_view, SourceLocation); +template Status MakeErrorImpl<6>(string_view, SourceLocation); +template Status MakeErrorImpl<7>(string_view, SourceLocation); +template Status MakeErrorImpl<8>(string_view, SourceLocation); +template Status MakeErrorImpl<9>(string_view, SourceLocation); +template Status MakeErrorImpl<10>(string_view, SourceLocation); +template Status MakeErrorImpl<11>(string_view, SourceLocation); +template Status MakeErrorImpl<12>(string_view, SourceLocation); +template Status MakeErrorImpl<13>(string_view, SourceLocation); +template Status MakeErrorImpl<14>(string_view, SourceLocation); +template Status MakeErrorImpl<15>(string_view, SourceLocation); +template Status MakeErrorImpl<16>(string_view, SourceLocation); +} // namespace status_internal bool IsAborted(const Status& status) { return status.code() == absl::StatusCode::kAborted;
diff --git a/absl/status/status.h b/absl/status/status.h index 62efd46..a2cd834 100644 --- a/absl/status/status.h +++ b/absl/status/status.h
@@ -1062,6 +1062,111 @@ const char* absl_nonnull StatusMessageAsCStr( const Status& status ABSL_ATTRIBUTE_LIFETIME_BOUND); +namespace status_internal { +// We use an int in the template parameter to shorten mangled names. +template <int error_code> +Status MakeErrorImpl(string_view message, SourceLocation loc); +// Make the instantiations extern to reduce bloat on callers. +extern template Status MakeErrorImpl<0>(string_view, SourceLocation); +extern template Status MakeErrorImpl<1>(string_view, SourceLocation); +extern template Status MakeErrorImpl<2>(string_view, SourceLocation); +extern template Status MakeErrorImpl<3>(string_view, SourceLocation); +extern template Status MakeErrorImpl<4>(string_view, SourceLocation); +extern template Status MakeErrorImpl<5>(string_view, SourceLocation); +extern template Status MakeErrorImpl<6>(string_view, SourceLocation); +extern template Status MakeErrorImpl<7>(string_view, SourceLocation); +extern template Status MakeErrorImpl<8>(string_view, SourceLocation); +extern template Status MakeErrorImpl<9>(string_view, SourceLocation); +extern template Status MakeErrorImpl<10>(string_view, SourceLocation); +extern template Status MakeErrorImpl<11>(string_view, SourceLocation); +extern template Status MakeErrorImpl<12>(string_view, SourceLocation); +extern template Status MakeErrorImpl<13>(string_view, SourceLocation); +extern template Status MakeErrorImpl<14>(string_view, SourceLocation); +extern template Status MakeErrorImpl<15>(string_view, SourceLocation); +extern template Status MakeErrorImpl<16>(string_view, SourceLocation); + +template <StatusCode error_code> +Status MakeError(string_view message, SourceLocation loc) { + Status out = MakeErrorImpl<static_cast<int>(error_code)>(message, loc); + // -Wassume warning complains about potential side effects of `ok()`, so use a + // local to avoid that. + ABSL_ATTRIBUTE_UNUSED bool ok = out.ok(); + ABSL_ASSUME(!ok); + return out; +} +} // namespace status_internal + +// Inline implementations to give the compiler static knowledge about the +// objects. +inline Status AbortedError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kAborted>(message, loc); +} +inline Status AlreadyExistsError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kAlreadyExists>(message, loc); +} +inline Status CancelledError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kCancelled>(message, loc); +} +inline Status DataLossError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kDataLoss>(message, loc); +} +inline Status DeadlineExceededError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kDeadlineExceeded>(message, + loc); +} +inline Status FailedPreconditionError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kFailedPrecondition>(message, + loc); +} +inline Status InternalError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kInternal>(message, loc); +} +inline Status InvalidArgumentError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kInvalidArgument>(message, loc); +} +inline Status NotFoundError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kNotFound>(message, loc); +} +inline Status OutOfRangeError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kOutOfRange>(message, loc); +} +inline Status PermissionDeniedError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kPermissionDenied>(message, + loc); +} +inline Status ResourceExhaustedError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kResourceExhausted>(message, + loc); +} +inline Status UnauthenticatedError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kUnauthenticated>(message, loc); +} +inline Status UnavailableError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kUnavailable>(message, loc); +} +inline Status UnimplementedError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kUnimplemented>(message, loc); +} +inline Status UnknownError(absl::string_view message, + absl::SourceLocation loc) { + return status_internal::MakeError<StatusCode::kUnknown>(message, loc); +} + ABSL_NAMESPACE_END } // namespace absl