diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index e08c1d063c1..ecc26faf20d 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -193,6 +193,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_pat(&mut self, pat: &'hir Pat<'hir>) { self.insert(pat.span, pat.hir_id, Node::Pat(pat)); + if let PatKind::Struct(_, fields, _) = pat.kind { + for field in fields { + self.insert(field.span, field.hir_id, Node::PatField(field)); + } + } self.with_parent(pat.hir_id, |this| { intravisit::walk_pat(this, pat); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index bd2e76e5528..51f67e505f4 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 7a87a3e4882..9885d33d444 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3338,6 +3338,7 @@ pub enum Node<'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 +3389,7 @@ impl<'hir> Node<'hir> { | Node::Block(..) | Node::Ctor(..) | Node::Pat(..) + | Node::PatField(..) | Node::Arm(..) | Node::Local(..) | Node::Crate(..) diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 6236dea10c8..1b05c82eade 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -56,6 +56,7 @@ pub enum Target { GenericParam(GenericParamKind), MacroDef, Param, + PatField, } impl Display for Target { @@ -183,6 +184,7 @@ impl Target { }, Target::MacroDef => "macro def", Target::Param => "function param", + Target::PatField => "pattern field", } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e0179bd3ed1..641175d4529 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -89,6 +89,7 @@ impl<'a> State<'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) => { @@ -1799,20 +1800,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(","); @@ -1907,6 +1895,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_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 47b04c33ec1..06fdef4142e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -297,6 +297,7 @@ impl<'hir> Map<'hir> { | Node::Infer(_) | Node::TraitRef(_) | Node::Pat(_) + | Node::PatField(_) | Node::Local(_) | Node::Param(_) | Node::Arm(_) @@ -1030,6 +1031,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)), @@ -1247,6 +1249,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { 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 f75fffb6871..42f5806c1f7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -652,7 +652,8 @@ impl CheckAttrVisitor<'_> { | Target::ForeignStatic | Target::ForeignTy | Target::GenericParam(..) - | Target::MacroDef => None, + | Target::MacroDef + | Target::PatField => None, } { tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location }); return false; @@ -2076,6 +2077,15 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_param(self, param); } + + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + if let hir::PatKind::Struct(_, fields, _) = p.kind { + for field in fields { + self.check_attributes(field.hir_id, field.span, Target::PatField, None); + } + } + intravisit::walk_pat(self, p); + } } fn is_c_like_enum(item: &Item<'_>) -> bool { 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 a2c23db162b..f1f4b05b33b 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,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { | hir::Node::TypeBinding(..) | hir::Node::TraitRef(..) | hir::Node::Pat(..) + | hir::Node::PatField(..) | hir::Node::Arm(..) | hir::Node::Local(..) | hir::Node::Ctor(..) 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 1c4abb9491e..87f498c0aee 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 { foo: 123 }; + 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 317d81c591d..3d2672687f8 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,12 @@ 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 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 +177,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 27 previous errors