From e735ee64f5249ff65d2d3b1f58069864a9ad0df5 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Fri, 2 Feb 2024 10:37:43 +0100 Subject: Upgrade lock_api to 0.4.11 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update external/rust/crates/lock_api For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md Test: TreeHugger Change-Id: I9fc3ffa4c6ee37b8f8fd373fb9930a663ece8e30 --- .cargo_vcs_info.json | 2 +- Android.bp | 6 +- Cargo.toml | 13 +- Cargo.toml.orig | 9 +- METADATA | 25 ++-- src/lib.rs | 3 + src/mutex.rs | 41 ++++-- src/remutex.rs | 39 ++++-- src/rwlock.rs | 387 ++++++++++++++++++++++++++++++++++++++++++++------- 9 files changed, 427 insertions(+), 98 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 6b5d531..73ab3ff 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "9e956adc2c6ecde7c15ff7611396d24be711c8a9" + "sha1": "8d92826bdcc8f7a507a2803ecbe5d98747f1df34" }, "path_in_vcs": "lock_api" } \ No newline at end of file diff --git a/Android.bp b/Android.bp index 0cf269e..ef48f40 100644 --- a/Android.bp +++ b/Android.bp @@ -42,9 +42,13 @@ rust_library { host_supported: true, crate_name: "lock_api", cargo_env_compat: true, - cargo_pkg_version: "0.4.9", + cargo_pkg_version: "0.4.11", srcs: ["src/lib.rs"], edition: "2018", + features: [ + "atomic_usize", + "default", + ], cfgs: ["has_const_fn_trait_bound"], rustlibs: ["libscopeguard"], apex_available: [ diff --git a/Cargo.toml b/Cargo.toml index b1ff8c4..501db6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,9 @@ [package] edition = "2018" +rust-version = "1.49.0" name = "lock_api" -version = "0.4.9" +version = "0.4.11" authors = ["Amanieu d'Antras "] description = "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std." keywords = [ @@ -28,6 +29,14 @@ categories = [ license = "MIT OR Apache-2.0" repository = "https://github.com/Amanieu/parking_lot" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", + "--generate-link-to-definition", +] + [dependencies.owning_ref] version = "0.4.1" optional = true @@ -46,4 +55,6 @@ version = "1.1.0" [features] arc_lock = [] +atomic_usize = [] +default = ["atomic_usize"] nightly = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index c21bd8a..683e69f 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "lock_api" -version = "0.4.9" +version = "0.4.11" authors = ["Amanieu d'Antras "] description = "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std." license = "MIT OR Apache-2.0" @@ -8,6 +8,11 @@ repository = "https://github.com/Amanieu/parking_lot" keywords = ["mutex", "rwlock", "lock", "no_std"] categories = ["concurrency", "no-std"] edition = "2018" +rust-version = "1.49.0" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] [dependencies] scopeguard = { version = "1.1.0", default-features = false } @@ -22,5 +27,7 @@ serde = { version = "1.0.126", default-features = false, optional = true } autocfg = "1.1.0" [features] +default = ["atomic_usize"] nightly = [] arc_lock = [] +atomic_usize = [] diff --git a/METADATA b/METADATA index e0c7e81..832bc1e 100644 --- a/METADATA +++ b/METADATA @@ -1,23 +1,20 @@ # This project was upgraded with external_updater. -# Usage: tools/external_updater/updater.sh update rust/crates/lock_api -# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md +# Usage: tools/external_updater/updater.sh update external/rust/crates/lock_api +# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md name: "lock_api" description: "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std." third_party { - url { - type: HOMEPAGE - value: "https://crates.io/crates/lock_api" - } - url { - type: ARCHIVE - value: "https://static.crates.io/crates/lock_api/lock_api-0.4.9.crate" - } - version: "0.4.9" license_type: NOTICE last_upgrade_date { - year: 2022 - month: 12 - day: 12 + year: 2024 + month: 2 + day: 2 + } + homepage: "https://crates.io/crates/lock_api" + identifier { + type: "Archive" + value: "https://static.crates.io/crates/lock_api/lock_api-0.4.11.crate" + version: "0.4.11" } } diff --git a/src/lib.rs b/src/lib.rs index cfa53bc..3ea417a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,6 +86,7 @@ //! requires the `alloc` crate to be present. #![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs)] #![warn(rust_2018_idioms)] @@ -106,7 +107,9 @@ unsafe impl Sync for GuardNoSend {} mod mutex; pub use crate::mutex::*; +#[cfg(feature = "atomic_usize")] mod remutex; +#[cfg(feature = "atomic_usize")] pub use crate::remutex::*; mod rwlock; diff --git a/src/mutex.rs b/src/mutex.rs index c97e543..80eadfa 100644 --- a/src/mutex.rs +++ b/src/mutex.rs @@ -189,11 +189,16 @@ impl Mutex { } impl Mutex { + /// Creates a new `MutexGuard` without checking if the mutex is locked. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. #[inline] - unsafe fn guard(&self) -> MutexGuard<'_, R, T> { + pub unsafe fn make_guard_unchecked(&self) -> MutexGuard<'_, R, T> { MutexGuard { mutex: self, marker: PhantomData, @@ -213,7 +218,7 @@ impl Mutex { pub fn lock(&self) -> MutexGuard<'_, R, T> { self.raw.lock(); // SAFETY: The lock is held, as required. - unsafe { self.guard() } + unsafe { self.make_guard_unchecked() } } /// Attempts to acquire this lock. @@ -227,7 +232,7 @@ impl Mutex { pub fn try_lock(&self) -> Option> { if self.raw.try_lock() { // SAFETY: The lock is held, as required. - Some(unsafe { self.guard() }) + Some(unsafe { self.make_guard_unchecked() }) } else { None } @@ -257,7 +262,7 @@ impl Mutex { /// # Safety /// /// This method must only be called if the current thread logically owns a - /// `MutexGuard` but that guard has be discarded using `mem::forget`. + /// `MutexGuard` but that guard has been discarded using `mem::forget`. /// Behavior is undefined if a mutex is unlocked when not locked. #[inline] pub unsafe fn force_unlock(&self) { @@ -294,12 +299,17 @@ impl Mutex { self.data.get() } + /// Creates a new `ArcMutexGuard` without checking if the mutex is locked. + /// /// # Safety /// - /// The lock needs to be held for the behavior of this function to be defined. + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn guard_arc(self: &Arc) -> ArcMutexGuard { + unsafe fn make_arc_guard_unchecked(self: &Arc) -> ArcMutexGuard { ArcMutexGuard { mutex: self.clone(), marker: PhantomData, @@ -315,7 +325,7 @@ impl Mutex { pub fn lock_arc(self: &Arc) -> ArcMutexGuard { self.raw.lock(); // SAFETY: the locking guarantee is upheld - unsafe { self.guard_arc() } + unsafe { self.make_arc_guard_unchecked() } } /// Attempts to acquire a lock through an `Arc`. @@ -327,7 +337,7 @@ impl Mutex { pub fn try_lock_arc(self: &Arc) -> Option> { if self.raw.try_lock() { // SAFETY: locking guarantee is upheld - Some(unsafe { self.guard_arc() }) + Some(unsafe { self.make_arc_guard_unchecked() }) } else { None } @@ -344,7 +354,7 @@ impl Mutex { /// # Safety /// /// This method must only be called if the current thread logically owns a - /// `MutexGuard` but that guard has be discarded using `mem::forget`. + /// `MutexGuard` but that guard has been discarded using `mem::forget`. /// Behavior is undefined if a mutex is unlocked when not locked. #[inline] pub unsafe fn force_unlock_fair(&self) { @@ -362,7 +372,7 @@ impl Mutex { pub fn try_lock_for(&self, timeout: R::Duration) -> Option> { if self.raw.try_lock_for(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.guard() }) + Some(unsafe { self.make_guard_unchecked() }) } else { None } @@ -377,7 +387,7 @@ impl Mutex { pub fn try_lock_until(&self, timeout: R::Instant) -> Option> { if self.raw.try_lock_until(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.guard() }) + Some(unsafe { self.make_guard_unchecked() }) } else { None } @@ -392,7 +402,7 @@ impl Mutex { pub fn try_lock_arc_for(self: &Arc, timeout: R::Duration) -> Option> { if self.raw.try_lock_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.guard_arc() }) + Some(unsafe { self.make_arc_guard_unchecked() }) } else { None } @@ -410,7 +420,7 @@ impl Mutex { ) -> Option> { if self.raw.try_lock_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.guard_arc() }) + Some(unsafe { self.make_arc_guard_unchecked() }) } else { None } @@ -485,6 +495,7 @@ where /// /// The data protected by the mutex can be accessed through this guard via its /// `Deref` and `DerefMut` implementations. +#[clippy::has_significant_drop] #[must_use = "if unused the Mutex will immediately unlock"] pub struct MutexGuard<'a, R: RawMutex, T: ?Sized> { mutex: &'a Mutex, @@ -678,6 +689,7 @@ unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<' /// This is similar to the `MutexGuard` struct, except instead of using a reference to unlock the `Mutex` it /// uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. #[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] #[must_use = "if unused the Mutex will immediately unlock"] pub struct ArcMutexGuard { mutex: Arc>, @@ -813,6 +825,7 @@ impl Drop for ArcMutexGuard { /// former doesn't support temporarily unlocking and re-locking, since that /// could introduce soundness issues if the locked object is modified by another /// thread. +#[clippy::has_significant_drop] #[must_use = "if unused the Mutex will immediately unlock"] pub struct MappedMutexGuard<'a, R: RawMutex, T: ?Sized> { raw: &'a R, diff --git a/src/remutex.rs b/src/remutex.rs index 3e2010f..74f2da3 100644 --- a/src/remutex.rs +++ b/src/remutex.rs @@ -183,8 +183,10 @@ impl RawReentrantMutex { if self.lock_count.get() == 1 { let id = self.owner.load(Ordering::Relaxed); self.owner.store(0, Ordering::Relaxed); + self.lock_count.set(0); self.mutex.bump(); self.owner.store(id, Ordering::Relaxed); + self.lock_count.set(1); } } } @@ -287,11 +289,16 @@ impl ReentrantMutex { } impl ReentrantMutex { + /// Creates a new `ReentrantMutexGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. #[inline] - unsafe fn guard(&self) -> ReentrantMutexGuard<'_, R, G, T> { + pub unsafe fn make_guard_unchecked(&self) -> ReentrantMutexGuard<'_, R, G, T> { ReentrantMutexGuard { remutex: &self, marker: PhantomData, @@ -312,7 +319,7 @@ impl ReentrantMutex { pub fn lock(&self) -> ReentrantMutexGuard<'_, R, G, T> { self.raw.lock(); // SAFETY: The lock is held, as required. - unsafe { self.guard() } + unsafe { self.make_guard_unchecked() } } /// Attempts to acquire this lock. @@ -326,7 +333,7 @@ impl ReentrantMutex { pub fn try_lock(&self) -> Option> { if self.raw.try_lock() { // SAFETY: The lock is held, as required. - Some(unsafe { self.guard() }) + Some(unsafe { self.make_guard_unchecked() }) } else { None } @@ -400,12 +407,17 @@ impl ReentrantMutex { self.data.get() } + /// Creates a new `ArcReentrantMutexGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held before calling this method. + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn guard_arc(self: &Arc) -> ArcReentrantMutexGuard { + pub unsafe fn make_arc_guard_unchecked(self: &Arc) -> ArcReentrantMutexGuard { ArcReentrantMutexGuard { remutex: self.clone(), marker: PhantomData, @@ -421,7 +433,7 @@ impl ReentrantMutex { pub fn lock_arc(self: &Arc) -> ArcReentrantMutexGuard { self.raw.lock(); // SAFETY: locking guarantee is upheld - unsafe { self.guard_arc() } + unsafe { self.make_arc_guard_unchecked() } } /// Attempts to acquire a reentrant mutex through an `Arc`. @@ -433,7 +445,7 @@ impl ReentrantMutex { pub fn try_lock_arc(self: &Arc) -> Option> { if self.raw.try_lock() { // SAFETY: locking guarantee is upheld - Some(unsafe { self.guard_arc() }) + Some(unsafe { self.make_arc_guard_unchecked() }) } else { None } @@ -468,7 +480,7 @@ impl ReentrantMutex { pub fn try_lock_for(&self, timeout: R::Duration) -> Option> { if self.raw.try_lock_for(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.guard() }) + Some(unsafe { self.make_guard_unchecked() }) } else { None } @@ -483,7 +495,7 @@ impl ReentrantMutex { pub fn try_lock_until(&self, timeout: R::Instant) -> Option> { if self.raw.try_lock_until(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.guard() }) + Some(unsafe { self.make_guard_unchecked() }) } else { None } @@ -501,7 +513,7 @@ impl ReentrantMutex { ) -> Option> { if self.raw.try_lock_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.guard_arc() }) + Some(unsafe { self.make_arc_guard_unchecked() }) } else { None } @@ -519,7 +531,7 @@ impl ReentrantMutex { ) -> Option> { if self.raw.try_lock_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.guard_arc() }) + Some(unsafe { self.make_arc_guard_unchecked() }) } else { None } @@ -599,6 +611,7 @@ where /// /// The data protected by the mutex can be accessed through this guard via its /// `Deref` implementation. +#[clippy::has_significant_drop] #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> { remutex: &'a ReentrantMutex, @@ -794,6 +807,7 @@ unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAdd /// `Mutex` it uses an `Arc`. This has several advantages, most notably that it has an `'static` /// lifetime. #[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ArcReentrantMutexGuard { remutex: Arc>, @@ -897,6 +911,7 @@ impl Drop for ArcReentrantMutexGuard { raw: &'a RawReentrantMutex, diff --git a/src/rwlock.rs b/src/rwlock.rs index c972fb6..cf9e8aa 100644 --- a/src/rwlock.rs +++ b/src/rwlock.rs @@ -409,22 +409,33 @@ impl RwLock { } impl RwLock { + /// Creates a new `RwLockReadGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds a read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` #[inline] - unsafe fn read_guard(&self) -> RwLockReadGuard<'_, R, T> { + pub unsafe fn make_read_guard_unchecked(&self) -> RwLockReadGuard<'_, R, T> { RwLockReadGuard { rwlock: self, marker: PhantomData, } } + /// Creates a new `RwLockReadGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds a write lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. #[inline] - unsafe fn write_guard(&self) -> RwLockWriteGuard<'_, R, T> { + pub unsafe fn make_write_guard_unchecked(&self) -> RwLockWriteGuard<'_, R, T> { RwLockWriteGuard { rwlock: self, marker: PhantomData, @@ -447,7 +458,7 @@ impl RwLock { pub fn read(&self) -> RwLockReadGuard<'_, R, T> { self.raw.lock_shared(); // SAFETY: The lock is held, as required. - unsafe { self.read_guard() } + unsafe { self.make_read_guard_unchecked() } } /// Attempts to acquire this `RwLock` with shared read access. @@ -461,7 +472,7 @@ impl RwLock { pub fn try_read(&self) -> Option> { if self.raw.try_lock_shared() { // SAFETY: The lock is held, as required. - Some(unsafe { self.read_guard() }) + Some(unsafe { self.make_read_guard_unchecked() }) } else { None } @@ -479,7 +490,7 @@ impl RwLock { pub fn write(&self) -> RwLockWriteGuard<'_, R, T> { self.raw.lock_exclusive(); // SAFETY: The lock is held, as required. - unsafe { self.write_guard() } + unsafe { self.make_write_guard_unchecked() } } /// Attempts to lock this `RwLock` with exclusive write access. @@ -493,7 +504,7 @@ impl RwLock { pub fn try_write(&self) -> Option> { if self.raw.try_lock_exclusive() { // SAFETY: The lock is held, as required. - Some(unsafe { self.write_guard() }) + Some(unsafe { self.make_write_guard_unchecked() }) } else { None } @@ -583,24 +594,35 @@ impl RwLock { self.data.get() } + /// Creates a new `RwLockReadGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds a read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` #[cfg(feature = "arc_lock")] #[inline] - unsafe fn read_guard_arc(self: &Arc) -> ArcRwLockReadGuard { + pub unsafe fn make_arc_read_guard_unchecked(self: &Arc) -> ArcRwLockReadGuard { ArcRwLockReadGuard { rwlock: self.clone(), marker: PhantomData, } } + /// Creates a new `RwLockWriteGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds a write lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. #[cfg(feature = "arc_lock")] #[inline] - unsafe fn write_guard_arc(self: &Arc) -> ArcRwLockWriteGuard { + pub unsafe fn make_arc_write_guard_unchecked(self: &Arc) -> ArcRwLockWriteGuard { ArcRwLockWriteGuard { rwlock: self.clone(), marker: PhantomData, @@ -616,7 +638,7 @@ impl RwLock { pub fn read_arc(self: &Arc) -> ArcRwLockReadGuard { self.raw.lock_shared(); // SAFETY: locking guarantee is upheld - unsafe { self.read_guard_arc() } + unsafe { self.make_arc_read_guard_unchecked() } } /// Attempts to lock this `RwLock` with read access, through an `Arc`. @@ -628,7 +650,7 @@ impl RwLock { pub fn try_read_arc(self: &Arc) -> Option> { if self.raw.try_lock_shared() { // SAFETY: locking guarantee is upheld - Some(unsafe { self.read_guard_arc() }) + Some(unsafe { self.make_arc_read_guard_unchecked() }) } else { None } @@ -643,7 +665,7 @@ impl RwLock { pub fn write_arc(self: &Arc) -> ArcRwLockWriteGuard { self.raw.lock_exclusive(); // SAFETY: locking guarantee is upheld - unsafe { self.write_guard_arc() } + unsafe { self.make_arc_write_guard_unchecked() } } /// Attempts to lock this `RwLock` with writ access, through an `Arc`. @@ -655,7 +677,7 @@ impl RwLock { pub fn try_write_arc(self: &Arc) -> Option> { if self.raw.try_lock_exclusive() { // SAFETY: locking guarantee is upheld - Some(unsafe { self.write_guard_arc() }) + Some(unsafe { self.make_arc_write_guard_unchecked() }) } else { None } @@ -707,7 +729,7 @@ impl RwLock { pub fn try_read_for(&self, timeout: R::Duration) -> Option> { if self.raw.try_lock_shared_for(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.read_guard() }) + Some(unsafe { self.make_read_guard_unchecked() }) } else { None } @@ -723,7 +745,7 @@ impl RwLock { pub fn try_read_until(&self, timeout: R::Instant) -> Option> { if self.raw.try_lock_shared_until(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.read_guard() }) + Some(unsafe { self.make_read_guard_unchecked() }) } else { None } @@ -739,7 +761,7 @@ impl RwLock { pub fn try_write_for(&self, timeout: R::Duration) -> Option> { if self.raw.try_lock_exclusive_for(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.write_guard() }) + Some(unsafe { self.make_write_guard_unchecked() }) } else { None } @@ -755,7 +777,7 @@ impl RwLock { pub fn try_write_until(&self, timeout: R::Instant) -> Option> { if self.raw.try_lock_exclusive_until(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.write_guard() }) + Some(unsafe { self.make_write_guard_unchecked() }) } else { None } @@ -773,7 +795,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_shared_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.read_guard_arc() }) + Some(unsafe { self.make_arc_read_guard_unchecked() }) } else { None } @@ -791,7 +813,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_shared_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.read_guard_arc() }) + Some(unsafe { self.make_arc_read_guard_unchecked() }) } else { None } @@ -809,7 +831,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_exclusive_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.write_guard_arc() }) + Some(unsafe { self.make_arc_write_guard_unchecked() }) } else { None } @@ -827,7 +849,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_exclusive_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.write_guard_arc() }) + Some(unsafe { self.make_arc_write_guard_unchecked() }) } else { None } @@ -854,7 +876,7 @@ impl RwLock { pub fn read_recursive(&self) -> RwLockReadGuard<'_, R, T> { self.raw.lock_shared_recursive(); // SAFETY: The lock is held, as required. - unsafe { self.read_guard() } + unsafe { self.make_read_guard_unchecked() } } /// Attempts to acquire this `RwLock` with shared read access. @@ -871,7 +893,7 @@ impl RwLock { pub fn try_read_recursive(&self) -> Option> { if self.raw.try_lock_shared_recursive() { // SAFETY: The lock is held, as required. - Some(unsafe { self.read_guard() }) + Some(unsafe { self.make_read_guard_unchecked() }) } else { None } @@ -886,7 +908,7 @@ impl RwLock { pub fn read_arc_recursive(self: &Arc) -> ArcRwLockReadGuard { self.raw.lock_shared_recursive(); // SAFETY: locking guarantee is upheld - unsafe { self.read_guard_arc() } + unsafe { self.make_arc_read_guard_unchecked() } } /// Attempts to lock this `RwLock` with shared read access, through an `Arc`. @@ -898,7 +920,7 @@ impl RwLock { pub fn try_read_recursive_arc(self: &Arc) -> Option> { if self.raw.try_lock_shared_recursive() { // SAFETY: locking guarantee is upheld - Some(unsafe { self.read_guard_arc() }) + Some(unsafe { self.make_arc_read_guard_unchecked() }) } else { None } @@ -923,7 +945,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_shared_recursive_for(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.read_guard() }) + Some(unsafe { self.make_read_guard_unchecked() }) } else { None } @@ -942,7 +964,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_shared_recursive_until(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.read_guard() }) + Some(unsafe { self.make_read_guard_unchecked() }) } else { None } @@ -960,7 +982,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_shared_recursive_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.read_guard_arc() }) + Some(unsafe { self.make_arc_read_guard_unchecked() }) } else { None } @@ -978,7 +1000,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_shared_recursive_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.read_guard_arc() }) + Some(unsafe { self.make_arc_read_guard_unchecked() }) } else { None } @@ -986,11 +1008,17 @@ impl RwLock { } impl RwLock { + /// Creates a new `RwLockUpgradableReadGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds an upgradable read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` #[inline] - unsafe fn upgradable_guard(&self) -> RwLockUpgradableReadGuard<'_, R, T> { + pub unsafe fn make_upgradable_guard_unchecked(&self) -> RwLockUpgradableReadGuard<'_, R, T> { RwLockUpgradableReadGuard { rwlock: self, marker: PhantomData, @@ -1010,7 +1038,7 @@ impl RwLock { pub fn upgradable_read(&self) -> RwLockUpgradableReadGuard<'_, R, T> { self.raw.lock_upgradable(); // SAFETY: The lock is held, as required. - unsafe { self.upgradable_guard() } + unsafe { self.make_upgradable_guard_unchecked() } } /// Attempts to acquire this `RwLock` with upgradable read access. @@ -1024,18 +1052,26 @@ impl RwLock { pub fn try_upgradable_read(&self) -> Option> { if self.raw.try_lock_upgradable() { // SAFETY: The lock is held, as required. - Some(unsafe { self.upgradable_guard() }) + Some(unsafe { self.make_upgradable_guard_unchecked() }) } else { None } } + /// Creates a new `ArcRwLockUpgradableReadGuard` without checking if the lock is held. + /// /// # Safety /// - /// The lock must be held when calling this method. + /// This method must only be called if the thread logically holds an upgradable read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` #[cfg(feature = "arc_lock")] #[inline] - unsafe fn upgradable_guard_arc(self: &Arc) -> ArcRwLockUpgradableReadGuard { + pub unsafe fn make_upgradable_arc_guard_unchecked( + self: &Arc, + ) -> ArcRwLockUpgradableReadGuard { ArcRwLockUpgradableReadGuard { rwlock: self.clone(), marker: PhantomData, @@ -1051,7 +1087,7 @@ impl RwLock { pub fn upgradable_read_arc(self: &Arc) -> ArcRwLockUpgradableReadGuard { self.raw.lock_upgradable(); // SAFETY: locking guarantee is upheld - unsafe { self.upgradable_guard_arc() } + unsafe { self.make_upgradable_arc_guard_unchecked() } } /// Attempts to lock this `RwLock` with upgradable read access, through an `Arc`. @@ -1063,7 +1099,7 @@ impl RwLock { pub fn try_upgradable_read_arc(self: &Arc) -> Option> { if self.raw.try_lock_upgradable() { // SAFETY: locking guarantee is upheld - Some(unsafe { self.upgradable_guard_arc() }) + Some(unsafe { self.make_upgradable_arc_guard_unchecked() }) } else { None } @@ -1084,7 +1120,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_upgradable_for(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.upgradable_guard() }) + Some(unsafe { self.make_upgradable_guard_unchecked() }) } else { None } @@ -1103,7 +1139,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_upgradable_until(timeout) { // SAFETY: The lock is held, as required. - Some(unsafe { self.upgradable_guard() }) + Some(unsafe { self.make_upgradable_guard_unchecked() }) } else { None } @@ -1121,7 +1157,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_upgradable_for(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.upgradable_guard_arc() }) + Some(unsafe { self.make_upgradable_arc_guard_unchecked() }) } else { None } @@ -1139,7 +1175,7 @@ impl RwLock { ) -> Option> { if self.raw.try_lock_upgradable_until(timeout) { // SAFETY: locking guarantee is upheld - Some(unsafe { self.upgradable_guard_arc() }) + Some(unsafe { self.make_upgradable_arc_guard_unchecked() }) } else { None } @@ -1182,12 +1218,15 @@ impl fmt::Debug for RwLock { /// RAII structure used to release the shared read access of a lock when /// dropped. +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockReadGuard<'a, R: RawRwLock, T: ?Sized> { rwlock: &'a RwLock, marker: PhantomData<(&'a T, R::GuardMarker)>, } +unsafe impl Sync for RwLockReadGuard<'_, R, T> {} + impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockReadGuard<'a, R, T> { /// Returns a reference to the original reader-writer lock object. pub fn rwlock(s: &Self) -> &'a RwLock { @@ -1246,8 +1285,6 @@ impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockReadGuard<'a, R, T> { /// Temporarily unlocks the `RwLock` to execute the given function. /// - /// The `RwLock` is unlocked a fair unlock protocol. - /// /// This is safe because `&mut` guarantees that there exist no other /// references to the data protected by the `RwLock`. #[inline] @@ -1359,6 +1396,7 @@ unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockReadG /// This is similar to the `RwLockReadGuard` struct, except instead of using a reference to unlock the `RwLock` /// it uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. #[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct ArcRwLockReadGuard { rwlock: Arc>, @@ -1470,12 +1508,15 @@ impl fmt::Display for ArcRwLockReadGuard /// RAII structure used to release the exclusive write access of a lock when /// dropped. +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockWriteGuard<'a, R: RawRwLock, T: ?Sized> { rwlock: &'a RwLock, marker: PhantomData<(&'a mut T, R::GuardMarker)>, } +unsafe impl Sync for RwLockWriteGuard<'_, R, T> {} + impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockWriteGuard<'a, R, T> { /// Returns a reference to the original reader-writer lock object. pub fn rwlock(s: &Self) -> &'a RwLock { @@ -1693,6 +1734,7 @@ unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockWrite /// This is similar to the `RwLockWriteGuard` struct, except instead of using a reference to unlock the `RwLock` /// it uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. #[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct ArcRwLockWriteGuard { rwlock: Arc>, @@ -1858,6 +1900,7 @@ impl fmt::Display for ArcRwLockWriteGuar /// RAII structure used to release the upgradable read access of a lock when /// dropped. +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockUpgradableReadGuard<'a, R: RawRwLockUpgrade, T: ?Sized> { rwlock: &'a RwLock, @@ -1892,7 +1935,7 @@ impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, f() } - /// Atomically upgrades an upgradable read lock lock into a exclusive write lock, + /// Atomically upgrades an upgradable read lock lock into an exclusive write lock, /// blocking the current thread until it can be acquired. pub fn upgrade(s: Self) -> RwLockWriteGuard<'a, R, T> { // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. @@ -1907,7 +1950,7 @@ impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, } } - /// Tries to atomically upgrade an upgradable read lock into a exclusive write lock. + /// Tries to atomically upgrade an upgradable read lock into an exclusive write lock. /// /// If the access could not be granted at this time, then the current guard is returned. pub fn try_upgrade(s: Self) -> Result, Self> { @@ -2000,10 +2043,60 @@ impl<'a, R: RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a> RwLockUpgradableRead marker: PhantomData, } } + + /// First, atomically upgrades an upgradable read lock lock into an exclusive write lock, + /// blocking the current thread until it can be acquired. + /// + /// Then, calls the provided closure with an exclusive reference to the lock's data. + /// + /// Finally, atomically downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `upgrade` which takes the guard by value. + pub fn with_upgraded Ret>(&mut self, f: F) -> Ret { + unsafe { + self.rwlock.raw.upgrade(); + } + + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_to_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + f(unsafe { &mut *self.rwlock.data.get() }) + } + + /// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock. + /// + /// If the access could not be granted at this time, then `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade` which takes the guard by value. + pub fn try_with_upgraded Ret>(&mut self, f: F) -> Option { + if unsafe { self.rwlock.raw.try_upgrade() } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_to_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } } impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> { - /// Tries to atomically upgrade an upgradable read lock into a exclusive + /// Tries to atomically upgrade an upgradable read lock into an exclusive /// write lock, until a timeout is reached. /// /// If the access could not be granted before the timeout expires, then @@ -2025,7 +2118,7 @@ impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuar } } - /// Tries to atomically upgrade an upgradable read lock into a exclusive + /// Tries to atomically upgrade an upgradable read lock into an exclusive /// write lock, until a timeout is reached. /// /// If the access could not be granted before the timeout expires, then @@ -2049,6 +2142,72 @@ impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuar } } +impl<'a, R: RawRwLockUpgradeTimed + RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a> + RwLockUpgradableReadGuard<'a, R, T> +{ + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_for` which takes the guard by value. + pub fn try_with_upgraded_for Ret>( + &mut self, + timeout: R::Duration, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_until` which takes the guard by value. + pub fn try_with_upgraded_until Ret>( + &mut self, + timeout: R::Instant, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } +} + impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> Deref for RwLockUpgradableReadGuard<'a, R, T> { type Target = T; #[inline] @@ -2094,6 +2253,7 @@ unsafe impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> StableAddress /// `RwLock` it uses an `Arc`. This has several advantages, most notably that it has an `'static` /// lifetime. #[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct ArcRwLockUpgradableReadGuard { rwlock: Arc>, @@ -2123,7 +2283,7 @@ impl ArcRwLockUpgradableReadGuard { f() } - /// Atomically upgrades an upgradable read lock lock into a exclusive write lock, + /// Atomically upgrades an upgradable read lock lock into an exclusive write lock, /// blocking the current thread until it can be acquired. pub fn upgrade(s: Self) -> ArcRwLockWriteGuard { // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. @@ -2142,7 +2302,7 @@ impl ArcRwLockUpgradableReadGuard { } } - /// Tries to atomically upgrade an upgradable read lock into a exclusive write lock. + /// Tries to atomically upgrade an upgradable read lock into an exclusive write lock. /// /// If the access could not be granted at this time, then the current guard is returned. pub fn try_upgrade(s: Self) -> Result, Self> { @@ -2231,11 +2391,61 @@ impl ArcRwLockUpgradableReadGuard marker: PhantomData, } } + + /// First, atomically upgrades an upgradable read lock lock into an exclusive write lock, + /// blocking the current thread until it can be acquired. + /// + /// Then, calls the provided closure with an exclusive reference to the lock's data. + /// + /// Finally, atomically downgrades the lock back to an upgradable read lock. + /// The closure's return value is returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `upgrade` which takes the guard by value. + pub fn with_upgraded Ret>(&mut self, f: F) -> Ret { + unsafe { + self.rwlock.raw.upgrade(); + } + + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + f(unsafe { &mut *self.rwlock.data.get() }) + } + + /// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock. + /// + /// If the access could not be granted at this time, then `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade` which takes the guard by value. + pub fn try_with_upgraded Ret>(&mut self, f: F) -> Option { + if unsafe { self.rwlock.raw.try_upgrade() } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } } #[cfg(feature = "arc_lock")] impl ArcRwLockUpgradableReadGuard { - /// Tries to atomically upgrade an upgradable read lock into a exclusive + /// Tries to atomically upgrade an upgradable read lock into an exclusive /// write lock, until a timeout is reached. /// /// If the access could not be granted before the timeout expires, then @@ -2259,7 +2469,7 @@ impl ArcRwLockUpgradableReadGuard { } } - /// Tries to atomically upgrade an upgradable read lock into a exclusive + /// Tries to atomically upgrade an upgradable read lock into an exclusive /// write lock, until a timeout is reached. /// /// If the access could not be granted before the timeout expires, then @@ -2285,6 +2495,73 @@ impl ArcRwLockUpgradableReadGuard { } } +#[cfg(feature = "arc_lock")] +impl + ArcRwLockUpgradableReadGuard +{ + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_for` which takes the guard by value. + pub fn try_with_upgraded_for Ret>( + &mut self, + timeout: R::Duration, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_until` which takes the guard by value. + pub fn try_with_upgraded_until Ret>( + &mut self, + timeout: R::Instant, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } +} + #[cfg(feature = "arc_lock")] impl Deref for ArcRwLockUpgradableReadGuard { type Target = T; @@ -2330,6 +2607,7 @@ impl fmt::Display /// former doesn't support temporarily unlocking and re-locking, since that /// could introduce soundness issues if the locked object is modified by another /// thread. +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct MappedRwLockReadGuard<'a, R: RawRwLock, T: ?Sized> { raw: &'a R, @@ -2465,6 +2743,7 @@ unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress /// former doesn't support temporarily unlocking and re-locking, since that /// could introduce soundness issues if the locked object is modified by another /// thread. +#[clippy::has_significant_drop] #[must_use = "if unused the RwLock will immediately unlock"] pub struct MappedRwLockWriteGuard<'a, R: RawRwLock, T: ?Sized> { raw: &'a R, -- cgit v1.2.3