summaryrefslogtreecommitdiff
path: root/absl/status
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2021-07-29 08:04:56 -0700
committerGravatar rogeeff <rogeeff@google.com>2021-07-29 14:17:36 -0400
commit89c531c1e0d7372e2e7029f072a35495c5447d61 (patch)
tree82d07491bf41094d1383e1ef1e1f8d725adabd85 /absl/status
parent4bb739310c0257bedc41bfe2824c3f2860398a65 (diff)
Export of internal Abseil changes
-- e1a0989213908927f05002ab7697955ad7dc5632 by Martijn Vels <mvels@google.com>: Introduce CordRepBtreeReader CordRepBtreeReader provides forward navigation on cord btrees with absolute positional (offset) context, iterating over btree data in absl::string_view chunks. PiperOrigin-RevId: 387585161 -- 206d298e2bccb998731995cb05717b31fa9d90ec by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 387577465 -- f07fafe8a400a4f5dfef186d1a3b61fb7f709fe5 by Abseil Team <absl-team@google.com>: This change adds debug-build enforcement that the inputs to absl::c_set_intersection are sorted, which is a prerequisite of std::set_intersection and required for correct operation of the algorithm. PiperOrigin-RevId: 387446657 -- 2ca15c6361bb758be7fb88cae82bf8489b4d3364 by Abseil Team <absl-team@google.com>: Change BadStatusOrAccess::what() to contain status_.ToString() This ensures that on uncaught exception propagation that would cause program termination, the message contains information on the error which caused the failure. Lazy initialization of what_ is a value judgement: if most callers are expected to call status() not what(), lazy initialization is correct. If most callers are expected to call what(), it should be initialized on construction to avoid atomic operation overhead. PiperOrigin-RevId: 387402243 -- 3e855084e104dc972a0c4385395e6d8e8465127f by Gennadiy Rozental <rogeeff@google.com>: LSC: Standardize access to GoogleTest flags on GTEST_FLAG_GET/GTEST_FLAG_SET This change is necessary to move Googletest flags out of the testing:: namespace without breaking code. These new macros will continue to be required for code that needs to work both inside Google's monorepo and outside in OSS, but can be used anywhere inside the monorepo. PiperOrigin-RevId: 387396025 -- 1ccf5895a15059ef689af5c4817d7b84f73190be by Gennadiy Rozental <rogeeff@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 387388496 GitOrigin-RevId: e1a0989213908927f05002ab7697955ad7dc5632 Change-Id: I3606d9ce29d909a3555e662e9df564202cf5068d
Diffstat (limited to 'absl/status')
-rw-r--r--absl/status/BUILD.bazel2
-rw-r--r--absl/status/CMakeLists.txt1
-rw-r--r--absl/status/statusor.cc36
-rw-r--r--absl/status/statusor.h28
-rw-r--r--absl/status/statusor_test.cc70
5 files changed, 109 insertions, 28 deletions
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel
index 189bd73d..30df22ae 100644
--- a/absl/status/BUILD.bazel
+++ b/absl/status/BUILD.bazel
@@ -78,6 +78,7 @@ cc_library(
copts = ABSL_DEFAULT_COPTS,
deps = [
":status",
+ "//absl/base",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/meta:type_traits",
@@ -96,6 +97,7 @@ cc_test(
":statusor",
"//absl/base",
"//absl/memory",
+ "//absl/strings",
"//absl/types:any",
"//absl/utility",
"@com_google_googletest//:gtest_main",
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt
index 1248dff0..43898564 100644
--- a/absl/status/CMakeLists.txt
+++ b/absl/status/CMakeLists.txt
@@ -64,6 +64,7 @@ absl_cc_library(
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::base
absl::status
absl::core_headers
absl::raw_logging_internal
diff --git a/absl/status/statusor.cc b/absl/status/statusor.cc
index b954b45e..96642b34 100644
--- a/absl/status/statusor.cc
+++ b/absl/status/statusor.cc
@@ -16,6 +16,7 @@
#include <cstdlib>
#include <utility>
+#include "absl/base/call_once.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
@@ -26,13 +27,44 @@ ABSL_NAMESPACE_BEGIN
BadStatusOrAccess::BadStatusOrAccess(absl::Status status)
: status_(std::move(status)) {}
-BadStatusOrAccess::~BadStatusOrAccess() = default;
+BadStatusOrAccess::BadStatusOrAccess(const BadStatusOrAccess& other)
+ : status_(other.status_) {}
+
+BadStatusOrAccess& BadStatusOrAccess::operator=(
+ const BadStatusOrAccess& other) {
+ // Ensure assignment is correct regardless of whether this->InitWhat() has
+ // already been called.
+ other.InitWhat();
+ status_ = other.status_;
+ what_ = other.what_;
+ return *this;
+}
+
+BadStatusOrAccess& BadStatusOrAccess::operator=(BadStatusOrAccess&& other) {
+ // Ensure assignment is correct regardless of whether this->InitWhat() has
+ // already been called.
+ other.InitWhat();
+ status_ = std::move(other.status_);
+ what_ = std::move(other.what_);
+ return *this;
+}
+
+BadStatusOrAccess::BadStatusOrAccess(BadStatusOrAccess&& other)
+ : status_(std::move(other.status_)) {}
+
const char* BadStatusOrAccess::what() const noexcept {
- return "Bad StatusOr access";
+ InitWhat();
+ return what_.c_str();
}
const absl::Status& BadStatusOrAccess::status() const { return status_; }
+void BadStatusOrAccess::InitWhat() const {
+ absl::call_once(init_what_, [this] {
+ what_ = absl::StrCat("Bad StatusOr access: ", status_.ToString());
+ });
+}
+
namespace internal_statusor {
void Helper::HandleInvalidStatusCtorArg(absl::Status* status) {
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
index b7c55cc8..235a3433 100644
--- a/absl/status/statusor.h
+++ b/absl/status/statusor.h
@@ -44,6 +44,7 @@
#include <utility>
#include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
#include "absl/meta/type_traits.h"
#include "absl/status/internal/statusor_internal.h"
#include "absl/status/status.h"
@@ -72,13 +73,18 @@ ABSL_NAMESPACE_BEGIN
class BadStatusOrAccess : public std::exception {
public:
explicit BadStatusOrAccess(absl::Status status);
- ~BadStatusOrAccess() override;
+ ~BadStatusOrAccess() override = default;
+
+ BadStatusOrAccess(const BadStatusOrAccess& other);
+ BadStatusOrAccess& operator=(const BadStatusOrAccess& other);
+ BadStatusOrAccess(BadStatusOrAccess&& other);
+ BadStatusOrAccess& operator=(BadStatusOrAccess&& other);
// BadStatusOrAccess::what()
//
// Returns the associated explanatory string of the `absl::StatusOr<T>`
- // object's error code. This function only returns the string literal "Bad
- // StatusOr Access" for cases when evaluating general exceptions.
+ // object's error code. This function contains information about the failing
+ // status, but its exact formatting may change and should not be depended on.
//
// The pointer of this string is guaranteed to be valid until any non-const
// function is invoked on the exception object.
@@ -91,7 +97,11 @@ class BadStatusOrAccess : public std::exception {
const absl::Status& status() const;
private:
+ void InitWhat() const;
+
absl::Status status_;
+ mutable absl::once_flag init_what_;
+ mutable std::string what_;
};
// Returned StatusOr objects may not be ignored.
@@ -437,8 +447,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
T, U&&>>>>>::value,
int> = 0>
StatusOr(U&& u) // NOLINT
- : StatusOr(absl::in_place, std::forward<U>(u)) {
- }
+ : StatusOr(absl::in_place, std::forward<U>(u)) {}
template <
typename U = T,
@@ -457,8 +466,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
absl::negation<std::is_convertible<U&&, T>>>::value,
int> = 0>
explicit StatusOr(U&& u) // NOLINT
- : StatusOr(absl::in_place, std::forward<U>(u)) {
- }
+ : StatusOr(absl::in_place, std::forward<U>(u)) {}
// StatusOr<T>::ok()
//
@@ -481,7 +489,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// Returns a reference to the current `absl::Status` contained within the
// `absl::StatusOr<T>`. If `absl::StatusOr<T>` contains a `T`, then this
// function returns `absl::OkStatus()`.
- const Status& status() const &;
+ const Status& status() const&;
Status status() &&;
// StatusOr<T>::value()
@@ -661,7 +669,9 @@ StatusOr<T>::StatusOr(absl::in_place_t, std::initializer_list<U> ilist,
: Base(absl::in_place, ilist, std::forward<Args>(args)...) {}
template <typename T>
-const Status& StatusOr<T>::status() const & { return this->status_; }
+const Status& StatusOr<T>::status() const& {
+ return this->status_;
+}
template <typename T>
Status StatusOr<T>::status() && {
return ok() ? OkStatus() : std::move(this->status_);
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc
index c2e8fb7e..7cae90e1 100644
--- a/absl/status/statusor_test.cc
+++ b/absl/status/statusor_test.cc
@@ -17,6 +17,7 @@
#include <array>
#include <initializer_list>
#include <memory>
+#include <string>
#include <type_traits>
#include <utility>
@@ -25,6 +26,7 @@
#include "absl/base/casts.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
+#include "absl/strings/string_view.h"
#include "absl/types/any.h"
#include "absl/utility/utility.h"
@@ -34,6 +36,7 @@ using ::testing::AllOf;
using ::testing::AnyWith;
using ::testing::ElementsAre;
using ::testing::Field;
+using ::testing::HasSubstr;
using ::testing::Ne;
using ::testing::Not;
using ::testing::Pointee;
@@ -257,9 +260,9 @@ TEST(StatusOr, TestMoveOnlyInitializationFromTemporaryByValueOrDie) {
TEST(StatusOr, TestValueOrDieOverloadForConstTemporary) {
static_assert(
- std::is_same<const int&&,
- decltype(
- std::declval<const absl::StatusOr<int>&&>().value())>(),
+ std::is_same<
+ const int&&,
+ decltype(std::declval<const absl::StatusOr<int>&&>().value())>(),
"value() for const temporaries should return const T&&");
}
@@ -303,20 +306,57 @@ TEST(StatusOr, StatusCtorForwards) {
EXPECT_NE(status.message(), "Some error");
}
+TEST(BadStatusOrAccessTest, CopyConstructionWhatOk) {
+ absl::Status error =
+ absl::InternalError("some arbitrary message too big for the sso buffer");
+ absl::BadStatusOrAccess e1{error};
+ absl::BadStatusOrAccess e2{e1};
+ EXPECT_THAT(e1.what(), HasSubstr(error.ToString()));
+ EXPECT_THAT(e2.what(), HasSubstr(error.ToString()));
+}
+
+TEST(BadStatusOrAccessTest, CopyAssignmentWhatOk) {
+ absl::Status error =
+ absl::InternalError("some arbitrary message too big for the sso buffer");
+ absl::BadStatusOrAccess e1{error};
+ absl::BadStatusOrAccess e2{absl::InternalError("other")};
+ e2 = e1;
+ EXPECT_THAT(e1.what(), HasSubstr(error.ToString()));
+ EXPECT_THAT(e2.what(), HasSubstr(error.ToString()));
+}
+
+TEST(BadStatusOrAccessTest, MoveConstructionWhatOk) {
+ absl::Status error =
+ absl::InternalError("some arbitrary message too big for the sso buffer");
+ absl::BadStatusOrAccess e1{error};
+ absl::BadStatusOrAccess e2{std::move(e1)};
+ EXPECT_THAT(e2.what(), HasSubstr(error.ToString()));
+}
+
+TEST(BadStatusOrAccessTest, MoveAssignmentWhatOk) {
+ absl::Status error =
+ absl::InternalError("some arbitrary message too big for the sso buffer");
+ absl::BadStatusOrAccess e1{error};
+ absl::BadStatusOrAccess e2{absl::InternalError("other")};
+ e2 = std::move(e1);
+ EXPECT_THAT(e2.what(), HasSubstr(error.ToString()));
+}
+
// 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.
#ifdef ABSL_HAVE_EXCEPTIONS
-#define EXPECT_DEATH_OR_THROW(statement, status_) \
- EXPECT_THROW( \
- { \
- try { \
- statement; \
- } catch (const absl::BadStatusOrAccess& e) { \
- EXPECT_EQ(e.status(), status_); \
- throw; \
- } \
- }, \
+#define EXPECT_DEATH_OR_THROW(statement, status_) \
+ EXPECT_THROW( \
+ { \
+ try { \
+ statement; \
+ } catch (const absl::BadStatusOrAccess& e) { \
+ EXPECT_EQ(e.status(), status_); \
+ EXPECT_THAT(e.what(), HasSubstr(e.status().ToString())); \
+ throw; \
+ } \
+ }, \
absl::BadStatusOrAccess);
#else // ABSL_HAVE_EXCEPTIONS
#define EXPECT_DEATH_OR_THROW(statement, status) \
@@ -412,8 +452,6 @@ TEST(StatusOr, TestStatusCtor) {
EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled);
}
-
-
TEST(StatusOr, TestValueCtor) {
const int kI = 4;
const absl::StatusOr<int> thing(kI);
@@ -1300,8 +1338,6 @@ TEST(StatusOr, TestPointerDefaultCtor) {
EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown);
}
-
-
TEST(StatusOr, TestPointerStatusCtor) {
absl::StatusOr<int*> thing(absl::CancelledError());
EXPECT_FALSE(thing.ok());