diff --git a/compiler/rustc_error_codes/src/error_codes/E0451.md b/compiler/rustc_error_codes/src/error_codes/E0451.md
index 821073fe16eae..a12378a206de2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0451.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0451.md
@@ -3,14 +3,14 @@ A struct constructor with private fields was invoked.
 Erroneous code example:
 
 ```compile_fail,E0451
-mod Bar {
+mod bar {
     pub struct Foo {
         pub a: isize,
         b: isize,
     }
 }
 
-let f = Bar::Foo{ a: 0, b: 0 }; // error: field `b` of struct `Bar::Foo`
+let f = bar::Foo{ a: 0, b: 0 }; // error: field `b` of struct `bar::Foo`
                                 //        is private
 ```
 
@@ -18,20 +18,20 @@ To fix this error, please ensure that all the fields of the struct are public,
 or implement a function for easy instantiation. Examples:
 
 ```
-mod Bar {
+mod bar {
     pub struct Foo {
         pub a: isize,
         pub b: isize, // we set `b` field public
     }
 }
 
-let f = Bar::Foo{ a: 0, b: 0 }; // ok!
+let f = bar::Foo{ a: 0, b: 0 }; // ok!
 ```
 
 Or:
 
 ```
-mod Bar {
+mod bar {
     pub struct Foo {
         pub a: isize,
         b: isize, // still private
@@ -44,5 +44,5 @@ mod Bar {
     }
 }
 
-let f = Bar::Foo::new(); // ok!
+let f = bar::Foo::new(); // ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0574.md b/compiler/rustc_error_codes/src/error_codes/E0574.md
index 8154d5b782e36..4881f61d0bc48 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0574.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0574.md
@@ -4,9 +4,9 @@ expected.
 Erroneous code example:
 
 ```compile_fail,E0574
-mod Mordor {}
+mod mordor {}
 
-let sauron = Mordor { x: () }; // error!
+let sauron = mordor { x: () }; // error!
 
 enum Jak {
     Daxter { i: isize },
@@ -19,17 +19,17 @@ match eco {
 ```
 
 In all these errors, a type was expected. For example, in the first error,
-we tried to instantiate the `Mordor` module, which is impossible. If you want
+we tried to instantiate the `mordor` module, which is impossible. If you want
 to instantiate a type inside a module, you can do it as follow:
 
 ```
-mod Mordor {
+mod mordor {
     pub struct TheRing {
         pub x: usize,
     }
 }
 
-let sauron = Mordor::TheRing { x: 1 }; // ok!
+let sauron = mordor::TheRing { x: 1 }; // ok!
 ```
 
 In the second error, we tried to bind the `Jak` enum directly, which is not
diff --git a/compiler/rustc_error_codes/src/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md
index 1feb9c0acf364..eba2d3b14175b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0577.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0577.md
@@ -11,13 +11,13 @@ fn main() {}
 ```
 
 `Sea` is not a module, therefore it is invalid to use it in a visibility path.
-To fix this error we need to ensure `Sea` is a module.
+To fix this error we need to ensure `sea` is a module.
 
 Please note that the visibility scope can only be applied on ancestors!
 
 ```edition2018
-pub mod Sea {
-    pub (in crate::Sea) struct Shark; // ok!
+pub mod sea {
+    pub (in crate::sea) struct Shark; // ok!
 }
 
 fn main() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0603.md b/compiler/rustc_error_codes/src/error_codes/E0603.md
index 69fefce3908fd..eb293118acc86 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0603.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0603.md
@@ -3,13 +3,13 @@ A private item was used outside its scope.
 Erroneous code example:
 
 ```compile_fail,E0603
-mod SomeModule {
+mod foo {
     const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we
                                             // can't use it outside of the
-                                            // `SomeModule` module.
+                                            // `foo` module.
 }
 
-println!("const value: {}", SomeModule::PRIVATE); // error: constant `PRIVATE`
+println!("const value: {}", foo::PRIVATE); // error: constant `PRIVATE`
                                                   //        is private
 ```
 
@@ -17,10 +17,10 @@ In order to fix this error, you need to make the item public by using the `pub`
 keyword. Example:
 
 ```
-mod SomeModule {
+mod foo {
     pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the
                                                 // `pub` keyword.
 }
 
-println!("const value: {}", SomeModule::PRIVATE); // ok!
+println!("const value: {}", foo::PRIVATE); // ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0742.md b/compiler/rustc_error_codes/src/error_codes/E0742.md
index fed9f1f4cee9c..e10c1639dd38a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0742.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0742.md
@@ -4,18 +4,18 @@ item.
 Erroneous code example:
 
 ```compile_fail,E0742,edition2018
-pub mod Sea {}
+pub mod sea {}
 
-pub (in crate::Sea) struct Shark; // error!
+pub (in crate::sea) struct Shark; // error!
 
 fn main() {}
 ```
 
-To fix this error, we need to move the `Shark` struct inside the `Sea` module:
+To fix this error, we need to move the `Shark` struct inside the `sea` module:
 
 ```edition2018
-pub mod Sea {
-    pub (in crate::Sea) struct Shark; // ok!
+pub mod sea {
+    pub (in crate::sea) struct Shark; // ok!
 }
 
 fn main() {}
@@ -25,9 +25,9 @@ Of course, you can do it as long as the module you're referring to is an
 ancestor:
 
 ```edition2018
-pub mod Earth {
-    pub mod Sea {
-        pub (in crate::Earth) struct Shark; // ok!
+pub mod earth {
+    pub mod sea {
+        pub (in crate::earth) struct Shark; // ok!
     }
 }
 
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 7043ad5464530..86ff110eec183 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,4 +1,5 @@
 #![allow(rustc::potential_query_instability)]
+#![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(associated_type_defaults)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index b86304ba6b1b1..04af1eaf67b6d 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -380,7 +380,7 @@ pub fn compile_declarative_macro(
     features: &Features,
     def: &ast::Item,
     edition: Edition,
-) -> (SyntaxExtension, Vec<Span>) {
+) -> (SyntaxExtension, Vec<(usize, Span)>) {
     debug!("compile_declarative_macro: {:?}", def);
     let mk_syn_ext = |expander| {
         SyntaxExtension::new(
@@ -539,11 +539,22 @@ pub fn compile_declarative_macro(
         None => {}
     }
 
-    // Compute the spans of the macro rules
-    // We only take the span of the lhs here,
-    // so that the spans of created warnings are smaller.
-    let rule_spans = if def.id != DUMMY_NODE_ID {
-        lhses.iter().map(|lhs| lhs.span()).collect::<Vec<_>>()
+    // Compute the spans of the macro rules for unused rule linting.
+    // To avoid warning noise, only consider the rules of this
+    // macro for the lint, if all rules are valid.
+    // Also, we are only interested in non-foreign macros.
+    let rule_spans = if valid && def.id != DUMMY_NODE_ID {
+        lhses
+            .iter()
+            .zip(rhses.iter())
+            .enumerate()
+            // If the rhs contains an invocation like compile_error!,
+            // don't consider the rule for the unused rule lint.
+            .filter(|(_idx, (_lhs, rhs))| !has_compile_error_macro(rhs))
+            // We only take the span of the lhs here,
+            // so that the spans of created warnings are smaller.
+            .map(|(idx, (lhs, _rhs))| (idx, lhs.span()))
+            .collect::<Vec<_>>()
     } else {
         Vec::new()
     };
@@ -651,6 +662,29 @@ fn check_matcher(sess: &ParseSess, def: &ast::Item, matcher: &[mbe::TokenTree])
     err == sess.span_diagnostic.err_count()
 }
 
+fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
+    match rhs {
+        mbe::TokenTree::Delimited(_sp, d) => {
+            let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| {
+                if let mbe::TokenTree::Token(ident) = ident &&
+                        let TokenKind::Ident(ident, _) = ident.kind &&
+                        ident == sym::compile_error &&
+                        let mbe::TokenTree::Token(bang) = bang &&
+                        let TokenKind::Not = bang.kind &&
+                        let mbe::TokenTree::Delimited(_, del) = args &&
+                        del.delim != Delimiter::Invisible
+                    {
+                        true
+                    } else {
+                        false
+                    }
+            });
+            if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) }
+        }
+        _ => false,
+    }
+}
+
 // `The FirstSets` for a matcher is a mapping from subsequences in the
 // matcher to the FIRST set for that subsequence.
 //
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index c3b79917dda91..120d09ee35382 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -191,6 +191,20 @@ pub enum StmtKind<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Expr<'_>, 104);
 
+#[derive(
+    Clone,
+    Debug,
+    Copy,
+    PartialEq,
+    Eq,
+    Hash,
+    HashStable,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable
+)]
+pub struct LocalVarId(pub hir::HirId);
+
 /// A THIR expression.
 #[derive(Clone, Debug, HashStable)]
 pub struct Expr<'tcx> {
@@ -332,7 +346,7 @@ pub enum ExprKind<'tcx> {
     },
     /// A local variable.
     VarRef {
-        id: hir::HirId,
+        id: LocalVarId,
     },
     /// Used to represent upvars mentioned in a closure/generator
     UpvarRef {
@@ -340,7 +354,7 @@ pub enum ExprKind<'tcx> {
         closure_def_id: DefId,
 
         /// HirId of the root variable
-        var_hir_id: hir::HirId,
+        var_hir_id: LocalVarId,
     },
     /// A borrow, e.g. `&arg`.
     Borrow {
@@ -596,7 +610,7 @@ pub enum PatKind<'tcx> {
         mutability: Mutability,
         name: Symbol,
         mode: BindingMode,
-        var: hir::HirId,
+        var: LocalVarId,
         ty: Ty<'tcx>,
         subpattern: Option<Pat<'tcx>>,
         /// Is this the leftmost occurrence of the binding, i.e., is `var` the
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 981441fab040f..e77f5931dd65d 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -3,8 +3,7 @@
 use crate::build::expr::category::Category;
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use rustc_hir::def_id::DefId;
-use rustc_hir::HirId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::hir::place::Projection as HirProjection;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
@@ -57,7 +56,7 @@ pub(crate) enum PlaceBase {
     /// figure out that it is captured until all the `Field` projections are applied.
     Upvar {
         /// HirId of the upvar
-        var_hir_id: HirId,
+        var_hir_id: LocalVarId,
         /// DefId of the closure
         closure_def_id: DefId,
         /// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
@@ -151,12 +150,12 @@ fn is_ancestor_or_same_capture(
 /// `ty::MinCaptureList` of the root variable `var_hir_id`.
 fn compute_capture_idx<'tcx>(
     closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>,
-    var_hir_id: HirId,
+    var_hir_id: LocalVarId,
     root_var_idx: usize,
 ) -> usize {
     let mut res = 0;
     for (var_id, capture_list) in closure_min_captures {
-        if *var_id == var_hir_id {
+        if *var_id == var_hir_id.0 {
             res += root_var_idx;
             break;
         } else {
@@ -176,12 +175,12 @@ fn compute_capture_idx<'tcx>(
 /// Returns None, when the ancestor is not found.
 fn find_capture_matching_projections<'a, 'tcx>(
     typeck_results: &'a ty::TypeckResults<'tcx>,
-    var_hir_id: HirId,
+    var_hir_id: LocalVarId,
     closure_def_id: DefId,
     projections: &[PlaceElem<'tcx>],
 ) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
     let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
-    let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?;
+    let root_variable_min_captures = closure_min_captures.get(&var_hir_id.0)?;
 
     let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);
 
@@ -500,8 +499,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 source_info,
             ),
             ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
-                let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local());
-                this.lower_captured_upvar(block, upvar_id)
+                this.lower_captured_upvar(block, closure_def_id.expect_local(), var_hir_id)
             }
 
             ExprKind::VarRef { id } => {
@@ -627,11 +625,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn lower_captured_upvar(
         &mut self,
         block: BasicBlock,
-        upvar_id: ty::UpvarId,
+        closure_expr_id: LocalDefId,
+        var_hir_id: LocalVarId,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        let closure_ty = self
-            .typeck_results
-            .node_type(self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
+        let closure_ty =
+            self.typeck_results.node_type(self.tcx.hir().local_def_id_to_hir_id(closure_expr_id));
 
         let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
             self.infcx.closure_kind(closure_substs).unwrap()
@@ -641,8 +639,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         };
 
         block.and(PlaceBuilder::from(PlaceBase::Upvar {
-            var_hir_id: upvar_id.var_path.hir_id,
-            closure_def_id: upvar_id.closure_expr_id.to_def_id(),
+            var_hir_id,
+            closure_def_id: closure_expr_id.to_def_id(),
             closure_kind,
         }))
     }
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 43a84f69699aa..dc1860cb11297 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -14,7 +14,6 @@ use rustc_data_structures::{
     fx::{FxHashSet, FxIndexMap, FxIndexSet},
     stack::ensure_sufficient_stack,
 };
-use rustc_hir::HirId;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
@@ -690,7 +689,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn storage_live_binding(
         &mut self,
         block: BasicBlock,
-        var: HirId,
+        var: LocalVarId,
         span: Span,
         for_guard: ForGuard,
         schedule_drop: bool,
@@ -700,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
         // Altough there is almost always scope for given variable in corner cases
         // like #92893 we might get variable with no scope.
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) && schedule_drop{
+        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
             self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
         }
         Place::from(local_id)
@@ -708,12 +707,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     pub(crate) fn schedule_drop_for_binding(
         &mut self,
-        var: HirId,
+        var: LocalVarId,
         span: Span,
         for_guard: ForGuard,
     ) {
         let local_id = self.var_local_id(var, for_guard);
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) {
+        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) {
             self.schedule_drop(span, region_scope, local_id, DropKind::Value);
         }
     }
@@ -730,7 +729,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Mutability,
             Symbol,
             BindingMode,
-            HirId,
+            LocalVarId,
             Span,
             Ty<'tcx>,
             UserTypeProjections,
@@ -917,7 +916,7 @@ fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
 struct Binding<'tcx> {
     span: Span,
     source: Place<'tcx>,
-    var_id: HirId,
+    var_id: LocalVarId,
     binding_mode: BindingMode,
 }
 
@@ -2184,7 +2183,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         mutability: Mutability,
         name: Symbol,
         mode: BindingMode,
-        var_id: HirId,
+        var_id: LocalVarId,
         var_ty: Ty<'tcx>,
         user_ty: UserTypeProjections,
         has_guard: ArmHasGuard,
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 4ae74433df63d..793066e43c3c7 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -4,11 +4,12 @@ use crate::build::scope::DropKind;
 use crate::thir::constant::parse_float;
 use crate::thir::pattern::pat_from_hir;
 use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{GeneratorKind, HirIdMap, Node};
+use rustc_hir::{GeneratorKind, Node};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
@@ -16,7 +17,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::Allocation;
 use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
 use rustc_middle::mir::*;
-use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
+use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
 use rustc_span::symbol::sym;
@@ -445,7 +446,7 @@ struct Builder<'a, 'tcx> {
 
     /// Maps `HirId`s of variable bindings to the `Local`s created for them.
     /// (A match binding can have two locals; the 2nd is for the arm's guard.)
-    var_indices: HirIdMap<LocalsForNode>,
+    var_indices: FxHashMap<LocalVarId, LocalsForNode>,
     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
     canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
     upvar_mutbls: Vec<Mutability>,
@@ -455,11 +456,11 @@ struct Builder<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool {
+    fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool {
         self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
     }
 
-    fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local {
+    fn var_local_id(&self, id: LocalVarId, for_guard: ForGuard) -> Local {
         self.var_indices[&id].local_id(for_guard)
     }
 }
@@ -543,11 +544,11 @@ enum LocalsForNode {
 
 #[derive(Debug)]
 struct GuardFrameLocal {
-    id: hir::HirId,
+    id: LocalVarId,
 }
 
 impl GuardFrameLocal {
-    fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self {
+    fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self {
         GuardFrameLocal { id }
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index bd9f599fff0a1..fb2f5861c6f03 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -903,9 +903,12 @@ impl<'tcx> Cx<'tcx> {
         );
 
         if is_upvar {
-            ExprKind::UpvarRef { closure_def_id: self.body_owner, var_hir_id }
+            ExprKind::UpvarRef {
+                closure_def_id: self.body_owner,
+                var_hir_id: LocalVarId(var_hir_id),
+            }
         } else {
-            ExprKind::VarRef { id: var_hir_id }
+            ExprKind::VarRef { id: LocalVarId(var_hir_id) }
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index e0dec1daf63c8..417cf0f89c412 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue};
 use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
 use rustc_middle::mir::{self, UserTypeProjection};
 use rustc_middle::mir::{BorrowKind, Field, Mutability};
-use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange};
+use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
@@ -288,7 +288,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     mutability,
                     mode,
                     name: ident.name,
-                    var: id,
+                    var: LocalVarId(id),
                     ty: var_ty,
                     subpattern: self.lower_opt_pattern(sub),
                     is_primary: id == pat.hir_id,
@@ -664,7 +664,7 @@ macro_rules! ClonePatternFoldableImpls {
 }
 
 ClonePatternFoldableImpls! { <'tcx>
-    Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>,
+    Span, Field, Mutability, Symbol, LocalVarId, usize, ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
     SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
     UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 20d9123e411ab..f8fa7a0941d00 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1220,12 +1220,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         ident: Ident,
         def_id: LocalDefId,
         node_id: NodeId,
-        rule_spans: &[Span],
+        rule_spans: &[(usize, Span)],
     ) {
         if !ident.as_str().starts_with('_') {
             self.r.unused_macros.insert(def_id, (node_id, ident));
-            for (rule_i, rule_span) in rule_spans.iter().enumerate() {
-                self.r.unused_macro_rules.insert((def_id, rule_i), (ident, *rule_span));
+            for (rule_i, rule_span) in rule_spans.iter() {
+                self.r.unused_macro_rules.insert((def_id, *rule_i), (ident, *rule_span));
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 2e2d3674560e8..3fb34cdcd9bd9 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -870,7 +870,7 @@ impl<'a> Resolver<'a> {
         &mut self,
         item: &ast::Item,
         edition: Edition,
-    ) -> (SyntaxExtension, Vec<Span>) {
+    ) -> (SyntaxExtension, Vec<(usize, Span)>) {
         let (mut result, mut rule_spans) = compile_declarative_macro(
             &self.session,
             self.session.features_untracked(),
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index b34cac41d78ca..975051100b039 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -16,15 +16,7 @@ pub fn target() -> Target {
     let mut post_link_args = LinkArgs::new();
     post_link_args.insert(
         LinkerFlavor::Em,
-        vec![
-            "-s".into(),
-            "ERROR_ON_UNDEFINED_SYMBOLS=1".into(),
-            "-s".into(),
-            "ASSERTIONS=1".into(),
-            "-s".into(),
-            "ABORTING_MALLOC=0".into(),
-            "-Wl,--fatal-warnings".into(),
-        ],
+        vec!["-sABORTING_MALLOC=0".into(), "-Wl,--fatal-warnings".into()],
     );
 
     let opts = TargetOptions {
diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs
index 97e32ca77db82..81bf1dfdf4510 100644
--- a/library/core/src/hash/sip.rs
+++ b/library/core/src/hash/sip.rs
@@ -38,7 +38,7 @@ struct SipHasher24 {
 /// SipHash is a general-purpose hashing function: it runs at a good
 /// speed (competitive with Spooky and City) and permits strong _keyed_
 /// hashing. This lets you key your hash tables from a strong RNG, such as
-/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
+/// [`rand::os::OsRng`](https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html).
 ///
 /// Although the SipHash algorithm is considered to be generally strong,
 /// it is not intended for cryptographic purposes. As such, all
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index cac7f435573a5..b4ea536083392 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -865,7 +865,7 @@ impl<T> MaybeUninit<T> {
     ///
     /// For instance, you cannot [`Read`] into an uninitialized buffer:
     ///
-    /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
+    /// [`Read`]: ../../std/io/trait.Read.html
     ///
     /// ```rust,no_run
     /// use std::{io, mem::MaybeUninit};
diff --git a/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs b/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs
new file mode 100644
index 0000000000000..4d51db89bc0b3
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs
@@ -0,0 +1,27 @@
+#![deny(unused_macro_rules)]
+// To make sure we are not hitting this
+#![deny(unused_macros)]
+
+macro_rules! num {
+    (one) => { 1 };
+    // Most simple (and common) case
+    (two) => { compile_error!("foo"); };
+    // Some nested use
+    (two_) => { foo(compile_error!("foo")); };
+    (three) => { 3 };
+    (four) => { 4 }; //~ ERROR: rule of macro
+}
+const _NUM: u8 = num!(one) + num!(three);
+
+// compile_error not used as a macro invocation
+macro_rules! num2 {
+    (one) => { 1 };
+    // Only identifier present
+    (two) => { fn compile_error() {} }; //~ ERROR: rule of macro
+    // Only identifier and bang present
+    (two_) => { compile_error! }; //~ ERROR: rule of macro
+    (three) => { 3 };
+}
+const _NUM2: u8 = num2!(one) + num2!(three);
+
+fn main() {}
diff --git a/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr b/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr
new file mode 100644
index 0000000000000..76af8c967db1e
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr
@@ -0,0 +1,26 @@
+error: 5th rule of macro `num` is never used
+  --> $DIR/unused-macro-rules-compile-error.rs:12:5
+   |
+LL |     (four) => { 4 };
+   |     ^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-macro-rules-compile-error.rs:1:9
+   |
+LL | #![deny(unused_macro_rules)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: 3rd rule of macro `num2` is never used
+  --> $DIR/unused-macro-rules-compile-error.rs:22:5
+   |
+LL |     (two_) => { compile_error! };
+   |     ^^^^^^
+
+error: 2nd rule of macro `num2` is never used
+  --> $DIR/unused-macro-rules-compile-error.rs:20:5
+   |
+LL |     (two) => { fn compile_error() {} };
+   |     ^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs
new file mode 100644
index 0000000000000..a826026ec405c
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs
@@ -0,0 +1,11 @@
+#![deny(unused_macro_rules)]
+
+macro_rules! foo {
+    (v) => {};
+    (w) => {};
+    () => 0; //~ ERROR: macro rhs must be delimited
+}
+
+fn main() {
+    foo!(v);
+}
diff --git a/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr
new file mode 100644
index 0000000000000..797c867103f03
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr
@@ -0,0 +1,8 @@
+error: macro rhs must be delimited
+  --> $DIR/unused-macro-rules-malformed-rule.rs:6:11
+   |
+LL |     () => 0;
+   |           ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/unused/unused-macros-malformed-rule.rs b/src/test/ui/lint/unused/unused-macros-malformed-rule.rs
new file mode 100644
index 0000000000000..d4c35fad9b0f0
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macros-malformed-rule.rs
@@ -0,0 +1,15 @@
+#![deny(unused_macros)]
+
+macro_rules! foo { //~ ERROR: unused macro definition
+    (v) => {};
+    () => 0; //~ ERROR: macro rhs must be delimited
+}
+
+macro_rules! bar {
+    (v) => {};
+    () => 0; //~ ERROR: macro rhs must be delimited
+}
+
+fn main() {
+    bar!(v);
+}
diff --git a/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr b/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr
new file mode 100644
index 0000000000000..9a880dccfbf6d
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr
@@ -0,0 +1,26 @@
+error: macro rhs must be delimited
+  --> $DIR/unused-macros-malformed-rule.rs:5:11
+   |
+LL |     () => 0;
+   |           ^
+
+error: macro rhs must be delimited
+  --> $DIR/unused-macros-malformed-rule.rs:10:11
+   |
+LL |     () => 0;
+   |           ^
+
+error: unused macro definition: `foo`
+  --> $DIR/unused-macros-malformed-rule.rs:3:14
+   |
+LL | macro_rules! foo {
+   |              ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-macros-malformed-rule.rs:1:9
+   |
+LL | #![deny(unused_macros)]
+   |         ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+