about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-20 09:23:09 +0000
committerbors <bors@rust-lang.org>2024-01-20 09:23:09 +0000
commit314384b5fb21f3c163f2b871ddceabdd88319958 (patch)
treef84abd66003884096b2174877c4cc544e1b09062
parent5378c1cf0713ab224eb6431327c28522182feb69 (diff)
parentbb816e67b46fe5f1c520a6ecfadfc6a393b5f84f (diff)
Auto merge of #120157 - matthiaskrgr:rollup-f0p3wkk, r=matthiaskrgr
Rollup of 10 pull requests

Successful merges:

 - #103730 (Added NonZeroXxx::from_mut(_unchecked)?)
 - #113142 (optimize EscapeAscii's Display  and CStr's Debug)
 - #118799 (Stabilize single-field offset_of)
 - #119613 (Expose Obligations created during type inference.)
 - #119752 (Avoid ICEs in trait names without `dyn`)
 - #120132 (Teach tidy about line/col information for malformed features)
 - #120135 (SMIR: Make the remaining "private" fields actually private)
 - #120148 (`single_use_lifetimes`: Don't suggest deleting lifetimes with bounds)
 - #120150 (Stabilize `round_ties_even`)
 - #120155 (Don't use `ReErased` to detect type test promotion failed)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs14
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0795.md4
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs24
-rw-r--r--compiler/rustc_infer/src/infer/at.rs1
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs16
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs136
-rw-r--r--compiler/stable_mir/src/ty.rs4
-rw-r--r--library/core/benches/ascii.rs28
-rw-r--r--library/core/src/ascii.rs11
-rw-r--r--library/core/src/iter/adapters/flatten.rs8
-rw-r--r--library/core/src/iter/adapters/fuse.rs4
-rw-r--r--library/core/src/iter/adapters/map.rs4
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/mem/mod.rs14
-rw-r--r--library/core/src/num/nonzero.rs33
-rw-r--r--library/core/src/slice/ascii.rs41
-rw-r--r--library/core/tests/ascii.rs10
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/std/src/f32.rs4
-rw-r--r--library/std/src/f64.rs4
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--src/tools/miri/src/lib.rs1
-rw-r--r--src/tools/miri/tests/pass/float.rs1
-rw-r--r--src/tools/tidy/src/features.rs32
-rw-r--r--tests/mir-opt/const_prop/offset_of.rs2
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.rs2
-rw-r--r--tests/pretty/offset_of.rs1
-rw-r--r--tests/ui/feature-gates/feature-gate-offset-of-enum.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-offset-of-enum.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-offset-of-nested.rs28
-rw-r--r--tests/ui/feature-gates/feature-gate-offset-of-nested.stderr60
-rw-r--r--tests/ui/layout/issue-112048-unsizing-niche.rs1
-rw-r--r--tests/ui/lint/dead-code/offset-of-correct-param-env.rs2
-rw-r--r--tests/ui/lint/dead-code/offset-of.rs2
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning-2.rs9
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning-2.stderr50
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning-3.rs17
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning-3.stderr148
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning.rs6
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning.stderr29
-rw-r--r--tests/ui/offset-of/offset-of-arg-count.rs2
-rw-r--r--tests/ui/offset-of/offset-of-arg-count.stderr14
-rw-r--r--tests/ui/offset-of/offset-of-dst-field.rs2
-rw-r--r--tests/ui/offset-of/offset-of-enum.rs2
-rw-r--r--tests/ui/offset-of/offset-of-inference.rs2
-rw-r--r--tests/ui/offset-of/offset-of-inference.stderr2
-rw-r--r--tests/ui/offset-of/offset-of-must-use.rs1
-rw-r--r--tests/ui/offset-of/offset-of-must-use.stderr4
-rw-r--r--tests/ui/offset-of/offset-of-output-type.rs2
-rw-r--r--tests/ui/offset-of/offset-of-output-type.stderr12
-rw-r--r--tests/ui/offset-of/offset-of-private.rs2
-rw-r--r--tests/ui/offset-of/offset-of-self.rs2
-rw-r--r--tests/ui/offset-of/offset-of-tuple-nested.rs2
-rw-r--r--tests/ui/offset-of/offset-of-tuple.rs2
-rw-r--r--tests/ui/offset-of/offset-of-unsized.rs2
-rw-r--r--tests/ui/offset-of/offset-of-unstable-with-feature.rs2
-rw-r--r--tests/ui/offset-of/offset-of-unstable.rs2
-rw-r--r--tests/ui/single-use-lifetime/issue-117965.rs18
-rw-r--r--tests/ui/single-use-lifetime/issue-117965.stderr16
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs23
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr168
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs17
-rw-r--r--tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr65
69 files changed, 1032 insertions, 155 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index cbf01feae06..89b203f80a4 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -18,7 +18,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
+use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::Span;
 
@@ -1145,6 +1145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
 
         let ty = ty.fold_with(&mut OpaqueFolder { tcx });
+        let mut failed = false;
 
         let ty = tcx.fold_regions(ty, |r, _depth| {
             let r_vid = self.to_region_vid(r);
@@ -1160,15 +1161,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
                 .find(|&u_r| self.eval_equal(u_r, r_vid))
                 .map(|u_r| ty::Region::new_var(tcx, u_r))
-                // In the case of a failure, use `ReErased`. We will eventually
-                // return `None` in this case.
-                .unwrap_or(tcx.lifetimes.re_erased)
+                // In case we could not find a named region to map to,
+                // we will return `None` below.
+                .unwrap_or_else(|| {
+                    failed = true;
+                    r
+                })
         });
 
         debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
 
         // This will be true if we failed to promote some region.
-        if ty.has_erased_regions() {
+        if failed {
             return None;
         }
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0795.md b/compiler/rustc_error_codes/src/error_codes/E0795.md
index 20f51441c29..ad77d72c913 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0795.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0795.md
@@ -3,7 +3,7 @@ Invalid argument for the `offset_of!` macro.
 Erroneous code example:
 
 ```compile_fail,E0795
-#![feature(offset_of, offset_of_enum)]
+#![feature(offset_of_enum, offset_of_nested)]
 
 let x = std::mem::offset_of!(Option<u8>, Some);
 ```
@@ -16,7 +16,7 @@ The offset of the contained `u8` in the `Option<u8>` can be found by specifying
 the field name `0`:
 
 ```
-#![feature(offset_of, offset_of_enum)]
+#![feature(offset_of_enum, offset_of_nested)]
 
 let x: usize = std::mem::offset_of!(Option<u8>, Some.0);
 ```
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 2f2b551e6ec..371b651f5e8 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -549,7 +549,9 @@ declare_features! (
     /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
     (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)),
     /// Allows using enums in offset_of!
-    (unstable, offset_of_enum, "1.75.0", Some(106655)),
+    (unstable, offset_of_enum, "1.75.0", Some(120141)),
+    /// Allows using multiple nested field accesses in offset_of!
+    (unstable, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(120140)),
     /// Allows using `#[optimize(X)]`.
     (unstable, optimize_attribute, "1.34.0", Some(54882)),
     /// Allows macro attributes on expressions, statements and non-inline modules.
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index 3761d529517..b5f42e98127 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -78,14 +78,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool {
         let tcx = self.tcx();
         let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
-        let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. })
-        | hir::Node::TraitItem(hir::TraitItem {
-            kind: hir::TraitItemKind::Fn(sig, _),
-            generics,
-            ..
-        })) = tcx.hir_node_by_def_id(parent_id)
-        else {
-            return false;
+        let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
+                (sig, generics, None)
+            }
+            hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Fn(sig, _),
+                generics,
+                owner_id,
+                ..
+            }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
+            _ => return false,
         };
         let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
             return false;
@@ -94,6 +97,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let is_object_safe = match self_ty.kind {
             hir::TyKind::TraitObject(objects, ..) => {
                 objects.iter().all(|o| match o.trait_ref.path.res {
+                    Res::Def(DefKind::Trait, id) if Some(id) == owner => {
+                        // When we're dealing with a recursive trait, we don't want to downgrade
+                        // the error, so we consider them to be object safe always. (#119652)
+                        true
+                    }
                     Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
                     _ => false,
                 })
@@ -122,7 +130,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ],
                     Applicability::MachineApplicable,
                 );
-            } else {
+            } else if diag.is_error() {
                 // We'll emit the object safety error already, with a structured suggestion.
                 diag.downgrade_to_delayed_bug();
             }
@@ -148,8 +156,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             if !is_object_safe {
                 diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
-                // We'll emit the object safety error already, with a structured suggestion.
-                diag.downgrade_to_delayed_bug();
+                if diag.is_error() {
+                    // We'll emit the object safety error already, with a structured suggestion.
+                    diag.downgrade_to_delayed_bug();
+                }
             } else {
                 let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
                     // There are more than one trait bound, we need surrounding parentheses.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 4b1ad28f094..33d7ba6268a 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -3246,6 +3246,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let container = self.to_ty(container).normalized;
 
+        if let Some(ident_2) = fields.get(1)
+            && !self.tcx.features().offset_of_nested
+        {
+            rustc_session::parse::feature_err(
+                &self.tcx.sess,
+                sym::offset_of_nested,
+                ident_2.span,
+                "only a single ident or integer is stable as the field in offset_of",
+            )
+            .emit();
+        }
+
         let mut field_indices = Vec::with_capacity(fields.len());
         let mut current_container = container;
         let mut fields = fields.into_iter();
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 67c35d717a1..80467ca9381 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -60,6 +60,7 @@ use rustc_hir::{HirIdMap, Node};
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_hir_analysis::check::check_abi;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::ObligationInspector;
 use rustc_middle::query::Providers;
 use rustc_middle::traits;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -139,7 +140,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef
 
 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
     let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity();
-    typeck_with_fallback(tcx, def_id, fallback)
+    typeck_with_fallback(tcx, def_id, fallback, None)
 }
 
 /// Used only to get `TypeckResults` for type inference during error recovery.
@@ -149,14 +150,28 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
         let span = tcx.hir().span(tcx.local_def_id_to_hir_id(def_id));
         Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used")
     };
-    typeck_with_fallback(tcx, def_id, fallback)
+    typeck_with_fallback(tcx, def_id, fallback, None)
 }
 
-#[instrument(level = "debug", skip(tcx, fallback), ret)]
+/// Same as `typeck` but `inspect` is invoked on evaluation of each root obligation.
+/// Inspecting obligations only works with the new trait solver.
+/// This function is *only to be used* by external tools, it should not be
+/// called from within rustc. Note, this is not a query, and thus is not cached.
+pub fn inspect_typeck<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    inspect: ObligationInspector<'tcx>,
+) -> &'tcx ty::TypeckResults<'tcx> {
+    let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity();
+    typeck_with_fallback(tcx, def_id, fallback, Some(inspect))
+}
+
+#[instrument(level = "debug", skip(tcx, fallback, inspector), ret)]
 fn typeck_with_fallback<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     fallback: impl Fn() -> Ty<'tcx> + 'tcx,
+    inspector: Option<ObligationInspector<'tcx>>,
 ) -> &'tcx ty::TypeckResults<'tcx> {
     // Closures' typeck results come from their outermost function,
     // as they are part of the same "inference environment".
@@ -178,6 +193,9 @@ fn typeck_with_fallback<'tcx>(
     let param_env = tcx.param_env(def_id);
 
     let inh = Inherited::new(tcx, def_id);
+    if let Some(inspector) = inspector {
+        inh.infcx.attach_obligation_inspector(inspector);
+    }
     let mut fcx = FnCtxt::new(&inh, param_env, def_id);
 
     if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index e60e3ffeaa7..0f1af81d9f0 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -90,6 +90,7 @@ impl<'tcx> InferCtxt<'tcx> {
             universe: self.universe.clone(),
             intercrate,
             next_trait_solver: self.next_trait_solver,
+            obligation_inspector: self.obligation_inspector.clone(),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 002aad19c49..1eab8575fc0 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -13,7 +13,9 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
 use self::opaque_types::OpaqueTypeStorage;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
 
-use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt};
+use crate::traits::{
+    self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, TraitEngineExt,
+};
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -334,6 +336,8 @@ pub struct InferCtxt<'tcx> {
     pub intercrate: bool,
 
     next_trait_solver: bool,
+
+    pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>,
 }
 
 impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
@@ -708,6 +712,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             universe: Cell::new(ty::UniverseIndex::ROOT),
             intercrate,
             next_trait_solver,
+            obligation_inspector: Cell::new(None),
         }
     }
 }
@@ -1718,6 +1723,15 @@ impl<'tcx> InferCtxt<'tcx> {
             }
         }
     }
+
+    /// Attach a callback to be invoked on each root obligation evaluated in the new trait solver.
+    pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) {
+        debug_assert!(
+            self.obligation_inspector.get().is_none(),
+            "shouldn't override a set obligation inspector"
+        );
+        self.obligation_inspector.set(Some(inspector));
+    }
 }
 
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index fdae093aac8..72ec07375ac 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -13,12 +13,15 @@ use std::hash::{Hash, Hasher};
 
 use hir::def_id::LocalDefId;
 use rustc_hir as hir;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::solve::Certainty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt};
 use rustc_span::Span;
 
 pub use self::ImplSource::*;
 pub use self::SelectionError::*;
+use crate::infer::InferCtxt;
 
 pub use self::engine::{TraitEngine, TraitEngineExt};
 pub use self::project::MismatchedProjectionTypes;
@@ -116,6 +119,11 @@ pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
 
 pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>;
 
+/// A callback that can be provided to `inspect_typeck`. Invoked on evaluation
+/// of root obligations.
+pub type ObligationInspector<'tcx> =
+    fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result<Certainty, NoSolution>);
+
 pub struct FulfillmentError<'tcx> {
     pub obligation: PredicateObligation<'tcx>,
     pub code: FulfillmentErrorCode<'tcx>,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 5a95f2083f6..abb0a7a465a 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2567,8 +2567,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     debug!(?param.ident, ?param.ident.span, ?use_span);
 
                     let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
+                    let deletion_span =
+                        if param.bounds.is_empty() { deletion_span() } else { None };
 
-                    let deletion_span = deletion_span();
                     self.r.lint_buffer.buffer_lint_with_diagnostic(
                         lint::builtin::SINGLE_USE_LIFETIMES,
                         param.id,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 44795022cba..7b0138d50ba 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1153,6 +1153,7 @@ symbols! {
         offset,
         offset_of,
         offset_of_enum,
+        offset_of_nested,
         ok_or_else,
         omit_gdb_pretty_printer_section,
         on,
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index c847425ebf4..f08622816ec 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 
 use super::eval_ctxt::GenerateProofTree;
-use super::{Certainty, InferCtxtEvalExt};
+use super::{Certainty, Goal, InferCtxtEvalExt};
 
 /// A trait engine using the new trait solver.
 ///
@@ -43,6 +43,21 @@ impl<'tcx> FulfillmentCtxt<'tcx> {
         );
         FulfillmentCtxt { obligations: Vec::new(), usable_in_snapshot: infcx.num_open_snapshots() }
     }
+
+    fn inspect_evaluated_obligation(
+        &self,
+        infcx: &InferCtxt<'tcx>,
+        obligation: &PredicateObligation<'tcx>,
+        result: &Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
+    ) {
+        if let Some(inspector) = infcx.obligation_inspector.get() {
+            let result = match result {
+                Ok((_, c, _)) => Ok(*c),
+                Err(NoSolution) => Err(NoSolution),
+            };
+            (inspector)(infcx, &obligation, result);
+        }
+    }
 }
 
 impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
@@ -100,65 +115,66 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
             let mut has_changed = false;
             for obligation in mem::take(&mut self.obligations) {
                 let goal = obligation.clone().into();
-                let (changed, certainty, nested_goals) =
-                    match infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0 {
-                        Ok(result) => result,
-                        Err(NoSolution) => {
-                            errors.push(FulfillmentError {
-                                obligation: obligation.clone(),
-                                code: match goal.predicate.kind().skip_binder() {
-                                    ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
-                                        FulfillmentErrorCode::ProjectionError(
-                                            // FIXME: This could be a `Sorts` if the term is a type
-                                            MismatchedProjectionTypes { err: TypeError::Mismatch },
-                                        )
-                                    }
-                                    ty::PredicateKind::NormalizesTo(..) => {
-                                        FulfillmentErrorCode::ProjectionError(
-                                            MismatchedProjectionTypes { err: TypeError::Mismatch },
-                                        )
-                                    }
-                                    ty::PredicateKind::AliasRelate(_, _, _) => {
-                                        FulfillmentErrorCode::ProjectionError(
-                                            MismatchedProjectionTypes { err: TypeError::Mismatch },
-                                        )
-                                    }
-                                    ty::PredicateKind::Subtype(pred) => {
-                                        let (a, b) = infcx.instantiate_binder_with_placeholders(
-                                            goal.predicate.kind().rebind((pred.a, pred.b)),
-                                        );
-                                        let expected_found = ExpectedFound::new(true, a, b);
-                                        FulfillmentErrorCode::SubtypeError(
-                                            expected_found,
-                                            TypeError::Sorts(expected_found),
-                                        )
-                                    }
-                                    ty::PredicateKind::Coerce(pred) => {
-                                        let (a, b) = infcx.instantiate_binder_with_placeholders(
-                                            goal.predicate.kind().rebind((pred.a, pred.b)),
-                                        );
-                                        let expected_found = ExpectedFound::new(false, a, b);
-                                        FulfillmentErrorCode::SubtypeError(
-                                            expected_found,
-                                            TypeError::Sorts(expected_found),
-                                        )
-                                    }
-                                    ty::PredicateKind::Clause(_)
-                                    | ty::PredicateKind::ObjectSafe(_)
-                                    | ty::PredicateKind::Ambiguous => {
-                                        FulfillmentErrorCode::SelectionError(
-                                            SelectionError::Unimplemented,
-                                        )
-                                    }
-                                    ty::PredicateKind::ConstEquate(..) => {
-                                        bug!("unexpected goal: {goal:?}")
-                                    }
-                                },
-                                root_obligation: obligation,
-                            });
-                            continue;
-                        }
-                    };
+                let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0;
+                self.inspect_evaluated_obligation(infcx, &obligation, &result);
+                let (changed, certainty, nested_goals) = match result {
+                    Ok(result) => result,
+                    Err(NoSolution) => {
+                        errors.push(FulfillmentError {
+                            obligation: obligation.clone(),
+                            code: match goal.predicate.kind().skip_binder() {
+                                ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
+                                    FulfillmentErrorCode::ProjectionError(
+                                        // FIXME: This could be a `Sorts` if the term is a type
+                                        MismatchedProjectionTypes { err: TypeError::Mismatch },
+                                    )
+                                }
+                                ty::PredicateKind::NormalizesTo(..) => {
+                                    FulfillmentErrorCode::ProjectionError(
+                                        MismatchedProjectionTypes { err: TypeError::Mismatch },
+                                    )
+                                }
+                                ty::PredicateKind::AliasRelate(_, _, _) => {
+                                    FulfillmentErrorCode::ProjectionError(
+                                        MismatchedProjectionTypes { err: TypeError::Mismatch },
+                                    )
+                                }
+                                ty::PredicateKind::Subtype(pred) => {
+                                    let (a, b) = infcx.instantiate_binder_with_placeholders(
+                                        goal.predicate.kind().rebind((pred.a, pred.b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(true, a, b);
+                                    FulfillmentErrorCode::SubtypeError(
+                                        expected_found,
+                                        TypeError::Sorts(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::Coerce(pred) => {
+                                    let (a, b) = infcx.instantiate_binder_with_placeholders(
+                                        goal.predicate.kind().rebind((pred.a, pred.b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(false, a, b);
+                                    FulfillmentErrorCode::SubtypeError(
+                                        expected_found,
+                                        TypeError::Sorts(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::Clause(_)
+                                | ty::PredicateKind::ObjectSafe(_)
+                                | ty::PredicateKind::Ambiguous => {
+                                    FulfillmentErrorCode::SelectionError(
+                                        SelectionError::Unimplemented,
+                                    )
+                                }
+                                ty::PredicateKind::ConstEquate(..) => {
+                                    bug!("unexpected goal: {goal:?}")
+                                }
+                            },
+                            root_obligation: obligation,
+                        });
+                        continue;
+                    }
+                };
                 // Push any nested goals that we get from unifying our canonical response
                 // with our obligation onto the fulfillment context.
                 self.obligations.extend(nested_goals.into_iter().map(|goal| {
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index eba2ac57012..b0a08cd9b79 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -12,7 +12,7 @@ use std::fmt::{self, Debug, Display, Formatter};
 use std::ops::Range;
 
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
-pub struct Ty(pub usize);
+pub struct Ty(usize);
 
 impl Debug for Ty {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@@ -138,7 +138,7 @@ impl Const {
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct ConstId(pub usize);
+pub struct ConstId(usize);
 
 type Ident = Opaque;
 
diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs
index 64938745a4a..71ec9fed2fe 100644
--- a/library/core/benches/ascii.rs
+++ b/library/core/benches/ascii.rs
@@ -63,6 +63,7 @@ macro_rules! benches {
     }
 }
 
+use std::fmt::Write;
 use test::black_box;
 use test::Bencher;
 
@@ -351,3 +352,30 @@ static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [
     N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
     N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
 ];
+
+const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps";
+const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#;
+
+#[bench]
+fn bench_ascii_escape_display_no_escape(b: &mut Bencher) {
+    let mut writer = String::with_capacity(8 * 1024);
+
+    b.iter(move || {
+        writer.clear();
+        let iter = ASCII_PATH.escape_ascii();
+        write!(writer, "{}", iter).unwrap();
+        writer.len()
+    })
+}
+
+#[bench]
+fn bench_ascii_escape_display_mixed(b: &mut Bencher) {
+    let mut writer = String::with_capacity(8 * 1024);
+
+    b.iter(move || {
+        writer.clear();
+        let iter = RUST_INCANTATION.escape_ascii();
+        write!(writer, "{}", iter).unwrap();
+        writer.len()
+    })
+}
diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs
index ef8e4d098ed..02867789b79 100644
--- a/library/core/src/ascii.rs
+++ b/library/core/src/ascii.rs
@@ -96,6 +96,17 @@ pub fn escape_default(c: u8) -> EscapeDefault {
     EscapeDefault(escape::EscapeIterInner::new(data, range))
 }
 
+impl EscapeDefault {
+    pub(crate) fn empty() -> Self {
+        let data = [Char::Null; 4];
+        EscapeDefault(escape::EscapeIterInner::new(data, 0..0))
+    }
+
+    pub(crate) fn as_str(&self) -> &str {
+        self.0.as_str()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Iterator for EscapeDefault {
     type Item = u8;
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 6122332da0d..7d6f746845e 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -24,6 +24,14 @@ impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
     pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
         FlatMap { inner: FlattenCompat::new(iter.map(f)) }
     }
+
+    pub(crate) fn into_parts(self) -> (Option<U::IntoIter>, Option<I>, Option<U::IntoIter>) {
+        (
+            self.inner.frontiter,
+            self.inner.iter.into_inner().map(Map::into_inner),
+            self.inner.backiter,
+        )
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs
index 462a7e87733..7781ed088b7 100644
--- a/library/core/src/iter/adapters/fuse.rs
+++ b/library/core/src/iter/adapters/fuse.rs
@@ -24,6 +24,10 @@ impl<I> Fuse<I> {
     pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
         Fuse { iter: Some(iter) }
     }
+
+    pub(crate) fn into_inner(self) -> Option<I> {
+        self.iter
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index e27fc7257f6..c882c9e7f3f 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -69,6 +69,10 @@ impl<I, F> Map<I, F> {
     pub(in crate::iter) fn new(iter: I, f: F) -> Map<I, F> {
         Map { iter, f }
     }
+
+    pub(crate) fn into_inner(self) -> I {
+        self.iter
+    }
 }
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1a8f245c8be..81bf6f28693 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -111,6 +111,7 @@
 //
 // Library features:
 // tidy-alphabetical-start
+#![cfg_attr(not(bootstrap), feature(offset_of_nested))]
 #![feature(char_indices_offset)]
 #![feature(const_align_of_val)]
 #![feature(const_align_of_val_raw)]
@@ -176,7 +177,6 @@
 #![feature(isqrt)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(non_null_convenience)]
-#![feature(offset_of)]
 #![feature(offset_of_enum)]
 #![feature(panic_internals)]
 #![feature(ptr_alignment_type)]
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 407954001e4..f04ccce40f1 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1303,11 +1303,12 @@ impl<T> SizedTypeProperties for T {}
 /// Enum variants may be traversed as if they were fields. Variants themselves do
 /// not have an offset.
 ///
+/// However, on stable only a single field name is supported, which blocks the use of
+/// enum support.
+///
 /// Visibility is respected - all types and fields must be visible to the call site:
 ///
 /// ```
-/// #![feature(offset_of)]
-///
 /// mod nested {
 ///     #[repr(C)]
 ///     pub struct Struct {
@@ -1330,8 +1331,6 @@ impl<T> SizedTypeProperties for T {}
 /// not *identical*, e.g.:
 ///
 /// ```
-/// #![feature(offset_of)]
-///
 /// struct Wrapper<T, U>(T, U);
 ///
 /// type A = Wrapper<u8, u8>;
@@ -1359,8 +1358,7 @@ impl<T> SizedTypeProperties for T {}
 /// # Examples
 ///
 /// ```
-/// #![feature(offset_of)]
-/// # #![feature(offset_of_enum)]
+/// #![feature(offset_of_enum, offset_of_nested)]
 ///
 /// use std::mem;
 /// #[repr(C)]
@@ -1396,7 +1394,7 @@ impl<T> SizedTypeProperties for T {}
 /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
 /// ```
 #[cfg(not(bootstrap))]
-#[unstable(feature = "offset_of", issue = "106655")]
+#[stable(feature = "offset_of", since = "CURRENT_RUSTC_VERSION")]
 #[allow_internal_unstable(builtin_syntax, hint_must_use)]
 pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {
     // The `{}` is for better error messages
@@ -1404,7 +1402,7 @@ pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {
 }
 
 #[cfg(bootstrap)]
-#[unstable(feature = "offset_of", issue = "106655")]
+#[stable(feature = "offset_of", since = "CURRENT_RUSTC_VERSION")]
 #[allow_internal_unstable(builtin_syntax, hint_must_use)]
 #[allow(missing_docs)]
 pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) {
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 7d60686597a..bda691b16d4 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -171,6 +171,39 @@ macro_rules! nonzero_integer {
                 }
             }
 
+            /// Converts a primitive mutable reference to a non-zero mutable reference
+            /// without checking whether the referenced value is non-zero.
+            /// This results in undefined behavior if `*n` is zero.
+            ///
+            /// # Safety
+            /// The referenced value must not be currently zero.
+            #[unstable(feature = "nonzero_from_mut", issue = "106290")]
+            #[must_use]
+            #[inline]
+            pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self {
+                // SAFETY: Self is repr(transparent), and the value is assumed to be non-zero.
+                unsafe {
+                    let n_alias = &mut *n;
+                    core::intrinsics::assert_unsafe_precondition!(
+                        concat!(stringify!($Ty), "::from_mut_unchecked requires the argument to dereference as non-zero"),
+                        (n_alias: &mut $Int) => *n_alias != 0
+                    );
+                    &mut *(n as *mut $Int as *mut Self)
+                }
+            }
+
+            /// Converts a primitive mutable reference to a non-zero mutable reference
+            /// if the referenced integer is not zero.
+            #[unstable(feature = "nonzero_from_mut", issue = "106290")]
+            #[must_use]
+            #[inline]
+            pub fn from_mut(n: &mut $Int) -> Option<&mut Self> {
+                // SAFETY: Self is repr(transparent), and the value is non-zero.
+                // As long as the returned reference is alive,
+                // the user cannot `*n = 0` directly.
+                (*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) })
+            }
+
             /// Returns the value as a primitive type.
             #[$stability]
             #[inline]
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index ce04a9f4089..5c4f0bf9b2b 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -5,6 +5,7 @@ use crate::fmt::{self, Write};
 use crate::iter;
 use crate::mem;
 use crate::ops;
+use core::ascii::EscapeDefault;
 
 #[cfg(not(test))]
 impl [u8] {
@@ -253,7 +254,45 @@ impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
 #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> fmt::Display for EscapeAscii<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.clone().try_for_each(|b| f.write_char(b as char))
+        // disassemble iterator, including front/back parts of flatmap in case it has been partially consumed
+        let (front, slice, back) = self.clone().inner.into_parts();
+        let front = front.unwrap_or(EscapeDefault::empty());
+        let mut bytes = slice.unwrap_or_default().as_slice();
+        let back = back.unwrap_or(EscapeDefault::empty());
+
+        // usually empty, so the formatter won't have to do any work
+        for byte in front {
+            f.write_char(byte as char)?;
+        }
+
+        fn needs_escape(b: u8) -> bool {
+            b > 0x7E || b < 0x20 || b == b'\\' || b == b'\'' || b == b'"'
+        }
+
+        while bytes.len() > 0 {
+            // fast path for the printable, non-escaped subset of ascii
+            let prefix = bytes.iter().take_while(|&&b| !needs_escape(b)).count();
+            // SAFETY: prefix length was derived by counting bytes in the same splice, so it's in-bounds
+            let (prefix, remainder) = unsafe { bytes.split_at_unchecked(prefix) };
+            // SAFETY: prefix is a valid utf8 sequence, as it's a subset of ASCII
+            let prefix = unsafe { crate::str::from_utf8_unchecked(prefix) };
+
+            f.write_str(prefix)?; // the fast part
+
+            bytes = remainder;
+
+            if let Some(&b) = bytes.first() {
+                // guaranteed to be non-empty, better to write it as a str
+                f.write_str(ascii::escape_default(b).as_str())?;
+                bytes = &bytes[1..];
+            }
+        }
+
+        // also usually empty
+        for byte in back {
+            f.write_char(byte as char)?;
+        }
+        Ok(())
     }
 }
 #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs
index f5f2dd04778..3d3f8ac10c6 100644
--- a/library/core/tests/ascii.rs
+++ b/library/core/tests/ascii.rs
@@ -479,3 +479,13 @@ fn ascii_ctype_const() {
         is_ascii_control      => [false, false, false, false, false];
     }
 }
+
+#[test]
+fn test_ascii_display() {
+    assert_eq!(b"foo'bar".escape_ascii().to_string(), r#"foo\'bar"#);
+    assert_eq!(b"\0\xff".escape_ascii().to_string(), r#"\x00\xff"#);
+    let mut it = b"\0fastpath\xffremainder\xff".escape_ascii();
+    let _ = it.advance_by(4);
+    let _ = it.advance_back_by(4);
+    assert_eq!(it.to_string(), r#"fastpath\xffremainder"#);
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 8604d41eb68..13fb97fdc7f 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -59,6 +59,7 @@
 #![feature(noop_waker)]
 #![feature(numfmt)]
 #![feature(num_midpoint)]
+#![cfg_attr(not(bootstrap), feature(offset_of_nested))]
 #![feature(isqrt)]
 #![feature(step_trait)]
 #![feature(str_internals)]
@@ -115,7 +116,6 @@
 #![feature(utf8_chunks)]
 #![feature(is_ascii_octdigit)]
 #![feature(get_many_mut)]
-#![feature(offset_of)]
 #![feature(iter_map_windows)]
 #![allow(internal_features)]
 #![deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index c3506175715..1b38ba72114 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -102,8 +102,6 @@ impl f32 {
     /// # Examples
     ///
     /// ```
-    /// #![feature(round_ties_even)]
-    ///
     /// let f = 3.3_f32;
     /// let g = -3.3_f32;
     /// let h = 3.5_f32;
@@ -116,7 +114,7 @@ impl f32 {
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    #[unstable(feature = "round_ties_even", issue = "96710")]
+    #[stable(feature = "round_ties_even", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub fn round_ties_even(self) -> f32 {
         unsafe { intrinsics::rintf32(self) }
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index e4b7bfeeb84..f8fc84440ae 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -102,8 +102,6 @@ impl f64 {
     /// # Examples
     ///
     /// ```
-    /// #![feature(round_ties_even)]
-    ///
     /// let f = 3.3_f64;
     /// let g = -3.3_f64;
     /// let h = 3.5_f64;
@@ -116,7 +114,7 @@ impl f64 {
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    #[unstable(feature = "round_ties_even", issue = "96710")]
+    #[stable(feature = "round_ties_even", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub fn round_ties_even(self) -> f64 {
         unsafe { intrinsics::rintf64(self) }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 7a8d9d0ceec..568645ddf73 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -329,7 +329,6 @@
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_write_slice)]
-#![feature(offset_of)]
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
@@ -338,7 +337,6 @@
 #![feature(prelude_2024)]
 #![feature(ptr_as_uninit)]
 #![feature(raw_os_nonzero)]
-#![feature(round_ties_even)]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(slice_range)]
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index cacd02bbfae..80a47c85269 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -8,7 +8,6 @@
 #![feature(variant_count)]
 #![feature(yeet_expr)]
 #![feature(nonzero_ops)]
-#![feature(round_ties_even)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
 #![feature(int_roundings)]
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 5f2d4489f4a..1bb44d56bf6 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -1,5 +1,4 @@
 #![feature(stmt_expr_attributes)]
-#![feature(round_ties_even)]
 #![feature(float_gamma)]
 #![allow(arithmetic_overflow)]
 
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 8e791a7dc69..d673ce7a736 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -15,7 +15,7 @@ use std::ffi::OsStr;
 use std::fmt;
 use std::fs;
 use std::num::NonZeroU32;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 
 use regex::Regex;
 
@@ -52,6 +52,8 @@ pub struct Feature {
     pub since: Option<Version>,
     pub has_gate_test: bool,
     pub tracking_issue: Option<NonZeroU32>,
+    pub file: PathBuf,
+    pub line: usize,
 }
 impl Feature {
     fn tracking_issue_display(&self) -> impl fmt::Display {
@@ -184,23 +186,25 @@ pub fn check(
         .chain(lib_features.iter().map(|feat| (feat, "lib")));
     for ((feature_name, feature), kind) in all_features_iter {
         let since = if let Some(since) = feature.since { since } else { continue };
+        let file = feature.file.display();
+        let line = feature.line;
         if since > version && since != Version::CurrentPlaceholder {
             tidy_error!(
                 bad,
-                "The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}"
+                "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}"
             );
         }
         if channel == "nightly" && since == version {
             tidy_error!(
                 bad,
-                "The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}",
+                "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}",
                 version::VERSION_PLACEHOLDER
             );
         }
         if channel != "nightly" && since == Version::CurrentPlaceholder {
             tidy_error!(
                 bad,
-                "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel",
+                "{file}:{line}: The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel",
             );
         }
     }
@@ -433,7 +437,14 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
                 );
             }
             Entry::Vacant(e) => {
-                e.insert(Feature { level, since, has_gate_test: false, tracking_issue });
+                e.insert(Feature {
+                    level,
+                    since,
+                    has_gate_test: false,
+                    tracking_issue,
+                    file: path.to_path_buf(),
+                    line: line_number,
+                });
             }
         }
     }
@@ -559,6 +570,8 @@ fn map_lib_features(
                         since: None,
                         has_gate_test: false,
                         tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none),
+                        file: file.to_path_buf(),
+                        line: i + 1,
                     };
                     mf(Ok((feature_name, feature)), file, i + 1);
                     continue;
@@ -588,7 +601,14 @@ fn map_lib_features(
                 };
                 let tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none);
 
-                let feature = Feature { level, since, has_gate_test: false, tracking_issue };
+                let feature = Feature {
+                    level,
+                    since,
+                    has_gate_test: false,
+                    tracking_issue,
+                    file: file.to_path_buf(),
+                    line: i + 1,
+                };
                 if line.contains(']') {
                     mf(Ok((feature_name, feature)), file, i + 1);
                 } else {
diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs
index 43ecbbed186..f15d15bfcb2 100644
--- a/tests/mir-opt/const_prop/offset_of.rs
+++ b/tests/mir-opt/const_prop/offset_of.rs
@@ -2,7 +2,7 @@
 // unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(offset_of, offset_of_enum)]
+#![feature(offset_of_enum, offset_of_nested)]
 
 use std::marker::PhantomData;
 use std::mem::offset_of;
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs
index e71b3f59eca..c1be6910258 100644
--- a/tests/mir-opt/dataflow-const-prop/offset_of.rs
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs
@@ -2,7 +2,7 @@
 // unit-test: DataflowConstProp
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 
 use std::marker::PhantomData;
 use std::mem::offset_of;
diff --git a/tests/pretty/offset_of.rs b/tests/pretty/offset_of.rs
index e1783432857..1307c335ad3 100644
--- a/tests/pretty/offset_of.rs
+++ b/tests/pretty/offset_of.rs
@@ -1,4 +1,3 @@
 // pp-exact
-#![feature(offset_of)]
 
 fn main() { std::mem::offset_of!(std :: ops :: Range < usize >, end); }
diff --git a/tests/ui/feature-gates/feature-gate-offset-of-enum.rs b/tests/ui/feature-gates/feature-gate-offset-of-enum.rs
index e19dcf9f6a5..1f2f7ee1e19 100644
--- a/tests/ui/feature-gates/feature-gate-offset-of-enum.rs
+++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.rs
@@ -1,4 +1,4 @@
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr b/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr
index 02ee54e8607..fc7dd7923f7 100644
--- a/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr
+++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr
@@ -13,7 +13,7 @@ error[E0658]: using enums in offset_of is experimental
 LL |     offset_of!(Alpha, One);
    |                       ^^^
    |
-   = note: see issue #106655 <https://github.com/rust-lang/rust/issues/106655> for more information
+   = note: see issue #120141 <https://github.com/rust-lang/rust/issues/120141> for more information
    = help: add `#![feature(offset_of_enum)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
@@ -29,7 +29,7 @@ error[E0658]: using enums in offset_of is experimental
 LL |     offset_of!(Alpha, Two.0);
    |                       ^^^
    |
-   = note: see issue #106655 <https://github.com/rust-lang/rust/issues/106655> for more information
+   = note: see issue #120141 <https://github.com/rust-lang/rust/issues/120141> for more information
    = help: add `#![feature(offset_of_enum)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.rs b/tests/ui/feature-gates/feature-gate-offset-of-nested.rs
new file mode 100644
index 00000000000..c4eb4720fde
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-offset-of-nested.rs
@@ -0,0 +1,28 @@
+#![feature(offset_of_enum)]
+
+use std::mem::offset_of;
+
+struct S {
+    a: u8,
+    b: (u8, u8),
+    c: T,
+}
+
+struct T {
+    t: &'static str,
+}
+
+enum Alpha {
+    One(u8),
+    Two(u8),
+}
+
+fn main() {
+    offset_of!(Alpha, Two.0); //~ ERROR only a single ident or integer is stable as the field in offset_of
+    offset_of!(S, a);
+    offset_of!((u8, S), 1);
+    offset_of!((u32, (S, T)), 1.1); //~ ERROR only a single ident or integer is stable as the field in offset_of
+    offset_of!(S, b.0); //~ ERROR only a single ident or integer is stable as the field in offset_of
+    offset_of!((S, ()), 0.c); //~ ERROR only a single ident or integer is stable as the field in offset_of
+    offset_of!(S, c.t); //~ ERROR only a single ident or integer is stable as the field in offset_of
+}
diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr
new file mode 100644
index 00000000000..f367fc9fa0d
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr
@@ -0,0 +1,60 @@
+error[E0658]: only a single ident or integer is stable as the field in offset_of
+  --> $DIR/feature-gate-offset-of-nested.rs:21:27
+   |
+LL |     offset_of!(Alpha, Two.0);
+   |                           ^
+   |
+   = note: see issue #120140 <https://github.com/rust-lang/rust/issues/120140> for more information
+   = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: only a single ident or integer is stable as the field in offset_of
+  --> $DIR/feature-gate-offset-of-nested.rs:24:33
+   |
+LL |       offset_of!((u32, (S, T)), 1.1);
+   |  _____----------------------------^-
+   | |     |
+   | |     in this macro invocation
+LL | |     offset_of!(S, b.0);
+LL | |     offset_of!((S, ()), 0.c);
+LL | |     offset_of!(S, c.t);
+...  |
+   |
+   = note: see issue #120140 <https://github.com/rust-lang/rust/issues/120140> for more information
+   = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: only a single ident or integer is stable as the field in offset_of
+  --> $DIR/feature-gate-offset-of-nested.rs:25:21
+   |
+LL |     offset_of!(S, b.0);
+   |                     ^
+   |
+   = note: see issue #120140 <https://github.com/rust-lang/rust/issues/120140> for more information
+   = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: only a single ident or integer is stable as the field in offset_of
+  --> $DIR/feature-gate-offset-of-nested.rs:26:27
+   |
+LL |     offset_of!((S, ()), 0.c);
+   |                           ^
+   |
+   = note: see issue #120140 <https://github.com/rust-lang/rust/issues/120140> for more information
+   = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: only a single ident or integer is stable as the field in offset_of
+  --> $DIR/feature-gate-offset-of-nested.rs:27:21
+   |
+LL |     offset_of!(S, c.t);
+   |                     ^
+   |
+   = note: see issue #120140 <https://github.com/rust-lang/rust/issues/120140> for more information
+   = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/layout/issue-112048-unsizing-niche.rs b/tests/ui/layout/issue-112048-unsizing-niche.rs
index 23588ba36ee..e59e063df99 100644
--- a/tests/ui/layout/issue-112048-unsizing-niche.rs
+++ b/tests/ui/layout/issue-112048-unsizing-niche.rs
@@ -2,7 +2,6 @@
 
 // Check that unsizing does not change which field is considered for niche layout.
 
-#![feature(offset_of)]
 #![allow(dead_code)]
 
 #[derive(Clone)]
diff --git a/tests/ui/lint/dead-code/offset-of-correct-param-env.rs b/tests/ui/lint/dead-code/offset-of-correct-param-env.rs
index 2c6fcef2500..ae81a252439 100644
--- a/tests/ui/lint/dead-code/offset-of-correct-param-env.rs
+++ b/tests/ui/lint/dead-code/offset-of-correct-param-env.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 #![deny(dead_code)]
 
 // This struct contains a projection that can only be normalized after getting the field type.
diff --git a/tests/ui/lint/dead-code/offset-of.rs b/tests/ui/lint/dead-code/offset-of.rs
index da91de3862f..5269426d2ff 100644
--- a/tests/ui/lint/dead-code/offset-of.rs
+++ b/tests/ui/lint/dead-code/offset-of.rs
@@ -1,4 +1,4 @@
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 #![deny(dead_code)]
 
 use std::mem::offset_of;
diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.rs b/tests/ui/object-safety/avoid-ice-on-warning-2.rs
new file mode 100644
index 00000000000..cd34362d3dd
--- /dev/null
+++ b/tests/ui/object-safety/avoid-ice-on-warning-2.rs
@@ -0,0 +1,9 @@
+fn id<F>(f: Copy) -> usize {
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+//~| ERROR the trait `Copy` cannot be made into an object
+    f()
+}
+fn main() {}
diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.stderr
new file mode 100644
index 00000000000..2755eee6f35
--- /dev/null
+++ b/tests/ui/object-safety/avoid-ice-on-warning-2.stderr
@@ -0,0 +1,50 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-2.rs:1:13
+   |
+LL | fn id<F>(f: Copy) -> usize {
+   |             ^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `Copy` it is not object safe, so it can't be `dyn`
+   = note: `#[warn(bare_trait_objects)]` on by default
+help: use a new generic type parameter, constrained by `Copy`
+   |
+LL | fn id<F, T: Copy>(f: T) -> usize {
+   |        +++++++++     ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL | fn id<F>(f: impl Copy) -> usize {
+   |             ++++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-2.rs:1:13
+   |
+LL | fn id<F>(f: Copy) -> usize {
+   |             ^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `Copy` it is not object safe, so it can't be `dyn`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: use a new generic type parameter, constrained by `Copy`
+   |
+LL | fn id<F, T: Copy>(f: T) -> usize {
+   |        +++++++++     ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL | fn id<F>(f: impl Copy) -> usize {
+   |             ++++
+
+error[E0038]: the trait `Copy` cannot be made into an object
+  --> $DIR/avoid-ice-on-warning-2.rs:1:13
+   |
+LL | fn id<F>(f: Copy) -> usize {
+   |             ^^^^ `Copy` cannot be made into an object
+   |
+   = note: the trait cannot be made into an object because it requires `Self: Sized`
+   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+
+error: aborting due to 1 previous error; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.rs b/tests/ui/object-safety/avoid-ice-on-warning-3.rs
new file mode 100644
index 00000000000..caaf4d0fd99
--- /dev/null
+++ b/tests/ui/object-safety/avoid-ice-on-warning-3.rs
@@ -0,0 +1,17 @@
+trait B { fn f(a: A) -> A; }
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+//~| WARN this is accepted in the current edition
+//~| WARN this is accepted in the current edition
+//~| ERROR the trait `A` cannot be made into an object
+trait A { fn g(b: B) -> B; }
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+//~| WARN this is accepted in the current edition
+//~| WARN this is accepted in the current edition
+//~| ERROR the trait `B` cannot be made into an object
+fn main() {}
diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.stderr
new file mode 100644
index 00000000000..0fc67770b96
--- /dev/null
+++ b/tests/ui/object-safety/avoid-ice-on-warning-3.stderr
@@ -0,0 +1,148 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-3.rs:9:19
+   |
+LL | trait A { fn g(b: B) -> B; }
+   |                   ^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `B` it is not object safe, so it can't be `dyn`
+   = note: `#[warn(bare_trait_objects)]` on by default
+help: use a new generic type parameter, constrained by `B`
+   |
+LL | trait A { fn g<T: B>(b: T) -> B; }
+   |               ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL | trait A { fn g(b: impl B) -> B; }
+   |                   ++++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-3.rs:9:25
+   |
+LL | trait A { fn g(b: B) -> B; }
+   |                         ^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type
+   |
+LL | trait A { fn g(b: B) -> impl B; }
+   |                         ++++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-3.rs:1:19
+   |
+LL | trait B { fn f(a: A) -> A; }
+   |                   ^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `A` it is not object safe, so it can't be `dyn`
+help: use a new generic type parameter, constrained by `A`
+   |
+LL | trait B { fn f<T: A>(a: T) -> A; }
+   |               ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL | trait B { fn f(a: impl A) -> A; }
+   |                   ++++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-3.rs:1:25
+   |
+LL | trait B { fn f(a: A) -> A; }
+   |                         ^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type
+   |
+LL | trait B { fn f(a: A) -> impl A; }
+   |                         ++++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-3.rs:1:19
+   |
+LL | trait B { fn f(a: A) -> A; }
+   |                   ^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `A` it is not object safe, so it can't be `dyn`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: use a new generic type parameter, constrained by `A`
+   |
+LL | trait B { fn f<T: A>(a: T) -> A; }
+   |               ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL | trait B { fn f(a: impl A) -> A; }
+   |                   ++++
+
+error[E0038]: the trait `A` cannot be made into an object
+  --> $DIR/avoid-ice-on-warning-3.rs:1:19
+   |
+LL | trait B { fn f(a: A) -> A; }
+   |                   ^ `A` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/avoid-ice-on-warning-3.rs:9:14
+   |
+LL | trait A { fn g(b: B) -> B; }
+   |       -      ^ ...because associated function `g` has no `self` parameter
+   |       |
+   |       this trait cannot be made into an object...
+help: consider turning `g` into a method by giving it a `&self` argument
+   |
+LL | trait A { fn g(&self, b: B) -> B; }
+   |                ++++++
+help: alternatively, consider constraining `g` so it does not apply to trait objects
+   |
+LL | trait A { fn g(b: B) -> B where Self: Sized; }
+   |                           +++++++++++++++++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning-3.rs:9:19
+   |
+LL | trait A { fn g(b: B) -> B; }
+   |                   ^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `B` it is not object safe, so it can't be `dyn`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: use a new generic type parameter, constrained by `B`
+   |
+LL | trait A { fn g<T: B>(b: T) -> B; }
+   |               ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL | trait A { fn g(b: impl B) -> B; }
+   |                   ++++
+
+error[E0038]: the trait `B` cannot be made into an object
+  --> $DIR/avoid-ice-on-warning-3.rs:9:19
+   |
+LL | trait A { fn g(b: B) -> B; }
+   |                   ^ `B` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/avoid-ice-on-warning-3.rs:1:14
+   |
+LL | trait B { fn f(a: A) -> A; }
+   |       -      ^ ...because associated function `f` has no `self` parameter
+   |       |
+   |       this trait cannot be made into an object...
+help: consider turning `f` into a method by giving it a `&self` argument
+   |
+LL | trait B { fn f(&self, a: A) -> A; }
+   |                ++++++
+help: alternatively, consider constraining `f` so it does not apply to trait objects
+   |
+LL | trait B { fn f(a: A) -> A where Self: Sized; }
+   |                           +++++++++++++++++
+
+error: aborting due to 2 previous errors; 6 warnings emitted
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/object-safety/avoid-ice-on-warning.rs b/tests/ui/object-safety/avoid-ice-on-warning.rs
new file mode 100644
index 00000000000..d2a1eeb5286
--- /dev/null
+++ b/tests/ui/object-safety/avoid-ice-on-warning.rs
@@ -0,0 +1,6 @@
+fn call_this<F>(f: F) : Fn(&str) + call_that {}
+//~^ ERROR return types are denoted using `->`
+//~| ERROR cannot find trait `call_that` in this scope
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+fn main() {}
diff --git a/tests/ui/object-safety/avoid-ice-on-warning.stderr b/tests/ui/object-safety/avoid-ice-on-warning.stderr
new file mode 100644
index 00000000000..1046f177e82
--- /dev/null
+++ b/tests/ui/object-safety/avoid-ice-on-warning.stderr
@@ -0,0 +1,29 @@
+error: return types are denoted using `->`
+  --> $DIR/avoid-ice-on-warning.rs:1:23
+   |
+LL | fn call_this<F>(f: F) : Fn(&str) + call_that {}
+   |                       ^ help: use `->` instead
+
+error[E0405]: cannot find trait `call_that` in this scope
+  --> $DIR/avoid-ice-on-warning.rs:1:36
+   |
+LL | fn call_this<F>(f: F) : Fn(&str) + call_that {}
+   |                                    ^^^^^^^^^ not found in this scope
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/avoid-ice-on-warning.rs:1:25
+   |
+LL | fn call_this<F>(f: F) : Fn(&str) + call_that {}
+   |                         ^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `#[warn(bare_trait_objects)]` on by default
+help: `Fn(&str) + call_that` is not object safe, use `impl Fn(&str) + call_that` to return an opaque type, as long as you return a single underlying type
+   |
+LL | fn call_this<F>(f: F) : impl Fn(&str) + call_that {}
+   |                         ++++
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs
index 7b92698c25e..c86e61a61a7 100644
--- a/tests/ui/offset-of/offset-of-arg-count.rs
+++ b/tests/ui/offset-of/offset-of-arg-count.rs
@@ -1,5 +1,3 @@
-#![feature(offset_of)]
-
 use std::mem::offset_of;
 
 fn main() {
diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr
index af0d42de30d..4cb24b3d034 100644
--- a/tests/ui/offset-of/offset-of-arg-count.stderr
+++ b/tests/ui/offset-of/offset-of-arg-count.stderr
@@ -1,5 +1,5 @@
 error: unexpected end of macro invocation
-  --> $DIR/offset-of-arg-count.rs:6:34
+  --> $DIR/offset-of-arg-count.rs:4:34
    |
 LL |     offset_of!(NotEnoughArguments);
    |                                  ^ missing tokens in macro arguments
@@ -8,7 +8,7 @@ note: while trying to match `,`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
 error: unexpected end of macro invocation
-  --> $DIR/offset-of-arg-count.rs:7:45
+  --> $DIR/offset-of-arg-count.rs:5:45
    |
 LL |     offset_of!(NotEnoughArgumentsWithAComma, );
    |                                             ^ missing tokens in macro arguments
@@ -17,7 +17,7 @@ note: while trying to match meta-variable `$fields:expr`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
 error: no rules expected the token `too`
-  --> $DIR/offset-of-arg-count.rs:8:34
+  --> $DIR/offset-of-arg-count.rs:6:34
    |
 LL |     offset_of!(Container, field, too many arguments);
    |                                  ^^^ no rules expected this token in macro call
@@ -25,25 +25,25 @@ LL |     offset_of!(Container, field, too many arguments);
    = note: while trying to match sequence end
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-arg-count.rs:11:21
+  --> $DIR/offset-of-arg-count.rs:9:21
    |
 LL |     offset_of!(S, f.);
    |                     ^
 
 error: unexpected token: `,`
-  --> $DIR/offset-of-arg-count.rs:12:21
+  --> $DIR/offset-of-arg-count.rs:10:21
    |
 LL |     offset_of!(S, f.,);
    |                     ^
 
 error: offset_of expects dot-separated field and variant names
-  --> $DIR/offset-of-arg-count.rs:13:19
+  --> $DIR/offset-of-arg-count.rs:11:19
    |
 LL |     offset_of!(S, f..);
    |                   ^^^
 
 error: offset_of expects dot-separated field and variant names
-  --> $DIR/offset-of-arg-count.rs:14:19
+  --> $DIR/offset-of-arg-count.rs:12:19
    |
 LL |     offset_of!(S, f..,);
    |                   ^^^
diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs
index e393b159e64..016ebfadd14 100644
--- a/tests/ui/offset-of/offset-of-dst-field.rs
+++ b/tests/ui/offset-of/offset-of-dst-field.rs
@@ -1,4 +1,4 @@
-#![feature(offset_of, extern_types)]
+#![feature(extern_types)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs
index a2d6aace47d..cb2f04786ac 100644
--- a/tests/ui/offset-of/offset-of-enum.rs
+++ b/tests/ui/offset-of/offset-of-enum.rs
@@ -1,4 +1,4 @@
-#![feature(offset_of, offset_of_enum)]
+#![feature(offset_of_enum, offset_of_nested)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/offset-of/offset-of-inference.rs b/tests/ui/offset-of/offset-of-inference.rs
index ba87574eae0..1b1ae25e1ee 100644
--- a/tests/ui/offset-of/offset-of-inference.rs
+++ b/tests/ui/offset-of/offset-of-inference.rs
@@ -1,7 +1,5 @@
 // Test that inference types in `offset_of!` don't ICE.
 
-#![feature(offset_of)]
-
 struct Foo<T> {
     x: T,
 }
diff --git a/tests/ui/offset-of/offset-of-inference.stderr b/tests/ui/offset-of/offset-of-inference.stderr
index 1845822f11d..8bd104ed7e2 100644
--- a/tests/ui/offset-of/offset-of-inference.stderr
+++ b/tests/ui/offset-of/offset-of-inference.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/offset-of-inference.rs:10:35
+  --> $DIR/offset-of-inference.rs:8:35
    |
 LL |     let _ = core::mem::offset_of!(Foo<_>, x);
    |                                   ^^^^^^ cannot infer type
diff --git a/tests/ui/offset-of/offset-of-must-use.rs b/tests/ui/offset-of/offset-of-must-use.rs
index e30145d7a2f..e4b092fcedf 100644
--- a/tests/ui/offset-of/offset-of-must-use.rs
+++ b/tests/ui/offset-of/offset-of-must-use.rs
@@ -1,6 +1,5 @@
 // check-pass
 
-#![feature(offset_of)]
 #![warn(unused)]
 
 fn main() {
diff --git a/tests/ui/offset-of/offset-of-must-use.stderr b/tests/ui/offset-of/offset-of-must-use.stderr
index 5fe387a7255..b6d88e098d0 100644
--- a/tests/ui/offset-of/offset-of-must-use.stderr
+++ b/tests/ui/offset-of/offset-of-must-use.stderr
@@ -1,11 +1,11 @@
 warning: unused return value of `must_use` that must be used
-  --> $DIR/offset-of-must-use.rs:7:5
+  --> $DIR/offset-of-must-use.rs:6:5
    |
 LL |     core::mem::offset_of!((String,), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/offset-of-must-use.rs:4:9
+  --> $DIR/offset-of-must-use.rs:3:9
    |
 LL | #![warn(unused)]
    |         ^^^^^^
diff --git a/tests/ui/offset-of/offset-of-output-type.rs b/tests/ui/offset-of/offset-of-output-type.rs
index 50c2e93841f..76a33154ba3 100644
--- a/tests/ui/offset-of/offset-of-output-type.rs
+++ b/tests/ui/offset-of/offset-of-output-type.rs
@@ -1,5 +1,3 @@
-#![feature(offset_of)]
-
 use std::mem::offset_of;
 
 struct S {
diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr
index 233d4987643..34ad931d0ca 100644
--- a/tests/ui/offset-of/offset-of-output-type.stderr
+++ b/tests/ui/offset-of/offset-of-output-type.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/offset-of-output-type.rs:12:17
+  --> $DIR/offset-of-output-type.rs:10:17
    |
 LL |     let _: u8 = offset_of!(S, v);
    |                 ^^^^^^^^^^^^^^^^ expected `u8`, found `usize`
@@ -7,7 +7,7 @@ LL |     let _: u8 = offset_of!(S, v);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/offset-of-output-type.rs:13:18
+  --> $DIR/offset-of-output-type.rs:11:18
    |
 LL |     let _: u16 = offset_of!(S, v);
    |                  ^^^^^^^^^^^^^^^^ expected `u16`, found `usize`
@@ -15,7 +15,7 @@ LL |     let _: u16 = offset_of!(S, v);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/offset-of-output-type.rs:14:18
+  --> $DIR/offset-of-output-type.rs:12:18
    |
 LL |     let _: u32 = offset_of!(S, v);
    |                  ^^^^^^^^^^^^^^^^ expected `u32`, found `usize`
@@ -23,7 +23,7 @@ LL |     let _: u32 = offset_of!(S, v);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/offset-of-output-type.rs:15:18
+  --> $DIR/offset-of-output-type.rs:13:18
    |
 LL |     let _: u64 = offset_of!(S, v);
    |                  ^^^^^^^^^^^^^^^^ expected `u64`, found `usize`
@@ -31,7 +31,7 @@ LL |     let _: u64 = offset_of!(S, v);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/offset-of-output-type.rs:16:20
+  --> $DIR/offset-of-output-type.rs:14:20
    |
 LL |     let _: isize = offset_of!(S, v);
    |                    ^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
@@ -39,7 +39,7 @@ LL |     let _: isize = offset_of!(S, v);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/offset-of-output-type.rs:19:5
+  --> $DIR/offset-of-output-type.rs:17:5
    |
 LL | fn main() {
    |          - expected `()` because of default return type
diff --git a/tests/ui/offset-of/offset-of-private.rs b/tests/ui/offset-of/offset-of-private.rs
index b7affdb7943..1c326b5c79a 100644
--- a/tests/ui/offset-of/offset-of-private.rs
+++ b/tests/ui/offset-of/offset-of-private.rs
@@ -1,4 +1,4 @@
-#![feature(offset_of, offset_of_enum)]
+#![feature(offset_of_enum, offset_of_nested)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/offset-of/offset-of-self.rs b/tests/ui/offset-of/offset-of-self.rs
index 04dcaf7c0a6..1558e13b530 100644
--- a/tests/ui/offset-of/offset-of-self.rs
+++ b/tests/ui/offset-of/offset-of-self.rs
@@ -1,4 +1,4 @@
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/offset-of/offset-of-tuple-nested.rs b/tests/ui/offset-of/offset-of-tuple-nested.rs
index 59b02e3c5c4..212176b2427 100644
--- a/tests/ui/offset-of/offset-of-tuple-nested.rs
+++ b/tests/ui/offset-of/offset-of-tuple-nested.rs
@@ -2,7 +2,7 @@
 // Test for issue #112204 -- make sure this goes through the entire compilation pipeline,
 // similar to why `offset-of-unsized.rs` is also build-pass
 
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs
index b6fc1e32229..75ba8d77f2f 100644
--- a/tests/ui/offset-of/offset-of-tuple.rs
+++ b/tests/ui/offset-of/offset-of-tuple.rs
@@ -1,4 +1,4 @@
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 #![feature(builtin_syntax)]
 
 use std::mem::offset_of;
diff --git a/tests/ui/offset-of/offset-of-unsized.rs b/tests/ui/offset-of/offset-of-unsized.rs
index 49c8328da5c..b70529ed7b8 100644
--- a/tests/ui/offset-of/offset-of-unsized.rs
+++ b/tests/ui/offset-of/offset-of-unsized.rs
@@ -2,8 +2,6 @@
 // regression test for #112051, not in `offset-of-dst` as the issue is in codegen,
 // and isn't triggered in the presence of typeck errors
 
-#![feature(offset_of)]
-
 struct S<T: ?Sized> {
     a: u64,
     b: T,
diff --git a/tests/ui/offset-of/offset-of-unstable-with-feature.rs b/tests/ui/offset-of/offset-of-unstable-with-feature.rs
index 7d2eb46c056..be275564a0a 100644
--- a/tests/ui/offset-of/offset-of-unstable-with-feature.rs
+++ b/tests/ui/offset-of/offset-of-unstable-with-feature.rs
@@ -1,7 +1,7 @@
 // check-pass
 // aux-build:offset-of-staged-api.rs
 
-#![feature(offset_of, unstable_test_feature)]
+#![feature(offset_of_nested, unstable_test_feature)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/offset-of/offset-of-unstable.rs b/tests/ui/offset-of/offset-of-unstable.rs
index 1e19f2091f2..da0882abd22 100644
--- a/tests/ui/offset-of/offset-of-unstable.rs
+++ b/tests/ui/offset-of/offset-of-unstable.rs
@@ -1,6 +1,6 @@
 // aux-build:offset-of-staged-api.rs
 
-#![feature(offset_of)]
+#![feature(offset_of_nested)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/single-use-lifetime/issue-117965.rs b/tests/ui/single-use-lifetime/issue-117965.rs
new file mode 100644
index 00000000000..5eb2a03e13d
--- /dev/null
+++ b/tests/ui/single-use-lifetime/issue-117965.rs
@@ -0,0 +1,18 @@
+#![deny(single_use_lifetimes)]
+
+pub enum Data<'a> {
+    Borrowed(&'a str),
+    Owned(String),
+}
+
+impl<'a> Data<'a> {
+    pub fn get<'b: 'a>(&'b self) -> &'a str {
+        //~^ ERROR lifetime parameter `'b` only used once
+        match &self {
+            Self::Borrowed(val) => val,
+            Self::Owned(val) => &val,
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/single-use-lifetime/issue-117965.stderr b/tests/ui/single-use-lifetime/issue-117965.stderr
new file mode 100644
index 00000000000..ed14ab92f4d
--- /dev/null
+++ b/tests/ui/single-use-lifetime/issue-117965.stderr
@@ -0,0 +1,16 @@
+error: lifetime parameter `'b` only used once
+  --> $DIR/issue-117965.rs:9:16
+   |
+LL |     pub fn get<'b: 'a>(&'b self) -> &'a str {
+   |                ^^       -- ...is used only here
+   |                |
+   |                this lifetime...
+   |
+note: the lint level is defined here
+  --> $DIR/issue-117965.rs:1:9
+   |
+LL | #![deny(single_use_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
new file mode 100644
index 00000000000..f48c3d124dd
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
@@ -0,0 +1,23 @@
+// edition:2021
+#![allow(bare_trait_objects)]
+trait A: Sized {
+    fn f(a: A) -> A;
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+    //~| ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `A` cannot be made into an object
+}
+trait B {
+    fn f(a: B) -> B;
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+    //~| ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `B` cannot be made into an object
+}
+trait C {
+    fn f(&self, a: C) -> C;
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
new file mode 100644
index 00000000000..73d5a24f831
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
@@ -0,0 +1,168 @@
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
+   |
+LL | trait A: Sized {
+   |       - in this trait
+LL |     fn f(a: A) -> A;
+   |             ^     ^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(a: Self) -> Self;
+   |             ~~~~     ~~~~
+
+error[E0038]: the trait `A` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
+   |
+LL |     fn f(a: A) -> A;
+   |             ^ `A` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:3:10
+   |
+LL | trait A: Sized {
+   |       -  ^^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait cannot be made into an object...
+
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
+   |
+LL | trait B {
+   |       - in this trait
+LL |     fn f(a: B) -> B;
+   |             ^     ^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(a: Self) -> Self;
+   |             ~~~~     ~~~~
+
+error[E0038]: the trait `B` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
+   |
+LL |     fn f(a: B) -> B;
+   |             ^ `B` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:8
+   |
+LL | trait B {
+   |       - this trait cannot be made into an object...
+LL |     fn f(a: B) -> B;
+   |        ^ ...because associated function `f` has no `self` parameter
+help: consider turning `f` into a method by giving it a `&self` argument
+   |
+LL |     fn f(&self, a: B) -> B;
+   |          ++++++
+help: alternatively, consider constraining `f` so it does not apply to trait objects
+   |
+LL |     fn f(a: B) -> B where Self: Sized;
+   |                     +++++++++++++++++
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
+   |
+LL |     fn f(a: A) -> A;
+   |             ^
+   |
+help: use a new generic type parameter, constrained by `A`
+   |
+LL |     fn f<T: A>(a: T) -> A;
+   |         ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn f(a: impl A) -> A;
+   |             ++++
+help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn f(a: &dyn A) -> A;
+   |             ++++
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19
+   |
+LL |     fn f(a: A) -> A;
+   |                   ^
+   |
+help: use `impl A` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn f(a: A) -> impl A;
+   |                   ++++
+help: alternatively, you can return an owned trait object
+   |
+LL |     fn f(a: A) -> Box<dyn A>;
+   |                   +++++++  +
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
+   |
+LL |     fn f(a: B) -> B;
+   |             ^
+   |
+help: use a new generic type parameter, constrained by `B`
+   |
+LL |     fn f<T: B>(a: T) -> B;
+   |         ++++++    ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn f(a: impl B) -> B;
+   |             ++++
+help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn f(a: &dyn B) -> B;
+   |             ++++
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19
+   |
+LL |     fn f(a: B) -> B;
+   |                   ^
+   |
+help: use `impl B` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn f(a: B) -> impl B;
+   |                   ++++
+help: alternatively, you can return an owned trait object
+   |
+LL |     fn f(a: B) -> Box<dyn B>;
+   |                   +++++++  +
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
+   |
+LL |     fn f(&self, a: C) -> C;
+   |                    ^
+   |
+help: use a new generic type parameter, constrained by `C`
+   |
+LL |     fn f<T: C>(&self, a: T) -> C;
+   |         ++++++           ~
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn f(&self, a: impl C) -> C;
+   |                    ++++
+help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn f(&self, a: &dyn C) -> C;
+   |                    ++++
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26
+   |
+LL |     fn f(&self, a: C) -> C;
+   |                          ^
+   |
+help: use `impl C` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn f(&self, a: C) -> impl C;
+   |                          ++++
+help: alternatively, you can return an owned trait object
+   |
+LL |     fn f(&self, a: C) -> Box<dyn C>;
+   |                          +++++++  +
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0038, E0782.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs
new file mode 100644
index 00000000000..a598e883f3f
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs
@@ -0,0 +1,17 @@
+// edition:2021
+#![allow(bare_trait_objects)]
+trait A: Sized {
+    fn f(a: dyn A) -> dyn A;
+    //~^ ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `A` cannot be made into an object
+}
+trait B {
+    fn f(a: dyn B) -> dyn B;
+    //~^ ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `B` cannot be made into an object
+}
+trait C {
+    fn f(&self, a: dyn C) -> dyn C;
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr
new file mode 100644
index 00000000000..d6376be9c04
--- /dev/null
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr
@@ -0,0 +1,65 @@
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13
+   |
+LL | trait A: Sized {
+   |       - in this trait
+LL |     fn f(a: dyn A) -> dyn A;
+   |             ^^^^^     ^^^^^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(a: Self) -> Self;
+   |             ~~~~     ~~~~
+
+error[E0038]: the trait `A` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13
+   |
+LL |     fn f(a: dyn A) -> dyn A;
+   |             ^^^^^ `A` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:3:10
+   |
+LL | trait A: Sized {
+   |       -  ^^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait cannot be made into an object...
+
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13
+   |
+LL | trait B {
+   |       - in this trait
+LL |     fn f(a: dyn B) -> dyn B;
+   |             ^^^^^     ^^^^^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(a: Self) -> Self;
+   |             ~~~~     ~~~~
+
+error[E0038]: the trait `B` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13
+   |
+LL |     fn f(a: dyn B) -> dyn B;
+   |             ^^^^^ `B` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:8
+   |
+LL | trait B {
+   |       - this trait cannot be made into an object...
+LL |     fn f(a: dyn B) -> dyn B;
+   |        ^ ...because associated function `f` has no `self` parameter
+help: consider turning `f` into a method by giving it a `&self` argument
+   |
+LL |     fn f(&self, a: dyn B) -> dyn B;
+   |          ++++++
+help: alternatively, consider constraining `f` so it does not apply to trait objects
+   |
+LL |     fn f(a: dyn B) -> dyn B where Self: Sized;
+   |                             +++++++++++++++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0038`.