about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs14
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs17
-rw-r--r--compiler/rustc_hir/src/hir.rs4
-rw-r--r--compiler/rustc_hir/src/intravisit.rs30
-rw-r--r--compiler/rustc_hir/src/target.rs4
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs60
-rw-r--r--compiler/rustc_lint/src/early.rs13
-rw-r--r--compiler/rustc_lint/src/levels.rs18
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs17
-rw-r--r--compiler/rustc_lint/src/types.rs98
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs6
-rw-r--r--compiler/rustc_passes/src/check_attr.rs14
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs25
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs2
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs2
-rw-r--r--src/test/ui/lint/lint-attr-everywhere-early.rs176
-rw-r--r--src/test/ui/lint/lint-attr-everywhere-early.stderr486
-rw-r--r--src/test/ui/lint/lint-attr-everywhere-late.rs197
-rw-r--r--src/test/ui/lint/lint-attr-everywhere-late.stderr428
-rw-r--r--src/test/ui/lint/unused/unused_attributes-must_use.rs6
-rw-r--r--src/test/ui/lint/unused/unused_attributes-must_use.stderr14
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs26
23 files changed, 1520 insertions, 141 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 92e6bc6013d..32dbd2ff47d 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 e08c1d063c1..2b7431f0990 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 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..2610d0b92d8 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 51b1bfad8a0..900370937f7 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 6236dea10c8..78bfd7191db 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 c7966b662de..e6fcb84730e 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 cbf1a677555..580a4566869 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, &param.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 7ab9302d835..1cabb58bbeb 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 8d04d68bf1c..2868aabfa07 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 5c07afeb7aa..cafd2c6e679 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 47b04c33ec1..79e6804a289 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 f75fffb6871..5789531d2ff 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 bac0be44aa9..07046f3f032 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 a2c23db162b..3e96b3ffb09 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 a13c7152582..6dcc364bb50 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 00000000000..fd0c4b43e05
--- /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<foo>() {} // 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 00000000000..1d6e3cda4e5
--- /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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+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 00000000000..1055157d602
--- /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>) {} // dyn_drop
+fn verify_no_warnings() {
+    discriminant::<i32>(&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<dyn Drop>) {} // 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<dyn Drop>) {} //~ ERROR types that do not implement `Drop`
+
+    #[deny(enum_intrinsics_non_enums)]
+    fn assoc_fn() { discriminant::<i32>(&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::<i32>(&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::<i32>(&123); //~ ERROR the return value of
+        }
+    }
+    match f {
+        #[deny(enum_intrinsics_non_enums)]
+        Match{f1} => {
+            discriminant::<i32>(&123); //~ ERROR the return value of
+        }
+    }
+
+    // Statement Block
+    {
+        #![deny(enum_intrinsics_non_enums)]
+        discriminant::<i32>(&123); //~ ERROR the return value of
+    }
+    let block_tail = {
+        #[deny(enum_intrinsics_non_enums)]
+        discriminant::<i32>(&123); //~ ERROR the return value of
+    };
+
+    // Before expression as a statement.
+    #[deny(enum_intrinsics_non_enums)]
+    discriminant::<i32>(&123); //~ ERROR the return value of
+
+    [#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)]; //~ ERROR the return value of
+    (#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123),); //~ ERROR the return value of
+    fn call(p: Discriminant<i32>) {}
+    call(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)); //~ ERROR the return value of
+    struct TupleStruct(Discriminant<i32>);
+    TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&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 00000000000..977843997c6
--- /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<dyn Drop>) {}
+   |                                      ^^^^
+   |
+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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&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::<i32>(&123)];
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:179:13
+   |
+LL |     [#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&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::<i32>(&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::<i32>(&123),);
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:180:13
+   |
+LL |     (#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&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::<i32>(&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::<i32>(&123));
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:182:17
+   |
+LL |     call(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&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::<i32>(&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::<i32>(&123));
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:184:24
+   |
+LL |     TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&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::<i32>(&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 1c4abb9491e..51f868706b6 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 317d81c591d..dd112c23e5d 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 5d41c63928d..59f10247a11 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)