From 218caa410aa38c29984be31a5229b9fa717560ee Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:13 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_lint/src/unused.rs | 299 +++++++++++++++++++------------------- 1 file changed, 151 insertions(+), 148 deletions(-) (limited to 'compiler/rustc_lint/src/unused.rs') diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index b5db94f8c..4c9b3df2d 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,9 +1,14 @@ +use crate::lints::{ + PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag, + UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDelim, UnusedDelimSuggestion, + UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult, +}; use crate::Lint; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; -use rustc_errors::{fluent, pluralize, Applicability, MultiSpan}; +use rustc_errors::{pluralize, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -96,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind && let ty = cx.typeck_results().expr_ty(&await_expr) - && let ty::Opaque(future_def_id, _) = ty.kind() + && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind() && cx.tcx.ty_is_opaque_future(ty) // FIXME: This also includes non-async fns that return `impl Future`. && let async_fn_def_id = cx.tcx.parent(*future_def_id) @@ -163,23 +168,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let mut op_warned = false; if let Some(must_use_op) = must_use_op { - cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| { - lint.set_arg("op", must_use_op) - .span_label(expr.span, fluent::label) - .span_suggestion_verbose( - expr.span.shrink_to_lo(), - fluent::suggestion, - "let _ = ", - Applicability::MachineApplicable, - ) - }); + cx.emit_spanned_lint( + UNUSED_MUST_USE, + expr.span, + UnusedOp { + op: must_use_op, + label: expr.span, + suggestion: expr.span.shrink_to_lo(), + }, + ); op_warned = true; } if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) { - cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| { - lint.set_arg("ty", ty) - }); + cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty }); } fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { @@ -251,12 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .map(|inner| MustUsePath::Boxed(Box::new(inner))) } ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), - ty::Opaque(def, _) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { elaborate_predicates_with_span( cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned(), ) - .filter_map(|obligation| { + .find_map(|obligation| { // 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, @@ -270,22 +272,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } }) .map(|inner| MustUsePath::Opaque(Box::new(inner))) - .next() } - ty::Dynamic(binders, _, _) => binders - .iter() - .filter_map(|predicate| { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = - predicate.skip_binder() - { - let def_id = trait_ref.def_id; - is_def_must_use(cx, def_id, span) - } else { - None - } - .map(|inner| MustUsePath::TraitObject(Box::new(inner))) - }) - .next(), + ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() + { + let def_id = trait_ref.def_id; + is_def_must_use(cx, def_id, span) + .map(|inner| MustUsePath::TraitObject(Box::new(inner))) + } else { + None + } + }), ty::Tuple(tys) => { let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind { debug_assert_eq!(elem_exprs.len(), tys.len()); @@ -407,47 +404,31 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Closure(span) => { - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_MUST_USE, *span, - fluent::lint_unused_closure, - |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the - // pre/post strings - lint.set_arg("count", plural_len) - .set_arg("pre", descr_pre) - .set_arg("post", descr_post) - .note(fluent::note) - }, + UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Generator(span) => { - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_MUST_USE, *span, - fluent::lint_unused_generator, - |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the - // pre/post strings - lint.set_arg("count", plural_len) - .set_arg("pre", descr_pre) - .set_arg("post", descr_post) - .note(fluent::note) - }, + UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Def(span, def_id, reason) => { - cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the pre/post - // strings - lint.set_arg("pre", descr_pre); - lint.set_arg("post", descr_post); - lint.set_arg("def", cx.tcx.def_path_str(*def_id)); - if let Some(note) = reason { - lint.note(note.as_str()); - } - lint - }); + cx.emit_spanned_lint( + UNUSED_MUST_USE, + *span, + UnusedDef { + pre: descr_pre, + post: descr_post, + cx, + def_id: *def_id, + note: *reason, + }, + ); } } } @@ -483,31 +464,15 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { if let hir::ExprKind::Path(_) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); if ty.needs_drop(cx.tcx, cx.param_env) { - cx.struct_span_lint( - PATH_STATEMENTS, - s.span, - fluent::lint_path_statement_drop, - |lint| { - if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { - lint.span_suggestion( - s.span, - fluent::suggestion, - format!("drop({});", snippet), - Applicability::MachineApplicable, - ); - } else { - lint.span_help(s.span, fluent::suggestion); - } - lint - }, - ); + let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) + { + PathStatementDropSub::Suggestion { span: s.span, snippet } + } else { + PathStatementDropSub::Help { span: s.span } + }; + cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub }) } else { - cx.struct_span_lint( - PATH_STATEMENTS, - s.span, - fluent::lint_path_statement_no_effect, - |lint| lint, - ); + cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect); } } } @@ -617,7 +582,10 @@ trait UnusedDelimLint { lhs_needs_parens || (followed_by_block && match &inner.kind { - ExprKind::Ret(_) | ExprKind::Break(..) | ExprKind::Yield(..) => true, + ExprKind::Ret(_) + | ExprKind::Break(..) + | ExprKind::Yield(..) + | ExprKind::Yeet(..) => true, ExprKind::Range(_lhs, Some(rhs), _limits) => { matches!(rhs.kind, ExprKind::Block(..)) } @@ -697,36 +665,35 @@ trait UnusedDelimLint { } else { MultiSpan::from(value_span) }; - cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| { - lint.set_arg("delim", Self::DELIM_STR); - lint.set_arg("item", msg); - if let Some((lo, hi)) = spans { - let sm = cx.sess().source_map(); - let lo_replace = + let suggestion = spans.map(|(lo, hi)| { + let sm = cx.sess().source_map(); + let lo_replace = if keep_space.0 && let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') { - " ".to_string() + " " } else { - "".to_string() + "" }; - let hi_replace = + let hi_replace = if keep_space.1 && let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') { - " ".to_string() + " " } else { - "".to_string() + "" }; - - let replacement = vec![(lo, lo_replace), (hi, hi_replace)]; - lint.multipart_suggestion( - fluent::suggestion, - replacement, - Applicability::MachineApplicable, - ); + UnusedDelimSuggestion { + start_span: lo, + start_replace: lo_replace, + end_span: hi, + end_replace: hi_replace, } - lint }); + cx.emit_spanned_lint( + self.lint(), + primary_span, + UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion }, + ); } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { @@ -857,7 +824,17 @@ declare_lint! { "`if`, `match`, `while` and `return` do not need parentheses" } -declare_lint_pass!(UnusedParens => [UNUSED_PARENS]); +pub struct UnusedParens { + with_self_ty_parens: bool, +} + +impl UnusedParens { + pub fn new() -> Self { + Self { with_self_ty_parens: false } + } +} + +impl_lint_pass!(UnusedParens => [UNUSED_PARENS]); impl UnusedDelimLint for UnusedParens { const DELIM_STR: &'static str = "parentheses"; @@ -946,6 +923,7 @@ impl UnusedParens { } impl EarlyLintPass for UnusedParens { + #[inline] fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { match e.kind { ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => { @@ -1031,36 +1009,58 @@ impl EarlyLintPass for UnusedParens { } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { - if let ast::TyKind::Paren(r) = &ty.kind { - match &r.kind { - ast::TyKind::TraitObject(..) => {} - ast::TyKind::BareFn(b) if b.generic_params.len() > 0 => {} - ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} - ast::TyKind::Array(_, len) => { - self.check_unused_delims_expr( - cx, - &len.value, - UnusedDelimsCtx::ArrayLenExpr, - false, - None, - None, - ); - } - _ => { - let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { - Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) - } else { - None - }; - self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); + match &ty.kind { + ast::TyKind::Array(_, len) => { + self.check_unused_delims_expr( + cx, + &len.value, + UnusedDelimsCtx::ArrayLenExpr, + false, + None, + None, + ); + } + ast::TyKind::Paren(r) => { + match &r.kind { + ast::TyKind::TraitObject(..) => {} + ast::TyKind::BareFn(b) + if self.with_self_ty_parens && b.generic_params.len() > 0 => {} + ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} + _ => { + let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { + Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) + } else { + None + }; + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); + } } + self.with_self_ty_parens = false; } + _ => {} } } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { ::check_item(self, cx, item) } + + fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) { + use rustc_ast::{WhereBoundPredicate, WherePredicate}; + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + bounded_ty, + bound_generic_params, + .. + }) = pred && + let ast::TyKind::Paren(_) = &bounded_ty.kind && + bound_generic_params.is_empty() { + self.with_self_ty_parens = true; + } + } + + fn exit_where_predicate(&mut self, _: &EarlyContext<'_>, _: &ast::WherePredicate) { + assert!(!self.with_self_ty_parens); + } } declare_lint! { @@ -1127,17 +1127,23 @@ impl UnusedDelimLint for UnusedBraces { // ``` // - the block has no attribute and was not created inside a macro // - if the block is an `anon_const`, the inner expr must be a literal - // (do not lint `struct A; let _: A<{ 2 + 3 }>;`) - // + // not created by a macro, i.e. do not lint on: + // ``` + // struct A; + // let _: A<{ 2 + 3 }>; + // let _: A<{produces_literal!()}>; + // ``` // FIXME(const_generics): handle paths when #67075 is fixed. if let [stmt] = inner.stmts.as_slice() { if let ast::StmtKind::Expr(ref expr) = stmt.kind { if !Self::is_expr_delims_necessary(expr, followed_by_block, false) && (ctx != UnusedDelimsCtx::AnonConst - || matches!(expr.kind, ast::ExprKind::Lit(_))) + || (matches!(expr.kind, ast::ExprKind::Lit(_)) + && !expr.span.from_expansion())) && !cx.sess().source_map().is_multiline(value.span) && value.attrs.is_empty() && !value.span.from_expansion() + && !inner.span.from_expansion() { self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos) } @@ -1164,6 +1170,7 @@ impl EarlyLintPass for UnusedBraces { ::check_stmt(self, cx, s) } + #[inline] fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { ::check_expr(self, cx, e); @@ -1274,7 +1281,7 @@ impl UnusedImportBraces { fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) { if let ast::UseTreeKind::Nested(ref items) = use_tree.kind { // Recursively check nested UseTrees - for &(ref tree, _) in items { + for (tree, _) in items { self.check_use_tree(cx, tree, item); } @@ -1296,11 +1303,10 @@ impl UnusedImportBraces { ast::UseTreeKind::Nested(_) => return, }; - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_IMPORT_BRACES, item.span, - fluent::lint_unused_import_braces, - |lint| lint.set_arg("node", node_name), + UnusedImportBracesDiag { node: node_name }, ); } } @@ -1350,17 +1356,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { for adj in cx.typeck_results().expr_adjustments(e) { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { - cx.struct_span_lint( - UNUSED_ALLOCATION, - e.span, - match m { - adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation, - adjustment::AutoBorrowMutability::Mut { .. } => { - fluent::lint_unused_allocation_mut - } - }, - |lint| lint, - ); + match m { + adjustment::AutoBorrowMutability::Not => { + cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag); + } + adjustment::AutoBorrowMutability::Mut { .. } => { + cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag); + } + }; } } } -- cgit v1.2.3