Apply nullability annotations to shared pointer libraries. Add an assertion to `TypeErasedRef::Cast()` to comply with nullability rules. PiperOrigin-RevId: 915259881
diff --git a/riegeli/base/BUILD b/riegeli/base/BUILD index 5ffd289..08a7056 100644 --- a/riegeli/base/BUILD +++ b/riegeli/base/BUILD
@@ -221,6 +221,7 @@ name = "type_erased_ref", hdrs = ["type_erased_ref.h"], deps = [ + ":assert", ":type_traits", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:nullability",
diff --git a/riegeli/base/intrusive_shared_ptr.h b/riegeli/base/intrusive_shared_ptr.h index 6c21793..1bf47eb 100644 --- a/riegeli/base/intrusive_shared_ptr.h +++ b/riegeli/base/intrusive_shared_ptr.h
@@ -30,6 +30,8 @@ #include "riegeli/base/initializer.h" #include "riegeli/base/ownership.h" +ABSL_POINTERS_DEFAULT_NONNULL + namespace riegeli { namespace intrusive_shared_ptr_internal { @@ -106,10 +108,12 @@ // Creates an `IntrusiveSharedPtr` holding `ptr`. // // Takes ownership of `ptr` unless the second parameter is `kShareOwnership`. - explicit IntrusiveSharedPtr(T* ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, + explicit IntrusiveSharedPtr(T* absl_nullable ptr + ABSL_ATTRIBUTE_LIFETIME_BOUND, PassOwnership = kPassOwnership) noexcept : ptr_(ptr) {} - explicit IntrusiveSharedPtr(T* ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, + explicit IntrusiveSharedPtr(T* absl_nullable ptr + ABSL_ATTRIBUTE_LIFETIME_BOUND, ShareOwnership) noexcept : ptr_(Ref(ptr)) {} @@ -174,11 +178,11 @@ // // The old object, if any, is destroyed afterwards. ABSL_ATTRIBUTE_REINITIALIZES - void Reset(T* ptr = nullptr, PassOwnership = kPassOwnership) { + void Reset(T* absl_nullable ptr = nullptr, PassOwnership = kPassOwnership) { ptr_.reset(ptr); } ABSL_ATTRIBUTE_REINITIALIZES - void Reset(T* ptr, ShareOwnership) { ptr_.reset(Ref(ptr)); } + void Reset(T* absl_nullable ptr, ShareOwnership) { ptr_.reset(Ref(ptr)); } // Replaces the object with a constructed value. // @@ -243,23 +247,25 @@ } // Returns the pointer. - T* get() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return ptr_.get(); } + T* absl_nullable get() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return ptr_.get(); + } // Dereferences the pointer. T& operator*() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - RIEGELI_ASSERT_NE(ptr_, nullptr) + RIEGELI_ASSERT(ptr_ != nullptr) << "Failed precondition of IntrusiveSharedPtr::operator*: null pointer"; return *ptr_; } T* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - RIEGELI_ASSERT_NE(ptr_, nullptr) + RIEGELI_ASSERT(ptr_ != nullptr) << "Failed precondition of IntrusiveSharedPtr::operator->: null " "pointer"; return ptr_.get(); } // Returns the pointer. This `IntrusiveSharedPtr` is left empty. - T* Release() { return ptr_.release(); } + T* absl_nullable Release() { return ptr_.release(); } template <typename OtherT> friend bool operator==(const IntrusiveSharedPtr& a, @@ -273,7 +279,8 @@ // Indicates support for: // * `ExternalRef(const IntrusiveSharedPtr&, substr)` // * `ExternalRef(IntrusiveSharedPtr&&, substr)` - friend void RiegeliSupportsExternalRef(const IntrusiveSharedPtr*) {} + friend void RiegeliSupportsExternalRef( + const IntrusiveSharedPtr* absl_nullable) {} // Supports `ExternalRef`. friend ExternalStorage RiegeliToExternalStorage(IntrusiveSharedPtr* self) { @@ -310,7 +317,7 @@ }; template <typename SubT> - static SubT* Ref(SubT* ptr) { + static SubT* absl_nullable Ref(SubT* absl_nullable ptr) { if (ptr != nullptr) ptr->Ref(); return ptr; } @@ -327,6 +334,7 @@ void ResetImpl(Initializer<T> value) { if constexpr (IsAssignable<T>::value) { if (IsUnique()) { + RIEGELI_ASSERT(ptr_ != nullptr) << "Guaranteed by IsUnique()"; *ptr_ = std::move(value); return; } @@ -334,14 +342,16 @@ ptr_ = std::move(value); } - std::unique_ptr<T, Unrefer> ptr_; + absl_nullable std::unique_ptr<T, Unrefer> ptr_; }; template <typename T> -explicit IntrusiveSharedPtr(T* ptr, PassOwnership = kPassOwnership) +explicit IntrusiveSharedPtr(T* absl_nullable ptr, + PassOwnership = kPassOwnership) -> IntrusiveSharedPtr<T>; template <typename T> -explicit IntrusiveSharedPtr(T* ptr, ShareOwnership) -> IntrusiveSharedPtr<T>; +explicit IntrusiveSharedPtr(T* absl_nullable ptr, ShareOwnership) + -> IntrusiveSharedPtr<T>; template <typename T, std::enable_if_t<!std::is_pointer_v<T>, int> = 0> explicit IntrusiveSharedPtr(T&& value) -> IntrusiveSharedPtr<TargetT<T>>;
diff --git a/riegeli/base/ownership.h b/riegeli/base/ownership.h index 3d1b137..03609d8 100644 --- a/riegeli/base/ownership.h +++ b/riegeli/base/ownership.h
@@ -17,6 +17,10 @@ #include <type_traits> +#include "absl/base/nullability.h" + +ABSL_POINTERS_DEFAULT_NONNULL + namespace riegeli { // `PassOwnership` and `ShareOwnership` type tags specify how ownership of a
diff --git a/riegeli/base/ref_count.h b/riegeli/base/ref_count.h index ed46d53..1551321 100644 --- a/riegeli/base/ref_count.h +++ b/riegeli/base/ref_count.h
@@ -20,8 +20,11 @@ #include <atomic> #include <type_traits> +#include "absl/base/nullability.h" #include "riegeli/base/ownership.h" +ABSL_POINTERS_DEFAULT_NONNULL + namespace riegeli { // `RefCount` provides operations on an atomic reference count.
diff --git a/riegeli/base/shared_ptr.h b/riegeli/base/shared_ptr.h index 0fbc791..0d4dabf 100644 --- a/riegeli/base/shared_ptr.h +++ b/riegeli/base/shared_ptr.h
@@ -33,6 +33,8 @@ #include "riegeli/base/new_aligned.h" #include "riegeli/base/ref_count.h" +ABSL_POINTERS_DEFAULT_NONNULL + namespace riegeli { // `SharedPtr<T>` implements shared ownership of an object of type `T`. @@ -177,16 +179,18 @@ } // Returns the pointer. - T* get() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return ptr_.get(); } + T* absl_nullable get() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return ptr_.get(); + } // Dereferences the pointer. T& operator*() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - RIEGELI_ASSERT_NE(ptr_, nullptr) + RIEGELI_ASSERT(ptr_ != nullptr) << "Failed precondition of SharedPtr::operator*: null pointer"; return *ptr_; } T* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - RIEGELI_ASSERT_NE(ptr_, nullptr) + RIEGELI_ASSERT(ptr_ != nullptr) << "Failed precondition of SharedPtr::operator->: null pointer"; return ptr_.get(); } @@ -196,12 +200,12 @@ // // If the returned pointer is `nullptr`, it allowed but not required to call // `DeleteReleased()`. - T* Release() { return ptr_.release(); } + T* absl_nullable Release() { return ptr_.release(); } // Deletes the pointer obtained by `Release()`. // // Does nothing if `ptr == nullptr`. - static void DeleteReleased(T* ptr) { + static void DeleteReleased(T* absl_nullable ptr) { if (ptr != nullptr) Unrefer()(ptr); } @@ -216,7 +220,7 @@ // Indicates support for: // * `ExternalRef(const SharedPtr&, substr)` // * `ExternalRef(SharedPtr&&, substr)` - friend void RiegeliSupportsExternalRef(const SharedPtr*) {} + friend void RiegeliSupportsExternalRef(const SharedPtr* absl_nullable) {} // Supports `ExternalRef`. friend ExternalStorage RiegeliToExternalStorage(SharedPtr* self) { @@ -278,8 +282,8 @@ } template <typename SubT> - static T* UpCast(SubT* ptr) { - T* const super_ptr = ptr; + static T* absl_nullable UpCast(SubT* absl_nullable ptr) { + T* const absl_nullable super_ptr = ptr; RIEGELI_CHECK( static_cast<void*>(const_cast<std::remove_cv_t<T>*>(super_ptr)) == static_cast<void*>(const_cast<std::remove_cv_t<SubT>*>(ptr))) @@ -356,7 +360,7 @@ } template <typename SubT> - static SubT* Ref(SubT* ptr) { + static SubT* absl_nullable Ref(SubT* absl_nullable ptr) { if (ptr != nullptr) ref_count(ptr).Ref(); return ptr; } @@ -372,6 +376,7 @@ void ResetImpl(Initializer<T> value) { if constexpr (IsAssignable<T>::value) { if (IsUnique()) { + RIEGELI_ASSERT(ptr_ != nullptr) << "Guaranteed by IsUnique()"; *ptr_ = std::move(value); return; } @@ -410,7 +415,7 @@ } } - std::unique_ptr<T, Unrefer> ptr_; + absl_nullable std::unique_ptr<T, Unrefer> ptr_; }; template <typename T>
diff --git a/riegeli/base/type_erased_ref.h b/riegeli/base/type_erased_ref.h index 7882f34..c788b7d 100644 --- a/riegeli/base/type_erased_ref.h +++ b/riegeli/base/type_erased_ref.h
@@ -22,6 +22,7 @@ #include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/meta/type_traits.h" +#include "riegeli/base/assert.h" #include "riegeli/base/type_traits.h" ABSL_POINTERS_DEFAULT_NONNULL @@ -79,11 +80,14 @@ // Recovers the `T&&`. template <typename T> T&& Cast() const { + const auto cast_ptr = + reinterpret_cast<std::remove_reference_t<T>* absl_nullable>(ptr_); + RIEGELI_ASSERT(cast_ptr != nullptr) + << "Failed precondition of TypeErasedRef::Cast(): empty TypeErasedRef"; if constexpr (!IsFunctionRef<T>::value) { - return std::forward<T>( - *reinterpret_cast<std::remove_reference_t<T>*>(ptr_)); + return std::forward<T>(*cast_ptr); } else { - return *reinterpret_cast<std::remove_reference_t<T>*>(ptr_); + return *cast_ptr; } }