about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-08 13:11:57 +0000
committerbors <bors@rust-lang.org>2022-09-08 13:11:57 +0000
commit24d69920201563f0ee7b530f1cda0f171b205cc2 (patch)
tree2071fdf41cd4126e7e1c4ed82e5c37f7fd0f17cd
parentccb5595df2ed412eda6444edc7eaf06f709fa79d (diff)
parente67f39f8bcb12dc4c985abe922d78c0daad7e5cd (diff)
downloadrust-24d69920201563f0ee7b530f1cda0f171b205cc2.tar.gz
rust-24d69920201563f0ee7b530f1cda0f171b205cc2.zip
Auto merge of #101467 - nnethercote:shrink-hir-Ty-Pat, r=spastorino
Shrink `hir::Ty` and `hir::Pat`

r? `@ghost`
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs11
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs21
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs57
-rw-r--r--compiler/rustc_hir/src/pat_util.rs6
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs11
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs5
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs8
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/test/ui/stats/hir-stats.stderr77
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs3
19 files changed, 142 insertions, 95 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 6fa8d7f0fcd..f9f273acb7e 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1128,8 +1128,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     );
                     // Destructure like a tuple struct.
-                    let tuple_struct_pat =
-                        hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
+                    let tuple_struct_pat = hir::PatKind::TupleStruct(
+                        qpath,
+                        pats,
+                        hir::DotDotPos::new(rest.map(|r| r.0)),
+                    );
                     return self.pat_without_dbm(lhs.span, tuple_struct_pat);
                 }
             }
@@ -1184,13 +1187,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
             ExprKind::Tup(elements) => {
                 let (pats, rest) =
                     self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
-                let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
+                let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));
                 return self.pat_without_dbm(lhs.span, tuple_pat);
             }
             ExprKind::Paren(e) => {
                 // We special-case `(..)` for consistency with patterns.
                 if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
-                    let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
+                    let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));
                     return self.pat_without_dbm(lhs.span, tuple_pat);
                 } else {
                     return self.destructure_assign_mut(e, eq_sign_span, assignments);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e7bbf7dbdec..e484f77cad4 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1196,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let lifetime_bound = this.elided_dyn_bound(t.span);
                 (bounds, lifetime_bound)
             });
-            let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+            let kind = hir::TyKind::TraitObject(bounds, &lifetime_bound, TraitObjectSyntax::None);
             return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
         }
 
@@ -1934,8 +1934,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let res = res.unwrap_or(
                     self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
                 );
-                let l = self.new_named_lifetime_with_res(id, span, ident, res);
-                hir::GenericArg::Lifetime(l)
+                hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res))
             },
         ));
 
@@ -2004,7 +2003,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
+    fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
         let span = self.lower_span(l.ident.span);
         let ident = self.lower_ident(l.ident);
         self.new_named_lifetime(l.id, l.id, span, ident)
@@ -2017,7 +2016,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         span: Span,
         ident: Ident,
         res: LifetimeRes,
-    ) -> hir::Lifetime {
+    ) -> &'hir hir::Lifetime {
         let name = match res {
             LifetimeRes::Param { param, .. } => {
                 let p_name = ParamName::Plain(ident);
@@ -2038,7 +2037,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
 
         debug!(?name);
-        hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
+        self.arena.alloc(hir::Lifetime {
+            hir_id: self.lower_node_id(id),
+            span: self.lower_span(span),
+            name,
+        })
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -2048,7 +2051,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         new_id: NodeId,
         span: Span,
         ident: Ident,
-    ) -> hir::Lifetime {
+    ) -> &'hir hir::Lifetime {
         let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
         self.new_named_lifetime_with_res(new_id, span, ident, res)
     }
@@ -2462,14 +2465,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// bound, like the bound in `Box<dyn Debug>`. This method is not invoked
     /// when the bound is written, even if it is written with `'_` like in
     /// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
-    fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
+    fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime {
         let r = hir::Lifetime {
             hir_id: self.next_id(),
             span: self.lower_span(span),
             name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
         };
         debug!("elided_dyn_bound: r={:?}", r);
-        r
+        self.arena.alloc(r)
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 69e6c2c8ad0..1ea76fdbfcb 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -116,7 +116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         pats: &[P<Pat>],
         ctx: &str,
-    ) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
+    ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
         let mut elems = Vec::with_capacity(pats.len());
         let mut rest = None;
 
@@ -160,7 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
 
-        (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
+        (self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
     }
 
     /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a668c0e95ce..cc5aed6cb54 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -259,7 +259,7 @@ impl InferArg {
 
 #[derive(Debug, HashStable_Generic)]
 pub enum GenericArg<'hir> {
-    Lifetime(Lifetime),
+    Lifetime(&'hir Lifetime),
     Type(&'hir Ty<'hir>),
     Const(ConstArg),
     Infer(InferArg),
@@ -430,7 +430,7 @@ pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
     // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
     LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
-    Outlives(Lifetime),
+    Outlives(&'hir Lifetime),
 }
 
 impl GenericBound<'_> {
@@ -756,7 +756,7 @@ impl<'hir> WhereBoundPredicate<'hir> {
 pub struct WhereRegionPredicate<'hir> {
     pub span: Span,
     pub in_where_clause: bool,
-    pub lifetime: Lifetime,
+    pub lifetime: &'hir Lifetime,
     pub bounds: GenericBounds<'hir>,
 }
 
@@ -1059,6 +1059,35 @@ impl fmt::Display for RangeEnd {
     }
 }
 
+// Equivalent to `Option<usize>`. That type takes up 16 bytes on 64-bit, but
+// this type only takes up 4 bytes, at the cost of being restricted to a
+// maximum value of `u32::MAX - 1`. In practice, this is more than enough.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct DotDotPos(u32);
+
+impl DotDotPos {
+    // Panics if n >= u32::MAX.
+    pub fn new(n: Option<usize>) -> Self {
+        match n {
+            Some(n) => {
+                assert!(n < u32::MAX as usize);
+                Self(n as u32)
+            }
+            None => Self(u32::MAX),
+        }
+    }
+
+    pub fn as_opt_usize(&self) -> Option<usize> {
+        if self.0 == u32::MAX { None } else { Some(self.0 as usize) }
+    }
+}
+
+impl fmt::Debug for DotDotPos {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_opt_usize().fmt(f)
+    }
+}
+
 #[derive(Debug, HashStable_Generic)]
 pub enum PatKind<'hir> {
     /// Represents a wildcard pattern (i.e., `_`).
@@ -1075,9 +1104,9 @@ pub enum PatKind<'hir> {
     Struct(QPath<'hir>, &'hir [PatField<'hir>], bool),
 
     /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
-    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+    /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
     /// `0 <= position <= subpats.len()`
-    TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option<usize>),
+    TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos),
 
     /// An or-pattern `A | B | C`.
     /// Invariant: `pats.len() >= 2`.
@@ -1089,7 +1118,7 @@ pub enum PatKind<'hir> {
     /// A tuple pattern (e.g., `(a, b)`).
     /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// `0 <= position <= subpats.len()`
-    Tuple(&'hir [Pat<'hir>], Option<usize>),
+    Tuple(&'hir [Pat<'hir>], DotDotPos),
 
     /// A `box` pattern.
     Box(&'hir Pat<'hir>),
@@ -2499,7 +2528,7 @@ pub enum TyKind<'hir> {
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
-    Rptr(Lifetime, MutTy<'hir>),
+    Rptr(&'hir Lifetime, MutTy<'hir>),
     /// A bare function (e.g., `fn(usize) -> bool`).
     BareFn(&'hir BareFnTy<'hir>),
     /// The never type (`!`).
@@ -2518,7 +2547,7 @@ pub enum TyKind<'hir> {
     OpaqueDef(ItemId, &'hir [GenericArg<'hir>]),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
-    TraitObject(&'hir [PolyTraitRef<'hir>], Lifetime, TraitObjectSyntax),
+    TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
     /// Unused for now.
     Typeof(AnonConst),
     /// `TyKind::Infer` means the type should be inferred instead of it having been
@@ -3474,7 +3503,7 @@ mod size_asserts {
     static_assert_size!(ForeignItem<'_>, 72);
     static_assert_size!(ForeignItemKind<'_>, 40);
     #[cfg(not(bootstrap))]
-    static_assert_size!(GenericArg<'_>, 32);
+    static_assert_size!(GenericArg<'_>, 24);
     static_assert_size!(GenericBound<'_>, 48);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
@@ -3486,17 +3515,17 @@ mod size_asserts {
     static_assert_size!(ItemKind<'_>, 48);
     static_assert_size!(Local<'_>, 64);
     static_assert_size!(Param<'_>, 32);
-    static_assert_size!(Pat<'_>, 88);
-    static_assert_size!(PatKind<'_>, 64);
+    static_assert_size!(Pat<'_>, 72);
+    static_assert_size!(PatKind<'_>, 48);
     static_assert_size!(Path<'_>, 48);
     static_assert_size!(PathSegment<'_>, 56);
     static_assert_size!(QPath<'_>, 24);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
     #[cfg(not(bootstrap))]
-    static_assert_size!(TraitItem<'static>, 88);
+    static_assert_size!(TraitItem<'_>, 88);
     #[cfg(not(bootstrap))]
     static_assert_size!(TraitItemKind<'_>, 48);
-    static_assert_size!(Ty<'_>, 72);
-    static_assert_size!(TyKind<'_>, 56);
+    static_assert_size!(Ty<'_>, 48);
+    static_assert_size!(TyKind<'_>, 32);
 }
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index 9baaf9390f2..0c1819bb0c7 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -35,7 +35,7 @@ pub trait EnumerateAndAdjustIterator {
     fn enumerate_and_adjust(
         self,
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> EnumerateAndAdjust<Self>
     where
         Self: Sized;
@@ -45,7 +45,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
     fn enumerate_and_adjust(
         self,
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> EnumerateAndAdjust<Self>
     where
         Self: Sized,
@@ -53,7 +53,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
         let actual_len = self.len();
         EnumerateAndAdjust {
             enumerate: self.enumerate(),
-            gap_pos: gap_pos.unwrap_or(expected_len),
+            gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len),
             gap_len: expected_len - actual_len,
         }
     }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1220755f44b..35a58296e37 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1761,7 +1761,8 @@ impl<'a> State<'a> {
             PatKind::TupleStruct(ref qpath, elts, ddpos) => {
                 self.print_qpath(qpath, true);
                 self.popen();
-                if let Some(ddpos) = ddpos {
+                if let Some(ddpos) = ddpos.as_opt_usize() {
+                    let ddpos = ddpos as usize;
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
@@ -1804,7 +1805,7 @@ impl<'a> State<'a> {
             }
             PatKind::Tuple(elts, ddpos) => {
                 self.popen();
-                if let Some(ddpos) = ddpos {
+                if let Some(ddpos) = ddpos.as_opt_usize() {
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7e09efe5972..4968032b416 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -338,7 +338,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         &mut self,
         pats: &'tcx [hir::Pat<'tcx>],
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> Vec<FieldPat<'tcx>> {
         pats.iter()
             .enumerate_and_adjust(expected_len, gap_pos)
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 625c854ea77..a7ce0f312af 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -226,19 +226,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         lhs: &hir::Pat<'_>,
         res: Res,
         pats: &[hir::Pat<'_>],
-        dotdot: Option<usize>,
+        dotdot: hir::DotDotPos,
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
             ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
         };
-        let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
+        let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len());
+        let first_n = pats.iter().enumerate().take(dotdot);
         let missing = variant.fields.len() - pats.len();
-        let last_n = pats
-            .iter()
-            .enumerate()
-            .skip(dotdot.unwrap_or(pats.len()))
-            .map(|(idx, pat)| (idx + missing, pat));
+        let last_n = pats.iter().enumerate().skip(dotdot).map(|(idx, pat)| (idx + missing, pat));
         for (idx, pat) in first_n.chain(last_n) {
             if let PatKind::Wild = pat.kind {
                 continue;
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 81ac0e1b6d4..075069feb52 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -437,6 +437,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         }
     }
 
+    fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
+        self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime);
+        hir_visit::walk_lifetime(self, lifetime)
+    }
+
     fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
         self.record("Path", Id::None, path);
         hir_visit::walk_path(self, path)
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 9fb915a056a..8906b622b68 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pat: &'tcx Pat<'tcx>,
         qpath: &'tcx hir::QPath<'tcx>,
         subpats: &'tcx [Pat<'tcx>],
-        ddpos: Option<usize>,
+        ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
@@ -1066,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Type-check subpatterns.
         if subpats.len() == variant.fields.len()
-            || subpats.len() < variant.fields.len() && ddpos.is_some()
+            || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
         {
             let ty::Adt(_, substs) = pat_ty.kind() else {
                 bug!("unexpected pattern type {:?}", pat_ty);
@@ -1254,14 +1254,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         span: Span,
         elements: &'tcx [Pat<'tcx>],
-        ddpos: Option<usize>,
+        ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let mut expected_len = elements.len();
-        if ddpos.is_some() {
+        if ddpos.as_opt_usize().is_some() {
             // Require known type only when `..` is present.
             if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
                 expected_len = tys.len();
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c2baea839f6..66f766bfbe8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -190,7 +190,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
     )
 }
 
-fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
+fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
     let def = cx.tcx.named_region(lifetime.hir_id);
     if let Some(
         rl::Region::EarlyBound(node_id)
@@ -495,7 +495,7 @@ fn clean_generic_param<'tcx>(
                     .filter(|bp| !bp.in_where_clause)
                     .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
-                        hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx),
+                        hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx),
                         _ => panic!(),
                     })
                     .collect()
@@ -1392,7 +1392,7 @@ fn maybe_expand_private_type_alias<'tcx>(
                     }
                     _ => None,
                 });
-                if let Some(lt) = lifetime.cloned() {
+                if let Some(lt) = lifetime {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
                     let cleaned =
                         if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr
index c8ceb6ff22d..8d977606530 100644
--- a/src/test/ui/stats/hir-stats.stderr
+++ b/src/test/ui/stats/hir-stats.stderr
@@ -119,59 +119,60 @@ hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
 hir-stats ----------------------------------------------------------------
 hir-stats ForeignItemRef            24 ( 0.2%)             1            24
+hir-stats Lifetime                  32 ( 0.3%)             1            32
 hir-stats Mod                       32 ( 0.3%)             1            32
 hir-stats ExprField                 40 ( 0.4%)             1            40
 hir-stats TraitItemRef              56 ( 0.6%)             2            28
-hir-stats Param                     64 ( 0.6%)             2            32
-hir-stats Local                     64 ( 0.6%)             1            64
+hir-stats Local                     64 ( 0.7%)             1            64
+hir-stats Param                     64 ( 0.7%)             2            32
 hir-stats InlineAsm                 72 ( 0.7%)             1            72
 hir-stats ImplItemRef               72 ( 0.7%)             2            36
-hir-stats FieldDef                  96 ( 0.9%)             2            48
-hir-stats Arm                       96 ( 0.9%)             2            48
-hir-stats Body                      96 ( 0.9%)             3            32
-hir-stats Stmt                      96 ( 0.9%)             3            32
+hir-stats Body                      96 ( 1.0%)             3            32
+hir-stats GenericArg                96 ( 1.0%)             4            24
+hir-stats - Type                      24 ( 0.2%)             1
+hir-stats - Lifetime                  72 ( 0.7%)             3
+hir-stats FieldDef                  96 ( 1.0%)             2            48
+hir-stats Arm                       96 ( 1.0%)             2            48
+hir-stats Stmt                      96 ( 1.0%)             3            32
 hir-stats - Local                     32 ( 0.3%)             1
 hir-stats - Semi                      32 ( 0.3%)             1
 hir-stats - Expr                      32 ( 0.3%)             1
 hir-stats FnDecl                   120 ( 1.2%)             3            40
 hir-stats Attribute                128 ( 1.3%)             4            32
-hir-stats GenericArg               128 ( 1.3%)             4            32
-hir-stats - Type                      32 ( 0.3%)             1
-hir-stats - Lifetime                  96 ( 0.9%)             3
-hir-stats GenericArgs              144 ( 1.4%)             3            48
-hir-stats Variant                  160 ( 1.6%)             2            80
-hir-stats GenericBound             192 ( 1.9%)             4            48
-hir-stats - Trait                    192 ( 1.9%)             4
-hir-stats WherePredicate           216 ( 2.1%)             3            72
-hir-stats - BoundPredicate           216 ( 2.1%)             3
-hir-stats Block                    288 ( 2.8%)             6            48
-hir-stats GenericParam             400 ( 3.9%)             5            80
-hir-stats Pat                      440 ( 4.3%)             5            88
-hir-stats - Wild                      88 ( 0.9%)             1
-hir-stats - Struct                    88 ( 0.9%)             1
-hir-stats - Binding                  264 ( 2.6%)             3
-hir-stats Generics                 560 ( 5.5%)            10            56
-hir-stats Expr                     768 ( 7.6%)            12            64
-hir-stats - Path                      64 ( 0.6%)             1
-hir-stats - Struct                    64 ( 0.6%)             1
-hir-stats - Match                     64 ( 0.6%)             1
-hir-stats - InlineAsm                 64 ( 0.6%)             1
+hir-stats GenericArgs              144 ( 1.5%)             3            48
+hir-stats Variant                  160 ( 1.7%)             2            80
+hir-stats WherePredicate           168 ( 1.7%)             3            56
+hir-stats - BoundPredicate           168 ( 1.7%)             3
+hir-stats GenericBound             192 ( 2.0%)             4            48
+hir-stats - Trait                    192 ( 2.0%)             4
+hir-stats Block                    288 ( 3.0%)             6            48
+hir-stats Pat                      360 ( 3.7%)             5            72
+hir-stats - Wild                      72 ( 0.7%)             1
+hir-stats - Struct                    72 ( 0.7%)             1
+hir-stats - Binding                  216 ( 2.2%)             3
+hir-stats GenericParam             400 ( 4.1%)             5            80
+hir-stats Generics                 560 ( 5.8%)            10            56
+hir-stats Ty                       720 ( 7.4%)            15            48
+hir-stats - Ptr                       48 ( 0.5%)             1
+hir-stats - Rptr                      48 ( 0.5%)             1
+hir-stats - Path                     624 ( 6.4%)            13
+hir-stats Expr                     768 ( 7.9%)            12            64
+hir-stats - Path                      64 ( 0.7%)             1
+hir-stats - Struct                    64 ( 0.7%)             1
+hir-stats - Match                     64 ( 0.7%)             1
+hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.3%)             2
-hir-stats - Block                    384 ( 3.8%)             6
-hir-stats Item                     960 ( 9.4%)            12            80
+hir-stats - Block                    384 ( 4.0%)             6
+hir-stats Item                     960 ( 9.9%)            12            80
 hir-stats - Trait                     80 ( 0.8%)             1
 hir-stats - Enum                      80 ( 0.8%)             1
 hir-stats - ExternCrate               80 ( 0.8%)             1
 hir-stats - ForeignMod                80 ( 0.8%)             1
 hir-stats - Impl                      80 ( 0.8%)             1
-hir-stats - Fn                       160 ( 1.6%)             2
-hir-stats - Use                      400 ( 3.9%)             5
-hir-stats Ty                     1_080 (10.6%)            15            72
-hir-stats - Ptr                       72 ( 0.7%)             1
-hir-stats - Rptr                      72 ( 0.7%)             1
-hir-stats - Path                     936 ( 9.2%)            13
-hir-stats Path                   1_536 (15.1%)            32            48
-hir-stats PathSegment            2_240 (22.0%)            40            56
+hir-stats - Fn                       160 ( 1.7%)             2
+hir-stats - Use                      400 ( 4.1%)             5
+hir-stats Path                   1_536 (15.9%)            32            48
+hir-stats PathSegment            2_240 (23.1%)            40            56
 hir-stats ----------------------------------------------------------------
-hir-stats Total                 10_168
+hir-stats Total                  9_680
 hir-stats
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index fdfb821ac78..bce49165e5b 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -51,7 +51,9 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
             false
         },
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
-        PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a),
+        PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => {
+            !etc.as_opt_usize().is_some() && array_rec(a)
+        }
         PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
         PatKind::Path(_) | PatKind::Lit(_) => true,
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index e32ef9933af..93874b103b4 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -248,7 +248,7 @@ impl<'a> NormalizedPat<'a> {
                 } else {
                     (None, adt.non_enum_variant())
                 };
-                let (front, back) = match wild_idx {
+                let (front, back) = match wild_idx.as_opt_usize() {
                     Some(i) => pats.split_at(i),
                     None => (pats, [].as_slice()),
                 };
@@ -268,7 +268,7 @@ impl<'a> NormalizedPat<'a> {
                     ty::Tuple(subs) => subs.len(),
                     _ => return Self::Wild,
                 };
-                let (front, back) = match wild_idx {
+                let (front, back) = match wild_idx.as_opt_usize() {
                     Some(i) => pats.split_at(i),
                     None => (pats, [].as_slice()),
                 };
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 95478af45b4..1bf1c4d1078 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -200,6 +200,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>,
             // We don't actually know the position and the presence of the `..` (dotdot) operator
             // in the arms, so we need to evaluate the correct offsets here in order to iterate in
             // both arms at the same time.
+            let left_pos = left_pos.as_opt_usize();
+            let right_pos = right_pos.as_opt_usize();
             let len = max(
                 left_in.len() + {
                     if left_pos.is_some() { 1 } else { 0 }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index f4f1fd336df..569870ab2b7 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -122,7 +122,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
     if_chain! {
         if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
         if !is_else_clause(cx.tcx, expr);
-        if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
+        if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
+        if ddpos.as_opt_usize().is_none();
         if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
         let caller_ty = cx.typeck_results().expr_ty(let_expr);
         let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 35824b03170..ce9ebad8c89 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -19,10 +19,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
         && cx.typeck_results().pat_ty(local.pat).is_unit()
     {
         if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
-            || matches!(local.pat.kind, PatKind::Tuple([], None)))
+            || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
             && expr_needs_inferred_result(cx, init)
         {
-            if !matches!(local.pat.kind, PatKind::Wild | PatKind::Tuple([], None)) {
+            if !matches!(local.pat.kind, PatKind::Wild)
+               && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())
+            {
                 span_lint_and_then(
                     cx,
                     LET_UNIT_VALUE,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 57448f716d4..ff23ed5fffa 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -929,7 +929,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         }
     }
 
-    pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
+    pub fn hash_lifetime(&mut self, lifetime: &Lifetime) {
         std::mem::discriminant(&lifetime.name).hash(&mut self.s);
         if let LifetimeName::Param(param_id, ref name) = lifetime.name {
             std::mem::discriminant(name).hash(&mut self.s);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index b27439cbec2..3cf043f22df 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1552,7 +1552,8 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if_chain! {
-            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
+            if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
+            if ddpos.as_opt_usize().is_none();
             if is_lang_ctor(cx, path, ResultOk);
             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
             if path_to_local_id(arm.body, hir_id);