summaryrefslogtreecommitdiff
path: root/absl/status
diff options
context:
space:
mode:
authorGravatar Benjamin Barenblat <bbaren@google.com>2021-04-08 10:23:55 -0400
committerGravatar Benjamin Barenblat <bbaren@google.com>2021-04-08 10:23:55 -0400
commitfeac56827dd1f0d159ea0bcf2ce37ef1990ac743 (patch)
treebc8ca767be02a5b22118108f9712b72ec64064c3 /absl/status
parent2b91b17d526b464840a3f45504c594cdb50152c5 (diff)
parent997aaf3a28308eba1b9156aa35ab7bca9688e9f6 (diff)
Merge new upstream LTS 20210324.0
Diffstat (limited to 'absl/status')
-rw-r--r--absl/status/internal/status_internal.h18
-rw-r--r--absl/status/internal/statusor_internal.h11
-rw-r--r--absl/status/status.cc51
-rw-r--r--absl/status/status.h101
-rw-r--r--absl/status/status_test.cc28
-rw-r--r--absl/status/statusor.h6
-rw-r--r--absl/status/statusor_test.cc11
7 files changed, 173 insertions, 53 deletions
diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h
index 1f82b8e4..99a2d964 100644
--- a/absl/status/internal/status_internal.h
+++ b/absl/status/internal/status_internal.h
@@ -19,6 +19,17 @@
#include "absl/container/inlined_vector.h"
#include "absl/strings/cord.h"
+#ifndef SWIG
+// Disabled for SWIG as it doesn't parse attributes correctly.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+// Returned Status objects may not be ignored. Codesearch doesn't handle ifdefs
+// as part of a class definitions (b/6995610), so we use a forward declaration.
+class ABSL_MUST_USE_RESULT Status;
+ABSL_NAMESPACE_END
+} // namespace absl
+#endif // !SWIG
+
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -36,6 +47,13 @@ using Payloads = absl::InlinedVector<Payload, 1>;
// Reference-counted representation of Status data.
struct StatusRep {
+ StatusRep(absl::StatusCode code, std::string message,
+ std::unique_ptr<status_internal::Payloads> payloads)
+ : ref(int32_t{1}),
+ code(code),
+ message(std::move(message)),
+ payloads(std::move(payloads)) {}
+
std::atomic<int32_t> ref;
absl::StatusCode code;
std::string message;
diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h
index 96e41da5..eaac2c0b 100644
--- a/absl/status/internal/statusor_internal.h
+++ b/absl/status/internal/statusor_internal.h
@@ -17,6 +17,7 @@
#include <type_traits>
#include <utility>
+#include "absl/base/attributes.h"
#include "absl/meta/type_traits.h"
#include "absl/status/status.h"
#include "absl/utility/utility.h"
@@ -135,18 +136,14 @@ class Helper {
public:
// Move type-agnostic error handling to the .cc.
static void HandleInvalidStatusCtorArg(Status*);
- static void Crash(const absl::Status& status);
+ ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status);
};
// Construct an instance of T in `p` through placement new, passing Args... to
// the constructor.
// This abstraction is here mostly for the gcc performance fix.
template <typename T, typename... Args>
-void PlacementNew(void* p, Args&&... args) {
-#if defined(__GNUC__) && !defined(__clang__)
- // Teach gcc that 'p' cannot be null, fixing code size issues.
- if (p == nullptr) __builtin_unreachable();
-#endif
+ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) {
new (p) T(std::forward<Args>(args)...);
}
@@ -215,7 +212,7 @@ class StatusOrData {
template <typename U,
absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
int> = 0>
- explicit StatusOrData(U&& v) : status_(v) {
+ explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
EnsureNotOk();
}
diff --git a/absl/status/status.cc b/absl/status/status.cc
index a27fd8b3..51a0d268 100644
--- a/absl/status/status.cc
+++ b/absl/status/status.cc
@@ -207,13 +207,12 @@ void Status::UnrefNonInlined(uintptr_t rep) {
}
}
-uintptr_t Status::NewRep(absl::StatusCode code, absl::string_view msg,
- std::unique_ptr<status_internal::Payloads> payloads) {
- status_internal::StatusRep* rep = new status_internal::StatusRep;
- rep->ref.store(1, std::memory_order_relaxed);
- rep->code = code;
- rep->message.assign(msg.data(), msg.size());
- rep->payloads = std::move(payloads);
+uintptr_t Status::NewRep(
+ absl::StatusCode code, absl::string_view msg,
+ std::unique_ptr<status_internal::Payloads> payloads) {
+ status_internal::StatusRep* rep = new status_internal::StatusRep(
+ code, std::string(msg.data(), msg.size()),
+ std::move(payloads));
return PointerToRep(rep);
}
@@ -239,8 +238,9 @@ absl::StatusCode Status::code() const {
void Status::PrepareToModify() {
ABSL_RAW_CHECK(!ok(), "PrepareToModify shouldn't be called on OK status.");
if (IsInlined(rep_)) {
- rep_ = NewRep(static_cast<absl::StatusCode>(raw_code()),
- absl::string_view(), nullptr);
+ rep_ =
+ NewRep(static_cast<absl::StatusCode>(raw_code()), absl::string_view(),
+ nullptr);
return;
}
@@ -251,7 +251,8 @@ void Status::PrepareToModify() {
if (rep->payloads) {
payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads);
}
- rep_ = NewRep(rep->code, message(), std::move(payloads));
+ rep_ = NewRep(rep->code, message(),
+ std::move(payloads));
UnrefNonInlined(rep_i);
}
}
@@ -290,20 +291,26 @@ bool Status::EqualsSlow(const absl::Status& a, const absl::Status& b) {
return true;
}
-std::string Status::ToStringSlow() const {
+std::string Status::ToStringSlow(StatusToStringMode mode) const {
std::string text;
absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message());
- status_internal::StatusPayloadPrinter printer =
- status_internal::GetStatusPayloadPrinter();
- this->ForEachPayload([&](absl::string_view type_url,
- const absl::Cord& payload) {
- absl::optional<std::string> result;
- if (printer) result = printer(type_url, payload);
- absl::StrAppend(
- &text, " [", type_url, "='",
- result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
- "']");
- });
+
+ const bool with_payload = (mode & StatusToStringMode::kWithPayload) ==
+ StatusToStringMode::kWithPayload;
+
+ if (with_payload) {
+ status_internal::StatusPayloadPrinter printer =
+ status_internal::GetStatusPayloadPrinter();
+ this->ForEachPayload([&](absl::string_view type_url,
+ const absl::Cord& payload) {
+ absl::optional<std::string> result;
+ if (printer) result = printer(type_url, payload);
+ absl::StrAppend(
+ &text, " [", type_url, "='",
+ result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
+ "']");
+ });
+ }
return text;
}
diff --git a/absl/status/status.h b/absl/status/status.h
index 42f634e0..61486fee 100644
--- a/absl/status/status.h
+++ b/absl/status/status.h
@@ -57,6 +57,7 @@
#include "absl/container/inlined_vector.h"
#include "absl/status/internal/status_internal.h"
#include "absl/strings/cord.h"
+#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
namespace absl {
@@ -98,7 +99,7 @@ enum class StatusCode : int {
// StatusCode::kCancelled
//
- // kCanelled (gRPC code "CANCELLED") indicates the operation was cancelled,
+ // kCancelled (gRPC code "CANCELLED") indicates the operation was cancelled,
// typically by the caller.
kCancelled = 1,
@@ -198,9 +199,9 @@ enum class StatusCode : int {
// `kAborted`, and `kUnavailable`.
kAborted = 10,
- // StatusCode::kOutofRange
+ // StatusCode::kOutOfRange
//
- // kOutofRange (gRPC code "OUT_OF_RANGE") indicates the operation was
+ // kOutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was
// attempted past the valid range, such as seeking or reading past an
// end-of-file.
//
@@ -279,6 +280,57 @@ std::string StatusCodeToString(StatusCode code);
// Streams StatusCodeToString(code) to `os`.
std::ostream& operator<<(std::ostream& os, StatusCode code);
+// absl::StatusToStringMode
+//
+// An `absl::StatusToStringMode` is an enumerated type indicating how
+// `absl::Status::ToString()` should construct the output string for an non-ok
+// status.
+enum class StatusToStringMode : int {
+ // ToString will not contain any extra data (such as payloads). It will only
+ // contain the error code and message, if any.
+ kWithNoExtraData = 0,
+ // ToString will contain the payloads.
+ kWithPayload = 1 << 0,
+ // ToString will include all the extra data this Status has.
+ kWithEverything = ~kWithNoExtraData,
+};
+
+// absl::StatusToStringMode is specified as a bitmask type, which means the
+// following operations must be provided:
+inline constexpr StatusToStringMode operator&(StatusToStringMode lhs,
+ StatusToStringMode rhs) {
+ return static_cast<StatusToStringMode>(static_cast<int>(lhs) &
+ static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator|(StatusToStringMode lhs,
+ StatusToStringMode rhs) {
+ return static_cast<StatusToStringMode>(static_cast<int>(lhs) |
+ static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator^(StatusToStringMode lhs,
+ StatusToStringMode rhs) {
+ return static_cast<StatusToStringMode>(static_cast<int>(lhs) ^
+ static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator~(StatusToStringMode arg) {
+ return static_cast<StatusToStringMode>(~static_cast<int>(arg));
+}
+inline StatusToStringMode& operator&=(StatusToStringMode& lhs,
+ StatusToStringMode rhs) {
+ lhs = lhs & rhs;
+ return lhs;
+}
+inline StatusToStringMode& operator|=(StatusToStringMode& lhs,
+ StatusToStringMode rhs) {
+ lhs = lhs | rhs;
+ return lhs;
+}
+inline StatusToStringMode& operator^=(StatusToStringMode& lhs,
+ StatusToStringMode rhs) {
+ lhs = lhs ^ rhs;
+ return lhs;
+}
+
// absl::Status
//
// The `absl::Status` class is generally used to gracefully handle errors
@@ -360,7 +412,12 @@ std::ostream& operator<<(std::ostream& os, StatusCode code);
// return result;
// }
//
-class ABSL_MUST_USE_RESULT Status final {
+// For documentation see https://abseil.io/docs/cpp/guides/status.
+//
+// Returned Status objects may not be ignored. status_internal.h has a forward
+// declaration of the form
+// class ABSL_MUST_USE_RESULT Status;
+class Status final {
public:
// Constructors
@@ -370,10 +427,10 @@ class ABSL_MUST_USE_RESULT Status final {
Status();
// Creates a status in the canonical error space with the specified
- // `absl::StatusCode` and error message. If `code == absl::StatusCode::kOk`,
+ // `absl::StatusCode` and error message. If `code == absl::StatusCode::kOk`, // NOLINT
// `msg` is ignored and an object identical to an OK status is constructed.
//
- // The `msg` string must be in UTF-8. The implementation may complain (e.g.,
+ // The `msg` string must be in UTF-8. The implementation may complain (e.g., // NOLINT
// by printing a warning) if it is not.
Status(absl::StatusCode code, absl::string_view msg);
@@ -442,15 +499,17 @@ class ABSL_MUST_USE_RESULT Status final {
// Status::ToString()
//
- // Returns a combination of the error code name, the message and any
- // associated payload messages. This string is designed simply to be human
- // readable and its exact format should not be load bearing. Do not depend on
- // the exact format of the result of `ToString()` which is subject to change.
+ // Returns a string based on the `mode`. By default, it returns combination of
+ // the error code name, the message and any associated payload messages. This
+ // string is designed simply to be human readable and its exact format should
+ // not be load bearing. Do not depend on the exact format of the result of
+ // `ToString()` which is subject to change.
//
// The printed code name and the message are generally substrings of the
// result, and the payloads to be printed use the status payload printer
// mechanism (which is internal).
- std::string ToString() const;
+ std::string ToString(
+ StatusToStringMode mode = StatusToStringMode::kWithPayload) const;
// Status::IgnoreError()
//
@@ -550,8 +609,9 @@ class ABSL_MUST_USE_RESULT Status final {
status_internal::Payloads* GetPayloads();
// Takes ownership of payload.
- static uintptr_t NewRep(absl::StatusCode code, absl::string_view msg,
- std::unique_ptr<status_internal::Payloads> payload);
+ static uintptr_t NewRep(
+ absl::StatusCode code, absl::string_view msg,
+ std::unique_ptr<status_internal::Payloads> payload);
static bool EqualsSlow(const absl::Status& a, const absl::Status& b);
// MSVC 14.0 limitation requires the const.
@@ -580,8 +640,7 @@ class ABSL_MUST_USE_RESULT Status final {
static uintptr_t PointerToRep(status_internal::StatusRep* r);
static status_internal::StatusRep* RepToPointer(uintptr_t r);
- // Returns string for non-ok Status.
- std::string ToStringSlow() const;
+ std::string ToStringSlow(StatusToStringMode mode) const;
// Status supports two different representations.
// - When the low bit is off it is an inlined representation.
@@ -704,9 +763,11 @@ inline Status::Status(Status&& x) noexcept : rep_(x.rep_) {
inline Status& Status::operator=(Status&& x) {
uintptr_t old_rep = rep_;
- rep_ = x.rep_;
- x.rep_ = MovedFromRep();
- Unref(old_rep);
+ if (x.rep_ != old_rep) {
+ rep_ = x.rep_;
+ x.rep_ = MovedFromRep();
+ Unref(old_rep);
+ }
return *this;
}
@@ -743,8 +804,8 @@ inline bool operator!=(const Status& lhs, const Status& rhs) {
return !(lhs == rhs);
}
-inline std::string Status::ToString() const {
- return ok() ? "OK" : ToStringSlow();
+inline std::string Status::ToString(StatusToStringMode mode) const {
+ return ok() ? "OK" : ToStringSlow(mode);
}
inline void Status::IgnoreError() const {
diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc
index ca9488ad..0e1a43ce 100644
--- a/absl/status/status_test.cc
+++ b/absl/status/status_test.cc
@@ -280,6 +280,27 @@ TEST(Status, ToString) {
HasSubstr("[bar='\\xff']")));
}
+TEST(Status, ToStringMode) {
+ absl::Status s(absl::StatusCode::kInternal, "fail");
+ s.SetPayload("foo", absl::Cord("bar"));
+ s.SetPayload("bar", absl::Cord("\377"));
+
+ EXPECT_EQ("INTERNAL: fail",
+ s.ToString(absl::StatusToStringMode::kWithNoExtraData));
+
+ EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithPayload),
+ AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
+ HasSubstr("[bar='\\xff']")));
+
+ EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithEverything),
+ AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
+ HasSubstr("[bar='\\xff']")));
+
+ EXPECT_THAT(s.ToString(~absl::StatusToStringMode::kWithPayload),
+ AllOf(HasSubstr("INTERNAL: fail"), Not(HasSubstr("[foo='bar']")),
+ Not(HasSubstr("[bar='\\xff']"))));
+}
+
absl::Status EraseAndReturn(const absl::Status& base) {
absl::Status copy = base;
EXPECT_TRUE(copy.ErasePayload(kUrl1));
@@ -397,6 +418,12 @@ TEST(Status, MoveAssignment) {
assignee = std::move(status);
EXPECT_EQ(assignee, copy);
}
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ absl::Status copy(status);
+ status = static_cast<absl::Status&&>(status);
+ EXPECT_EQ(status, copy);
+ }
}
TEST(Status, Update) {
@@ -454,5 +481,4 @@ TEST(Status, Swap) {
test_swap(no_payload, with_payload);
test_swap(with_payload, no_payload);
}
-
} // namespace
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
index bdf6039d..b7c55cc8 100644
--- a/absl/status/statusor.h
+++ b/absl/status/statusor.h
@@ -129,13 +129,13 @@ class ABSL_MUST_USE_RESULT StatusOr;
// Example:
//
// absl::StatusOr<int> i = GetCount();
-// if (foo.ok()) {
+// if (i.ok()) {
// updated_total += *i
// }
//
// NOTE: using `absl::StatusOr<T>::value()` when no valid value is present will
// throw an exception if exceptions are enabled or terminate the process when
-// execeptions are not enabled.
+// exceptions are not enabled.
//
// Example:
//
@@ -542,7 +542,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// StatusOr<T>::value_or()
//
- // Returns the current value of `this->ok() == true`. Otherwise constructs a
+ // Returns the current value if `this->ok() == true`. Otherwise constructs a
// value using the provided `default_value`.
//
// Unlike `value`, this function returns by value, copying the current value
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc
index 5e4b2687..c2e8fb7e 100644
--- a/absl/status/statusor_test.cc
+++ b/absl/status/statusor_test.cc
@@ -292,6 +292,17 @@ TEST(StatusOr, TestDefaultCtor) {
EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown);
}
+TEST(StatusOr, StatusCtorForwards) {
+ absl::Status status(absl::StatusCode::kInternal, "Some error");
+
+ EXPECT_EQ(absl::StatusOr<int>(status).status().message(), "Some error");
+ EXPECT_EQ(status.message(), "Some error");
+
+ EXPECT_EQ(absl::StatusOr<int>(std::move(status)).status().message(),
+ "Some error");
+ EXPECT_NE(status.message(), "Some error");
+}
+
// Define `EXPECT_DEATH_OR_THROW` to test the behavior of `StatusOr::value`,
// which either throws `BadStatusOrAccess` or `LOG(FATAL)` based on whether
// exceptions are enabled.