diff options
author | Abseil Team <absl-team@google.com> | 2024-04-02 07:41:09 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-04-02 07:42:26 -0700 |
commit | d1dd9cd60a7167bc6e2f34877660e747e5b92842 (patch) | |
tree | 0d043a7326084b80538f9e6e722f74682ec3f7b9 /absl/status | |
parent | c02bb5f6dae73df83abc0d960ccf5cf3ab00f24c (diff) |
Add internal traits to absl::StatusOr for lifetimebound detection
This helps compilers that understand `ABSL_ATTRIBUTE_LIFETIME_BOUND` flag constructs such as
`absl::StatusOr<std::string_view> str = std::string(...)`
as error-prone.
PiperOrigin-RevId: 621169918
Change-Id: Id621f63b9da4dc72eb4bd42c62d88bcc15a05243
Diffstat (limited to 'absl/status')
-rw-r--r-- | absl/status/internal/statusor_internal.h | 35 | ||||
-rw-r--r-- | absl/status/statusor.h | 108 |
2 files changed, 104 insertions, 39 deletions
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<absl::in_place_t, absl::remove_cvref_t<U>>, IsForwardingAssignmentAmbiguous<T, U>>>>; -template <bool Explicit, typename T> -using NegationIf = std::conditional_t<Explicit, absl::negation<T>, T>; +template <bool Value, typename T> +using Equality = std::conditional_t<Value, T, absl::negation<T>>; -template <typename T, typename U, bool Explicit> +template <bool Explicit, typename T, typename U, bool Lifetimebound> using IsConstructionValid = absl::conjunction< + Equality<Lifetimebound, + type_traits_internal::IsLifetimeBoundAssignment<T, U>>, IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>, - NegationIf<Explicit, std::is_convertible<U&&, T>>, + Equality<!Explicit, std::is_convertible<U&&, T>>, absl::disjunction< std::is_same<T, absl::remove_cvref_t<U>>, absl::conjunction< @@ -140,8 +142,10 @@ using IsConstructionValid = absl::conjunction< absl::negation< internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>; -template <typename T, typename U> +template <typename T, typename U, bool Lifetimebound> using IsAssignmentValid = absl::conjunction< + Equality<Lifetimebound, + type_traits_internal::IsLifetimeBoundAssignment<T, U>>, std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>, absl::disjunction< std::is_same<T, absl::remove_cvref_t<U>>, @@ -150,27 +154,30 @@ using IsAssignmentValid = absl::conjunction< absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>, IsForwardingAssignmentValid<T, U&&>>; -template <typename T, typename U, bool Explicit> +template <bool Explicit, typename T, typename U> using IsConstructionFromStatusValid = absl::conjunction< absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>, absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>, absl::negation<std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>>, - NegationIf<Explicit, std::is_convertible<U, absl::Status>>, + Equality<!Explicit, std::is_convertible<U, absl::Status>>, std::is_constructible<absl::Status, U>, absl::negation<HasConversionOperatorToStatusOr<T, U>>>; -template <typename T, typename U> -using IsStatusAssignmentValid = IsConstructionFromStatusValid<T, U, false>; - -template <typename T, typename U, typename UQ, bool Explicit> +template <bool Explicit, typename T, typename U, bool Lifetimebound, + typename UQ> using IsConstructionFromStatusOrValid = absl::conjunction< - absl::negation<std::is_same<T, U>>, std::is_constructible<T, UQ>, - NegationIf<Explicit, std::is_convertible<UQ, T>>, + absl::negation<std::is_same<T, U>>, + Equality<Lifetimebound, + type_traits_internal::IsLifetimeBoundAssignment<T, U>>, + std::is_constructible<T, UQ>, + Equality<!Explicit, std::is_convertible<UQ, T>>, absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>; -template <typename T, typename U> +template <typename T, typename U, bool Lifetimebound> using IsStatusOrAssignmentValid = absl::conjunction< absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>, + Equality<Lifetimebound, + type_traits_internal::IsLifetimeBoundAssignment<T, U>>, std::is_constructible<T, U>, std::is_assignable<T, U>, absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr< T, absl::remove_cvref_t<U>>>>; 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<T>, // underlying constructor.) template <typename U, absl::enable_if_t< internal_statusor::IsConstructionFromStatusOrValid< - T, U, const U&, false>::value, + false, T, U, false, const U&>::value, int> = 0> StatusOr(const StatusOr<U>& other) // NOLINT : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {} template <typename U, absl::enable_if_t< internal_statusor::IsConstructionFromStatusOrValid< - T, U, const U&, true>::value, + false, T, U, true, const U&>::value, + int> = 0> + StatusOr(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT + : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {} + template <typename U, absl::enable_if_t< + internal_statusor::IsConstructionFromStatusOrValid< + true, T, U, false, const U&>::value, int> = 0> explicit StatusOr(const StatusOr<U>& other) : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {} + template <typename U, absl::enable_if_t< + internal_statusor::IsConstructionFromStatusOrValid< + true, T, U, true, const U&>::value, + int> = 0> + explicit StatusOr(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) + : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {} template <typename U, absl::enable_if_t< internal_statusor::IsConstructionFromStatusOrValid< - T, U, U&&, false>::value, + false, T, U, false, U&&>::value, int> = 0> StatusOr(StatusOr<U>&& other) // NOLINT : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} template <typename U, absl::enable_if_t< internal_statusor::IsConstructionFromStatusOrValid< - T, U, U&&, true>::value, + false, T, U, true, U&&>::value, + int> = 0> + StatusOr(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT + : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} + template <typename U, absl::enable_if_t< + internal_statusor::IsConstructionFromStatusOrValid< + true, T, U, false, U&&>::value, int> = 0> explicit StatusOr(StatusOr<U>&& other) : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} + template <typename U, absl::enable_if_t< + internal_statusor::IsConstructionFromStatusOrValid< + true, T, U, true, U&&>::value, + int> = 0> + explicit StatusOr(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) + : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} // Converting Assignment Operators @@ -283,20 +307,36 @@ class StatusOr : private internal_statusor::StatusOrData<T>, // assigned from `StatusOr<U>`. template <typename U, absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid< - T, const U&>::value, + T, const U&, false>::value, int> = 0> StatusOr& operator=(const StatusOr<U>& other) { this->Assign(other); return *this; } - template < - typename U, - absl::enable_if_t< - internal_statusor::IsStatusOrAssignmentValid<T, U&&>::value, int> = 0> + template <typename U, + absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid< + T, const U&, true>::value, + int> = 0> + StatusOr& operator=(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) { + this->Assign(other); + return *this; + } + template <typename U, + absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid< + T, U&&, false>::value, + int> = 0> StatusOr& operator=(StatusOr<U>&& other) { this->Assign(std::move(other)); return *this; } + template <typename U, + absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid< + T, U&&, true>::value, + int> = 0> + StatusOr& operator=(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) { + this->Assign(std::move(other)); + return *this; + } // Constructs a new `absl::StatusOr<T>` 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<T>, // of passing absl::StatusCode::kInternal as a fallback. template <typename U = absl::Status, absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid< - T, U, false>::value, + false, T, U>::value, int> = 0> StatusOr(U&& v) : Base(std::forward<U>(v)) {} template <typename U = absl::Status, absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid< - T, U, true>::value, + true, T, U>::value, int> = 0> explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {} - - template < - typename U = absl::Status, - absl::enable_if_t<internal_statusor::IsStatusAssignmentValid<T, U>::value, - int> = 0> + template <typename U = absl::Status, + absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid< + false, T, U>::value, + int> = 0> StatusOr& operator=(U&& v) { this->AssignStatus(std::forward<U>(v)); return *this; @@ -347,12 +386,21 @@ class StatusOr : private internal_statusor::StatusOrData<T>, // StatusOr<bool> s2 = false; // s2.ok() && *s2 == false // s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`? template <typename U = T, - typename = typename std::enable_if< - internal_statusor::IsAssignmentValid<T, U>::value>::type> + typename std::enable_if< + internal_statusor::IsAssignmentValid<T, U, false>::value, + int>::type = 0> StatusOr& operator=(U&& v) { this->Assign(std::forward<U>(v)); return *this; } + template <typename U = T, + typename std::enable_if< + internal_statusor::IsAssignmentValid<T, U, true>::value, + int>::type = 0> + StatusOr& operator=(U&& v ABSL_ATTRIBUTE_LIFETIME_BOUND) { + this->Assign(std::forward<U>(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<T>, // ambiguity, this constructor is disabled if `U` is a `StatusOr<J>`, where // `J` is convertible to `T`. template <typename U = T, - absl::enable_if_t< - absl::conjunction<internal_statusor::IsConstructionValid< - T, U, false> >::value, - int> = 0> + absl::enable_if_t<internal_statusor::IsConstructionValid< + false, T, U, false>::value, + int> = 0> StatusOr(U&& u) // NOLINT : StatusOr(absl::in_place, std::forward<U>(u)) {} + template <typename U = T, + absl::enable_if_t<internal_statusor::IsConstructionValid< + false, T, U, true>::value, + int> = 0> + StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT + : StatusOr(absl::in_place, std::forward<U>(u)) {} template <typename U = T, + absl::enable_if_t<internal_statusor::IsConstructionValid< + true, T, U, false>::value, + int> = 0> + explicit StatusOr(U&& u) // NOLINT + : StatusOr(absl::in_place, std::forward<U>(u)) {} + template <typename U = T, absl::enable_if_t< - absl::conjunction< - internal_statusor::IsConstructionValid<T, U, true> >::value, + internal_statusor::IsConstructionValid<true, T, U, true>::value, int> = 0> - explicit StatusOr(U&& u) // NOLINT + explicit StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT : StatusOr(absl::in_place, std::forward<U>(u)) {} // StatusOr<T>::ok() |