From d1dd9cd60a7167bc6e2f34877660e747e5b92842 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 2 Apr 2024 07:41:09 -0700 Subject: Add internal traits to absl::StatusOr for lifetimebound detection This helps compilers that understand `ABSL_ATTRIBUTE_LIFETIME_BOUND` flag constructs such as `absl::StatusOr str = std::string(...)` as error-prone. PiperOrigin-RevId: 621169918 Change-Id: Id621f63b9da4dc72eb4bd42c62d88bcc15a05243 --- absl/status/internal/statusor_internal.h | 35 ++++++---- absl/status/statusor.h | 108 ++++++++++++++++++++++++------- 2 files changed, 104 insertions(+), 39 deletions(-) (limited to 'absl/status') diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h index 1afd3179..414aa300 100644 --- a/absl/status/internal/statusor_internal.h +++ b/absl/status/internal/statusor_internal.h @@ -123,13 +123,15 @@ using IsForwardingAssignmentValid = absl::disjunction< std::is_same>, IsForwardingAssignmentAmbiguous>>>; -template -using NegationIf = std::conditional_t, T>; +template +using Equality = std::conditional_t>; -template +template using IsConstructionValid = absl::conjunction< + Equality>, IsDirectInitializationValid, std::is_constructible, - NegationIf>, + Equality>, absl::disjunction< std::is_same>, absl::conjunction< @@ -140,8 +142,10 @@ using IsConstructionValid = absl::conjunction< absl::negation< internal_statusor::HasConversionOperatorToStatusOr>>>>; -template +template using IsAssignmentValid = absl::conjunction< + Equality>, std::is_constructible, std::is_assignable, absl::disjunction< std::is_same>, @@ -150,27 +154,30 @@ using IsAssignmentValid = absl::conjunction< absl::negation>>>, IsForwardingAssignmentValid>; -template +template using IsConstructionFromStatusValid = absl::conjunction< absl::negation, absl::remove_cvref_t>>, absl::negation>>, absl::negation>>, - NegationIf>, + Equality>, std::is_constructible, absl::negation>>; -template -using IsStatusAssignmentValid = IsConstructionFromStatusValid; - -template +template using IsConstructionFromStatusOrValid = absl::conjunction< - absl::negation>, std::is_constructible, - NegationIf>, + absl::negation>, + Equality>, + std::is_constructible, + Equality>, absl::negation>>; -template +template using IsStatusOrAssignmentValid = absl::conjunction< absl::negation>>, + Equality>, std::is_constructible, std::is_assignable, absl::negation>>>; diff --git a/absl/status/statusor.h b/absl/status/statusor.h index 0ed986dc..b1da45e6 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h @@ -238,29 +238,53 @@ class StatusOr : private internal_statusor::StatusOrData, // underlying constructor.) template ::value, + false, T, U, false, const U&>::value, int> = 0> StatusOr(const StatusOr& other) // NOLINT : Base(static_cast::Base&>(other)) {} template ::value, + false, T, U, true, const U&>::value, + int> = 0> + StatusOr(const StatusOr& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT + : Base(static_cast::Base&>(other)) {} + template ::value, int> = 0> explicit StatusOr(const StatusOr& other) : Base(static_cast::Base&>(other)) {} + template ::value, + int> = 0> + explicit StatusOr(const StatusOr& other ABSL_ATTRIBUTE_LIFETIME_BOUND) + : Base(static_cast::Base&>(other)) {} template ::value, + false, T, U, false, U&&>::value, int> = 0> StatusOr(StatusOr&& other) // NOLINT : Base(static_cast::Base&&>(other)) {} template ::value, + false, T, U, true, U&&>::value, + int> = 0> + StatusOr(StatusOr&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT + : Base(static_cast::Base&&>(other)) {} + template ::value, int> = 0> explicit StatusOr(StatusOr&& other) : Base(static_cast::Base&&>(other)) {} + template ::value, + int> = 0> + explicit StatusOr(StatusOr&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) + : Base(static_cast::Base&&>(other)) {} // Converting Assignment Operators @@ -283,20 +307,36 @@ class StatusOr : private internal_statusor::StatusOrData, // assigned from `StatusOr`. template ::value, + T, const U&, false>::value, int> = 0> StatusOr& operator=(const StatusOr& other) { this->Assign(other); return *this; } - template < - typename U, - absl::enable_if_t< - internal_statusor::IsStatusOrAssignmentValid::value, int> = 0> + template ::value, + int> = 0> + StatusOr& operator=(const StatusOr& other ABSL_ATTRIBUTE_LIFETIME_BOUND) { + this->Assign(other); + return *this; + } + template ::value, + int> = 0> StatusOr& operator=(StatusOr&& other) { this->Assign(std::move(other)); return *this; } + template ::value, + int> = 0> + StatusOr& operator=(StatusOr&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) { + this->Assign(std::move(other)); + return *this; + } // Constructs a new `absl::StatusOr` with a non-ok status. After calling // this constructor, `this->ok()` will be `false` and calls to `value()` will @@ -311,20 +351,19 @@ class StatusOr : private internal_statusor::StatusOrData, // of passing absl::StatusCode::kInternal as a fallback. template ::value, + false, T, U>::value, int> = 0> StatusOr(U&& v) : Base(std::forward(v)) {} template ::value, + true, T, U>::value, int> = 0> explicit StatusOr(U&& v) : Base(std::forward(v)) {} - - template < - typename U = absl::Status, - absl::enable_if_t::value, - int> = 0> + template ::value, + int> = 0> StatusOr& operator=(U&& v) { this->AssignStatus(std::forward(v)); return *this; @@ -347,12 +386,21 @@ class StatusOr : private internal_statusor::StatusOrData, // StatusOr s2 = false; // s2.ok() && *s2 == false // s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`? template ::value>::type> + typename std::enable_if< + internal_statusor::IsAssignmentValid::value, + int>::type = 0> StatusOr& operator=(U&& v) { this->Assign(std::forward(v)); return *this; } + template ::value, + int>::type = 0> + StatusOr& operator=(U&& v ABSL_ATTRIBUTE_LIFETIME_BOUND) { + this->Assign(std::forward(v)); + return *this; + } // Constructs the inner value `T` in-place using the provided args, using the // `T(args...)` constructor. @@ -370,19 +418,29 @@ class StatusOr : private internal_statusor::StatusOrData, // ambiguity, this constructor is disabled if `U` is a `StatusOr`, where // `J` is convertible to `T`. template >::value, - int> = 0> + absl::enable_if_t::value, + int> = 0> StatusOr(U&& u) // NOLINT : StatusOr(absl::in_place, std::forward(u)) {} + template ::value, + int> = 0> + StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT + : StatusOr(absl::in_place, std::forward(u)) {} + template ::value, + int> = 0> + explicit StatusOr(U&& u) // NOLINT + : StatusOr(absl::in_place, std::forward(u)) {} template >::value, + internal_statusor::IsConstructionValid::value, int> = 0> - explicit StatusOr(U&& u) // NOLINT + explicit StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT : StatusOr(absl::in_place, std::forward(u)) {} // StatusOr::ok() -- cgit v1.2.3