diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 92e6bc6013dc2..32dbd2ff47d6b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1406,8 +1406,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { + let hir_id = self.lower_node_id(f.id); + self.lower_attrs(hir_id, &f.attrs); hir::ExprField { - hir_id: self.next_id(), + hir_id, ident: self.lower_ident(f.ident), expr: self.lower_expr(&f.expr), span: self.lower_span(f.span), diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index e08c1d063c105..2b7431f099057 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -199,6 +199,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) { + self.insert(field.span, field.hir_id, Node::PatField(field)); + self.with_parent(field.hir_id, |this| { + intravisit::walk_pat_field(this, field); + }); + } + fn visit_arm(&mut self, arm: &'hir Arm<'hir>) { let node = Node::Arm(arm); @@ -225,6 +232,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_expr_field(&mut self, field: &'hir ExprField<'hir>) { + self.insert(field.span, field.hir_id, Node::ExprField(field)); + self.with_parent(field.hir_id, |this| { + intravisit::walk_expr_field(this, field); + }); + } + fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) { self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt)); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index bd2e76e5528da..51f67e505f4ee 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -64,12 +64,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); - let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField { - hir_id: self.next_id(), - ident: self.lower_ident(f.ident), - pat: self.lower_pat(&f.pat), - is_shorthand: f.is_shorthand, - span: self.lower_span(f.span), + let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { + let hir_id = self.lower_node_id(f.id); + self.lower_attrs(hir_id, &f.attrs); + + hir::PatField { + hir_id, + ident: self.lower_ident(f.ident), + pat: self.lower_pat(&f.pat), + is_shorthand: f.is_shorthand, + span: self.lower_span(f.span), + } })); break hir::PatKind::Struct(qpath, fs, etc); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 7a87a3e488260..2610d0b92d8f3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3332,12 +3332,14 @@ pub enum Node<'hir> { Field(&'hir FieldDef<'hir>), AnonConst(&'hir AnonConst), Expr(&'hir Expr<'hir>), + ExprField(&'hir ExprField<'hir>), Stmt(&'hir Stmt<'hir>), PathSegment(&'hir PathSegment<'hir>), Ty(&'hir Ty<'hir>), TypeBinding(&'hir TypeBinding<'hir>), TraitRef(&'hir TraitRef<'hir>), Pat(&'hir Pat<'hir>), + PatField(&'hir PatField<'hir>), Arm(&'hir Arm<'hir>), Block(&'hir Block<'hir>), Local(&'hir Local<'hir>), @@ -3388,6 +3390,8 @@ impl<'hir> Node<'hir> { | Node::Block(..) | Node::Ctor(..) | Node::Pat(..) + | Node::PatField(..) + | Node::ExprField(..) | Node::Arm(..) | Node::Local(..) | Node::Crate(..) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 51b1bfad8a0d8..900370937f79a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -325,6 +325,9 @@ pub trait Visitor<'v>: Sized { fn visit_pat(&mut self, p: &'v Pat<'v>) { walk_pat(self, p) } + fn visit_pat_field(&mut self, f: &'v PatField<'v>) { + walk_pat_field(self, f) + } fn visit_array_length(&mut self, len: &'v ArrayLen) { walk_array_len(self, len) } @@ -337,6 +340,9 @@ pub trait Visitor<'v>: Sized { fn visit_let_expr(&mut self, lex: &'v Let<'v>) { walk_let_expr(self, lex) } + fn visit_expr_field(&mut self, field: &'v ExprField<'v>) { + walk_expr_field(self, field) + } fn visit_ty(&mut self, t: &'v Ty<'v>) { walk_ty(self, t) } @@ -761,11 +767,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { } PatKind::Struct(ref qpath, fields, _) => { visitor.visit_qpath(qpath, pattern.hir_id, pattern.span); - for field in fields { - visitor.visit_id(field.hir_id); - visitor.visit_ident(field.ident); - visitor.visit_pat(&field.pat) - } + walk_list!(visitor, visit_pat_field, fields); } PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats), PatKind::Tuple(tuple_elements, _) => { @@ -792,6 +794,12 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { } } +pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) { + visitor.visit_id(field.hir_id); + visitor.visit_ident(field.ident); + visitor.visit_pat(&field.pat) +} + pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) { visitor.visit_id(foreign_item.hir_id()); visitor.visit_ident(foreign_item.ident); @@ -1059,6 +1067,12 @@ pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) walk_list!(visitor, visit_ty, let_expr.ty); } +pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) { + visitor.visit_id(field.hir_id); + visitor.visit_ident(field.ident); + visitor.visit_expr(&field.expr) +} + pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) { visitor.visit_id(expression.hir_id); match expression.kind { @@ -1073,11 +1087,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) } ExprKind::Struct(ref qpath, fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.hir_id, expression.span); - for field in fields { - visitor.visit_id(field.hir_id); - visitor.visit_ident(field.ident); - visitor.visit_expr(&field.expr) - } + walk_list!(visitor, visit_expr_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(subexpressions) => { diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 6236dea10c88f..78bfd7191dba9 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -56,6 +56,8 @@ pub enum Target { GenericParam(GenericParamKind), MacroDef, Param, + PatField, + ExprField, } impl Display for Target { @@ -183,6 +185,8 @@ impl Target { }, Target::MacroDef => "macro def", Target::Param => "function param", + Target::PatField => "pattern field", + Target::ExprField => "struct field", } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index c7966b662de9f..e6fcb84730ea4 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -83,12 +83,14 @@ impl<'a> State<'a> { Node::Variant(a) => self.print_variant(a), Node::AnonConst(a) => self.print_anon_const(a), Node::Expr(a) => self.print_expr(a), + Node::ExprField(a) => self.print_expr_field(&a), Node::Stmt(a) => self.print_stmt(a), Node::PathSegment(a) => self.print_path_segment(a), Node::Ty(a) => self.print_type(a), Node::TypeBinding(a) => self.print_type_binding(a), Node::TraitRef(a) => self.print_trait_ref(a), Node::Pat(a) => self.print_pat(a), + Node::PatField(a) => self.print_patfield(&a), Node::Arm(a) => self.print_arm(a), Node::Infer(_) => self.word("_"), Node::Block(a) => { @@ -1127,20 +1129,7 @@ impl<'a> State<'a> { ) { self.print_qpath(qpath, true); self.word("{"); - self.commasep_cmnt( - Consistent, - fields, - |s, field| { - s.ibox(INDENT_UNIT); - if !field.is_shorthand { - s.print_ident(field.ident); - s.word_space(":"); - } - s.print_expr(field.expr); - s.end() - }, - |f| f.span, - ); + self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span); if let Some(expr) = wth { self.ibox(INDENT_UNIT); if !fields.is_empty() { @@ -1157,6 +1146,20 @@ impl<'a> State<'a> { self.word("}"); } + fn print_expr_field(&mut self, field: &hir::ExprField<'_>) { + if self.attrs(field.hir_id).is_empty() { + self.space(); + } + self.cbox(INDENT_UNIT); + self.print_outer_attributes(&self.attrs(field.hir_id)); + if !field.is_shorthand { + self.print_ident(field.ident); + self.word_space(":"); + } + self.print_expr(&field.expr); + self.end() + } + fn print_expr_tup(&mut self, exprs: &[hir::Expr<'_>]) { self.popen(); self.commasep_exprs(Inconsistent, exprs); @@ -1803,20 +1806,7 @@ impl<'a> State<'a> { if !empty { self.space(); } - self.commasep_cmnt( - Consistent, - fields, - |s, f| { - s.cbox(INDENT_UNIT); - if !f.is_shorthand { - s.print_ident(f.ident); - s.word_nbsp(":"); - } - s.print_pat(f.pat); - s.end() - }, - |f| f.pat.span, - ); + self.commasep_cmnt(Consistent, &fields, |s, f| s.print_patfield(f), |f| f.pat.span); if etc { if !fields.is_empty() { self.word_space(","); @@ -1911,6 +1901,20 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } + pub fn print_patfield(&mut self, field: &hir::PatField<'_>) { + if self.attrs(field.hir_id).is_empty() { + self.space(); + } + self.cbox(INDENT_UNIT); + self.print_outer_attributes(&self.attrs(field.hir_id)); + if !field.is_shorthand { + self.print_ident(field.ident); + self.word_nbsp(":"); + } + self.print_pat(field.pat); + self.end(); + } + pub fn print_param(&mut self, arg: &hir::Param<'_>) { self.print_outer_attributes(self.attrs(arg.hir_id)); self.print_pat(arg.pat); diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index cbf1a67755501..580a4566869f0 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -101,6 +101,12 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_pat_post, p); } + fn visit_pat_field(&mut self, field: &'a ast::PatField) { + self.with_lint_attrs(field.id, &field.attrs, |cx| { + ast_visit::walk_pat_field(cx, field); + }); + } + fn visit_anon_const(&mut self, c: &'a ast::AnonConst) { self.check_id(c.id); ast_visit::walk_anon_const(self, c); @@ -219,9 +225,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { - run_early_pass!(self, check_generic_param, param); - self.check_id(param.id); - ast_visit::walk_generic_param(self, param); + self.with_lint_attrs(param.id, ¶m.attrs, |cx| { + run_early_pass!(cx, check_generic_param, param); + ast_visit::walk_generic_param(cx, param); + }); } fn visit_generics(&mut self, g: &'a ast::Generics) { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 7ab9302d835a2..1cabb58bbebfd 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -766,6 +766,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { }) } + fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { + self.with_lint_attrs(field.hir_id, |builder| { + intravisit::walk_expr_field(builder, field); + }) + } + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { self.with_lint_attrs(s.hir_id, |builder| { intravisit::walk_field_def(builder, s); @@ -801,6 +807,18 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { intravisit::walk_impl_item(builder, impl_item); }); } + + fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) { + self.with_lint_attrs(field.hir_id, |builder| { + intravisit::walk_pat_field(builder, field); + }) + } + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + self.with_lint_attrs(p.hir_id, |builder| { + intravisit::walk_generic_param(builder, p); + }); + } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 8d04d68bf1c2d..2868aabfa07e2 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -437,19 +437,14 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) { if let PatKind::Binding(_, hid, ident, _) = p.kind { - if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid)) + if let hir::Node::PatField(field) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid)) { - if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind { - if field_pats - .iter() - .any(|field| !field.is_shorthand && field.pat.hir_id == p.hir_id) - { - // Only check if a new name has been introduced, to avoid warning - // on both the struct definition and this pattern. - self.check_snake_case(cx, "variable", &ident); - } - return; + if !field.is_shorthand { + // Only check if a new name has been introduced, to avoid warning + // on both the struct definition and this pattern. + self.check_snake_case(cx, "variable", &ident); } + return; } self.check_snake_case(cx, "variable", &ident); } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 5c07afeb7aa8f..cafd2c6e67994 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -125,45 +125,51 @@ fn lint_overflowing_range_endpoint<'tcx>( lit_val: u128, max: u128, expr: &'tcx hir::Expr<'tcx>, - parent_expr: &'tcx hir::Expr<'tcx>, ty: &str, ) -> bool { // We only want to handle exclusive (`..`) ranges, // which are represented as `ExprKind::Struct`. + let par_id = cx.tcx.hir().get_parent_node(expr.hir_id); + let Node::ExprField(field) = cx.tcx.hir().get(par_id) else { return false }; + let field_par_id = cx.tcx.hir().get_parent_node(field.hir_id); + let Node::Expr(struct_expr) = cx.tcx.hir().get(field_par_id) else { return false }; + if !is_range_literal(struct_expr) { + return false; + }; + let ExprKind::Struct(_, eps, _) = &struct_expr.kind else { return false }; + if eps.len() != 2 { + return false; + } + let mut overwritten = false; - if let ExprKind::Struct(_, eps, _) = &parent_expr.kind { - if eps.len() != 2 { - return false; - } - // We can suggest using an inclusive range - // (`..=`) instead only if it is the `end` that is - // overflowing and only by 1. - if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { - cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| { - let mut err = lint.build(fluent::lint::range_endpoint_out_of_range); - err.set_arg("ty", ty); - if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { - use ast::{LitIntType, LitKind}; - // We need to preserve the literal's suffix, - // as it may determine typing information. - let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsuffixed) => "", - _ => bug!(), - }; - let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); - err.span_suggestion( - parent_expr.span, - fluent::lint::suggestion, - suggestion, - Applicability::MachineApplicable, - ); - err.emit(); - overwritten = true; - } - }); - } + // We can suggest using an inclusive range + // (`..=`) instead only if it is the `end` that is + // overflowing and only by 1. + if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { + cx.struct_span_lint(OVERFLOWING_LITERALS, struct_expr.span, |lint| { + let mut err = lint.build(fluent::lint::range_endpoint_out_of_range); + err.set_arg("ty", ty); + if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { + use ast::{LitIntType, LitKind}; + // We need to preserve the literal's suffix, + // as it may determine typing information. + let suffix = match lit.node { + LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsuffixed) => "", + _ => bug!(), + }; + let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); + err.span_suggestion( + struct_expr.span, + fluent::lint::suggestion, + suggestion, + Applicability::MachineApplicable, + ); + err.emit(); + overwritten = true; + } + }); } overwritten } @@ -339,16 +345,9 @@ fn lint_int_literal<'tcx>( return; } - let par_id = cx.tcx.hir().get_parent_node(e.hir_id); - if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { - if let hir::ExprKind::Struct(..) = par_e.kind { - if is_range_literal(par_e) - && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str()) - { - // The overflowing literal lint was overridden. - return; - } - } + if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) { + // The overflowing literal lint was overridden. + return; } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { @@ -408,16 +407,13 @@ fn lint_uint_literal<'tcx>( return; } } - hir::ExprKind::Struct(..) if is_range_literal(par_e) => { - let t = t.name_str(); - if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { - // The overflowing literal lint was overridden. - return; - } - } _ => {} } } + if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) { + // The overflowing literal lint was overridden. + return; + } if let Some(repr_str) = get_bin_hex_repr(cx, lit) { report_bin_hex_error( cx, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 47b04c33ec1cd..79e6804a28992 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -297,6 +297,8 @@ impl<'hir> Map<'hir> { | Node::Infer(_) | Node::TraitRef(_) | Node::Pat(_) + | Node::PatField(_) + | Node::ExprField(_) | Node::Local(_) | Node::Param(_) | Node::Arm(_) @@ -1020,6 +1022,7 @@ impl<'hir> Map<'hir> { Node::Field(field) => field.span, Node::AnonConst(constant) => self.body(constant.body).value.span, Node::Expr(expr) => expr.span, + Node::ExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, Node::PathSegment(seg) => { let ident_span = seg.ident.span; @@ -1030,6 +1033,7 @@ impl<'hir> Map<'hir> { Node::TypeBinding(tb) => tb.span, Node::TraitRef(tr) => tr.path.span, Node::Pat(pat) => pat.span, + Node::PatField(field) => field.span, Node::Arm(arm) => arm.span, Node::Block(block) => block.span, Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)), @@ -1241,12 +1245,14 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { } Some(Node::AnonConst(_)) => node_str("const"), Some(Node::Expr(_)) => node_str("expr"), + Some(Node::ExprField(_)) => node_str("expr field"), Some(Node::Stmt(_)) => node_str("stmt"), Some(Node::PathSegment(_)) => node_str("path segment"), Some(Node::Ty(_)) => node_str("type"), Some(Node::TypeBinding(_)) => node_str("type binding"), Some(Node::TraitRef(_)) => node_str("trait ref"), Some(Node::Pat(_)) => node_str("pat"), + Some(Node::PatField(_)) => node_str("pattern field"), Some(Node::Param(_)) => node_str("param"), Some(Node::Arm(_)) => node_str("arm"), Some(Node::Block(_)) => node_str("block"), diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f75fffb6871f7..5789531d2ff5a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -652,7 +652,9 @@ impl CheckAttrVisitor<'_> { | Target::ForeignStatic | Target::ForeignTy | Target::GenericParam(..) - | Target::MacroDef => None, + | Target::MacroDef + | Target::PatField + | Target::ExprField => None, } { tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location }); return false; @@ -2066,6 +2068,11 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_expr(self, expr) } + fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { + self.check_attributes(field.hir_id, field.span, Target::ExprField, None); + intravisit::walk_expr_field(self, field) + } + fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) { self.check_attributes(variant.id, variant.span, Target::Variant, None); intravisit::walk_variant(self, variant) @@ -2076,6 +2083,11 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_param(self, param); } + + fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) { + self.check_attributes(field.hir_id, field.span, Target::PatField, None); + intravisit::walk_pat_field(self, field); + } } fn is_c_like_enum(item: &Item<'_>) -> bool { diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index bac0be44aa9a2..07046f3f0326b 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -638,11 +638,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }?; match hir.find(hir.get_parent_node(expr.hir_id))? { - Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) => { - for field in *fields { - if field.ident.name == local.name && field.is_shorthand { - return Some(local.name); - } + Node::ExprField(field) => { + if field.ident.name == local.name && field.is_shorthand { + return Some(local.name); } } _ => {} @@ -1073,21 +1071,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut sugg = vec![]; - if let Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Struct(_, fields, _), .. - })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) + if let Some(hir::Node::ExprField(field)) = + self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) { // `expr` is a literal field for a struct, only suggest if appropriate - match (*fields) - .iter() - .find(|field| field.expr.hir_id == expr.hir_id && field.is_shorthand) - { + if field.is_shorthand { // This is a field literal - Some(field) => { - sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident))); - } + sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident))); + } else { // Likely a field was meant, but this field wasn't found. Do not suggest anything. - None => return false, + return false; } }; diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index a2c23db162b03..3e96b3ffb0940 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -256,6 +256,8 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { | hir::Node::TypeBinding(..) | hir::Node::TraitRef(..) | hir::Node::Pat(..) + | hir::Node::PatField(..) + | hir::Node::ExprField(..) | hir::Node::Arm(..) | hir::Node::Local(..) | hir::Node::Ctor(..) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index a13c715258207..6dcc364bb50f7 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -927,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); match self.tcx.hir().get(self.tcx.hir().get_parent_node(pat.hir_id)) { - hir::Node::Pat(Pat { kind: hir::PatKind::Struct(..), .. }) => { + hir::Node::PatField(..) => { e.span_suggestion_verbose( ident.span.shrink_to_hi(), "bind the struct field to a different name instead", diff --git a/src/test/ui/lint/lint-attr-everywhere-early.rs b/src/test/ui/lint/lint-attr-everywhere-early.rs new file mode 100644 index 0000000000000..fd0c4b43e05c6 --- /dev/null +++ b/src/test/ui/lint/lint-attr-everywhere-early.rs @@ -0,0 +1,176 @@ +// Tests that lint levels can be set for early lints. +#![allow(non_camel_case_types, unsafe_code, while_true, unused_parens)] + +// The following is a check of the lints used here to verify they do not warn +// when allowed. +fn verify_no_warnings() { + type non_camel_type = i32; // non_camel_case_types + struct NON_CAMEL_IS_ALLOWED; // non_camel_case_types + unsafe {} // unsafe_code + enum Enum { + VARIANT_CAMEL // non_camel_case_types + } + fn generics() {} // non_camel_case_types + while true {} // while_true + type T = (i32); // unused_parens +} + + +// ################## Types + +#[deny(non_camel_case_types)] +type type_outer = i32; //~ ERROR type `type_outer` should have an upper camel case name + +type BareFnPtr = fn(#[deny(unused_parens)](i32)); //~ ERROR unnecessary parentheses around type +// There aren't any early lints that currently apply to the variadic spot. +// type BareFnPtrVariadic = extern "C" fn(i32, #[deny()]...); + +// ################## Items +#[deny(non_camel_case_types)] +struct ITEM_OUTER; //~ ERROR type `ITEM_OUTER` should have an upper camel case name + +mod module_inner { + #![deny(unsafe_code)] + fn f() { + unsafe {} //~ ERROR usage of an `unsafe` block + } +} + +struct Associated; +impl Associated { + #![deny(unsafe_code)] + + fn inherent_denied_from_inner() { unsafe {} } //~ usage of an `unsafe` block + + #[deny(while_true)] + fn inherent_fn() { while true {} } //~ ERROR denote infinite loops with + + #[deny(while_true)] + const INHERENT_CONST: i32 = {while true {} 1}; //~ ERROR denote infinite loops with +} + +trait trait_inner { //~ ERROR trait `trait_inner` should have an upper camel case name + #![deny(non_camel_case_types)] +} + +trait AssociatedTrait { + #![deny(unsafe_code)] + + fn denied_from_inner() { unsafe {} } //~ ERROR usage of an `unsafe` block + + #[deny(while_true)] + fn assoc_fn() { while true {} } //~ ERROR denote infinite loops with + + #[deny(while_true)] + const ASSOC_CONST: i32 = {while true {} 1}; //~ ERROR denote infinite loops with + + #[deny(non_camel_case_types)] + type assoc_type; //~ ERROR associated type `assoc_type` should have an upper camel case name +} + +impl AssociatedTrait for Associated { + #![deny(unsafe_code)] + + fn denied_from_inner() { unsafe {} } //~ ERROR usage of an `unsafe` block + + #[deny(while_true)] + fn assoc_fn() { while true {} } //~ ERROR denote infinite loops with + + #[deny(while_true)] + const ASSOC_CONST: i32 = {while true {} 1}; //~ ERROR denote infinite loops with + + #[deny(unused_parens)] + type assoc_type = (i32); //~ ERROR unnecessary parentheses around type +} + +struct StructFields { + #[deny(unused_parens)]f1: (i32), //~ ERROR unnecessary parentheses around type +} +struct StructTuple(#[deny(unused_parens)](i32)); //~ ERROR unnecessary parentheses around type + +enum Enum { + #[deny(non_camel_case_types)] + VARIANT_CAMEL, //~ ERROR variant `VARIANT_CAMEL` should have an upper camel case name +} + +extern "C" { + #![deny(unused_parens)] + + fn foreign_denied_from_inner(x: (i32)); //~ ERROR unnecessary parentheses around type +} + +extern "C" { + #[deny(unused_parens)] + fn foreign_denied_from_outer(x: (i32)); //~ ERROR unnecessary parentheses around type +} + +fn function(#[deny(unused_parens)] param: (i32)) {} //~ ERROR unnecessary parentheses around type + +fn generics<#[deny(non_camel_case_types)]foo>() {} //~ ERROR type parameter `foo` should have an upper camel case name + + +// ################## Statements +fn statements() { + #[deny(unused_parens)] + let x = (1); //~ ERROR unnecessary parentheses around assigned value +} + + +// ################## Expressions +fn expressions() { + let closure = |#[deny(unused_parens)] param: (i32)| {}; //~ ERROR unnecessary parentheses around type + + struct Match{f1: i32} + // Strangely unused_parens doesn't fire with {f1: (123)} + let f = Match{#[deny(unused_parens)]f1: {(123)}}; //~ ERROR unnecessary parentheses around block return value + + match f { + #![deny(unsafe_code)] + + #[deny(while_true)] + Match{f1} => { + unsafe {} //~ ERROR usage of an `unsafe` block + while true {} //~ ERROR denote infinite loops with + } + } + + // Statement Block + { + #![deny(unsafe_code)] + unsafe {} //~ ERROR usage of an `unsafe` block + } + let block_tail = { + #[deny(unsafe_code)] + unsafe {} //~ ERROR usage of an `unsafe` block + }; + + // Before expression as a statement. + #[deny(unsafe_code)] + unsafe {}; //~ ERROR usage of an `unsafe` block + + [#[deny(unsafe_code)] unsafe {123}]; //~ ERROR usage of an `unsafe` block + (#[deny(unsafe_code)] unsafe {123},); //~ ERROR usage of an `unsafe` block + fn call(p: i32) {} + call(#[deny(unsafe_code)] unsafe {123}); //~ ERROR usage of an `unsafe` block + struct TupleStruct(i32); + TupleStruct(#[deny(unsafe_code)] unsafe {123}); //~ ERROR usage of an `unsafe` block +} + + +// ################## Patterns +fn patterns() { + struct PatField{f1: i32, f2: i32}; + let f = PatField{f1: 1, f2: 2}; + match f { + PatField { + #[deny(ellipsis_inclusive_range_patterns)] + f1: 0...100, + //~^ ERROR range patterns are deprecated + //~| WARNING this is accepted in the current edition + .. + } => {} + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/lint/lint-attr-everywhere-early.stderr b/src/test/ui/lint/lint-attr-everywhere-early.stderr new file mode 100644 index 0000000000000..1d6e3cda4e533 --- /dev/null +++ b/src/test/ui/lint/lint-attr-everywhere-early.stderr @@ -0,0 +1,486 @@ +error: type `type_outer` should have an upper camel case name + --> $DIR/lint-attr-everywhere-early.rs:22:6 + | +LL | type type_outer = i32; + | ^^^^^^^^^^ help: convert the identifier to upper camel case: `TypeOuter` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:21:8 + | +LL | #[deny(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:24:43 + | +LL | type BareFnPtr = fn(#[deny(unused_parens)](i32)); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:24:28 + | +LL | type BareFnPtr = fn(#[deny(unused_parens)](i32)); + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - type BareFnPtr = fn(#[deny(unused_parens)](i32)); +LL + type BareFnPtr = fn(#[deny(unused_parens)]i32); + | + +error: type `ITEM_OUTER` should have an upper camel case name + --> $DIR/lint-attr-everywhere-early.rs:30:8 + | +LL | struct ITEM_OUTER; + | ^^^^^^^^^^ help: convert the identifier to upper camel case: `ItemOuter` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:29:8 + | +LL | #[deny(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:35:9 + | +LL | unsafe {} + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:33:13 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:43:39 + | +LL | fn inherent_denied_from_inner() { unsafe {} } + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:41:13 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: denote infinite loops with `loop { ... }` + --> $DIR/lint-attr-everywhere-early.rs:46:24 + | +LL | fn inherent_fn() { while true {} } + | ^^^^^^^^^^ help: use `loop` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:45:12 + | +LL | #[deny(while_true)] + | ^^^^^^^^^^ + +error: denote infinite loops with `loop { ... }` + --> $DIR/lint-attr-everywhere-early.rs:49:34 + | +LL | const INHERENT_CONST: i32 = {while true {} 1}; + | ^^^^^^^^^^ help: use `loop` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:48:12 + | +LL | #[deny(while_true)] + | ^^^^^^^^^^ + +error: trait `trait_inner` should have an upper camel case name + --> $DIR/lint-attr-everywhere-early.rs:52:7 + | +LL | trait trait_inner { + | ^^^^^^^^^^^ help: convert the identifier to upper camel case: `TraitInner` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:53:13 + | +LL | #![deny(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:59:30 + | +LL | fn denied_from_inner() { unsafe {} } + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:57:13 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: denote infinite loops with `loop { ... }` + --> $DIR/lint-attr-everywhere-early.rs:62:21 + | +LL | fn assoc_fn() { while true {} } + | ^^^^^^^^^^ help: use `loop` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:61:12 + | +LL | #[deny(while_true)] + | ^^^^^^^^^^ + +error: denote infinite loops with `loop { ... }` + --> $DIR/lint-attr-everywhere-early.rs:65:31 + | +LL | const ASSOC_CONST: i32 = {while true {} 1}; + | ^^^^^^^^^^ help: use `loop` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:64:12 + | +LL | #[deny(while_true)] + | ^^^^^^^^^^ + +error: associated type `assoc_type` should have an upper camel case name + --> $DIR/lint-attr-everywhere-early.rs:68:10 + | +LL | type assoc_type; + | ^^^^^^^^^^ help: convert the identifier to upper camel case: `AssocType` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:67:12 + | +LL | #[deny(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:74:30 + | +LL | fn denied_from_inner() { unsafe {} } + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:72:13 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: denote infinite loops with `loop { ... }` + --> $DIR/lint-attr-everywhere-early.rs:77:21 + | +LL | fn assoc_fn() { while true {} } + | ^^^^^^^^^^ help: use `loop` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:76:12 + | +LL | #[deny(while_true)] + | ^^^^^^^^^^ + +error: denote infinite loops with `loop { ... }` + --> $DIR/lint-attr-everywhere-early.rs:80:31 + | +LL | const ASSOC_CONST: i32 = {while true {} 1}; + | ^^^^^^^^^^ help: use `loop` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:79:12 + | +LL | #[deny(while_true)] + | ^^^^^^^^^^ + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:83:23 + | +LL | type assoc_type = (i32); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:82:12 + | +LL | #[deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - type assoc_type = (i32); +LL + type assoc_type = i32; + | + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:87:31 + | +LL | #[deny(unused_parens)]f1: (i32), + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:87:12 + | +LL | #[deny(unused_parens)]f1: (i32), + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - #[deny(unused_parens)]f1: (i32), +LL + #[deny(unused_parens)]f1: i32, + | + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:89:42 + | +LL | struct StructTuple(#[deny(unused_parens)](i32)); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:89:27 + | +LL | struct StructTuple(#[deny(unused_parens)](i32)); + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - struct StructTuple(#[deny(unused_parens)](i32)); +LL + struct StructTuple(#[deny(unused_parens)]i32); + | + +error: variant `VARIANT_CAMEL` should have an upper camel case name + --> $DIR/lint-attr-everywhere-early.rs:93:5 + | +LL | VARIANT_CAMEL, + | ^^^^^^^^^^^^^ help: convert the identifier to upper camel case: `VariantCamel` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:92:12 + | +LL | #[deny(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:99:37 + | +LL | fn foreign_denied_from_inner(x: (i32)); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:97:13 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - fn foreign_denied_from_inner(x: (i32)); +LL + fn foreign_denied_from_inner(x: i32); + | + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:104:37 + | +LL | fn foreign_denied_from_outer(x: (i32)); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:103:12 + | +LL | #[deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - fn foreign_denied_from_outer(x: (i32)); +LL + fn foreign_denied_from_outer(x: i32); + | + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:107:43 + | +LL | fn function(#[deny(unused_parens)] param: (i32)) {} + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:107:20 + | +LL | fn function(#[deny(unused_parens)] param: (i32)) {} + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - fn function(#[deny(unused_parens)] param: (i32)) {} +LL + fn function(#[deny(unused_parens)] param: i32) {} + | + +error: type parameter `foo` should have an upper camel case name + --> $DIR/lint-attr-everywhere-early.rs:109:42 + | +LL | fn generics<#[deny(non_camel_case_types)]foo>() {} + | ^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:109:20 + | +LL | fn generics<#[deny(non_camel_case_types)]foo>() {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary parentheses around assigned value + --> $DIR/lint-attr-everywhere-early.rs:115:13 + | +LL | let x = (1); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:114:12 + | +LL | #[deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let x = (1); +LL + let x = 1; + | + +error: unnecessary parentheses around type + --> $DIR/lint-attr-everywhere-early.rs:121:50 + | +LL | let closure = |#[deny(unused_parens)] param: (i32)| {}; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:121:27 + | +LL | let closure = |#[deny(unused_parens)] param: (i32)| {}; + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let closure = |#[deny(unused_parens)] param: (i32)| {}; +LL + let closure = |#[deny(unused_parens)] param: i32| {}; + | + +error: unnecessary parentheses around block return value + --> $DIR/lint-attr-everywhere-early.rs:125:46 + | +LL | let f = Match{#[deny(unused_parens)]f1: {(123)}}; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:125:26 + | +LL | let f = Match{#[deny(unused_parens)]f1: {(123)}}; + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let f = Match{#[deny(unused_parens)]f1: {(123)}}; +LL + let f = Match{#[deny(unused_parens)]f1: {123}}; + | + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:132:13 + | +LL | unsafe {} + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:128:17 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: denote infinite loops with `loop { ... }` + --> $DIR/lint-attr-everywhere-early.rs:133:13 + | +LL | while true {} + | ^^^^^^^^^^ help: use `loop` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:130:16 + | +LL | #[deny(while_true)] + | ^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:140:9 + | +LL | unsafe {} + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:139:17 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:144:9 + | +LL | unsafe {} + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:143:16 + | +LL | #[deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:149:5 + | +LL | unsafe {}; + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:148:12 + | +LL | #[deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:151:27 + | +LL | [#[deny(unsafe_code)] unsafe {123}]; + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:151:13 + | +LL | [#[deny(unsafe_code)] unsafe {123}]; + | ^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:152:27 + | +LL | (#[deny(unsafe_code)] unsafe {123},); + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:152:13 + | +LL | (#[deny(unsafe_code)] unsafe {123},); + | ^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:154:31 + | +LL | call(#[deny(unsafe_code)] unsafe {123}); + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:154:17 + | +LL | call(#[deny(unsafe_code)] unsafe {123}); + | ^^^^^^^^^^^ + +error: usage of an `unsafe` block + --> $DIR/lint-attr-everywhere-early.rs:156:38 + | +LL | TupleStruct(#[deny(unsafe_code)] unsafe {123}); + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:156:24 + | +LL | TupleStruct(#[deny(unsafe_code)] unsafe {123}); + | ^^^^^^^^^^^ + +error: `...` range patterns are deprecated + --> $DIR/lint-attr-everywhere-early.rs:167:18 + | +LL | f1: 0...100, + | ^^^ help: use `..=` for an inclusive range + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-early.rs:166:20 + | +LL | #[deny(ellipsis_inclusive_range_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + +error: aborting due to 36 previous errors + diff --git a/src/test/ui/lint/lint-attr-everywhere-late.rs b/src/test/ui/lint/lint-attr-everywhere-late.rs new file mode 100644 index 0000000000000..1055157d6020c --- /dev/null +++ b/src/test/ui/lint/lint-attr-everywhere-late.rs @@ -0,0 +1,197 @@ +// Tests that lint levels can be set for late lints. +#![allow( + non_snake_case, + overflowing_literals, + missing_docs, + dyn_drop, + enum_intrinsics_non_enums, + clashing_extern_declarations +)] + +extern crate core; +use core::mem::{Discriminant, discriminant}; + +// The following is a check of the lints used here to verify they do not warn +// when allowed. +pub fn missing_docs_allowed() {} // missing_docs +fn dyn_drop_allowed(_x: Box) {} // dyn_drop +fn verify_no_warnings() { + discriminant::(&123); // enum_intrinsics_non_enums + let x: u8 = 1000; // overflowing_literals + let NON_SNAKE_CASE = 1; // non_snake_case +} +mod clashing_extern_allowed { + extern "C" { + fn extern_allowed(); + } +} +extern "C" { + fn extern_allowed(_: i32); // clashing_extern_declarations +} + +// ################## Types + +#[deny(missing_docs)] +pub type MissingDocType = i32; //~ ERROR missing documentation for a type alias + +// There aren't any late lints that I can find that can be easily used with types. +// type BareFnPtr = fn(#[deny()]i32); +// type BareFnPtrVariadic = extern "C" fn(i32, #[deny()]...); + +// ################## Items +#[deny(missing_docs)] +pub struct ItemOuter; //~ ERROR missing documentation for a struct + +pub mod module_inner { //~ ERROR missing documentation for a module + #![deny(missing_docs)] + pub fn missing_inner() {} //~ ERROR missing documentation for a function +} + +pub struct Associated; +impl Associated { + #![deny(missing_docs)] + + pub fn inherent_denied_from_inner() {} //~ ERROR missing documentation for an associated function +} + +impl Associated { + #[deny(missing_docs)] + pub fn inherent_fn() {} //~ ERROR missing documentation for an associated function + + #[deny(missing_docs)] + pub const INHERENT_CONST: i32 = 1; //~ ERROR missing documentation for an associated constant +} + +pub trait TraitInner { //~ ERROR missing documentation for a trait + #![deny(missing_docs)] +} + +pub trait AssociatedTraitInner { //~ ERROR missing documentation for a trait + #![deny(missing_docs)] + + fn denied_from_inner() {} //~ ERROR missing documentation for an associated function +} + +pub trait AssociatedTrait { + fn denied_from_inner(_x: Box) {} // Used below + + #[deny(missing_docs)] + fn assoc_fn() {} //~ ERROR missing documentation for an associated function + + #[deny(missing_docs)] + const ASSOC_CONST: u8 = 1; //~ ERROR missing documentation for an associated constant + + #[deny(missing_docs)] + type AssocType; //~ ERROR missing documentation for an associated type +} + +struct Foo; + +impl AssociatedTrait for Associated { + #![deny(dyn_drop)] + + fn denied_from_inner(_x: Box) {} //~ ERROR types that do not implement `Drop` + + #[deny(enum_intrinsics_non_enums)] + fn assoc_fn() { discriminant::(&123); } //~ ERROR the return value of + + #[deny(overflowing_literals)] const ASSOC_CONST: u8 = 1000; //~ ERROR literal out of range + type AssocType = i32; +} + + +// There aren't any late lints that can apply to a field that I can find. +// non_snake_case doesn't work on fields +// struct StructFields { +// #[deny()]f1: i32, +// } +// struct StructTuple(#[deny()]i32); + +pub enum Enum { + #[deny(missing_docs)] + Variant1, //~ ERROR missing documentation for a variant +} + +mod clashing_extern { + extern "C" { + fn clashing1(); + fn clashing2(); + } +} +extern "C" { + #![deny(clashing_extern_declarations)] + fn clashing1(_: i32); //~ ERROR `clashing1` redeclared with a different signature +} + +extern "C" { + #[deny(clashing_extern_declarations)] + fn clashing2(_: i32); //~ ERROR `clashing2` redeclared with a different signature +} + +fn function(#[deny(non_snake_case)] PARAM: i32) {} //~ ERROR variable `PARAM` should have a snake case name +// There aren't any late lints that can apply to generics that I can find. +// fn generics<#[deny()]T>() {} + + +// ################## Statements +fn statements() { + #[deny(enum_intrinsics_non_enums)] + let _ = discriminant::(&123); //~ ERROR the return value of +} + + +// ################## Expressions +fn expressions() { + let closure = |#[deny(non_snake_case)] PARAM: i32| {}; //~ ERROR variable `PARAM` should have a snake case name + + struct Match{f1: i32} + // I can't find any late lints for patterns. + // let f = Match{#[deny()]f1: 123}; + + let f = Match{f1: 123}; + match f { + #![deny(enum_intrinsics_non_enums)] + Match{f1} => { + discriminant::(&123); //~ ERROR the return value of + } + } + match f { + #[deny(enum_intrinsics_non_enums)] + Match{f1} => { + discriminant::(&123); //~ ERROR the return value of + } + } + + // Statement Block + { + #![deny(enum_intrinsics_non_enums)] + discriminant::(&123); //~ ERROR the return value of + } + let block_tail = { + #[deny(enum_intrinsics_non_enums)] + discriminant::(&123); //~ ERROR the return value of + }; + + // Before expression as a statement. + #[deny(enum_intrinsics_non_enums)] + discriminant::(&123); //~ ERROR the return value of + + [#[deny(enum_intrinsics_non_enums)] discriminant::(&123)]; //~ ERROR the return value of + (#[deny(enum_intrinsics_non_enums)] discriminant::(&123),); //~ ERROR the return value of + fn call(p: Discriminant) {} + call(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); //~ ERROR the return value of + struct TupleStruct(Discriminant); + TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); //~ ERROR the return value of +} + + +// ################## Patterns +fn patterns() { + // There aren't any late lints that I can find that apply to pattern fields. + // + // struct PatField{f1: i32, f2: i32}; + // let f = PatField{f1: 1, f2: 2}; + // let PatField{#[deny()]f1, #[deny()]..} = f; +} + +fn main() {} diff --git a/src/test/ui/lint/lint-attr-everywhere-late.stderr b/src/test/ui/lint/lint-attr-everywhere-late.stderr new file mode 100644 index 0000000000000..977843997c6dc --- /dev/null +++ b/src/test/ui/lint/lint-attr-everywhere-late.stderr @@ -0,0 +1,428 @@ +error: missing documentation for a type alias + --> $DIR/lint-attr-everywhere-late.rs:35:1 + | +LL | pub type MissingDocType = i32; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:34:8 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for a struct + --> $DIR/lint-attr-everywhere-late.rs:43:1 + | +LL | pub struct ItemOuter; + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:42:8 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for a module + --> $DIR/lint-attr-everywhere-late.rs:45:1 + | +LL | pub mod module_inner { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:46:13 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for a function + --> $DIR/lint-attr-everywhere-late.rs:47:5 + | +LL | pub fn missing_inner() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for an associated function + --> $DIR/lint-attr-everywhere-late.rs:54:5 + | +LL | pub fn inherent_denied_from_inner() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:52:13 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for an associated function + --> $DIR/lint-attr-everywhere-late.rs:59:5 + | +LL | pub fn inherent_fn() {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:58:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for an associated constant + --> $DIR/lint-attr-everywhere-late.rs:62:5 + | +LL | pub const INHERENT_CONST: i32 = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:61:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for a trait + --> $DIR/lint-attr-everywhere-late.rs:65:1 + | +LL | pub trait TraitInner { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:66:13 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for a trait + --> $DIR/lint-attr-everywhere-late.rs:69:1 + | +LL | pub trait AssociatedTraitInner { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:70:13 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for an associated function + --> $DIR/lint-attr-everywhere-late.rs:72:5 + | +LL | fn denied_from_inner() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for an associated function + --> $DIR/lint-attr-everywhere-late.rs:79:5 + | +LL | fn assoc_fn() {} + | ^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:78:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for an associated constant + --> $DIR/lint-attr-everywhere-late.rs:82:5 + | +LL | const ASSOC_CONST: u8 = 1; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:81:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for an associated type + --> $DIR/lint-attr-everywhere-late.rs:85:5 + | +LL | type AssocType; + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:84:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for a variant + --> $DIR/lint-attr-everywhere-late.rs:112:5 + | +LL | Variant1, + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:111:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: `clashing1` redeclared with a different signature + --> $DIR/lint-attr-everywhere-late.rs:123:5 + | +LL | fn clashing1(); + | --------------- `clashing1` previously declared here +... +LL | fn clashing1(_: i32); + | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:122:13 + | +LL | #![deny(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `unsafe extern "C" fn()` + found `unsafe extern "C" fn(i32)` + +error: `clashing2` redeclared with a different signature + --> $DIR/lint-attr-everywhere-late.rs:128:5 + | +LL | fn clashing2(); + | --------------- `clashing2` previously declared here +... +LL | fn clashing2(_: i32); + | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:127:12 + | +LL | #[deny(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `unsafe extern "C" fn()` + found `unsafe extern "C" fn(i32)` + +error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped + --> $DIR/lint-attr-everywhere-late.rs:93:38 + | +LL | fn denied_from_inner(_x: Box) {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:91:13 + | +LL | #![deny(dyn_drop)] + | ^^^^^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:96:21 + | +LL | fn assoc_fn() { discriminant::(&123); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:95:12 + | +LL | #[deny(enum_intrinsics_non_enums)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:96:41 + | +LL | fn assoc_fn() { discriminant::(&123); } + | ^^^^ + +error: literal out of range for `u8` + --> $DIR/lint-attr-everywhere-late.rs:98:59 + | +LL | #[deny(overflowing_literals)] const ASSOC_CONST: u8 = 1000; + | ^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:98:12 + | +LL | #[deny(overflowing_literals)] const ASSOC_CONST: u8 = 1000; + | ^^^^^^^^^^^^^^^^^^^^ + = note: the literal `1000` does not fit into the type `u8` whose range is `0..=255` + +error: variable `PARAM` should have a snake case name + --> $DIR/lint-attr-everywhere-late.rs:131:37 + | +LL | fn function(#[deny(non_snake_case)] PARAM: i32) {} + | ^^^^^ help: convert the identifier to snake case: `param` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:131:20 + | +LL | fn function(#[deny(non_snake_case)] PARAM: i32) {} + | ^^^^^^^^^^^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:139:13 + | +LL | let _ = discriminant::(&123); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:138:12 + | +LL | #[deny(enum_intrinsics_non_enums)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:139:33 + | +LL | let _ = discriminant::(&123); + | ^^^^ + +error: variable `PARAM` should have a snake case name + --> $DIR/lint-attr-everywhere-late.rs:145:44 + | +LL | let closure = |#[deny(non_snake_case)] PARAM: i32| {}; + | ^^^^^ help: convert the identifier to snake case: `param` + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:145:27 + | +LL | let closure = |#[deny(non_snake_case)] PARAM: i32| {}; + | ^^^^^^^^^^^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:155:13 + | +LL | discriminant::(&123); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:153:17 + | +LL | #![deny(enum_intrinsics_non_enums)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:155:33 + | +LL | discriminant::(&123); + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:161:13 + | +LL | discriminant::(&123); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:159:16 + | +LL | #[deny(enum_intrinsics_non_enums)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:161:33 + | +LL | discriminant::(&123); + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:168:9 + | +LL | discriminant::(&123); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:167:17 + | +LL | #![deny(enum_intrinsics_non_enums)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:168:29 + | +LL | discriminant::(&123); + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:172:9 + | +LL | discriminant::(&123); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:171:16 + | +LL | #[deny(enum_intrinsics_non_enums)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:172:29 + | +LL | discriminant::(&123); + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:177:5 + | +LL | discriminant::(&123); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:176:12 + | +LL | #[deny(enum_intrinsics_non_enums)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:177:25 + | +LL | discriminant::(&123); + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:179:41 + | +LL | [#[deny(enum_intrinsics_non_enums)] discriminant::(&123)]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:179:13 + | +LL | [#[deny(enum_intrinsics_non_enums)] discriminant::(&123)]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:179:61 + | +LL | [#[deny(enum_intrinsics_non_enums)] discriminant::(&123)]; + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:180:41 + | +LL | (#[deny(enum_intrinsics_non_enums)] discriminant::(&123),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:180:13 + | +LL | (#[deny(enum_intrinsics_non_enums)] discriminant::(&123),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:180:61 + | +LL | (#[deny(enum_intrinsics_non_enums)] discriminant::(&123),); + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:182:45 + | +LL | call(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:182:17 + | +LL | call(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:182:65 + | +LL | call(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); + | ^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-attr-everywhere-late.rs:184:52 + | +LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:184:24 + | +LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. + --> $DIR/lint-attr-everywhere-late.rs:184:72 + | +LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); + | ^^^^ + +error: aborting due to 31 previous errors + diff --git a/src/test/ui/lint/unused/unused_attributes-must_use.rs b/src/test/ui/lint/unused/unused_attributes-must_use.rs index 1c4abb9491e00..51f868706b69b 100644 --- a/src/test/ui/lint/unused/unused_attributes-must_use.rs +++ b/src/test/ui/lint/unused/unused_attributes-must_use.rs @@ -122,4 +122,10 @@ fn main() { Some(res) => res, None => 0, }; + + struct PatternField { + foo: i32, + } + let s = PatternField { #[must_use] foo: 123 }; //~ ERROR `#[must_use]` has no effect + let PatternField { #[must_use] foo } = s; //~ ERROR `#[must_use]` has no effect } diff --git a/src/test/ui/lint/unused/unused_attributes-must_use.stderr b/src/test/ui/lint/unused/unused_attributes-must_use.stderr index 317d81c591d55..dd112c23e5d9e 100644 --- a/src/test/ui/lint/unused/unused_attributes-must_use.stderr +++ b/src/test/ui/lint/unused/unused_attributes-must_use.stderr @@ -105,6 +105,18 @@ error: `#[must_use]` has no effect when applied to an match arm LL | #[must_use] | ^^^^^^^^^^^ +error: `#[must_use]` has no effect when applied to a struct field + --> $DIR/unused_attributes-must_use.rs:129:28 + | +LL | let s = PatternField { #[must_use] foo: 123 }; + | ^^^^^^^^^^^ + +error: `#[must_use]` has no effect when applied to a pattern field + --> $DIR/unused_attributes-must_use.rs:130:24 + | +LL | let PatternField { #[must_use] foo } = s; + | ^^^^^^^^^^^ + error: `#[must_use]` has no effect when applied to an associated const --> $DIR/unused_attributes-must_use.rs:68:5 | @@ -171,5 +183,5 @@ error: unused return value of `Use::get_four` that must be used LL | ().get_four(); | ^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 5d41c63928dfb..59f10247a11d4 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; -use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; +use clippy_utils::{get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; @@ -699,6 +699,19 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)) }, + Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) { + Some(Expr { + hir_id, + kind: ExprKind::Struct(path, ..), + .. + }) => variant_of_res(cx, cx.qpath_res(path, *hir_id)) + .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name)) + .map(|field_def| { + ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg() + }), + _ => None, + }, + Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind { ExprKind::Ret(_) => { let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap()); @@ -788,17 +801,6 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & } }) }, - ExprKind::Struct(path, fields, _) => { - let variant = variant_of_res(cx, cx.qpath_res(path, parent.hir_id)); - fields - .iter() - .find(|f| f.expr.hir_id == child_id) - .zip(variant) - .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name)) - .map(|field| { - ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg() - }) - }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)