about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_arena/src/lib.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs17
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs3
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs8
-rw-r--r--compiler/rustc_lint/src/builtin.rs19
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs8
-rw-r--r--compiler/rustc_middle/src/middle/resolve_lifetime.rs10
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs3
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs56
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs29
-rw-r--r--compiler/rustc_parse_format/src/lib.rs4
-rw-r--r--compiler/rustc_parse_format/src/tests.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs28
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs454
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs19
-rw-r--r--compiler/rustc_typeck/src/collect.rs23
-rw-r--r--library/alloc/src/vec/into_iter.rs13
-rw-r--r--library/alloc/src/vec/mod.rs4
-rw-r--r--library/core/src/fmt/builders.rs18
-rw-r--r--library/core/src/ptr/const_ptr.rs2
-rw-r--r--library/core/src/ptr/mut_ptr.rs2
-rw-r--r--library/core/src/slice/iter/macros.rs2
-rw-r--r--library/core/tests/atomic.rs2
-rw-r--r--library/core/tests/ptr.rs2
-rw-r--r--library/std/src/fs.rs29
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs4
-rw-r--r--library/std/src/io/mod.rs4
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/test/codegen/issue-96274.rs11
-rw-r--r--src/test/incremental/hashes/enum_defs.rs8
-rw-r--r--src/test/incremental/hashes/trait_defs.rs16
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff3
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.rs2
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.stderr13
44 files changed, 330 insertions, 534 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index d2f8ef8eaae..46dbbd83d19 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -16,6 +16,7 @@
 #![feature(maybe_uninit_slice)]
 #![feature(min_specialization)]
 #![feature(decl_macro)]
+#![feature(pointer_byte_offsets)]
 #![feature(rustc_attrs)]
 #![cfg_attr(test, feature(test))]
 #![feature(strict_provenance)]
@@ -211,7 +212,7 @@ impl<T> TypedArena<T> {
 
         unsafe {
             if mem::size_of::<T>() == 0 {
-                self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
+                self.ptr.set(self.ptr.get().wrapping_byte_add(1));
                 let ptr = ptr::NonNull::<T>::dangling().as_ptr();
                 // Don't drop the object. This `write` is equivalent to `forget`.
                 ptr::write(ptr, object);
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 2816f81fef1..21004871075 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -541,7 +541,7 @@ impl<'a, 'b> Context<'a, 'b> {
     ) {
         match c {
             parse::CountImplied | parse::CountIs(..) => {}
-            parse::CountIsParam(i) => {
+            parse::CountIsParam(i) | parse::CountIsStar(i) => {
                 self.unused_names_lint.maybe_add_positional_named_arg(
                     self.args.get(i),
                     named_arg_type,
@@ -589,7 +589,7 @@ impl<'a, 'b> Context<'a, 'b> {
             + self
                 .arg_with_formatting
                 .iter()
-                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
+                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
                 .count();
         if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
             e = self.ecx.struct_span_err(
@@ -639,7 +639,7 @@ impl<'a, 'b> Context<'a, 'b> {
             if let Some(span) = fmt.precision_span {
                 let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.precision {
-                    parse::CountIsParam(pos) if pos > self.num_args() => {
+                    parse::CountIsParam(pos) if pos >= self.num_args() => {
                         e.span_label(
                             span,
                             &format!(
@@ -651,12 +651,12 @@ impl<'a, 'b> Context<'a, 'b> {
                         );
                         zero_based_note = true;
                     }
-                    parse::CountIsParam(pos) => {
+                    parse::CountIsStar(pos) => {
                         let count = self.pieces.len()
                             + self
                                 .arg_with_formatting
                                 .iter()
-                                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
+                                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
                                 .count();
                         e.span_label(
                             span,
@@ -837,7 +837,7 @@ impl<'a, 'b> Context<'a, 'b> {
         };
         match c {
             parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
-            parse::CountIsParam(i) => {
+            parse::CountIsParam(i) | parse::CountIsStar(i) => {
                 // This needs mapping too, as `i` is referring to a macro
                 // argument. If `i` is not found in `count_positions` then
                 // the error had already been emitted elsewhere.
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 2da9123b846..d37eaeed095 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -187,9 +187,6 @@ pub enum LocalValue<Prov: Provenance = AllocId> {
 
 impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> {
     /// Read the local's value or error if the local is not yet live or not live anymore.
-    ///
-    /// Note: This may only be invoked from the `Machine::access_local` hook and not from
-    /// anywhere else. You may be invalidating machine invariants if you do!
     #[inline]
     pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
         match &self.value {
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 6bed8a7a007..b151d03681f 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -215,23 +215,12 @@ pub trait Machine<'mir, 'tcx>: Sized {
         right: &ImmTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>;
 
-    /// Called to read the specified `local` from the `frame`.
-    /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
-    /// for ZST reads.
-    #[inline]
-    fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
-        local: mir::Local,
-    ) -> InterpResult<'tcx, &'a Operand<Self::Provenance>>
-    where
-        'tcx: 'mir,
-    {
-        frame.locals[local].access()
-    }
-
     /// Called to write the specified `local` from the `frame`.
     /// Since writing a ZST is not actually accessing memory or locals, this is never invoked
     /// for ZST reads.
+    ///
+    /// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut
+    /// Frame`.
     #[inline]
     fn access_local_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index e80a82acd58..91a97fe4d4d 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -444,7 +444,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
-    /// Read from a local. Will not actually access the local if reading from a ZST.
+    /// Read from a local.
     /// Will not access memory, instead an indirect `Operand` is returned.
     ///
     /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
@@ -456,12 +456,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         let layout = self.layout_of_local(frame, local, layout)?;
-        let op = if layout.is_zst() {
-            // Bypass `access_local` (helps in ConstProp)
-            Operand::Immediate(Immediate::Uninit)
-        } else {
-            *M::access_local(frame, local)?
-        };
+        let op = *frame.locals[local].access()?;
         Ok(OpTy { op, layout, align: Some(layout.align.abi) })
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 7aa76fe1dae..d56323448ce 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -642,7 +642,7 @@ where
         // avoid force_allocation.
         let src = match self.read_immediate_raw(src)? {
             Ok(src_val) => {
-                assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
+                assert!(!src.layout.is_unsized(), "cannot copy unsized immediates");
                 assert!(
                     !dest.layout.is_unsized(),
                     "the src is sized, so the dest must also be sized"
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 742339f2b0a..16ce5bc7175 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -100,6 +100,8 @@ where
         // This makes several assumptions about what layouts we will encounter; we match what
         // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
         let field_val: Immediate<_> = match (*base, base.layout.abi) {
+            // if the entire value is uninit, then so is the field (can happen in ConstProp)
+            (Immediate::Uninit, _) => Immediate::Uninit,
             // the field contains no information, can be left uninit
             _ if field_layout.is_zst() => Immediate::Uninit,
             // the field covers the entire type
@@ -124,6 +126,7 @@ where
                     b_val
                 })
             }
+            // everything else is a bug
             _ => span_bug!(
                 self.cur_span(),
                 "invalid field access on immediate {}, layout {:#?}",
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index c1b201da691..ddad72fdab9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -103,7 +103,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                     // Find the index of the named region that was part of the
                     // error. We will then search the function parameters for a bound
                     // region at the right depth with the same index
-                    (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+                    (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
                         debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                         if id == def_id {
                             self.found_type = Some(arg);
@@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                         Some(
                             rl::Region::Static
                             | rl::Region::Free(_, _)
-                            | rl::Region::EarlyBound(_, _)
+                            | rl::Region::EarlyBound(_)
                             | rl::Region::LateBound(_, _, _),
                         )
                         | None,
@@ -188,7 +188,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
     fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
         match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
             // the lifetime of the TyPath!
-            (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+            (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
                 debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                 if id == def_id {
                     self.found_it = true;
@@ -209,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
             (
                 Some(
                     rl::Region::Static
-                    | rl::Region::EarlyBound(_, _)
+                    | rl::Region::EarlyBound(_)
                     | rl::Region::LateBound(_, _, _)
                     | rl::Region::Free(_, _),
                 )
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index af7ef96e485..3d002380f09 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2026,13 +2026,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
         inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
-        index: u32,
+        def_id: DefId,
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
             .filter_map(|(pred, _)| match pred.kind().skip_binder() {
                 ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
-                    ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
+                    ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
                     _ => None,
                 },
                 _ => None,
@@ -2069,8 +2069,12 @@ impl ExplicitOutlivesRequirements {
             .filter_map(|(i, bound)| {
                 if let hir::GenericBound::Outlives(lifetime) = bound {
                     let is_inferred = match tcx.named_region(lifetime.hir_id) {
-                        Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
-                            if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false }
+                        Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
+                            if let ty::ReEarlyBound(ebr) = **r {
+                                ebr.def_id == def_id
+                            } else {
+                                false
+                            }
                         }),
                         _ => false,
                     };
@@ -2164,11 +2168,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
             for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
                 let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
                     hir::WherePredicate::RegionPredicate(predicate) => {
-                        if let Some(Region::EarlyBound(index, ..)) =
+                        if let Some(Region::EarlyBound(region_def_id)) =
                             cx.tcx.named_region(predicate.lifetime.hir_id)
                         {
                             (
-                                Self::lifetimes_outliving_lifetime(inferred_outlives, index),
+                                Self::lifetimes_outliving_lifetime(
+                                    inferred_outlives,
+                                    region_def_id,
+                                ),
                                 &predicate.bounds,
                                 predicate.span,
                                 predicate.in_where_clause,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 643294cace4..9d201a0c799 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -199,6 +199,7 @@ provide! { tcx, def_id, other, cdata,
     codegen_fn_attrs => { table }
     impl_trait_ref => { table }
     const_param_default => { table }
+    object_lifetime_default => { table }
     thir_abstract_const => { table }
     optimized_mir => { table }
     mir_for_ctfe => { table }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index cd5da40150d..3482d9f0451 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1076,6 +1076,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
                 }
             }
+            if let DefKind::TyParam | DefKind::ConstParam = def_kind {
+                if let Some(default) = self.tcx.object_lifetime_default(def_id) {
+                    record!(self.tables.object_lifetime_default[def_id] <- default);
+                }
+            }
             if let DefKind::Trait | DefKind::TraitAlias = def_kind {
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
             }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index e6cceaf29d5..aeffc85b507 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -16,6 +16,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
+use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc_middle::mir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
@@ -358,6 +359,7 @@ define_tables! {
     codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
     impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
     const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
+    object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
     optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 25c18cf50c1..8f787739248 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -486,7 +486,9 @@ impl<'hir> Map<'hir> {
         let def_kind = self.tcx.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => def_id,
-            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id),
+            DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
+                self.tcx.local_parent(def_id)
+            }
             _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
@@ -495,7 +497,9 @@ impl<'hir> Map<'hir> {
         let def_kind = self.tcx.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
-            DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()),
+            DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
+                self.tcx.item_name(def_id.to_def_id())
+            }
             _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index 9b2f4456705..a171f5711dc 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -10,7 +10,7 @@ use rustc_macros::HashStable;
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum Region {
     Static,
-    EarlyBound(/* index */ u32, /* lifetime decl */ DefId),
+    EarlyBound(/* lifetime decl */ DefId),
     LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId),
     Free(DefId, /* lifetime decl */ DefId),
 }
@@ -35,7 +35,13 @@ impl<T: PartialEq> Set1<T> {
     }
 }
 
-pub type ObjectLifetimeDefault = Set1<Region>;
+#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
+pub enum ObjectLifetimeDefault {
+    Empty,
+    Static,
+    Ambiguous,
+    Param(DefId),
+}
 
 /// Maps the id of each lifetime reference to the lifetime decl
 /// that it corresponds to.
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index ecedbe8fc8e..ddca9820da1 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1597,8 +1597,9 @@ rustc_queries! {
     /// for each parameter if a trait object were to be passed for that parameter.
     /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`.
     /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`.
-    query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> {
-        desc { "looking up lifetime defaults for a region on an item" }
+    query object_lifetime_default(key: DefId) -> Option<ObjectLifetimeDefault> {
+        desc { "looking up lifetime defaults for generic parameter `{:?}`", key }
+        separate_provide_extern
     }
     query late_bound_vars_map(_: LocalDefId)
         -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 823e7f22af2..42b5d5a6efd 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -1,4 +1,3 @@
-use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
 use crate::ty;
 use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::EarlyBinder;
@@ -13,7 +12,7 @@ use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predi
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum GenericParamDefKind {
     Lifetime,
-    Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool },
+    Type { has_default: bool, synthetic: bool },
     Const { has_default: bool },
 }
 
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index ae6e2eecbff..19b8f27bc95 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -53,6 +53,7 @@ trivially_parameterized_over_tcx! {
     crate::metadata::ModChild,
     crate::middle::codegen_fn_attrs::CodegenFnAttrs,
     crate::middle::exported_symbols::SymbolExportInfo,
+    crate::middle::resolve_lifetime::ObjectLifetimeDefault,
     crate::mir::ConstQualifs,
     ty::Generics,
     ty::ImplPolarity,
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 5c9f4f57243..53f33a7a0ba 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -243,24 +243,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
 
-    fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
-        local: Local,
-    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> {
-        let l = &frame.locals[local];
-
-        if matches!(
-            l.value,
-            LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit))
-        ) {
-            // For us "uninit" means "we don't know its value, might be initiailized or not".
-            // So stop here.
-            throw_machine_stop_str!("tried to access alocal with unknown value ")
-        }
-
-        l.access()
-    }
-
     fn access_local_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
@@ -431,7 +413,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
     fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
         let op = match self.ecx.eval_place_to_op(place, None) {
-            Ok(op) => op,
+            Ok(op) => {
+                if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) {
+                    // Make sure nobody accidentally uses this value.
+                    return None;
+                }
+                op
+            }
             Err(e) => {
                 trace!("get_const failed: {}", e);
                 return None;
@@ -643,6 +631,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         if rvalue.needs_subst() {
             return None;
         }
+        if !rvalue
+            .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
+            .is_sized(self.ecx.tcx, self.param_env)
+        {
+            // the interpreter doesn't support unsized locals (only unsized arguments),
+            // but rustc does (in a kinda broken way), so we have to skip them here
+            return None;
+        }
 
         if self.tcx.sess.mir_opt_level() >= 4 {
             self.eval_rvalue_with_identities(rvalue, place)
@@ -660,18 +656,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         self.use_ecx(|this| match rvalue {
             Rvalue::BinaryOp(op, box (left, right))
             | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
-                let l = this.ecx.eval_operand(left, None);
-                let r = this.ecx.eval_operand(right, None);
+                let l = this.ecx.eval_operand(left, None).and_then(|x| this.ecx.read_immediate(&x));
+                let r =
+                    this.ecx.eval_operand(right, None).and_then(|x| this.ecx.read_immediate(&x));
 
                 let const_arg = match (l, r) {
-                    (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
-                    (Err(e), Err(_)) => return Err(e),
-                    (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
+                    (Ok(x), Err(_)) | (Err(_), Ok(x)) => x, // exactly one side is known
+                    (Err(e), Err(_)) => return Err(e),      // neither side is known
+                    (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), // both sides are known
                 };
 
                 if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) {
                     // We cannot handle Scalar Pair stuff.
-                    return this.ecx.eval_rvalue_into_place(rvalue, place);
+                    // No point in calling `eval_rvalue_into_place`, since only one side is known
+                    throw_machine_stop_str!("cannot optimize this")
                 }
 
                 let arg_value = const_arg.to_scalar().to_bits(const_arg.layout.size)?;
@@ -696,7 +694,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                             this.ecx.write_immediate(*const_arg, &dest)
                         }
                     }
-                    _ => this.ecx.eval_rvalue_into_place(rvalue, place),
+                    _ => throw_machine_stop_str!("cannot optimize this"),
                 }
             }
             _ => this.ecx.eval_rvalue_into_place(rvalue, place),
@@ -1073,7 +1071,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
                 if let Some(ref value) = self.eval_operand(&cond) {
                     trace!("assertion on {:?} should be {:?}", value, expected);
                     let expected = Scalar::from_bool(*expected);
-                    let value_const = self.ecx.read_scalar(&value).unwrap();
+                    let Ok(value_const) = self.ecx.read_scalar(&value) else {
+                        // FIXME should be used use_ecx rather than a local match... but we have
+                        // quite a few of these read_scalar/read_immediate that need fixing.
+                        return
+                    };
                     if expected != value_const {
                         // Poison all places this operand references so that further code
                         // doesn't use the invalid value
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 74b146833d0..082d6c9f07e 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -6,6 +6,7 @@ use crate::const_prop::ConstPropMachine;
 use crate::const_prop::ConstPropMode;
 use crate::MirLint;
 use rustc_const_eval::const_eval::ConstEvalErr;
+use rustc_const_eval::interpret::Immediate;
 use rustc_const_eval::interpret::{
     self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, StackPopCleanup,
 };
@@ -229,7 +230,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
     fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
         let op = match self.ecx.eval_place_to_op(place, None) {
-            Ok(op) => op,
+            Ok(op) => {
+                if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) {
+                    // Make sure nobody accidentally uses this value.
+                    return None;
+                }
+                op
+            }
             Err(e) => {
                 trace!("get_const failed: {}", e);
                 return None;
@@ -515,6 +522,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         if rvalue.needs_subst() {
             return None;
         }
+        if !rvalue
+            .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
+            .is_sized(self.ecx.tcx, self.param_env)
+        {
+            // the interpreter doesn't support unsized locals (only unsized arguments),
+            // but rustc does (in a kinda broken way), so we have to skip them here
+            return None;
+        }
 
         self.use_ecx(source_info, |this| this.ecx.eval_rvalue_into_place(rvalue, place))
     }
@@ -624,7 +639,11 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
                 if let Some(ref value) = self.eval_operand(&cond, source_info) {
                     trace!("assertion on {:?} should be {:?}", value, expected);
                     let expected = Scalar::from_bool(*expected);
-                    let value_const = self.ecx.read_scalar(&value).unwrap();
+                    let Ok(value_const) = self.ecx.read_scalar(&value) else {
+                        // FIXME should be used use_ecx rather than a local match... but we have
+                        // quite a few of these read_scalar/read_immediate that need fixing.
+                        return
+                    };
                     if expected != value_const {
                         enum DbgVal<T> {
                             Val(T),
@@ -641,9 +660,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
                         let mut eval_to_int = |op| {
                             // This can be `None` if the lhs wasn't const propagated and we just
                             // triggered the assert on the value of the rhs.
-                            self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| {
-                                DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int())
-                            })
+                            self.eval_operand(op, source_info)
+                                .and_then(|op| self.ecx.read_immediate(&op).ok())
+                                .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int()))
                         };
                         let msg = match msg {
                             AssertKind::DivisionByZero(op) => {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index b63a173cc29..a9e502016aa 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -167,6 +167,8 @@ pub enum Count<'a> {
     CountIsName(&'a str, InnerSpan),
     /// The count is specified by the argument at the given index.
     CountIsParam(usize),
+    /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
+    CountIsStar(usize),
     /// The count is implied and cannot be explicitly specified.
     CountImplied,
 }
@@ -618,7 +620,7 @@ impl<'a> Parser<'a> {
                 // We can do this immediately as `position` is resolved later.
                 let i = self.curarg;
                 self.curarg += 1;
-                spec.precision = CountIsParam(i);
+                spec.precision = CountIsStar(i);
             } else {
                 spec.precision = self.count(start + 1);
             }
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 44ef0cd0eb5..2f8c229c68f 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -244,7 +244,7 @@ fn format_counts() {
                 fill: None,
                 align: AlignUnknown,
                 flags: 0,
-                precision: CountIsParam(0),
+                precision: CountIsStar(0),
                 precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
                 width_span: None,
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 5789531d2ff..f376da29bd9 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -16,6 +16,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
 use rustc_hir::{MethodKind, Target};
 use rustc_middle::hir::nested_filter;
+use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
@@ -172,6 +173,9 @@ impl CheckAttrVisitor<'_> {
                 sym::no_implicit_prelude => {
                     self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
                 }
+                sym::rustc_object_lifetime_default => {
+                    self.check_object_lifetime_default(hir_id, span)
+                }
                 _ => {}
             }
 
@@ -410,6 +414,30 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    /// Debugging aid for `object_lifetime_default` query.
+    fn check_object_lifetime_default(&self, hir_id: HirId, span: Span) {
+        let tcx = self.tcx;
+        if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) {
+            let object_lifetime_default_reprs: String = generics
+                .params
+                .iter()
+                .filter_map(|p| {
+                    let param_id = tcx.hir().local_def_id(p.hir_id);
+                    let default = tcx.object_lifetime_default(param_id)?;
+                    Some(match default {
+                        ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
+                        ObjectLifetimeDefault::Static => "'static".to_owned(),
+                        ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
+                        ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
+                    })
+                })
+                .collect::<Vec<String>>()
+                .join(",");
+
+            tcx.sess.span_err(span, &object_lifetime_default_reprs);
+        }
+    }
+
     /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
     fn check_track_caller(
         &self,
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 94460e33d8b..6ea976a5900 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -11,23 +11,21 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefIdMap, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
 use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
-use std::borrow::Cow;
 use std::fmt;
-use std::mem::take;
 
 trait RegionExt {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
+    fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
     fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
@@ -36,19 +34,13 @@ trait RegionExt {
     fn shifted(self, amount: u32) -> Region;
 
     fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region;
-
-    fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option<Region>
-    where
-        L: Iterator<Item = &'a hir::Lifetime>;
 }
 
 impl RegionExt for Region {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
-        let i = *index;
-        *index += 1;
+    fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
         let def_id = hir_map.local_def_id(param.hir_id);
-        debug!("Region::early: index={} def_id={:?}", i, def_id);
-        (def_id, Region::EarlyBound(i, def_id.to_def_id()))
+        debug!("Region::early: def_id={:?}", def_id);
+        (def_id, Region::EarlyBound(def_id.to_def_id()))
     }
 
     fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
@@ -65,9 +57,7 @@ impl RegionExt for Region {
         match *self {
             Region::Static => None,
 
-            Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => {
-                Some(id)
-            }
+            Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id),
         }
     }
 
@@ -88,17 +78,6 @@ impl RegionExt for Region {
             _ => self,
         }
     }
-
-    fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option<Region>
-    where
-        L: Iterator<Item = &'a hir::Lifetime>,
-    {
-        if let Region::EarlyBound(index, _) = self {
-            params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned())
-        } else {
-            Some(self)
-        }
-    }
 }
 
 /// Maps the id of each lifetime reference to the lifetime decl
@@ -131,9 +110,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> {
     /// be false if the `Item` we are resolving lifetimes for is not a trait or
     /// we eventually need lifetimes resolve for trait items.
     trait_definition_only: bool,
-
-    /// Cache for cross-crate per-definition object lifetime defaults.
-    xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 }
 
 #[derive(Debug)]
@@ -147,25 +123,6 @@ enum Scope<'a> {
         /// for diagnostics.
         lifetimes: FxIndexMap<LocalDefId, Region>,
 
-        /// if we extend this scope with another scope, what is the next index
-        /// we should use for an early-bound region?
-        next_early_index: u32,
-
-        /// Whether or not this binder would serve as the parent
-        /// binder for opaque types introduced within. For example:
-        ///
-        /// ```text
-        ///     fn foo<'a>() -> impl for<'b> Trait<Item = impl Trait2<'a>>
-        /// ```
-        ///
-        /// Here, the opaque types we create for the `impl Trait`
-        /// and `impl Trait2` references will both have the `foo` item
-        /// as their parent. When we get to `impl Trait2`, we find
-        /// that it is nested within the `for<>` binder -- this flag
-        /// allows us to skip that when looking for the parent binder
-        /// of the resulting opaque type.
-        opaque_type_parent: bool,
-
         scope_type: BinderScopeType,
 
         /// The late bound vars for a given item are stored by `HirId` to be
@@ -245,19 +202,9 @@ struct TruncatedScopeDebug<'a>(&'a Scope<'a>);
 impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.0 {
-            Scope::Binder {
-                lifetimes,
-                next_early_index,
-                opaque_type_parent,
-                scope_type,
-                hir_id,
-                where_bound_origin,
-                s: _,
-            } => f
+            Scope::Binder { lifetimes, scope_type, hir_id, where_bound_origin, s: _ } => f
                 .debug_struct("Binder")
                 .field("lifetimes", lifetimes)
-                .field("next_early_index", next_early_index)
-                .field("opaque_type_parent", opaque_type_parent)
                 .field("scope_type", scope_type)
                 .field("hir_id", hir_id)
                 .field("where_bound_origin", where_bound_origin)
@@ -294,10 +241,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
 
         named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
         is_late_bound_map,
-        object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) {
-            Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
-            _ => None,
-        },
+        object_lifetime_default,
         late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
 
         ..*providers
@@ -363,7 +307,6 @@ fn do_resolve(
         map: &mut named_region_map,
         scope: ROOT_SCOPE,
         trait_definition_only,
-        xcrate_object_lifetime_defaults: Default::default(),
     };
     visitor.visit_item(item);
 
@@ -432,13 +375,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
     item
 }
 
-/// In traits, there is an implicit `Self` type parameter which comes before the generics.
-/// We have to account for this when computing the index of the other generic parameters.
-/// This function returns whether there is such an implicit parameter defined on the given item.
-fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool {
-    matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..))
-}
-
 fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
     match region {
         Region::LateBound(_, _, def_id) => {
@@ -558,7 +494,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 }
             }
 
-            let next_early_index = self.next_early_index();
             let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
                 bound_generic_params
                     .iter()
@@ -576,8 +511,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 hir_id: e.hir_id,
                 lifetimes,
                 s: self.scope,
-                next_early_index,
-                opaque_type_parent: false,
                 scope_type: BinderScopeType::Normal,
                 where_bound_origin: None,
             };
@@ -603,7 +536,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         }
         match item.kind {
             hir::ItemKind::Fn(_, ref generics, _) => {
-                self.visit_early_late(None, item.hir_id(), generics, |this| {
+                self.visit_early_late(item.hir_id(), generics, |this| {
                     intravisit::walk_item(this, item);
                 });
             }
@@ -670,31 +603,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             | hir::ItemKind::TraitAlias(ref generics, ..)
             | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
                 // These kinds of items have only early-bound lifetime parameters.
-                let mut index = if sub_items_have_self_param(&item.kind) {
-                    1 // Self comes before lifetimes
-                } else {
-                    0
-                };
-                let mut non_lifetime_count = 0;
                 let lifetimes = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                            non_lifetime_count += 1;
-                            None
+                            Some(Region::early(self.tcx.hir(), param))
                         }
+                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
                     })
                     .collect();
                 self.map.late_bound_vars.insert(item.hir_id(), vec![]);
                 let scope = Scope::Binder {
                     hir_id: item.hir_id(),
                     lifetimes,
-                    next_early_index: index + non_lifetime_count,
-                    opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     s: ROOT_SCOPE,
                     where_bound_origin: None,
@@ -712,7 +634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
         match item.kind {
             hir::ForeignItemKind::Fn(_, _, ref generics) => {
-                self.visit_early_late(None, item.hir_id(), generics, |this| {
+                self.visit_early_late(item.hir_id(), generics, |this| {
                     intravisit::walk_foreign_item(this, item);
                 })
             }
@@ -729,7 +651,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
         match ty.kind {
             hir::TyKind::BareFn(ref c) => {
-                let next_early_index = self.next_early_index();
                 let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
                     .generic_params
                     .iter()
@@ -746,8 +667,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     hir_id: ty.hir_id,
                     lifetimes,
                     s: self.scope,
-                    next_early_index,
-                    opaque_type_parent: false,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -886,32 +805,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
                 // We want to start our early-bound indices at the end of the parent scope,
                 // not including any parent `impl Trait`s.
-                let mut index = self.next_early_index_for_opaque_type();
-                debug!(?index);
-
                 let mut lifetimes = FxIndexMap::default();
-                let mut non_lifetime_count = 0;
                 debug!(?generics.params);
                 for param in generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
+                            let (def_id, reg) = Region::early(self.tcx.hir(), &param);
                             lifetimes.insert(def_id, reg);
                         }
-                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                            non_lifetime_count += 1;
-                        }
+                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
                     }
                 }
-                let next_early_index = index + non_lifetime_count;
                 self.map.late_bound_vars.insert(ty.hir_id, vec![]);
 
                 let scope = Scope::Binder {
                     hir_id: ty.hir_id,
                     lifetimes,
-                    next_early_index,
                     s: self.scope,
-                    opaque_type_parent: false,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -933,39 +843,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
             Fn(_, _) => {
-                let tcx = self.tcx;
-                self.visit_early_late(
-                    Some(tcx.hir().get_parent_item(trait_item.hir_id())),
-                    trait_item.hir_id(),
-                    &trait_item.generics,
-                    |this| intravisit::walk_trait_item(this, trait_item),
-                );
+                self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| {
+                    intravisit::walk_trait_item(this, trait_item)
+                });
             }
             Type(bounds, ref ty) => {
                 let generics = &trait_item.generics;
-                let mut index = self.next_early_index();
-                debug!("visit_ty: index = {}", index);
-                let mut non_lifetime_count = 0;
                 let lifetimes = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                            non_lifetime_count += 1;
-                            None
+                            Some(Region::early(self.tcx.hir(), param))
                         }
+                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
                     })
                     .collect();
                 self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]);
                 let scope = Scope::Binder {
                     hir_id: trait_item.hir_id(),
                     lifetimes,
-                    next_early_index: index + non_lifetime_count,
                     s: self.scope,
-                    opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -993,40 +891,26 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
-            Fn(..) => {
-                let tcx = self.tcx;
-                self.visit_early_late(
-                    Some(tcx.hir().get_parent_item(impl_item.hir_id())),
-                    impl_item.hir_id(),
-                    &impl_item.generics,
-                    |this| intravisit::walk_impl_item(this, impl_item),
-                );
-            }
+            Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
+                intravisit::walk_impl_item(this, impl_item)
+            }),
             TyAlias(ref ty) => {
                 let generics = &impl_item.generics;
-                let mut index = self.next_early_index();
-                let mut non_lifetime_count = 0;
-                debug!("visit_ty: index = {}", index);
                 let lifetimes: FxIndexMap<LocalDefId, Region> = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => {
-                            non_lifetime_count += 1;
-                            None
+                            Some(Region::early(self.tcx.hir(), param))
                         }
+                        GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
                     })
                     .collect();
                 self.map.late_bound_vars.insert(ty.hir_id, vec![]);
                 let scope = Scope::Binder {
                     hir_id: ty.hir_id,
                     lifetimes,
-                    next_early_index: index + non_lifetime_count,
                     s: self.scope,
-                    opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -1129,7 +1013,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 })
                                 .unzip();
                         this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
-                        let next_early_index = this.next_early_index();
                         // Even if there are no lifetimes defined here, we still wrap it in a binder
                         // scope. If there happens to be a nested poly trait ref (an error), that
                         // will be `Concatenating` anyways, so we don't have to worry about the depth
@@ -1138,8 +1021,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                             hir_id: bounded_ty.hir_id,
                             lifetimes,
                             s: this.scope,
-                            next_early_index,
-                            opaque_type_parent: false,
                             scope_type: BinderScopeType::Normal,
                             where_bound_origin: Some(origin),
                         };
@@ -1210,8 +1091,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     hir_id: *hir_id,
                     lifetimes: FxIndexMap::default(),
                     s: self.scope,
-                    next_early_index: self.next_early_index(),
-                    opaque_type_parent: false,
                     scope_type,
                     where_bound_origin: None,
                 };
@@ -1230,7 +1109,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     ) {
         debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
 
-        let next_early_index = self.next_early_index();
         let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
 
         let initial_bound_vars = binders.len() as u32;
@@ -1260,8 +1138,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             hir_id: trait_ref.trait_ref.hir_ref_id,
             lifetimes,
             s: self.scope,
-            next_early_index,
-            opaque_type_parent: false,
             scope_type,
             where_bound_origin: None,
         };
@@ -1272,127 +1148,46 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 }
 
-fn compute_object_lifetime_defaults<'tcx>(
+fn object_lifetime_default<'tcx>(
     tcx: TyCtxt<'tcx>,
-    item: &hir::Item<'_>,
-) -> Option<&'tcx [ObjectLifetimeDefault]> {
-    match item.kind {
-        hir::ItemKind::Struct(_, ref generics)
-        | hir::ItemKind::Union(_, ref generics)
-        | hir::ItemKind::Enum(_, ref generics)
-        | hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-            ref generics,
-            origin: hir::OpaqueTyOrigin::TyAlias,
-            ..
-        })
-        | hir::ItemKind::TyAlias(_, ref generics)
-        | hir::ItemKind::Trait(_, _, ref generics, ..) => {
-            let result = object_lifetime_defaults_for_item(tcx, generics);
-
-            // Debugging aid.
-            let attrs = tcx.hir().attrs(item.hir_id());
-            if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) {
-                let object_lifetime_default_reprs: String = result
-                    .iter()
-                    .map(|set| match *set {
-                        Set1::Empty => "BaseDefault".into(),
-                        Set1::One(Region::Static) => "'static".into(),
-                        Set1::One(Region::EarlyBound(mut i, _)) => generics
-                            .params
-                            .iter()
-                            .find_map(|param| match param.kind {
-                                GenericParamKind::Lifetime { .. } => {
-                                    if i == 0 {
-                                        return Some(param.name.ident().to_string().into());
-                                    }
-                                    i -= 1;
-                                    None
-                                }
-                                _ => None,
-                            })
-                            .unwrap(),
-                        Set1::One(_) => bug!(),
-                        Set1::Many => "Ambiguous".into(),
-                    })
-                    .collect::<Vec<Cow<'static, str>>>()
-                    .join(",");
-                tcx.sess.span_err(item.span, &object_lifetime_default_reprs);
-            }
-
-            Some(result)
-        }
-        _ => None,
-    }
-}
-
-/// Scan the bounds and where-clauses on parameters to extract bounds
-/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
-/// for each type parameter.
-fn object_lifetime_defaults_for_item<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    generics: &hir::Generics<'_>,
-) -> &'tcx [ObjectLifetimeDefault] {
-    fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>]) {
-        for bound in bounds {
-            if let hir::GenericBound::Outlives(ref lifetime) = *bound {
-                set.insert(lifetime.name.normalize_to_macros_2_0());
-            }
-        }
-    }
-
-    let process_param = |param: &hir::GenericParam<'_>| match param.kind {
+    param_def_id: DefId,
+) -> Option<ObjectLifetimeDefault> {
+    let param_def_id = param_def_id.expect_local();
+    let parent_def_id = tcx.local_parent(param_def_id);
+    let generics = tcx.hir().get_generics(parent_def_id)?;
+    let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
+    let param = generics.params.iter().find(|p| p.hir_id == param_hir_id)?;
+
+    // Scan the bounds and where-clauses on parameters to extract bounds
+    // of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
+    // for each type parameter.
+    match param.kind {
         GenericParamKind::Lifetime { .. } => None,
         GenericParamKind::Type { .. } => {
             let mut set = Set1::Empty;
 
-            let param_def_id = tcx.hir().local_def_id(param.hir_id);
-            for predicate in generics.predicates {
-                // Look for `type: ...` where clauses.
-                let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue };
-
+            // Look for `type: ...` where clauses.
+            for bound in generics.bounds_for_param(param_def_id) {
                 // Ignore `for<'a> type: ...` as they can change what
                 // lifetimes mean (although we could "just" handle it).
-                if !data.bound_generic_params.is_empty() {
+                if !bound.bound_generic_params.is_empty() {
                     continue;
                 }
 
-                let res = match data.bounded_ty.kind {
-                    hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res,
-                    _ => continue,
-                };
-
-                if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) {
-                    add_bounds(&mut set, &data.bounds);
+                for bound in bound.bounds {
+                    if let hir::GenericBound::Outlives(ref lifetime) = *bound {
+                        set.insert(lifetime.name.normalize_to_macros_2_0());
+                    }
                 }
             }
 
             Some(match set {
-                Set1::Empty => Set1::Empty,
-                Set1::One(name) => {
-                    if name == hir::LifetimeName::Static {
-                        Set1::One(Region::Static)
-                    } else {
-                        generics
-                            .params
-                            .iter()
-                            .filter_map(|param| match param.kind {
-                                GenericParamKind::Lifetime { .. } => {
-                                    let param_def_id = tcx.hir().local_def_id(param.hir_id);
-                                    Some((
-                                        param_def_id,
-                                        hir::LifetimeName::Param(param_def_id, param.name),
-                                    ))
-                                }
-                                _ => None,
-                            })
-                            .enumerate()
-                            .find(|&(_, (_, lt_name))| lt_name == name)
-                            .map_or(Set1::Many, |(i, (def_id, _))| {
-                                Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
-                            })
-                    }
+                Set1::Empty => ObjectLifetimeDefault::Empty,
+                Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
+                Set1::One(hir::LifetimeName::Param(param_def_id, _)) => {
+                    ObjectLifetimeDefault::Param(param_def_id.to_def_id())
                 }
-                Set1::Many => Set1::Many,
+                _ => ObjectLifetimeDefault::Ambiguous,
             })
         }
         GenericParamKind::Const { .. } => {
@@ -1400,11 +1195,9 @@ fn object_lifetime_defaults_for_item<'tcx>(
             //
             // We still store a dummy value here to allow generic parameters
             // in an arbitrary order.
-            Some(Set1::Empty)
+            Some(ObjectLifetimeDefault::Empty)
         }
-    };
-
-    tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param))
+    }
 }
 
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
@@ -1413,20 +1206,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext { tcx, map, .. } = self;
-        let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
         let mut this = LifetimeContext {
             tcx: *tcx,
             map,
             scope: &wrap_scope,
             trait_definition_only: self.trait_definition_only,
-            xcrate_object_lifetime_defaults,
         };
         let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
         {
             let _enter = span.enter();
             f(&mut this);
         }
-        self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
     }
 
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
@@ -1449,30 +1239,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     /// ordering is not important there.
     fn visit_early_late<F>(
         &mut self,
-        parent_id: Option<LocalDefId>,
         hir_id: hir::HirId,
         generics: &'tcx hir::Generics<'tcx>,
         walk: F,
     ) where
         F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
     {
-        // Find the start of nested early scopes, e.g., in methods.
-        let mut next_early_index = 0;
-        if let Some(parent_id) = parent_id {
-            let parent = self.tcx.hir().expect_item(parent_id);
-            if sub_items_have_self_param(&parent.kind) {
-                next_early_index += 1; // Self comes before lifetimes
-            }
-            match parent.kind {
-                hir::ItemKind::Trait(_, _, ref generics, ..)
-                | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
-                    next_early_index += generics.params.len() as u32;
-                }
-                _ => {}
-            }
-        }
-
-        let mut non_lifetime_count = 0;
         let mut named_late_bound_vars = 0;
         let lifetimes: FxIndexMap<LocalDefId, Region> = generics
             .params
@@ -1484,16 +1256,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         named_late_bound_vars += 1;
                         Some(Region::late(late_bound_idx, self.tcx.hir(), param))
                     } else {
-                        Some(Region::early(self.tcx.hir(), &mut next_early_index, param))
+                        Some(Region::early(self.tcx.hir(), param))
                     }
                 }
-                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                    non_lifetime_count += 1;
-                    None
-                }
+                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
             })
             .collect();
-        let next_early_index = next_early_index + non_lifetime_count;
 
         let binders: Vec<_> = generics
             .params
@@ -1512,51 +1280,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let scope = Scope::Binder {
             hir_id,
             lifetimes,
-            next_early_index,
             s: self.scope,
-            opaque_type_parent: true,
             scope_type: BinderScopeType::Normal,
             where_bound_origin: None,
         };
         self.with(scope, walk);
     }
 
-    fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 {
-        let mut scope = self.scope;
-        loop {
-            match *scope {
-                Scope::Root => return 0,
-
-                Scope::Binder { next_early_index, opaque_type_parent, .. }
-                    if (!only_opaque_type_parent || opaque_type_parent) =>
-                {
-                    return next_early_index;
-                }
-
-                Scope::Binder { s, .. }
-                | Scope::Body { s, .. }
-                | Scope::Elision { s, .. }
-                | Scope::ObjectLifetimeDefault { s, .. }
-                | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. } => scope = s,
-            }
-        }
-    }
-
-    /// Returns the next index one would use for an early-bound-region
-    /// if extending the current scope.
-    fn next_early_index(&self) -> u32 {
-        self.next_early_index_helper(true)
-    }
-
-    /// Returns the next index one would use for an `impl Trait` that
-    /// is being converted into an opaque type alias `impl Trait`. This will be the
-    /// next early index from the enclosing item, for the most
-    /// part. See the `opaque_type_parent` field for more info.
-    fn next_early_index_for_opaque_type(&self) -> u32 {
-        self.next_early_index_helper(false)
-    }
-
     #[tracing::instrument(level = "debug", skip(self))]
     fn resolve_lifetime_ref(
         &mut self,
@@ -1679,17 +1409,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         );
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn visit_segment_args(
         &mut self,
         res: Res,
         depth: usize,
         generic_args: &'tcx hir::GenericArgs<'tcx>,
     ) {
-        debug!(
-            "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})",
-            res, depth, generic_args,
-        );
-
         if generic_args.parenthesized {
             self.visit_fn_like_elision(
                 generic_args.inputs(),
@@ -1707,13 +1433,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
         // Figure out if this is a type/trait segment,
         // which requires object lifetime defaults.
-        let parent_def_id = |this: &mut Self, def_id: DefId| {
-            let def_key = this.tcx.def_key(def_id);
-            DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") }
-        };
         let type_def_id = match res {
-            Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)),
-            Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)),
+            Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)),
+            Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)),
             Res::Def(
                 DefKind::Struct
                 | DefKind::Union
@@ -1725,7 +1447,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             _ => None,
         };
 
-        debug!("visit_segment_args: type_def_id={:?}", type_def_id);
+        debug!(?type_def_id);
 
         // Compute a vector of defaults, one for each type parameter,
         // per the rules given in RFCs 599 and 1156. Example:
@@ -1763,55 +1485,39 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             };
 
             let map = &self.map;
-            let set_to_region = |set: &ObjectLifetimeDefault| match *set {
-                Set1::Empty => {
+            let generics = self.tcx.generics_of(def_id);
+
+            // `type_def_id` points to an item, so there is nothing to inherit generics from.
+            debug_assert_eq!(generics.parent_count, 0);
+
+            let set_to_region = |set: ObjectLifetimeDefault| match set {
+                ObjectLifetimeDefault::Empty => {
                     if in_body {
                         None
                     } else {
                         Some(Region::Static)
                     }
                 }
-                Set1::One(r) => {
-                    let lifetimes = generic_args.args.iter().filter_map(|arg| match arg {
-                        GenericArg::Lifetime(lt) => Some(lt),
+                ObjectLifetimeDefault::Static => Some(Region::Static),
+                ObjectLifetimeDefault::Param(param_def_id) => {
+                    // This index can be used with `generic_args` since `parent_count == 0`.
+                    let index = generics.param_def_id_to_index[&param_def_id] as usize;
+                    generic_args.args.get(index).and_then(|arg| match arg {
+                        GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id).copied(),
                         _ => None,
-                    });
-                    r.subst(lifetimes, map)
+                    })
                 }
-                Set1::Many => None,
+                ObjectLifetimeDefault::Ambiguous => None,
             };
-            if let Some(def_id) = def_id.as_local() {
-                let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                self.tcx
-                    .object_lifetime_defaults(id.owner)
-                    .unwrap()
-                    .iter()
-                    .map(set_to_region)
-                    .collect()
-            } else {
-                let tcx = self.tcx;
-                self.xcrate_object_lifetime_defaults
-                    .entry(def_id)
-                    .or_insert_with(|| {
-                        tcx.generics_of(def_id)
-                            .params
-                            .iter()
-                            .filter_map(|param| match param.kind {
-                                GenericParamDefKind::Type { object_lifetime_default, .. } => {
-                                    Some(object_lifetime_default)
-                                }
-                                GenericParamDefKind::Const { .. } => Some(Set1::Empty),
-                                GenericParamDefKind::Lifetime => None,
-                            })
-                            .collect()
-                    })
-                    .iter()
-                    .map(set_to_region)
-                    .collect()
-            }
+            generics
+                .params
+                .iter()
+                .filter_map(|param| self.tcx.object_lifetime_default(param.def_id))
+                .map(set_to_region)
+                .collect()
         });
 
-        debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults);
+        debug!(?object_lifetime_defaults);
 
         let mut i = 0;
         for arg in generic_args.args {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 5bb02bc246c..5c96f1c4623 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -222,9 +222,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 tcx.mk_region(ty::ReLateBound(debruijn, br))
             }
 
-            Some(rl::Region::EarlyBound(index, id)) => {
-                let name = lifetime_name(id.expect_local());
-                tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name }))
+            Some(rl::Region::EarlyBound(def_id)) => {
+                let name = tcx.hir().ty_param_name(def_id.expect_local());
+                let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
+                let generics = tcx.generics_of(item_def_id);
+                let index = generics.param_def_id_to_index[&def_id];
+                tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }))
             }
 
             Some(rl::Region::Free(scope, id)) => {
@@ -253,9 +256,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 })
             }
         };
-
         debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r);
-
         r
     }
 
@@ -2853,10 +2854,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             );
 
             if !infer_replacements.is_empty() {
-                diag.multipart_suggestion(&format!(
+                diag.multipart_suggestion(
+                    &format!(
                     "try replacing `_` with the type{} in the corresponding trait method signature",
                     rustc_errors::pluralize!(infer_replacements.len()),
-                ), infer_replacements, Applicability::MachineApplicable);
+                ),
+                    infer_replacements,
+                    Applicability::MachineApplicable,
+                );
             }
 
             diag.emit();
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 970b39dc845..6236ad370df 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1617,7 +1617,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                         pure_wrt_drop: false,
                         kind: ty::GenericParamDefKind::Type {
                             has_default: false,
-                            object_lifetime_default: rl::Set1::Empty,
                             synthetic: false,
                         },
                     });
@@ -1661,8 +1660,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         kind: ty::GenericParamDefKind::Lifetime,
     }));
 
-    let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner);
-
     // Now create the real type and const parameters.
     let type_start = own_start - has_self as u32 + params.len() as u32;
     let mut i = 0;
@@ -1687,13 +1684,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 }
             }
 
-            let kind = ty::GenericParamDefKind::Type {
-                has_default: default.is_some(),
-                object_lifetime_default: object_lifetime_defaults
-                    .as_ref()
-                    .map_or(rl::Set1::Empty, |o| o[i]),
-                synthetic,
-            };
+            let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
 
             let param_def = ty::GenericParamDef {
                 index: type_start + i as u32,
@@ -1745,11 +1736,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             name: Symbol::intern(arg),
             def_id,
             pure_wrt_drop: false,
-            kind: ty::GenericParamDefKind::Type {
-                has_default: false,
-                object_lifetime_default: rl::Set1::Empty,
-                synthetic: false,
-            },
+            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
         }));
     }
 
@@ -1762,11 +1749,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 name: Symbol::intern("<const_ty>"),
                 def_id,
                 pure_wrt_drop: false,
-                kind: ty::GenericParamDefKind::Type {
-                    has_default: false,
-                    object_lifetime_default: rl::Set1::Empty,
-                    synthetic: false,
-                },
+                kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
             });
         }
     }
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 4351548811d..ed049194dd0 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -4,7 +4,6 @@ use crate::alloc::{Allocator, Global};
 use crate::raw_vec::RawVec;
 use core::array;
 use core::fmt;
-use core::intrinsics::arith_offset;
 use core::iter::{
     FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
 };
@@ -154,7 +153,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
             // purposefully don't use 'ptr.offset' because for
             // vectors with 0-size elements this would return the
             // same pointer.
-            self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
+            self.ptr = self.ptr.wrapping_byte_add(1);
 
             // Make up a value of this ZST.
             Some(unsafe { mem::zeroed() })
@@ -184,7 +183,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
             // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound
             // effectively results in unsigned pointers representing positions 0..usize::MAX,
             // which is valid for ZSTs.
-            self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T }
+            self.ptr = self.ptr.wrapping_byte_add(step_size);
         } else {
             // SAFETY: the min() above ensures that step_size is in bounds
             self.ptr = unsafe { self.ptr.add(step_size) };
@@ -217,7 +216,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
                 return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) });
             }
 
-            self.ptr = unsafe { arith_offset(self.ptr as *const i8, N as isize) as *mut T };
+            self.ptr = self.ptr.wrapping_byte_add(N);
             // Safety: ditto
             return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) });
         }
@@ -267,7 +266,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
             None
         } else if mem::size_of::<T>() == 0 {
             // See above for why 'ptr.offset' isn't used
-            self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T };
+            self.end = self.ptr.wrapping_byte_sub(1);
 
             // Make up a value of this ZST.
             Some(unsafe { mem::zeroed() })
@@ -283,9 +282,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
         let step_size = self.len().min(n);
         if mem::size_of::<T>() == 0 {
             // SAFETY: same as for advance_by()
-            self.end = unsafe {
-                arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T
-            }
+            self.end = self.end.wrapping_byte_sub(step_size);
         } else {
             // SAFETY: same as for advance_by()
             self.end = unsafe { self.end.sub(step_size) };
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 2c786fd511e..1f19b9e5945 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -59,7 +59,7 @@ use core::cmp::Ordering;
 use core::convert::TryFrom;
 use core::fmt;
 use core::hash::{Hash, Hasher};
-use core::intrinsics::{arith_offset, assume};
+use core::intrinsics::assume;
 use core::iter;
 #[cfg(not(no_global_oom_handling))]
 use core::iter::FromIterator;
@@ -2678,7 +2678,7 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {
             let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
             let begin = me.as_mut_ptr();
             let end = if mem::size_of::<T>() == 0 {
-                arith_offset(begin as *const i8, me.len() as isize) as *const T
+                begin.wrapping_byte_add(me.len())
             } else {
                 begin.add(me.len()) as *const T
             };
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 32d1a4e5508..7da49b04aaa 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -28,24 +28,14 @@ impl<'buf, 'state> PadAdapter<'buf, 'state> {
 }
 
 impl fmt::Write for PadAdapter<'_, '_> {
-    fn write_str(&mut self, mut s: &str) -> fmt::Result {
-        while !s.is_empty() {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        for s in s.split_inclusive('\n') {
             if self.state.on_newline {
                 self.buf.write_str("    ")?;
             }
 
-            let split = match s.find('\n') {
-                Some(pos) => {
-                    self.state.on_newline = true;
-                    pos + 1
-                }
-                None => {
-                    self.state.on_newline = false;
-                    s.len()
-                }
-            };
-            self.buf.write_str(&s[..split])?;
-            s = &s[split..];
+            self.state.on_newline = s.ends_with('\n');
+            self.buf.write_str(s)?;
         }
 
         Ok(())
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 3f3eb3b3c5c..ef7b3b1d147 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -249,7 +249,7 @@ impl<T: ?Sized> *const T {
         let offset = dest_addr.wrapping_sub(self_addr);
 
         // This is the canonical desugarring of this operation
-        self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+        self.wrapping_byte_offset(offset)
     }
 
     /// Creates a new pointer by mapping `self`'s address to a new one.
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 03ee879f7da..6a3b9ee9a7d 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -255,7 +255,7 @@ impl<T: ?Sized> *mut T {
         let offset = dest_addr.wrapping_sub(self_addr);
 
         // This is the canonical desugarring of this operation
-        self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+        self.wrapping_byte_offset(offset)
     }
 
     /// Creates a new pointer by mapping `self`'s address to a new one.
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index c05242222dd..47455760a4b 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -64,7 +64,7 @@ macro_rules! iterator {
         // backwards by `n`. `n` must not exceed `self.len()`.
         macro_rules! zst_shrink {
             ($self: ident, $n: ident) => {
-                $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
+                $self.end = $self.end.wrapping_byte_offset(-$n);
             }
         }
 
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index 13b12db209a..94b0310603b 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -155,7 +155,7 @@ fn ptr_add_data() {
 
     assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1));
     assert_eq!(atom.load(SeqCst), n);
-    let bytes_from_n = |b| n.cast::<u8>().wrapping_add(b).cast::<i64>();
+    let bytes_from_n = |b| n.wrapping_byte_add(b);
 
     assert_eq!(atom.fetch_byte_add(1, SeqCst), n);
     assert_eq!(atom.load(SeqCst), bytes_from_n(1));
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 12861794c2d..97a36981005 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -650,7 +650,7 @@ fn thin_box() {
                     .unwrap_or_else(|| handle_alloc_error(layout))
                     .cast::<DynMetadata<T>>();
                 ptr.as_ptr().write(meta);
-                ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
+                ptr.as_ptr().byte_add(offset).cast::<Value>().write(value);
                 Self { ptr, phantom: PhantomData }
             }
         }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index e1ab06b0d0f..28a2c99f7e5 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -377,6 +377,35 @@ impl File {
         OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
     }
 
+    /// Creates a new file in read-write mode; error if the file exists.
+    ///
+    /// This function will create a file if it does not exist, or return an error if it does. This
+    /// way, if the call succeeds, the file returned is guaranteed to be new.
+    ///
+    /// This option is useful because it is atomic. Otherwise between checking whether a file
+    /// exists and creating a new one, the file may have been created by another process (a TOCTOU
+    /// race condition / attack).
+    ///
+    /// This can also be written using
+    /// `File::options().read(true).write(true).create_new(true).open(...)`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_create_new)]
+    ///
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut f = File::create_new("foo.txt")?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_create_new", issue = "none")]
+    pub fn create_new<P: AsRef<Path>>(path: P) -> io::Result<File> {
+        OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref())
+    }
+
     /// Returns a new OpenOptions object.
     ///
     /// This function returns a new OpenOptions object that you can use to
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 292bf4826fd..781ae03ad45 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -269,10 +269,10 @@ where
         }
         TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
         TAG_CUSTOM => {
-            // It would be correct for us to use `ptr::sub` here (see the
+            // It would be correct for us to use `ptr::byte_sub` here (see the
             // comment above the `wrapping_add` call in `new_custom` for why),
             // but it isn't clear that it makes a difference, so we don't.
-            let custom = ptr.as_ptr().cast::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>();
+            let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>();
             ErrorData::Custom(make_custom(custom))
         }
         _ => {
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index a9fa7b0a6ac..01a3873c75c 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1037,8 +1037,6 @@ pub trait Read {
 /// # Examples
 ///
 /// ```no_run
-/// #![feature(io_read_to_string)]
-///
 /// # use std::io;
 /// fn main() -> io::Result<()> {
 ///     let stdin = io::read_to_string(io::stdin())?;
@@ -1047,7 +1045,7 @@ pub trait Read {
 ///     Ok(())
 /// }
 /// ```
-#[unstable(feature = "io_read_to_string", issue = "80218")]
+#[stable(feature = "io_read_to_string", since = "CURRENT_RUSTC_VERSION")]
 pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
     let mut buf = String::new();
     reader.read_to_string(&mut buf)?;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index f5dcdab4cd5..8936e11b8e0 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -300,6 +300,7 @@
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
+#![feature(pointer_byte_offsets)]
 #![feature(pointer_is_aligned)]
 #![feature(portable_simd)]
 #![feature(prelude_2024)]
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 420159b5a67..c425de081a6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -192,7 +192,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
 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)
+        rl::Region::EarlyBound(node_id)
         | rl::Region::LateBound(_, _, node_id)
         | rl::Region::Free(_, node_id),
     ) = def
diff --git a/src/test/codegen/issue-96274.rs b/src/test/codegen/issue-96274.rs
new file mode 100644
index 00000000000..e3abf730961
--- /dev/null
+++ b/src/test/codegen/issue-96274.rs
@@ -0,0 +1,11 @@
+// min-llvm-version: 15.0
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+use std::mem::MaybeUninit;
+
+pub fn maybe_uninit() -> [MaybeUninit<u8>; 3000] {
+    // CHECK-NOT: memset
+    [MaybeUninit::uninit(); 3000]
+}
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index b466cfdd595..0f8898c389b 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -504,9 +504,9 @@ enum EnumAddLifetimeBoundToParameter<'a, T> {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail6")]
 enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
     Variant1(T),
@@ -559,9 +559,9 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail6")]
 enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
     Variant1(T),
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 1988f3f3541..c453eeceb77 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -1066,9 +1066,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
 
@@ -1144,9 +1144,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + Refer
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
 
@@ -1201,9 +1201,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
 
@@ -1254,9 +1254,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }
 
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
index 4f205667be0..186a9537356 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
@@ -41,7 +41,8 @@
           StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
           _4 = (_2.1: i32);                // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
           StorageLive(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
-          _5 = (_2.0: i32);                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
+-         _5 = (_2.0: i32);                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
++         _5 = const 1_i32;                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
           nop;                             // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2
           StorageDead(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
           StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs
index 84f4cc7f4cc..f00cb05c9eb 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.rs
+++ b/src/test/ui/fmt/ifmt-bad-arg.rs
@@ -94,4 +94,6 @@ tenth number: {}",
     // doesn't exist.
     println!("{:.*}");
     //~^ ERROR 2 positional arguments in format string, but no arguments were given
+    println!("{:.0$}");
+    //~^ ERROR 1 positional argument in format string, but no arguments were given
 }
diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr
index 5439ee17398..dbb4bc6d937 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.stderr
+++ b/src/test/ui/fmt/ifmt-bad-arg.stderr
@@ -273,6 +273,17 @@ LL |     println!("{:.*}");
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/ifmt-bad-arg.rs:97:15
+   |
+LL |     println!("{:.0$}");
+   |               ^^---^
+   |                 |
+   |                 this precision flag expects an `usize` argument at position 0, but no arguments were given
+   |
+   = note: positional arguments are zero-based
+   = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
 error[E0425]: cannot find value `foo` in this scope
   --> $DIR/ifmt-bad-arg.rs:27:18
    |
@@ -339,7 +350,7 @@ LL |     pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
    |            ^^^^^^^^^^
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 37 previous errors
+error: aborting due to 38 previous errors
 
 Some errors have detailed explanations: E0308, E0425.
 For more information about an error, try `rustc --explain E0308`.