about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-29 21:46:59 +0000
committerbors <bors@rust-lang.org>2024-07-29 21:46:59 +0000
commit368e2fd458a22d0cc133d0c254f2612ee999744f (patch)
tree0edd5e971bab5ed0dc132f5f264f1e3324fa5b6b
parent612a33f20b9b2c27380edbc4b26a01433ed114bc (diff)
parentc2616203bc0836496af23be4b35f3856e52108a6 (diff)
downloadrust-368e2fd458a22d0cc133d0c254f2612ee999744f.tar.gz
rust-368e2fd458a22d0cc133d0c254f2612ee999744f.zip
Auto merge of #128360 - matthiaskrgr:rollup-wwy5mkj, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #126247 (rustdoc: word wrap CamelCase in the item list table and sidebar)
 - #128104 (Not lint pub structs without pub constructors intentionally)
 - #128153 (Stop using `MoveDataParamEnv` for places that don't need a param-env)
 - #128284 (Stabilize offset_of_nested)
 - #128342 (simplify the use of `CiEnv`)
 - #128355 (triagebot: make sure Nora is called Nora)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_borrowck/src/lib.rs16
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0795.md4
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs12
-rw-r--r--compiler/rustc_mir_dataflow/src/drop_flag_effects.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs60
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs9
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs16
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs9
-rw-r--r--compiler/rustc_passes/src/dead.rs36
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/mem/mod.rs3
-rw-r--r--library/core/tests/lib.rs110
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs2
-rw-r--r--src/bootstrap/src/core/builder.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs2
-rw-r--r--src/bootstrap/src/lib.rs4
-rw-r--r--src/bootstrap/src/utils/exec.rs4
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/html/escape.rs55
-rw-r--r--src/librustdoc/html/escape/tests.rs68
-rw-r--r--src/librustdoc/html/format.rs3
-rw-r--r--src/librustdoc/html/layout.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs8
-rw-r--r--src/librustdoc/html/render/sidebar.rs16
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css5
-rw-r--r--src/librustdoc/html/templates/page.html2
-rw-r--r--src/librustdoc/html/templates/sidebar.html8
-rw-r--r--src/tools/compiletest/src/runtest.rs1
-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/rustdoc-gui/duplicate-macro-reexport.goml4
-rw-r--r--tests/rustdoc-gui/font-weight.goml4
-rw-r--r--tests/rustdoc-gui/item-info.goml4
-rw-r--r--tests/rustdoc-gui/label-next-to-symbol.goml21
-rw-r--r--tests/rustdoc-gui/notable-trait.goml8
-rw-r--r--tests/rustdoc-gui/search-result-color.goml12
-rw-r--r--tests/rustdoc-gui/sidebar-macro-reexport.goml2
-rw-r--r--tests/rustdoc-gui/sidebar-mobile.goml7
-rw-r--r--tests/rustdoc-gui/sidebar-source-code.goml8
-rw-r--r--tests/rustdoc-gui/source-anchor-scroll.goml2
-rw-r--r--tests/rustdoc/extremely_long_typename.extremely_long_typename.html1
-rw-r--r--tests/rustdoc/extremely_long_typename.rs7
-rw-r--r--tests/rustdoc/item-desc-list-at-start.item-table.html2
-rw-r--r--tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs4
-rw-r--r--tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr16
-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.stderr8
-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/lint/dead-code/offset-of-correct-param-env.rs1
-rw-r--r--tests/ui/lint/dead-code/offset-of.rs1
-rw-r--r--tests/ui/lint/dead-code/offset-of.stderr12
-rw-r--r--tests/ui/lint/dead-code/unconstructible-pub-struct.rs35
-rw-r--r--tests/ui/lint/dead-code/unconstructible-pub-struct.stderr14
-rw-r--r--tests/ui/offset-of/offset-of-enum.rs2
-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-self.stderr14
-rw-r--r--tests/ui/offset-of/offset-of-slice.rs2
-rw-r--r--tests/ui/offset-of/offset-of-tuple-nested.rs2
-rw-r--r--tests/ui/offset-of/offset-of-tuple.rs1
-rw-r--r--tests/ui/offset-of/offset-of-tuple.stderr66
-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/offset-of/offset-of-unstable.stderr16
-rw-r--r--triagebot.toml4
70 files changed, 478 insertions, 378 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 281599a21fc..1a7d7e3f5d7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4826,6 +4826,7 @@ dependencies = [
  "tracing",
  "tracing-subscriber",
  "tracing-tree",
+ "unicode-segmentation",
 ]
 
 [[package]]
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 74d9f9d8f81..9c2a0036bef 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -45,7 +45,7 @@ use rustc_mir_dataflow::impls::{
 use rustc_mir_dataflow::move_paths::{
     InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
 };
-use rustc_mir_dataflow::{Analysis, MoveDataParamEnv};
+use rustc_mir_dataflow::Analysis;
 use rustc_session::lint::builtin::UNUSED_MUT;
 use rustc_span::{Span, Symbol};
 use rustc_target::abi::FieldIdx;
@@ -194,9 +194,7 @@ fn do_mir_borrowck<'tcx>(
         .iter_enumerated()
         .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, param_env, |_| true)));
 
-    let mdpe = MoveDataParamEnv { move_data, param_env };
-
-    let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+    let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint()
@@ -204,7 +202,7 @@ fn do_mir_borrowck<'tcx>(
 
     let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
     let borrow_set =
-        Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
+        Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data));
 
     // Compute non-lexical lifetimes.
     let nll::NllOutput {
@@ -222,7 +220,7 @@ fn do_mir_borrowck<'tcx>(
         &location_table,
         param_env,
         &mut flow_inits,
-        &mdpe.move_data,
+        &move_data,
         &borrow_set,
         tcx.closure_captures(def),
         consumer_options,
@@ -254,11 +252,11 @@ fn do_mir_borrowck<'tcx>(
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
-    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
+    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
-    let flow_ever_inits = EverInitializedPlaces::new(body, &mdpe)
+    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data)
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
@@ -324,7 +322,7 @@ fn do_mir_borrowck<'tcx>(
         infcx: &infcx,
         param_env,
         body,
-        move_data: &mdpe.move_data,
+        move_data: &move_data,
         location_table: &location_table,
         movable_coroutine,
         locals_are_invalidated_at_exit,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0795.md b/compiler/rustc_error_codes/src/error_codes/E0795.md
index ad77d72c913..69e61f7738f 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_enum, offset_of_nested)]
+#![feature(offset_of_enum)]
 
 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_enum, offset_of_nested)]
+#![feature(offset_of_enum)]
 
 let x: usize = std::mem::offset_of!(Option<u8>, Some.0);
 ```
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 46992347f83..99fcc66a4ad 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -292,6 +292,8 @@ declare_features! (
     (accepted, non_exhaustive, "1.40.0", Some(44109)),
     /// Allows `foo.rs` as an alternative to `foo/mod.rs`.
     (accepted, non_modrs_mods, "1.30.0", Some(44660)),
+    /// Allows using multiple nested field accesses in offset_of!
+    (accepted, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(120140)),
     /// Allows the use of or-patterns (e.g., `0 | 1`).
     (accepted, or_patterns, "1.53.0", Some(54883)),
     /// Allows using `+bundle,+whole-archive` link modifiers with native libs.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 7d0ca3a1d0f..a57ff3f7b00 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -560,8 +560,6 @@ declare_features! (
     (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)),
     /// Allows using enums in offset_of!
     (unstable, offset_of_enum, "1.75.0", Some(120141)),
-    /// Allows using multiple nested field accesses in offset_of!
-    (unstable, offset_of_nested, "1.77.0", Some(120140)),
     /// Allows using fields with slice type in offset_of!
     (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)),
     /// Allows using `#[optimize(X)]`.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index f3266e04f81..d75a5f8806b 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -3338,18 +3338,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let container = self.lower_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_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index 4f67a0fa095..bb53eaf6cbd 100644
--- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -3,7 +3,6 @@ use rustc_target::abi::VariantIdx;
 use tracing::debug;
 
 use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex};
-use super::MoveDataParamEnv;
 use crate::elaborate_drops::DropFlagState;
 
 pub fn move_path_children_matching<'tcx, F>(
@@ -70,12 +69,11 @@ pub fn on_all_children_bits<'tcx, F>(
 
 pub fn drop_flag_effects_for_function_entry<'tcx, F>(
     body: &Body<'tcx>,
-    ctxt: &MoveDataParamEnv<'tcx>,
+    move_data: &MoveData<'tcx>,
     mut callback: F,
 ) where
     F: FnMut(MovePathIndex, DropFlagState),
 {
-    let move_data = &ctxt.move_data;
     for arg in body.args_iter() {
         let place = mir::Place::from(arg);
         let lookup_result = move_data.rev_lookup.find(place.as_ref());
@@ -87,13 +85,12 @@ pub fn drop_flag_effects_for_function_entry<'tcx, F>(
 
 pub fn drop_flag_effects_for_location<'tcx, F>(
     body: &Body<'tcx>,
-    ctxt: &MoveDataParamEnv<'tcx>,
+    move_data: &MoveData<'tcx>,
     loc: Location,
     mut callback: F,
 ) where
     F: FnMut(MovePathIndex, DropFlagState),
 {
-    let move_data = &ctxt.move_data;
     debug!("drop_flag_effects_for_location({:?})", loc);
 
     // first, move out of the RHS
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index 77f4dcf892a..e9e8ddefa02 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -11,7 +11,7 @@ use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData
 use crate::{
     drop_flag_effects, drop_flag_effects_for_function_entry, drop_flag_effects_for_location,
     lattice, on_all_children_bits, on_lookup_result_bits, AnalysisDomain, GenKill, GenKillAnalysis,
-    MaybeReachable, MoveDataParamEnv,
+    MaybeReachable,
 };
 
 /// `MaybeInitializedPlaces` tracks all places that might be
@@ -52,17 +52,13 @@ use crate::{
 pub struct MaybeInitializedPlaces<'a, 'mir, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'mir Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
     skip_unreachable_unwind: bool,
 }
 
 impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        body: &'mir Body<'tcx>,
-        mdpe: &'a MoveDataParamEnv<'tcx>,
-    ) -> Self {
-        MaybeInitializedPlaces { tcx, body, mdpe, skip_unreachable_unwind: false }
+    pub fn new(tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
+        MaybeInitializedPlaces { tcx, body, move_data, skip_unreachable_unwind: false }
     }
 
     pub fn skipping_unreachable_unwind(mut self) -> Self {
@@ -89,7 +85,7 @@ impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> {
 
 impl<'a, 'mir, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'mir, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -131,22 +127,18 @@ impl<'a, 'mir, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'mir, 'tcx
 pub struct MaybeUninitializedPlaces<'a, 'mir, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'mir Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
 
     mark_inactive_variants_as_uninit: bool,
     skip_unreachable_unwind: BitSet<mir::BasicBlock>,
 }
 
 impl<'a, 'mir, 'tcx> MaybeUninitializedPlaces<'a, 'mir, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        body: &'mir Body<'tcx>,
-        mdpe: &'a MoveDataParamEnv<'tcx>,
-    ) -> Self {
+    pub fn new(tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
         MaybeUninitializedPlaces {
             tcx,
             body,
-            mdpe,
+            move_data,
             mark_inactive_variants_as_uninit: false,
             skip_unreachable_unwind: BitSet::new_empty(body.basic_blocks.len()),
         }
@@ -173,7 +165,7 @@ impl<'a, 'mir, 'tcx> MaybeUninitializedPlaces<'a, 'mir, 'tcx> {
 
 impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, '_, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -213,18 +205,18 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, '_, 'tcx> {
 /// that would require a dynamic drop-flag at that statement.
 pub struct DefinitelyInitializedPlaces<'a, 'tcx> {
     body: &'a Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
 }
 
 impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
-    pub fn new(body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        DefinitelyInitializedPlaces { body, mdpe }
+    pub fn new(body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
+        DefinitelyInitializedPlaces { body, move_data }
     }
 }
 
 impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -259,18 +251,18 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
 /// ```
 pub struct EverInitializedPlaces<'a, 'mir, 'tcx> {
     body: &'mir Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
+    move_data: &'a MoveData<'tcx>,
 }
 
 impl<'a, 'mir, 'tcx> EverInitializedPlaces<'a, 'mir, 'tcx> {
-    pub fn new(body: &'mir Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        EverInitializedPlaces { body, mdpe }
+    pub fn new(body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
+        EverInitializedPlaces { body, move_data }
     }
 }
 
 impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, '_, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
+        self.move_data
     }
 }
 
@@ -328,7 +320,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         *state =
             MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len()));
-        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
             assert!(s == DropFlagState::Present);
             state.gen_(path);
         });
@@ -348,7 +340,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
 
@@ -380,7 +372,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
         {
             edges = TerminatorEdges::Single(target);
         }
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(state, path, s)
         });
         edges
@@ -465,7 +457,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> {
         // set all bits to 1 (uninit) before gathering counter-evidence
         state.insert_all();
 
-        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
             assert!(s == DropFlagState::Present);
             state.remove(path);
         });
@@ -485,7 +477,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> {
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
 
@@ -499,7 +491,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> {
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
         if self.skip_unreachable_unwind.contains(location.block) {
@@ -592,7 +584,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         state.0.clear();
 
-        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
             assert!(s == DropFlagState::Present);
             state.0.insert(path);
         });
@@ -612,7 +604,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
@@ -623,7 +615,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
         terminator.edges()
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 23bf35b30ca..0171cc85918 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -16,7 +16,7 @@ use crate::impls::{
     DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
 };
 use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
-use crate::{Analysis, JoinSemiLattice, MoveDataParamEnv, ResultsCursor};
+use crate::{Analysis, JoinSemiLattice, ResultsCursor};
 
 pub struct SanityCheck;
 
@@ -46,10 +46,9 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
 
         let param_env = tcx.param_env(def_id);
         let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
-        let mdpe = MoveDataParamEnv { move_data, param_env };
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
-            let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+            let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
@@ -57,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
-            let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
+            let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
@@ -65,7 +64,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
-            let flow_def_inits = DefinitelyInitializedPlaces::new(body, &mdpe)
+            let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 026812852dd..5a22ef77903 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -62,7 +62,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
         let elaborate_patch = {
             let env = MoveDataParamEnv { move_data, param_env };
 
-            let mut inits = MaybeInitializedPlaces::new(tcx, body, &env)
+            let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data)
                 .skipping_unreachable_unwind()
                 .into_engine(tcx, body)
                 .pass_name("elaborate_drops")
@@ -70,7 +70,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
                 .into_results_cursor(body);
             let dead_unwinds = compute_dead_unwinds(body, &mut inits);
 
-            let uninits = MaybeUninitializedPlaces::new(tcx, body, &env)
+            let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data)
                 .mark_inactive_variants_as_uninit()
                 .skipping_unreachable_unwind(dead_unwinds)
                 .into_engine(tcx, body)
@@ -443,9 +443,13 @@ impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> {
 
     fn drop_flags_for_args(&mut self) {
         let loc = Location::START;
-        rustc_mir_dataflow::drop_flag_effects_for_function_entry(self.body, self.env, |path, ds| {
-            self.set_drop_flag(loc, path, ds);
-        })
+        rustc_mir_dataflow::drop_flag_effects_for_function_entry(
+            self.body,
+            &self.env.move_data,
+            |path, ds| {
+                self.set_drop_flag(loc, path, ds);
+            },
+        )
     }
 
     fn drop_flags_for_locs(&mut self) {
@@ -478,7 +482,7 @@ impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> {
                 let loc = Location { block: bb, statement_index: i };
                 rustc_mir_dataflow::drop_flag_effects_for_location(
                     self.body,
-                    self.env,
+                    &self.env.move_data,
                     loc,
                     |path, ds| self.set_drop_flag(loc, path, ds),
                 )
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index d642c307a3f..fae1cb5f7d8 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -3,7 +3,7 @@ use rustc_middle::mir::{Body, TerminatorKind};
 use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, VariantDef};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
-use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable, MoveDataParamEnv};
+use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable};
 use rustc_target::abi::FieldIdx;
 
 use crate::MirPass;
@@ -24,8 +24,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
         let move_data =
             MoveData::gather_moves(body, tcx, param_env, |ty| ty.needs_drop(tcx, param_env));
 
-        let mdpe = MoveDataParamEnv { move_data, param_env };
-        let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+        let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
             .into_engine(tcx, body)
             .pass_name("remove_uninit_drops")
             .iterate_to_fixpoint()
@@ -40,7 +39,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
             let MaybeReachable::Reachable(maybe_inits) = maybe_inits.get() else { continue };
 
             // If there's no move path for the dropped place, it's probably a `Deref`. Let it alone.
-            let LookupResult::Exact(mpi) = mdpe.move_data.rev_lookup.find(place.as_ref()) else {
+            let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) else {
                 continue;
             };
 
@@ -48,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
                 tcx,
                 param_env,
                 maybe_inits,
-                &mdpe.move_data,
+                &move_data,
                 place.ty(body, tcx).ty,
                 mpi,
             );
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 3b1a796130c..8a931fc4158 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -73,24 +73,26 @@ fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
 }
 
 fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool {
-    // treat PhantomData and positional ZST as public,
-    // we don't want to lint types which only have them,
-    // cause it's a common way to use such types to check things like well-formedness
-    tcx.adt_def(id).all_fields().all(|field| {
+    let adt_def = tcx.adt_def(id);
+
+    // skip types contain fields of unit and never type,
+    // it's usually intentional to make the type not constructible
+    let not_require_constructor = adt_def.all_fields().any(|field| {
         let field_type = tcx.type_of(field.did).instantiate_identity();
-        if field_type.is_phantom_data() {
-            return true;
-        }
-        let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
-        if is_positional
-            && tcx
-                .layout_of(tcx.param_env(field.did).and(field_type))
-                .map_or(true, |layout| layout.is_zst())
-        {
-            return true;
-        }
-        field.vis.is_public()
-    })
+        field_type.is_unit() || field_type.is_never()
+    });
+
+    not_require_constructor
+        || adt_def.all_fields().all(|field| {
+            let field_type = tcx.type_of(field.did).instantiate_identity();
+            // skip fields of PhantomData,
+            // cause it's a common way to check things like well-formedness
+            if field_type.is_phantom_data() {
+                return true;
+            }
+
+            field.vis.is_public()
+        })
 }
 
 /// check struct and its fields are public or not,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index a3eca34a35c..d9c7a087739 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -107,6 +107,7 @@
 //
 // Library features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(offset_of_nested))]
 #![feature(array_ptr_get)]
 #![feature(asm_experimental_arch)]
 #![feature(char_indices_offset)]
@@ -172,7 +173,6 @@
 #![feature(isqrt)]
 #![feature(link_cfg)]
 #![feature(offset_of_enum)]
-#![feature(offset_of_nested)]
 #![feature(panic_internals)]
 #![feature(ptr_alignment_type)]
 #![feature(ptr_metadata)]
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index b8e9f606a9a..ea2dcdce6e8 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1321,7 +1321,8 @@ impl<T> SizedTypeProperties for T {}
 /// # Examples
 ///
 /// ```
-/// #![feature(offset_of_enum, offset_of_nested)]
+/// # #![cfg_attr(bootstrap, feature(offset_of_nested))]
+/// #![feature(offset_of_enum)]
 ///
 /// use std::mem;
 /// #[repr(C)]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 5dad5937a60..1e336bf96b8 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -1,6 +1,11 @@
+// tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(offset_of_nested))]
+#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
+#![cfg_attr(test, feature(cfg_match))]
 #![feature(alloc_layout_extra)]
 #![feature(array_chunks)]
 #![feature(array_ptr_get)]
+#![feature(array_try_from_fn)]
 #![feature(array_windows)]
 #![feature(ascii_char)]
 #![feature(ascii_char_variants)]
@@ -9,112 +14,109 @@
 #![feature(bigint_helper_methods)]
 #![feature(cell_update)]
 #![feature(clone_to_uninit)]
-#![feature(const_align_offset)]
 #![feature(const_align_of_val_raw)]
+#![feature(const_align_offset)]
+#![feature(const_array_from_ref)]
 #![feature(const_black_box)]
 #![feature(const_cell_into_inner)]
 #![feature(const_hash)]
 #![feature(const_heap)]
 #![feature(const_intrinsic_copy)]
+#![feature(const_ip)]
+#![feature(const_ipv4)]
+#![feature(const_ipv6)]
+#![feature(const_likely)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
+#![feature(const_mut_refs)]
 #![feature(const_nonnull_new)]
+#![feature(const_option)]
+#![feature(const_option_ext)]
+#![feature(const_pin)]
 #![feature(const_pointer_is_aligned)]
 #![feature(const_ptr_as_ref)]
 #![feature(const_ptr_write)]
+#![feature(const_result)]
+#![feature(const_slice_from_ref)]
 #![feature(const_three_way_compare)]
 #![feature(const_trait_impl)]
-#![feature(const_likely)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
 #![feature(dec2flt)]
-#![feature(duration_consts_float)]
 #![feature(duration_constants)]
 #![feature(duration_constructors)]
+#![feature(duration_consts_float)]
+#![feature(error_generic_member_access)]
 #![feature(exact_size_is_empty)]
 #![feature(extern_types)]
-#![feature(freeze)]
+#![feature(float_minimum_maximum)]
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
-#![feature(float_minimum_maximum)]
+#![feature(freeze)]
 #![feature(future_join)]
 #![feature(generic_assert_internals)]
-#![feature(array_try_from_fn)]
+#![feature(get_many_mut)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
-#![feature(try_find)]
-#![feature(layout_for_ptr)]
-#![feature(pattern)]
-#![feature(slice_take)]
-#![feature(slice_from_ptr_range)]
-#![feature(slice_split_once)]
-#![feature(split_as_slice)]
-#![feature(maybe_uninit_fill)]
-#![feature(maybe_uninit_write_slice)]
-#![feature(maybe_uninit_uninit_array_transpose)]
-#![feature(min_specialization)]
-#![feature(noop_waker)]
-#![feature(numfmt)]
-#![feature(num_midpoint)]
-#![feature(offset_of_nested)]
-#![feature(isqrt)]
-#![feature(unsigned_is_multiple_of)]
-#![feature(step_trait)]
-#![feature(str_internals)]
-#![feature(std_internals)]
-#![feature(test)]
-#![feature(trusted_len)]
-#![feature(try_blocks)]
-#![feature(try_trait_v2)]
-#![feature(slice_internals)]
-#![feature(slice_partition_dedup)]
+#![feature(int_roundings)]
 #![feature(ip)]
+#![feature(is_ascii_octdigit)]
+#![feature(isqrt)]
 #![feature(iter_advance_by)]
 #![feature(iter_array_chunks)]
 #![feature(iter_chain)]
 #![feature(iter_collect_into)]
-#![feature(iter_partition_in_place)]
 #![feature(iter_intersperse)]
 #![feature(iter_is_partitioned)]
+#![feature(iter_map_windows)]
 #![feature(iter_next_chunk)]
 #![feature(iter_order_by)]
+#![feature(iter_partition_in_place)]
 #![feature(iter_repeat_n)]
 #![feature(iterator_try_collect)]
 #![feature(iterator_try_reduce)]
-#![feature(const_ip)]
-#![feature(const_ipv4)]
-#![feature(const_ipv6)]
-#![feature(const_mut_refs)]
-#![feature(const_pin)]
+#![feature(layout_for_ptr)]
+#![feature(maybe_uninit_fill)]
+#![feature(maybe_uninit_uninit_array_transpose)]
+#![feature(maybe_uninit_write_slice)]
+#![feature(min_specialization)]
 #![feature(never_type)]
-#![feature(unwrap_infallible)]
+#![feature(noop_waker)]
+#![feature(num_midpoint)]
+#![feature(numfmt)]
+#![feature(pattern)]
 #![feature(pointer_is_aligned_to)]
 #![feature(portable_simd)]
 #![feature(ptr_metadata)]
-#![feature(unsized_tuple_coercion)]
-#![feature(const_option)]
-#![feature(const_option_ext)]
-#![feature(const_result)]
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
-#![cfg_attr(test, feature(cfg_match))]
-#![feature(int_roundings)]
+#![feature(slice_from_ptr_range)]
+#![feature(slice_internals)]
+#![feature(slice_partition_dedup)]
+#![feature(slice_split_once)]
+#![feature(slice_take)]
 #![feature(split_array)]
+#![feature(split_as_slice)]
+#![feature(std_internals)]
+#![feature(step_trait)]
+#![feature(str_internals)]
 #![feature(strict_provenance)]
 #![feature(strict_provenance_atomic_ptr)]
+#![feature(test)]
+#![feature(trait_upcasting)]
+#![feature(trusted_len)]
 #![feature(trusted_random_access)]
+#![feature(try_blocks)]
+#![feature(try_find)]
+#![feature(try_trait_v2)]
+#![feature(unsigned_is_multiple_of)]
 #![feature(unsize)]
-#![feature(const_array_from_ref)]
-#![feature(const_slice_from_ref)]
+#![feature(unsized_tuple_coercion)]
+#![feature(unwrap_infallible)]
 #![feature(waker_getters)]
-#![feature(error_generic_member_access)]
-#![feature(trait_upcasting)]
-#![feature(is_ascii_octdigit)]
-#![feature(get_many_mut)]
-#![feature(iter_map_windows)]
+// tidy-alphabetical-end
 #![allow(internal_features)]
-#![deny(unsafe_op_in_unsafe_fn)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 mod alloc;
 mod any;
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index ec96307deb2..c40aa718e7c 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2086,7 +2086,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         let git_config = builder.config.git_config();
         cmd.arg("--git-repository").arg(git_config.git_repository);
         cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
-        cmd.force_coloring_in_ci(builder.ci_env);
+        cmd.force_coloring_in_ci();
 
         #[cfg(feature = "build-metrics")]
         builder.metrics.begin_test_suite(
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 9eb4ca033a8..84c23c059e9 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -2157,7 +2157,7 @@ impl<'a> Builder<'a> {
         // Try to use a sysroot-relative bindir, in case it was configured absolutely.
         cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());
 
-        cargo.force_coloring_in_ci(self.ci_env);
+        cargo.force_coloring_in_ci();
 
         // When we build Rust dylibs they're all intended for intermediate
         // usage, so make sure we pass the -Cprefer-dynamic flag instead of
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index b0a967d756b..1343e257efe 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -2092,7 +2092,7 @@ impl Config {
 
         // CI should always run stage 2 builds, unless it specifically states otherwise
         #[cfg(not(test))]
-        if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
+        if flags.stage.is_none() && build_helper::ci::CiEnv::is_ci() {
             match config.cmd {
                 Subcommand::Test { .. }
                 | Subcommand::Miri { .. }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index d2f5d166718..453fb39327d 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -26,7 +26,7 @@ use std::sync::OnceLock;
 use std::time::SystemTime;
 use std::{env, io, str};
 
-use build_helper::ci::{gha, CiEnv};
+use build_helper::ci::gha;
 use build_helper::exit;
 use sha2::digest::Digest;
 use termcolor::{ColorChoice, StandardStream, WriteColor};
@@ -168,7 +168,6 @@ pub struct Build {
     crates: HashMap<String, Crate>,
     crate_paths: HashMap<PathBuf, String>,
     is_sudo: bool,
-    ci_env: CiEnv,
     delayed_failures: RefCell<Vec<String>>,
     prerelease_version: Cell<Option<u32>>,
 
@@ -400,7 +399,6 @@ impl Build {
             crates: HashMap::new(),
             crate_paths: HashMap::new(),
             is_sudo,
-            ci_env: CiEnv::current(),
             delayed_failures: RefCell::new(Vec::new()),
             prerelease_version: Cell::new(None),
 
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index e1387bbbd35..9f0d0b7e969 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -175,8 +175,8 @@ impl BootstrapCommand {
     }
 
     /// If in a CI environment, forces the command to run with colors.
-    pub fn force_coloring_in_ci(&mut self, ci_env: CiEnv) {
-        if ci_env != CiEnv::None {
+    pub fn force_coloring_in_ci(&mut self) {
+        if CiEnv::is_ci() {
             // Due to use of stamp/docker, the output stream of bootstrap is not
             // a TTY in CI, so coloring is by-default turned off.
             // The explicit `TERM=xterm` environment is needed for
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index fe531f0ff59..dfd7414652f 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -23,6 +23,7 @@ tempfile = "3"
 tracing = "0.1"
 tracing-tree = "0.3.0"
 threadpool = "1.8.1"
+unicode-segmentation = "1.9"
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs
index ea4b573aeb9..691f86847b5 100644
--- a/src/librustdoc/html/escape.rs
+++ b/src/librustdoc/html/escape.rs
@@ -5,6 +5,8 @@
 
 use std::fmt;
 
+use unicode_segmentation::UnicodeSegmentation;
+
 /// Wrapper struct which will emit the HTML-escaped version of the contained
 /// string when passed to a format string.
 pub(crate) struct Escape<'a>(pub &'a str);
@@ -74,3 +76,56 @@ impl<'a> fmt::Display for EscapeBodyText<'a> {
         Ok(())
     }
 }
+
+/// Wrapper struct which will emit the HTML-escaped version of the contained
+/// string when passed to a format string. This function also word-breaks
+/// CamelCase and snake_case word names.
+///
+/// This is only safe to use for text nodes. If you need your output to be
+/// safely contained in an attribute, use [`Escape`]. If you don't know the
+/// difference, use [`Escape`].
+pub(crate) struct EscapeBodyTextWithWbr<'a>(pub &'a str);
+
+impl<'a> fmt::Display for EscapeBodyTextWithWbr<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let EscapeBodyTextWithWbr(text) = *self;
+        if text.len() < 8 {
+            return EscapeBodyText(text).fmt(fmt);
+        }
+        let mut last = 0;
+        let mut it = text.grapheme_indices(true).peekable();
+        let _ = it.next(); // don't insert wbr before first char
+        while let Some((i, s)) = it.next() {
+            let pk = it.peek();
+            if s.chars().all(|c| c.is_whitespace()) {
+                // don't need "First <wbr>Second"; the space is enough
+                EscapeBodyText(&text[last..i]).fmt(fmt)?;
+                last = i;
+                continue;
+            }
+            let is_uppercase = || s.chars().any(|c| c.is_uppercase());
+            let next_is_uppercase =
+                || pk.map_or(true, |(_, t)| t.chars().any(|c| c.is_uppercase()));
+            let next_is_underscore = || pk.map_or(true, |(_, t)| t.contains('_'));
+            let next_is_colon = || pk.map_or(true, |(_, t)| t.contains(':'));
+            if i - last > 3 && is_uppercase() && !next_is_uppercase() {
+                EscapeBodyText(&text[last..i]).fmt(fmt)?;
+                fmt.write_str("<wbr>")?;
+                last = i;
+            } else if (s.contains(':') && !next_is_colon())
+                || (s.contains('_') && !next_is_underscore())
+            {
+                EscapeBodyText(&text[last..i + 1]).fmt(fmt)?;
+                fmt.write_str("<wbr>")?;
+                last = i + 1;
+            }
+        }
+        if last < text.len() {
+            EscapeBodyText(&text[last..]).fmt(fmt)?;
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/librustdoc/html/escape/tests.rs b/src/librustdoc/html/escape/tests.rs
new file mode 100644
index 00000000000..a09649e9e18
--- /dev/null
+++ b/src/librustdoc/html/escape/tests.rs
@@ -0,0 +1,68 @@
+// basic examples
+#[test]
+fn escape_body_text_with_wbr() {
+    use super::EscapeBodyTextWithWbr as E;
+    // extreme corner cases
+    assert_eq!(&E("").to_string(), "");
+    assert_eq!(&E("a").to_string(), "a");
+    assert_eq!(&E("A").to_string(), "A");
+    assert_eq!(&E("_").to_string(), "_");
+    assert_eq!(&E(":").to_string(), ":");
+    assert_eq!(&E(" ").to_string(), " ");
+    assert_eq!(&E("___________").to_string(), "___________");
+    assert_eq!(&E(":::::::::::").to_string(), ":::::::::::");
+    assert_eq!(&E("           ").to_string(), "           ");
+    // real(istic) examples
+    assert_eq!(&E("FirstSecond").to_string(), "First<wbr>Second");
+    assert_eq!(&E("First_Second").to_string(), "First_<wbr>Second");
+    assert_eq!(&E("First Second").to_string(), "First Second");
+    assert_eq!(&E("First HSecond").to_string(), "First HSecond");
+    assert_eq!(&E("First HTTPSecond").to_string(), "First HTTP<wbr>Second");
+    assert_eq!(&E("First SecondThird").to_string(), "First Second<wbr>Third");
+    assert_eq!(&E("First<T>_Second").to_string(), "First&lt;<wbr>T&gt;_<wbr>Second");
+    assert_eq!(&E("first_second").to_string(), "first_<wbr>second");
+    assert_eq!(&E("first:second").to_string(), "first:<wbr>second");
+    assert_eq!(&E("first::second").to_string(), "first::<wbr>second");
+    assert_eq!(&E("MY_CONSTANT").to_string(), "MY_<wbr>CONSTANT");
+    // a string won't get wrapped if it's less than 8 bytes
+    assert_eq!(&E("HashSet").to_string(), "HashSet");
+    // an individual word won't get wrapped if it's less than 4 bytes
+    assert_eq!(&E("VecDequeue").to_string(), "VecDequeue");
+    assert_eq!(&E("VecDequeueSet").to_string(), "VecDequeue<wbr>Set");
+    // how to handle acronyms
+    assert_eq!(&E("BTreeMap").to_string(), "BTree<wbr>Map");
+    assert_eq!(&E("HTTPSProxy").to_string(), "HTTPS<wbr>Proxy");
+    // more corners
+    assert_eq!(&E("ṼẽçÑñéå").to_string(), "Ṽẽç<wbr>Ññéå");
+    assert_eq!(&E("V\u{0300}e\u{0300}c\u{0300}D\u{0300}e\u{0300}q\u{0300}u\u{0300}e\u{0300}u\u{0300}e\u{0300}").to_string(), "V\u{0300}e\u{0300}c\u{0300}<wbr>D\u{0300}e\u{0300}q\u{0300}u\u{0300}e\u{0300}u\u{0300}e\u{0300}");
+    assert_eq!(&E("LPFNACCESSIBLEOBJECTFROMWINDOW").to_string(), "LPFNACCESSIBLEOBJECTFROMWINDOW");
+}
+// property test
+#[test]
+fn escape_body_text_with_wbr_makes_sense() {
+    use itertools::Itertools as _;
+
+    use super::EscapeBodyTextWithWbr as E;
+    const C: [u8; 3] = [b'a', b'A', b'_'];
+    for chars in [
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+    ]
+    .into_iter()
+    .multi_cartesian_product()
+    {
+        let s = String::from_utf8(chars).unwrap();
+        assert_eq!(s.len(), 8);
+        let esc = E(&s).to_string();
+        assert!(!esc.contains("<wbr><wbr>"));
+        assert!(!esc.ends_with("<wbr>"));
+        assert!(!esc.starts_with("<wbr>"));
+        assert_eq!(&esc.replace("<wbr>", ""), &s);
+    }
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index d6aed75103d..bb5ac303ffd 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -32,7 +32,7 @@ use crate::clean::utils::find_nearest_parent_module;
 use crate::clean::{self, ExternalCrate, PrimitiveType};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::html::escape::Escape;
+use crate::html::escape::{Escape, EscapeBodyText};
 use crate::html::render::Context;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
@@ -988,6 +988,7 @@ pub(crate) fn anchor<'a, 'cx: 'a>(
                 f,
                 r#"<a class="{short_ty}" href="{url}" title="{short_ty} {path}">{text}</a>"#,
                 path = join_with_double_colon(&fqp),
+                text = EscapeBodyText(text.as_str()),
             )
         } else {
             f.write_str(text.as_str())
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 7dfcc88398f..780cda9b1cd 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -69,6 +69,8 @@ struct PageLayout<'a> {
     display_krate_version_extra: &'a str,
 }
 
+pub(crate) use crate::html::render::sidebar::filters;
+
 pub(crate) fn render<T: Print, S: Print>(
     layout: &Layout,
     page: &Page<'_>,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index aaac8678264..b5cc495ce41 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -30,7 +30,7 @@ mod tests;
 
 mod context;
 mod print_item;
-mod sidebar;
+pub(crate) mod sidebar;
 mod span_map;
 mod type_layout;
 mod write_shared;
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 24476e80778..eec6df9dd20 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -29,7 +29,7 @@ use crate::clean;
 use crate::config::ModuleSorting;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
-use crate::html::escape::Escape;
+use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
 use crate::html::format::{
     display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space,
     print_where_clause, visibility_print_with_space, Buffer, Ending, PrintWithSpace,
@@ -423,7 +423,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                         "<div class=\"item-name\"><code>{}extern crate {} as {};",
                         visibility_print_with_space(myitem, cx),
                         anchor(myitem.item_id.expect_def_id(), src, cx),
-                        myitem.name.unwrap(),
+                        EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     ),
                     None => write!(
                         w,
@@ -520,7 +520,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                         {stab_tags}\
                      </div>\
                      {docs_before}{docs}{docs_after}",
-                    name = myitem.name.unwrap(),
+                    name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     visibility_and_hidden = visibility_and_hidden,
                     stab_tags = extra_info_tags(myitem, item, tcx),
                     class = myitem.type_(),
@@ -558,7 +558,7 @@ fn extra_info_tags<'a, 'tcx: 'a>(
             display_fn(move |f| {
                 write!(
                     f,
-                    r#"<span class="stab {class}" title="{title}">{contents}</span>"#,
+                    r#"<wbr><span class="stab {class}" title="{title}">{contents}</span>"#,
                     title = Escape(title),
                 )
             })
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 6e826446c0e..101cc839f09 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -77,6 +77,22 @@ impl<'a> Link<'a> {
     }
 }
 
+pub(crate) mod filters {
+    use std::fmt::Display;
+
+    use rinja::filters::Safe;
+
+    use crate::html::escape::EscapeBodyTextWithWbr;
+    use crate::html::render::display_fn;
+    pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>>
+    where
+        T: Display,
+    {
+        let string = v.to_string();
+        Ok(Safe(display_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f))))
+    }
+}
+
 pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     let blocks: Vec<LinkBlock<'_>> = match *it.kind {
         clean::StructItem(ref s) => sidebar_struct(cx, it, s),
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index e936e1ca07e..cafe5fe4c87 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -586,12 +586,15 @@ ul.block, .block li {
 }
 
 .sidebar h2 {
+	text-wrap: balance;
 	overflow-wrap: anywhere;
 	padding: 0;
 	margin: 0.7rem 0;
 }
 
 .sidebar h3 {
+	text-wrap: balance;
+	overflow-wrap: anywhere;
 	font-size: 1.125rem; /* 18px */
 	padding: 0;
 	margin: 0;
@@ -2222,7 +2225,7 @@ in src-script.js and main.js
 		width: 33%;
 	}
 	.item-table > li > div {
-		word-break: break-all;
+		overflow-wrap: anywhere;
 	}
 }
 
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index cdf01fa7a97..65c4304e202 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -98,7 +98,7 @@
             </a> {# #}
             {% endif %}
             <h2> {# #}
-                <a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate}}</a> {# #}
+                <a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate|wrapped|safe}}</a> {# #}
                 {% if !display_krate_version_number.is_empty() %}
                     <span class="version">{{+ display_krate_version_number}}</span>
                 {% endif %}
diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html
index 3251b4c14c9..0990c2716b8 100644
--- a/src/librustdoc/html/templates/sidebar.html
+++ b/src/librustdoc/html/templates/sidebar.html
@@ -1,6 +1,6 @@
 {% if !title.is_empty() %}
     <h2 class="location"> {# #}
-        <a href="#">{{title_prefix}}{{title}}</a> {# #}
+        <a href="#">{{title_prefix}}{{title|wrapped|safe}}</a> {# #}
     </h2>
 {% endif %}
 <div class="sidebar-elems">
@@ -15,7 +15,9 @@
             {% for block in blocks %}
                 {% if block.should_render() %}
                     {% if !block.heading.name.is_empty() %}
-                        <h3><a href="#{{block.heading.href|safe}}">{{block.heading.name}}</a></h3>
+                        <h3><a href="#{{block.heading.href|safe}}"> {# #}
+                            {{block.heading.name|wrapped|safe}} {# #}
+                        </a></h3> {# #}
                     {% endif %}
                     {% if !block.links.is_empty() %}
                         <ul class="block{% if !block.class.is_empty() +%} {{+block.class}}{% endif %}">
@@ -29,6 +31,6 @@
         </section>
     {% endif %}
     {% if !path.is_empty() %}
-        <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path}}</a></h2>
+        <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path|wrapped|safe}}</a></h2>
     {% endif %}
 </div>
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index f6e8fdd6244..1f15605d8be 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2731,6 +2731,7 @@ impl<'test> TestCx<'test> {
 
         #[rustfmt::skip]
         let tidy_args = [
+            "--new-blocklevel-tags", "rustdoc-search",
             "--indent", "yes",
             "--indent-spaces", "2",
             "--wrap", "0",
diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs
index 264c8a3d21c..c2f5e83d686 100644
--- a/tests/mir-opt/const_prop/offset_of.rs
+++ b/tests/mir-opt/const_prop/offset_of.rs
@@ -2,7 +2,7 @@
 //@ test-mir-pass: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(offset_of_enum, offset_of_nested)]
+#![feature(offset_of_enum)]
 
 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 12396b31ed0..bb4a74d3712 100644
--- a/tests/mir-opt/dataflow-const-prop/offset_of.rs
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs
@@ -1,8 +1,6 @@
 //@ test-mir-pass: DataflowConstProp
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(offset_of_nested)]
-
 use std::marker::PhantomData;
 use std::mem::offset_of;
 
diff --git a/tests/rustdoc-gui/duplicate-macro-reexport.goml b/tests/rustdoc-gui/duplicate-macro-reexport.goml
index 7d01c88f31b..a838d99c4bf 100644
--- a/tests/rustdoc-gui/duplicate-macro-reexport.goml
+++ b/tests/rustdoc-gui/duplicate-macro-reexport.goml
@@ -4,11 +4,11 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/macro.a.html"
 wait-for: ".sidebar-elems .macro"
 // Check there is only one macro named "a" listed in the sidebar.
 assert-count: (
-    "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[text()='a']",
+    "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[normalize-space()='a']",
     1,
 )
 // Check there is only one macro named "b" listed in the sidebar.
 assert-count: (
-    "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[text()='b']",
+    "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[normalize-space()='b']",
     1,
 )
diff --git a/tests/rustdoc-gui/font-weight.goml b/tests/rustdoc-gui/font-weight.goml
index 602b8d6f5b3..26e9bf515a3 100644
--- a/tests/rustdoc-gui/font-weight.goml
+++ b/tests/rustdoc-gui/font-weight.goml
@@ -1,8 +1,8 @@
 // This test checks that the font weight is correctly applied.
 go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
-assert-css: ("//*[@class='rust item-decl']//a[text()='Alias']", {"font-weight": "400"})
+assert-css: ("//*[@class='rust item-decl']//a[normalize-space()='Alias']", {"font-weight": "400"})
 assert-css: (
-    "//*[@class='structfield section-header']//a[text()='Alias']",
+    "//*[@class='structfield section-header']//a[normalize-space()='Alias']",
     {"font-weight": "400"},
 )
 assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"})
diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml
index 1eb46e832b7..7a0194c6cc1 100644
--- a/tests/rustdoc-gui/item-info.goml
+++ b/tests/rustdoc-gui/item-info.goml
@@ -12,11 +12,11 @@ assert-position: (".item-info .stab", {"x": 245})
 // test for <https://github.com/rust-lang/rust/issues/118615>.
 set-window-size: (850, 800)
 store-position: (
-    "//*[@class='stab portability']//code[text()='Win32_System']",
+    "//*[@class='stab portability']//code[normalize-space()='Win32_System']",
     {"x": first_line_x, "y": first_line_y},
 )
 store-position: (
-    "//*[@class='stab portability']//code[text()='Win32_System_Diagnostics']",
+    "//*[@class='stab portability']//code[normalize-space()='Win32_System_Diagnostics']",
     {"x": second_line_x, "y": second_line_y},
 )
 assert: |first_line_x| != |second_line_x| && |first_line_x| == 516 && |second_line_x| == 272
diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml
index 0582bd2cad3..a8363f29dd5 100644
--- a/tests/rustdoc-gui/label-next-to-symbol.goml
+++ b/tests/rustdoc-gui/label-next-to-symbol.goml
@@ -23,11 +23,12 @@ assert-css: (
 // table like view
 assert-css: (".desc.docblock-short", { "padding-left": "0px" })
 compare-elements-position-near: (
-    "//*[@class='item-name']//a[text()='replaced_function']",
+    "//*[@class='item-name']//a[normalize-space()='replaced_function']",
     ".item-name .stab.deprecated",
     {"y": 2},
 )
-compare-elements-position: (
+// "Unix" part is on second line
+compare-elements-position-false: (
     ".item-name .stab.deprecated",
     ".item-name .stab.portability",
     ["y"],
@@ -35,8 +36,8 @@ compare-elements-position: (
 
 // Ensure no wrap
 compare-elements-position: (
-    "//*[@class='item-name']//a[text()='replaced_function']/..",
-    "//*[@class='desc docblock-short'][text()='a thing with a label']",
+    "//*[@class='item-name']//a[normalize-space()='replaced_function']/..",
+    "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']",
     ["y"],
 )
 
@@ -45,7 +46,7 @@ set-window-size: (600, 600)
 // staggered layout with 2em spacing
 assert-css: (".desc.docblock-short", { "padding-left": "32px" })
 compare-elements-position-near: (
-    "//*[@class='item-name']//a[text()='replaced_function']",
+    "//*[@class='item-name']//a[normalize-space()='replaced_function']",
     ".item-name .stab.deprecated",
     {"y": 2},
 )
@@ -57,13 +58,13 @@ compare-elements-position: (
 
 // Ensure wrap
 compare-elements-position-false: (
-    "//*[@class='item-name']//a[text()='replaced_function']/..",
-    "//*[@class='desc docblock-short'][text()='a thing with a label']",
+    "//*[@class='item-name']//a[normalize-space()='replaced_function']/..",
+    "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']",
     ["y"],
 )
 compare-elements-position-false: (
     ".item-name .stab.deprecated",
-    "//*[@class='desc docblock-short'][text()='a thing with a label']",
+    "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']",
     ["y"],
 )
 
@@ -73,7 +74,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/cfgs/index.html"
 // This part of the tags should not be on the same line as the beginning since the width
 // is too small for that.
 compare-elements-position-false: (
-    "//*[@class='stab portability']/code[text()='appservice-api-c']",
-    "//*[@class='stab portability']/code[text()='server']",
+    "//*[@class='stab portability']/code[normalize-space()='appservice-api-c']",
+    "//*[@class='stab portability']/code[normalize-space()='server']",
     ["y"],
 )
diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml
index 6ee810c5768..e2a8a43007e 100644
--- a/tests/rustdoc-gui/notable-trait.goml
+++ b/tests/rustdoc-gui/notable-trait.goml
@@ -9,19 +9,19 @@ define-function: (
     block {
         // Checking they have the same y position.
         compare-elements-position: (
-            "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
+            "//*[@id='method.create_an_iterator_from_read']//a[normalize-space()='NotableStructWithLongName']",
             "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
             ["y"],
         )
         // Checking they don't have the same x position.
         compare-elements-position-false: (
-            "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
+            "//*[@id='method.create_an_iterator_from_read']//a[normalize-space()='NotableStructWithLongName']",
             "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
             ["x"],
         )
         // The `i` should be *after* the type.
         assert-position: (
-            "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
+            "//*[@id='method.create_an_iterator_from_read']//a[normalize-space()='NotableStructWithLongName']",
             {"x": |x|},
         )
         assert-position: (
@@ -70,7 +70,7 @@ call-function: ("check-notable-tooltip-position-complete", {
 // Now only the `i` should be on the next line.
 set-window-size: (1055, 600)
 compare-elements-position-false: (
-    "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
+    "//*[@id='method.create_an_iterator_from_read']//a[normalize-space()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ["y", "x"],
 )
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index 9825f92b453..e8da43eb896 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -20,11 +20,11 @@ define-function: (
             ALL,
         )
         assert-css: (
-            "//*[@class='desc'][text()='Just a normal struct.']",
+            "//*[@class='desc'][normalize-space()='Just a normal struct.']",
             {"color": |desc_color|},
         )
         assert-css: (
-            "//*[@class='result-name']//*[text()='test_docs::']",
+            "//*[@class='result-name']//*[normalize-space()='test_docs::']",
             {"color": |path_color|},
         )
 
@@ -85,19 +85,19 @@ define-function: (
         move-cursor-to: ".search-input"
         focus: ".search-input" // To ensure the `<a>` container isn't focused or hovered.
         assert-css: (
-            "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a",
+            "//*[@class='result-name']//*[normalize-space()='test_docs::']/ancestor::a",
             {"color": |path_color|, "background-color": "transparent"},
             ALL,
         )
 
         // Checking color and background on hover.
-        move-cursor-to: "//*[@class='desc'][text()='Just a normal struct.']"
+        move-cursor-to: "//*[@class='desc'][normalize-space()='Just a normal struct.']"
         assert-css: (
-            "//*[@class='result-name']//*[text()='test_docs::']",
+            "//*[@class='result-name']//*[normalize-space()='test_docs::']",
             {"color": |hover_path_color|},
         )
         assert-css: (
-            "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a",
+            "//*[@class='result-name']//*[normalize-space()='test_docs::']/ancestor::a",
             {"color": |hover_path_color|, "background-color": |hover_background|},
         )
     }
diff --git a/tests/rustdoc-gui/sidebar-macro-reexport.goml b/tests/rustdoc-gui/sidebar-macro-reexport.goml
index 0f7ef6c3558..cad25507fbb 100644
--- a/tests/rustdoc-gui/sidebar-macro-reexport.goml
+++ b/tests/rustdoc-gui/sidebar-macro-reexport.goml
@@ -2,4 +2,4 @@
 // displayed twice in the sidebar.
 go-to: "file://" + |DOC_PATH| + "/test_docs/macro.repro.html"
 wait-for: ".sidebar-elems .block.macro a"
-assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
+assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[normalize-space()='repro']", 1)
diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml
index b4ff483c180..4ada4837a57 100644
--- a/tests/rustdoc-gui/sidebar-mobile.goml
+++ b/tests/rustdoc-gui/sidebar-mobile.goml
@@ -25,9 +25,12 @@ click: ".sidebar-menu-toggle"
 assert-css: (".sidebar", {"left": "0px"})
 
 // Make sure the "struct Foo" header is hidden, since the mobile topbar already does it.
-assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='Foo']/parent::h2", {"display": "none"})
+assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[normalize-space()='Foo']/parent::h2", {"display": "none"})
 // Make sure the global navigation is still here.
-assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In crate test_docs']/parent::h2", {"display": "block"})
+assert-css: (
+    "//nav[contains(@class, 'sidebar')]//h2/a[normalize-space()='In crate test_docs']/parent::h2",
+    {"display": "block"}
+)
 
 // Click elsewhere.
 click: "body"
diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml
index ef0b5ab38b1..6afccf6a95f 100644
--- a/tests/rustdoc-gui/sidebar-source-code.goml
+++ b/tests/rustdoc-gui/sidebar-source-code.goml
@@ -66,12 +66,12 @@ click: "#sidebar-button"
 // We wait for the sidebar to be expanded.
 wait-for-css: (".src-sidebar-expanded nav.sidebar", {"width": "300px"})
 assert: "//*[@class='dir-entry' and @open]/*[text()='lib2']"
-assert: "//*[@class='dir-entry' and @open]/*[text()='another_folder']"
-assert: "//*[@class='dir-entry' and @open]/*[text()='sub_mod']"
+assert: "//*[@class='dir-entry' and @open]/*[normalize-space()='another_folder']"
+assert: "//*[@class='dir-entry' and @open]/*[normalize-space()='sub_mod']"
 // Only "another_folder" should be "open" in "lib2".
-assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']"
+assert: "//*[@class='dir-entry' and not(@open)]/*[normalize-space()='another_mod']"
 // All other trees should be collapsed.
-assert-count: ("//*[@id='src-sidebar']/details[not(text()='lib2') and not(@open)]", 11)
+assert-count: ("//*[@id='src-sidebar']/details[not(normalize-space()='lib2') and not(@open)]", 11)
 
 // We now switch to mobile mode.
 set-window-size: (600, 600)
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index 940851ea146..3508b26a0bf 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -11,7 +11,7 @@ click: '//a[text() = "barbar" and @href="#5-7"]'
 assert-property: ("html", {"scrollTop": "123"})
 click: '//a[text() = "bar" and @href="#28-36"]'
 assert-property: ("html", {"scrollTop": "154"})
-click: '//a[text() = "sub_fn" and @href="#2-4"]'
+click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
 assert-property: ("html", {"scrollTop": "51"})
 
 // We now check that clicking on lines doesn't change the scroll
diff --git a/tests/rustdoc/extremely_long_typename.extremely_long_typename.html b/tests/rustdoc/extremely_long_typename.extremely_long_typename.html
new file mode 100644
index 00000000000..b20e59866da
--- /dev/null
+++ b/tests/rustdoc/extremely_long_typename.extremely_long_typename.html
@@ -0,0 +1 @@
+<li><div class="item-name"><a class="struct" href="struct.CreateSubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEuBankTransfer.html" title="struct extremely_long_typename::CreateSubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEuBankTransfer">Create<wbr />Subscription<wbr />Payment<wbr />Settings<wbr />Payment<wbr />Method<wbr />Options<wbr />Customer<wbr />Balance<wbr />Bank<wbr />Transfer<wbr />EuBank<wbr />Transfer</a></div></li>
\ No newline at end of file
diff --git a/tests/rustdoc/extremely_long_typename.rs b/tests/rustdoc/extremely_long_typename.rs
new file mode 100644
index 00000000000..212afe2d110
--- /dev/null
+++ b/tests/rustdoc/extremely_long_typename.rs
@@ -0,0 +1,7 @@
+// ignore-tidy-linelength
+// Make sure that, if an extremely long type name is named,
+// the item table has it line wrapped.
+// There should be some reasonably-placed `<wbr>` tags in the snapshot file.
+
+// @snapshot extremely_long_typename "extremely_long_typename/index.html" '//ul[@class="item-table"]/li'
+pub struct CreateSubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEuBankTransfer;
diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc/item-desc-list-at-start.item-table.html
index 72bde573cea..cff4f816529 100644
--- a/tests/rustdoc/item-desc-list-at-start.item-table.html
+++ b/tests/rustdoc/item-desc-list-at-start.item-table.html
@@ -1 +1 @@
-<ul class="item-table"><li><div class="item-name"><a class="constant" href="constant.MY_CONSTANT.html" title="constant item_desc_list_at_start::MY_CONSTANT">MY_CONSTANT</a></div><div class="desc docblock-short">Groups: <code>SamplePatternSGIS</code>, <code>SamplePatternEXT</code></div></li></ul>
\ No newline at end of file
+<ul class="item-table"><li><div class="item-name"><a class="constant" href="constant.MY_CONSTANT.html" title="constant item_desc_list_at_start::MY_CONSTANT">MY_<wbr />CONSTANT</a></div><div class="desc docblock-short">Groups: <code>SamplePatternSGIS</code>, <code>SamplePatternEXT</code></div></li></ul>
\ No newline at end of file
diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
index 885dacc727a..6ab1fb7b039 100644
--- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
+++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
@@ -1,9 +1,9 @@
 #![forbid(dead_code)]
 
 #[derive(Debug)]
-pub struct Whatever { //~ ERROR struct `Whatever` is never constructed
+pub struct Whatever {
     pub field0: (),
-    field1: (),
+    field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
     field2: (),
     field3: (),
     field4: (),
diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
index e10d28ad03a..e9b757b6bae 100644
--- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
+++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
@@ -1,9 +1,19 @@
-error: struct `Whatever` is never constructed
-  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12
+error: fields `field1`, `field2`, `field3`, and `field4` are never read
+  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
    |
 LL | pub struct Whatever {
-   |            ^^^^^^^^
+   |            -------- fields in this struct
+LL |     pub field0: (),
+LL |     field1: (),
+   |     ^^^^^^
+LL |     field2: (),
+   |     ^^^^^^
+LL |     field3: (),
+   |     ^^^^^^
+LL |     field4: (),
+   |     ^^^^^^
    |
+   = note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
 note: the lint level is defined here
   --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11
    |
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 1f2f7ee1e19..cc9efeb67f3 100644
--- a/tests/ui/feature-gates/feature-gate-offset-of-enum.rs
+++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.rs
@@ -1,5 +1,3 @@
-#![feature(offset_of_nested)]
-
 use std::mem::offset_of;
 
 enum Alpha {
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 fc7dd7923f7..8a73abc8cad 100644
--- a/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr
+++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr
@@ -1,5 +1,5 @@
 error[E0573]: expected type, found variant `Alpha::One`
-  --> $DIR/feature-gate-offset-of-enum.rs:11:16
+  --> $DIR/feature-gate-offset-of-enum.rs:9:16
    |
 LL |     offset_of!(Alpha::One, 0);
    |                ^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     offset_of!(Alpha::One, 0);
    |                help: try using the variant's enum: `Alpha`
 
 error[E0658]: using enums in offset_of is experimental
-  --> $DIR/feature-gate-offset-of-enum.rs:12:23
+  --> $DIR/feature-gate-offset-of-enum.rs:10:23
    |
 LL |     offset_of!(Alpha, One);
    |                       ^^^
@@ -18,13 +18,13 @@ LL |     offset_of!(Alpha, One);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0795]: `One` is an enum variant; expected field at end of `offset_of`
-  --> $DIR/feature-gate-offset-of-enum.rs:12:23
+  --> $DIR/feature-gate-offset-of-enum.rs:10:23
    |
 LL |     offset_of!(Alpha, One);
    |                       ^^^ enum variant
 
 error[E0658]: using enums in offset_of is experimental
-  --> $DIR/feature-gate-offset-of-enum.rs:14:23
+  --> $DIR/feature-gate-offset-of-enum.rs:12:23
    |
 LL |     offset_of!(Alpha, Two.0);
    |                       ^^^
diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.rs b/tests/ui/feature-gates/feature-gate-offset-of-nested.rs
deleted file mode 100644
index c4eb4720fde..00000000000
--- a/tests/ui/feature-gates/feature-gate-offset-of-nested.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-#![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
deleted file mode 100644
index f367fc9fa0d..00000000000
--- a/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr
+++ /dev/null
@@ -1,60 +0,0 @@
-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/lint/dead-code/offset-of-correct-param-env.rs b/tests/ui/lint/dead-code/offset-of-correct-param-env.rs
index 61babdeb28b..8cb242f8282 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,5 @@
 //@ check-pass
 
-#![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 5269426d2ff..89e9fd910cb 100644
--- a/tests/ui/lint/dead-code/offset-of.rs
+++ b/tests/ui/lint/dead-code/offset-of.rs
@@ -1,4 +1,3 @@
-#![feature(offset_of_nested)]
 #![deny(dead_code)]
 
 use std::mem::offset_of;
diff --git a/tests/ui/lint/dead-code/offset-of.stderr b/tests/ui/lint/dead-code/offset-of.stderr
index ed2916461cd..4a903a9d6e8 100644
--- a/tests/ui/lint/dead-code/offset-of.stderr
+++ b/tests/ui/lint/dead-code/offset-of.stderr
@@ -1,5 +1,5 @@
 error: field `b` is never read
-  --> $DIR/offset-of.rs:8:5
+  --> $DIR/offset-of.rs:7:5
    |
 LL | struct Alpha {
    |        ----- field in this struct
@@ -8,13 +8,13 @@ LL |     b: (),
    |     ^
    |
 note: the lint level is defined here
-  --> $DIR/offset-of.rs:2:9
+  --> $DIR/offset-of.rs:1:9
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
 
 error: field `a` is never read
-  --> $DIR/offset-of.rs:13:5
+  --> $DIR/offset-of.rs:12:5
    |
 LL | struct Beta {
    |        ---- field in this struct
@@ -22,7 +22,7 @@ LL |     a: (),
    |     ^
 
 error: field `a` is never read
-  --> $DIR/offset-of.rs:18:5
+  --> $DIR/offset-of.rs:17:5
    |
 LL | struct Gamma {
    |        ----- field in this struct
@@ -30,7 +30,7 @@ LL |     a: (),
    |     ^
 
 error: field `b` is never read
-  --> $DIR/offset-of.rs:24:5
+  --> $DIR/offset-of.rs:23:5
    |
 LL | struct Delta {
    |        ----- field in this struct
@@ -39,7 +39,7 @@ LL |     b: (),
    |     ^
 
 error: field `a` is never read
-  --> $DIR/offset-of.rs:35:5
+  --> $DIR/offset-of.rs:34:5
    |
 LL | struct Project<T: Trait> {
    |        ------- field in this struct
diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.rs b/tests/ui/lint/dead-code/unconstructible-pub-struct.rs
new file mode 100644
index 00000000000..2202cbb6730
--- /dev/null
+++ b/tests/ui/lint/dead-code/unconstructible-pub-struct.rs
@@ -0,0 +1,35 @@
+#![feature(never_type)]
+#![deny(dead_code)]
+
+pub struct T1(!);
+pub struct T2(());
+pub struct T3<X>(std::marker::PhantomData<X>);
+
+pub struct T4 {
+    _x: !,
+}
+
+pub struct T5<X> {
+    _x: !,
+    _y: X,
+}
+
+pub struct T6 {
+    _x: (),
+}
+
+pub struct T7<X> {
+    _x: (),
+    _y: X,
+}
+
+pub struct T8<X> {
+    _x: std::marker::PhantomData<X>,
+}
+
+pub struct T9<X> { //~ ERROR struct `T9` is never constructed
+    _x: std::marker::PhantomData<X>,
+    _y: i32,
+}
+
+fn main() {}
diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr b/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr
new file mode 100644
index 00000000000..a3dde042bbe
--- /dev/null
+++ b/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr
@@ -0,0 +1,14 @@
+error: struct `T9` is never constructed
+  --> $DIR/unconstructible-pub-struct.rs:30:12
+   |
+LL | pub struct T9<X> {
+   |            ^^
+   |
+note: the lint level is defined here
+  --> $DIR/unconstructible-pub-struct.rs:2:9
+   |
+LL | #![deny(dead_code)]
+   |         ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs
index cb2f04786ac..64850e47823 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_enum, offset_of_nested)]
+#![feature(offset_of_enum)]
 
 use std::mem::offset_of;
 
diff --git a/tests/ui/offset-of/offset-of-private.rs b/tests/ui/offset-of/offset-of-private.rs
index 1c326b5c79a..8b8ffb5e08e 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_enum, offset_of_nested)]
+#![feature(offset_of_enum)]
 
 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 1558e13b530..e5730b8cf6c 100644
--- a/tests/ui/offset-of/offset-of-self.rs
+++ b/tests/ui/offset-of/offset-of-self.rs
@@ -1,5 +1,3 @@
-#![feature(offset_of_nested)]
-
 use std::mem::offset_of;
 
 struct C<T> {
diff --git a/tests/ui/offset-of/offset-of-self.stderr b/tests/ui/offset-of/offset-of-self.stderr
index 7c7576e066b..5bbb4ecf091 100644
--- a/tests/ui/offset-of/offset-of-self.stderr
+++ b/tests/ui/offset-of/offset-of-self.stderr
@@ -1,11 +1,11 @@
 error: offset_of expects dot-separated field and variant names
-  --> $DIR/offset-of-self.rs:20:26
+  --> $DIR/offset-of-self.rs:18:26
    |
 LL |         offset_of!(Self, Self::v);
    |                          ^^^^^^^
 
 error[E0412]: cannot find type `S` in module `self`
-  --> $DIR/offset-of-self.rs:34:26
+  --> $DIR/offset-of-self.rs:32:26
    |
 LL |         offset_of!(self::S, v);
    |                          ^ not found in `self`
@@ -21,7 +21,7 @@ LL +         offset_of!(S, v);
    |
 
 error[E0411]: cannot find type `Self` in this scope
-  --> $DIR/offset-of-self.rs:51:16
+  --> $DIR/offset-of-self.rs:49:16
    |
 LL | fn main() {
    |    ---- `Self` not allowed in a function
@@ -30,7 +30,7 @@ LL |     offset_of!(Self, v);
    |                ^^^^ `Self` is only available in impls, traits, and type definitions
 
 error[E0609]: no field `Self` on type `S`
-  --> $DIR/offset-of-self.rs:21:23
+  --> $DIR/offset-of-self.rs:19:23
    |
 LL |         offset_of!(S, Self);
    |                       ^^^^
@@ -38,13 +38,13 @@ LL |         offset_of!(S, Self);
    = note: available fields are: `v`, `w`
 
 error[E0616]: field `v` of struct `T` is private
-  --> $DIR/offset-of-self.rs:40:30
+  --> $DIR/offset-of-self.rs:38:30
    |
 LL |             offset_of!(Self, v)
    |                              ^ private field
 
 error[E0609]: no field `self` on type `S`
-  --> $DIR/offset-of-self.rs:53:19
+  --> $DIR/offset-of-self.rs:51:19
    |
 LL |     offset_of!(S, self);
    |                   ^^^^
@@ -52,7 +52,7 @@ LL |     offset_of!(S, self);
    = note: available fields are: `v`, `w`
 
 error[E0609]: no field `self` on type `u8`
-  --> $DIR/offset-of-self.rs:54:21
+  --> $DIR/offset-of-self.rs:52:21
    |
 LL |     offset_of!(S, v.self);
    |                     ^^^^
diff --git a/tests/ui/offset-of/offset-of-slice.rs b/tests/ui/offset-of/offset-of-slice.rs
index a0fe3198f68..e6eb12abd7b 100644
--- a/tests/ui/offset-of/offset-of-slice.rs
+++ b/tests/ui/offset-of/offset-of-slice.rs
@@ -1,5 +1,5 @@
 //@run-pass
-#![feature(offset_of_slice, offset_of_nested)]
+#![feature(offset_of_slice)]
 
 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 4a58b7167cb..210a8b6e897 100644
--- a/tests/ui/offset-of/offset-of-tuple-nested.rs
+++ b/tests/ui/offset-of/offset-of-tuple-nested.rs
@@ -2,8 +2,6 @@
 // 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_nested)]
-
 use std::mem::offset_of;
 
 type ComplexTup = ((u8, (u8, (u8, u16), u8)), (u8, u32, u16));
diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs
index 75ba8d77f2f..b0822352c9d 100644
--- a/tests/ui/offset-of/offset-of-tuple.rs
+++ b/tests/ui/offset-of/offset-of-tuple.rs
@@ -1,4 +1,3 @@
-#![feature(offset_of_nested)]
 #![feature(builtin_syntax)]
 
 use std::mem::offset_of;
diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr
index 1e2d9240267..e6b45c0b6b8 100644
--- a/tests/ui/offset-of/offset-of-tuple.stderr
+++ b/tests/ui/offset-of/offset-of-tuple.stderr
@@ -1,11 +1,11 @@
 error: suffixes on a tuple index are invalid
-  --> $DIR/offset-of-tuple.rs:19:35
+  --> $DIR/offset-of-tuple.rs:18:35
    |
 LL |     builtin # offset_of((u8, u8), 1_u8);
    |                                   ^^^^ invalid suffix `u8`
 
 error: leading `+` is not supported
-  --> $DIR/offset-of-tuple.rs:23:37
+  --> $DIR/offset-of-tuple.rs:22:37
    |
 LL |     { builtin # offset_of((u8, u8), +1) };
    |                                     ^ unexpected `+`
@@ -17,67 +17,67 @@ LL +     { builtin # offset_of((u8, u8), 1) };
    |
 
 error: offset_of expects dot-separated field and variant names
-  --> $DIR/offset-of-tuple.rs:24:38
+  --> $DIR/offset-of-tuple.rs:23:38
    |
 LL |     { builtin # offset_of((u8, u8), 1.) };
    |                                      ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:25:40
+  --> $DIR/offset-of-tuple.rs:24:40
    |
 LL |     { builtin # offset_of((u8, u8), 1 .) };
    |                                        ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:47:45
+  --> $DIR/offset-of-tuple.rs:46:45
    |
 LL |     { builtin # offset_of(ComplexTup, 0.0.1.) };
    |                                             ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:48:46
+  --> $DIR/offset-of-tuple.rs:47:46
    |
 LL |     { builtin # offset_of(ComplexTup, 0 .0.1.) };
    |                                              ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:49:47
+  --> $DIR/offset-of-tuple.rs:48:47
    |
 LL |     { builtin # offset_of(ComplexTup, 0 . 0.1.) };
    |                                               ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:50:46
+  --> $DIR/offset-of-tuple.rs:49:46
    |
 LL |     { builtin # offset_of(ComplexTup, 0. 0.1.) };
    |                                              ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:51:46
+  --> $DIR/offset-of-tuple.rs:50:46
    |
 LL |     { builtin # offset_of(ComplexTup, 0.0 .1.) };
    |                                              ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:52:47
+  --> $DIR/offset-of-tuple.rs:51:47
    |
 LL |     { builtin # offset_of(ComplexTup, 0.0 . 1.) };
    |                                               ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:53:46
+  --> $DIR/offset-of-tuple.rs:52:46
    |
 LL |     { builtin # offset_of(ComplexTup, 0.0. 1.) };
    |                                              ^
 
 error: suffixes on a tuple index are invalid
-  --> $DIR/offset-of-tuple.rs:10:26
+  --> $DIR/offset-of-tuple.rs:9:26
    |
 LL |     offset_of!((u8, u8), 1_u8);
    |                          ^^^^ invalid suffix `u8`
 
 error: no rules expected the token `+`
-  --> $DIR/offset-of-tuple.rs:12:26
+  --> $DIR/offset-of-tuple.rs:11:26
    |
 LL |     offset_of!((u8, u8), +1);
    |                          ^ no rules expected this token in macro call
@@ -86,115 +86,115 @@ note: while trying to match meta-variable `$fields:expr`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
 error: offset_of expects dot-separated field and variant names
-  --> $DIR/offset-of-tuple.rs:13:26
+  --> $DIR/offset-of-tuple.rs:12:26
    |
 LL |     offset_of!((u8, u8), -1);
    |                          ^^
 
 error: offset_of expects dot-separated field and variant names
-  --> $DIR/offset-of-tuple.rs:14:27
+  --> $DIR/offset-of-tuple.rs:13:27
    |
 LL |     offset_of!((u8, u8), 1.);
    |                           ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:15:29
+  --> $DIR/offset-of-tuple.rs:14:29
    |
 LL |     offset_of!((u8, u8), 1 .);
    |                             ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:36:34
+  --> $DIR/offset-of-tuple.rs:35:34
    |
 LL |     offset_of!(ComplexTup, 0.0.1.);
    |                                  ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:37:35
+  --> $DIR/offset-of-tuple.rs:36:35
    |
 LL |     offset_of!(ComplexTup, 0 .0.1.);
    |                                   ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:38:36
+  --> $DIR/offset-of-tuple.rs:37:36
    |
 LL |     offset_of!(ComplexTup, 0 . 0.1.);
    |                                    ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:39:35
+  --> $DIR/offset-of-tuple.rs:38:35
    |
 LL |     offset_of!(ComplexTup, 0. 0.1.);
    |                                   ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:40:35
+  --> $DIR/offset-of-tuple.rs:39:35
    |
 LL |     offset_of!(ComplexTup, 0.0 .1.);
    |                                   ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:41:36
+  --> $DIR/offset-of-tuple.rs:40:36
    |
 LL |     offset_of!(ComplexTup, 0.0 . 1.);
    |                                    ^
 
 error: unexpected token: `)`
-  --> $DIR/offset-of-tuple.rs:42:35
+  --> $DIR/offset-of-tuple.rs:41:35
    |
 LL |     offset_of!(ComplexTup, 0.0. 1.);
    |                                   ^
 
 error[E0609]: no field `_0` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:7:26
+  --> $DIR/offset-of-tuple.rs:6:26
    |
 LL |     offset_of!((u8, u8), _0);
    |                          ^^
 
 error[E0609]: no field `01` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:8:26
+  --> $DIR/offset-of-tuple.rs:7:26
    |
 LL |     offset_of!((u8, u8), 01);
    |                          ^^
 
 error[E0609]: no field `1e2` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:9:26
+  --> $DIR/offset-of-tuple.rs:8:26
    |
 LL |     offset_of!((u8, u8), 1e2);
    |                          ^^^
 
 error[E0609]: no field `1_` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:10:26
+  --> $DIR/offset-of-tuple.rs:9:26
    |
 LL |     offset_of!((u8, u8), 1_u8);
    |                          ^^^^
 
 error[E0609]: no field `1e2` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:16:35
+  --> $DIR/offset-of-tuple.rs:15:35
    |
 LL |     builtin # offset_of((u8, u8), 1e2);
    |                                   ^^^
 
 error[E0609]: no field `_0` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:17:35
+  --> $DIR/offset-of-tuple.rs:16:35
    |
 LL |     builtin # offset_of((u8, u8), _0);
    |                                   ^^
 
 error[E0609]: no field `01` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:18:35
+  --> $DIR/offset-of-tuple.rs:17:35
    |
 LL |     builtin # offset_of((u8, u8), 01);
    |                                   ^^
 
 error[E0609]: no field `1_` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:19:35
+  --> $DIR/offset-of-tuple.rs:18:35
    |
 LL |     builtin # offset_of((u8, u8), 1_u8);
    |                                   ^^^^
 
 error[E0609]: no field `2` on type `(u8, u16)`
-  --> $DIR/offset-of-tuple.rs:31:47
+  --> $DIR/offset-of-tuple.rs:30:47
    |
 LL |       offset_of!(((u8, u16), (u32, u16, u8)), 0.2);
    |  _____------------------------------------------^-
@@ -207,7 +207,7 @@ LL | |     offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0609]: no field `0` on type `u8`
-  --> $DIR/offset-of-tuple.rs:33:49
+  --> $DIR/offset-of-tuple.rs:32:49
    |
 LL |     offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0);
    |                                                 ^
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 c9d4f30e99a..c2614ba3d8a 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_nested, unstable_test_feature)]
+#![feature(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 ab6f89ce52a..d249e8871c3 100644
--- a/tests/ui/offset-of/offset-of-unstable.rs
+++ b/tests/ui/offset-of/offset-of-unstable.rs
@@ -1,7 +1,5 @@
 //@ aux-build:offset-of-staged-api.rs
 
-#![feature(offset_of_nested)]
-
 use std::mem::offset_of;
 
 extern crate offset_of_staged_api;
diff --git a/tests/ui/offset-of/offset-of-unstable.stderr b/tests/ui/offset-of/offset-of-unstable.stderr
index 4882dee4042..44ccad3ff39 100644
--- a/tests/ui/offset-of/offset-of-unstable.stderr
+++ b/tests/ui/offset-of/offset-of-unstable.stderr
@@ -1,5 +1,5 @@
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:14:9
+  --> $DIR/offset-of-unstable.rs:12:9
    |
 LL |         Unstable,
    |         ^^^^^^^^
@@ -8,7 +8,7 @@ LL |         Unstable,
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:23:9
+  --> $DIR/offset-of-unstable.rs:21:9
    |
 LL |         UnstableWithStableFieldType,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |         UnstableWithStableFieldType,
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:28:9
+  --> $DIR/offset-of-unstable.rs:26:9
    |
 LL |         UnstableWithStableFieldType,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |         UnstableWithStableFieldType,
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:12:5
+  --> $DIR/offset-of-unstable.rs:10:5
    |
 LL | /     offset_of!(
 LL | |
@@ -40,7 +40,7 @@ LL | |     );
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:18:5
+  --> $DIR/offset-of-unstable.rs:16:5
    |
 LL |     offset_of!(StableWithUnstableField, unstable);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL |     offset_of!(StableWithUnstableField, unstable);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:20:5
+  --> $DIR/offset-of-unstable.rs:18:5
    |
 LL |     offset_of!(StableWithUnstableFieldType, stable.unstable);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     offset_of!(StableWithUnstableFieldType, stable.unstable);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:21:5
+  --> $DIR/offset-of-unstable.rs:19:5
    |
 LL | /     offset_of!(
 LL | |
@@ -74,7 +74,7 @@ LL | |     );
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
-  --> $DIR/offset-of-unstable.rs:26:5
+  --> $DIR/offset-of-unstable.rs:24:5
    |
 LL | /     offset_of!(
 LL | |
diff --git a/triagebot.toml b/triagebot.toml
index 5c5aa475385..2795f937284 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -852,7 +852,7 @@ cc = ["@Urgau"]
 cc = ["@Urgau"]
 
 [mentions."src/doc/rustc/src/platform-support"]
-cc = ["@Nilstrieb"]
+cc = ["@Noratrieb"]
 
 [mentions."tests/codegen/sanitizer"]
 cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
@@ -938,7 +938,7 @@ libs = [
     "@cuviper",
     "@Mark-Simulacrum",
     "@Amanieu",
-    "@Nilstrieb",
+    "@Noratrieb",
     "@workingjubilee",
     "@joboet",
     "@jhpratt",