diff options
Diffstat (limited to 'compiler/rustc_lint/src/unused.rs')
-rw-r--r-- | compiler/rustc_lint/src/unused.rs | 158 |
1 files changed, 125 insertions, 33 deletions
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 8f75fa11d..5015b751e 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,7 +1,8 @@ use crate::lints::{ PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag, UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim, - UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult, + UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion, + UnusedResult, }; use crate::Lint; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -93,7 +94,15 @@ declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]); impl<'tcx> LateLintPass<'tcx> for UnusedResults { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { - let hir::StmtKind::Semi(expr) = s.kind else { return; }; + let hir::StmtKind::Semi(mut expr) = s.kind else { return; }; + + let mut expr_is_from_block = false; + while let hir::ExprKind::Block(blk, ..) = expr.kind + && let hir::Block { expr: Some(e), .. } = blk + { + expr = e; + expr_is_from_block = true; + } if let hir::ExprKind::Ret(..) = expr.kind { return; @@ -113,6 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { expr.span, "output of future returned by ", "", + expr_is_from_block, ) { // We have a bare `foo().await;` on an opaque type from an async function that was @@ -125,13 +135,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span); let type_lint_emitted_or_suppressed = match must_use_result { Some(path) => { - emit_must_use_untranslated(cx, &path, "", "", 1, false); + emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block); true } None => false, }; - let fn_warned = check_fn_must_use(cx, expr); + let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block); if !fn_warned && type_lint_emitted_or_suppressed { // We don't warn about unused unit or uninhabited types. @@ -176,7 +186,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { UnusedOp { op: must_use_op, label: expr.span, - suggestion: expr.span.shrink_to_lo(), + suggestion: if expr_is_from_block { + UnusedOpSuggestion::BlockTailExpr { + before_span: expr.span.shrink_to_lo(), + after_span: expr.span.shrink_to_hi(), + } + } else { + UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() } + }, }, ); op_warned = true; @@ -186,7 +203,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty }); } - fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + fn check_fn_must_use( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + expr_is_from_block: bool, + ) -> bool { let maybe_def_id = match expr.kind { hir::ExprKind::Call(ref callee, _) => { match callee.kind { @@ -207,7 +228,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { _ => None, }; if let Some(def_id) = maybe_def_id { - check_must_use_def(cx, def_id, expr.span, "return value of ", "") + check_must_use_def( + cx, + def_id, + expr.span, + "return value of ", + "", + expr_is_from_block, + ) } else { false } @@ -261,9 +289,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .filter_only_self() .find_map(|(pred, _span)| { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait( - ref poly_trait_predicate, - )) = pred.kind().skip_binder() + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = + pred.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; @@ -350,6 +377,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { span: Span, descr_pre_path: &str, descr_post_path: &str, + expr_is_from_block: bool, ) -> bool { is_def_must_use(cx, def_id, span) .map(|must_use_path| { @@ -360,6 +388,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_post_path, 1, false, + expr_is_from_block, ) }) .is_some() @@ -373,6 +402,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_post: &str, plural_len: usize, is_inner: bool, + expr_is_from_block: bool, ) { let plural_suffix = pluralize!(plural_len); @@ -380,21 +410,51 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { MustUsePath::Suppressed => {} MustUsePath::Boxed(path) => { let descr_pre = &format!("{}boxed ", descr_pre); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, + ); } MustUsePath::Opaque(path) => { let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, + ); } MustUsePath::TraitObject(path) => { let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, + ); } MustUsePath::TupleElement(elems) => { for (index, path) in elems { let descr_post = &format!(" in tuple element {}", index); emit_must_use_untranslated( - cx, path, descr_pre, descr_post, plural_len, true, + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, ); } } @@ -407,6 +467,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_post, plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)), true, + expr_is_from_block, ); } MustUsePath::Closure(span) => { @@ -433,8 +494,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx, def_id: *def_id, note: *reason, - suggestion: (!is_inner) - .then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }), + suggestion: (!is_inner).then_some(if expr_is_from_block { + UnusedDefSuggestion::BlockTailExpr { + before_span: span.shrink_to_lo(), + after_span: span.shrink_to_hi(), + } + } else { + UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() } + }), }, ); } @@ -556,6 +623,7 @@ trait UnusedDelimLint { followed_by_block: bool, left_pos: Option<BytePos>, right_pos: Option<BytePos>, + is_kw: bool, ); fn is_expr_delims_necessary( @@ -624,6 +692,7 @@ trait UnusedDelimLint { ctx: UnusedDelimsCtx, left_pos: Option<BytePos>, right_pos: Option<BytePos>, + is_kw: bool, ) { // If `value` has `ExprKind::Err`, unused delim lint can be broken. // For example, the following code caused ICE. @@ -667,7 +736,7 @@ trait UnusedDelimLint { left_pos.is_some_and(|s| s >= value.span.lo()), right_pos.is_some_and(|s| s <= value.span.hi()), ); - self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space); + self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space, is_kw); } fn emit_unused_delims( @@ -677,6 +746,7 @@ trait UnusedDelimLint { spans: Option<(Span, Span)>, msg: &str, keep_space: (bool, bool), + is_kw: bool, ) { let primary_span = if let Some((lo, hi)) = spans { if hi.is_empty() { @@ -690,7 +760,7 @@ trait UnusedDelimLint { let suggestion = spans.map(|(lo, hi)| { let sm = cx.sess().source_map(); let lo_replace = - if keep_space.0 && + if (keep_space.0 || is_kw) && let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') { " " } else { @@ -720,7 +790,7 @@ trait UnusedDelimLint { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { use rustc_ast::ExprKind::*; - let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind { + let (value, ctx, followed_by_block, left_pos, right_pos, is_kw) = match e.kind { // Do not lint `unused_braces` in `if let` expressions. If(ref cond, ref block, _) if !matches!(cond.kind, Let(_, _, _)) @@ -728,7 +798,7 @@ trait UnusedDelimLint { { let left = e.span.lo() + rustc_span::BytePos(2); let right = block.span.lo(); - (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right)) + (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right), true) } // Do not lint `unused_braces` in `while let` expressions. @@ -738,27 +808,27 @@ trait UnusedDelimLint { { let left = e.span.lo() + rustc_span::BytePos(5); let right = block.span.lo(); - (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right)) + (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true) } ForLoop(_, ref cond, ref block, ..) => { - (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo())) + (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()), true) } Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { let left = e.span.lo() + rustc_span::BytePos(5); - (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None) + (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true) } Ret(Some(ref value)) => { let left = e.span.lo() + rustc_span::BytePos(3); - (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None) + (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true) } - Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None), + Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false), Assign(_, ref value, _) | AssignOp(.., ref value) => { - (value, UnusedDelimsCtx::AssignedValue, false, None, None) + (value, UnusedDelimsCtx::AssignedValue, false, None, None, false) } // either function/method call, or something this lint doesn't care about ref call_or_other => { @@ -778,12 +848,20 @@ trait UnusedDelimLint { return; } for arg in args_to_check { - self.check_unused_delims_expr(cx, arg, ctx, false, None, None); + self.check_unused_delims_expr(cx, arg, ctx, false, None, None, false); } return; } }; - self.check_unused_delims_expr(cx, &value, ctx, followed_by_block, left_pos, right_pos); + self.check_unused_delims_expr( + cx, + &value, + ctx, + followed_by_block, + left_pos, + right_pos, + is_kw, + ); } fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { @@ -794,7 +872,7 @@ trait UnusedDelimLint { None => UnusedDelimsCtx::AssignedValue, Some(_) => UnusedDelimsCtx::AssignedValueLetElse, }; - self.check_unused_delims_expr(cx, init, ctx, false, None, None); + self.check_unused_delims_expr(cx, init, ctx, false, None, None, false); } } StmtKind::Expr(ref expr) => { @@ -805,6 +883,7 @@ trait UnusedDelimLint { false, None, None, + false, ); } _ => {} @@ -824,6 +903,7 @@ trait UnusedDelimLint { false, None, None, + false, ); } } @@ -879,6 +959,7 @@ impl UnusedDelimLint for UnusedParens { followed_by_block: bool, left_pos: Option<BytePos>, right_pos: Option<BytePos>, + is_kw: bool, ) { match value.kind { ast::ExprKind::Paren(ref inner) => { @@ -893,7 +974,7 @@ impl UnusedDelimLint for UnusedParens { _, ) if node.lazy())) { - self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos) + self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw) } } ast::ExprKind::Let(_, ref expr, _) => { @@ -904,6 +985,7 @@ impl UnusedDelimLint for UnusedParens { followed_by_block, None, None, + false, ); } _ => {} @@ -942,7 +1024,7 @@ impl UnusedParens { .span .find_ancestor_inside(value.span) .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))); - self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space); + self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false); } } } @@ -967,6 +1049,7 @@ impl EarlyLintPass for UnusedParens { true, None, None, + true, ); for stmt in &block.stmts { <Self as UnusedDelimLint>::check_stmt(self, cx, stmt); @@ -985,6 +1068,7 @@ impl EarlyLintPass for UnusedParens { false, None, None, + true, ); } } @@ -1043,6 +1127,7 @@ impl EarlyLintPass for UnusedParens { false, None, None, + false, ); } ast::TyKind::Paren(r) => { @@ -1057,7 +1142,7 @@ impl EarlyLintPass for UnusedParens { .find_ancestor_inside(ty.span) .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))); - self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); } } self.with_self_ty_parens = false; @@ -1130,6 +1215,7 @@ impl UnusedDelimLint for UnusedBraces { followed_by_block: bool, left_pos: Option<BytePos>, right_pos: Option<BytePos>, + is_kw: bool, ) { match value.kind { ast::ExprKind::Block(ref inner, None) @@ -1170,7 +1256,7 @@ impl UnusedDelimLint for UnusedBraces { && !value.span.from_expansion() && !inner.span.from_expansion() { - self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos) + self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw) } } } @@ -1183,6 +1269,7 @@ impl UnusedDelimLint for UnusedBraces { followed_by_block, None, None, + false, ); } _ => {} @@ -1207,6 +1294,7 @@ impl EarlyLintPass for UnusedBraces { false, None, None, + false, ); } } @@ -1220,6 +1308,7 @@ impl EarlyLintPass for UnusedBraces { false, None, None, + false, ); } } @@ -1233,6 +1322,7 @@ impl EarlyLintPass for UnusedBraces { false, None, None, + false, ); } } @@ -1247,6 +1337,7 @@ impl EarlyLintPass for UnusedBraces { false, None, None, + false, ); } @@ -1258,6 +1349,7 @@ impl EarlyLintPass for UnusedBraces { false, None, None, + false, ); } |