mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-23 13:13:17 +00:00
Auto merge of #8419 - flip1995:await_parking_alot, r=llogiq
Fix `await_holding_lock` not linting `parking_lot` Mutex/RwLock
This adds tests for `RwLock` and `parking_lot::{Mutex, RwLock}`, which were added before in 2dc8c083f5
, but never tested in UI tests. I noticed this while reading [fasterthanli.me](https://fasterthanli.me/articles/a-rust-match-made-in-hell) latest blog post, complaining that Clippy doesn't catch this for `parking_lot`. (Too many people read his blog, he's too powerful)
Some more things:
- Adds a test for #6446
- Improves the lint message
changelog: [`await_holding_lock`]: Now also lints for `parking_lot::{Mutex, RwLock}`
This commit is contained in:
commit
02f3c17593
@ -1,4 +1,4 @@
|
|||||||
use clippy_utils::diagnostics::span_lint_and_note;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::{match_def_path, paths};
|
use clippy_utils::{match_def_path, paths};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
|
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
|
||||||
@ -9,8 +9,7 @@ use rustc_span::Span;
|
|||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Checks for calls to await while holding a
|
/// Checks for calls to await while holding a non-async-aware MutexGuard.
|
||||||
/// non-async-aware MutexGuard.
|
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// The Mutex types found in std::sync and parking_lot
|
/// The Mutex types found in std::sync and parking_lot
|
||||||
@ -22,41 +21,57 @@ declare_clippy_lint! {
|
|||||||
/// either by introducing a scope or an explicit call to Drop::drop.
|
/// either by introducing a scope or an explicit call to Drop::drop.
|
||||||
///
|
///
|
||||||
/// ### Known problems
|
/// ### Known problems
|
||||||
/// Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)).
|
/// Will report false positive for explicitly dropped guards
|
||||||
|
/// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
|
||||||
|
/// to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust,ignore
|
/// ```rust
|
||||||
/// use std::sync::Mutex;
|
/// # use std::sync::Mutex;
|
||||||
///
|
/// # async fn baz() {}
|
||||||
/// async fn foo(x: &Mutex<u32>) {
|
/// async fn foo(x: &Mutex<u32>) {
|
||||||
/// let guard = x.lock().unwrap();
|
/// let mut guard = x.lock().unwrap();
|
||||||
/// *guard += 1;
|
/// *guard += 1;
|
||||||
/// bar.await;
|
/// baz().await;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async fn bar(x: &Mutex<u32>) {
|
||||||
|
/// let mut guard = x.lock().unwrap();
|
||||||
|
/// *guard += 1;
|
||||||
|
/// drop(guard); // explicit drop
|
||||||
|
/// baz().await;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```rust,ignore
|
/// ```rust
|
||||||
/// use std::sync::Mutex;
|
/// # use std::sync::Mutex;
|
||||||
///
|
/// # async fn baz() {}
|
||||||
/// async fn foo(x: &Mutex<u32>) {
|
/// async fn foo(x: &Mutex<u32>) {
|
||||||
/// {
|
/// {
|
||||||
/// let guard = x.lock().unwrap();
|
/// let mut guard = x.lock().unwrap();
|
||||||
/// *guard += 1;
|
/// *guard += 1;
|
||||||
/// }
|
/// }
|
||||||
/// bar.await;
|
/// baz().await;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async fn bar(x: &Mutex<u32>) {
|
||||||
|
/// {
|
||||||
|
/// let mut guard = x.lock().unwrap();
|
||||||
|
/// *guard += 1;
|
||||||
|
/// } // guard dropped here at end of scope
|
||||||
|
/// baz().await;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.45.0"]
|
#[clippy::version = "1.45.0"]
|
||||||
pub AWAIT_HOLDING_LOCK,
|
pub AWAIT_HOLDING_LOCK,
|
||||||
pedantic,
|
suspicious,
|
||||||
"Inside an async function, holding a MutexGuard while calling await"
|
"inside an async function, holding a `MutexGuard` while calling `await`"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Checks for calls to await while holding a
|
/// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
|
||||||
/// `RefCell` `Ref` or `RefMut`.
|
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// `RefCell` refs only check for exclusive mutable access
|
/// `RefCell` refs only check for exclusive mutable access
|
||||||
@ -64,35 +79,52 @@ declare_clippy_lint! {
|
|||||||
/// risks panics from a mutable ref shared while other refs are outstanding.
|
/// risks panics from a mutable ref shared while other refs are outstanding.
|
||||||
///
|
///
|
||||||
/// ### Known problems
|
/// ### Known problems
|
||||||
/// Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)).
|
/// Will report false positive for explicitly dropped refs
|
||||||
|
/// ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is
|
||||||
|
/// to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust,ignore
|
/// ```rust
|
||||||
/// use std::cell::RefCell;
|
/// # use std::cell::RefCell;
|
||||||
///
|
/// # async fn baz() {}
|
||||||
/// async fn foo(x: &RefCell<u32>) {
|
/// async fn foo(x: &RefCell<u32>) {
|
||||||
/// let mut y = x.borrow_mut();
|
/// let mut y = x.borrow_mut();
|
||||||
/// *y += 1;
|
/// *y += 1;
|
||||||
/// bar.await;
|
/// baz().await;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async fn bar(x: &RefCell<u32>) {
|
||||||
|
/// let mut y = x.borrow_mut();
|
||||||
|
/// *y += 1;
|
||||||
|
/// drop(y); // explicit drop
|
||||||
|
/// baz().await;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```rust,ignore
|
/// ```rust
|
||||||
/// use std::cell::RefCell;
|
/// # use std::cell::RefCell;
|
||||||
///
|
/// # async fn baz() {}
|
||||||
/// async fn foo(x: &RefCell<u32>) {
|
/// async fn foo(x: &RefCell<u32>) {
|
||||||
/// {
|
/// {
|
||||||
/// let mut y = x.borrow_mut();
|
/// let mut y = x.borrow_mut();
|
||||||
/// *y += 1;
|
/// *y += 1;
|
||||||
/// }
|
/// }
|
||||||
/// bar.await;
|
/// baz().await;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async fn bar(x: &RefCell<u32>) {
|
||||||
|
/// {
|
||||||
|
/// let mut y = x.borrow_mut();
|
||||||
|
/// *y += 1;
|
||||||
|
/// } // y dropped here at end of scope
|
||||||
|
/// baz().await;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.49.0"]
|
#[clippy::version = "1.49.0"]
|
||||||
pub AWAIT_HOLDING_REFCELL_REF,
|
pub AWAIT_HOLDING_REFCELL_REF,
|
||||||
pedantic,
|
suspicious,
|
||||||
"Inside an async function, holding a RefCell ref while calling await"
|
"inside an async function, holding a `RefCell` ref while calling `await`"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);
|
declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);
|
||||||
@ -118,23 +150,36 @@ fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorType
|
|||||||
for ty_cause in ty_causes {
|
for ty_cause in ty_causes {
|
||||||
if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
|
if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
|
||||||
if is_mutex_guard(cx, adt.did) {
|
if is_mutex_guard(cx, adt.did) {
|
||||||
span_lint_and_note(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
AWAIT_HOLDING_LOCK,
|
AWAIT_HOLDING_LOCK,
|
||||||
ty_cause.span,
|
ty_cause.span,
|
||||||
"this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await",
|
"this `MutexGuard` is held across an `await` point",
|
||||||
ty_cause.scope_span.or(Some(span)),
|
|diag| {
|
||||||
"these are all the await points this lock is held through",
|
diag.help(
|
||||||
|
"consider using an async-aware `Mutex` type or ensuring the \
|
||||||
|
`MutexGuard` is dropped before calling await",
|
||||||
|
);
|
||||||
|
diag.span_note(
|
||||||
|
ty_cause.scope_span.unwrap_or(span),
|
||||||
|
"these are all the `await` points this lock is held through",
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if is_refcell_ref(cx, adt.did) {
|
if is_refcell_ref(cx, adt.did) {
|
||||||
span_lint_and_note(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
AWAIT_HOLDING_REFCELL_REF,
|
AWAIT_HOLDING_REFCELL_REF,
|
||||||
ty_cause.span,
|
ty_cause.span,
|
||||||
"this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await",
|
"this `RefCell` reference is held across an `await` point",
|
||||||
ty_cause.scope_span.or(Some(span)),
|
|diag| {
|
||||||
"these are all the await points this ref is held through",
|
diag.help("ensure the reference is dropped before calling `await`");
|
||||||
|
diag.span_note(
|
||||||
|
ty_cause.scope_span.unwrap_or(span),
|
||||||
|
"these are all the `await` points this reference is held through",
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||||||
LintId::of(attrs::DEPRECATED_SEMVER),
|
LintId::of(attrs::DEPRECATED_SEMVER),
|
||||||
LintId::of(attrs::MISMATCHED_TARGET_OS),
|
LintId::of(attrs::MISMATCHED_TARGET_OS),
|
||||||
LintId::of(attrs::USELESS_ATTRIBUTE),
|
LintId::of(attrs::USELESS_ATTRIBUTE),
|
||||||
|
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||||
|
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||||
LintId::of(bit_mask::BAD_BIT_MASK),
|
LintId::of(bit_mask::BAD_BIT_MASK),
|
||||||
LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
|
LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
|
||||||
LintId::of(blacklisted_name::BLACKLISTED_NAME),
|
LintId::of(blacklisted_name::BLACKLISTED_NAME),
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
|
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
|
||||||
LintId::of(attrs::INLINE_ALWAYS),
|
LintId::of(attrs::INLINE_ALWAYS),
|
||||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
|
|
||||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
|
||||||
LintId::of(bit_mask::VERBOSE_BIT_MASK),
|
LintId::of(bit_mask::VERBOSE_BIT_MASK),
|
||||||
LintId::of(borrow_as_ptr::BORROW_AS_PTR),
|
LintId::of(borrow_as_ptr::BORROW_AS_PTR),
|
||||||
LintId::of(bytecount::NAIVE_BYTECOUNT),
|
LintId::of(bytecount::NAIVE_BYTECOUNT),
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
|
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
|
||||||
LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
|
LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
|
||||||
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
|
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
|
||||||
|
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||||
|
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||||
LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
|
LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
|
||||||
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
|
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
|
||||||
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
|
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
|
||||||
|
@ -105,9 +105,9 @@ pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString",
|
|||||||
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
|
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
|
||||||
pub const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"];
|
pub const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"];
|
||||||
pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"];
|
pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"];
|
||||||
pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
|
pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
|
||||||
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
|
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"];
|
||||||
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
|
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
|
||||||
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
|
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
|
||||||
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
|
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
|
||||||
pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
|
pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
|
||||||
|
@ -1,64 +1,192 @@
|
|||||||
#![warn(clippy::await_holding_lock)]
|
#![warn(clippy::await_holding_lock)]
|
||||||
|
|
||||||
use std::sync::Mutex;
|
// When adding or modifying a test, please do the same for parking_lot::Mutex.
|
||||||
|
mod std_mutex {
|
||||||
|
use super::baz;
|
||||||
|
use std::sync::{Mutex, RwLock};
|
||||||
|
|
||||||
async fn bad(x: &Mutex<u32>) -> u32 {
|
pub async fn bad(x: &Mutex<u32>) -> u32 {
|
||||||
let guard = x.lock().unwrap();
|
let guard = x.lock().unwrap();
|
||||||
baz().await
|
baz().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn good(x: &Mutex<u32>) -> u32 {
|
||||||
|
{
|
||||||
|
let guard = x.lock().unwrap();
|
||||||
|
let y = *guard + 1;
|
||||||
|
}
|
||||||
|
baz().await;
|
||||||
|
let guard = x.lock().unwrap();
|
||||||
|
47
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn bad_rw(x: &RwLock<u32>) -> u32 {
|
||||||
|
let guard = x.read().unwrap();
|
||||||
|
baz().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn bad_rw_write(x: &RwLock<u32>) -> u32 {
|
||||||
|
let mut guard = x.write().unwrap();
|
||||||
|
baz().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn good_rw(x: &RwLock<u32>) -> u32 {
|
||||||
|
{
|
||||||
|
let guard = x.read().unwrap();
|
||||||
|
let y = *guard + 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut guard = x.write().unwrap();
|
||||||
|
*guard += 1;
|
||||||
|
}
|
||||||
|
baz().await;
|
||||||
|
let guard = x.read().unwrap();
|
||||||
|
47
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn also_bad(x: &Mutex<u32>) -> u32 {
|
||||||
|
let first = baz().await;
|
||||||
|
|
||||||
|
let guard = x.lock().unwrap();
|
||||||
|
|
||||||
|
let second = baz().await;
|
||||||
|
|
||||||
|
let third = baz().await;
|
||||||
|
|
||||||
|
first + second + third
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn not_good(x: &Mutex<u32>) -> u32 {
|
||||||
|
let first = baz().await;
|
||||||
|
|
||||||
|
let second = {
|
||||||
|
let guard = x.lock().unwrap();
|
||||||
|
baz().await
|
||||||
|
};
|
||||||
|
|
||||||
|
let third = baz().await;
|
||||||
|
|
||||||
|
first + second + third
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::manual_async_fn)]
|
||||||
|
pub fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
|
||||||
|
async move {
|
||||||
|
let guard = x.lock().unwrap();
|
||||||
|
baz().await
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn good(x: &Mutex<u32>) -> u32 {
|
// When adding or modifying a test, please do the same for std::Mutex.
|
||||||
{
|
mod parking_lot_mutex {
|
||||||
let guard = x.lock().unwrap();
|
use super::baz;
|
||||||
let y = *guard + 1;
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
|
||||||
|
pub async fn bad(x: &Mutex<u32>) -> u32 {
|
||||||
|
let guard = x.lock();
|
||||||
|
baz().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn good(x: &Mutex<u32>) -> u32 {
|
||||||
|
{
|
||||||
|
let guard = x.lock();
|
||||||
|
let y = *guard + 1;
|
||||||
|
}
|
||||||
|
baz().await;
|
||||||
|
let guard = x.lock();
|
||||||
|
47
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn bad_rw(x: &RwLock<u32>) -> u32 {
|
||||||
|
let guard = x.read();
|
||||||
|
baz().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn bad_rw_write(x: &RwLock<u32>) -> u32 {
|
||||||
|
let mut guard = x.write();
|
||||||
|
baz().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn good_rw(x: &RwLock<u32>) -> u32 {
|
||||||
|
{
|
||||||
|
let guard = x.read();
|
||||||
|
let y = *guard + 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut guard = x.write();
|
||||||
|
*guard += 1;
|
||||||
|
}
|
||||||
|
baz().await;
|
||||||
|
let guard = x.read();
|
||||||
|
47
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn also_bad(x: &Mutex<u32>) -> u32 {
|
||||||
|
let first = baz().await;
|
||||||
|
|
||||||
|
let guard = x.lock();
|
||||||
|
|
||||||
|
let second = baz().await;
|
||||||
|
|
||||||
|
let third = baz().await;
|
||||||
|
|
||||||
|
first + second + third
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn not_good(x: &Mutex<u32>) -> u32 {
|
||||||
|
let first = baz().await;
|
||||||
|
|
||||||
|
let second = {
|
||||||
|
let guard = x.lock();
|
||||||
|
baz().await
|
||||||
|
};
|
||||||
|
|
||||||
|
let third = baz().await;
|
||||||
|
|
||||||
|
first + second + third
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::manual_async_fn)]
|
||||||
|
pub fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
|
||||||
|
async move {
|
||||||
|
let guard = x.lock();
|
||||||
|
baz().await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
baz().await;
|
|
||||||
let guard = x.lock().unwrap();
|
|
||||||
47
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn baz() -> u32 {
|
async fn baz() -> u32 {
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn also_bad(x: &Mutex<u32>) -> u32 {
|
async fn no_await(x: std::sync::Mutex<u32>) {
|
||||||
let first = baz().await;
|
let mut guard = x.lock().unwrap();
|
||||||
|
*guard += 1;
|
||||||
let guard = x.lock().unwrap();
|
|
||||||
|
|
||||||
let second = baz().await;
|
|
||||||
|
|
||||||
let third = baz().await;
|
|
||||||
|
|
||||||
first + second + third
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn not_good(x: &Mutex<u32>) -> u32 {
|
// FIXME: FP, because the `MutexGuard` is dropped before crossing the await point. This is
|
||||||
let first = baz().await;
|
// something the needs to be fixed in rustc. There's already drop-tracking, but this is currently
|
||||||
|
// disabled, see rust-lang/rust#93751. This case isn't picked up by drop-tracking though. If the
|
||||||
let second = {
|
// `*guard += 1` is removed it is picked up.
|
||||||
let guard = x.lock().unwrap();
|
async fn dropped_before_await(x: std::sync::Mutex<u32>) {
|
||||||
baz().await
|
let mut guard = x.lock().unwrap();
|
||||||
};
|
*guard += 1;
|
||||||
|
drop(guard);
|
||||||
let third = baz().await;
|
baz().await;
|
||||||
|
|
||||||
first + second + third
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::manual_async_fn)]
|
|
||||||
fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
|
|
||||||
async move {
|
|
||||||
let guard = x.lock().unwrap();
|
|
||||||
baz().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let m = Mutex::new(100);
|
let m = std::sync::Mutex::new(100);
|
||||||
good(&m);
|
std_mutex::good(&m);
|
||||||
bad(&m);
|
std_mutex::bad(&m);
|
||||||
also_bad(&m);
|
std_mutex::also_bad(&m);
|
||||||
not_good(&m);
|
std_mutex::not_good(&m);
|
||||||
block_bad(&m);
|
std_mutex::block_bad(&m);
|
||||||
|
|
||||||
|
let m = parking_lot::Mutex::new(100);
|
||||||
|
parking_lot_mutex::good(&m);
|
||||||
|
parking_lot_mutex::bad(&m);
|
||||||
|
parking_lot_mutex::also_bad(&m);
|
||||||
|
parking_lot_mutex::not_good(&m);
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,208 @@
|
|||||||
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
|
error: this `MutexGuard` is held across an `await` point
|
||||||
--> $DIR/await_holding_lock.rs:6:9
|
--> $DIR/await_holding_lock.rs:9:13
|
||||||
|
|
|
|
||||||
LL | let guard = x.lock().unwrap();
|
LL | let guard = x.lock().unwrap();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::await-holding-lock` implied by `-D warnings`
|
= note: `-D clippy::await-holding-lock` implied by `-D warnings`
|
||||||
note: these are all the await points this lock is held through
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
--> $DIR/await_holding_lock.rs:6:5
|
note: these are all the `await` points this lock is held through
|
||||||
|
|
--> $DIR/await_holding_lock.rs:9:9
|
||||||
LL | / let guard = x.lock().unwrap();
|
|
||||||
LL | | baz().await
|
|
||||||
LL | | }
|
|
||||||
| |_^
|
|
||||||
|
|
||||||
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
|
|
||||||
--> $DIR/await_holding_lock.rs:27:9
|
|
||||||
|
|
|
||||||
LL | let guard = x.lock().unwrap();
|
|
||||||
| ^^^^^
|
|
||||||
|
|
|
||||||
note: these are all the await points this lock is held through
|
|
||||||
--> $DIR/await_holding_lock.rs:27:5
|
|
||||||
|
|
|
||||||
LL | / let guard = x.lock().unwrap();
|
|
||||||
LL | |
|
|
||||||
LL | | let second = baz().await;
|
|
||||||
LL | |
|
|
||||||
... |
|
|
||||||
LL | | first + second + third
|
|
||||||
LL | | }
|
|
||||||
| |_^
|
|
||||||
|
|
||||||
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
|
|
||||||
--> $DIR/await_holding_lock.rs:40:13
|
|
||||||
|
|
|
||||||
LL | let guard = x.lock().unwrap();
|
|
||||||
| ^^^^^
|
|
||||||
|
|
|
||||||
note: these are all the await points this lock is held through
|
|
||||||
--> $DIR/await_holding_lock.rs:40:9
|
|
||||||
|
|
|
||||||
LL | / let guard = x.lock().unwrap();
|
|
||||||
LL | | baz().await
|
|
||||||
LL | | };
|
|
||||||
| |_____^
|
|
||||||
|
|
||||||
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
|
|
||||||
--> $DIR/await_holding_lock.rs:52:13
|
|
||||||
|
|
|
||||||
LL | let guard = x.lock().unwrap();
|
|
||||||
| ^^^^^
|
|
||||||
|
|
|
||||||
note: these are all the await points this lock is held through
|
|
||||||
--> $DIR/await_holding_lock.rs:52:9
|
|
||||||
|
|
|
|
||||||
LL | / let guard = x.lock().unwrap();
|
LL | / let guard = x.lock().unwrap();
|
||||||
LL | | baz().await
|
LL | | baz().await
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:24:13
|
||||||
|
|
|
||||||
|
LL | let guard = x.read().unwrap();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:24:9
|
||||||
|
|
|
||||||
|
LL | / let guard = x.read().unwrap();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:29:13
|
||||||
|
|
|
||||||
|
LL | let mut guard = x.write().unwrap();
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:29:9
|
||||||
|
|
|
||||||
|
LL | / let mut guard = x.write().unwrap();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:50:13
|
||||||
|
|
|
||||||
|
LL | let guard = x.lock().unwrap();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:50:9
|
||||||
|
|
|
||||||
|
LL | / let guard = x.lock().unwrap();
|
||||||
|
LL | |
|
||||||
|
LL | | let second = baz().await;
|
||||||
|
LL | |
|
||||||
|
... |
|
||||||
|
LL | | first + second + third
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:63:17
|
||||||
|
|
|
||||||
|
LL | let guard = x.lock().unwrap();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:63:13
|
||||||
|
|
|
||||||
|
LL | / let guard = x.lock().unwrap();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | };
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:75:17
|
||||||
|
|
|
||||||
|
LL | let guard = x.lock().unwrap();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:75:13
|
||||||
|
|
|
||||||
|
LL | / let guard = x.lock().unwrap();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:87:13
|
||||||
|
|
|
||||||
|
LL | let guard = x.lock();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:87:9
|
||||||
|
|
|
||||||
|
LL | / let guard = x.lock();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:102:13
|
||||||
|
|
|
||||||
|
LL | let guard = x.read();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:102:9
|
||||||
|
|
|
||||||
|
LL | / let guard = x.read();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:107:13
|
||||||
|
|
|
||||||
|
LL | let mut guard = x.write();
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:107:9
|
||||||
|
|
|
||||||
|
LL | / let mut guard = x.write();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:128:13
|
||||||
|
|
|
||||||
|
LL | let guard = x.lock();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:128:9
|
||||||
|
|
|
||||||
|
LL | / let guard = x.lock();
|
||||||
|
LL | |
|
||||||
|
LL | | let second = baz().await;
|
||||||
|
LL | |
|
||||||
|
... |
|
||||||
|
LL | | first + second + third
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:141:17
|
||||||
|
|
|
||||||
|
LL | let guard = x.lock();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:141:13
|
||||||
|
|
|
||||||
|
LL | / let guard = x.lock();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | };
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:153:17
|
||||||
|
|
|
||||||
|
LL | let guard = x.lock();
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:153:13
|
||||||
|
|
|
||||||
|
LL | / let guard = x.lock();
|
||||||
|
LL | | baz().await
|
||||||
|
LL | | }
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
error: this `MutexGuard` is held across an `await` point
|
||||||
|
--> $DIR/await_holding_lock.rs:173:9
|
||||||
|
|
|
||||||
|
LL | let mut guard = x.lock().unwrap();
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
|
||||||
|
note: these are all the `await` points this lock is held through
|
||||||
|
--> $DIR/await_holding_lock.rs:173:5
|
||||||
|
|
|
||||||
|
LL | / let mut guard = x.lock().unwrap();
|
||||||
|
LL | | *guard += 1;
|
||||||
|
LL | | drop(guard);
|
||||||
|
LL | | baz().await;
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to 13 previous errors
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
|
error: this `RefCell` reference is held across an `await` point
|
||||||
--> $DIR/await_holding_refcell_ref.rs:6:9
|
--> $DIR/await_holding_refcell_ref.rs:6:9
|
||||||
|
|
|
|
||||||
LL | let b = x.borrow();
|
LL | let b = x.borrow();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
|
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
|
||||||
note: these are all the await points this ref is held through
|
= help: ensure the reference is dropped before calling `await`
|
||||||
|
note: these are all the `await` points this reference is held through
|
||||||
--> $DIR/await_holding_refcell_ref.rs:6:5
|
--> $DIR/await_holding_refcell_ref.rs:6:5
|
||||||
|
|
|
|
||||||
LL | / let b = x.borrow();
|
LL | / let b = x.borrow();
|
||||||
@ -13,13 +14,14 @@ LL | | baz().await
|
|||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
|
error: this `RefCell` reference is held across an `await` point
|
||||||
--> $DIR/await_holding_refcell_ref.rs:11:9
|
--> $DIR/await_holding_refcell_ref.rs:11:9
|
||||||
|
|
|
|
||||||
LL | let b = x.borrow_mut();
|
LL | let b = x.borrow_mut();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: these are all the await points this ref is held through
|
= help: ensure the reference is dropped before calling `await`
|
||||||
|
note: these are all the `await` points this reference is held through
|
||||||
--> $DIR/await_holding_refcell_ref.rs:11:5
|
--> $DIR/await_holding_refcell_ref.rs:11:5
|
||||||
|
|
|
|
||||||
LL | / let b = x.borrow_mut();
|
LL | / let b = x.borrow_mut();
|
||||||
@ -27,13 +29,14 @@ LL | | baz().await
|
|||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
|
error: this `RefCell` reference is held across an `await` point
|
||||||
--> $DIR/await_holding_refcell_ref.rs:32:9
|
--> $DIR/await_holding_refcell_ref.rs:32:9
|
||||||
|
|
|
|
||||||
LL | let b = x.borrow_mut();
|
LL | let b = x.borrow_mut();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: these are all the await points this ref is held through
|
= help: ensure the reference is dropped before calling `await`
|
||||||
|
note: these are all the `await` points this reference is held through
|
||||||
--> $DIR/await_holding_refcell_ref.rs:32:5
|
--> $DIR/await_holding_refcell_ref.rs:32:5
|
||||||
|
|
|
|
||||||
LL | / let b = x.borrow_mut();
|
LL | / let b = x.borrow_mut();
|
||||||
@ -45,13 +48,14 @@ LL | | first + second + third
|
|||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
|
error: this `RefCell` reference is held across an `await` point
|
||||||
--> $DIR/await_holding_refcell_ref.rs:44:9
|
--> $DIR/await_holding_refcell_ref.rs:44:9
|
||||||
|
|
|
|
||||||
LL | let b = x.borrow_mut();
|
LL | let b = x.borrow_mut();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: these are all the await points this ref is held through
|
= help: ensure the reference is dropped before calling `await`
|
||||||
|
note: these are all the `await` points this reference is held through
|
||||||
--> $DIR/await_holding_refcell_ref.rs:44:5
|
--> $DIR/await_holding_refcell_ref.rs:44:5
|
||||||
|
|
|
|
||||||
LL | / let b = x.borrow_mut();
|
LL | / let b = x.borrow_mut();
|
||||||
@ -63,13 +67,14 @@ LL | | first + second + third
|
|||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
|
error: this `RefCell` reference is held across an `await` point
|
||||||
--> $DIR/await_holding_refcell_ref.rs:59:13
|
--> $DIR/await_holding_refcell_ref.rs:59:13
|
||||||
|
|
|
|
||||||
LL | let b = x.borrow_mut();
|
LL | let b = x.borrow_mut();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: these are all the await points this ref is held through
|
= help: ensure the reference is dropped before calling `await`
|
||||||
|
note: these are all the `await` points this reference is held through
|
||||||
--> $DIR/await_holding_refcell_ref.rs:59:9
|
--> $DIR/await_holding_refcell_ref.rs:59:9
|
||||||
|
|
|
|
||||||
LL | / let b = x.borrow_mut();
|
LL | / let b = x.borrow_mut();
|
||||||
@ -77,13 +82,14 @@ LL | | baz().await
|
|||||||
LL | | };
|
LL | | };
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
||||||
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
|
error: this `RefCell` reference is held across an `await` point
|
||||||
--> $DIR/await_holding_refcell_ref.rs:71:13
|
--> $DIR/await_holding_refcell_ref.rs:71:13
|
||||||
|
|
|
|
||||||
LL | let b = x.borrow_mut();
|
LL | let b = x.borrow_mut();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: these are all the await points this ref is held through
|
= help: ensure the reference is dropped before calling `await`
|
||||||
|
note: these are all the `await` points this reference is held through
|
||||||
--> $DIR/await_holding_refcell_ref.rs:71:9
|
--> $DIR/await_holding_refcell_ref.rs:71:9
|
||||||
|
|
|
|
||||||
LL | / let b = x.borrow_mut();
|
LL | / let b = x.borrow_mut();
|
||||||
|
Loading…
Reference in New Issue
Block a user