diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e7bb56cd547..4bdbc91db939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6220,7 +6220,6 @@ Released 2018-09-13 [`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold [`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit [`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold -[`unconditional-send-futures`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unconditional-send-futures [`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size [`unreadable-literal-lint-fractions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unreadable-literal-lint-fractions [`upper-case-acronyms-aggressive`]: https://doc.rust-lang.org/clippy/lint_configuration.html#upper-case-acronyms-aggressive diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index bfbf5ee16fba..43b551ae2161 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -883,33 +883,6 @@ The maximum complexity a type can have * [`type_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) -## `unconditional-send-futures` -Whether `future_not_send` should require futures to implement `Send` unconditionally. -Enabling this makes the lint more strict and requires generic functions have `Send` bounds -on type parameters. - -### Example -``` -async fn foo(r: R) { - std::future::ready(()).await; - r; -} -``` -The returned future by this async function may or may not be `Send` - it depends on the particular type -that `R` is instantiated with at call site, so it is **not** unconditionally `Send`. -Adding an `R: Send` bound to the function definition satisfies it, but is more restrictive for callers. - -For library crate authors that want to make sure that their async functions are compatible -with both single-threaded and multi-threaded executors, the default behavior of allowing `!Send` futures -if type parameters are `!Send` makes sense. - -**Default Value:** `false` - ---- -**Affected lints:** -* [`future_not_send`](https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send) - - ## `unnecessary-box-size` The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 049648a3617d..4757c0b1339a 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -645,26 +645,6 @@ define_Conf! { /// The maximum complexity a type can have #[lints(type_complexity)] type_complexity_threshold: u64 = 250, - /// Whether `future_not_send` should require futures to implement `Send` unconditionally. - /// Enabling this makes the lint more strict and requires generic functions have `Send` bounds - /// on type parameters. - /// - /// ### Example - /// ``` - /// async fn foo(r: R) { - /// std::future::ready(()).await; - /// r; - /// } - /// ``` - /// The returned future by this async function may or may not be `Send` - it depends on the particular type - /// that `R` is instantiated with at call site, so it is **not** unconditionally `Send`. - /// Adding an `R: Send` bound to the function definition satisfies it, but is more restrictive for callers. - /// - /// For library crate authors that want to make sure that their async functions are compatible - /// with both single-threaded and multi-threaded executors, the default behavior of allowing `!Send` futures - /// if type parameters are `!Send` makes sense. - #[lints(future_not_send)] - unconditional_send_futures: bool = false, /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint #[lints(unnecessary_box_returns)] unnecessary_box_size: u64 = 128, diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index ab506c0bb888..f408aedefe6a 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -1,6 +1,5 @@ use std::ops::ControlFlow; -use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::return_ty; use rustc_hir::intravisit::FnKind; @@ -11,7 +10,7 @@ use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{ self, AliasTy, Binder, ClauseKind, PredicateKind, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_session::impl_lint_pass; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -20,23 +19,17 @@ use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { /// ### What it does /// This lint requires Future implementations returned from - /// functions and methods to implement the `Send` marker trait. + /// functions and methods to implement the `Send` marker trait, + /// ignoring type parameters. + /// + /// If a function is generic and its Future conditionally implements `Send` + /// based on a generic parameter then it is considered `Send` and no warning is emitted. /// - /// The default configuration of this lint only emits warnings for futures - /// that are unconditionally `!Send`, ignoring generic parameters. /// This can be used by library authors (public and internal) to ensure - /// their functions are compatible with multi-threaded runtimes that require `Send` futures, + /// their functions are compatible with both multi-threaded runtimes that require `Send` futures, /// as well as single-threaded runtimes where callers may choose `!Send` types /// for generic parameters. /// - /// A more strict version can be enabled through the `unconditional_send_futures` configuration, - /// which requires that futures must always unconditionally implement `Send`, - /// even if whether the future is `Send` or not is determined at call site for generic functions. - /// This can be useful for binary crates that always use a multi-threaded runtime to find `!Send` futures - /// as early as possible and keep errors contained in the most relevant place, - /// instead of propagating `!Send` and be left with a hard-to-debug error in an - /// unrelated place (e.g. the final future passed to `tokio::spawn()`). - /// /// ### Why is this bad? /// A Future implementation captures some state that it /// needs to eventually produce its final value. When targeting a multithreaded @@ -66,19 +59,7 @@ declare_clippy_lint! { "public Futures must be Send" } -pub struct FutureNotSend { - unconditionally_not_send: bool, -} - -impl FutureNotSend { - pub fn new(conf: &'static Conf) -> Self { - Self { - unconditionally_not_send: conf.unconditional_send_futures, - } - } -} - -impl_lint_pass!(FutureNotSend => [FUTURE_NOT_SEND]); +declare_lint_pass!(FutureNotSend => [FUTURE_NOT_SEND]); impl<'tcx> LateLintPass<'tcx> for FutureNotSend { fn check_fn( @@ -111,43 +92,39 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); let send_errors = ocx.select_all_or_error(); - let is_send = if self.unconditionally_not_send { - send_errors.is_empty() - } else { - // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top - // level". - // For example, allow errors that `T: Send` can't be proven, but reject `Rc: Send` errors, - // which is always unconditionally `!Send` for any possible type `T`. - // - // We also allow associated type projections if the self type is either itself a projection or a - // type parameter. - // This is to prevent emitting warnings for e.g. holding a `::Output` across await - // points, where `Fut` is a type parameter. + // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top + // level". + // For example, allow errors that `T: Send` can't be proven, but reject `Rc: Send` errors, + // which is always unconditionally `!Send` for any possible type `T`. + // + // We also allow associated type projections if the self type is either itself a projection or a + // type parameter. + // This is to prevent emitting warnings for e.g. holding a `::Output` across await + // points, where `Fut` is a type parameter. - struct TypeWalker; - impl<'tcx> TypeVisitor> for TypeWalker { - type Result = ControlFlow; - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - match ty.kind() { - ty::Param(_) => ControlFlow::Break(true), - ty::Alias(ty::AliasTyKind::Projection, ty) => ty.visit_with(self), - _ => ControlFlow::Break(false), - } + struct TypeWalker; + impl<'tcx> TypeVisitor> for TypeWalker { + type Result = ControlFlow; + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + match ty.kind() { + ty::Param(_) => ControlFlow::Break(true), + ty::Alias(ty::AliasTyKind::Projection, ty) => ty.visit_with(self), + _ => ControlFlow::Break(false), } } + } - send_errors.iter().all(|err| { - err.obligation - .predicate - .as_trait_clause() - .map(Binder::skip_binder) - .is_some_and(|pred| { - pred.def_id() == send_trait - && pred.self_ty().has_param() - && TypeWalker.visit_ty(pred.self_ty()) == ControlFlow::Break(true) - }) - }) - }; + let is_send = send_errors.iter().all(|err| { + err.obligation + .predicate + .as_trait_clause() + .map(Binder::skip_binder) + .is_some_and(|pred| { + pred.def_id() == send_trait + && pred.self_ty().has_param() + && TypeWalker.visit_ty(pred.self_ty()) == ControlFlow::Break(true) + }) + }); if !is_send { span_lint_and_then( diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e67f7ac3b9e7..a0ff8316d5cd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -777,7 +777,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress)); store.register_late_pass(|_| Box::>::default()); store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); - store.register_late_pass(move |_| Box::new(future_not_send::FutureNotSend::new(conf))); + store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(conf))); store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|_| Box::new(if_not_else::IfNotElse)); diff --git a/tests/ui-toml/future_not_send/default/clippy.toml b/tests/ui-toml/future_not_send/default/clippy.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/ui-toml/future_not_send/test.uncond.stderr b/tests/ui-toml/future_not_send/test.uncond.stderr deleted file mode 100644 index 5ba873b2cc46..000000000000 --- a/tests/ui-toml/future_not_send/test.uncond.stderr +++ /dev/null @@ -1,191 +0,0 @@ -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:11:1 - | -LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` - | -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:14:20 - | -LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { - | -- has type `std::rc::Rc<[u8]>` which is not `Send` -... -LL | async { true }.await - | ^^^^^ await occurs here, with `rc` maybe used later - = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` -note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui-toml/future_not_send/test.rs:11:39 - | -LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` - = note: `std::cell::Cell` doesn't implement `std::marker::Sync` - = note: `-D clippy::future-not-send` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:17:1 - | -LL | pub async fn public_future(rc: Rc<[u8]>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` - | -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:20:20 - | -LL | pub async fn public_future(rc: Rc<[u8]>) { - | -- has type `std::rc::Rc<[u8]>` which is not `Send` -... -LL | async { true }.await; - | ^^^^^ await occurs here, with `rc` maybe used later - = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:27:1 - | -LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send` - | -note: captured value is not `Send` - --> tests/ui-toml/future_not_send/test.rs:27:26 - | -LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` - = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` -note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui-toml/future_not_send/test.rs:27:40 - | -LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` - = note: `std::cell::Cell` doesn't implement `std::marker::Sync` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:33:1 - | -LL | pub async fn public_future2(rc: Rc<[u8]>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send` - | -note: captured value is not `Send` - --> tests/ui-toml/future_not_send/test.rs:33:29 - | -LL | pub async fn public_future2(rc: Rc<[u8]>) {} - | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` - = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:46:5 - | -LL | async fn private_future(&self) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` - | -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:49:24 - | -LL | async fn private_future(&self) -> usize { - | ----- has type `&Dummy` which is not `Send` -... -LL | async { true }.await; - | ^^^^^ await occurs here, with `&self` maybe used later - = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:53:5 - | -LL | pub async fn public_future(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` - | -note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui-toml/future_not_send/test.rs:53:32 - | -LL | pub async fn public_future(&self) { - | ^^^^^ has type `&Dummy` which is not `Send`, because `Dummy` is not `Sync` - = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:65:1 - | -LL | / async fn generic_future(t: T) -> T -LL | | -LL | | -LL | | where -LL | | T: Send, - | |____________^ future returned by `generic_future` is not `Send` - | -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:72:20 - | -LL | let rt = &t; - | -- has type `&T` which is not `Send` -LL | async { true }.await; - | ^^^^^ await occurs here, with `rt` maybe used later - = note: `T` doesn't implement `std::marker::Sync` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:77:1 - | -LL | async fn maybe_send_generic_future(t: T) -> T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `maybe_send_generic_future` is not `Send` - | -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:79:20 - | -LL | async fn maybe_send_generic_future(t: T) -> T { - | - has type `T` which is not `Send` -LL | -LL | async { true }.await; - | ^^^^^ await occurs here, with `t` maybe used later - = note: `T` doesn't implement `std::marker::Send` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:83:1 - | -LL | async fn maybe_send_generic_future2 Fut, Fut: Future>(f: F) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `maybe_send_generic_future2` is not `Send` - | -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:85:20 - | -LL | async fn maybe_send_generic_future2 Fut, Fut: Future>(f: F) { - | - has type `F` which is not `Send` -LL | -LL | async { true }.await; - | ^^^^^ await occurs here, with `f` maybe used later - = note: `F` doesn't implement `std::marker::Send` -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:87:20 - | -LL | let res = f(); - | --- has type `Fut` which is not `Send` -LL | async { true }.await; - | ^^^^^ await occurs here, with `res` maybe used later - = note: `Fut` doesn't implement `std::marker::Send` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:90:1 - | -LL | async fn generic_future_always_unsend(_: Rc) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send` - | -note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:93:20 - | -LL | async fn generic_future_always_unsend(_: Rc) { - | - has type `std::rc::Rc` which is not `Send` -... -LL | async { true }.await; - | ^^^^^ await occurs here, with `_` maybe used later - = note: `std::rc::Rc` doesn't implement `std::marker::Send` - -error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:103:1 - | -LL | async fn unclear_future(t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `unclear_future` is not `Send` - | -note: captured value is not `Send` - --> tests/ui-toml/future_not_send/test.rs:103:28 - | -LL | async fn unclear_future(t: T) {} - | ^ has type `T` which is not `Send` - = note: `T` doesn't implement `std::marker::Send` - -error: aborting due to 11 previous errors - diff --git a/tests/ui-toml/future_not_send/unconditional_send_futures/clippy.toml b/tests/ui-toml/future_not_send/unconditional_send_futures/clippy.toml deleted file mode 100644 index 62736818ed5d..000000000000 --- a/tests/ui-toml/future_not_send/unconditional_send_futures/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -unconditional-send-futures = true diff --git a/tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.rs b/tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.rs deleted file mode 100644 index 6e126aff7512..000000000000 --- a/tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@compile-flags: --cap-lints=warn -// https://github.com/rust-lang/rust-clippy/issues/10645 - -#![warn(clippy::future_not_send)] -pub async fn bar<'a, T: 'a>(_: T) {} - -fn main() {} diff --git a/tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.stderr b/tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.stderr deleted file mode 100644 index 6cc5a79f1f6e..000000000000 --- a/tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.rs:5:1 - | -LL | pub async fn bar<'a, T: 'a>(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `bar` is not `Send` - | -note: captured value is not `Send` - --> tests/ui-toml/future_not_send/unconditional_send_futures/ice-10645.rs:5:29 - | -LL | pub async fn bar<'a, T: 'a>(_: T) {} - | ^ has type `T` which is not `Send` - = note: `T` doesn't implement `std::marker::Send` - = note: `-D clippy::future-not-send` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` - -warning: 1 warning emitted - diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 17f2ef389aac..5cf9c0fb2710 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -70,7 +70,6 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect too-many-lines-threshold trivial-copy-size-limit type-complexity-threshold - unconditional-send-futures unnecessary-box-size unreadable-literal-lint-fractions upper-case-acronyms-aggressive @@ -155,7 +154,6 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect too-many-lines-threshold trivial-copy-size-limit type-complexity-threshold - unconditional-send-futures unnecessary-box-size unreadable-literal-lint-fractions upper-case-acronyms-aggressive @@ -240,7 +238,6 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni too-many-lines-threshold trivial-copy-size-limit type-complexity-threshold - unconditional-send-futures unnecessary-box-size unreadable-literal-lint-fractions upper-case-acronyms-aggressive diff --git a/tests/ui-toml/future_not_send/test.rs b/tests/ui/future_not_send.rs similarity index 68% rename from tests/ui-toml/future_not_send/test.rs rename to tests/ui/future_not_send.rs index 700d4ba14af5..626ee6de9e4f 100644 --- a/tests/ui-toml/future_not_send/test.rs +++ b/tests/ui/future_not_send.rs @@ -1,6 +1,3 @@ -//@revisions: default uncond -//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/future_not_send/default -//@[uncond] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/future_not_send/unconditional_send_futures #![warn(clippy::future_not_send)] use std::cell::Cell; @@ -9,14 +6,12 @@ use std::rc::Rc; use std::sync::Arc; async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { - //~[uncond]^ future_not_send - //~[default]| future_not_send + //~^ ERROR: future cannot be sent between threads safely async { true }.await } pub async fn public_future(rc: Rc<[u8]>) { - //~[uncond]^ future_not_send - //~[default]| future_not_send + //~^ ERROR: future cannot be sent between threads safely async { true }.await; } @@ -25,14 +20,12 @@ pub async fn public_send(arc: Arc<[u8]>) -> bool { } async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - //~[uncond]^ future_not_send - //~[default]| future_not_send + //~^ ERROR: future cannot be sent between threads safely true } pub async fn public_future2(rc: Rc<[u8]>) {} -//~[uncond]^ future_not_send -//~[default]| future_not_send +//~^ ERROR: future cannot be sent between threads safely pub async fn public_send2(arc: Arc<[u8]>) -> bool { false @@ -44,15 +37,13 @@ struct Dummy { impl Dummy { async fn private_future(&self) -> usize { - //~[uncond]^ future_not_send - //~[default]| future_not_send + //~^ ERROR: future cannot be sent between threads safely async { true }.await; self.rc.len() } pub async fn public_future(&self) { - //~[uncond]^ future_not_send - //~[default]| future_not_send + //~^ ERROR: future cannot be sent between threads safely self.private_future().await; } @@ -63,8 +54,7 @@ impl Dummy { } async fn generic_future(t: T) -> T -//~[uncond]^ future_not_send -//~[default]| future_not_send +//~^ ERROR: future cannot be sent between threads safely where T: Send, { @@ -75,21 +65,18 @@ where } async fn maybe_send_generic_future(t: T) -> T { - //~[uncond]^ future_not_send async { true }.await; t } async fn maybe_send_generic_future2 Fut, Fut: Future>(f: F) { - //~[uncond]^ future_not_send async { true }.await; let res = f(); async { true }.await; } async fn generic_future_always_unsend(_: Rc) { - //~[uncond]^ future_not_send - //~[default]| future_not_send + //~^ ERROR: future cannot be sent between threads safely async { true }.await; } @@ -101,7 +88,6 @@ where } async fn unclear_future(t: T) {} -//~[uncond]^ future_not_send fn main() { let rc = Rc::new([1, 2, 3]); diff --git a/tests/ui-toml/future_not_send/test.default.stderr b/tests/ui/future_not_send.stderr similarity index 85% rename from tests/ui-toml/future_not_send/test.default.stderr rename to tests/ui/future_not_send.stderr index 9cd88f7eb9b5..3807c7470136 100644 --- a/tests/ui-toml/future_not_send/test.default.stderr +++ b/tests/ui/future_not_send.stderr @@ -1,20 +1,20 @@ error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:11:1 + --> tests/ui/future_not_send.rs:8:1 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:14:20 + --> tests/ui/future_not_send.rs:10:20 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` -... +LL | LL | async { true }.await | ^^^^^ await occurs here, with `rc` maybe used later = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui-toml/future_not_send/test.rs:11:39 + --> tests/ui/future_not_send.rs:8:39 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` @@ -23,94 +23,93 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:17:1 + --> tests/ui/future_not_send.rs:13:1 | LL | pub async fn public_future(rc: Rc<[u8]>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:20:20 + --> tests/ui/future_not_send.rs:15:20 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` -... +LL | LL | async { true }.await; | ^^^^^ await occurs here, with `rc` maybe used later = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:27:1 + --> tests/ui/future_not_send.rs:22:1 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send` | note: captured value is not `Send` - --> tests/ui-toml/future_not_send/test.rs:27:26 + --> tests/ui/future_not_send.rs:22:26 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui-toml/future_not_send/test.rs:27:40 + --> tests/ui/future_not_send.rs:22:40 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:33:1 + --> tests/ui/future_not_send.rs:27:1 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send` | note: captured value is not `Send` - --> tests/ui-toml/future_not_send/test.rs:33:29 + --> tests/ui/future_not_send.rs:27:29 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:46:5 + --> tests/ui/future_not_send.rs:39:5 | LL | async fn private_future(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:49:24 + --> tests/ui/future_not_send.rs:41:24 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` -... +LL | LL | async { true }.await; | ^^^^^ await occurs here, with `&self` maybe used later = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:53:5 + --> tests/ui/future_not_send.rs:45:5 | LL | pub async fn public_future(&self) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` | note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui-toml/future_not_send/test.rs:53:32 + --> tests/ui/future_not_send.rs:45:32 | LL | pub async fn public_future(&self) { | ^^^^^ has type `&Dummy` which is not `Send`, because `Dummy` is not `Sync` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:65:1 + --> tests/ui/future_not_send.rs:56:1 | LL | / async fn generic_future(t: T) -> T LL | | -LL | | LL | | where LL | | T: Send, | |____________^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:72:20 + --> tests/ui/future_not_send.rs:62:20 | LL | let rt = &t; | -- has type `&T` which is not `Send` @@ -119,17 +118,17 @@ LL | async { true }.await; = note: `T` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui-toml/future_not_send/test.rs:90:1 + --> tests/ui/future_not_send.rs:78:1 | LL | async fn generic_future_always_unsend(_: Rc) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui-toml/future_not_send/test.rs:93:20 + --> tests/ui/future_not_send.rs:80:20 | LL | async fn generic_future_always_unsend(_: Rc) { | - has type `std::rc::Rc` which is not `Send` -... +LL | LL | async { true }.await; | ^^^^^ await occurs here, with `_` maybe used later = note: `std::rc::Rc` doesn't implement `std::marker::Send`