Commit d1dd9cd6 by Abseil Team Committed by Copybara-Service

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
parent c02bb5f6
...@@ -123,13 +123,15 @@ using IsForwardingAssignmentValid = absl::disjunction< ...@@ -123,13 +123,15 @@ using IsForwardingAssignmentValid = absl::disjunction<
std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>, std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
IsForwardingAssignmentAmbiguous<T, U>>>>; IsForwardingAssignmentAmbiguous<T, U>>>>;
template <bool Explicit, typename T> template <bool Value, typename T>
using NegationIf = std::conditional_t<Explicit, absl::negation<T>, 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< using IsConstructionValid = absl::conjunction<
Equality<Lifetimebound,
type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
IsDirectInitializationValid<T, U&&>, std::is_constructible<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< absl::disjunction<
std::is_same<T, absl::remove_cvref_t<U>>, std::is_same<T, absl::remove_cvref_t<U>>,
absl::conjunction< absl::conjunction<
...@@ -140,8 +142,10 @@ using IsConstructionValid = absl::conjunction< ...@@ -140,8 +142,10 @@ using IsConstructionValid = absl::conjunction<
absl::negation< absl::negation<
internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>; internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>;
template <typename T, typename U> template <typename T, typename U, bool Lifetimebound>
using IsAssignmentValid = absl::conjunction< using IsAssignmentValid = absl::conjunction<
Equality<Lifetimebound,
type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>, std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
absl::disjunction< absl::disjunction<
std::is_same<T, absl::remove_cvref_t<U>>, std::is_same<T, absl::remove_cvref_t<U>>,
...@@ -150,27 +154,30 @@ using IsAssignmentValid = absl::conjunction< ...@@ -150,27 +154,30 @@ using IsAssignmentValid = absl::conjunction<
absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>, absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>,
IsForwardingAssignmentValid<T, U&&>>; IsForwardingAssignmentValid<T, U&&>>;
template <typename T, typename U, bool Explicit> template <bool Explicit, typename T, typename U>
using IsConstructionFromStatusValid = absl::conjunction< using IsConstructionFromStatusValid = absl::conjunction<
absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>, 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<T, absl::remove_cvref_t<U>>>,
absl::negation<std::is_same<absl::in_place_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>, std::is_constructible<absl::Status, U>,
absl::negation<HasConversionOperatorToStatusOr<T, U>>>; absl::negation<HasConversionOperatorToStatusOr<T, U>>>;
template <typename T, typename U> template <bool Explicit, typename T, typename U, bool Lifetimebound,
using IsStatusAssignmentValid = IsConstructionFromStatusValid<T, U, false>; typename UQ>
template <typename T, typename U, typename UQ, bool Explicit>
using IsConstructionFromStatusOrValid = absl::conjunction< using IsConstructionFromStatusOrValid = absl::conjunction<
absl::negation<std::is_same<T, U>>, std::is_constructible<T, UQ>, absl::negation<std::is_same<T, U>>,
NegationIf<Explicit, std::is_convertible<UQ, T>>, 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>>>; absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>;
template <typename T, typename U> template <typename T, typename U, bool Lifetimebound>
using IsStatusOrAssignmentValid = absl::conjunction< using IsStatusOrAssignmentValid = absl::conjunction<
absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>, 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>, std::is_constructible<T, U>, std::is_assignable<T, U>,
absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr< absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
T, absl::remove_cvref_t<U>>>>; T, absl::remove_cvref_t<U>>>>;
......
...@@ -238,29 +238,53 @@ class StatusOr : private internal_statusor::StatusOrData<T>, ...@@ -238,29 +238,53 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// underlying constructor.) // underlying constructor.)
template <typename U, absl::enable_if_t< template <typename U, absl::enable_if_t<
internal_statusor::IsConstructionFromStatusOrValid< internal_statusor::IsConstructionFromStatusOrValid<
T, U, const U&, false>::value, false, T, U, false, const U&>::value,
int> = 0> int> = 0>
StatusOr(const StatusOr<U>& other) // NOLINT StatusOr(const StatusOr<U>& other) // NOLINT
: Base(static_cast<const typename StatusOr<U>::Base&>(other)) {} : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
template <typename U, absl::enable_if_t< template <typename U, absl::enable_if_t<
internal_statusor::IsConstructionFromStatusOrValid< 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> int> = 0>
explicit StatusOr(const StatusOr<U>& other) explicit StatusOr(const StatusOr<U>& other)
: Base(static_cast<const typename StatusOr<U>::Base&>(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< template <typename U, absl::enable_if_t<
internal_statusor::IsConstructionFromStatusOrValid< internal_statusor::IsConstructionFromStatusOrValid<
T, U, U&&, false>::value, false, T, U, false, U&&>::value,
int> = 0> int> = 0>
StatusOr(StatusOr<U>&& other) // NOLINT StatusOr(StatusOr<U>&& other) // NOLINT
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {} : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
template <typename U, absl::enable_if_t< template <typename U, absl::enable_if_t<
internal_statusor::IsConstructionFromStatusOrValid< 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> int> = 0>
explicit StatusOr(StatusOr<U>&& other) explicit StatusOr(StatusOr<U>&& other)
: Base(static_cast<typename StatusOr<U>::Base&&>(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 // Converting Assignment Operators
...@@ -283,20 +307,36 @@ class StatusOr : private internal_statusor::StatusOrData<T>, ...@@ -283,20 +307,36 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// assigned from `StatusOr<U>`. // assigned from `StatusOr<U>`.
template <typename U, template <typename U,
absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid< absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
T, const U&>::value, T, const U&, false>::value,
int> = 0> int> = 0>
StatusOr& operator=(const StatusOr<U>& other) { StatusOr& operator=(const StatusOr<U>& other) {
this->Assign(other); this->Assign(other);
return *this; return *this;
} }
template < template <typename U,
typename U, absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
absl::enable_if_t< T, const U&, true>::value,
internal_statusor::IsStatusOrAssignmentValid<T, U&&>::value, int> = 0> 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) { StatusOr& operator=(StatusOr<U>&& other) {
this->Assign(std::move(other)); this->Assign(std::move(other));
return *this; 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 // 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 // this constructor, `this->ok()` will be `false` and calls to `value()` will
...@@ -311,19 +351,18 @@ class StatusOr : private internal_statusor::StatusOrData<T>, ...@@ -311,19 +351,18 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// of passing absl::StatusCode::kInternal as a fallback. // of passing absl::StatusCode::kInternal as a fallback.
template <typename U = absl::Status, template <typename U = absl::Status,
absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid< absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
T, U, false>::value, false, T, U>::value,
int> = 0> int> = 0>
StatusOr(U&& v) : Base(std::forward<U>(v)) {} StatusOr(U&& v) : Base(std::forward<U>(v)) {}
template <typename U = absl::Status, template <typename U = absl::Status,
absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid< absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
T, U, true>::value, true, T, U>::value,
int> = 0> int> = 0>
explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {} explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {}
template <typename U = absl::Status,
template < absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
typename U = absl::Status, false, T, U>::value,
absl::enable_if_t<internal_statusor::IsStatusAssignmentValid<T, U>::value,
int> = 0> int> = 0>
StatusOr& operator=(U&& v) { StatusOr& operator=(U&& v) {
this->AssignStatus(std::forward<U>(v)); this->AssignStatus(std::forward<U>(v));
...@@ -347,12 +386,21 @@ class StatusOr : private internal_statusor::StatusOrData<T>, ...@@ -347,12 +386,21 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// StatusOr<bool> s2 = false; // s2.ok() && *s2 == false // StatusOr<bool> s2 = false; // s2.ok() && *s2 == false
// s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`? // s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`?
template <typename U = T, template <typename U = T,
typename = typename std::enable_if< typename std::enable_if<
internal_statusor::IsAssignmentValid<T, U>::value>::type> internal_statusor::IsAssignmentValid<T, U, false>::value,
int>::type = 0>
StatusOr& operator=(U&& v) { StatusOr& operator=(U&& v) {
this->Assign(std::forward<U>(v)); this->Assign(std::forward<U>(v));
return *this; 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 // Constructs the inner value `T` in-place using the provided args, using the
// `T(args...)` constructor. // `T(args...)` constructor.
...@@ -370,20 +418,30 @@ class StatusOr : private internal_statusor::StatusOrData<T>, ...@@ -370,20 +418,30 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// ambiguity, this constructor is disabled if `U` is a `StatusOr<J>`, where // ambiguity, this constructor is disabled if `U` is a `StatusOr<J>`, where
// `J` is convertible to `T`. // `J` is convertible to `T`.
template <typename U = T, template <typename U = T,
absl::enable_if_t< absl::enable_if_t<internal_statusor::IsConstructionValid<
absl::conjunction<internal_statusor::IsConstructionValid< false, T, U, false>::value,
T, U, false> >::value,
int> = 0> int> = 0>
StatusOr(U&& u) // NOLINT StatusOr(U&& u) // NOLINT
: StatusOr(absl::in_place, std::forward<U>(u)) {} : 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, template <typename U = T,
absl::enable_if_t< absl::enable_if_t<internal_statusor::IsConstructionValid<
absl::conjunction< true, T, U, false>::value,
internal_statusor::IsConstructionValid<T, U, true> >::value,
int> = 0> int> = 0>
explicit StatusOr(U&& u) // NOLINT explicit StatusOr(U&& u) // NOLINT
: StatusOr(absl::in_place, std::forward<U>(u)) {} : StatusOr(absl::in_place, std::forward<U>(u)) {}
template <typename U = T,
absl::enable_if_t<
internal_statusor::IsConstructionValid<true, T, U, true>::value,
int> = 0>
explicit StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
: StatusOr(absl::in_place, std::forward<U>(u)) {}
// StatusOr<T>::ok() // StatusOr<T>::ok()
// //
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment