From 207a248dde232b28f2880d4b8c456b1b72b06f2b Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Mon, 5 Jan 2026 16:47:51 +0100 Subject: [PATCH 01/10] Improved large_futures to be applicable to any expression of type Future --- clippy_lints/src/large_futures.rs | 132 ++++++++++--- tests/ui/large_futures.rs | 8 +- tests/ui/large_futures.stderr | 297 +++++++++++++++++++++++++----- 3 files changed, 361 insertions(+), 76 deletions(-) diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index b11e89a9b566..e56ede94a61e 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -1,12 +1,17 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_abi::Size; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem, MatchSource}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{FnKind, Visitor, walk_body, walk_expr}; +use rustc_hir::{Body, Expr, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -14,7 +19,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Coroutine`, - /// large size of a `Future` may cause stack overflows. + /// large size of a `Future` may cause stack overflows or be inefficient. /// /// ### Example /// ```no_run @@ -25,7 +30,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// `Box::pin` the big future instead. + /// `Box::pin` the big future or the captured elements inside the future instead. /// /// ```no_run /// async fn large_future(_x: [u8; 16 * 1024]) {} @@ -54,29 +59,106 @@ impl LargeFuture { impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); -impl<'tcx> LateLintPass<'tcx> for LargeFuture { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind - && let ExprKind::Call(func, [arg]) = scrutinee.kind - && let ExprKind::Path(qpath) = func.kind - && cx.tcx.qpath_is_lang_item(qpath, LangItem::IntoFutureIntoFuture) +struct AsyncFnVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + future_size_threshold: u64, + /// Depth of the visitor with value `0` denoting the top-level expression. + depth: usize, + /// Whether a clippy suggestion was emitted for deeper levels of expressions. + emitted: bool, +} + +impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + // For each expression, try to find the 'deepest' occurance of a too large a future. + // Chances are that subsequent less deep expression contain that too large a future, + // and hence it is redudant to also emit a suggestion for these expressions. + // Expressions on the same depth level can however emit a suggestion too. + + self.depth += 1; + let old_emitted = self.emitted; + self.emitted = false; // Reset emitted for deeper level, but recover it later. + walk_expr(self, expr); + self.depth -= 1; + + if !self.emitted && !expr.span.from_expansion() - && let ty = cx.typeck_results().expr_ty(arg) - && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, ty, future_trait_def_id, &[]) - && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) - && let size = layout.layout.size() - && size >= Size::from_bytes(self.future_size_threshold) + && let Some(ty) = self.cx.typeck_results().expr_ty_opt(expr) + && let Some(size) = type_is_large_future(self.cx, ty, self.future_size_threshold) { - span_lint_and_sugg( - cx, - LARGE_FUTURES, - arg.span, - format!("large future with a size of {} bytes", size.bytes()), - "consider `Box::pin` on it", - format!("Box::pin({})", snippet(cx, arg.span, "..")), - Applicability::Unspecified, - ); + if self.depth == 0 { + // Special lint for top level fn bodies. + span_lint_hir_and_then( + self.cx, + LARGE_FUTURES, + expr.hir_id, + expr.span, + format!("definition for a large future with a size of {} bytes", size.bytes()), + |db| { + db.span_help(expr.span, "consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible"); + }, + ); + } else { + // Expressions within a fn body. + span_lint_hir_and_then( + self.cx, + LARGE_FUTURES, + expr.hir_id, + expr.span, + format!("usage of large future with a size of {} bytes", size.bytes()), + |db| { + db.span_suggestion( + expr.span, + "consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible", + format!("Box::pin({})", snippet(self.cx, expr.span, "..")), + Applicability::Unspecified, + ); + }, + ); + } + + self.emitted = true; } + + self.emitted |= old_emitted; + } + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.cx.tcx + } +} + +fn type_is_large_future<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, future_size_threshold: u64) -> Option { + if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() + && implements_trait(cx, ty, future_trait_def_id, &[]) + && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) + && let size = layout.layout.size() + && size >= Size::from_bytes(future_size_threshold) + { + Some(size) + } else { + None + } +} + +impl<'tcx> LateLintPass<'tcx> for LargeFuture { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'_>, + body: &'tcx Body<'_>, + _: Span, + _: LocalDefId, + ) { + let mut visitor = AsyncFnVisitor { + cx, + depth: 0, + future_size_threshold: self.future_size_threshold, + emitted: false, + }; + walk_body(&mut visitor, body); } } diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 2b5860583f5e..f30069335b61 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -7,6 +7,7 @@ #![warn(clippy::large_futures)] async fn big_fut(_arg: [u8; 1024 * 16]) {} +//~^ large_futures async fn wait() { let f = async { @@ -45,16 +46,17 @@ pub fn foo() -> impl std::future::Future { async {}.await; dbg!(x); } + //~^ large_futures } pub async fn lines() { async { - //~^ large_futures - let x = [0i32; 1024 * 16]; async {}.await; + println!("{:?}", x); } + //~^ large_futures .await; } @@ -62,7 +64,6 @@ pub async fn macro_expn() { macro_rules! macro_ { () => { async { - //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; println!("macro: {:?}", x); @@ -71,5 +72,6 @@ pub async fn macro_expn() { } macro_!().await } +//~^ large_futures fn main() {} diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 4280c9e2af28..770d279aedee 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -1,89 +1,290 @@ -error: large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:13:9 +error: definition for a large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:9:41 | -LL | big_fut([0u8; 1024 * 16]).await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` +LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} + | ^^ + | +help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible + --> tests/ui/large_futures.rs:9:41 | +LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} + | ^^ = note: `-D clippy::large-futures` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` -error: large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:16:5 +error: usage of large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:14:9 + | +LL | big_fut([0u8; 1024 * 16]).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - big_fut([0u8; 1024 * 16]).await; +LL + Box::pin(big_fut([0u8; 1024 * 16])).await; + | + +error: usage of large future with a size of 16386 bytes + --> tests/ui/large_futures.rs:17:5 | LL | f.await - | ^ help: consider `Box::pin` on it: `Box::pin(f)` + | ^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - f.await +LL + Box::pin(f).await + | -error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:21:9 +error: usage of large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:14:9 + | +LL | big_fut([0u8; 1024 * 16]).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - big_fut([0u8; 1024 * 16]).await; +LL + Box::pin(big_fut([0u8; 1024 * 16])).await; + | + +error: usage of large future with a size of 16386 bytes + --> tests/ui/large_futures.rs:17:5 + | +LL | f.await + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - f.await +LL + Box::pin(f).await + | + +error: usage of large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:14:9 + | +LL | big_fut([0u8; 1024 * 16]).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - big_fut([0u8; 1024 * 16]).await; +LL + Box::pin(big_fut([0u8; 1024 * 16])).await; + | + +error: usage of large future with a size of 16387 bytes + --> tests/ui/large_futures.rs:22:9 + | +LL | wait().await; + | ^^^^^^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - wait().await; +LL + Box::pin(wait()).await; + | + +error: usage of large future with a size of 16387 bytes + --> tests/ui/large_futures.rs:28:13 + | +LL | wait().await; + | ^^^^^^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - wait().await; +LL + Box::pin(wait()).await; + | + +error: usage of large future with a size of 16387 bytes + --> tests/ui/large_futures.rs:22:9 | LL | wait().await; - | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - wait().await; +LL + Box::pin(wait()).await; + | -error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:27:13 +error: usage of large future with a size of 16387 bytes + --> tests/ui/large_futures.rs:28:13 | LL | wait().await; - | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - wait().await; +LL + Box::pin(wait()).await; + | + +error: usage of large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:35:15 + | +LL | let fut = big_fut([0u8; 1024 * 16]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - let fut = big_fut([0u8; 1024 * 16]); +LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); + | + +error: usage of large future with a size of 65540 bytes + --> tests/ui/large_futures.rs:36:5 + | +LL | foo().await; + | ^^^^^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - foo().await; +LL + Box::pin(foo()).await; + | + +error: usage of large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:39:15 + | +LL | calls_fut(fut).await; + | ^^^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - calls_fut(fut).await; +LL + calls_fut(Box::pin(fut)).await; + | -error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:35:5 +error: usage of large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:35:15 + | +LL | let fut = big_fut([0u8; 1024 * 16]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - let fut = big_fut([0u8; 1024 * 16]); +LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); + | + +error: usage of large future with a size of 65540 bytes + --> tests/ui/large_futures.rs:36:5 | LL | foo().await; - | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - foo().await; +LL + Box::pin(foo()).await; + | -error: large future with a size of 49159 bytes - --> tests/ui/large_futures.rs:38:5 +error: usage of large future with a size of 16385 bytes + --> tests/ui/large_futures.rs:39:15 | LL | calls_fut(fut).await; - | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - calls_fut(fut).await; +LL + calls_fut(Box::pin(fut)).await; + | -error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:51:5 +error: usage of large future with a size of 65540 bytes + --> tests/ui/large_futures.rs:44:5 | LL | / async { -LL | | -LL | | LL | | let x = [0i32; 1024 * 16]; LL | | async {}.await; -LL | | println!("{:?}", x); +LL | | dbg!(x); LL | | } | |_____^ | -help: consider `Box::pin` on it +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL ~ Box::pin(async { -LL + -LL + LL + let x = [0i32; 1024 * 16]; LL + async {}.await; +LL + dbg!(x); +LL + }) + | + +error: usage of large future with a size of 65540 bytes + --> tests/ui/large_futures.rs:53:5 + | +LL | / async { +LL | | let x = [0i32; 1024 * 16]; +LL | | async {}.await; +... | +LL | | } + | |_____^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL ~ Box::pin(async { +LL + let x = [0i32; 1024 * 16]; +LL + async {}.await; +LL + LL + println!("{:?}", x); LL + }) | -error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:64:13 +error: usage of large future with a size of 65540 bytes + --> tests/ui/large_futures.rs:53:5 + | +LL | / async { +LL | | let x = [0i32; 1024 * 16]; +LL | | async {}.await; +... | +LL | | } + | |_____^ | -LL | / async { -LL | | -LL | | let x = [0i32; 1024 * 16]; -LL | | async {}.await; -LL | | println!("macro: {:?}", x); -LL | | } - | |_____________^ -... -LL | macro_!().await - | --------- in this macro invocation + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL ~ Box::pin(async { +LL + let x = [0i32; 1024 * 16]; +LL + async {}.await; +LL + +LL + println!("{:?}", x); +LL + }) + | + +error: definition for a large future with a size of 65544 bytes + --> tests/ui/large_futures.rs:63:27 | - = note: this error originates in the macro `macro_` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider `Box::pin` on it +LL | pub async fn macro_expn() { + | ___________________________^ +LL | | macro_rules! macro_ { +LL | | () => { +LL | | async { +... | +LL | | macro_!().await +LL | | } + | |_^ | -LL ~ Box::pin(async { -LL + -LL + let x = [0i32; 1024 * 16]; -LL + async {}.await; -LL + println!("macro: {:?}", x); -LL + }) +help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible + --> tests/ui/large_futures.rs:63:27 | +LL | pub async fn macro_expn() { + | ___________________________^ +LL | | macro_rules! macro_ { +LL | | () => { +LL | | async { +... | +LL | | macro_!().await +LL | | } + | |_^ -error: aborting due to 8 previous errors +error: aborting due to 20 previous errors From 9ab11a49ffc2c3840182ec2a4762b43f85274b1d Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Mon, 12 Jan 2026 15:40:02 +0100 Subject: [PATCH 02/10] Temporarily note duplicate lints in test --- tests/ui/large_futures.fixed | 31 ++++++++++++++++++++++--------- tests/ui/large_futures.rs | 17 ++++++++++++++--- tests/ui/large_futures.stderr | 34 +++++++++++++++++----------------- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index 4c7215f0abeb..215eaa41fe58 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -7,66 +7,79 @@ #![warn(clippy::large_futures)] async fn big_fut(_arg: [u8; 1024 * 16]) {} +//~^ large_futures async fn wait() { let f = async { Box::pin(big_fut([0u8; 1024 * 16])).await; //~^ large_futures + //~^^ large_futures + //~^^^ large_futures }; Box::pin(f).await //~^ large_futures + //~^^ large_futures } async fn calls_fut(fut: impl std::future::Future) { loop { Box::pin(wait()).await; //~^ large_futures + //~^^ large_futures if true { return fut.await; } else { Box::pin(wait()).await; //~^ large_futures + //~^^ large_futures } } } pub async fn test() { - let fut = big_fut([0u8; 1024 * 16]); + let fut = Box::pin(big_fut([0u8; 1024 * 16])); + //~^ large_futures + //~^^ large_futures + Box::pin(foo()).await; //~^ large_futures + //~^^ large_futures - Box::pin(calls_fut(fut)).await; + calls_fut(Box::pin(fut)).await; //~^ large_futures + //~^^ large_futures } pub fn foo() -> impl std::future::Future { - async { + //~v large_futures + Box::pin(async { let x = [0i32; 1024 * 16]; async {}.await; dbg!(x); - } + }) } pub async fn lines() { + //~vv large_futures + //~v large_futures Box::pin(async { - //~^ large_futures - let x = [0i32; 1024 * 16]; async {}.await; + println!("{:?}", x); }) .await; } +//~v large_futures pub async fn macro_expn() { macro_rules! macro_ { () => { - Box::pin(async { - //~^ large_futures + async { let x = [0i32; 1024 * 16]; async {}.await; println!("macro: {:?}", x); - }) + } }; } macro_!().await diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index f30069335b61..9259bb90e6be 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -13,53 +13,65 @@ async fn wait() { let f = async { big_fut([0u8; 1024 * 16]).await; //~^ large_futures + //~^^ large_futures + //~^^^ large_futures }; f.await //~^ large_futures + //~^^ large_futures } async fn calls_fut(fut: impl std::future::Future) { loop { wait().await; //~^ large_futures + //~^^ large_futures if true { return fut.await; } else { wait().await; //~^ large_futures + //~^^ large_futures } } } pub async fn test() { let fut = big_fut([0u8; 1024 * 16]); + //~^ large_futures + //~^^ large_futures + foo().await; //~^ large_futures + //~^^ large_futures calls_fut(fut).await; //~^ large_futures + //~^^ large_futures } pub fn foo() -> impl std::future::Future { + //~v large_futures async { let x = [0i32; 1024 * 16]; async {}.await; dbg!(x); } - //~^ large_futures } pub async fn lines() { + //~vv large_futures + //~v large_futures async { let x = [0i32; 1024 * 16]; async {}.await; println!("{:?}", x); } - //~^ large_futures .await; } +//~v large_futures pub async fn macro_expn() { macro_rules! macro_ { () => { @@ -72,6 +84,5 @@ pub async fn macro_expn() { } macro_!().await } -//~^ large_futures fn main() {} diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 770d279aedee..91bd63f36d3c 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -25,7 +25,7 @@ LL + Box::pin(big_fut([0u8; 1024 * 16])).await; | error: usage of large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:17:5 + --> tests/ui/large_futures.rs:19:5 | LL | f.await | ^ @@ -50,7 +50,7 @@ LL + Box::pin(big_fut([0u8; 1024 * 16])).await; | error: usage of large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:17:5 + --> tests/ui/large_futures.rs:19:5 | LL | f.await | ^ @@ -76,7 +76,7 @@ LL + Box::pin(big_fut([0u8; 1024 * 16])).await; | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:22:9 + --> tests/ui/large_futures.rs:25:9 | LL | wait().await; | ^^^^^^ @@ -88,7 +88,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:28:13 + --> tests/ui/large_futures.rs:32:13 | LL | wait().await; | ^^^^^^ @@ -100,7 +100,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:22:9 + --> tests/ui/large_futures.rs:25:9 | LL | wait().await; | ^^^^^^ @@ -113,7 +113,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:28:13 + --> tests/ui/large_futures.rs:32:13 | LL | wait().await; | ^^^^^^ @@ -126,7 +126,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:35:15 + --> tests/ui/large_futures.rs:40:15 | LL | let fut = big_fut([0u8; 1024 * 16]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +138,7 @@ LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:36:5 + --> tests/ui/large_futures.rs:44:5 | LL | foo().await; | ^^^^^ @@ -150,7 +150,7 @@ LL + Box::pin(foo()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:39:15 + --> tests/ui/large_futures.rs:48:15 | LL | calls_fut(fut).await; | ^^^ @@ -162,7 +162,7 @@ LL + calls_fut(Box::pin(fut)).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:35:15 + --> tests/ui/large_futures.rs:40:15 | LL | let fut = big_fut([0u8; 1024 * 16]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +175,7 @@ LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:36:5 + --> tests/ui/large_futures.rs:44:5 | LL | foo().await; | ^^^^^ @@ -188,7 +188,7 @@ LL + Box::pin(foo()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:39:15 + --> tests/ui/large_futures.rs:48:15 | LL | calls_fut(fut).await; | ^^^ @@ -201,7 +201,7 @@ LL + calls_fut(Box::pin(fut)).await; | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:44:5 + --> tests/ui/large_futures.rs:55:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -220,7 +220,7 @@ LL + }) | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:53:5 + --> tests/ui/large_futures.rs:65:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -240,7 +240,7 @@ LL + }) | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:53:5 + --> tests/ui/large_futures.rs:65:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -261,7 +261,7 @@ LL + }) | error: definition for a large future with a size of 65544 bytes - --> tests/ui/large_futures.rs:63:27 + --> tests/ui/large_futures.rs:75:27 | LL | pub async fn macro_expn() { | ___________________________^ @@ -274,7 +274,7 @@ LL | | } | |_^ | help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible - --> tests/ui/large_futures.rs:63:27 + --> tests/ui/large_futures.rs:75:27 | LL | pub async fn macro_expn() { | ___________________________^ From fb83cae73c26e57d5fd3e6d9dfb07037050d19bb Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Mon, 12 Jan 2026 16:36:21 +0100 Subject: [PATCH 03/10] Deduplicate lints based on expression hir_id --- clippy_lints/src/large_futures.rs | 15 ++- tests/ui/large_futures.fixed | 9 -- tests/ui/large_futures.rs | 9 -- tests/ui/large_futures.stderr | 147 +++--------------------------- 4 files changed, 22 insertions(+), 158 deletions(-) diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index e56ede94a61e..9ee56abaf826 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -6,7 +6,7 @@ use rustc_abi::Size; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_body, walk_expr}; -use rustc_hir::{Body, Expr, FnDecl}; +use rustc_hir::{Body, Expr, FnDecl, HirIdSet}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::Ty; @@ -47,12 +47,14 @@ declare_clippy_lint! { pub struct LargeFuture { future_size_threshold: u64, + visited: HirIdSet, } impl LargeFuture { pub fn new(conf: &'static Conf) -> Self { Self { future_size_threshold: conf.future_size_threshold, + visited: HirIdSet::default(), } } } @@ -60,8 +62,8 @@ impl LargeFuture { impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); struct AsyncFnVisitor<'a, 'tcx> { + parent: &'a mut LargeFuture, cx: &'a LateContext<'tcx>, - future_size_threshold: u64, /// Depth of the visitor with value `0` denoting the top-level expression. depth: usize, /// Whether a clippy suggestion was emitted for deeper levels of expressions. @@ -77,6 +79,11 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { // and hence it is redudant to also emit a suggestion for these expressions. // Expressions on the same depth level can however emit a suggestion too. + if !self.parent.visited.insert(expr.hir_id) { + // This expression was already visited once. + return; + } + self.depth += 1; let old_emitted = self.emitted; self.emitted = false; // Reset emitted for deeper level, but recover it later. @@ -86,7 +93,7 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { if !self.emitted && !expr.span.from_expansion() && let Some(ty) = self.cx.typeck_results().expr_ty_opt(expr) - && let Some(size) = type_is_large_future(self.cx, ty, self.future_size_threshold) + && let Some(size) = type_is_large_future(self.cx, ty, self.parent.future_size_threshold) { if self.depth == 0 { // Special lint for top level fn bodies. @@ -154,9 +161,9 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture { _: LocalDefId, ) { let mut visitor = AsyncFnVisitor { + parent: self, cx, depth: 0, - future_size_threshold: self.future_size_threshold, emitted: false, }; walk_body(&mut visitor, body); diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index 215eaa41fe58..8bd56c524964 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -13,25 +13,20 @@ async fn wait() { let f = async { Box::pin(big_fut([0u8; 1024 * 16])).await; //~^ large_futures - //~^^ large_futures - //~^^^ large_futures }; Box::pin(f).await //~^ large_futures - //~^^ large_futures } async fn calls_fut(fut: impl std::future::Future) { loop { Box::pin(wait()).await; //~^ large_futures - //~^^ large_futures if true { return fut.await; } else { Box::pin(wait()).await; //~^ large_futures - //~^^ large_futures } } } @@ -39,15 +34,12 @@ async fn calls_fut(fut: impl std::future::Future) { pub async fn test() { let fut = Box::pin(big_fut([0u8; 1024 * 16])); //~^ large_futures - //~^^ large_futures Box::pin(foo()).await; //~^ large_futures - //~^^ large_futures calls_fut(Box::pin(fut)).await; //~^ large_futures - //~^^ large_futures } pub fn foo() -> impl std::future::Future { @@ -60,7 +52,6 @@ pub fn foo() -> impl std::future::Future { } pub async fn lines() { - //~vv large_futures //~v large_futures Box::pin(async { let x = [0i32; 1024 * 16]; diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 9259bb90e6be..143fd1468da2 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -13,25 +13,20 @@ async fn wait() { let f = async { big_fut([0u8; 1024 * 16]).await; //~^ large_futures - //~^^ large_futures - //~^^^ large_futures }; f.await //~^ large_futures - //~^^ large_futures } async fn calls_fut(fut: impl std::future::Future) { loop { wait().await; //~^ large_futures - //~^^ large_futures if true { return fut.await; } else { wait().await; //~^ large_futures - //~^^ large_futures } } } @@ -39,15 +34,12 @@ async fn calls_fut(fut: impl std::future::Future) { pub async fn test() { let fut = big_fut([0u8; 1024 * 16]); //~^ large_futures - //~^^ large_futures foo().await; //~^ large_futures - //~^^ large_futures calls_fut(fut).await; //~^ large_futures - //~^^ large_futures } pub fn foo() -> impl std::future::Future { @@ -60,7 +52,6 @@ pub fn foo() -> impl std::future::Future { } pub async fn lines() { - //~vv large_futures //~v large_futures async { let x = [0i32; 1024 * 16]; diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 91bd63f36d3c..6e0780867653 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -25,7 +25,7 @@ LL + Box::pin(big_fut([0u8; 1024 * 16])).await; | error: usage of large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:19:5 + --> tests/ui/large_futures.rs:17:5 | LL | f.await | ^ @@ -36,47 +36,8 @@ LL - f.await LL + Box::pin(f).await | -error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:14:9 - | -LL | big_fut([0u8; 1024 * 16]).await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - big_fut([0u8; 1024 * 16]).await; -LL + Box::pin(big_fut([0u8; 1024 * 16])).await; - | - -error: usage of large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:19:5 - | -LL | f.await - | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - f.await -LL + Box::pin(f).await - | - -error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:14:9 - | -LL | big_fut([0u8; 1024 * 16]).await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - big_fut([0u8; 1024 * 16]).await; -LL + Box::pin(big_fut([0u8; 1024 * 16])).await; - | - error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:25:9 + --> tests/ui/large_futures.rs:22:9 | LL | wait().await; | ^^^^^^ @@ -88,7 +49,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:32:13 + --> tests/ui/large_futures.rs:28:13 | LL | wait().await; | ^^^^^^ @@ -99,75 +60,12 @@ LL - wait().await; LL + Box::pin(wait()).await; | -error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:25:9 - | -LL | wait().await; - | ^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - wait().await; -LL + Box::pin(wait()).await; - | - -error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:32:13 - | -LL | wait().await; - | ^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - wait().await; -LL + Box::pin(wait()).await; - | - -error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:40:15 - | -LL | let fut = big_fut([0u8; 1024 * 16]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - let fut = big_fut([0u8; 1024 * 16]); -LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); - | - -error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:44:5 - | -LL | foo().await; - | ^^^^^ - | -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - foo().await; -LL + Box::pin(foo()).await; - | - -error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:48:15 - | -LL | calls_fut(fut).await; - | ^^^ - | -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL - calls_fut(fut).await; -LL + calls_fut(Box::pin(fut)).await; - | - error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:40:15 + --> tests/ui/large_futures.rs:35:15 | LL | let fut = big_fut([0u8; 1024 * 16]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL - let fut = big_fut([0u8; 1024 * 16]); @@ -175,12 +73,11 @@ LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:44:5 + --> tests/ui/large_futures.rs:38:5 | LL | foo().await; | ^^^^^ | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL - foo().await; @@ -188,12 +85,11 @@ LL + Box::pin(foo()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:48:15 + --> tests/ui/large_futures.rs:41:15 | LL | calls_fut(fut).await; | ^^^ | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL - calls_fut(fut).await; @@ -201,7 +97,7 @@ LL + calls_fut(Box::pin(fut)).await; | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:55:5 + --> tests/ui/large_futures.rs:47:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -220,27 +116,7 @@ LL + }) | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:65:5 - | -LL | / async { -LL | | let x = [0i32; 1024 * 16]; -LL | | async {}.await; -... | -LL | | } - | |_____^ - | -help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible - | -LL ~ Box::pin(async { -LL + let x = [0i32; 1024 * 16]; -LL + async {}.await; -LL + -LL + println!("{:?}", x); -LL + }) - | - -error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:65:5 + --> tests/ui/large_futures.rs:56:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -249,7 +125,6 @@ LL | | async {}.await; LL | | } | |_____^ | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL ~ Box::pin(async { @@ -261,7 +136,7 @@ LL + }) | error: definition for a large future with a size of 65544 bytes - --> tests/ui/large_futures.rs:75:27 + --> tests/ui/large_futures.rs:66:27 | LL | pub async fn macro_expn() { | ___________________________^ @@ -274,7 +149,7 @@ LL | | } | |_^ | help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible - --> tests/ui/large_futures.rs:75:27 + --> tests/ui/large_futures.rs:66:27 | LL | pub async fn macro_expn() { | ___________________________^ @@ -286,5 +161,5 @@ LL | | macro_!().await LL | | } | |_^ -error: aborting due to 20 previous errors +error: aborting due to 11 previous errors From 34f19576536856ffb67525d7abbb95f4fd9a5826 Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Tue, 13 Jan 2026 13:58:57 +0100 Subject: [PATCH 04/10] Do not expand expression when 'Box::pin' has been applied --- clippy_lints/src/large_futures.rs | 14 ++++- .../ui-toml/large_futures/large_futures.fixed | 28 --------- tests/ui-toml/large_futures/large_futures.rs | 2 + .../large_futures/large_futures.stderr | 37 +++++++++-- tests/ui/large_futures.fixed | 14 ++--- tests/ui/large_futures.rs | 14 ++--- tests/ui/large_futures.stderr | 62 ++++--------------- tests/ui/large_futures_unfixable.rs | 5 ++ tests/ui/large_futures_unfixable.stderr | 16 +++++ 9 files changed, 92 insertions(+), 100 deletions(-) delete mode 100644 tests/ui-toml/large_futures/large_futures.fixed create mode 100644 tests/ui/large_futures_unfixable.rs create mode 100644 tests/ui/large_futures_unfixable.stderr diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 9ee56abaf826..d53a9d3048b2 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -1,12 +1,14 @@ +use crate::clippy_utils::res::MaybeDef; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::res::MaybeResPath; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_abi::Size; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_body, walk_expr}; -use rustc_hir::{Body, Expr, FnDecl, HirIdSet}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirIdSet, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::Ty; @@ -84,6 +86,16 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { return; } + if let ExprKind::Call(method, _) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = method.kind + && ty.basic_res().is_lang_item(self.cx, LangItem::OwnedBox) + && seg.ident.name.as_str() == "pin" + { + // When the current expression is already a `Box::pin(...)` call, + // our suggestion has been applied. Do not recurse deeper. + return; + } + self.depth += 1; let old_emitted = self.emitted; self.emitted = false; // Reset emitted for deeper level, but recover it later. diff --git a/tests/ui-toml/large_futures/large_futures.fixed b/tests/ui-toml/large_futures/large_futures.fixed deleted file mode 100644 index 17d6553a283b..000000000000 --- a/tests/ui-toml/large_futures/large_futures.fixed +++ /dev/null @@ -1,28 +0,0 @@ -#![warn(clippy::large_futures)] - -fn main() {} - -pub async fn should_warn() { - let x = [0u8; 1024]; - async {}.await; - dbg!(x); -} - -pub async fn should_not_warn() { - let x = [0u8; 1020]; - async {}.await; - dbg!(x); -} - -pub async fn bar() { - Box::pin(should_warn()).await; - //~^ large_futures - - async { - let x = [0u8; 1024]; - dbg!(x); - } - .await; - - should_not_warn().await; -} diff --git a/tests/ui-toml/large_futures/large_futures.rs b/tests/ui-toml/large_futures/large_futures.rs index bc601227e562..a30e77e45dde 100644 --- a/tests/ui-toml/large_futures/large_futures.rs +++ b/tests/ui-toml/large_futures/large_futures.rs @@ -1,7 +1,9 @@ #![warn(clippy::large_futures)] +//@no-rustfix fn main() {} +//~v large_futures pub async fn should_warn() { let x = [0u8; 1024]; async {}.await; diff --git a/tests/ui-toml/large_futures/large_futures.stderr b/tests/ui-toml/large_futures/large_futures.stderr index 7779bfeca5dd..89a3421062f5 100644 --- a/tests/ui-toml/large_futures/large_futures.stderr +++ b/tests/ui-toml/large_futures/large_futures.stderr @@ -1,11 +1,38 @@ -error: large future with a size of 1026 bytes - --> tests/ui-toml/large_futures/large_futures.rs:18:5 +error: definition for a large future with a size of 1026 bytes + --> tests/ui-toml/large_futures/large_futures.rs:7:28 | -LL | should_warn().await; - | ^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(should_warn())` +LL | pub async fn should_warn() { + | ____________________________^ +LL | | let x = [0u8; 1024]; +LL | | async {}.await; +LL | | dbg!(x); +LL | | } + | |_^ + | +help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible + --> tests/ui-toml/large_futures/large_futures.rs:7:28 | +LL | pub async fn should_warn() { + | ____________________________^ +LL | | let x = [0u8; 1024]; +LL | | async {}.await; +LL | | dbg!(x); +LL | | } + | |_^ = note: `-D clippy::large-futures` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` -error: aborting due to 1 previous error +error: usage of large future with a size of 1026 bytes + --> tests/ui-toml/large_futures/large_futures.rs:20:5 + | +LL | should_warn().await; + | ^^^^^^^^^^^^^ + | +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL - should_warn().await; +LL + Box::pin(should_warn()).await; + | + +error: aborting due to 2 previous errors diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index 8bd56c524964..d3d69f462e5e 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -1,13 +1,10 @@ -#![allow( - clippy::future_not_send, - clippy::manual_async_fn, - clippy::never_loop, - clippy::uninlined_format_args -)] +#![allow(clippy::manual_async_fn)] #![warn(clippy::large_futures)] +// Note: large_futures are allowed here, as rustfix cannot actually fix this case. +// See large_futures_unfixable instead. +#[allow(clippy::large_futures)] async fn big_fut(_arg: [u8; 1024 * 16]) {} -//~^ large_futures async fn wait() { let f = async { @@ -62,7 +59,8 @@ pub async fn lines() { .await; } -//~v large_futures +// Note: large_futures are allowed here, as rustfix cannot actually fix this case. +#[allow(clippy::large_futures)] pub async fn macro_expn() { macro_rules! macro_ { () => { diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 143fd1468da2..474498f06061 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -1,13 +1,10 @@ -#![allow( - clippy::future_not_send, - clippy::manual_async_fn, - clippy::never_loop, - clippy::uninlined_format_args -)] +#![allow(clippy::manual_async_fn)] #![warn(clippy::large_futures)] +// Note: large_futures are allowed here, as rustfix cannot actually fix this case. +// See large_futures_unfixable instead. +#[allow(clippy::large_futures)] async fn big_fut(_arg: [u8; 1024 * 16]) {} -//~^ large_futures async fn wait() { let f = async { @@ -62,7 +59,8 @@ pub async fn lines() { .await; } -//~v large_futures +// Note: large_futures are allowed here, as rustfix cannot actually fix this case. +#[allow(clippy::large_futures)] pub async fn macro_expn() { macro_rules! macro_ { () => { diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 6e0780867653..84110696913e 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -1,23 +1,11 @@ -error: definition for a large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:9:41 - | -LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} - | ^^ - | -help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible - --> tests/ui/large_futures.rs:9:41 - | -LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} - | ^^ - = note: `-D clippy::large-futures` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` - error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:14:9 + --> tests/ui/large_futures.rs:11:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: `-D clippy::large-futures` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL - big_fut([0u8; 1024 * 16]).await; @@ -25,7 +13,7 @@ LL + Box::pin(big_fut([0u8; 1024 * 16])).await; | error: usage of large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:17:5 + --> tests/ui/large_futures.rs:14:5 | LL | f.await | ^ @@ -37,7 +25,7 @@ LL + Box::pin(f).await | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:22:9 + --> tests/ui/large_futures.rs:19:9 | LL | wait().await; | ^^^^^^ @@ -49,7 +37,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:28:13 + --> tests/ui/large_futures.rs:25:13 | LL | wait().await; | ^^^^^^ @@ -61,7 +49,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:35:15 + --> tests/ui/large_futures.rs:32:15 | LL | let fut = big_fut([0u8; 1024 * 16]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +61,7 @@ LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:38:5 + --> tests/ui/large_futures.rs:35:5 | LL | foo().await; | ^^^^^ @@ -85,7 +73,7 @@ LL + Box::pin(foo()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:41:15 + --> tests/ui/large_futures.rs:38:15 | LL | calls_fut(fut).await; | ^^^ @@ -97,7 +85,7 @@ LL + calls_fut(Box::pin(fut)).await; | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:47:5 + --> tests/ui/large_futures.rs:44:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -116,7 +104,7 @@ LL + }) | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:56:5 + --> tests/ui/large_futures.rs:53:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -135,31 +123,5 @@ LL + println!("{:?}", x); LL + }) | -error: definition for a large future with a size of 65544 bytes - --> tests/ui/large_futures.rs:66:27 - | -LL | pub async fn macro_expn() { - | ___________________________^ -LL | | macro_rules! macro_ { -LL | | () => { -LL | | async { -... | -LL | | macro_!().await -LL | | } - | |_^ - | -help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible - --> tests/ui/large_futures.rs:66:27 - | -LL | pub async fn macro_expn() { - | ___________________________^ -LL | | macro_rules! macro_ { -LL | | () => { -LL | | async { -... | -LL | | macro_!().await -LL | | } - | |_^ - -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/large_futures_unfixable.rs b/tests/ui/large_futures_unfixable.rs new file mode 100644 index 000000000000..076ed7085c62 --- /dev/null +++ b/tests/ui/large_futures_unfixable.rs @@ -0,0 +1,5 @@ +#![warn(clippy::large_futures)] +//@no-rustfix + +async fn big_fut(_arg: [u8; 1024 * 16]) {} +//~^ large_futures diff --git a/tests/ui/large_futures_unfixable.stderr b/tests/ui/large_futures_unfixable.stderr new file mode 100644 index 000000000000..bead02cb19bd --- /dev/null +++ b/tests/ui/large_futures_unfixable.stderr @@ -0,0 +1,16 @@ +error: definition for a large future with a size of 16385 bytes + --> tests/ui/large_futures_unfixable.rs:4:41 + | +LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} + | ^^ + | +help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible + --> tests/ui/large_futures_unfixable.rs:4:41 + | +LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} + | ^^ + = note: `-D clippy::large-futures` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` + +error: aborting due to 1 previous error + From 849c31946ddf7b8ab15876aa3ab424c15086cd54 Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Tue, 13 Jan 2026 14:10:36 +0100 Subject: [PATCH 05/10] Use sym::pin instead of matching on string --- clippy_lints/src/large_futures.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index d53a9d3048b2..1ec1514c9ed8 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -3,6 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::MaybeResPath; use clippy_utils::source::snippet; +use clippy_utils::sym; use clippy_utils::ty::implements_trait; use rustc_abi::Size; use rustc_errors::Applicability; @@ -89,7 +90,7 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { if let ExprKind::Call(method, _) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = method.kind && ty.basic_res().is_lang_item(self.cx, LangItem::OwnedBox) - && seg.ident.name.as_str() == "pin" + && seg.ident.name == sym::pin { // When the current expression is already a `Box::pin(...)` call, // our suggestion has been applied. Do not recurse deeper. From 90030105b4e15bf37da9ff7153df3f9ab13a4e37 Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Wed, 14 Jan 2026 11:39:13 +0100 Subject: [PATCH 06/10] Clarified test comment --- tests/ui/large_futures.fixed | 3 ++- tests/ui/large_futures.rs | 3 ++- tests/ui/large_futures.stderr | 18 +++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index d3d69f462e5e..b4a7d68a583a 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -2,7 +2,8 @@ #![warn(clippy::large_futures)] // Note: large_futures are allowed here, as rustfix cannot actually fix this case. -// See large_futures_unfixable instead. +// The reason we still keep it around is that it's used as a helper in other tests. +// See large_futures_unfixable.rs where this definition is demonstrated to emit a lint as well. #[allow(clippy::large_futures)] async fn big_fut(_arg: [u8; 1024 * 16]) {} diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 474498f06061..a32b0e12fdd9 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -2,7 +2,8 @@ #![warn(clippy::large_futures)] // Note: large_futures are allowed here, as rustfix cannot actually fix this case. -// See large_futures_unfixable instead. +// The reason we still keep it around is that it's used as a helper in other tests. +// See large_futures_unfixable.rs where this definition is demonstrated to emit a lint as well. #[allow(clippy::large_futures)] async fn big_fut(_arg: [u8; 1024 * 16]) {} diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 84110696913e..a091b65a8316 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -1,5 +1,5 @@ error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:11:9 + --> tests/ui/large_futures.rs:12:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + Box::pin(big_fut([0u8; 1024 * 16])).await; | error: usage of large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:14:5 + --> tests/ui/large_futures.rs:15:5 | LL | f.await | ^ @@ -25,7 +25,7 @@ LL + Box::pin(f).await | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:19:9 + --> tests/ui/large_futures.rs:20:9 | LL | wait().await; | ^^^^^^ @@ -37,7 +37,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:25:13 + --> tests/ui/large_futures.rs:26:13 | LL | wait().await; | ^^^^^^ @@ -49,7 +49,7 @@ LL + Box::pin(wait()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:32:15 + --> tests/ui/large_futures.rs:33:15 | LL | let fut = big_fut([0u8; 1024 * 16]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let fut = Box::pin(big_fut([0u8; 1024 * 16])); | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:35:5 + --> tests/ui/large_futures.rs:36:5 | LL | foo().await; | ^^^^^ @@ -73,7 +73,7 @@ LL + Box::pin(foo()).await; | error: usage of large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:38:15 + --> tests/ui/large_futures.rs:39:15 | LL | calls_fut(fut).await; | ^^^ @@ -85,7 +85,7 @@ LL + calls_fut(Box::pin(fut)).await; | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:44:5 + --> tests/ui/large_futures.rs:45:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -104,7 +104,7 @@ LL + }) | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:53:5 + --> tests/ui/large_futures.rs:54:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; From 92006e0234d7db9dae67b758c5e4d6f31a249ce4 Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Wed, 14 Jan 2026 12:27:25 +0100 Subject: [PATCH 07/10] Handle macro expansions too, whilst not handling desugared .await --- clippy_lints/src/large_futures.rs | 4 ++-- tests/ui/large_futures.fixed | 6 +++--- tests/ui/large_futures.rs | 2 +- tests/ui/large_futures.stderr | 25 ++++++++++++++++++++++++- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 1ec1514c9ed8..2c03a130599f 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{DesugaringKind, Span}; declare_clippy_lint! { /// ### What it does @@ -104,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { self.depth -= 1; if !self.emitted - && !expr.span.from_expansion() + && !expr.span.is_desugaring(DesugaringKind::Await) && let Some(ty) = self.cx.typeck_results().expr_ty_opt(expr) && let Some(size) = type_is_large_future(self.cx, ty, self.parent.future_size_threshold) { diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index b4a7d68a583a..889106e60a12 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -61,15 +61,15 @@ pub async fn lines() { } // Note: large_futures are allowed here, as rustfix cannot actually fix this case. -#[allow(clippy::large_futures)] pub async fn macro_expn() { macro_rules! macro_ { () => { - async { + //~v large_futures + Box::pin(async { let x = [0i32; 1024 * 16]; async {}.await; println!("macro: {:?}", x); - } + }) }; } macro_!().await diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index a32b0e12fdd9..3161d32ff748 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -61,10 +61,10 @@ pub async fn lines() { } // Note: large_futures are allowed here, as rustfix cannot actually fix this case. -#[allow(clippy::large_futures)] pub async fn macro_expn() { macro_rules! macro_ { () => { + //~v large_futures async { let x = [0i32; 1024 * 16]; async {}.await; diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index a091b65a8316..f11f7f812742 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -123,5 +123,28 @@ LL + println!("{:?}", x); LL + }) | -error: aborting due to 9 previous errors +error: usage of large future with a size of 65540 bytes + --> tests/ui/large_futures.rs:68:13 + | +LL | / async { +LL | | let x = [0i32; 1024 * 16]; +LL | | async {}.await; +LL | | println!("macro: {:?}", x); +LL | | } + | |_____________^ +... +LL | macro_!().await + | --------- in this macro invocation + | + = note: this error originates in the macro `macro_` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible + | +LL ~ Box::pin(async { +LL + let x = [0i32; 1024 * 16]; +LL + async {}.await; +LL + println!("macro: {:?}", x); +LL + }) + | + +error: aborting due to 10 previous errors From b40fe675e61d10cc9fb514383f1e8a3c64f7f359 Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Wed, 14 Jan 2026 12:33:04 +0100 Subject: [PATCH 08/10] Prefer to use ~^ instead of ~v --- tests/ui/large_futures.fixed | 6 +++--- tests/ui/large_futures.rs | 6 +++--- tests/ui/large_futures.stderr | 15 +++++++++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index 889106e60a12..9d98d48473bd 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -41,8 +41,8 @@ pub async fn test() { } pub fn foo() -> impl std::future::Future { - //~v large_futures Box::pin(async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; dbg!(x); @@ -50,8 +50,8 @@ pub fn foo() -> impl std::future::Future { } pub async fn lines() { - //~v large_futures Box::pin(async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; @@ -64,8 +64,8 @@ pub async fn lines() { pub async fn macro_expn() { macro_rules! macro_ { () => { - //~v large_futures Box::pin(async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; println!("macro: {:?}", x); diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 3161d32ff748..c8ce63baea37 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -41,8 +41,8 @@ pub async fn test() { } pub fn foo() -> impl std::future::Future { - //~v large_futures async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; dbg!(x); @@ -50,8 +50,8 @@ pub fn foo() -> impl std::future::Future { } pub async fn lines() { - //~v large_futures async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; @@ -64,8 +64,8 @@ pub async fn lines() { pub async fn macro_expn() { macro_rules! macro_ { () => { - //~v large_futures async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; println!("macro: {:?}", x); diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index f11f7f812742..0b2c39e442d4 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -85,9 +85,10 @@ LL + calls_fut(Box::pin(fut)).await; | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:45:5 + --> tests/ui/large_futures.rs:44:5 | LL | / async { +LL | | LL | | let x = [0i32; 1024 * 16]; LL | | async {}.await; LL | | dbg!(x); @@ -97,6 +98,7 @@ LL | | } help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL ~ Box::pin(async { +LL + LL + let x = [0i32; 1024 * 16]; LL + async {}.await; LL + dbg!(x); @@ -104,18 +106,21 @@ LL + }) | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:54:5 + --> tests/ui/large_futures.rs:53:5 | LL | / async { +LL | | LL | | let x = [0i32; 1024 * 16]; LL | | async {}.await; -... | +LL | | +LL | | println!("{:?}", x); LL | | } | |_____^ | help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL ~ Box::pin(async { +LL + LL + let x = [0i32; 1024 * 16]; LL + async {}.await; LL + @@ -124,9 +129,10 @@ LL + }) | error: usage of large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:68:13 + --> tests/ui/large_futures.rs:67:13 | LL | / async { +LL | | LL | | let x = [0i32; 1024 * 16]; LL | | async {}.await; LL | | println!("macro: {:?}", x); @@ -140,6 +146,7 @@ LL | macro_!().await help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL ~ Box::pin(async { +LL + LL + let x = [0i32; 1024 * 16]; LL + async {}.await; LL + println!("macro: {:?}", x); From 2d0a4fde66b3316bef3d9984a1393d459ede2168 Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Wed, 14 Jan 2026 13:13:55 +0100 Subject: [PATCH 09/10] Use entire function decl span when emitting a lint for the body expression --- clippy_lints/src/large_futures.rs | 9 ++++++--- tests/ui-toml/large_futures/large_futures.stderr | 16 +++------------- tests/ui/large_futures_unfixable.stderr | 10 +++------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 2c03a130599f..2455f8f0fd68 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -67,6 +67,8 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); struct AsyncFnVisitor<'a, 'tcx> { parent: &'a mut LargeFuture, cx: &'a LateContext<'tcx>, + /// Span of the function decl to be used when emitting a lint concerning the entire decl. + top_level_span: Span, /// Depth of the visitor with value `0` denoting the top-level expression. depth: usize, /// Whether a clippy suggestion was emitted for deeper levels of expressions. @@ -114,10 +116,10 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { self.cx, LARGE_FUTURES, expr.hir_id, - expr.span, + self.top_level_span, format!("definition for a large future with a size of {} bytes", size.bytes()), |db| { - db.span_help(expr.span, "consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible"); + db.help("consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible"); }, ); } else { @@ -170,12 +172,13 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture { _: FnKind<'tcx>, _: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, - _: Span, + span: Span, _: LocalDefId, ) { let mut visitor = AsyncFnVisitor { parent: self, cx, + top_level_span: span, depth: 0, emitted: false, }; diff --git a/tests/ui-toml/large_futures/large_futures.stderr b/tests/ui-toml/large_futures/large_futures.stderr index 89a3421062f5..2a48b8ecb4b8 100644 --- a/tests/ui-toml/large_futures/large_futures.stderr +++ b/tests/ui-toml/large_futures/large_futures.stderr @@ -1,24 +1,14 @@ error: definition for a large future with a size of 1026 bytes - --> tests/ui-toml/large_futures/large_futures.rs:7:28 + --> tests/ui-toml/large_futures/large_futures.rs:7:1 | -LL | pub async fn should_warn() { - | ____________________________^ +LL | / pub async fn should_warn() { LL | | let x = [0u8; 1024]; LL | | async {}.await; LL | | dbg!(x); LL | | } | |_^ | -help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible - --> tests/ui-toml/large_futures/large_futures.rs:7:28 - | -LL | pub async fn should_warn() { - | ____________________________^ -LL | | let x = [0u8; 1024]; -LL | | async {}.await; -LL | | dbg!(x); -LL | | } - | |_^ + = help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible = note: `-D clippy::large-futures` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` diff --git a/tests/ui/large_futures_unfixable.stderr b/tests/ui/large_futures_unfixable.stderr index bead02cb19bd..d48c60128013 100644 --- a/tests/ui/large_futures_unfixable.stderr +++ b/tests/ui/large_futures_unfixable.stderr @@ -1,14 +1,10 @@ error: definition for a large future with a size of 16385 bytes - --> tests/ui/large_futures_unfixable.rs:4:41 + --> tests/ui/large_futures_unfixable.rs:4:1 | LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible - --> tests/ui/large_futures_unfixable.rs:4:41 - | -LL | async fn big_fut(_arg: [u8; 1024 * 16]) {} - | ^^ + = help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible = note: `-D clippy::large-futures` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` From 93216cf8115912645643b0111ac1542d540a58ea Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Wed, 14 Jan 2026 13:20:59 +0100 Subject: [PATCH 10/10] Split out ui-toml tests and add note on buffer size --- .../ui-toml/large_futures/large_futures.fixed | 35 +++++++++++++++++++ tests/ui-toml/large_futures/large_futures.rs | 11 ++++-- .../large_futures/large_futures.stderr | 20 +++-------- .../large_futures/large_futures_unfixable.rs | 11 ++++++ .../large_futures_unfixable.stderr | 16 +++++++++ 5 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 tests/ui-toml/large_futures/large_futures.fixed create mode 100644 tests/ui-toml/large_futures/large_futures_unfixable.rs create mode 100644 tests/ui-toml/large_futures/large_futures_unfixable.stderr diff --git a/tests/ui-toml/large_futures/large_futures.fixed b/tests/ui-toml/large_futures/large_futures.fixed new file mode 100644 index 000000000000..39b968da361e --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures.fixed @@ -0,0 +1,35 @@ +#![warn(clippy::large_futures)] + +fn main() {} + +// Note: large_futures are allowed here, as rustfix cannot actually fix this case. +// The reason we still keep it around is that it's used as a helper in other tests. +// See large_futures_unfixable.rs where this definition is demonstrated to emit a lint as well. +#[allow(clippy::large_futures)] +pub async fn should_warn() { + let x = [0u8; 1024]; + async {}.await; + dbg!(x); +} + +pub async fn should_not_warn() { + // Note: not 1020 bytes as expected, because after being corrected to `Box::pin(should_warn())`, + // `bar()` is now the largest future in the tree, and with this being 1020 bytes `bar()` is larger + // than 1024 bytes because of the added discriminant overhead. + let x = [0u8; 1012]; + async {}.await; + dbg!(x); +} + +pub async fn bar() { + Box::pin(should_warn()).await; + //~^ large_futures + + async { + let x = [0u8; 1024]; + dbg!(x); + } + .await; + + should_not_warn().await; +} diff --git a/tests/ui-toml/large_futures/large_futures.rs b/tests/ui-toml/large_futures/large_futures.rs index a30e77e45dde..bd9ff5a0bf36 100644 --- a/tests/ui-toml/large_futures/large_futures.rs +++ b/tests/ui-toml/large_futures/large_futures.rs @@ -1,9 +1,11 @@ #![warn(clippy::large_futures)] -//@no-rustfix fn main() {} -//~v large_futures +// Note: large_futures are allowed here, as rustfix cannot actually fix this case. +// The reason we still keep it around is that it's used as a helper in other tests. +// See large_futures_unfixable.rs where this definition is demonstrated to emit a lint as well. +#[allow(clippy::large_futures)] pub async fn should_warn() { let x = [0u8; 1024]; async {}.await; @@ -11,7 +13,10 @@ pub async fn should_warn() { } pub async fn should_not_warn() { - let x = [0u8; 1020]; + // Note: not 1020 bytes as expected, because after being corrected to `Box::pin(should_warn())`, + // `bar()` is now the largest future in the tree, and with this being 1020 bytes `bar()` is larger + // than 1024 bytes because of the added discriminant overhead. + let x = [0u8; 1012]; async {}.await; dbg!(x); } diff --git a/tests/ui-toml/large_futures/large_futures.stderr b/tests/ui-toml/large_futures/large_futures.stderr index 2a48b8ecb4b8..a629a85e14e6 100644 --- a/tests/ui-toml/large_futures/large_futures.stderr +++ b/tests/ui-toml/large_futures/large_futures.stderr @@ -1,28 +1,16 @@ -error: definition for a large future with a size of 1026 bytes - --> tests/ui-toml/large_futures/large_futures.rs:7:1 - | -LL | / pub async fn should_warn() { -LL | | let x = [0u8; 1024]; -LL | | async {}.await; -LL | | dbg!(x); -LL | | } - | |_^ - | - = help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible - = note: `-D clippy::large-futures` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` - error: usage of large future with a size of 1026 bytes - --> tests/ui-toml/large_futures/large_futures.rs:20:5 + --> tests/ui-toml/large_futures/large_futures.rs:25:5 | LL | should_warn().await; | ^^^^^^^^^^^^^ | + = note: `-D clippy::large-futures` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` help: consider `Box::pin` on it or reducing direct ownership of the items in scope and use references instead where possible | LL - should_warn().await; LL + Box::pin(should_warn()).await; | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui-toml/large_futures/large_futures_unfixable.rs b/tests/ui-toml/large_futures/large_futures_unfixable.rs new file mode 100644 index 000000000000..7c29db40c6cd --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures_unfixable.rs @@ -0,0 +1,11 @@ +#![warn(clippy::large_futures)] +//@no-rustfix + +fn main() {} + +//~v large_futures +pub async fn should_warn() { + let x = [0u8; 1024]; + async {}.await; + dbg!(x); +} diff --git a/tests/ui-toml/large_futures/large_futures_unfixable.stderr b/tests/ui-toml/large_futures/large_futures_unfixable.stderr new file mode 100644 index 000000000000..3e6e2208d7bc --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures_unfixable.stderr @@ -0,0 +1,16 @@ +error: definition for a large future with a size of 1026 bytes + --> tests/ui-toml/large_futures/large_futures_unfixable.rs:7:1 + | +LL | / pub async fn should_warn() { +LL | | let x = [0u8; 1024]; +LL | | async {}.await; +LL | | dbg!(x); +LL | | } + | |_^ + | + = help: consider `Box::pin` when constructing it or reducing direct ownership of the items in scope and use references instead where possible + = note: `-D clippy::large-futures` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` + +error: aborting due to 1 previous error +