From 53fc7fbc9606ba8b29e674ab08c3ccf1ebfd128d Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 26 Jul 2019 19:52:37 -0300 Subject: [PATCH] Lint attributes on function arguments --- src/librustc/hir/intravisit.rs | 15 +- src/librustc/hir/lowering.rs | 43 ++++- src/librustc/hir/map/collector.rs | 8 + src/librustc/hir/map/mod.rs | 7 + src/librustc/hir/mod.rs | 5 +- src/librustc/hir/print.rs | 5 + src/librustc/lint/context.rs | 14 ++ src/librustc/lint/mod.rs | 10 +- src/librustc_mir/build/mod.rs | 47 ++++- src/librustc_passes/hir_stats.rs | 5 + src/librustc_typeck/check/_match.rs | 25 ++- src/librustc_typeck/check/demand.rs | 82 ++++---- src/libsyntax/ast.rs | 2 + src/libsyntax/ext/build.rs | 1 + src/libsyntax/mut_visit.rs | 3 +- src/libsyntax/parse/diagnostics.rs | 2 +- src/libsyntax/parse/parser.rs | 8 +- src/libsyntax/visit.rs | 15 +- src/test/ui/lint/lint-unused-mut-variables.rs | 64 ++++++- .../ui/lint/lint-unused-mut-variables.stderr | 112 ++++++++--- src/test/ui/lint/lint-unused-variables.rs | 64 +++++++ src/test/ui/lint/lint-unused-variables.stderr | 56 ++++++ .../ui/mismatched_types/issue-38371.stderr | 6 +- .../param-attrs-allowed.rs | 179 +++--------------- .../rfc-2565-param-attrs/param-attrs-cfg.rs | 40 ++-- .../param-attrs-cfg.stderr | 46 +++-- .../param-attrs-feature-gate.rs | 4 +- .../param-attrs-feature-gate.stderr | 10 +- 28 files changed, 586 insertions(+), 292 deletions(-) create mode 100644 src/test/ui/lint/lint-unused-variables.rs create mode 100644 src/test/ui/lint/lint-unused-variables.stderr diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2d82314f86ac2..3781d7df1764c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -210,6 +210,10 @@ pub trait Visitor<'v> : Sized { } } + fn visit_arg(&mut self, arg: &'v Arg) { + walk_arg(self, arg) + } + /// Visits the top-level item and (optionally) nested items / impl items. See /// `visit_nested_item` for details. fn visit_item(&mut self, i: &'v Item) { @@ -396,10 +400,7 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_hir_id } pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { - for argument in &body.arguments { - visitor.visit_id(argument.hir_id); - visitor.visit_pat(&argument.pat); - } + walk_list!(visitor, visit_arg, &body.arguments); visitor.visit_expr(&body.value); } @@ -452,6 +453,12 @@ pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id) } +pub fn walk_arg<'v, V: Visitor<'v>>(visitor: &mut V, arg: &'v Arg) { + visitor.visit_id(arg.hir_id); + visitor.visit_pat(&arg.pat); + walk_list!(visitor, visit_attribute, &arg.attrs); +} + pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.ident); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 288fd2714e251..e1fc61b82546e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2461,8 +2461,10 @@ impl<'a> LoweringContext<'a> { fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { hir::Arg { + attrs: self.lower_attrs(&arg.attrs), hir_id: self.lower_node_id(arg.id), pat: self.lower_pat(&arg.pat), + span: arg.span, } } @@ -3279,19 +3281,29 @@ impl<'a> LoweringContext<'a> { // // If this is the simple case, this argument will end up being the same as the // original argument, but with a different pattern id. + let mut stmt_attrs = ThinVec::new(); + stmt_attrs.extend(argument.attrs.iter().cloned()); let (new_argument_pat, new_argument_id) = this.pat_ident(desugared_span, ident); let new_argument = hir::Arg { + attrs: argument.attrs, hir_id: argument.hir_id, pat: new_argument_pat, + span: argument.span, }; + if is_simple_argument { // If this is the simple case, then we only insert one statement that is // `let = ;`. We re-use the original argument's pattern so that // `HirId`s are densely assigned. let expr = this.expr_ident(desugared_span, ident, new_argument_id); let stmt = this.stmt_let_pat( - desugared_span, Some(P(expr)), argument.pat, hir::LocalSource::AsyncFn); + stmt_attrs, + desugared_span, + Some(P(expr)), + argument.pat, + hir::LocalSource::AsyncFn + ); statements.push(stmt); } else { // If this is not the simple case, then we construct two statements: @@ -3313,14 +3325,23 @@ impl<'a> LoweringContext<'a> { desugared_span, ident, hir::BindingAnnotation::Mutable); let move_expr = this.expr_ident(desugared_span, ident, new_argument_id); let move_stmt = this.stmt_let_pat( - desugared_span, Some(P(move_expr)), move_pat, hir::LocalSource::AsyncFn); + ThinVec::new(), + desugared_span, + Some(P(move_expr)), + move_pat, + hir::LocalSource::AsyncFn + ); // Construct the `let = __argN;` statement. We re-use the original // argument's pattern so that `HirId`s are densely assigned. let pattern_expr = this.expr_ident(desugared_span, ident, move_id); let pattern_stmt = this.stmt_let_pat( - desugared_span, Some(P(pattern_expr)), argument.pat, - hir::LocalSource::AsyncFn); + stmt_attrs, + desugared_span, + Some(P(pattern_expr)), + argument.pat, + hir::LocalSource::AsyncFn + ); statements.push(move_stmt); statements.push(pattern_stmt); @@ -4910,6 +4931,7 @@ impl<'a> LoweringContext<'a> { // `let mut __next` let next_let = self.stmt_let_pat( + ThinVec::new(), desugared_span, None, next_pat, @@ -4919,6 +4941,7 @@ impl<'a> LoweringContext<'a> { // `let = __next` let pat = self.lower_pat(pat); let pat_let = self.stmt_let_pat( + ThinVec::new(), head_sp, Some(next_expr), pat, @@ -5413,19 +5436,20 @@ impl<'a> LoweringContext<'a> { fn stmt_let_pat( &mut self, + attrs: ThinVec, span: Span, init: Option>, pat: P, source: hir::LocalSource, ) -> hir::Stmt { let local = hir::Local { - pat, - ty: None, - init, + attrs, hir_id: self.next_id(), - span, + init, + pat, source, - attrs: ThinVec::new() + span, + ty: None, }; self.stmt(span, hir::StmtKind::Local(P(local))) } @@ -5831,6 +5855,7 @@ impl<'a> LoweringContext<'a> { hir::BindingAnnotation::Mutable, ); let pinned_let = self.stmt_let_pat( + ThinVec::new(), span, Some(expr), pinned_pat, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 12ea772c1fb31..b6807f7d3bbd2 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -363,6 +363,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.currently_in_body = prev_in_body; } + fn visit_arg(&mut self, arg: &'hir Arg) { + let node = Node::Arg(arg); + self.insert(arg.pat.span, arg.hir_id, node); + self.with_parent(arg.hir_id, |this| { + intravisit::walk_arg(this, arg); + }); + } + fn visit_item(&mut self, i: &'hir Item) { debug!("visit_item: {:?}", i); debug_assert_eq!(i.hir_id.owner, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 43b1dbb6216d7..5a28d9e7b7db6 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -360,6 +360,7 @@ impl<'hir> Map<'hir> { Node::Pat(_) | Node::Binding(_) | Node::Local(_) | + Node::Arg(_) | Node::Arm(_) | Node::Lifetime(_) | Node::Visibility(_) | @@ -932,6 +933,7 @@ impl<'hir> Map<'hir> { pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { self.read(id); // reveals attributes on the node let attrs = match self.find_entry(id).map(|entry| entry.node) { + Some(Node::Arg(a)) => Some(&a.attrs[..]), Some(Node::Local(l)) => Some(&l.attrs[..]), Some(Node::Item(i)) => Some(&i.attrs[..]), Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), @@ -995,6 +997,7 @@ impl<'hir> Map<'hir> { pub fn span(&self, hir_id: HirId) -> Span { self.read(hir_id); // reveals span from node match self.find_entry(hir_id).map(|entry| entry.node) { + Some(Node::Arg(arg)) => arg.span, Some(Node::Item(item)) => item.span, Some(Node::ForeignItem(foreign_item)) => foreign_item.span, Some(Node::TraitItem(trait_method)) => trait_method.span, @@ -1197,6 +1200,7 @@ impl<'hir> print::PpAnn for Map<'hir> { impl<'a> print::State<'a> { pub fn print_node(&mut self, node: Node<'_>) { match node { + Node::Arg(a) => self.print_arg(&a), Node::Item(a) => self.print_item(&a), Node::ForeignItem(a) => self.print_foreign_item(&a), Node::TraitItem(a) => self.print_trait_item(a), @@ -1338,6 +1342,9 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { Some(Node::Pat(_)) => { format!("pat {}{}", map.hir_to_pretty_string(id), id_str) } + Some(Node::Arg(_)) => { + format!("arg {}{}", map.hir_to_pretty_string(id), id_str) + } Some(Node::Arm(_)) => { format!("arm {}{}", map.hir_to_pretty_string(id), id_str) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e7b37d40b4b2f..821585da4ebb2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2010,8 +2010,10 @@ pub struct InlineAsm { /// Represents an argument in a function header. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct Arg { - pub pat: P, + pub attrs: HirVec, pub hir_id: HirId, + pub pat: P, + pub span: Span, } /// Represents the header (not the body) of a function declaration. @@ -2701,6 +2703,7 @@ impl CodegenFnAttrs { #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { + Arg(&'hir Arg), Item(&'hir Item), ForeignItem(&'hir ForeignItem), TraitItem(&'hir TraitItem), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 3e571baaa4e51..9f6be0a9290e6 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1767,6 +1767,11 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } + pub fn print_arg(&mut self, arg: &hir::Arg) { + self.print_outer_attributes(&arg.attrs); + self.print_pat(&arg.pat); + } + pub fn print_arm(&mut self, arm: &hir::Arm) { // I have no idea why this check is necessary, but here it // is :( diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 2930f7690dd8e..597ea8e8e5fb7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -966,6 +966,13 @@ for LateContextAndPass<'a, 'tcx, T> { self.context.tables = old_tables; } + fn visit_arg(&mut self, arg: &'tcx hir::Arg) { + self.with_lint_attrs(arg.hir_id, &arg.attrs, |cx| { + lint_callback!(cx, check_arg, arg); + hir_visit::walk_arg(cx, arg); + }); + } + fn visit_body(&mut self, body: &'tcx hir::Body) { lint_callback!(self, check_body, body); hir_visit::walk_body(self, body); @@ -1156,6 +1163,13 @@ for LateContextAndPass<'a, 'tcx, T> { } impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> { + fn visit_arg(&mut self, arg: &'a ast::Arg) { + self.with_lint_attrs(arg.id, &arg.attrs, |cx| { + run_early_pass!(cx, check_arg, arg); + ast_visit::walk_arg(cx, arg); + }); + } + fn visit_item(&mut self, it: &'a ast::Item) { self.with_lint_attrs(it.id, &it.attrs, |cx| { run_early_pass!(cx, check_item, it); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index dddbc31ccd4ea..8ddf4603490a1 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -206,6 +206,7 @@ macro_rules! declare_lint_pass { macro_rules! late_lint_methods { ($macro:path, $args:tt, [$hir:tt]) => ( $macro!($args, [$hir], [ + fn check_arg(a: &$hir hir::Arg); fn check_body(a: &$hir hir::Body); fn check_body_post(a: &$hir hir::Body); fn check_name(a: Span, b: ast::Name); @@ -358,6 +359,7 @@ macro_rules! declare_combined_late_lint_pass { macro_rules! early_lint_methods { ($macro:path, $args:tt) => ( $macro!($args, [ + fn check_arg(a: &ast::Arg); fn check_ident(a: ast::Ident); fn check_crate(a: &ast::Crate); fn check_crate_post(a: &ast::Crate); @@ -495,8 +497,6 @@ pub type EarlyLintPassObject = Box LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>; - - /// Identifies a lint known to the compiler. #[derive(Clone, Copy, Debug)] pub struct LintId { @@ -812,6 +812,12 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } + fn visit_arg(&mut self, arg: &'tcx hir::Arg) { + self.with_lint_attrs(arg.hir_id, &arg.attrs, |builder| { + intravisit::walk_arg(builder, arg); + }); + } + fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(it.hir_id, &it.attrs, |builder| { intravisit::walk_item(builder, it); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 8948d1c4b3663..4e970aee42cf4 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -121,7 +121,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { self_arg = None; } - ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg) + ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&arg), self_arg) }); let arguments = implicit_argument.into_iter().chain(explicit_arguments); @@ -511,7 +511,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, abi: Abi) -> bool { /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Pat>, Option); +struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Arg>, Option); fn construct_fn<'a, 'tcx, A>( hir: Cx<'a, 'tcx>, @@ -782,13 +782,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { -> BlockAnd<()> { // Allocate locals for the function arguments - for &ArgInfo(ty, _, pattern, _) in arguments.iter() { + for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { // If this is a simple binding pattern, give the local a name for // debuginfo and so that error reporting knows that this is a user // variable. For any other pattern the pattern introduces new // variables which will be named instead. - let (name, span) = if let Some(pat) = pattern { - (pat.simple_ident().map(|ident| ident.name), pat.span) + let (name, span) = if let Some(arg) = arg_opt { + (arg.pat.simple_ident().map(|ident| ident.name), arg.pat.span) } else { (None, self.fn_span) }; @@ -813,18 +813,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Function arguments always get the first Local indices after the return place let local = Local::new(index + 1); let place = Place::from(local); - let &ArgInfo(ty, opt_ty_info, pattern, ref self_binding) = arg_info; + let &ArgInfo(ty, opt_ty_info, arg_opt, ref self_binding) = arg_info; // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( - pattern.as_ref().map_or(ast_body.span, |pat| pat.span), + arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span), argument_scope, local, ty, DropKind::Value, ); - if let Some(pattern) = pattern { - let pattern = self.hir.pattern_from_hir(pattern); + if let Some(arg) = arg_opt { + let pattern = self.hir.pattern_from_hir(&arg.pat); + let original_source_scope = self.source_scope; let span = pattern.span; - + self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); match *pattern.kind { // Don't introduce extra copies for simple bindings PatternKind::Binding { @@ -835,6 +836,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .. } => { self.local_decls[local].mutability = mutability; + self.local_decls[local].source_info.scope = self.source_scope; self.local_decls[local].is_user_variable = if let Some(kind) = self_binding { Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind))) @@ -860,6 +862,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unpack!(block = self.place_into_pattern(block, pattern, &place, false)); } } + self.source_scope = original_source_scope; } } @@ -872,6 +875,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.into(&Place::RETURN_PLACE, block, body) } + fn set_correct_source_scope_for_arg( + &mut self, + arg_hir_id: hir::HirId, + original_source_scope: SourceScope, + pattern_span: Span + ) { + let tcx = self.hir.tcx(); + let current_root = tcx.maybe_lint_level_root_bounded( + arg_hir_id, + self.hir.root_lint_level + ); + let parent_root = tcx.maybe_lint_level_root_bounded( + self.source_scope_local_data[original_source_scope].lint_root, + self.hir.root_lint_level, + ); + if current_root != parent_root { + self.source_scope = self.new_source_scope( + pattern_span, + LintLevel::Explicit(current_root), + None + ); + } + } + fn get_unit_temp(&mut self) -> Place<'tcx> { match self.unit_temp { Some(ref tmp) => tmp.clone(), diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index e7f6abc410a32..8fba3256ec429 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -94,6 +94,11 @@ impl<'k> StatCollector<'k> { } impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { + fn visit_arg(&mut self, arg: &'v hir::Arg) { + self.record("Arg", Id::Node(arg.hir_id), arg); + hir_visit::walk_arg(self, arg) + } + fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> { panic!("visit_nested_xxx must be manually implemented in this visitor") } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index de42a6a35c89a..c8983fef2de57 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -551,21 +551,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let tcx = self.tcx; if let PatKind::Binding(..) = inner.node { - let parent_id = tcx.hir().get_parent_node(pat.hir_id); - let parent = tcx.hir().get(parent_id); - debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); - match parent { - hir::Node::Item(hir::Item { node: hir::ItemKind::Fn(..), .. }) | - hir::Node::ForeignItem(hir::ForeignItem { - node: hir::ForeignItemKind::Fn(..), .. - }) | - hir::Node::TraitItem(hir::TraitItem { node: hir::TraitItemKind::Method(..), .. }) | - hir::Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { - // this pat is likely an argument + let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id); + let binding_parent = tcx.hir().get(binding_parent_id); + debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent); + match binding_parent { + hir::Node::Arg(hir::Arg { span, .. }) => { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { - // FIXME: turn into structured suggestion, will need a span that also - // includes the the arg's type. - err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); + err.span_suggestion( + *span, + &format!("did you mean `{}`", snippet), + format!(" &{}", expected), + Applicability::MachineApplicable, + ); } } hir::Node::Arm(_) | diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 14c38ae053d23..3229d49841e79 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -235,40 +235,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &hir::Expr, ) -> Option<(Span, &'static str, String)> { - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.node { - if let hir::def::Res::Local(id) = path.res { - let parent = self.tcx.hir().get_parent_node(id); - if let Some(Node::Expr(hir::Expr { - hir_id, - node: hir::ExprKind::Closure(_, decl, ..), - .. - })) = self.tcx.hir().find(parent) { - let parent = self.tcx.hir().get_parent_node(*hir_id); - if let (Some(Node::Expr(hir::Expr { - node: hir::ExprKind::MethodCall(path, span, expr), - .. - })), 1) = (self.tcx.hir().find(parent), decl.inputs.len()) { - let self_ty = self.tables.borrow().node_type(expr[0].hir_id); - let self_ty = format!("{:?}", self_ty); - let name = path.ident.as_str(); - let is_as_ref_able = ( - self_ty.starts_with("&std::option::Option") || - self_ty.starts_with("&std::result::Result") || - self_ty.starts_with("std::option::Option") || - self_ty.starts_with("std::result::Result") - ) && (name == "map" || name == "and_then"); - match (is_as_ref_able, self.sess().source_map().span_to_snippet(*span)) { - (true, Ok(src)) => { - return Some((*span, "consider using `as_ref` instead", - format!("as_ref().{}", src))); - }, - _ => () - } - } - } - } + let path = match expr.node { + hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => path, + _ => return None + }; + + let local_id = match path.res { + hir::def::Res::Local(id) => id, + _ => return None + }; + + let local_parent = self.tcx.hir().get_parent_node(local_id); + let arg_hir_id = match self.tcx.hir().find(local_parent) { + Some(Node::Arg(hir::Arg { hir_id, .. })) => hir_id, + _ => return None + }; + + let arg_parent = self.tcx.hir().get_parent_node(*arg_hir_id); + let (expr_hir_id, closure_fn_decl) = match self.tcx.hir().find(arg_parent) { + Some(Node::Expr( + hir::Expr { hir_id, node: hir::ExprKind::Closure(_, decl, ..), .. } + )) => (hir_id, decl), + _ => return None + }; + + let expr_parent = self.tcx.hir().get_parent_node(*expr_hir_id); + let hir = self.tcx.hir().find(expr_parent); + let closure_params_len = closure_fn_decl.inputs.len(); + let (method_path, method_span, method_expr) = match (hir, closure_params_len) { + (Some(Node::Expr( + hir::Expr { node: hir::ExprKind::MethodCall(path, span, expr), .. } + )), 1) => (path, span, expr), + _ => return None + }; + + let self_ty = self.tables.borrow().node_type(method_expr[0].hir_id); + let self_ty = format!("{:?}", self_ty); + let name = method_path.ident.as_str(); + let is_as_ref_able = ( + self_ty.starts_with("&std::option::Option") || + self_ty.starts_with("&std::result::Result") || + self_ty.starts_with("std::option::Option") || + self_ty.starts_with("std::result::Result") + ) && (name == "map" || name == "and_then"); + match (is_as_ref_able, self.sess().source_map().span_to_snippet(*method_span)) { + (true, Ok(src)) => { + let suggestion = format!("as_ref().{}", src); + Some((*method_span, "consider using `as_ref` instead", suggestion)) + }, + _ => None } - None } crate fn is_hir_id_from_struct_pattern_shorthand_field( diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index b9b43c89346c7..471a657c82ae0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1776,6 +1776,7 @@ pub struct Arg { pub ty: P, pub pat: P, pub id: NodeId, + pub span: Span, } /// Alternative representation for `Arg`s describing `self` parameter of methods. @@ -1834,6 +1835,7 @@ impl Arg { node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), span, }), + span, ty, id: DUMMY_NODE_ID, }; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index baf1031de1e7c..e1f8310ee8d03 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -966,6 +966,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat: arg_pat, + span, ty, } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index dc656222fbc10..23dfad32911ed 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -558,10 +558,11 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { attrs, id, pat, ty }: &mut Arg, vis: &mut T) { +pub fn noop_visit_arg(Arg { attrs, id, pat, span, ty }: &mut Arg, vis: &mut T) { vis.visit_id(id); visit_thin_attrs(attrs, vis); vis.visit_pat(pat); + vis.visit_span(span); vis.visit_ty(ty); } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index f4fc87506f357..39cb5042fbc11 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -30,7 +30,7 @@ crate fn dummy_arg(ident: Ident) -> Arg { span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, ty: P(ty) } + Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) } } pub enum Error { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index da38869463737..ed4cb405fe74b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1502,6 +1502,7 @@ impl<'a> Parser<'a> { where F: Fn(&token::Token) -> bool { + let lo = self.token.span; let attrs = self.parse_arg_attributes()?; if let Some(mut arg) = self.parse_self_arg()? { arg.attrs = attrs.into(); @@ -1565,11 +1566,14 @@ impl<'a> Parser<'a> { } }; - Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, ty }) + let span = lo.to(self.token.span); + + Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, span, ty }) } /// Parses an argument in a lambda header (e.g., `|arg, arg|`). fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { + let lo = self.token.span; let attrs = self.parse_arg_attributes()?; let pat = self.parse_pat(Some("argument name"))?; let t = if self.eat(&token::Colon) { @@ -1581,10 +1585,12 @@ impl<'a> Parser<'a> { span: self.prev_span, }) }; + let span = lo.to(self.token.span); Ok(Arg { attrs: attrs.into(), ty: t, pat, + span, id: ast::DUMMY_NODE_ID }) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9ec9550f93ab9..5fc8bdb608e47 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -66,6 +66,7 @@ pub trait Visitor<'ast>: Sized { fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } fn visit_stmt(&mut self, s: &'ast Stmt) { walk_stmt(self, s) } + fn visit_arg(&mut self, arg: &'ast Arg) { walk_arg(self, arg) } fn visit_arm(&mut self, a: &'ast Arm) { walk_arm(self, a) } fn visit_pat(&mut self, p: &'ast Pat) { walk_pat(self, p) } fn visit_anon_const(&mut self, c: &'ast AnonConst) { walk_anon_const(self, c) } @@ -549,12 +550,10 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR } pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { - for argument in &function_declaration.inputs { - walk_list!(visitor, visit_attribute, argument.attrs.iter()); - visitor.visit_pat(&argument.pat); - visitor.visit_ty(&argument.ty); + for arg in &function_declaration.inputs { + visitor.visit_arg(arg); } - visitor.visit_fn_ret_ty(&function_declaration.output) + visitor.visit_fn_ret_ty(&function_declaration.output); } pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl, _span: Span) @@ -824,6 +823,12 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr_post(expression) } +pub fn walk_arg<'a, V: Visitor<'a>>(visitor: &mut V, arg: &'a Arg) { + walk_list!(visitor, visit_attribute, arg.attrs.iter()); + visitor.visit_pat(&arg.pat); + visitor.visit_ty(&arg.ty); +} + pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { walk_list!(visitor, visit_pat, &arm.pats); if let Some(ref e) = &arm.guard { diff --git a/src/test/ui/lint/lint-unused-mut-variables.rs b/src/test/ui/lint/lint-unused-mut-variables.rs index 78609a6e24b5e..2957f93111051 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.rs +++ b/src/test/ui/lint/lint-unused-mut-variables.rs @@ -1,12 +1,70 @@ +// edition:2018 + // Exercise the unused_mut attribute in some positive and negative cases -#![allow(unused_assignments)] -#![allow(unused_variables)] -#![allow(dead_code)] #![deny(unused_mut)] +#![feature(async_await, async_closure, param_attrs)] + +async fn baz_async( + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, +) {} +fn baz( + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, + #[allow(unused_mut)] (mut c, d): (i32, i32) +) {} + +struct RefStruct {} +impl RefStruct { + async fn baz_async( + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, + ) {} + fn baz( + &self, + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, + #[allow(unused_mut)] (mut c, d): (i32, i32) + ) {} +} +trait RefTrait { + fn baz( + &self, + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, + #[allow(unused_mut)] (mut c, d): (i32, i32) + ) {} +} +impl RefTrait for () { + fn baz( + &self, + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, + #[allow(unused_mut)] (mut c, d): (i32, i32) + ) {} +} fn main() { + let _ = async move | + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, + | {}; + let _ = | + mut a: i32, + //~^ ERROR: variable does not need to be mutable + #[allow(unused_mut)] mut b: i32, + #[allow(unused_mut)] (mut c, d): (i32, i32) + | {}; + // negative cases let mut a = 3; //~ ERROR: variable does not need to be mutable diff --git a/src/test/ui/lint/lint-unused-mut-variables.stderr b/src/test/ui/lint/lint-unused-mut-variables.stderr index 1a175c9683ec7..92c2b68652dc2 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.stderr +++ b/src/test/ui/lint/lint-unused-mut-variables.stderr @@ -1,19 +1,83 @@ error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:46:14 + --> $DIR/lint-unused-mut-variables.rs:9:5 | -LL | let x = |mut y: isize| 10; - | ----^ - | | - | help: remove this `mut` +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` | note: lint level defined here - --> $DIR/lint-unused-mut-variables.rs:6:9 + --> $DIR/lint-unused-mut-variables.rs:5:9 | LL | #![deny(unused_mut)] | ^^^^^^^^^^ error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:11:9 + --> $DIR/lint-unused-mut-variables.rs:14:5 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:23:9 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:29:9 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:39:9 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:48:9 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:57:9 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:62:9 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:104:14 + | +LL | let x = |mut y: isize| 10; + | ----^ + | | + | help: remove this `mut` + +error: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:69:9 | LL | let mut a = 3; | ----^ @@ -21,7 +85,7 @@ LL | let mut a = 3; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:13:9 + --> $DIR/lint-unused-mut-variables.rs:71:9 | LL | let mut a = 2; | ----^ @@ -29,7 +93,7 @@ LL | let mut a = 2; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:15:9 + --> $DIR/lint-unused-mut-variables.rs:73:9 | LL | let mut b = 3; | ----^ @@ -37,7 +101,7 @@ LL | let mut b = 3; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:17:9 + --> $DIR/lint-unused-mut-variables.rs:75:9 | LL | let mut a = vec![3]; | ----^ @@ -45,7 +109,7 @@ LL | let mut a = vec![3]; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:19:10 + --> $DIR/lint-unused-mut-variables.rs:77:10 | LL | let (mut a, b) = (1, 2); | ----^ @@ -53,7 +117,7 @@ LL | let (mut a, b) = (1, 2); | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:21:9 + --> $DIR/lint-unused-mut-variables.rs:79:9 | LL | let mut a; | ----^ @@ -61,7 +125,7 @@ LL | let mut a; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:25:9 + --> $DIR/lint-unused-mut-variables.rs:83:9 | LL | let mut b; | ----^ @@ -69,7 +133,7 @@ LL | let mut b; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:34:9 + --> $DIR/lint-unused-mut-variables.rs:92:9 | LL | mut x => {} | ----^ @@ -77,7 +141,7 @@ LL | mut x => {} | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:38:8 + --> $DIR/lint-unused-mut-variables.rs:96:8 | LL | (mut x, 1) | | ----^ @@ -85,7 +149,7 @@ LL | (mut x, 1) | | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:51:9 + --> $DIR/lint-unused-mut-variables.rs:109:9 | LL | let mut a = &mut 5; | ----^ @@ -93,7 +157,7 @@ LL | let mut a = &mut 5; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:56:9 + --> $DIR/lint-unused-mut-variables.rs:114:9 | LL | let mut b = (&mut a,); | ----^ @@ -101,7 +165,7 @@ LL | let mut b = (&mut a,); | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:59:9 + --> $DIR/lint-unused-mut-variables.rs:117:9 | LL | let mut x = &mut 1; | ----^ @@ -109,7 +173,7 @@ LL | let mut x = &mut 1; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:71:9 + --> $DIR/lint-unused-mut-variables.rs:129:9 | LL | let mut v : &mut Vec<()> = &mut vec![]; | ----^ @@ -117,7 +181,7 @@ LL | let mut v : &mut Vec<()> = &mut vec![]; | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:48:13 + --> $DIR/lint-unused-mut-variables.rs:106:13 | LL | fn what(mut foo: isize) {} | ----^^^ @@ -125,7 +189,7 @@ LL | fn what(mut foo: isize) {} | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:66:20 + --> $DIR/lint-unused-mut-variables.rs:124:20 | LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { | ----^^^ @@ -133,7 +197,7 @@ LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:138:9 + --> $DIR/lint-unused-mut-variables.rs:196:9 | LL | let mut b = vec![2]; | ----^ @@ -141,10 +205,10 @@ LL | let mut b = vec![2]; | help: remove this `mut` | note: lint level defined here - --> $DIR/lint-unused-mut-variables.rs:134:8 + --> $DIR/lint-unused-mut-variables.rs:192:8 | LL | #[deny(unused_mut)] | ^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 25 previous errors diff --git a/src/test/ui/lint/lint-unused-variables.rs b/src/test/ui/lint/lint-unused-variables.rs new file mode 100644 index 0000000000000..a1660d2351123 --- /dev/null +++ b/src/test/ui/lint/lint-unused-variables.rs @@ -0,0 +1,64 @@ +// compile-flags: --cfg something +// edition:2018 + +#![feature(async_await, async_closure, param_attrs)] +#![deny(unused_variables)] + +async fn foo_async( + a: i32, + //~^ ERROR unused variable: `a` + #[allow(unused_variables)] b: i32, +) {} +fn foo( + #[allow(unused_variables)] a: i32, + b: i32, + //~^ ERROR unused variable: `b` +) {} + +struct RefStruct {} +impl RefStruct { + async fn bar_async( + &self, + a: i32, + //~^ ERROR unused variable: `a` + #[allow(unused_variables)] b: i32, + ) {} + fn bar( + &self, + #[allow(unused_variables)] a: i32, + b: i32, + //~^ ERROR unused variable: `b` + ) {} +} +trait RefTrait { + fn bar( + &self, + #[allow(unused_variables)] a: i32, + b: i32, + //~^ ERROR unused variable: `b` + ) {} +} +impl RefTrait for RefStruct { + fn bar( + &self, + #[allow(unused_variables)] a: i32, + b: i32, + //~^ ERROR unused variable: `b` + ) {} +} + +fn main() { + let _: fn(_, _) = foo; + let a = async move | + a: i32, + //~^ ERROR unused variable: `a` + #[allow(unused_variables)] b: i32, + | {}; + let b = | + #[allow(unused_variables)] a: i32, + b: i32, + //~^ ERROR unused variable: `b` + | {}; + let _ = a(1, 2); + let _ = b(1, 2); +} diff --git a/src/test/ui/lint/lint-unused-variables.stderr b/src/test/ui/lint/lint-unused-variables.stderr new file mode 100644 index 0000000000000..7ed5669e33c24 --- /dev/null +++ b/src/test/ui/lint/lint-unused-variables.stderr @@ -0,0 +1,56 @@ +error: unused variable: `a` + --> $DIR/lint-unused-variables.rs:8:5 + | +LL | a: i32, + | ^ help: consider prefixing with an underscore: `_a` + | +note: lint level defined here + --> $DIR/lint-unused-variables.rs:5:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: unused variable: `b` + --> $DIR/lint-unused-variables.rs:14:5 + | +LL | b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/lint-unused-variables.rs:53:9 + | +LL | a: i32, + | ^ help: consider prefixing with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/lint-unused-variables.rs:59:9 + | +LL | b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `b` + --> $DIR/lint-unused-variables.rs:37:9 + | +LL | b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/lint-unused-variables.rs:22:9 + | +LL | a: i32, + | ^ help: consider prefixing with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/lint-unused-variables.rs:29:9 + | +LL | b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `b` + --> $DIR/lint-unused-variables.rs:45:9 + | +LL | b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index a9347926bda0a..79a0807c33721 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -2,11 +2,13 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:4:8 | LL | fn foo(&foo: Foo) { - | ^^^^ expected struct `Foo`, found reference + | ^^^^------ + | | + | expected struct `Foo`, found reference + | help: did you mean `foo`: `&Foo` | = note: expected type `Foo` found type `&_` - = help: did you mean `foo: &Foo`? error[E0308]: mismatched types --> $DIR/issue-38371.rs:18:9 diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs index e796e37bbaa45..5eeda66173ded 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs @@ -1,189 +1,66 @@ +// check-pass // compile-flags: --cfg something -// build-pass (FIXME(62277): could be check-pass?) +#![deny(unused_mut)] #![feature(param_attrs)] extern "C" { fn ffi( - #[allow(C)] a: i32, + #[allow(unused_mut)] a: i32, #[cfg(something)] b: i32, #[cfg_attr(something, cfg(nothing))] c: i32, - #[deny(C)] d: i32, - #[forbid(C)] #[warn(C)] ... + #[deny(unused_mut)] d: i32, + #[forbid(unused_mut)] #[warn(unused_mut)] ... ); } type FnType = fn( - #[allow(C)] a: i32, + #[allow(unused_mut)] a: i32, #[cfg(something)] b: i32, #[cfg_attr(something, cfg(nothing))] c: i32, - #[deny(C)] d: i32, - #[forbid(C)] #[warn(C)] e: i32 + #[deny(unused_mut)] d: i32, + #[forbid(unused_mut)] #[warn(unused_mut)] e: i32 ); pub fn foo( - #[allow(C)] a: i32, + #[allow(unused_mut)] a: i32, #[cfg(something)] b: i32, #[cfg_attr(something, cfg(nothing))] c: i32, - #[deny(C)] d: i32, - #[forbid(C)] #[warn(C)] e: i32 + #[deny(unused_mut)] d: i32, + #[forbid(unused_mut)] #[warn(unused_mut)] _e: i32 ) {} -// self, &self and &mut self +// self struct SelfStruct {} impl SelfStruct { fn foo( - #[allow(C)] self, + #[allow(unused_mut)] self, #[cfg(something)] a: i32, #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, + #[deny(unused_mut)] b: i32, ) {} } struct RefStruct {} impl RefStruct { fn foo( - #[allow(C)] &self, + #[allow(unused_mut)] &self, #[cfg(something)] a: i32, #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, + #[deny(unused_mut)] b: i32, ) {} } trait RefTrait { fn foo( - #[forbid(C)] &self, - #[warn(C)] a: i32 + #[forbid(unused_mut)] &self, + #[warn(unused_mut)] a: i32 ) {} } impl RefTrait for RefStruct { fn foo( - #[forbid(C)] &self, - #[warn(C)] a: i32 - ) {} -} - -struct MutStruct {} -impl MutStruct { - fn foo( - #[allow(C)] &mut self, - #[cfg(something)] a: i32, - #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, - ) {} -} -trait MutTrait { - fn foo( - #[forbid(C)] &mut self, - #[warn(C)] a: i32 - ) {} -} -impl MutTrait for MutStruct { - fn foo( - #[forbid(C)] &mut self, - #[warn(C)] a: i32 - ) {} -} - -// self: Self, self: &Self and self: &mut Self - -struct NamedSelfSelfStruct {} -impl NamedSelfSelfStruct { - fn foo( - #[allow(C)] self: Self, - #[cfg(something)] a: i32, - #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, - ) {} -} - -struct NamedSelfRefStruct {} -impl NamedSelfRefStruct { - fn foo( - #[allow(C)] self: &Self, - #[cfg(something)] a: i32, - #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, - ) {} -} -trait NamedSelfRefTrait { - fn foo( - #[forbid(C)] self: &Self, - #[warn(C)] a: i32 - ) {} -} -impl NamedSelfRefTrait for NamedSelfRefStruct { - fn foo( - #[forbid(C)] self: &Self, - #[warn(C)] a: i32 - ) {} -} - -struct NamedSelfMutStruct {} -impl NamedSelfMutStruct { - fn foo( - #[allow(C)] self: &mut Self, - #[cfg(something)] a: i32, - #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, - ) {} -} -trait NamedSelfMutTrait { - fn foo( - #[forbid(C)] self: &mut Self, - #[warn(C)] a: i32 - ) {} -} -impl NamedSelfMutTrait for NamedSelfMutStruct { - fn foo( - #[forbid(C)] self: &mut Self, - #[warn(C)] a: i32 - ) {} -} - -// &'a self and &'a mut self - -struct NamedLifetimeRefStruct {} -impl NamedLifetimeRefStruct { - fn foo<'a>( - #[allow(C)] self: &'a Self, - #[cfg(something)] a: i32, - #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, - ) {} -} -trait NamedLifetimeRefTrait { - fn foo<'a>( - #[forbid(C)] &'a self, - #[warn(C)] a: i32 - ) {} -} -impl NamedLifetimeRefTrait for NamedLifetimeRefStruct { - fn foo<'a>( - #[forbid(C)] &'a self, - #[warn(C)] a: i32 - ) {} -} - -struct NamedLifetimeMutStruct {} -impl NamedLifetimeMutStruct { - fn foo<'a>( - #[allow(C)] self: &'a mut Self, - #[cfg(something)] a: i32, - #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, - ) {} -} -trait NamedLifetimeMutTrait { - fn foo<'a>( - #[forbid(C)] &'a mut self, - #[warn(C)] a: i32 - ) {} -} -impl NamedLifetimeMutTrait for NamedLifetimeMutStruct { - fn foo<'a>( - #[forbid(C)] &'a mut self, - #[warn(C)] a: i32 + #[forbid(unused_mut)] &self, + #[warn(unused_mut)] a: i32 ) {} } @@ -192,22 +69,22 @@ impl NamedLifetimeMutTrait for NamedLifetimeMutStruct { struct BoxSelfStruct {} impl BoxSelfStruct { fn foo( - #[allow(C)] self: Box, + #[allow(unused_mut)] self: Box, #[cfg(something)] a: i32, #[cfg_attr(something, cfg(nothing))] - #[deny(C)] b: i32, + #[deny(unused_mut)] b: i32, ) {} } trait BoxSelfTrait { fn foo( - #[forbid(C)] self: Box, - #[warn(C)] a: i32 + #[forbid(unused_mut)] self: Box, + #[warn(unused_mut)] a: i32 ) {} } impl BoxSelfTrait for BoxSelfStruct { fn foo( - #[forbid(C)] self: Box, - #[warn(C)] a: i32 + #[forbid(unused_mut)] self: Box, + #[warn(unused_mut)] a: i32 ) {} } @@ -216,10 +93,10 @@ fn main() { let _: fn(_, _, _, _) = foo; let _: FnType = |_, _, _, _| {}; let c = | - #[allow(C)] a: u32, + #[allow(unused_mut)] a: u32, #[cfg(something)] b: i32, #[cfg_attr(something, cfg(nothing))] - #[deny(C)] c: i32, + #[deny(unused_mut)] c: i32, | {}; let _ = c(1, 2); } diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs index 977b5d9ce3495..069332ffa255f 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs @@ -1,6 +1,7 @@ // compile-flags: --cfg something +// edition:2018 -#![feature(param_attrs)] +#![feature(async_await, async_closure, param_attrs)] #![deny(unused_variables)] extern "C" { @@ -19,24 +20,35 @@ type FnType = fn( #[cfg_attr(something, cfg(nothing))] d: i32, ); +async fn foo_async( + #[cfg(something)] a: i32, + //~^ ERROR unused variable: `a` + #[cfg(nothing)] b: i32, +) {} fn foo( #[cfg(nothing)] a: i32, #[cfg(something)] b: i32, - //~^ ERROR unused variable: `b` [unused_variables] + //~^ ERROR unused variable: `b` #[cfg_attr(nothing, cfg(nothing))] c: i32, - //~^ ERROR unused variable: `c` [unused_variables] + //~^ ERROR unused variable: `c` #[cfg_attr(something, cfg(nothing))] d: i32, ) {} struct RefStruct {} impl RefStruct { + async fn bar_async( + &self, + #[cfg(something)] a: i32, + //~^ ERROR unused variable: `a` + #[cfg(nothing)] b: i32, + ) {} fn bar( &self, #[cfg(nothing)] a: i32, #[cfg(something)] b: i32, - //~^ ERROR unused variable: `b` [unused_variables] + //~^ ERROR unused variable: `b` #[cfg_attr(nothing, cfg(nothing))] c: i32, - //~^ ERROR unused variable: `c` [unused_variables] + //~^ ERROR unused variable: `c` #[cfg_attr(something, cfg(nothing))] d: i32, ) {} } @@ -45,9 +57,9 @@ trait RefTrait { &self, #[cfg(nothing)] a: i32, #[cfg(something)] b: i32, - //~^ ERROR unused variable: `b` [unused_variables] + //~^ ERROR unused variable: `b` #[cfg_attr(nothing, cfg(nothing))] c: i32, - //~^ ERROR unused variable: `c` [unused_variables] + //~^ ERROR unused variable: `c` #[cfg_attr(something, cfg(nothing))] d: i32, ) {} } @@ -56,9 +68,9 @@ impl RefTrait for RefStruct { &self, #[cfg(nothing)] a: i32, #[cfg(something)] b: i32, - //~^ ERROR unused variable: `b` [unused_variables] + //~^ ERROR unused variable: `b` #[cfg_attr(nothing, cfg(nothing))] c: i32, - //~^ ERROR unused variable: `c` [unused_variables] + //~^ ERROR unused variable: `c` #[cfg_attr(something, cfg(nothing))] d: i32, ) {} } @@ -67,13 +79,19 @@ fn main() { let _: unsafe extern "C" fn(_, ...) = ffi; let _: fn(_, _) = foo; let _: FnType = |_, _| {}; + let a = async move | + #[cfg(something)] a: i32, + //~^ ERROR unused variable: `a` + #[cfg(nothing)] b: i32, + | {}; let c = | #[cfg(nothing)] a: i32, #[cfg(something)] b: i32, - //~^ ERROR unused variable: `b` [unused_variables] + //~^ ERROR unused variable: `b` #[cfg_attr(nothing, cfg(nothing))] c: i32, - //~^ ERROR unused variable: `c` [unused_variables] + //~^ ERROR unused variable: `c` #[cfg_attr(something, cfg(nothing))] d: i32, | {}; + let _ = a(1); let _ = c(1, 2); } diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr index c97190324e5a2..3232e2a0411a2 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr @@ -1,68 +1,86 @@ -error: unused variable: `b` +error: unused variable: `a` --> $DIR/param-attrs-cfg.rs:24:23 | -LL | #[cfg(something)] b: i32, - | ^ help: consider prefixing with an underscore: `_b` +LL | #[cfg(something)] a: i32, + | ^ help: consider prefixing with an underscore: `_a` | note: lint level defined here - --> $DIR/param-attrs-cfg.rs:4:9 + --> $DIR/param-attrs-cfg.rs:5:9 | LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:30:23 + | +LL | #[cfg(something)] b: i32, + | ^ help: consider prefixing with an underscore: `_b` + error: unused variable: `c` - --> $DIR/param-attrs-cfg.rs:26:40 + --> $DIR/param-attrs-cfg.rs:32:40 | LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, | ^ help: consider prefixing with an underscore: `_c` +error: unused variable: `a` + --> $DIR/param-attrs-cfg.rs:83:27 + | +LL | #[cfg(something)] a: i32, + | ^ help: consider prefixing with an underscore: `_a` + error: unused variable: `b` - --> $DIR/param-attrs-cfg.rs:72:27 + --> $DIR/param-attrs-cfg.rs:89:27 | LL | #[cfg(something)] b: i32, | ^ help: consider prefixing with an underscore: `_b` error: unused variable: `c` - --> $DIR/param-attrs-cfg.rs:74:44 + --> $DIR/param-attrs-cfg.rs:91:44 | LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, | ^ help: consider prefixing with an underscore: `_c` error: unused variable: `b` - --> $DIR/param-attrs-cfg.rs:47:27 + --> $DIR/param-attrs-cfg.rs:59:27 | LL | #[cfg(something)] b: i32, | ^ help: consider prefixing with an underscore: `_b` error: unused variable: `c` - --> $DIR/param-attrs-cfg.rs:49:44 + --> $DIR/param-attrs-cfg.rs:61:44 | LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, | ^ help: consider prefixing with an underscore: `_c` +error: unused variable: `a` + --> $DIR/param-attrs-cfg.rs:41:27 + | +LL | #[cfg(something)] a: i32, + | ^ help: consider prefixing with an underscore: `_a` + error: unused variable: `b` - --> $DIR/param-attrs-cfg.rs:36:27 + --> $DIR/param-attrs-cfg.rs:48:27 | LL | #[cfg(something)] b: i32, | ^ help: consider prefixing with an underscore: `_b` error: unused variable: `c` - --> $DIR/param-attrs-cfg.rs:38:44 + --> $DIR/param-attrs-cfg.rs:50:44 | LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, | ^ help: consider prefixing with an underscore: `_c` error: unused variable: `b` - --> $DIR/param-attrs-cfg.rs:58:27 + --> $DIR/param-attrs-cfg.rs:70:27 | LL | #[cfg(something)] b: i32, | ^ help: consider prefixing with an underscore: `_b` error: unused variable: `c` - --> $DIR/param-attrs-cfg.rs:60:44 + --> $DIR/param-attrs-cfg.rs:72:44 | LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, | ^ help: consider prefixing with an underscore: `_c` -error: aborting due to 10 previous errors +error: aborting due to 13 previous errors diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs index c5a6514efb0f0..a7f4855915b24 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs @@ -1,12 +1,14 @@ // gate-test-param_attrs +#![deny(unused_variables)] + fn foo( /// Foo //~^ ERROR documentation comments cannot be applied to function parameters //~| NOTE doc comments are not allowed here //~| ERROR attributes on function parameters are unstable //~| NOTE https://github.com/rust-lang/rust/issues/60406 - #[allow(C)] a: u8 + #[allow(unused_variables)] a: u8 //~^ ERROR attributes on function parameters are unstable //~| NOTE https://github.com/rust-lang/rust/issues/60406 ) {} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr index 704c41f0fa641..0bb9d05dca0ac 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr @@ -1,11 +1,11 @@ error: documentation comments cannot be applied to function parameters - --> $DIR/param-attrs-feature-gate.rs:4:5 + --> $DIR/param-attrs-feature-gate.rs:6:5 | LL | /// Foo | ^^^^^^^ doc comments are not allowed here error[E0658]: attributes on function parameters are unstable - --> $DIR/param-attrs-feature-gate.rs:4:5 + --> $DIR/param-attrs-feature-gate.rs:6:5 | LL | /// Foo | ^^^^^^^ @@ -14,10 +14,10 @@ LL | /// Foo = help: add `#![feature(param_attrs)]` to the crate attributes to enable error[E0658]: attributes on function parameters are unstable - --> $DIR/param-attrs-feature-gate.rs:9:5 + --> $DIR/param-attrs-feature-gate.rs:11:5 | -LL | #[allow(C)] a: u8 - | ^^^^^^^^^^^ +LL | #[allow(unused_variables)] a: u8 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/60406 = help: add `#![feature(param_attrs)]` to the crate attributes to enable