1
Fork 0

Rollup merge of #61856 - c410-f3r:attrs-fn, r=matthewjasper

Lint attributes on function arguments

Fixes #61238.

cc #60406
This commit is contained in:
Mazdak Farrokhzad 2019-07-28 21:19:50 +02:00 committed by GitHub
commit a4cd2ecab2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 596 additions and 302 deletions

View file

@ -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);

View file

@ -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 <pat> = <pat>;`. 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 <pat> = __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);
@ -5030,6 +5051,7 @@ impl<'a> LoweringContext<'a> {
// `let mut __next`
let next_let = self.stmt_let_pat(
ThinVec::new(),
desugared_span,
None,
next_pat,
@ -5039,6 +5061,7 @@ impl<'a> LoweringContext<'a> {
// `let <pat> = __next`
let pat = self.lower_pat(pat);
let pat_let = self.stmt_let_pat(
ThinVec::new(),
head_sp,
Some(next_expr),
pat,
@ -5533,19 +5556,20 @@ impl<'a> LoweringContext<'a> {
fn stmt_let_pat(
&mut self,
attrs: ThinVec<Attribute>,
span: Span,
init: Option<P<hir::Expr>>,
pat: P<hir::Pat>,
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)))
}
@ -5959,6 +5983,7 @@ impl<'a> LoweringContext<'a> {
hir::BindingAnnotation::Mutable,
);
let pinned_let = self.stmt_let_pat(
ThinVec::new(),
span,
Some(expr),
pinned_pat,

View file

@ -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,

View file

@ -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)
}

View file

@ -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<Pat>,
pub attrs: HirVec<Attribute>,
pub hir_id: HirId,
pub pat: P<Pat>,
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),

View file

@ -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 :(

View file

@ -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);

View file

@ -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<dyn EarlyLintPass + sync::Send + sync::Sync +
pub type LateLintPassObject = Box<dyn for<'a, 'tcx> 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);

View file

@ -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<Span>, Option<&'tcx hir::Pat>, Option<ImplicitSelfKind>);
struct ArgInfo<'tcx>(Ty<'tcx>, Option<Span>, Option<&'tcx hir::Arg>, Option<ImplicitSelfKind>);
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(),

View file

@ -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")
}

View file

@ -555,21 +555,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(_) |

View file

@ -235,41 +235,57 @@ 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 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 = path.ident.as_str();
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(*span)) {
match (is_as_ref_able, self.sess().source_map().span_to_snippet(*method_span)) {
(true, Ok(src)) => {
return Some((*span, "consider using `as_ref` instead",
format!("as_ref().{}", 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(
&self,

View file

@ -1796,6 +1796,7 @@ pub struct Arg {
pub ty: P<Ty>,
pub pat: P<Pat>,
pub id: NodeId,
pub span: Span,
}
/// Alternative representation for `Arg`s describing `self` parameter of methods.
@ -1854,6 +1855,7 @@ impl Arg {
node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
span,
}),
span,
ty,
id: DUMMY_NODE_ID,
};

View file

@ -966,6 +966,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
attrs: ThinVec::default(),
id: ast::DUMMY_NODE_ID,
pat: arg_pat,
span,
ty,
}
}

View file

@ -558,10 +558,11 @@ pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
vis.visit_span(span);
}
pub fn noop_visit_arg<T: MutVisitor>(Arg { attrs, id, pat, ty }: &mut Arg, vis: &mut T) {
pub fn noop_visit_arg<T: MutVisitor>(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);
}

View file

@ -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 {

View file

@ -1515,6 +1515,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();
@ -1578,11 +1579,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) {
@ -1594,10 +1598,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
})
}

View file

@ -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) }
@ -547,12 +548,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)
@ -822,6 +821,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 {

View file

@ -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

View file

@ -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;
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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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<Self>,
#[allow(unused_mut)] self: Box<Self>,
#[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<Self>,
#[warn(C)] a: i32
#[forbid(unused_mut)] self: Box<Self>,
#[warn(unused_mut)] a: i32
) {}
}
impl BoxSelfTrait for BoxSelfStruct {
fn foo(
#[forbid(C)] self: Box<Self>,
#[warn(C)] a: i32
#[forbid(unused_mut)] self: Box<Self>,
#[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);
}

View file

@ -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);
}

View file

@ -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: `c`
--> $DIR/param-attrs-cfg.rs:26:40
|
LL | #[cfg_attr(nothing, cfg(nothing))] c: i32,
| ^ help: consider prefixing with an underscore: `_c`
error: unused variable: `b`
--> $DIR/param-attrs-cfg.rs:72:27
--> $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:74:44
--> $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:47: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:49: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:36: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:38: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:48:27
|
LL | #[cfg(something)] b: i32,
| ^ help: consider prefixing with an underscore: `_b`
error: unused variable: `c`
--> $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

View file

@ -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
) {}

View file

@ -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