Rollup merge of #61856 - c410-f3r:attrs-fn, r=matthewjasper
Lint attributes on function arguments Fixes #61238. cc #60406
This commit is contained in:
commit
a4cd2ecab2
28 changed files with 596 additions and 302 deletions
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 :(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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(_) |
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -966,6 +966,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
attrs: ThinVec::default(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
pat: arg_pat,
|
||||
span,
|
||||
ty,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
64
src/test/ui/lint/lint-unused-variables.rs
Normal file
64
src/test/ui/lint/lint-unused-variables.rs
Normal 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);
|
||||
}
|
56
src/test/ui/lint/lint-unused-variables.stderr
Normal file
56
src/test/ui/lint/lint-unused-variables.stderr
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
) {}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue