about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-28 15:18:16 +0000
committerbors <bors@rust-lang.org>2023-03-28 15:18:16 +0000
commit478cbb42b730ba4739351b72ce2aa928e78e2f81 (patch)
treebf25c6aa92d6d0ad61724051f4404c237df72d71
parentbf57e8ada6dc62369d1cee7ab055fb4074bd2d10 (diff)
parent60ce19d848682b10543934229750cf30ef7af8a6 (diff)
downloadrust-478cbb42b730ba4739351b72ce2aa928e78e2f81.tar.gz
rust-478cbb42b730ba4739351b72ce2aa928e78e2f81.zip
Auto merge of #109692 - Nilstrieb:rollup-hq65rps, r=Nilstrieb
Rollup of 8 pull requests

Successful merges:

 - #91793 (socket ancillary data implementation for FreeBSD (from 13 and above).)
 - #92284 (Change advance(_back)_by to return the remainder instead of the number of processed elements)
 - #102472 (stop special-casing `'static` in evaluation)
 - #108480 (Use Rayon's TLV directly)
 - #109321 (Erase impl regions when checking for impossible to eagerly monomorphize items)
 - #109470 (Correctly substitute GAT's type used in `normalize_param_env` in `check_type_bounds`)
 - #109562 (Update ar_archive_writer to 0.1.3)
 - #109629 (remove obsolete `givens` from regionck)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock20
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock4
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs2
-rw-r--r--compiler/rustc_data_structures/Cargo.toml8
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs108
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs9
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs4
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs17
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs47
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs11
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs48
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs3
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs44
-rw-r--r--compiler/rustc_interface/Cargo.toml6
-rw-r--r--compiler/rustc_interface/src/util.rs2
-rw-r--r--compiler/rustc_middle/Cargo.toml4
-rw-r--r--compiler/rustc_middle/src/ty/context/tls.rs59
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs48
-rw-r--r--compiler/rustc_query_impl/Cargo.toml2
-rw-r--r--compiler/rustc_query_system/Cargo.toml2
-rw-r--r--compiler/rustc_query_system/src/query/job.rs2
-rw-r--r--compiler/rustc_serialize/Cargo.toml2
-rw-r--r--compiler/rustc_span/Cargo.toml2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs164
-rw-r--r--library/alloc/src/collections/vec_deque/into_iter.rs29
-rw-r--r--library/alloc/src/collections/vec_deque/iter.rs33
-rw-r--r--library/alloc/src/collections/vec_deque/iter_mut.rs32
-rw-r--r--library/alloc/src/vec/into_iter.rs15
-rw-r--r--library/alloc/tests/vec.rs22
-rw-r--r--library/alloc/tests/vec_deque.rs23
-rw-r--r--library/core/src/array/iter.rs15
-rw-r--r--library/core/src/iter/adapters/by_ref_sized.rs5
-rw-r--r--library/core/src/iter/adapters/chain.rs51
-rw-r--r--library/core/src/iter/adapters/copied.rs5
-rw-r--r--library/core/src/iter/adapters/cycle.rs26
-rw-r--r--library/core/src/iter/adapters/enumerate.rs22
-rw-r--r--library/core/src/iter/adapters/flatten.rs21
-rw-r--r--library/core/src/iter/adapters/rev.rs5
-rw-r--r--library/core/src/iter/adapters/skip.rs54
-rw-r--r--library/core/src/iter/adapters/take.rs34
-rw-r--r--library/core/src/iter/range.rs25
-rw-r--r--library/core/src/iter/sources/repeat.rs5
-rw-r--r--library/core/src/iter/sources/repeat_n.rs8
-rw-r--r--library/core/src/iter/traits/double_ended.rs26
-rw-r--r--library/core/src/iter/traits/iterator.rs22
-rw-r--r--library/core/src/ops/index_range.rs15
-rw-r--r--library/core/src/slice/iter/macros.rs8
-rw-r--r--library/core/tests/array.rs19
-rw-r--r--library/core/tests/iter/adapters/chain.rs41
-rw-r--r--library/core/tests/iter/adapters/enumerate.rs15
-rw-r--r--library/core/tests/iter/adapters/flatten.rs46
-rw-r--r--library/core/tests/iter/adapters/skip.rs14
-rw-r--r--library/core/tests/iter/adapters/take.rs15
-rw-r--r--library/core/tests/iter/range.rs19
-rw-r--r--library/core/tests/iter/traits/iterator.rs18
-rw-r--r--library/core/tests/slice.rs21
-rw-r--r--library/std/build.rs3
-rw-r--r--library/std/src/os/unix/net/ancillary.rs141
-rw-r--r--library/std/src/os/unix/net/datagram.rs36
-rw-r--r--library/std/src/os/unix/net/stream.rs36
-rw-r--r--library/std/src/os/unix/net/tests.rs2
-rw-r--r--library/std/src/sys/unix/net.rs11
-rw-r--r--src/bootstrap/lib.rs1
-rw-r--r--tests/ui/codegen/mono-impossible-2.rs19
-rw-r--r--tests/ui/generic-associated-types/gat-bounds-normalize-pred.rs17
-rw-r--r--tests/ui/implied-bounds/ice-unbound-region-vars.rs24
-rw-r--r--tests/ui/implied-bounds/normalization.rs58
-rw-r--r--tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs6
-rw-r--r--tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.stderr31
-rw-r--r--tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs14
-rw-r--r--tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr14
77 files changed, 1014 insertions, 748 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b07a7a8e5cb..f0507c873d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -106,11 +106,11 @@ checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
 
 [[package]]
 name = "ar_archive_writer"
-version = "0.1.1"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
+checksum = "b0639441fd17a3197d1cbca8dc8768cc172a63b64b4bb6c372e8f41ed0acc9bb"
 dependencies = [
- "object 0.29.0",
+ "object 0.30.1",
 ]
 
 [[package]]
@@ -2689,9 +2689,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indexmap"
-version = "1.9.2"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
  "hashbrown 0.12.3",
@@ -4160,21 +4160,19 @@ dependencies = [
 
 [[package]]
 name = "rustc-rayon"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a79f0b0b2609e2eacf9758013f50e7176cb4b29fd6436a747b14a5362c8727a"
+checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710"
 dependencies = [
- "autocfg",
- "crossbeam-deque",
  "either",
  "rustc-rayon-core",
 ]
 
 [[package]]
 name = "rustc-rayon-core"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02269144a0db9bb55cf5d4a41a5a0e95b334b0b78b08269018ca9b0250718c30"
+checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 157ef4bf389..87e4ac26605 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -235,9 +235,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.9.2"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
  "hashbrown",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 0e64fba6bec..5dadcaaec42 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -25,7 +25,7 @@ target-lexicon = "0.12.0"
 gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
-indexmap = "1.9.1"
+indexmap = "1.9.3"
 libloading = { version = "0.7.3", optional = true }
 once_cell = "1.10.0"
 smallvec = "1.8.1"
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index a570f2af0f0..12da21dc477 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -110,7 +110,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
         // FIXME use ArArchiveBuilder on most targets again once reading thin archives is
         // implemented
-        if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
+        if true {
             Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
         } else {
             Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 056ee1f63be..0b2b03da208 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -10,12 +10,12 @@ arrayvec = { version = "0.7", default-features = false }
 bitflags = "1.2.1"
 cfg-if = "1.0"
 ena = "0.14.2"
-indexmap = { version = "1.9.1" }
+indexmap = { version = "1.9.3" }
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 libc = "0.2"
 measureme = "10.0.0"
-rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true }
-rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
+rustc-rayon-core = { version = "0.5.0", optional = true }
+rustc-rayon = { version = "0.5.0", optional = true }
 rustc_graphviz = { path = "../rustc_graphviz" }
 rustc-hash = "1.1.0"
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
@@ -51,4 +51,4 @@ features = [
 memmap2 = "0.2.1"
 
 [features]
-rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rayon", "rayon-core"]
+rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon", "rustc-rayon-core"]
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 49665525967..2d509a114ad 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -330,7 +330,6 @@ fn compare_method_predicate_entailment<'tcx>(
     // lifetime parameters.
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        Some(infcx),
         infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()),
     );
     infcx.process_registered_region_obligations(
@@ -727,7 +726,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     // lifetime parameters.
     let outlives_environment = OutlivesEnvironment::with_bounds(
         param_env,
-        Some(infcx),
         infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
     );
     infcx
@@ -1876,14 +1874,17 @@ pub(super) fn check_type_bounds<'tcx>(
     impl_ty: ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
+    let param_env = tcx.param_env(impl_ty.def_id);
+    let container_id = impl_ty.container_id(tcx);
     // Given
     //
     // impl<A, B> Foo<u32> for (A, B) {
-    //     type Bar<C> =...
+    //     type Bar<C> = Wrapper<A, B, C>
     // }
     //
     // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
-    // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
+    // - `normalize_impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
+    // - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
     // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
     //    the *trait* with the generic associated type parameters (as bound vars).
     //
@@ -1912,56 +1913,46 @@ pub(super) fn check_type_bounds<'tcx>(
     // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
     // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
     // the trait (notably, that X: Eq and T: Family).
-    let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
-    let mut substs = smallvec::SmallVec::with_capacity(defs.count());
-    if let Some(def_id) = defs.parent {
-        let parent_defs = tcx.generics_of(def_id);
-        InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
-            tcx.mk_param_from_def(param)
-        });
-    }
     let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
-        smallvec::SmallVec::with_capacity(defs.count());
-    InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
-        GenericParamDefKind::Type { .. } => {
-            let kind = ty::BoundTyKind::Param(param.def_id, param.name);
-            let bound_var = ty::BoundVariableKind::Ty(kind);
-            bound_vars.push(bound_var);
-            tcx.mk_bound(
-                ty::INNERMOST,
-                ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
-            )
-            .into()
-        }
-        GenericParamDefKind::Lifetime => {
-            let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
-            let bound_var = ty::BoundVariableKind::Region(kind);
-            bound_vars.push(bound_var);
-            tcx.mk_re_late_bound(
-                ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
-            )
-            .into()
-        }
-        GenericParamDefKind::Const { .. } => {
-            let bound_var = ty::BoundVariableKind::Const;
-            bound_vars.push(bound_var);
-            tcx.mk_const(
-                ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
-                tcx.type_of(param.def_id).subst_identity(),
-            )
-            .into()
-        }
-    });
-    let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
-    let impl_ty_substs = tcx.mk_substs(&substs);
-    let container_id = impl_ty.container_id(tcx);
-
-    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
-    let impl_ty_value = tcx.type_of(impl_ty.def_id).subst_identity();
-
-    let param_env = tcx.param_env(impl_ty.def_id);
-
+        smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
+    // Extend the impl's identity substs with late-bound GAT vars
+    let normalize_impl_ty_substs = ty::InternalSubsts::identity_for_item(tcx, container_id)
+        .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
+            GenericParamDefKind::Type { .. } => {
+                let kind = ty::BoundTyKind::Param(param.def_id, param.name);
+                let bound_var = ty::BoundVariableKind::Ty(kind);
+                bound_vars.push(bound_var);
+                tcx.mk_bound(
+                    ty::INNERMOST,
+                    ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+                )
+                .into()
+            }
+            GenericParamDefKind::Lifetime => {
+                let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
+                let bound_var = ty::BoundVariableKind::Region(kind);
+                bound_vars.push(bound_var);
+                tcx.mk_re_late_bound(
+                    ty::INNERMOST,
+                    ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+                )
+                .into()
+            }
+            GenericParamDefKind::Const { .. } => {
+                let bound_var = ty::BoundVariableKind::Const;
+                bound_vars.push(bound_var);
+                tcx.mk_const(
+                    ty::ConstKind::Bound(
+                        ty::INNERMOST,
+                        ty::BoundVar::from_usize(bound_vars.len() - 1),
+                    ),
+                    tcx.type_of(param.def_id)
+                        .no_bound_vars()
+                        .expect("const parameter types cannot be generic"),
+                )
+                .into()
+            }
+        });
     // When checking something like
     //
     // trait X { type Y: PartialEq<<Self as X>::Y> }
@@ -1971,9 +1962,13 @@ pub(super) fn check_type_bounds<'tcx>(
     // we want <T as X>::Y to normalize to S. This is valid because we are
     // checking the default value specifically here. Add this equality to the
     // ParamEnv for normalization specifically.
+    let normalize_impl_ty = tcx.type_of(impl_ty.def_id).subst(tcx, normalize_impl_ty_substs);
+    let rebased_substs =
+        normalize_impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
+    let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
     let normalize_param_env = {
         let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
-        match impl_ty_value.kind() {
+        match normalize_impl_ty.kind() {
             ty::Alias(ty::Projection, proj)
                 if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
             {
@@ -1987,7 +1982,7 @@ pub(super) fn check_type_bounds<'tcx>(
                 ty::Binder::bind_with_vars(
                     ty::ProjectionPredicate {
                         projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
-                        term: impl_ty_value.into(),
+                        term: normalize_impl_ty.into(),
                     },
                     bound_vars,
                 )
@@ -2068,8 +2063,7 @@ pub(super) fn check_type_bounds<'tcx>(
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
     let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
-    let outlives_environment =
-        OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
+    let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
 
     infcx.err_ctxt().check_region_obligations_and_report_errors(
         impl_ty.def_id.expect_local(),
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index c912a8a640d..d126f7beb10 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -114,8 +114,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
         return;
     }
 
-    let outlives_environment =
-        OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+    let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
 
     let _ = infcx
         .err_ctxt()
@@ -675,7 +674,6 @@ fn resolve_regions_with_wf_tys<'tcx>(
     let infcx = tcx.infer_ctxt().build();
     let outlives_environment = OutlivesEnvironment::with_bounds(
         param_env,
-        Some(&infcx),
         infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
     );
     let region_bound_pairs = outlives_environment.region_bound_pairs();
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index dfa9e6148aa..b5bae5788f6 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -179,7 +179,7 @@ fn get_impl_substs(
     }
 
     let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
-    let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+    let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
     let _ =
         infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index c36c75e4443..11ff65d0c37 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -238,15 +238,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Note that there are two tests to check that this remains true
         // (`regions-reassign-{match,let}-bound-pointer.rs`).
         //
-        // 2. Things go horribly wrong if we use subtype. The reason for
-        // THIS is a fairly subtle case involving bound regions. See the
-        // `givens` field in `region_constraints`, as well as the test
+        // 2. An outdated issue related to the old HIR borrowck. See the test
         // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
-        // for details. Short version is that we must sometimes detect
-        // relationships between specific region variables and regions
-        // bound in a closure signature, and that detection gets thrown
-        // off when we substitute fresh region variables here to enable
-        // subtyping.
     }
 
     /// Compute the new expected type and default binding mode from the old ones
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 268896b671a..e98f68ae5a8 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -640,11 +640,9 @@ pub fn make_query_region_constraints<'tcx>(
     outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
     region_constraints: &RegionConstraintData<'tcx>,
 ) -> QueryRegionConstraints<'tcx> {
-    let RegionConstraintData { constraints, verifys, givens, member_constraints } =
-        region_constraints;
+    let RegionConstraintData { constraints, verifys, member_constraints } = region_constraints;
 
     assert!(verifys.is_empty());
-    assert!(givens.is_empty());
 
     debug!(?constraints);
 
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index f09f93abf45..d89f63e5c53 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -43,18 +43,16 @@ pub struct TypeFreshener<'a, 'tcx> {
     const_freshen_count: u32,
     ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
     const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
-    keep_static: bool,
 }
 
 impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
         TypeFreshener {
             infcx,
             ty_freshen_count: 0,
             const_freshen_count: 0,
             ty_freshen_map: Default::default(),
             const_freshen_map: Default::default(),
-            keep_static,
         }
     }
 
@@ -121,18 +119,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
             | ty::ReFree(_)
             | ty::ReVar(_)
             | ty::RePlaceholder(..)
+            | ty::ReStatic
             | ty::ReError(_)
-            | ty::ReErased => {
-                // replace all free regions with 'erased
-                self.interner().lifetimes.re_erased
-            }
-            ty::ReStatic => {
-                if self.keep_static {
-                    r
-                } else {
-                    self.interner().lifetimes.re_erased
-                }
-            }
+            | ty::ReErased => self.interner().lifetimes.re_erased,
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 2c480355085..cf657756ff5 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
 };
 use rustc_data_structures::intern::Interned;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::PlaceholderRegion;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -132,7 +132,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         }
 
         let graph = self.construct_graph();
-        self.expand_givens(&graph);
         self.expansion(&mut var_data);
         self.collect_errors(&mut var_data, errors);
         self.collect_var_errors(&var_data, &graph, errors);
@@ -164,38 +163,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         }
     }
 
-    fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
-        // Givens are a kind of horrible hack to account for
-        // constraints like 'c <= '0 that are known to hold due to
-        // closure signatures (see the comment above on the `givens`
-        // field). They should go away. But until they do, the role
-        // of this fn is to account for the transitive nature:
-        //
-        //     Given 'c <= '0
-        //     and   '0 <= '1
-        //     then  'c <= '1
-
-        let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
-        for (r, vid) in seeds {
-            // While all things transitively reachable in the graph
-            // from the variable (`'0` in the example above).
-            let seed_index = NodeIndex(vid.index() as usize);
-            for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
-                let succ_index = succ_index.0;
-
-                // The first N nodes correspond to the region
-                // variables. Other nodes correspond to constant
-                // regions.
-                if succ_index < self.num_vars() {
-                    let succ_vid = RegionVid::new(succ_index);
-
-                    // Add `'c <= '1`.
-                    self.data.givens.insert((r, succ_vid));
-                }
-            }
-        }
-    }
-
     /// Gets the LUb of a given region and the empty region
     fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> {
         match *a_region {
@@ -362,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     ) -> bool {
         debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
 
-        match *a_region {
-            // Check if this relationship is implied by a given.
-            ty::ReEarlyBound(_) | ty::ReFree(_) => {
-                if self.data.givens.contains(&(a_region, b_vid)) {
-                    debug!("given");
-                    return false;
-                }
-            }
-
-            _ => {}
-        }
-
         match *b_data {
             VarValue::Empty(empty_ui) => {
                 let lub = match self.lub_empty(a_region) {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 9afe9cc1e76..9903ffa90ba 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -713,12 +713,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
-        freshen::TypeFreshener::new(self, false)
-    }
-
-    /// Like `freshener`, but does not replace `'static` regions.
-    pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
-        freshen::TypeFreshener::new(self, true)
+        freshen::TypeFreshener::new(self)
     }
 
     pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
@@ -874,10 +869,6 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
     }
 
-    pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
-        self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
-    }
-
     pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
     where
         T: at::ToTrace<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 24e3c34dd94..47e3dd762b0 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -1,9 +1,9 @@
 use crate::infer::free_regions::FreeRegionMap;
-use crate::infer::{GenericKind, InferCtxt};
+use crate::infer::GenericKind;
 use crate::traits::query::OutlivesBound;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
-use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
+use rustc_middle::ty::{self, Region};
 
 use super::explicit_outlives_bounds;
 
@@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
             region_bound_pairs: Default::default(),
         };
 
-        builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
+        builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
 
         builder
     }
@@ -89,11 +89,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
     /// Create a new `OutlivesEnvironment` with extra outlives bounds.
     pub fn with_bounds(
         param_env: ty::ParamEnv<'tcx>,
-        infcx: Option<&InferCtxt<'tcx>>,
         extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
     ) -> Self {
         let mut builder = Self::builder(param_env);
-        builder.add_outlives_bounds(infcx, extra_bounds);
+        builder.add_outlives_bounds(extra_bounds);
         builder.build()
     }
 
@@ -120,12 +119,7 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
     }
 
     /// Processes outlives bounds that are known to hold, whether from implied or other sources.
-    ///
-    /// The `infcx` parameter is optional; if the implied bounds may
-    /// contain inference variables, it must be supplied, in which
-    /// case we will register "givens" on the inference context. (See
-    /// `RegionConstraintData`.)
-    fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
+    fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
     where
         I: IntoIterator<Item = OutlivesBound<'tcx>>,
     {
@@ -142,27 +136,17 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
                     self.region_bound_pairs
                         .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
                 }
-                OutlivesBound::RegionSubRegion(r_a, r_b) => {
-                    if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
-                        infcx
-                            .expect("no infcx provided but region vars found")
-                            .add_given(r_a, vid_b);
-                    } else {
-                        // In principle, we could record (and take
-                        // advantage of) every relationship here, but
-                        // we are also free not to -- it simply means
-                        // strictly less that we can successfully type
-                        // check. Right now we only look for things
-                        // relationships between free regions. (It may
-                        // also be that we should revise our inference
-                        // system to be more general and to make use
-                        // of *every* relationship that arises here,
-                        // but presently we do not.)
-                        if r_a.is_free_or_static() && r_b.is_free() {
-                            self.region_relation.add(r_a, r_b)
-                        }
-                    }
-                }
+                OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
+                    (
+                        ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
+                        ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
+                    ) => self.region_relation.add(r_a, r_b),
+                    (ty::ReError(_), _) | (_, ty::ReError(_)) => {}
+                    // FIXME(#109628): We shouldn't have existential variables in implied bounds.
+                    // Panic here once the linked issue is resolved!
+                    (ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
+                    _ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
+                },
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index e413b2bb570..89ada23c667 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -424,9 +424,6 @@ impl<'tcx> MiniGraph<'tcx> {
                 &AddConstraint(Constraint::RegSubReg(a, b)) => {
                     each_edge(a, b);
                 }
-                &AddGiven(a, b) => {
-                    each_edge(a, tcx.mk_re_var(b));
-                }
                 &AddVerify(i) => span_bug!(
                     verifys[i].origin.span(),
                     "we never add verifications while doing higher-ranked things",
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 0b86d9c1fb8..7b272dfd2a4 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -7,7 +7,7 @@ use super::{
     InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
 };
 
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
@@ -104,26 +104,6 @@ pub struct RegionConstraintData<'tcx> {
     /// An example is a `A <= B` where neither `A` nor `B` are
     /// inference variables.
     pub verifys: Vec<Verify<'tcx>>,
-
-    /// A "given" is a relationship that is known to hold. In
-    /// particular, we often know from closure fn signatures that a
-    /// particular free region must be a subregion of a region
-    /// variable:
-    ///
-    ///    foo.iter().filter(<'a> |x: &'a &'b T| ...)
-    ///
-    /// In situations like this, `'b` is in fact a region variable
-    /// introduced by the call to `iter()`, and `'a` is a bound region
-    /// on the closure (as indicated by the `<'a>` prefix). If we are
-    /// naive, we wind up inferring that `'b` must be `'static`,
-    /// because we require that it be greater than `'a` and we do not
-    /// know what `'a` is precisely.
-    ///
-    /// This hashmap is used to avoid that naive scenario. Basically
-    /// we record the fact that `'a <= 'b` is implied by the fn
-    /// signature, and then ignore the constraint when solving
-    /// equations. This is a bit of a hack but seems to work.
-    pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
 }
 
 /// Represents a constraint that influences the inference process.
@@ -297,9 +277,6 @@ pub(crate) enum UndoLog<'tcx> {
     /// We added the given `verify`.
     AddVerify(usize),
 
-    /// We added the given `given`.
-    AddGiven(Region<'tcx>, ty::RegionVid),
-
     /// We added a GLB/LUB "combination variable".
     AddCombination(CombineMapType, TwoRegions<'tcx>),
 }
@@ -348,9 +325,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> {
                 self.data.verifys.pop();
                 assert_eq!(self.data.verifys.len(), index);
             }
-            AddGiven(sub, sup) => {
-                self.data.givens.remove(&(sub, sup));
-            }
             AddCombination(Glb, ref regions) => {
                 self.glbs.remove(regions);
             }
@@ -492,15 +466,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         self.undo_log.push(AddVerify(index));
     }
 
-    pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
-        // cannot add givens once regions are resolved
-        if self.data.givens.insert((sub, sup)) {
-            debug!("add_given({:?} <= {:?})", sub, sup);
-
-            self.undo_log.push(AddGiven(sub, sup));
-        }
-    }
-
     pub(super) fn make_eqregion(
         &mut self,
         origin: SubregionOrigin<'tcx>,
@@ -804,11 +769,8 @@ impl<'tcx> RegionConstraintData<'tcx> {
     /// Returns `true` if this region constraint data contains no constraints, and `false`
     /// otherwise.
     pub fn is_empty(&self) -> bool {
-        let RegionConstraintData { constraints, member_constraints, verifys, givens } = self;
-        constraints.is_empty()
-            && member_constraints.is_empty()
-            && verifys.is_empty()
-            && givens.is_empty()
+        let RegionConstraintData { constraints, member_constraints, verifys } = self;
+        constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty()
     }
 }
 
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 96d6a1cb062..98d3ab87f9c 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -8,8 +8,8 @@ edition = "2021"
 [dependencies]
 libloading = "0.7.1"
 tracing = "0.1"
-rustc-rayon-core = { version = "0.4.0", optional = true }
-rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
+rustc-rayon-core = { version = "0.5.0", optional = true }
+rustc-rayon = { version = "0.5.0", optional = true }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
@@ -52,4 +52,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
 
 [features]
 llvm = ['rustc_codegen_llvm']
-rustc_use_parallel_compiler = ['rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']
+rustc_use_parallel_compiler = ['rustc-rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f3c80c6d854..612903810d2 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -183,7 +183,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
                     .try_collect_active_jobs()
                     .expect("active jobs shouldn't be locked in deadlock handler")
             });
-            let registry = rustc_rayon_core::Registry::current();
+            let registry = rayon_core::Registry::current();
             thread::spawn(move || deadlock(query_map, &registry));
         });
     if let Some(size) = get_stack_size() {
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index a2b78cc2985..5b2ec9029b1 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -26,8 +26,8 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_query_system = { path = "../rustc_query_system" }
-rustc-rayon-core = { version = "0.4.0", optional = true }
-rustc-rayon = { version = "0.4.0", optional = true }
+rustc-rayon-core = { version = "0.5.0", optional = true }
+rustc-rayon = { version = "0.5.0", optional = true }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs
index 5426ac8d739..fb0d909307e 100644
--- a/compiler/rustc_middle/src/ty/context/tls.rs
+++ b/compiler/rustc_middle/src/ty/context/tls.rs
@@ -4,6 +4,8 @@ use crate::dep_graph::TaskDepsRef;
 use crate::ty::query;
 use rustc_data_structures::sync::{self, Lock};
 use rustc_errors::Diagnostic;
+#[cfg(not(parallel_compiler))]
+use std::cell::Cell;
 use std::mem;
 use std::ptr;
 use thin_vec::ThinVec;
@@ -47,52 +49,15 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
     }
 }
 
+// Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
 #[cfg(parallel_compiler)]
-mod tlv {
-    use rustc_rayon_core as rayon_core;
-    use std::ptr;
-
-    /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
-    /// This is used to get the pointer to the current `ImplicitCtxt`.
-    #[inline]
-    pub(super) fn get_tlv() -> *const () {
-        ptr::from_exposed_addr(rayon_core::tlv::get())
-    }
-
-    /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
-    /// to `value` during the call to `f`. It is restored to its previous value after.
-    /// This is used to set the pointer to the new `ImplicitCtxt`.
-    #[inline]
-    pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
-        rayon_core::tlv::with(value.expose_addr(), f)
-    }
-}
+use rayon_core::tlv::TLV;
 
+// Otherwise define our own
 #[cfg(not(parallel_compiler))]
-mod tlv {
-    use std::cell::Cell;
-    use std::ptr;
-
-    thread_local! {
-        /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
-        static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
-    }
-
-    /// Gets the pointer to the current `ImplicitCtxt`.
-    #[inline]
-    pub(super) fn get_tlv() -> *const () {
-        TLV.with(|tlv| tlv.get())
-    }
-
-    /// Sets TLV to `value` during the call to `f`.
-    /// It is restored to its previous value after.
-    /// This is used to set the pointer to the new `ImplicitCtxt`.
-    #[inline]
-    pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
-        let old = TLV.replace(value);
-        let _reset = rustc_data_structures::OnDrop(move || TLV.set(old));
-        f()
-    }
+thread_local! {
+    /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
+    static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
 }
 
 #[inline]
@@ -111,7 +76,11 @@ pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) ->
 where
     F: FnOnce() -> R,
 {
-    tlv::with_tlv(erase(context), f)
+    TLV.with(|tlv| {
+        let old = tlv.replace(erase(context));
+        let _reset = rustc_data_structures::OnDrop(move || tlv.set(old));
+        f()
+    })
 }
 
 /// Allows access to the current `ImplicitCtxt` in a closure if one is available.
@@ -120,7 +89,7 @@ pub fn with_context_opt<F, R>(f: F) -> R
 where
     F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
 {
-    let context = tlv::get_tlv();
+    let context = TLV.get();
     if context.is_null() {
         f(None)
     } else {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 8e7012c2774..98265d58a0a 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1327,27 +1327,40 @@ fn create_mono_items_for_default_impls<'tcx>(
         return;
     }
 
+    let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
+        return;
+    };
+
+    // Lifetimes never affect trait selection, so we are allowed to eagerly
+    // instantiate an instance of an impl method if the impl (and method,
+    // which we check below) is only parameterized over lifetime. In that case,
+    // we use the ReErased, which has no lifetime information associated with
+    // it, to validate whether or not the impl is legal to instantiate at all.
+    let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind {
+        GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+        GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+            unreachable!(
+                "`own_requires_monomorphization` check means that \
+                we should have no type/const params"
+            )
+        }
+    };
+    let impl_substs = InternalSubsts::for_item(tcx, item.owner_id.to_def_id(), only_region_params);
+    let trait_ref = trait_ref.subst(tcx, impl_substs);
+
     // Unlike 'lazy' monomorphization that begins by collecting items transitively
     // called by `main` or other global items, when eagerly monomorphizing impl
     // items, we never actually check that the predicates of this impl are satisfied
     // in a empty reveal-all param env (i.e. with no assumptions).
     //
-    // Even though this impl has no substitutions, because we don't consider higher-
-    // ranked predicates such as `for<'a> &'a mut [u8]: Copy` to be trivially false,
-    // we must now check that the impl has no impossible-to-satisfy predicates.
-    if tcx.subst_and_check_impossible_predicates((
-        item.owner_id.to_def_id(),
-        &InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()),
-    )) {
+    // Even though this impl has no type or const substitutions, because we don't
+    // consider higher-ranked predicates such as `for<'a> &'a mut [u8]: Copy` to
+    // be trivially false. We must now check that the impl has no impossible-to-satisfy
+    // predicates.
+    if tcx.subst_and_check_impossible_predicates((item.owner_id.to_def_id(), impl_substs)) {
         return;
     }
 
-    let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
-        return;
-    };
-
-    let trait_ref = trait_ref.subst_identity();
-
     let param_env = ty::ParamEnv::reveal_all();
     let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
     let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
@@ -1360,12 +1373,9 @@ fn create_mono_items_for_default_impls<'tcx>(
             continue;
         }
 
-        let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
-            GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-            GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                trait_ref.substs[param.index as usize]
-            }
-        });
+        // As mentioned above, the method is legal to eagerly instantiate if it
+        // only has lifetime substitutions. This is validated by
+        let substs = trait_ref.substs.extend_to(tcx, method.def_id, only_region_params);
         let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, substs);
 
         let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 3e8a88c7e81..b107a3f03fe 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -16,7 +16,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_query_system = { path = "../rustc_query_system" }
-rustc-rayon-core = { version = "0.4.0", optional = true }
+rustc-rayon-core = { version = "0.5.0", optional = true }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 7d8f75e2566..12b4a114313 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -15,7 +15,7 @@ rustc_feature = { path = "../rustc_feature" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
-rustc-rayon-core = { version = "0.4.0", optional = true }
+rustc-rayon-core = { version = "0.5.0", optional = true }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index c9bc2240c21..a534b54070c 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -18,11 +18,11 @@ use std::num::NonZeroU64;
 #[cfg(parallel_compiler)]
 use {
     parking_lot::{Condvar, Mutex},
+    rayon_core,
     rustc_data_structures::fx::FxHashSet,
     rustc_data_structures::sync::Lock,
     rustc_data_structures::sync::Lrc,
     rustc_data_structures::{jobserver, OnDrop},
-    rustc_rayon_core as rayon_core,
     rustc_span::DUMMY_SP,
     std::iter,
     std::process,
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index c0446571905..e4dbb8a637c 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-indexmap = "1.9.1"
+indexmap = "1.9.3"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.12"
 
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 98d6e0ab117..a7c7575f392 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -18,4 +18,4 @@ tracing = "0.1"
 sha1 = "0.10.0"
 sha2 = "0.10.1"
 md5 = { package = "md-5", version = "0.10.0" }
-indexmap = { version = "1.9.1" }
+indexmap = { version = "1.9.3" }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index b7fafb0dca7..4e5e756dc4a 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -402,7 +402,6 @@ fn resolve_negative_obligation<'tcx>(
     let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        Some(&infcx),
         infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
     );
 
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 336db4fee6c..0bde43c54df 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -111,7 +111,6 @@ pub fn type_allowed_to_implement_copy<'tcx>(
             // Check regions assuming the self type of the impl is WF
             let outlives_env = OutlivesEnvironment::with_bounds(
                 param_env,
-                Some(&infcx),
                 infcx.implied_bounds_tys(
                     param_env,
                     parent_cause.body_id,
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index bac02f2d383..6d2dc94845d 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -3,7 +3,8 @@ use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
 use crate::traits::query::NoSolution;
 use crate::traits::{ObligationCause, ObligationCtxt};
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_middle::ty::{self, ParamEnv, Ty};
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
 use rustc_span::def_id::LocalDefId;
 
 pub use rustc_middle::traits::query::OutlivesBound;
@@ -52,6 +53,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
         body_id: LocalDefId,
         ty: Ty<'tcx>,
     ) -> Vec<OutlivesBound<'tcx>> {
+        let ty = self.resolve_vars_if_possible(ty);
+        let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
+        assert!(!ty.needs_infer());
+
         let span = self.tcx.def_span(body_id);
         let result = param_env
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
@@ -106,10 +111,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
         tys: FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx> {
         tys.into_iter()
-            .map(move |ty| {
-                let ty = self.resolve_vars_if_possible(ty);
-                self.implied_outlives_bounds(param_env, body_id, ty)
-            })
+            .map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
             .flatten()
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 4f429f018ed..98c3e7c13ac 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -211,7 +211,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx,
-            freshener: infcx.freshener_keep_static(),
+            freshener: infcx.freshener(),
             intercrate_ambiguity_causes: None,
             query_mode: TraitQueryMode::Standard,
         }
@@ -770,14 +770,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
 
                 ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => {
-                    // A global type with no late-bound regions can only
-                    // contain the "'static" lifetime (any other lifetime
-                    // would either be late-bound or local), so it is guaranteed
-                    // to outlive any other lifetime
-                    if pred.0.is_global() && !pred.0.has_late_bound_vars() {
-                        Ok(EvaluatedToOk)
-                    } else {
+                    // A global type with no free lifetimes or generic parameters
+                    // outlives anything.
+                    if pred.0.has_free_regions()
+                        || pred.0.has_late_bound_regions()
+                        || pred.0.has_non_region_infer()
+                        || pred.0.has_non_region_infer()
+                    {
                         Ok(EvaluatedToOkModuloRegions)
+                    } else {
+                        Ok(EvaluatedToOk)
                     }
                 }
 
@@ -1825,6 +1827,12 @@ enum DropVictim {
     No,
 }
 
+impl DropVictim {
+    fn drop_if(should_drop: bool) -> DropVictim {
+        if should_drop { DropVictim::Yes } else { DropVictim::No }
+    }
+}
+
 /// ## Winnowing
 ///
 /// Winnowing is the process of attempting to resolve ambiguity by
@@ -1890,11 +1898,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     // or the current one if tied (they should both evaluate to the same answer). This is
                     // probably best characterized as a "hack", since we might prefer to just do our
                     // best to *not* create essentially duplicate candidates in the first place.
-                    if other.bound_vars().len() <= victim.bound_vars().len() {
-                        DropVictim::Yes
-                    } else {
-                        DropVictim::No
-                    }
+                    DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len())
                 } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
                     && victim.skip_binder().constness == ty::BoundConstness::NotConst
                     && other.skip_binder().polarity == victim.skip_binder().polarity
@@ -1924,17 +1928,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 | ObjectCandidate(_)
                 | ProjectionCandidate(..),
             ) => {
-                if is_global(other_cand) {
-                    DropVictim::No
-                } else {
-                    // We have a where clause so don't go around looking
-                    // for impls. Arbitrarily give param candidates priority
-                    // over projection and object candidates.
-                    //
-                    // Global bounds from the where clause should be ignored
-                    // here (see issue #50825).
-                    DropVictim::Yes
-                }
+                // We have a where clause so don't go around looking
+                // for impls. Arbitrarily give param candidates priority
+                // over projection and object candidates.
+                //
+                // Global bounds from the where clause should be ignored
+                // here (see issue #50825).
+                DropVictim::drop_if(!is_global(other_cand))
             }
             (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
                 // Prefer these to a global where-clause bound
@@ -1956,18 +1956,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             ) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
-                if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() {
-                    DropVictim::Yes
-                } else {
-                    DropVictim::No
-                }
+                DropVictim::drop_if(
+                    is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
+                )
             }
 
             (ProjectionCandidate(i, _), ProjectionCandidate(j, _))
             | (ObjectCandidate(i), ObjectCandidate(j)) => {
                 // Arbitrarily pick the lower numbered candidate for backwards
                 // compatibility reasons. Don't let this affect inference.
-                if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No }
+                DropVictim::drop_if(i < j && !needs_infer)
             }
             (ObjectCandidate(_), ProjectionCandidate(..))
             | (ProjectionCandidate(..), ObjectCandidate(_)) => {
@@ -2018,55 +2016,65 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     }
                 }
 
-                if other.evaluation.must_apply_considering_regions() {
-                    match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
-                        Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
-                            // Subtle: If the predicate we are evaluating has inference
-                            // variables, do *not* allow discarding candidates due to
-                            // marker trait impls.
-                            //
-                            // Without this restriction, we could end up accidentally
-                            // constraining inference variables based on an arbitrarily
-                            // chosen trait impl.
-                            //
-                            // Imagine we have the following code:
-                            //
-                            // ```rust
-                            // #[marker] trait MyTrait {}
-                            // impl MyTrait for u8 {}
-                            // impl MyTrait for bool {}
-                            // ```
-                            //
-                            // And we are evaluating the predicate `<_#0t as MyTrait>`.
-                            //
-                            // During selection, we will end up with one candidate for each
-                            // impl of `MyTrait`. If we were to discard one impl in favor
-                            // of the other, we would be left with one candidate, causing
-                            // us to "successfully" select the predicate, unifying
-                            // _#0t with (for example) `u8`.
-                            //
-                            // However, we have no reason to believe that this unification
-                            // is correct - we've essentially just picked an arbitrary
-                            // *possibility* for _#0t, and required that this be the *only*
-                            // possibility.
-                            //
-                            // Eventually, we will either:
-                            // 1) Unify all inference variables in the predicate through
-                            // some other means (e.g. type-checking of a function). We will
-                            // then be in a position to drop marker trait candidates
-                            // without constraining inference variables (since there are
-                            // none left to constrain)
-                            // 2) Be left with some unconstrained inference variables. We
-                            // will then correctly report an inference error, since the
-                            // existence of multiple marker trait impls tells us nothing
-                            // about which one should actually apply.
-                            if needs_infer { DropVictim::No } else { DropVictim::Yes }
-                        }
-                        Some(_) => DropVictim::Yes,
-                        None => DropVictim::No,
+                match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+                    // For #33140 the impl headers must be exactly equal, the trait must not have
+                    // any associated items and there are no where-clauses.
+                    //
+                    // We can just arbitrarily drop one of the impls.
+                    Some(ty::ImplOverlapKind::Issue33140) => {
+                        assert_eq!(other.evaluation, victim.evaluation);
+                        DropVictim::Yes
                     }
-                } else {
-                    DropVictim::No
+                    // For candidates which already reference errors it doesn't really
+                    // matter what we do 🤷
+                    Some(ty::ImplOverlapKind::Permitted { marker: false }) => {
+                        DropVictim::drop_if(other.evaluation.must_apply_considering_regions())
+                    }
+                    Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
+                        // Subtle: If the predicate we are evaluating has inference
+                        // variables, do *not* allow discarding candidates due to
+                        // marker trait impls.
+                        //
+                        // Without this restriction, we could end up accidentally
+                        // constraining inference variables based on an arbitrarily
+                        // chosen trait impl.
+                        //
+                        // Imagine we have the following code:
+                        //
+                        // ```rust
+                        // #[marker] trait MyTrait {}
+                        // impl MyTrait for u8 {}
+                        // impl MyTrait for bool {}
+                        // ```
+                        //
+                        // And we are evaluating the predicate `<_#0t as MyTrait>`.
+                        //
+                        // During selection, we will end up with one candidate for each
+                        // impl of `MyTrait`. If we were to discard one impl in favor
+                        // of the other, we would be left with one candidate, causing
+                        // us to "successfully" select the predicate, unifying
+                        // _#0t with (for example) `u8`.
+                        //
+                        // However, we have no reason to believe that this unification
+                        // is correct - we've essentially just picked an arbitrary
+                        // *possibility* for _#0t, and required that this be the *only*
+                        // possibility.
+                        //
+                        // Eventually, we will either:
+                        // 1) Unify all inference variables in the predicate through
+                        // some other means (e.g. type-checking of a function). We will
+                        // then be in a position to drop marker trait candidates
+                        // without constraining inference variables (since there are
+                        // none left to constrain)
+                        // 2) Be left with some unconstrained inference variables. We
+                        // will then correctly report an inference error, since the
+                        // existence of multiple marker trait impls tells us nothing
+                        // about which one should actually apply.
+                        DropVictim::drop_if(
+                            !needs_infer && other.evaluation.must_apply_considering_regions(),
+                        )
+                    }
+                    None => DropVictim::No,
                 }
             }
 
diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs
index 34bc0ce9177..e2b40f7912e 100644
--- a/library/alloc/src/collections/vec_deque/into_iter.rs
+++ b/library/alloc/src/collections/vec_deque/into_iter.rs
@@ -1,4 +1,5 @@
 use core::iter::{FusedIterator, TrustedLen};
+use core::num::NonZeroUsize;
 use core::{array, fmt, mem::MaybeUninit, ops::Try, ptr};
 
 use crate::alloc::{Allocator, Global};
@@ -54,15 +55,16 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        if self.inner.len < n {
-            let len = self.inner.len;
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        let len = self.inner.len;
+        let rem = if len < n {
             self.inner.clear();
-            Err(len)
+            n - len
         } else {
             self.inner.drain(..n);
-            Ok(())
-        }
+            0
+        };
+        NonZeroUsize::new(rem).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -182,15 +184,16 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let len = self.inner.len;
-        if len >= n {
-            self.inner.truncate(len - n);
-            Ok(())
-        } else {
+        let rem = if len < n {
             self.inner.clear();
-            Err(len)
-        }
+            n - len
+        } else {
+            self.inner.truncate(len - n);
+            0
+        };
+        NonZeroUsize::new(rem).map_or(Ok(()), Err)
     }
 
     fn try_rfold<B, F, R>(&mut self, mut init: B, mut f: F) -> R
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index d9f3937144d..646a2a991e7 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -1,4 +1,5 @@
 use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
+use core::num::NonZeroUsize;
 use core::ops::Try;
 use core::{fmt, mem, slice};
 
@@ -55,13 +56,15 @@ impl<'a, T> Iterator for Iter<'a, T> {
         }
     }
 
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let m = match self.i1.advance_by(n) {
-            Ok(_) => return Ok(()),
-            Err(m) => m,
-        };
-        mem::swap(&mut self.i1, &mut self.i2);
-        self.i1.advance_by(n - m).map_err(|o| o + m)
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        let remaining = self.i1.advance_by(n);
+        match remaining {
+            Ok(()) => return Ok(()),
+            Err(n) => {
+                mem::swap(&mut self.i1, &mut self.i2);
+                self.i1.advance_by(n.get())
+            }
+        }
     }
 
     #[inline]
@@ -125,14 +128,14 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
         }
     }
 
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
-        let m = match self.i2.advance_back_by(n) {
-            Ok(_) => return Ok(()),
-            Err(m) => m,
-        };
-
-        mem::swap(&mut self.i1, &mut self.i2);
-        self.i2.advance_back_by(n - m).map_err(|o| m + o)
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        match self.i2.advance_back_by(n) {
+            Ok(()) => return Ok(()),
+            Err(n) => {
+                mem::swap(&mut self.i1, &mut self.i2);
+                self.i2.advance_back_by(n.get())
+            }
+        }
     }
 
     fn rfold<Acc, F>(self, accum: Acc, mut f: F) -> Acc
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 2c59d95cd53..7defbb1090f 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -1,4 +1,5 @@
 use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
+use core::num::NonZeroUsize;
 use core::ops::Try;
 use core::{fmt, mem, slice};
 
@@ -47,13 +48,14 @@ impl<'a, T> Iterator for IterMut<'a, T> {
         }
     }
 
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let m = match self.i1.advance_by(n) {
-            Ok(_) => return Ok(()),
-            Err(m) => m,
-        };
-        mem::swap(&mut self.i1, &mut self.i2);
-        self.i1.advance_by(n - m).map_err(|o| o + m)
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        match self.i1.advance_by(n) {
+            Ok(()) => return Ok(()),
+            Err(remaining) => {
+                mem::swap(&mut self.i1, &mut self.i2);
+                self.i1.advance_by(remaining.get())
+            }
+        }
     }
 
     #[inline]
@@ -117,14 +119,14 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
         }
     }
 
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
-        let m = match self.i2.advance_back_by(n) {
-            Ok(_) => return Ok(()),
-            Err(m) => m,
-        };
-
-        mem::swap(&mut self.i1, &mut self.i2);
-        self.i2.advance_back_by(n - m).map_err(|o| m + o)
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        match self.i2.advance_back_by(n) {
+            Ok(()) => return Ok(()),
+            Err(remaining) => {
+                mem::swap(&mut self.i1, &mut self.i2);
+                self.i2.advance_back_by(remaining.get())
+            }
+        }
     }
 
     fn rfold<Acc, F>(self, accum: Acc, mut f: F) -> Acc
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index f6525eb9003..6a05f70e437 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -11,6 +11,7 @@ use core::iter::{
 };
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
+use core::num::NonZeroUsize;
 #[cfg(not(no_global_oom_handling))]
 use core::ops::Deref;
 use core::ptr::{self, NonNull};
@@ -213,7 +214,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let step_size = self.len().min(n);
         let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
         if T::IS_ZST {
@@ -227,10 +228,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
         unsafe {
             ptr::drop_in_place(to_drop);
         }
-        if step_size < n {
-            return Err(step_size);
-        }
-        Ok(())
+        NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -313,7 +311,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let step_size = self.len().min(n);
         if T::IS_ZST {
             // SAFETY: same as for advance_by()
@@ -327,10 +325,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
         unsafe {
             ptr::drop_in_place(to_drop);
         }
-        if step_size < n {
-            return Err(step_size);
-        }
-        Ok(())
+        NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 2f07c2911a5..3ee16f04e92 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1,5 +1,7 @@
 use core::alloc::{Allocator, Layout};
+use core::assert_eq;
 use core::iter::IntoIterator;
+use core::num::NonZeroUsize;
 use core::ptr::NonNull;
 use std::alloc::System;
 use std::assert_matches::assert_matches;
@@ -1062,21 +1064,21 @@ fn test_into_iter_leak() {
 
 #[test]
 fn test_into_iter_advance_by() {
-    let mut i = [1, 2, 3, 4, 5].into_iter();
-    i.advance_by(0).unwrap();
-    i.advance_back_by(0).unwrap();
+    let mut i = vec![1, 2, 3, 4, 5].into_iter();
+    assert_eq!(i.advance_by(0), Ok(()));
+    assert_eq!(i.advance_back_by(0), Ok(()));
     assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]);
 
-    i.advance_by(1).unwrap();
-    i.advance_back_by(1).unwrap();
+    assert_eq!(i.advance_by(1), Ok(()));
+    assert_eq!(i.advance_back_by(1), Ok(()));
     assert_eq!(i.as_slice(), [2, 3, 4]);
 
-    assert_eq!(i.advance_back_by(usize::MAX), Err(3));
+    assert_eq!(i.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 3).unwrap()));
 
-    assert_eq!(i.advance_by(usize::MAX), Err(0));
+    assert_eq!(i.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
 
-    i.advance_by(0).unwrap();
-    i.advance_back_by(0).unwrap();
+    assert_eq!(i.advance_by(0), Ok(()));
+    assert_eq!(i.advance_back_by(0), Ok(()));
 
     assert_eq!(i.len(), 0);
 }
@@ -1124,7 +1126,7 @@ fn test_into_iter_zst() {
     for _ in vec![C; 5].into_iter().rev() {}
 
     let mut it = vec![C, C].into_iter();
-    it.advance_by(1).unwrap();
+    assert_eq!(it.advance_by(1), Ok(()));
     drop(it);
 
     let mut it = vec![C, C].into_iter();
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index 5a0b852e8d5..ddc27e34ed9 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -1,3 +1,4 @@
+use core::num::NonZeroUsize;
 use std::assert_matches::assert_matches;
 use std::collections::TryReserveErrorKind::*;
 use std::collections::{vec_deque::Drain, VecDeque};
@@ -426,6 +427,28 @@ fn test_into_iter() {
         assert_eq!(it.next(), Some(7));
         assert_eq!(it.size_hint(), (5, Some(5)));
     }
+
+    // advance_by
+    {
+        let mut d = VecDeque::new();
+        for i in 0..=4 {
+            d.push_back(i);
+        }
+        for i in 6..=8 {
+            d.push_front(i);
+        }
+
+        let mut it = d.into_iter();
+        assert_eq!(it.advance_by(1), Ok(()));
+        assert_eq!(it.next(), Some(7));
+        assert_eq!(it.advance_back_by(1), Ok(()));
+        assert_eq!(it.next_back(), Some(3));
+
+        let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
+        assert_eq!(it.advance_by(10), Err(NonZeroUsize::new(5).unwrap()));
+        let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
+        assert_eq!(it.advance_back_by(10), Err(NonZeroUsize::new(5).unwrap()));
+    }
 }
 
 #[test]
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 8259c087d22..73e2c2cfbbe 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -1,5 +1,6 @@
 //! Defines the `IntoIter` owned iterator for arrays.
 
+use crate::num::NonZeroUsize;
 use crate::{
     fmt,
     iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
@@ -284,12 +285,11 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
         self.next_back()
     }
 
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let original_len = self.len();
-
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         // This also moves the start, which marks them as conceptually "dropped",
         // so if anything goes bad then our drop impl won't double-free them.
         let range_to_drop = self.alive.take_prefix(n);
+        let remaining = n - range_to_drop.len();
 
         // SAFETY: These elements are currently initialized, so it's fine to drop them.
         unsafe {
@@ -297,7 +297,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        if n > original_len { Err(original_len) } else { Ok(()) }
+        NonZeroUsize::new(remaining).map_or(Ok(()), Err)
     }
 }
 
@@ -334,12 +334,11 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
         })
     }
 
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
-        let original_len = self.len();
-
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         // This also moves the end, which marks them as conceptually "dropped",
         // so if anything goes bad then our drop impl won't double-free them.
         let range_to_drop = self.alive.take_suffix(n);
+        let remaining = n - range_to_drop.len();
 
         // SAFETY: These elements are currently initialized, so it's fine to drop them.
         unsafe {
@@ -347,7 +346,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        if n > original_len { Err(original_len) } else { Ok(()) }
+        NonZeroUsize::new(remaining).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs
index 477e7117c3e..4e0e19ddc78 100644
--- a/library/core/src/iter/adapters/by_ref_sized.rs
+++ b/library/core/src/iter/adapters/by_ref_sized.rs
@@ -1,3 +1,4 @@
+use crate::num::NonZeroUsize;
 use crate::ops::{NeverShortCircuit, Try};
 
 /// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
@@ -26,7 +27,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         I::advance_by(self.0, n)
     }
 
@@ -62,7 +63,7 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         I::advance_back_by(self.0, n)
     }
 
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index d4b2640e81d..2046b70c9c6 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -1,4 +1,5 @@
 use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
+use crate::num::NonZeroUsize;
 use crate::ops::Try;
 
 /// An iterator that links two iterators together, in a chain.
@@ -95,38 +96,33 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let mut rem = n;
-
+    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
         if let Some(ref mut a) = self.a {
-            match a.advance_by(rem) {
+            n = match a.advance_by(n) {
                 Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+                Err(k) => k.get(),
+            };
             self.a = None;
         }
 
         if let Some(ref mut b) = self.b {
-            match b.advance_by(rem) {
-                Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+            return b.advance_by(n);
             // we don't fuse the second iterator
         }
 
-        if rem == 0 { Ok(()) } else { Err(n - rem) }
+        NonZeroUsize::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
     fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
         if let Some(ref mut a) = self.a {
-            match a.advance_by(n) {
+            n = match a.advance_by(n) {
                 Ok(()) => match a.next() {
-                    None => n = 0,
+                    None => 0,
                     x => return x,
                 },
-                Err(k) => n -= k,
-            }
+                Err(k) => k.get(),
+            };
 
             self.a = None;
         }
@@ -186,38 +182,33 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
-        let mut rem = n;
-
+    fn advance_back_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
         if let Some(ref mut b) = self.b {
-            match b.advance_back_by(rem) {
+            n = match b.advance_back_by(n) {
                 Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+                Err(k) => k.get(),
+            };
             self.b = None;
         }
 
         if let Some(ref mut a) = self.a {
-            match a.advance_back_by(rem) {
-                Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+            return a.advance_back_by(n);
             // we don't fuse the second iterator
         }
 
-        if rem == 0 { Ok(()) } else { Err(n - rem) }
+        NonZeroUsize::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
     fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
         if let Some(ref mut b) = self.b {
-            match b.advance_back_by(n) {
+            n = match b.advance_back_by(n) {
                 Ok(()) => match b.next_back() {
-                    None => n = 0,
+                    None => 0,
                     x => return x,
                 },
-                Err(k) => n -= k,
-            }
+                Err(k) => k.get(),
+            };
 
             self.b = None;
         }
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index a076ab925e3..2289025d0a7 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -4,6 +4,7 @@ use crate::iter::adapters::{
 use crate::iter::{FusedIterator, TrustedLen};
 use crate::mem::MaybeUninit;
 use crate::mem::SizedTypeProperties;
+use crate::num::NonZeroUsize;
 use crate::ops::Try;
 use crate::{array, ptr};
 
@@ -89,7 +90,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.it.advance_by(n)
     }
 
@@ -130,7 +131,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.it.advance_back_by(n)
     }
 }
diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs
index 02b5939072e..51bd09b6eff 100644
--- a/library/core/src/iter/adapters/cycle.rs
+++ b/library/core/src/iter/adapters/cycle.rs
@@ -1,3 +1,4 @@
+use crate::num::NonZeroUsize;
 use crate::{iter::FusedIterator, ops::Try};
 
 /// An iterator that repeats endlessly.
@@ -81,23 +82,22 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let mut rem = n;
-        match self.iter.advance_by(rem) {
-            ret @ Ok(_) => return ret,
-            Err(advanced) => rem -= advanced,
-        }
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        let mut n = match self.iter.advance_by(n) {
+            Ok(()) => return Ok(()),
+            Err(rem) => rem.get(),
+        };
 
-        while rem > 0 {
+        while n > 0 {
             self.iter = self.orig.clone();
-            match self.iter.advance_by(rem) {
-                ret @ Ok(_) => return ret,
-                Err(0) => return Err(n - rem),
-                Err(advanced) => rem -= advanced,
-            }
+            n = match self.iter.advance_by(n) {
+                Ok(()) => return Ok(()),
+                e @ Err(rem) if rem.get() == n => return e,
+                Err(rem) => rem.get(),
+            };
         }
 
-        Ok(())
+        NonZeroUsize::new(n).map_or(Ok(()), Err)
     }
 
     // No `fold` override, because `fold` doesn't make much sense for `Cycle`,
diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs
index 8c32a35a12f..479ea6d83c7 100644
--- a/library/core/src/iter/adapters/enumerate.rs
+++ b/library/core/src/iter/adapters/enumerate.rs
@@ -2,6 +2,7 @@ use crate::iter::adapters::{
     zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
 };
 use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
+use crate::num::NonZeroUsize;
 use crate::ops::Try;
 
 /// An iterator that yields the current count and the element during iteration.
@@ -114,17 +115,14 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        match self.iter.advance_by(n) {
-            ret @ Ok(_) => {
-                self.count += n;
-                ret
-            }
-            ret @ Err(advanced) => {
-                self.count += advanced;
-                ret
-            }
-        }
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        let remaining = self.iter.advance_by(n);
+        let advanced = match remaining {
+            Ok(()) => n,
+            Err(rem) => n - rem.get(),
+        };
+        self.count += advanced;
+        remaining
     }
 
     #[rustc_inherit_overflow_checks]
@@ -208,7 +206,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         // we do not need to update the count since that only tallies the number of items
         // consumed from the front. consuming items from the back can never reduce that.
         self.iter.advance_back_by(n)
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index e4020c45f71..e0308e3360f 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -1,5 +1,6 @@
 use crate::fmt;
 use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen};
+use crate::num::NonZeroUsize;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that maps each element to an iterator, and yields the elements
@@ -75,7 +76,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.inner.advance_by(n)
     }
 
@@ -120,7 +121,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.inner.advance_back_by(n)
     }
 }
@@ -236,7 +237,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.inner.advance_by(n)
     }
 
@@ -281,7 +282,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.inner.advance_back_by(n)
     }
 }
@@ -552,18 +553,18 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         #[inline]
         #[rustc_inherit_overflow_checks]
         fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
             match iter.advance_by(n) {
                 Ok(()) => ControlFlow::Break(()),
-                Err(advanced) => ControlFlow::Continue(n - advanced),
+                Err(remaining) => ControlFlow::Continue(remaining.get()),
             }
         }
 
         match self.iter_try_fold(n, advance) {
-            ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+            ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
             _ => Ok(()),
         }
     }
@@ -642,18 +643,18 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         #[inline]
         #[rustc_inherit_overflow_checks]
         fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
             match iter.advance_back_by(n) {
                 Ok(()) => ControlFlow::Break(()),
-                Err(advanced) => ControlFlow::Continue(n - advanced),
+                Err(remaining) => ControlFlow::Continue(remaining.get()),
             }
         }
 
         match self.iter_try_rfold(n, advance) {
-            ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+            ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
             _ => Ok(()),
         }
     }
diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs
index 8ae6d96fde4..1d882087f69 100644
--- a/library/core/src/iter/adapters/rev.rs
+++ b/library/core/src/iter/adapters/rev.rs
@@ -1,4 +1,5 @@
 use crate::iter::{FusedIterator, TrustedLen};
+use crate::num::NonZeroUsize;
 use crate::ops::Try;
 
 /// A double-ended iterator with the direction inverted.
@@ -38,7 +39,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.iter.advance_back_by(n)
     }
 
@@ -83,7 +84,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.iter.advance_by(n)
     }
 
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index c6334880db5..306338bc7cc 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -1,5 +1,6 @@
 use crate::intrinsics::unlikely;
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::num::NonZeroUsize;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that skips over `n` elements of `iter`.
@@ -128,34 +129,27 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let mut rem = n;
-        let step_one = self.n.saturating_add(rem);
-
-        match self.iter.advance_by(step_one) {
-            Ok(_) => {
-                rem -= step_one - self.n;
-                self.n = 0;
-            }
-            Err(advanced) => {
-                let advanced_without_skip = advanced.saturating_sub(self.n);
-                self.n = self.n.saturating_sub(advanced);
-                return if n == 0 { Ok(()) } else { Err(advanced_without_skip) };
-            }
-        }
+    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
+        let skip_inner = self.n;
+        let skip_and_advance = skip_inner.saturating_add(n);
 
-        // step_one calculation may have saturated
-        if unlikely(rem > 0) {
-            return match self.iter.advance_by(rem) {
-                ret @ Ok(_) => ret,
-                Err(advanced) => {
-                    rem -= advanced;
-                    Err(n - rem)
-                }
-            };
+        let remainder = match self.iter.advance_by(skip_and_advance) {
+            Ok(()) => 0,
+            Err(n) => n.get(),
+        };
+        let advanced_inner = skip_and_advance - remainder;
+        n -= advanced_inner.saturating_sub(skip_inner);
+        self.n = self.n.saturating_sub(advanced_inner);
+
+        // skip_and_advance may have saturated
+        if unlikely(remainder == 0 && n > 0) {
+            n = match self.iter.advance_by(n) {
+                Ok(()) => 0,
+                Err(n) => n.get(),
+            }
         }
 
-        Ok(())
+        NonZeroUsize::new(n).map_or(Ok(()), Err)
     }
 }
 
@@ -209,13 +203,11 @@ where
     impl_fold_via_try_fold! { rfold -> try_rfold }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let min = crate::cmp::min(self.len(), n);
-        return match self.iter.advance_back_by(min) {
-            ret @ Ok(_) if n <= min => ret,
-            Ok(_) => Err(min),
-            _ => panic!("ExactSizeIterator contract violation"),
-        };
+        let rem = self.iter.advance_back_by(min);
+        assert!(rem.is_ok(), "ExactSizeIterator contract violation");
+        NonZeroUsize::new(n - min).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index d947c7b0e30..ce18bffe714 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -1,5 +1,6 @@
 use crate::cmp;
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
+use crate::num::NonZeroUsize;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that only iterates over the first `n` iterations of `iter`.
@@ -121,18 +122,15 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let min = self.n.min(n);
-        match self.iter.advance_by(min) {
-            Ok(_) => {
-                self.n -= min;
-                if min < n { Err(min) } else { Ok(()) }
-            }
-            ret @ Err(advanced) => {
-                self.n -= advanced;
-                ret
-            }
-        }
+        let rem = match self.iter.advance_by(min) {
+            Ok(()) => 0,
+            Err(rem) => rem.get(),
+        };
+        let advanced = min - rem;
+        self.n -= advanced;
+        NonZeroUsize::new(n - advanced).map_or(Ok(()), Err)
     }
 }
 
@@ -223,7 +221,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         // The amount by which the inner iterator needs to be shortened for it to be
         // at most as long as the take() amount.
         let trim_inner = self.iter.len().saturating_sub(self.n);
@@ -232,12 +230,14 @@ where
         // about having to advance more than usize::MAX here.
         let advance_by = trim_inner.saturating_add(n);
 
-        let advanced = match self.iter.advance_back_by(advance_by) {
-            Ok(_) => advance_by - trim_inner,
-            Err(advanced) => advanced - trim_inner,
+        let remainder = match self.iter.advance_back_by(advance_by) {
+            Ok(()) => 0,
+            Err(rem) => rem.get(),
         };
-        self.n -= advanced;
-        return if advanced < n { Err(advanced) } else { Ok(()) };
+        let advanced_by_inner = advance_by - remainder;
+        let advanced_by = advanced_by_inner - trim_inner;
+        self.n -= advanced_by;
+        NonZeroUsize::new(n - advanced_by).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index f19636fba5d..1cd71193bd7 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -1,6 +1,7 @@
 use crate::convert::TryFrom;
 use crate::marker::Destruct;
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::ops::{self, Try};
 
 use super::{
@@ -530,12 +531,12 @@ trait RangeIteratorImpl {
     // Iterator
     fn spec_next(&mut self) -> Option<Self::Item>;
     fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
-    fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>;
+    fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
 
     // DoubleEndedIterator
     fn spec_next_back(&mut self) -> Option<Self::Item>;
     fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
-    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>;
+    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
 }
 
 impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> {
@@ -567,7 +568,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
     }
 
     #[inline]
-    default fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
+    default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -579,7 +580,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
         self.start =
             Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld");
 
-        if taken < n { Err(taken) } else { Ok(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -608,7 +609,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
     }
 
     #[inline]
-    default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -620,7 +621,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
         self.end =
             Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld");
 
-        if taken < n { Err(taken) } else { Ok(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
@@ -651,7 +652,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
     }
 
     #[inline]
-    fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -666,7 +667,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
         // Otherwise 0 is returned which always safe to use.
         self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) };
 
-        if taken < n { Err(taken) } else { Ok(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -695,7 +696,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
     }
 
     #[inline]
-    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -707,7 +708,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
         // SAFETY: same as the spec_advance_by() implementation
         self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) };
 
-        if taken < n { Err(taken) } else { Ok(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
@@ -757,7 +758,7 @@ impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.spec_advance_by(n)
     }
 
@@ -836,7 +837,7 @@ impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.spec_advance_back_by(n)
     }
 }
diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs
index 733142ed011..67051f6e97b 100644
--- a/library/core/src/iter/sources/repeat.rs
+++ b/library/core/src/iter/sources/repeat.rs
@@ -1,4 +1,5 @@
 use crate::iter::{FusedIterator, TrustedLen};
+use crate::num::NonZeroUsize;
 
 /// Creates a new iterator that endlessly repeats a single element.
 ///
@@ -80,7 +81,7 @@ impl<A: Clone> Iterator for Repeat<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         // Advancing an infinite iterator of a single element is a no-op.
         let _ = n;
         Ok(())
@@ -109,7 +110,7 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         // Advancing an infinite iterator of a single element is a no-op.
         let _ = n;
         Ok(())
diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs
index dc61d6065b8..0b0445850bf 100644
--- a/library/core/src/iter/sources/repeat_n.rs
+++ b/library/core/src/iter/sources/repeat_n.rs
@@ -1,5 +1,6 @@
 use crate::iter::{FusedIterator, TrustedLen};
 use crate::mem::ManuallyDrop;
+use crate::num::NonZeroUsize;
 
 /// Creates a new iterator that repeats a single element a given number of times.
 ///
@@ -137,7 +138,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, skip: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, skip: usize) -> Result<(), NonZeroUsize> {
         let len = self.count;
 
         if skip >= len {
@@ -145,7 +146,8 @@ impl<A: Clone> Iterator for RepeatN<A> {
         }
 
         if skip > len {
-            Err(len)
+            // SAFETY: we just checked that the difference is positive
+            Err(unsafe { NonZeroUsize::new_unchecked(skip - len) })
         } else {
             self.count = len - skip;
             Ok(())
@@ -178,7 +180,7 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.advance_by(n)
     }
 
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 7a10dea500a..d82ecb698dd 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -1,4 +1,5 @@
 use crate::marker::Destruct;
+use crate::num::NonZeroUsize;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator able to yield elements from both ends.
@@ -100,10 +101,11 @@ pub trait DoubleEndedIterator: Iterator {
     /// eagerly skip `n` elements starting from the back by calling [`next_back`] up
     /// to `n` times until [`None`] is encountered.
     ///
-    /// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by
-    /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number of
-    /// elements the iterator is advanced by before running out of elements (i.e. the length
-    /// of the iterator). Note that `k` is always less than `n`.
+    /// `advance_back_by(n)` will return `Ok(())` if the iterator successfully advances by
+    /// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered, where `k`
+    /// is remaining number of steps that could not be advanced because the iterator ran out.
+    /// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
+    /// Otherwise, `k` is always less than `n`.
     ///
     /// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its
     /// outer iterator until it finds an inner iterator that is not empty, which then often
@@ -120,25 +122,29 @@ pub trait DoubleEndedIterator: Iterator {
     /// ```
     /// #![feature(iter_advance_by)]
     ///
+    /// use std::num::NonZeroUsize;
     /// let a = [3, 4, 5, 6];
     /// let mut iter = a.iter();
     ///
     /// assert_eq!(iter.advance_back_by(2), Ok(()));
     /// assert_eq!(iter.next_back(), Some(&4));
     /// assert_eq!(iter.advance_back_by(0), Ok(()));
-    /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped
+    /// assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&3` was skipped
     /// ```
     ///
     /// [`Ok(())`]: Ok
     /// [`Err(k)`]: Err
     #[inline]
     #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize>
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
     where
         Self::Item: ~const Destruct,
     {
         for i in 0..n {
-            self.next_back().ok_or(i)?;
+            if self.next_back().is_none() {
+                // SAFETY: `i` is always less than `n`.
+                return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
+            }
         }
         Ok(())
     }
@@ -188,7 +194,9 @@ pub trait DoubleEndedIterator: Iterator {
     #[stable(feature = "iter_nth_back", since = "1.37.0")]
     #[rustc_do_not_const_check]
     fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        self.advance_back_by(n).ok()?;
+        if self.advance_back_by(n).is_err() {
+            return None;
+        }
         self.next_back()
     }
 
@@ -374,7 +382,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
     fn next_back(&mut self) -> Option<I::Item> {
         (**self).next_back()
     }
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         (**self).advance_back_by(n)
     }
     fn nth_back(&mut self, n: usize) -> Option<I::Item> {
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 16c9f668b8e..080330fa41e 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1,6 +1,7 @@
 use crate::array;
 use crate::cmp::{self, Ordering};
 use crate::marker::Destruct;
+use crate::num::NonZeroUsize;
 use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 
 use super::super::try_process;
@@ -308,10 +309,11 @@ pub trait Iterator {
     /// This method will eagerly skip `n` elements by calling [`next`] up to `n`
     /// times until [`None`] is encountered.
     ///
-    /// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by
-    /// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number
-    /// of elements the iterator is advanced by before running out of elements (i.e. the
-    /// length of the iterator). Note that `k` is always less than `n`.
+    /// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by
+    /// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered,
+    /// where `k` is remaining number of steps that could not be advanced because the iterator ran out.
+    /// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
+    /// Otherwise, `k` is always less than `n`.
     ///
     /// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`]
     /// can advance its outer iterator until it finds an inner iterator that is not empty, which
@@ -327,22 +329,26 @@ pub trait Iterator {
     /// ```
     /// #![feature(iter_advance_by)]
     ///
+    /// use std::num::NonZeroUsize;
     /// let a = [1, 2, 3, 4];
     /// let mut iter = a.iter();
     ///
     /// assert_eq!(iter.advance_by(2), Ok(()));
     /// assert_eq!(iter.next(), Some(&3));
     /// assert_eq!(iter.advance_by(0), Ok(()));
-    /// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped
+    /// assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&4` was skipped
     /// ```
     #[inline]
     #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize>
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
     where
         Self::Item: ~const Destruct,
     {
         for i in 0..n {
-            self.next().ok_or(i)?;
+            if self.next().is_none() {
+                // SAFETY: `i` is always less than `n`.
+                return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
+            }
         }
         Ok(())
     }
@@ -4013,7 +4019,7 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
     fn size_hint(&self) -> (usize, Option<usize>) {
         (**self).size_hint()
     }
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         (**self).advance_by(n)
     }
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index 3e06776d2c6..265022a394e 100644
--- a/library/core/src/ops/index_range.rs
+++ b/library/core/src/ops/index_range.rs
@@ -1,5 +1,6 @@
 use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub};
 use crate::iter::{FusedIterator, TrustedLen};
+use crate::num::NonZeroUsize;
 
 /// Like a `Range<usize>`, but with a safety invariant that `start <= end`.
 ///
@@ -132,10 +133,9 @@ impl Iterator for IndexRange {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let original_len = self.len();
-        self.take_prefix(n);
-        if n > original_len { Err(original_len) } else { Ok(()) }
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        let taken = self.take_prefix(n);
+        NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
     }
 }
 
@@ -151,10 +151,9 @@ impl DoubleEndedIterator for IndexRange {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
-        let original_len = self.len();
-        self.take_suffix(n);
-        if n > original_len { Err(original_len) } else { Ok(()) }
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+        let taken = self.take_suffix(n);
+        NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index a800da546b4..b73e35f1e91 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -176,11 +176,11 @@ macro_rules! iterator {
             }
 
             #[inline]
-            fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+            fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.post_inc_start(advance) };
-                if advance == n { Ok(()) } else { Err(advance) }
+                NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
             }
 
             #[inline]
@@ -371,11 +371,11 @@ macro_rules! iterator {
             }
 
             #[inline]
-            fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+            fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.pre_dec_end(advance) };
-                if advance == n { Ok(()) } else { Err(advance) }
+                NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
             }
         }
 
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index 5327e4f8139..0869644c040 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -1,5 +1,6 @@
-use core::array;
+use core::{array, assert_eq};
 use core::convert::TryFrom;
+use core::num::NonZeroUsize;
 use core::sync::atomic::{AtomicUsize, Ordering};
 
 #[test]
@@ -557,7 +558,7 @@ fn array_intoiter_advance_by() {
     assert_eq!(counter.get(), 13);
 
     let r = it.advance_by(123456);
-    assert_eq!(r, Err(87));
+    assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 
@@ -567,7 +568,7 @@ fn array_intoiter_advance_by() {
     assert_eq!(counter.get(), 100);
 
     let r = it.advance_by(10);
-    assert_eq!(r, Err(0));
+    assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 }
@@ -610,7 +611,7 @@ fn array_intoiter_advance_back_by() {
     assert_eq!(counter.get(), 13);
 
     let r = it.advance_back_by(123456);
-    assert_eq!(r, Err(87));
+    assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 
@@ -620,7 +621,7 @@ fn array_intoiter_advance_back_by() {
     assert_eq!(counter.get(), 100);
 
     let r = it.advance_back_by(10);
-    assert_eq!(r, Err(0));
+    assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 }
@@ -679,8 +680,8 @@ fn array_into_iter_fold() {
 
     let a = [1, 2, 3, 4, 5, 6];
     let mut it = a.into_iter();
-    it.advance_by(1).unwrap();
-    it.advance_back_by(2).unwrap();
+    assert_eq!(it.advance_by(1), Ok(()));
+    assert_eq!(it.advance_back_by(2), Ok(()));
     let s = it.fold(10, |a, b| 10 * a + b);
     assert_eq!(s, 10234);
 }
@@ -695,8 +696,8 @@ fn array_into_iter_rfold() {
 
     let a = [1, 2, 3, 4, 5, 6];
     let mut it = a.into_iter();
-    it.advance_by(1).unwrap();
-    it.advance_back_by(2).unwrap();
+    assert_eq!(it.advance_by(1), Ok(()));
+    assert_eq!(it.advance_back_by(2), Ok(()));
     let s = it.rfold(10, |a, b| 10 * a + b);
     assert_eq!(s, 10432);
 }
diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs
index f419f9cec12..175a1b638e1 100644
--- a/library/core/tests/iter/adapters/chain.rs
+++ b/library/core/tests/iter/adapters/chain.rs
@@ -1,5 +1,6 @@
 use super::*;
 use core::iter::*;
+use core::num::NonZeroUsize;
 
 #[test]
 fn test_iterator_chain() {
@@ -31,28 +32,28 @@ fn test_iterator_chain_advance_by() {
 
         for i in 0..xs.len() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_by(i).unwrap();
+            assert_eq!(iter.advance_by(i), Ok(()));
             assert_eq!(iter.next(), Some(&xs[i]));
-            assert_eq!(iter.advance_by(100), Err(len - i - 1));
-            iter.advance_by(0).unwrap();
+            assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap()));
+            assert_eq!(iter.advance_by(0), Ok(()));
         }
 
         for i in 0..ys.len() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_by(xs.len() + i).unwrap();
+            assert_eq!(iter.advance_by(xs.len() + i), Ok(()));
             assert_eq!(iter.next(), Some(&ys[i]));
-            assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
-            iter.advance_by(0).unwrap();
+            assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (ys.len() - i - 1)).unwrap()));
+            assert_eq!(iter.advance_by(0), Ok(()));
         }
 
         let mut iter = xs.iter().chain(ys);
-        iter.advance_by(len).unwrap();
+        assert_eq!(iter.advance_by(len), Ok(()));
         assert_eq!(iter.next(), None);
-        iter.advance_by(0).unwrap();
+        assert_eq!(iter.advance_by(0), Ok(()));
 
         let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_by(len + 1), Err(len));
-        iter.advance_by(0).unwrap();
+        assert_eq!(iter.advance_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
+        assert_eq!(iter.advance_by(0), Ok(()));
     }
 
     test_chain(&[], &[]);
@@ -68,28 +69,28 @@ fn test_iterator_chain_advance_back_by() {
 
         for i in 0..ys.len() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_back_by(i).unwrap();
+            assert_eq!(iter.advance_back_by(i), Ok(()));
             assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
-            assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
-            iter.advance_back_by(0).unwrap();
+            assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap()));
+            assert_eq!(iter.advance_back_by(0), Ok(()));
         }
 
         for i in 0..xs.len() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_back_by(ys.len() + i).unwrap();
+            assert_eq!(iter.advance_back_by(ys.len() + i), Ok(()));
             assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
-            assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
-            iter.advance_back_by(0).unwrap();
+            assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (xs.len() - i - 1)).unwrap()));
+            assert_eq!(iter.advance_back_by(0), Ok(()));
         }
 
         let mut iter = xs.iter().chain(ys);
-        iter.advance_back_by(len).unwrap();
+        assert_eq!(iter.advance_back_by(len), Ok(()));
         assert_eq!(iter.next_back(), None);
-        iter.advance_back_by(0).unwrap();
+        assert_eq!(iter.advance_back_by(0), Ok(()));
 
         let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_back_by(len + 1), Err(len));
-        iter.advance_back_by(0).unwrap();
+        assert_eq!(iter.advance_back_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
+        assert_eq!(iter.advance_back_by(0), Ok(()));
     }
 
     test_chain(&[], &[]);
diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs
index 0e603387847..ff57973a62a 100644
--- a/library/core/tests/iter/adapters/enumerate.rs
+++ b/library/core/tests/iter/adapters/enumerate.rs
@@ -1,4 +1,5 @@
 use core::iter::*;
+use core::num::NonZeroUsize;
 
 #[test]
 fn test_iterator_enumerate() {
@@ -56,6 +57,20 @@ fn test_iterator_enumerate_count() {
 }
 
 #[test]
+fn test_iterator_enumerate_advance_by() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let mut it = xs.iter().enumerate();
+    assert_eq!(it.advance_by(0), Ok(()));
+    assert_eq!(it.next(), Some((0, &0)));
+    assert_eq!(it.advance_by(1), Ok(()));
+    assert_eq!(it.next(), Some((2, &2)));
+    assert_eq!(it.advance_by(2), Ok(()));
+    assert_eq!(it.next(), Some((5, &5)));
+    assert_eq!(it.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
 fn test_iterator_enumerate_fold() {
     let xs = [0, 1, 2, 3, 4, 5];
     let mut it = xs.iter().enumerate();
diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
index 690fd0c2197..91809c9e5fd 100644
--- a/library/core/tests/iter/adapters/flatten.rs
+++ b/library/core/tests/iter/adapters/flatten.rs
@@ -1,5 +1,7 @@
+use core::assert_eq;
 use super::*;
 use core::iter::*;
+use core::num::NonZeroUsize;
 
 #[test]
 fn test_iterator_flatten() {
@@ -61,19 +63,19 @@ fn test_flatten_try_folds() {
 fn test_flatten_advance_by() {
     let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
 
-    it.advance_by(5).unwrap();
+    assert_eq!(it.advance_by(5), Ok(()));
     assert_eq!(it.next(), Some(5));
-    it.advance_by(9).unwrap();
+    assert_eq!(it.advance_by(9), Ok(()));
     assert_eq!(it.next(), Some(15));
-    it.advance_back_by(4).unwrap();
+    assert_eq!(it.advance_back_by(4), Ok(()));
     assert_eq!(it.next_back(), Some(35));
-    it.advance_back_by(9).unwrap();
+    assert_eq!(it.advance_back_by(9), Ok(()));
     assert_eq!(it.next_back(), Some(25));
 
-    assert_eq!(it.advance_by(usize::MAX), Err(9));
-    assert_eq!(it.advance_back_by(usize::MAX), Err(0));
-    it.advance_by(0).unwrap();
-    it.advance_back_by(0).unwrap();
+    assert_eq!(it.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 9).unwrap()));
+    assert_eq!(it.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
+    assert_eq!(it.advance_by(0), Ok(()));
+    assert_eq!(it.advance_back_by(0), Ok(()));
     assert_eq!(it.size_hint(), (0, Some(0)));
 }
 
@@ -174,19 +176,19 @@ fn test_flatten_count() {
     let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
 
     assert_eq!(it.clone().count(), 40);
-    it.advance_by(5).unwrap();
+    assert_eq!(it.advance_by(5), Ok(()));
     assert_eq!(it.clone().count(), 35);
-    it.advance_back_by(5).unwrap();
+    assert_eq!(it.advance_back_by(5), Ok(()));
     assert_eq!(it.clone().count(), 30);
-    it.advance_by(10).unwrap();
+    assert_eq!(it.advance_by(10), Ok(()));
     assert_eq!(it.clone().count(), 20);
-    it.advance_back_by(8).unwrap();
+    assert_eq!(it.advance_back_by(8), Ok(()));
     assert_eq!(it.clone().count(), 12);
-    it.advance_by(4).unwrap();
+    assert_eq!(it.advance_by(4), Ok(()));
     assert_eq!(it.clone().count(), 8);
-    it.advance_back_by(5).unwrap();
+    assert_eq!(it.advance_back_by(5), Ok(()));
     assert_eq!(it.clone().count(), 3);
-    it.advance_by(3).unwrap();
+    assert_eq!(it.advance_by(3), Ok(()));
     assert_eq!(it.clone().count(), 0);
 }
 
@@ -195,18 +197,18 @@ fn test_flatten_last() {
     let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
 
     assert_eq!(it.clone().last(), Some(39));
-    it.advance_by(5).unwrap(); // 5..40
+    assert_eq!(it.advance_by(5), Ok(())); // 5..40
     assert_eq!(it.clone().last(), Some(39));
-    it.advance_back_by(5).unwrap(); // 5..35
+    assert_eq!(it.advance_back_by(5), Ok(())); // 5..35
     assert_eq!(it.clone().last(), Some(34));
-    it.advance_by(10).unwrap(); // 15..35
+    assert_eq!(it.advance_by(10), Ok(())); // 15..35
     assert_eq!(it.clone().last(), Some(34));
-    it.advance_back_by(8).unwrap(); // 15..27
+    assert_eq!(it.advance_back_by(8), Ok(())); // 15..27
     assert_eq!(it.clone().last(), Some(26));
-    it.advance_by(4).unwrap(); // 19..27
+    assert_eq!(it.advance_by(4), Ok(())); // 19..27
     assert_eq!(it.clone().last(), Some(26));
-    it.advance_back_by(5).unwrap(); // 19..22
+    assert_eq!(it.advance_back_by(5), Ok(())); // 19..22
     assert_eq!(it.clone().last(), Some(21));
-    it.advance_by(3).unwrap(); // 22..22
+    assert_eq!(it.advance_by(3), Ok(())); // 22..22
     assert_eq!(it.clone().last(), None);
 }
diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs
index 754641834e8..e3e88a84fad 100644
--- a/library/core/tests/iter/adapters/skip.rs
+++ b/library/core/tests/iter/adapters/skip.rs
@@ -1,4 +1,5 @@
 use core::iter::*;
+use core::num::NonZeroUsize;
 
 use super::Unfuse;
 
@@ -74,11 +75,14 @@ fn test_iterator_skip_nth() {
 #[test]
 fn test_skip_advance_by() {
     assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
-    assert_eq!((0..0).skip(10).advance_by(1), Err(0));
-    assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1));
-    assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(()));
-
-    assert_eq!((0..2).skip(1).advance_back_by(10), Err(1));
+    assert_eq!((0..0).skip(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!(
+        (0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5),
+        Err(NonZeroUsize::new(usize::MAX - 16).unwrap())
+    );
+    assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(()));
+
+    assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
     assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
 }
 
diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs
index 3e26b43a2ed..3cad47c06de 100644
--- a/library/core/tests/iter/adapters/take.rs
+++ b/library/core/tests/iter/adapters/take.rs
@@ -1,4 +1,5 @@
 use core::iter::*;
+use core::num::NonZeroUsize;
 
 #[test]
 fn test_iterator_take() {
@@ -78,21 +79,21 @@ fn test_take_advance_by() {
     let mut take = (0..10).take(3);
     assert_eq!(take.advance_by(2), Ok(()));
     assert_eq!(take.next(), Some(2));
-    assert_eq!(take.advance_by(1), Err(0));
+    assert_eq!(take.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
 
     assert_eq!((0..0).take(10).advance_by(0), Ok(()));
-    assert_eq!((0..0).take(10).advance_by(1), Err(0));
-    assert_eq!((0..10).take(4).advance_by(5), Err(4));
+    assert_eq!((0..0).take(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!((0..10).take(4).advance_by(5), Err(NonZeroUsize::new(1).unwrap()));
 
     let mut take = (0..10).take(3);
     assert_eq!(take.advance_back_by(2), Ok(()));
     assert_eq!(take.next(), Some(0));
-    assert_eq!(take.advance_back_by(1), Err(0));
+    assert_eq!(take.advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
 
-    assert_eq!((0..2).take(1).advance_back_by(10), Err(1));
-    assert_eq!((0..0).take(1).advance_back_by(1), Err(0));
+    assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
+    assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
     assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
-    assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100));
+    assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 100).unwrap()));
 }
 
 #[test]
diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs
index 0f91ffe2dfc..0a77ecddb84 100644
--- a/library/core/tests/iter/range.rs
+++ b/library/core/tests/iter/range.rs
@@ -1,3 +1,4 @@
+use core::num::NonZeroUsize;
 use super::*;
 
 #[test]
@@ -287,25 +288,25 @@ fn test_range_step() {
 #[test]
 fn test_range_advance_by() {
     let mut r = 0..usize::MAX;
-    r.advance_by(0).unwrap();
-    r.advance_back_by(0).unwrap();
+    assert_eq!(Ok(()), r.advance_by(0));
+    assert_eq!(Ok(()), r.advance_back_by(0));
 
     assert_eq!(r.len(), usize::MAX);
 
-    r.advance_by(1).unwrap();
-    r.advance_back_by(1).unwrap();
+    assert_eq!(Ok(()), r.advance_by(1));
+    assert_eq!(Ok(()), r.advance_back_by(1));
 
     assert_eq!((r.start, r.end), (1, usize::MAX - 1));
 
-    assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2));
+    assert_eq!(Err(NonZeroUsize::new(2).unwrap()), r.advance_by(usize::MAX));
 
-    r.advance_by(0).unwrap();
-    r.advance_back_by(0).unwrap();
+    assert_eq!(Ok(()), r.advance_by(0));
+    assert_eq!(Ok(()), r.advance_back_by(0));
 
     let mut r = 0u128..u128::MAX;
 
-    r.advance_by(usize::MAX).unwrap();
-    r.advance_back_by(usize::MAX).unwrap();
+    assert_eq!(Ok(()), r.advance_by(usize::MAX));
+    assert_eq!(Ok(()), r.advance_back_by(usize::MAX));
 
     assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128));
 }
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 62566a9502d..9eebfb1f1f3 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -1,3 +1,5 @@
+use core::num::NonZeroUsize;
+
 /// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
 /// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min`
 /// return the correct element if some of them are equal.
@@ -150,11 +152,11 @@ fn test_iterator_advance_by() {
         let mut iter = v.iter();
         assert_eq!(iter.advance_by(i), Ok(()));
         assert_eq!(iter.next().unwrap(), &v[i]);
-        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+        assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_by(100), Err(v.len()));
+    assert_eq!(v.iter().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -165,11 +167,11 @@ fn test_iterator_advance_back_by() {
         let mut iter = v.iter();
         assert_eq!(iter.advance_back_by(i), Ok(()));
         assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
-        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+        assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
+    assert_eq!(v.iter().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -180,11 +182,11 @@ fn test_iterator_rev_advance_back_by() {
         let mut iter = v.iter().rev();
         assert_eq!(iter.advance_back_by(i), Ok(()));
         assert_eq!(iter.next_back().unwrap(), &v[i]);
-        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+        assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
-    assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
+    assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -424,11 +426,11 @@ fn test_iterator_rev_advance_by() {
         let mut iter = v.iter().rev();
         assert_eq!(iter.advance_by(i), Ok(()));
         assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
-        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+        assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
+    assert_eq!(v.iter().rev().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
 }
 
 #[test]
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 39559cdbb5e..88f54591bb4 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1,6 +1,7 @@
 use core::cell::Cell;
 use core::cmp::Ordering;
 use core::mem::MaybeUninit;
+use core::num::NonZeroUsize;
 use core::result::Result::{Err, Ok};
 use core::slice;
 
@@ -142,20 +143,20 @@ fn test_iterator_advance_by() {
 
     for i in 0..=v.len() {
         let mut iter = v.iter();
-        iter.advance_by(i).unwrap();
+        assert_eq!(iter.advance_by(i), Ok(()));
         assert_eq!(iter.as_slice(), &v[i..]);
     }
 
     let mut iter = v.iter();
-    assert_eq!(iter.advance_by(v.len() + 1), Err(v.len()));
+    assert_eq!(iter.advance_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
     assert_eq!(iter.as_slice(), &[]);
 
     let mut iter = v.iter();
-    iter.advance_by(3).unwrap();
+    assert_eq!(iter.advance_by(3), Ok(()));
     assert_eq!(iter.as_slice(), &v[3..]);
-    iter.advance_by(2).unwrap();
+    assert_eq!(iter.advance_by(2), Ok(()));
     assert_eq!(iter.as_slice(), &[]);
-    iter.advance_by(0).unwrap();
+    assert_eq!(iter.advance_by(0), Ok(()));
 }
 
 #[test]
@@ -164,20 +165,20 @@ fn test_iterator_advance_back_by() {
 
     for i in 0..=v.len() {
         let mut iter = v.iter();
-        iter.advance_back_by(i).unwrap();
+        assert_eq!(iter.advance_back_by(i), Ok(()));
         assert_eq!(iter.as_slice(), &v[..v.len() - i]);
     }
 
     let mut iter = v.iter();
-    assert_eq!(iter.advance_back_by(v.len() + 1), Err(v.len()));
+    assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
     assert_eq!(iter.as_slice(), &[]);
 
     let mut iter = v.iter();
-    iter.advance_back_by(3).unwrap();
+    assert_eq!(iter.advance_back_by(3), Ok(()));
     assert_eq!(iter.as_slice(), &v[..v.len() - 3]);
-    iter.advance_back_by(2).unwrap();
+    assert_eq!(iter.advance_back_by(2), Ok(()));
     assert_eq!(iter.as_slice(), &[]);
-    iter.advance_back_by(0).unwrap();
+    assert_eq!(iter.advance_back_by(0), Ok(()));
 }
 
 #[test]
diff --git a/library/std/build.rs b/library/std/build.rs
index ea879667558..cf708db6f27 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -6,6 +6,9 @@ fn main() {
     if target.contains("freebsd") {
         if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() {
             println!("cargo:rustc-cfg=freebsd12");
+        } else if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() {
+            println!("cargo:rustc-cfg=freebsd12");
+            println!("cargo:rustc-cfg=freebsd13");
         }
     } else if target.contains("linux")
         || target.contains("netbsd")
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 7cc901a7944..7565fbc0d09 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -86,7 +86,12 @@ fn add_to_ancillary_data<T>(
     cmsg_level: libc::c_int,
     cmsg_type: libc::c_int,
 ) -> bool {
-    let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
+    #[cfg(not(target_os = "freebsd"))]
+    let cmsg_size = source.len().checked_mul(size_of::<T>());
+    #[cfg(target_os = "freebsd")]
+    let cmsg_size = Some(unsafe { libc::SOCKCRED2SIZE(1) });
+
+    let source_len = if let Some(source_len) = cmsg_size {
         if let Ok(source_len) = u32::try_from(source_len) {
             source_len
         } else {
@@ -178,7 +183,13 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
     }
 }
 
-#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
+#[cfg(all(
+    doc,
+    not(target_os = "android"),
+    not(target_os = "linux"),
+    not(target_os = "netbsd"),
+    not(target_os = "freebsd")
+))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 #[derive(Clone)]
 pub struct SocketCred(());
@@ -194,6 +205,11 @@ pub struct SocketCred(libc::ucred);
 #[derive(Clone)]
 pub struct SocketCred(libc::sockcred);
 
+#[cfg(target_os = "freebsd")]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(libc::sockcred2);
+
 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
 #[cfg(any(target_os = "android", target_os = "linux"))]
 impl SocketCred {
@@ -246,6 +262,66 @@ impl SocketCred {
     }
 }
 
+#[cfg(target_os = "freebsd")]
+impl SocketCred {
+    /// Create a Unix credential struct.
+    ///
+    /// PID, UID and GID is set to 0.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    #[must_use]
+    pub fn new() -> SocketCred {
+        SocketCred(libc::sockcred2 {
+            sc_version: 0,
+            sc_pid: 0,
+            sc_uid: 0,
+            sc_euid: 0,
+            sc_gid: 0,
+            sc_egid: 0,
+            sc_ngroups: 0,
+            sc_groups: [0; 1],
+        })
+    }
+
+    /// Set the PID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_pid(&mut self, pid: libc::pid_t) {
+        self.0.sc_pid = pid;
+    }
+
+    /// Get the current PID.
+    #[must_use]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn get_pid(&self) -> libc::pid_t {
+        self.0.sc_pid
+    }
+
+    /// Set the UID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_uid(&mut self, uid: libc::uid_t) {
+        self.0.sc_euid = uid;
+    }
+
+    /// Get the current UID.
+    #[must_use]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn get_uid(&self) -> libc::uid_t {
+        self.0.sc_euid
+    }
+
+    /// Set the GID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_gid(&mut self, gid: libc::gid_t) {
+        self.0.sc_egid = gid;
+    }
+
+    /// Get the current GID.
+    #[must_use]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn get_gid(&self) -> libc::gid_t {
+        self.0.sc_egid
+    }
+}
+
 #[cfg(target_os = "netbsd")]
 impl SocketCred {
     /// Create a Unix credential struct.
@@ -271,6 +347,7 @@ impl SocketCred {
     }
 
     /// Get the current PID.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn get_pid(&self) -> libc::pid_t {
         self.0.sc_pid
@@ -283,6 +360,7 @@ impl SocketCred {
     }
 
     /// Get the current UID.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn get_uid(&self) -> libc::uid_t {
         self.0.sc_uid
@@ -295,6 +373,7 @@ impl SocketCred {
     }
 
     /// Get the current GID.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn get_gid(&self) -> libc::gid_t {
         self.0.sc_gid
@@ -316,7 +395,13 @@ impl<'a> Iterator for ScmRights<'a> {
     }
 }
 
-#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
+#[cfg(all(
+    doc,
+    not(target_os = "android"),
+    not(target_os = "linux"),
+    not(target_os = "netbsd"),
+    not(target_os = "freebsd")
+))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
 
@@ -327,11 +412,21 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
 
+#[cfg(target_os = "freebsd")]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred2>);
+
 #[cfg(target_os = "netbsd")]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
 
-#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+#[cfg(any(
+    doc,
+    target_os = "android",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "freebsd"
+))]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 impl<'a> Iterator for ScmCredentials<'a> {
     type Item = SocketCred;
@@ -353,7 +448,13 @@ pub enum AncillaryError {
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub enum AncillaryData<'a> {
     ScmRights(ScmRights<'a>),
-    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+    #[cfg(any(
+        doc,
+        target_os = "android",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "freebsd"
+    ))]
     ScmCredentials(ScmCredentials<'a>),
 }
 
@@ -376,7 +477,13 @@ impl<'a> AncillaryData<'a> {
     ///
     /// `data` must contain a valid control message and the control message must be type of
     /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
-    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+    #[cfg(any(
+        doc,
+        target_os = "android",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "freebsd"
+    ))]
     unsafe fn as_credentials(data: &'a [u8]) -> Self {
         let ancillary_data_iter = AncillaryDataIter::new(data);
         let scm_credentials = ScmCredentials(ancillary_data_iter);
@@ -395,6 +502,8 @@ impl<'a> AncillaryData<'a> {
                     libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
                     #[cfg(any(target_os = "android", target_os = "linux",))]
                     libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
+                    #[cfg(target_os = "freebsd")]
+                    libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
                     #[cfg(target_os = "netbsd")]
                     libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
                     cmsg_type => {
@@ -603,12 +712,18 @@ impl<'a> SocketAncillary<'a> {
 
     /// Add credentials to the ancillary data.
     ///
-    /// The function returns `true` if there was enough space in the buffer.
-    /// If there was not enough space then no credentials was appended.
+    /// The function returns `true` if there is enough space in the buffer.
+    /// If there is not enough space then no credentials will be appended.
     /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
-    /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
-    ///
-    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+    /// and type `SCM_CREDENTIALS`, `SCM_CREDS`, or `SCM_CREDS2`.
+    ///
+    #[cfg(any(
+        doc,
+        target_os = "android",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "freebsd"
+    ))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
         self.truncated = false;
@@ -617,8 +732,10 @@ impl<'a> SocketAncillary<'a> {
             &mut self.length,
             creds,
             libc::SOL_SOCKET,
-            #[cfg(not(target_os = "netbsd"))]
+            #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
             libc::SCM_CREDENTIALS,
+            #[cfg(target_os = "freebsd")]
+            libc::SCM_CREDS2,
             #[cfg(target_os = "netbsd")]
             libc::SCM_CREDS,
         )
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index e64569758a0..41cdcda4613 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -808,8 +808,24 @@ impl UnixDatagram {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(
+            target_os = "android",
+            target_os = "linux",
+            target_os = "netbsd",
+            target_os = "freebsd",
+        ),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(
+            target_os = "android",
+            target_os = "linux",
+            target_os = "netbsd",
+            target_os = "freebsd"
+        )),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::UnixDatagram;
     ///
@@ -819,7 +835,13 @@ impl UnixDatagram {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+    #[cfg(any(
+        doc,
+        target_os = "android",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "freebsd"
+    ))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
         self.0.set_passcred(passcred)
@@ -831,7 +853,13 @@ impl UnixDatagram {
     /// Get the socket option `SO_PASSCRED`.
     ///
     /// [`set_passcred`]: UnixDatagram::set_passcred
-    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+    #[cfg(any(
+        doc,
+        target_os = "android",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "freebsd"
+    ))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn passcred(&self) -> io::Result<bool> {
         self.0.passcred()
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 65cb4ae07a5..5aa3fb92576 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -397,8 +397,24 @@ impl UnixStream {
     ///
     /// # Examples
     ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    #[cfg_attr(
+        any(
+            target_os = "android",
+            target_os = "linux",
+            target_os = "netbsd",
+            target_os = "freebsd"
+        ),
+        doc = "```no_run"
+    )]
+    #[cfg_attr(
+        not(any(
+            target_os = "android",
+            target_os = "linux",
+            target_os = "netbsd",
+            target_os = "freebsd"
+        )),
+        doc = "```ignore"
+    )]
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::UnixStream;
     ///
@@ -408,7 +424,13 @@ impl UnixStream {
     ///     Ok(())
     /// }
     /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+    #[cfg(any(
+        doc,
+        target_os = "android",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "freebsd"
+    ))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
         self.0.set_passcred(passcred)
@@ -420,7 +442,13 @@ impl UnixStream {
     /// Get the socket option `SO_PASSCRED`.
     ///
     /// [`set_passcred`]: UnixStream::set_passcred
-    #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+    #[cfg(any(
+        doc,
+        target_os = "android",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "freebsd"
+    ))]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn passcred(&self) -> io::Result<bool> {
         self.0.passcred()
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index f8c29a6d3a1..39f10c50dc4 100644
--- a/library/std/src/os/unix/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
@@ -646,7 +646,7 @@ fn test_send_vectored_fds_unix_stream() {
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux",))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
 #[test]
 fn test_send_vectored_with_ancillary_to_unix_datagram() {
     fn getpid() -> libc::pid_t {
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index f84240d268f..573bfa6587e 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -443,6 +443,17 @@ impl Socket {
         Ok(passcred != 0)
     }
 
+    #[cfg(target_os = "freebsd")]
+    pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
+        setsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT, passcred as libc::c_int)
+    }
+
+    #[cfg(target_os = "freebsd")]
+    pub fn passcred(&self) -> io::Result<bool> {
+        let passcred: libc::c_int = getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)?;
+        Ok(passcred != 0)
+    }
+
     #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         let mut nonblocking = nonblocking as libc::c_int;
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 20b92b294fe..ed103a9a51c 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -125,6 +125,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
     (Some(Mode::Std), "no_rc", None),
     (Some(Mode::Std), "no_sync", None),
     (Some(Mode::Std), "freebsd12", None),
+    (Some(Mode::Std), "freebsd13", None),
     (Some(Mode::Std), "backtrace_in_libstd", None),
     /* Extra values not defined in the built-in targets yet, but used in std */
     (Some(Mode::Std), "target_env", Some(&["libnx"])),
diff --git a/tests/ui/codegen/mono-impossible-2.rs b/tests/ui/codegen/mono-impossible-2.rs
new file mode 100644
index 00000000000..21eb2c9b2f2
--- /dev/null
+++ b/tests/ui/codegen/mono-impossible-2.rs
@@ -0,0 +1,19 @@
+//compile-flags: --crate-type=lib -Clink-dead-code=on
+// build-pass
+
+// Make sure that we don't monomorphize the impossible method `<() as Visit>::visit`,
+// which does not hold under a reveal-all param env.
+
+pub trait Visit {
+    fn visit() {}
+}
+
+pub trait Array {
+    type Element;
+}
+
+impl<'a> Visit for () where (): Array<Element = &'a ()> {}
+
+impl Array for () {
+    type Element = ();
+}
diff --git a/tests/ui/generic-associated-types/gat-bounds-normalize-pred.rs b/tests/ui/generic-associated-types/gat-bounds-normalize-pred.rs
new file mode 100644
index 00000000000..b43f982283b
--- /dev/null
+++ b/tests/ui/generic-associated-types/gat-bounds-normalize-pred.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+trait Foo {
+    type Assoc<T>: PartialEq<Self::Assoc<i32>>;
+}
+
+impl Foo for () {
+    type Assoc<T> = Wrapper<T>;
+}
+
+struct Wrapper<T>(T);
+
+impl<T> PartialEq<Wrapper<i32>> for Wrapper<T> {
+    fn eq(&self, _other: &Wrapper<i32>) -> bool { true }
+}
+
+fn main() {}
diff --git a/tests/ui/implied-bounds/ice-unbound-region-vars.rs b/tests/ui/implied-bounds/ice-unbound-region-vars.rs
new file mode 100644
index 00000000000..9e1e3feaeec
--- /dev/null
+++ b/tests/ui/implied-bounds/ice-unbound-region-vars.rs
@@ -0,0 +1,24 @@
+// Because of #109628, we can have unbounded region vars in implied bounds.
+// Make sure we don't ICE in this case!
+//
+// check-pass
+
+pub trait MapAccess {
+    type Error;
+    fn next_key_seed(&mut self) -> Option<Self::Error>;
+}
+
+struct Access<'a> {
+    _marker: std::marker::PhantomData<&'a ()>,
+}
+
+// implied_bounds(Option<Self::Error>) = ['?1: 'a, ]
+// where '?1 is a fresh region var.
+impl<'a, 'b: 'a> MapAccess for Access<'a> {
+    type Error = ();
+    fn next_key_seed(&mut self) -> Option<Self::Error> {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/implied-bounds/normalization.rs b/tests/ui/implied-bounds/normalization.rs
new file mode 100644
index 00000000000..f776fc98a9e
--- /dev/null
+++ b/tests/ui/implied-bounds/normalization.rs
@@ -0,0 +1,58 @@
+// Test that we get implied bounds from complex projections after normalization.
+
+// check-pass
+
+// implementations wil ensure that
+// WF(<T as Combine<'a>>::Ty) implies T: 'a
+trait Combine<'a> {
+    type Ty;
+}
+
+impl<'a, T: 'a> Combine<'a> for Box<T> {
+    type Ty = &'a T;
+}
+
+// ======= Wrappers ======
+
+// normalizes to a projection
+struct WrapA<T>(T);
+impl<'a, T> Combine<'a> for WrapA<T>
+where
+    T: Combine<'a>,
+{
+    type Ty = T::Ty;
+}
+
+// <WrapB<T> as Combine<'a>>::Ty normalizes to a type variable ?X
+// with constraint `<T as Combine<'a>>::Ty == ?X`
+struct WrapB<T>(T);
+impl<'a, X, T> Combine<'a> for WrapB<T>
+where
+    T: Combine<'a, Ty = X>,
+{
+    type Ty = X;
+}
+
+// <WrapC<T> as Combine<'a>>::Ty normalizes to `&'a &'?x ()`
+// with constraint `<T as Combine<'a>>::Ty == &'a &'?x ()`
+struct WrapC<T>(T);
+impl<'a, 'x: 'a, T> Combine<'a> for WrapC<T>
+where
+    T: Combine<'a, Ty = &'a &'x ()>,
+{
+    type Ty = &'a &'x ();
+}
+
+//==== Test implied bounds ======
+
+fn test_wrap<'a, 'b, 'c1, 'c2, A, B>(
+    _: <WrapA<Box<A>> as Combine<'a>>::Ty,        // normalized: &'a A
+    _: <WrapB<Box<B>> as Combine<'b>>::Ty,        // normalized: &'b B
+    _: <WrapC<Box<&'c1 ()>> as Combine<'c2>>::Ty, // normalized: &'c2 &'c1 ()
+) {
+    None::<&'a A>;
+    None::<&'b B>;
+    None::<&'c2 &'c1 ()>;
+}
+
+fn main() {}
diff --git a/tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs b/tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs
index 62aa22d41ed..b9f1de7ec13 100644
--- a/tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs
+++ b/tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs
@@ -1,4 +1,8 @@
-// check-pass
+// known-bug: #89515
+//
+// The trait solver cannot deal with ambiguous marker trait impls
+// if there are lifetimes involved. As we must not special-case any
+// regions this does not work, even with 'static
 #![feature(marker_trait_attr)]
 
 #[marker]
diff --git a/tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.stderr b/tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.stderr
new file mode 100644
index 00000000000..fe4de540b51
--- /dev/null
+++ b/tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.stderr
@@ -0,0 +1,31 @@
+error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
+  --> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:17
+   |
+LL | impl Marker for &'static () {}
+   |                 ^^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `&'static (): Marker` found
+  --> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
+   |
+LL | impl Marker for &'static () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Marker for &'static () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
+  --> $DIR/overlap-marker-trait-with-static-lifetime.rs:12:17
+   |
+LL | impl Marker for &'static () {}
+   |                 ^^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `&'static (): Marker` found
+  --> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
+   |
+LL | impl Marker for &'static () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Marker for &'static () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs b/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs
index a8f3db5f5b2..97a814f51ee 100644
--- a/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs
+++ b/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.rs
@@ -1,9 +1,17 @@
-// check-pass
+// known-bug: #109481
+//
+// While the `T: Copy` is always applicable when checking
+// that the impl `impl<T: Copy> F for T {}` is well formed,
+// the old trait solver can only approximate this by checking
+// that there are no inference variables in the obligation and
+// no region constraints in the evaluation result.
+//
+// Because of this we end up with ambiguity here.
 #![feature(marker_trait_attr)]
 
 #[marker]
 pub trait F {}
-impl<T> F for T where T: Copy {}
-impl<T> F for T where T: 'static {}
+impl<T: Copy> F for T {}
+impl<T: 'static> F for T {}
 
 fn main() {}
diff --git a/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr b/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr
new file mode 100644
index 00000000000..e713d1451cf
--- /dev/null
+++ b/tests/ui/marker_trait_attr/overlapping-impl-1-modulo-regions.stderr
@@ -0,0 +1,14 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/overlapping-impl-1-modulo-regions.rs:14:21
+   |
+LL | impl<T: Copy> F for T {}
+   |                     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<T: Copy + 'static> F for T {}
+   |              +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.