about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-12-15 11:08:21 +0000
committerbors <bors@rust-lang.org>2024-12-15 11:08:21 +0000
commit0894fb0fbf457916bb013168476d802852d9dd6a (patch)
tree9f2cff703de820bf5898feea9d58327fd5953744
parent87139bd9cfb999eff4025ff3d2ab5659c8082678 (diff)
parent6c75fc848da25c961c3b20cedab1f9c962b02b94 (diff)
Auto merge of #134332 - Zalathar:rollup-oe23hkw, r=Zalathar
Rollup of 7 pull requests

Successful merges:

 - #130361 (std::net: Solaris supports `SOCK_CLOEXEC` as well since 11.4.)
 - #133406 (Add value accessor methods to `Mutex` and `RwLock`)
 - #133633 (don't show the full linker args unless `--verbose` is passed)
 - #134285 (Add some convenience helper methods on `hir::Safety`)
 - #134310 (Add clarity to the examples of some `Vec` & `VecDeque` methods)
 - #134313 (Don't make a def id for `impl_trait_in_bindings`)
 - #134315 (A couple of polonius fact generation cleanups)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/nll.rs2
-rw-r--r--compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs (renamed from compiler/rustc_borrowck/src/polonius/loan_invalidations.rs)0
-rw-r--r--compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs (renamed from compiler/rustc_borrowck/src/polonius/loan_kills.rs)0
-rw-r--r--compiler/rustc_borrowck/src/polonius/legacy/mod.rs184
-rw-r--r--compiler/rustc_borrowck/src/polonius/mod.rs185
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs143
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs70
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs5
-rw-r--r--compiler/rustc_hir/src/hir.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs16
-rw-r--r--compiler/rustc_passes/src/check_attr.rs4
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs9
-rw-r--r--compiler/rustc_resolve/src/lib.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs23
-rw-r--r--library/alloc/src/vec/mod.rs28
-rw-r--r--library/core/src/slice/mod.rs24
-rw-r--r--library/std/src/sync/mutex.rs110
-rw-r--r--library/std/src/sync/mutex/tests.rs161
-rw-r--r--library/std/src/sync/poison.rs35
-rw-r--r--library/std/src/sync/rwlock.rs128
-rw-r--r--library/std/src/sync/rwlock/tests.rs169
-rw-r--r--library/std/src/sys/pal/unix/net.rs1
-rw-r--r--src/librustdoc/html/format.rs5
-rw-r--r--src/librustdoc/html/render/print_item.rs6
-rw-r--r--src/librustdoc/json/conversions.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs10
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs6
-rw-r--r--tests/run-make/link-args-order/rmake.rs6
-rw-r--r--tests/run-make/link-dedup/rmake.rs12
-rw-r--r--tests/run-make/linker-warning/fake-linker.rs13
-rw-r--r--tests/run-make/linker-warning/main.rs1
-rw-r--r--tests/run-make/linker-warning/rmake.rs28
-rw-r--r--tests/ui/impl-trait/in-bindings/dont-make-def-id.rs10
56 files changed, 1030 insertions, 471 deletions
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index be02e2f48df..d7ea8e1bcc2 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -116,7 +116,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
     let var_origins = infcx.get_region_var_origins();
 
     // If requested, emit legacy polonius facts.
-    polonius::emit_facts(
+    polonius::legacy::emit_facts(
         &mut all_facts,
         infcx.tcx,
         location_table,
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
index f646beeecf7..f646beeecf7 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs
index 68e0865ab82..68e0865ab82 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_kills.rs
+++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs
diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs
new file mode 100644
index 00000000000..9fccc00bdaf
--- /dev/null
+++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs
@@ -0,0 +1,184 @@
+//! Functions dedicated to fact generation for the `-Zpolonius=legacy` datalog implementation.
+//!
+//! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature
+//! parity.
+
+use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK};
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
+use tracing::debug;
+
+use crate::borrow_set::BorrowSet;
+use crate::facts::{AllFacts, PoloniusRegionVid};
+use crate::location::LocationTable;
+use crate::type_check::free_region_relations::UniversalRegionRelations;
+
+mod loan_invalidations;
+mod loan_kills;
+
+/// When requested, emit most of the facts needed by polonius:
+/// - moves and assignments
+/// - universal regions and their relations
+/// - CFG points and edges
+/// - loan kills
+/// - loan invalidations
+///
+/// The rest of the facts are emitted during typeck and liveness.
+pub(crate) fn emit_facts<'tcx>(
+    all_facts: &mut Option<AllFacts>,
+    tcx: TyCtxt<'tcx>,
+    location_table: &LocationTable,
+    body: &Body<'tcx>,
+    borrow_set: &BorrowSet<'tcx>,
+    move_data: &MoveData<'_>,
+    universal_region_relations: &UniversalRegionRelations<'_>,
+) {
+    let Some(all_facts) = all_facts else {
+        // We don't do anything if there are no facts to fill.
+        return;
+    };
+    let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
+    emit_move_facts(all_facts, move_data, location_table, body);
+    emit_universal_region_facts(all_facts, borrow_set, universal_region_relations);
+    emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
+    emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
+}
+
+/// Emit facts needed for move/init analysis: moves and assignments.
+fn emit_move_facts(
+    all_facts: &mut AllFacts,
+    move_data: &MoveData<'_>,
+    location_table: &LocationTable,
+    body: &Body<'_>,
+) {
+    all_facts
+        .path_is_var
+        .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
+
+    for (child, move_path) in move_data.move_paths.iter_enumerated() {
+        if let Some(parent) = move_path.parent {
+            all_facts.child_path.push((child, parent));
+        }
+    }
+
+    let fn_entry_start =
+        location_table.start_index(Location { block: START_BLOCK, statement_index: 0 });
+
+    // initialized_at
+    for init in move_data.inits.iter() {
+        match init.location {
+            InitLocation::Statement(location) => {
+                let block_data = &body[location.block];
+                let is_terminator = location.statement_index == block_data.statements.len();
+
+                if is_terminator && init.kind == InitKind::NonPanicPathOnly {
+                    // We are at the terminator of an init that has a panic path,
+                    // and where the init should not happen on panic
+
+                    for successor in block_data.terminator().successors() {
+                        if body[successor].is_cleanup {
+                            continue;
+                        }
+
+                        // The initialization happened in (or rather, when arriving at)
+                        // the successors, but not in the unwind block.
+                        let first_statement = Location { block: successor, statement_index: 0 };
+                        all_facts
+                            .path_assigned_at_base
+                            .push((init.path, location_table.start_index(first_statement)));
+                    }
+                } else {
+                    // In all other cases, the initialization just happens at the
+                    // midpoint, like any other effect.
+                    all_facts
+                        .path_assigned_at_base
+                        .push((init.path, location_table.mid_index(location)));
+                }
+            }
+            // Arguments are initialized on function entry
+            InitLocation::Argument(local) => {
+                assert!(body.local_kind(local) == LocalKind::Arg);
+                all_facts.path_assigned_at_base.push((init.path, fn_entry_start));
+            }
+        }
+    }
+
+    for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
+        if body.local_kind(local) != LocalKind::Arg {
+            // Non-arguments start out deinitialised; we simulate this with an
+            // initial move:
+            all_facts.path_moved_at_base.push((path, fn_entry_start));
+        }
+    }
+
+    // moved_out_at
+    // deinitialisation is assumed to always happen!
+    all_facts
+        .path_moved_at_base
+        .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
+}
+
+/// Emit universal regions facts, and their relations.
+fn emit_universal_region_facts(
+    all_facts: &mut AllFacts,
+    borrow_set: &BorrowSet<'_>,
+    universal_region_relations: &UniversalRegionRelations<'_>,
+) {
+    // 1: universal regions are modeled in Polonius as a pair:
+    // - the universal region vid itself.
+    // - a "placeholder loan" associated to this universal region. Since they don't exist in
+    //   the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
+    //   added to the existing number of loans, as if they succeeded them in the set.
+    //
+    let universal_regions = &universal_region_relations.universal_regions;
+    all_facts
+        .universal_region
+        .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from));
+    let borrow_count = borrow_set.len();
+    debug!(
+        "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
+        universal_regions.len(),
+        borrow_count
+    );
+
+    for universal_region in universal_regions.universal_regions_iter() {
+        let universal_region_idx = universal_region.index();
+        let placeholder_loan_idx = borrow_count + universal_region_idx;
+        all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
+    }
+
+    // 2: the universal region relations `outlives` constraints are emitted as
+    //  `known_placeholder_subset` facts.
+    for (fr1, fr2) in universal_region_relations.known_outlives() {
+        if fr1 != fr2 {
+            debug!(
+                "emit_universal_region_facts: emitting polonius `known_placeholder_subset` \
+                     fr1={:?}, fr2={:?}",
+                fr1, fr2
+            );
+            all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
+        }
+    }
+}
+
+/// Emit facts about loan invalidations.
+fn emit_loan_invalidations_facts<'tcx>(
+    all_facts: &mut AllFacts,
+    tcx: TyCtxt<'tcx>,
+    location_table: &LocationTable,
+    body: &Body<'tcx>,
+    borrow_set: &BorrowSet<'tcx>,
+) {
+    loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set);
+}
+
+/// Emit facts about CFG points and edges, as well as locations where loans are killed.
+fn emit_cfg_and_loan_kills_facts<'tcx>(
+    all_facts: &mut AllFacts,
+    tcx: TyCtxt<'tcx>,
+    location_table: &LocationTable,
+    body: &Body<'tcx>,
+    borrow_set: &BorrowSet<'tcx>,
+) {
+    loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set);
+}
diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs
index 9fccc00bdaf..9c1583f1988 100644
--- a/compiler/rustc_borrowck/src/polonius/mod.rs
+++ b/compiler/rustc_borrowck/src/polonius/mod.rs
@@ -1,184 +1 @@
-//! Functions dedicated to fact generation for the `-Zpolonius=legacy` datalog implementation.
-//!
-//! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature
-//! parity.
-
-use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK};
-use rustc_middle::ty::TyCtxt;
-use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
-use tracing::debug;
-
-use crate::borrow_set::BorrowSet;
-use crate::facts::{AllFacts, PoloniusRegionVid};
-use crate::location::LocationTable;
-use crate::type_check::free_region_relations::UniversalRegionRelations;
-
-mod loan_invalidations;
-mod loan_kills;
-
-/// When requested, emit most of the facts needed by polonius:
-/// - moves and assignments
-/// - universal regions and their relations
-/// - CFG points and edges
-/// - loan kills
-/// - loan invalidations
-///
-/// The rest of the facts are emitted during typeck and liveness.
-pub(crate) fn emit_facts<'tcx>(
-    all_facts: &mut Option<AllFacts>,
-    tcx: TyCtxt<'tcx>,
-    location_table: &LocationTable,
-    body: &Body<'tcx>,
-    borrow_set: &BorrowSet<'tcx>,
-    move_data: &MoveData<'_>,
-    universal_region_relations: &UniversalRegionRelations<'_>,
-) {
-    let Some(all_facts) = all_facts else {
-        // We don't do anything if there are no facts to fill.
-        return;
-    };
-    let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
-    emit_move_facts(all_facts, move_data, location_table, body);
-    emit_universal_region_facts(all_facts, borrow_set, universal_region_relations);
-    emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
-    emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
-}
-
-/// Emit facts needed for move/init analysis: moves and assignments.
-fn emit_move_facts(
-    all_facts: &mut AllFacts,
-    move_data: &MoveData<'_>,
-    location_table: &LocationTable,
-    body: &Body<'_>,
-) {
-    all_facts
-        .path_is_var
-        .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
-
-    for (child, move_path) in move_data.move_paths.iter_enumerated() {
-        if let Some(parent) = move_path.parent {
-            all_facts.child_path.push((child, parent));
-        }
-    }
-
-    let fn_entry_start =
-        location_table.start_index(Location { block: START_BLOCK, statement_index: 0 });
-
-    // initialized_at
-    for init in move_data.inits.iter() {
-        match init.location {
-            InitLocation::Statement(location) => {
-                let block_data = &body[location.block];
-                let is_terminator = location.statement_index == block_data.statements.len();
-
-                if is_terminator && init.kind == InitKind::NonPanicPathOnly {
-                    // We are at the terminator of an init that has a panic path,
-                    // and where the init should not happen on panic
-
-                    for successor in block_data.terminator().successors() {
-                        if body[successor].is_cleanup {
-                            continue;
-                        }
-
-                        // The initialization happened in (or rather, when arriving at)
-                        // the successors, but not in the unwind block.
-                        let first_statement = Location { block: successor, statement_index: 0 };
-                        all_facts
-                            .path_assigned_at_base
-                            .push((init.path, location_table.start_index(first_statement)));
-                    }
-                } else {
-                    // In all other cases, the initialization just happens at the
-                    // midpoint, like any other effect.
-                    all_facts
-                        .path_assigned_at_base
-                        .push((init.path, location_table.mid_index(location)));
-                }
-            }
-            // Arguments are initialized on function entry
-            InitLocation::Argument(local) => {
-                assert!(body.local_kind(local) == LocalKind::Arg);
-                all_facts.path_assigned_at_base.push((init.path, fn_entry_start));
-            }
-        }
-    }
-
-    for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
-        if body.local_kind(local) != LocalKind::Arg {
-            // Non-arguments start out deinitialised; we simulate this with an
-            // initial move:
-            all_facts.path_moved_at_base.push((path, fn_entry_start));
-        }
-    }
-
-    // moved_out_at
-    // deinitialisation is assumed to always happen!
-    all_facts
-        .path_moved_at_base
-        .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
-}
-
-/// Emit universal regions facts, and their relations.
-fn emit_universal_region_facts(
-    all_facts: &mut AllFacts,
-    borrow_set: &BorrowSet<'_>,
-    universal_region_relations: &UniversalRegionRelations<'_>,
-) {
-    // 1: universal regions are modeled in Polonius as a pair:
-    // - the universal region vid itself.
-    // - a "placeholder loan" associated to this universal region. Since they don't exist in
-    //   the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
-    //   added to the existing number of loans, as if they succeeded them in the set.
-    //
-    let universal_regions = &universal_region_relations.universal_regions;
-    all_facts
-        .universal_region
-        .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from));
-    let borrow_count = borrow_set.len();
-    debug!(
-        "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
-        universal_regions.len(),
-        borrow_count
-    );
-
-    for universal_region in universal_regions.universal_regions_iter() {
-        let universal_region_idx = universal_region.index();
-        let placeholder_loan_idx = borrow_count + universal_region_idx;
-        all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
-    }
-
-    // 2: the universal region relations `outlives` constraints are emitted as
-    //  `known_placeholder_subset` facts.
-    for (fr1, fr2) in universal_region_relations.known_outlives() {
-        if fr1 != fr2 {
-            debug!(
-                "emit_universal_region_facts: emitting polonius `known_placeholder_subset` \
-                     fr1={:?}, fr2={:?}",
-                fr1, fr2
-            );
-            all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
-        }
-    }
-}
-
-/// Emit facts about loan invalidations.
-fn emit_loan_invalidations_facts<'tcx>(
-    all_facts: &mut AllFacts,
-    tcx: TyCtxt<'tcx>,
-    location_table: &LocationTable,
-    body: &Body<'tcx>,
-    borrow_set: &BorrowSet<'tcx>,
-) {
-    loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set);
-}
-
-/// Emit facts about CFG points and edges, as well as locations where loans are killed.
-fn emit_cfg_and_loan_kills_facts<'tcx>(
-    all_facts: &mut AllFacts,
-    tcx: TyCtxt<'tcx>,
-    location_table: &LocationTable,
-    body: &Body<'tcx>,
-    borrow_set: &BorrowSet<'tcx>,
-) {
-    loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set);
-}
+pub(crate) mod legacy;
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index 20d19a53752..05e4a176a6d 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -45,7 +45,7 @@ pub(super) fn generate<'a, 'tcx>(
     let (relevant_live_locals, boring_locals) =
         compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
 
-    polonius::populate_access_facts(typeck, body, move_data);
+    polonius::emit_access_facts(typeck, body, move_data);
 
     trace::trace(
         typeck,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index e8d8ae0850b..5ffba94ee68 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -11,88 +11,19 @@ use crate::location::{LocationIndex, LocationTable};
 type VarPointRelation = Vec<(Local, LocationIndex)>;
 type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;
 
-struct UseFactsExtractor<'a, 'tcx> {
-    var_defined_at: &'a mut VarPointRelation,
-    var_used_at: &'a mut VarPointRelation,
-    location_table: &'a LocationTable,
-    var_dropped_at: &'a mut VarPointRelation,
-    move_data: &'a MoveData<'tcx>,
-    path_accessed_at_base: &'a mut PathPointRelation,
-}
-
-// A Visitor to walk through the MIR and extract point-wise facts
-impl<'tcx> UseFactsExtractor<'_, 'tcx> {
-    fn location_to_index(&self, location: Location) -> LocationIndex {
-        self.location_table.mid_index(location)
-    }
-
-    fn insert_def(&mut self, local: Local, location: Location) {
-        debug!("UseFactsExtractor::insert_def()");
-        self.var_defined_at.push((local, self.location_to_index(location)));
-    }
-
-    fn insert_use(&mut self, local: Local, location: Location) {
-        debug!("UseFactsExtractor::insert_use()");
-        self.var_used_at.push((local, self.location_to_index(location)));
-    }
-
-    fn insert_drop_use(&mut self, local: Local, location: Location) {
-        debug!("UseFactsExtractor::insert_drop_use()");
-        self.var_dropped_at.push((local, self.location_to_index(location)));
-    }
-
-    fn insert_path_access(&mut self, path: MovePathIndex, location: Location) {
-        debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location);
-        self.path_accessed_at_base.push((path, self.location_to_index(location)));
-    }
-
-    fn place_to_mpi(&self, place: &Place<'tcx>) -> Option<MovePathIndex> {
-        match self.move_data.rev_lookup.find(place.as_ref()) {
-            LookupResult::Exact(mpi) => Some(mpi),
-            LookupResult::Parent(mmpi) => mmpi,
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for UseFactsExtractor<'a, 'tcx> {
-    fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
-        match def_use::categorize(context) {
-            Some(DefUse::Def) => self.insert_def(local, location),
-            Some(DefUse::Use) => self.insert_use(local, location),
-            Some(DefUse::Drop) => self.insert_drop_use(local, location),
-            _ => (),
-        }
-    }
-
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
-        self.super_place(place, context, location);
-        match context {
-            PlaceContext::NonMutatingUse(_) => {
-                if let Some(mpi) = self.place_to_mpi(place) {
-                    self.insert_path_access(mpi, location);
-                }
-            }
-
-            PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
-                if let Some(mpi) = self.place_to_mpi(place) {
-                    self.insert_path_access(mpi, location);
-                }
-            }
-            _ => (),
-        }
-    }
-}
-
-pub(super) fn populate_access_facts<'a, 'tcx>(
+/// Emit polonius facts for variable defs, uses, drops, and path accesses.
+pub(super) fn emit_access_facts<'a, 'tcx>(
     typeck: &mut TypeChecker<'a, 'tcx>,
     body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
 ) {
     if let Some(facts) = typeck.all_facts.as_mut() {
-        debug!("populate_access_facts()");
+        debug!("emit_access_facts()");
+
+        let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
         let location_table = typeck.location_table;
 
-        let mut extractor = UseFactsExtractor {
+        let mut extractor = AccessFactsExtractor {
             var_defined_at: &mut facts.var_defined_at,
             var_used_at: &mut facts.var_used_at,
             var_dropped_at: &mut facts.var_dropped_at,
@@ -107,7 +38,6 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
                 "add use_of_var_derefs_origin facts - local={:?}, type={:?}",
                 local, local_decl.ty
             );
-            let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
             let universal_regions = &typeck.universal_regions;
             typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
                 let region_vid = universal_regions.to_region_vid(region);
@@ -119,12 +49,12 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
 
 /// For every potentially drop()-touched region `region` in `local`'s type
 /// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
-pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
+pub(super) fn emit_drop_facts<'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     local: Local,
     kind: &GenericArg<'tcx>,
 ) {
-    debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind);
+    debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
     if let Some(facts) = typeck.all_facts.as_mut() {
         let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
         let universal_regions = &typeck.universal_regions;
@@ -134,3 +64,60 @@ pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
         });
     }
 }
+
+/// MIR visitor extracting point-wise facts about accesses.
+struct AccessFactsExtractor<'a, 'tcx> {
+    var_defined_at: &'a mut VarPointRelation,
+    var_used_at: &'a mut VarPointRelation,
+    location_table: &'a LocationTable,
+    var_dropped_at: &'a mut VarPointRelation,
+    move_data: &'a MoveData<'tcx>,
+    path_accessed_at_base: &'a mut PathPointRelation,
+}
+
+impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
+    fn location_to_index(&self, location: Location) -> LocationIndex {
+        self.location_table.mid_index(location)
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
+        match def_use::categorize(context) {
+            Some(DefUse::Def) => {
+                debug!("AccessFactsExtractor - emit def");
+                self.var_defined_at.push((local, self.location_to_index(location)));
+            }
+            Some(DefUse::Use) => {
+                debug!("AccessFactsExtractor - emit use");
+                self.var_used_at.push((local, self.location_to_index(location)));
+            }
+            Some(DefUse::Drop) => {
+                debug!("AccessFactsExtractor - emit drop");
+                self.var_dropped_at.push((local, self.location_to_index(location)));
+            }
+            _ => (),
+        }
+    }
+
+    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
+        self.super_place(place, context, location);
+
+        match context {
+            PlaceContext::NonMutatingUse(_)
+            | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
+                let path = match self.move_data.rev_lookup.find(place.as_ref()) {
+                    LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path,
+                    _ => {
+                        // There's no path access to emit.
+                        return;
+                    }
+                };
+                debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})");
+                self.path_accessed_at_base.push((path, self.location_to_index(location)));
+            }
+
+            _ => {}
+        }
+    }
+}
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 3ec36c16cbf..539d3f97a63 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -590,7 +590,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         // the destructor and must be live at this point.
         for &kind in &drop_data.dropck_result.kinds {
             Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
-            polonius::add_drop_of_var_derefs_origin(self.typeck, dropped_local, &kind);
+            polonius::emit_drop_facts(self.typeck, dropped_local, &kind);
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 31ac8c6e66a..cfd40a575b1 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -986,12 +986,12 @@ fn link_natively(
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 let escaped_output = escape_linker_output(&output, flavor);
-                // FIXME: Add UI tests for this error.
                 let err = errors::LinkingFailed {
                     linker_path: &linker_path,
                     exit_status: prog.status,
-                    command: &cmd,
+                    command: cmd,
                     escaped_output,
+                    verbose: sess.opts.verbose,
                 };
                 sess.dcx().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index ab2d24e8d2d..12c5065cd71 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -6,7 +6,7 @@ use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
-use rustc_hir::{self as hir, HirId, LangItem, lang_items};
+use rustc_hir::{HirId, LangItem, lang_items};
 use rustc_middle::middle::codegen_fn_attrs::{
     CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
 };
@@ -251,7 +251,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             sym::target_feature => {
                 if !tcx.is_closure_like(did.to_def_id())
                     && let Some(fn_sig) = fn_sig()
-                    && fn_sig.skip_binder().safety() == hir::Safety::Safe
+                    && fn_sig.skip_binder().safety().is_safe()
                 {
                     if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
                         // The `#[target_feature]` attribute is allowed on
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 00f8654e670..c7213bbc801 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,6 +1,7 @@
 //! Errors emitted by codegen_ssa
 
 use std::borrow::Cow;
+use std::ffi::OsString;
 use std::io::Error;
 use std::num::ParseIntError;
 use std::path::{Path, PathBuf};
@@ -345,21 +346,82 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper {
 }
 
 pub(crate) struct LinkingFailed<'a> {
-    pub linker_path: &'a PathBuf,
+    pub linker_path: &'a Path,
     pub exit_status: ExitStatus,
-    pub command: &'a Command,
+    pub command: Command,
     pub escaped_output: String,
+    pub verbose: bool,
 }
 
 impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+    fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
         let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed);
         diag.arg("linker_path", format!("{}", self.linker_path.display()));
         diag.arg("exit_status", format!("{}", self.exit_status));
 
         let contains_undefined_ref = self.escaped_output.contains("undefined reference to");
 
-        diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+        if self.verbose {
+            diag.note(format!("{:?}", self.command));
+        } else {
+            enum ArgGroup {
+                Regular(OsString),
+                Objects(usize),
+                Rlibs(PathBuf, Vec<OsString>),
+            }
+
+            // Omit rust object files and fold rlibs in the error by default to make linker errors a
+            // bit less verbose.
+            let orig_args = self.command.take_args();
+            let mut args: Vec<ArgGroup> = vec![];
+            for arg in orig_args {
+                if arg.as_encoded_bytes().ends_with(b".rcgu.o") {
+                    if let Some(ArgGroup::Objects(n)) = args.last_mut() {
+                        *n += 1;
+                    } else {
+                        args.push(ArgGroup::Objects(1));
+                    }
+                } else if arg.as_encoded_bytes().ends_with(b".rlib") {
+                    let rlib_path = Path::new(&arg);
+                    let dir = rlib_path.parent().unwrap();
+                    let filename = rlib_path.file_name().unwrap().to_owned();
+                    if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() {
+                        if parent == dir {
+                            rlibs.push(filename);
+                        } else {
+                            args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
+                        }
+                    } else {
+                        args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
+                    }
+                } else {
+                    args.push(ArgGroup::Regular(arg));
+                }
+            }
+            self.command.args(args.into_iter().map(|arg_group| match arg_group {
+                ArgGroup::Regular(arg) => arg,
+                ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
+                ArgGroup::Rlibs(dir, rlibs) => {
+                    let mut arg = dir.into_os_string();
+                    arg.push("/{");
+                    let mut first = true;
+                    for rlib in rlibs {
+                        if !first {
+                            arg.push(",");
+                        }
+                        first = false;
+                        arg.push(rlib);
+                    }
+                    arg.push("}");
+                    arg
+                }
+            }));
+
+            diag.note(format!("{:?}", self.command));
+            diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
+        }
+
+        diag.note(self.escaped_output);
 
         // Trying to match an error from OS linkers
         // which by now we have no way to translate.
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index f5396c62433..babf99c4c1f 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -57,9 +57,8 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             Some(stab) => {
                 if cfg!(debug_assertions) && stab.promotable {
                     let sig = tcx.fn_sig(def_id);
-                    assert_eq!(
-                        sig.skip_binder().safety(),
-                        hir::Safety::Safe,
+                    assert!(
+                        sig.skip_binder().safety().is_safe(),
                         "don't mark const unsafe fns as promotable",
                         // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                     );
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 2e795d84559..957d1b48a27 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3434,6 +3434,19 @@ impl Safety {
             Self::Safe => "",
         }
     }
+
+    #[inline]
+    pub fn is_unsafe(self) -> bool {
+        !self.is_safe()
+    }
+
+    #[inline]
+    pub fn is_safe(self) -> bool {
+        match self {
+            Self::Unsafe => false,
+            Self::Safe => true,
+        }
+    }
 }
 
 impl fmt::Display for Safety {
@@ -3478,7 +3491,7 @@ impl FnHeader {
     }
 
     pub fn is_unsafe(&self) -> bool {
-        matches!(&self.safety, Safety::Unsafe)
+        self.safety.is_unsafe()
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 022a6d457ec..8ff94fa566d 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::MultiSpan;
 use rustc_errors::codes::*;
 use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::{Node, Safety, intravisit};
+use rustc_hir::{Node, intravisit};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::{Obligation, ObligationCauseCode};
 use rustc_lint_defs::builtin::{
@@ -161,7 +161,7 @@ fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) {
     };
     let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
     for field in def.all_fields() {
-        if field.safety != Safety::Unsafe {
+        if !field.safety.is_unsafe() {
             continue;
         }
         let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args))
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index bf41dcbe4a3..7d7c9331edf 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -863,7 +863,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             let outer_universe = self.infcx.universe();
 
             let result = if let ty::FnPtr(_, hdr_b) = b.kind()
-                && let (hir::Safety::Safe, hir::Safety::Unsafe) = (fn_ty_a.safety(), hdr_b.safety)
+                && fn_ty_a.safety().is_safe()
+                && hdr_b.safety.is_unsafe()
             {
                 let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
                 self.unify_and(unsafe_a, b, to_unsafe)
@@ -925,7 +926,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
                     // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
 
-                    if b_hdr.safety == hir::Safety::Safe
+                    if b_hdr.safety.is_safe()
                         && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
                     {
                         return Err(TypeError::TargetFeatureCast(def_id));
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index b57c248ed2b..c128485d93e 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -762,7 +762,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
                     if let Some(def_id) = typeck_results.type_dependent_def_id(ex.hir_id)
                         && let method_ty = self.fcx.tcx.type_of(def_id).instantiate_identity()
                         && let sig = method_ty.fn_sig(self.fcx.tcx)
-                        && let hir::Safety::Unsafe = sig.safety()
+                        && sig.safety().is_unsafe()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Method),
@@ -782,7 +782,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
 
                     if func_ty.is_fn()
                         && let sig = func_ty.fn_sig(self.fcx.tcx)
-                        && let hir::Safety::Unsafe = sig.safety()
+                        && sig.safety().is_unsafe()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Call),
@@ -813,7 +813,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
                     // `is_fn` excludes closures, but those can't be unsafe.
                     if ty.is_fn()
                         && let sig = ty.fn_sig(self.fcx.tcx)
-                        && let hir::Safety::Unsafe = sig.safety()
+                        && sig.safety().is_unsafe()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Path),
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index db1a479f580..8337b0f9c1b 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -586,7 +586,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     }
 
     fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool {
-        self.trait_def(trait_def_id).safety == hir::Safety::Unsafe
+        self.trait_def(trait_def_id).safety.is_unsafe()
     }
 
     fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
@@ -722,7 +722,7 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
     }
 
     fn is_safe(self) -> bool {
-        matches!(self, hir::Safety::Safe)
+        self.is_safe()
     }
 
     fn prefix_str(self) -> &'static str {
@@ -2521,7 +2521,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// that is, a `fn` type that is equivalent in every way for being
     /// unsafe.
     pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
-        assert_eq!(sig.safety(), hir::Safety::Safe);
+        assert!(sig.safety().is_safe());
         Ty::new_fn_ptr(self, sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig }))
     }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index e47b0cf0b3b..262eba64027 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -33,9 +33,9 @@ use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
+use rustc_hir::LangItem;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
-use rustc_hir::{LangItem, Safety};
 use rustc_index::IndexVec;
 use rustc_macros::{
     Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
@@ -1281,7 +1281,7 @@ impl VariantDef {
 
     /// Returns whether this variant has unsafe fields.
     pub fn has_unsafe_fields(&self) -> bool {
-        self.fields.iter().any(|x| x.safety == Safety::Unsafe)
+        self.fields.iter().any(|x| x.safety.is_unsafe())
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index fda9898ed56..fc3530e3dde 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1291,7 +1291,7 @@ impl<'tcx> Ty<'tcx> {
     /// Checks whether this type is an ADT that has unsafe fields.
     pub fn has_unsafe_fields(self) -> bool {
         if let ty::Adt(adt_def, ..) = self.kind() {
-            adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe)
+            adt_def.all_fields().any(|x| x.safety.is_unsafe())
         } else {
             false
         }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index f37b3f977fa..90be690e034 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -4,7 +4,7 @@ use std::ops::Bound;
 
 use rustc_errors::DiagArgValue;
 use rustc_hir::def::DefKind;
-use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Safety};
+use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::span_bug;
@@ -342,7 +342,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             PatKind::Leaf { subpatterns, .. } => {
                 if let ty::Adt(adt_def, ..) = pat.ty.kind() {
                     for pat in subpatterns {
-                        if adt_def.non_enum_variant().fields[pat.field].safety == Safety::Unsafe {
+                        if adt_def.non_enum_variant().fields[pat.field].safety.is_unsafe() {
                             self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
                         }
                     }
@@ -367,7 +367,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             PatKind::Variant { adt_def, args: _, variant_index, subpatterns } => {
                 for pat in subpatterns {
                     let field = &pat.field;
-                    if adt_def.variant(*variant_index).fields[*field].safety == Safety::Unsafe {
+                    if adt_def.variant(*variant_index).fields[*field].safety.is_unsafe() {
                         self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
                     }
                 }
@@ -479,7 +479,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 return; // don't visit the whole expression
             }
             ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
-                if self.thir[fun].ty.fn_sig(self.tcx).safety() == hir::Safety::Unsafe {
+                if self.thir[fun].ty.fn_sig(self.tcx).safety().is_unsafe() {
                     let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
                         Some(*func_id)
                     } else {
@@ -623,7 +623,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             ExprKind::Field { lhs, variant_index, name } => {
                 let lhs = &self.thir[lhs];
                 if let ty::Adt(adt_def, _) = lhs.ty.kind() {
-                    if adt_def.variant(variant_index).fields[name].safety == Safety::Unsafe {
+                    if adt_def.variant(variant_index).fields[name].safety.is_unsafe() {
                         self.requires_unsafe(expr.span, UseOfUnsafeField);
                     } else if adt_def.is_union() {
                         if let Some(assigned_ty) = self.assignment_info {
@@ -1112,11 +1112,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
 
     let hir_id = tcx.local_def_id_to_hir_id(def);
     let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
-        if fn_sig.header.safety == hir::Safety::Unsafe {
-            SafetyContext::UnsafeFn
-        } else {
-            SafetyContext::Safe
-        }
+        if fn_sig.header.safety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe }
     });
     let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
     let mut warnings = Vec::new();
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 074fe77324f..a400fa6752a 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -715,7 +715,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attrs: &[Attribute],
     ) {
         match target {
-            Target::Fn => {
+            Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
+            | Target::Fn => {
                 // `#[target_feature]` is not allowed in lang items.
                 if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
                     // Calling functions with `#[target_feature]` is
@@ -732,7 +733,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     });
                 }
             }
-            Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {}
             // FIXME: #[target_feature] was previously erroneously allowed on statements and some
             // crates used this, so only emit a warning.
             Target::Statement => {
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 66492842581..ec442e22204 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -356,6 +356,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 let kind = match self.impl_trait_context {
                     ImplTraitContext::Universal => DefKind::TyParam,
                     ImplTraitContext::Existential => DefKind::OpaqueTy,
+                    ImplTraitContext::InBinding => return visit::walk_ty(self, ty),
                 };
                 let id = self.create_def(*id, name, kind, ty.span);
                 match self.impl_trait_context {
@@ -365,6 +366,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                     ImplTraitContext::Existential => {
                         self.with_parent(id, |this| visit::walk_ty(this, ty))
                     }
+                    ImplTraitContext::InBinding => unreachable!(),
                 };
             }
             _ => visit::walk_ty(self, ty),
@@ -374,6 +376,13 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
     fn visit_stmt(&mut self, stmt: &'a Stmt) {
         match stmt.kind {
             StmtKind::MacCall(..) => self.visit_macro_invoc(stmt.id),
+            // FIXME(impl_trait_in_bindings): We don't really have a good way of
+            // introducing the right `ImplTraitContext` here for all the cases we
+            // care about, in case we want to introduce ITIB to other positions
+            // such as turbofishes (e.g. `foo::<impl Fn()>(|| {})`).
+            StmtKind::Let(ref local) => self.with_impl_trait(ImplTraitContext::InBinding, |this| {
+                visit::walk_local(this, local)
+            }),
             _ => visit::walk_stmt(self, stmt),
         }
     }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 94adfcd3b91..5c4c401af31 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -190,6 +190,7 @@ impl InvocationParent {
 enum ImplTraitContext {
     Existential,
     Universal,
+    InBinding,
 }
 
 /// Used for tracking import use types which will be used for redundant import checking.
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index def741e3546..4f568a20332 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -439,7 +439,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 let sig = sig_tys.with(hdr);
                 self.push("F");
                 self.in_binder(&sig, |cx, sig| {
-                    if sig.safety == hir::Safety::Unsafe {
+                    if sig.safety.is_unsafe() {
                         cx.push("U");
                     }
                     match sig.abi {
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index d216ae72913..7a67b943e94 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -84,7 +84,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
         return Err(CopyImplementationError::HasDestructor);
     }
 
-    if impl_safety == hir::Safety::Safe && self_type.has_unsafe_fields() {
+    if impl_safety.is_safe() && self_type.has_unsafe_fields() {
         return Err(CopyImplementationError::HasUnsafeFields);
     }
 
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index cf51a84bb6f..0b6a55297e1 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1869,7 +1869,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if `index` is greater than deque's length
+    /// Panics if `index` is strictly greater than deque's length
     ///
     /// # Examples
     ///
@@ -1884,6 +1884,9 @@ impl<T, A: Allocator> VecDeque<T, A> {
     ///
     /// vec_deque.insert(1, 'd');
     /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']);
+    ///
+    /// vec_deque.insert(4, 'e');
+    /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c', 'e']);
     /// ```
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
     #[track_caller]
@@ -1928,13 +1931,13 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// use std::collections::VecDeque;
     ///
     /// let mut buf = VecDeque::new();
-    /// buf.push_back(1);
-    /// buf.push_back(2);
-    /// buf.push_back(3);
-    /// assert_eq!(buf, [1, 2, 3]);
+    /// buf.push_back('a');
+    /// buf.push_back('b');
+    /// buf.push_back('c');
+    /// assert_eq!(buf, ['a', 'b', 'c']);
     ///
-    /// assert_eq!(buf.remove(1), Some(2));
-    /// assert_eq!(buf, [1, 3]);
+    /// assert_eq!(buf.remove(1), Some('b'));
+    /// assert_eq!(buf, ['a', 'c']);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_confusables("delete", "take")]
@@ -1982,10 +1985,10 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<_> = [1, 2, 3].into();
+    /// let mut buf: VecDeque<_> = ['a', 'b', 'c'].into();
     /// let buf2 = buf.split_off(1);
-    /// assert_eq!(buf, [1]);
-    /// assert_eq!(buf2, [2, 3]);
+    /// assert_eq!(buf, ['a']);
+    /// assert_eq!(buf2, ['b', 'c']);
     /// ```
     #[inline]
     #[must_use = "use `.truncate()` if you don't need the other half"]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 457be3ae77f..7e7a8ff72c7 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1953,11 +1953,11 @@ impl<T, A: Allocator> Vec<T, A> {
     /// # Examples
     ///
     /// ```
-    /// let mut vec = vec![1, 2, 3];
-    /// vec.insert(1, 4);
-    /// assert_eq!(vec, [1, 4, 2, 3]);
-    /// vec.insert(4, 5);
-    /// assert_eq!(vec, [1, 4, 2, 3, 5]);
+    /// let mut vec = vec!['a', 'b', 'c'];
+    /// vec.insert(1, 'd');
+    /// assert_eq!(vec, ['a', 'd', 'b', 'c']);
+    /// vec.insert(4, 'e');
+    /// assert_eq!(vec, ['a', 'd', 'b', 'c', 'e']);
     /// ```
     ///
     /// # Time complexity
@@ -2024,9 +2024,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// # Examples
     ///
     /// ```
-    /// let mut v = vec![1, 2, 3];
-    /// assert_eq!(v.remove(1), 2);
-    /// assert_eq!(v, [1, 3]);
+    /// let mut v = vec!['a', 'b', 'c'];
+    /// assert_eq!(v.remove(1), 'b');
+    /// assert_eq!(v, ['a', 'c']);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[track_caller]
@@ -2715,10 +2715,10 @@ impl<T, A: Allocator> Vec<T, A> {
     /// # Examples
     ///
     /// ```
-    /// let mut vec = vec![1, 2, 3];
+    /// let mut vec = vec!['a', 'b', 'c'];
     /// let vec2 = vec.split_off(1);
-    /// assert_eq!(vec, [1]);
-    /// assert_eq!(vec2, [2, 3]);
+    /// assert_eq!(vec, ['a']);
+    /// assert_eq!(vec2, ['b', 'c']);
     /// ```
     #[cfg(not(no_global_oom_handling))]
     #[inline]
@@ -2982,9 +2982,9 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// vec.resize(3, "world");
     /// assert_eq!(vec, ["hello", "world", "world"]);
     ///
-    /// let mut vec = vec![1, 2, 3, 4];
-    /// vec.resize(2, 0);
-    /// assert_eq!(vec, [1, 2]);
+    /// let mut vec = vec!['a', 'b', 'c', 'd'];
+    /// vec.resize(2, '_');
+    /// assert_eq!(vec, ['a', 'b']);
     /// ```
     #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_resize", since = "1.5.0")]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 97a7338b0bf..de00bdf8594 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1883,23 +1883,23 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// let v = [1, 2, 3, 4, 5, 6];
+    /// let v = ['a', 'b', 'c'];
     ///
     /// {
     ///    let (left, right) = v.split_at(0);
     ///    assert_eq!(left, []);
-    ///    assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+    ///    assert_eq!(right, ['a', 'b', 'c']);
     /// }
     ///
     /// {
     ///     let (left, right) = v.split_at(2);
-    ///     assert_eq!(left, [1, 2]);
-    ///     assert_eq!(right, [3, 4, 5, 6]);
+    ///     assert_eq!(left, ['a', 'b']);
+    ///     assert_eq!(right, ['c']);
     /// }
     ///
     /// {
-    ///     let (left, right) = v.split_at(6);
-    ///     assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    ///     let (left, right) = v.split_at(3);
+    ///     assert_eq!(left, ['a', 'b', 'c']);
     ///     assert_eq!(right, []);
     /// }
     /// ```
@@ -1969,23 +1969,23 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// let v = [1, 2, 3, 4, 5, 6];
+    /// let v = ['a', 'b', 'c'];
     ///
     /// unsafe {
     ///    let (left, right) = v.split_at_unchecked(0);
     ///    assert_eq!(left, []);
-    ///    assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+    ///    assert_eq!(right, ['a', 'b', 'c']);
     /// }
     ///
     /// unsafe {
     ///     let (left, right) = v.split_at_unchecked(2);
-    ///     assert_eq!(left, [1, 2]);
-    ///     assert_eq!(right, [3, 4, 5, 6]);
+    ///     assert_eq!(left, ['a', 'b']);
+    ///     assert_eq!(right, ['c']);
     /// }
     ///
     /// unsafe {
-    ///     let (left, right) = v.split_at_unchecked(6);
-    ///     assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    ///     let (left, right) = v.split_at_unchecked(3);
+    ///     assert_eq!(left, ['a', 'b', 'c']);
     ///     assert_eq!(right, []);
     /// }
     /// ```
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index fe2aca031a2..e28c2090afe 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -4,10 +4,10 @@ mod tests;
 use crate::cell::UnsafeCell;
 use crate::fmt;
 use crate::marker::PhantomData;
-use crate::mem::ManuallyDrop;
+use crate::mem::{self, ManuallyDrop};
 use crate::ops::{Deref, DerefMut};
 use crate::ptr::NonNull;
-use crate::sync::{LockResult, TryLockError, TryLockResult, poison};
+use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison};
 use crate::sys::sync as sys;
 
 /// A mutual exclusion primitive useful for protecting shared data
@@ -273,6 +273,100 @@ impl<T> Mutex<T> {
     pub const fn new(t: T) -> Mutex<T> {
         Mutex { inner: sys::Mutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
     }
+
+    /// Returns the contained value by cloning it.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.get_cloned().unwrap(), 7);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn get_cloned(&self) -> Result<T, PoisonError<()>>
+    where
+        T: Clone,
+    {
+        match self.lock() {
+            Ok(guard) => Ok((*guard).clone()),
+            Err(_) => Err(PoisonError::new(())),
+        }
+    }
+
+    /// Sets the contained value.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error containing the provided `value` instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.get_cloned().unwrap(), 7);
+    /// mutex.set(11).unwrap();
+    /// assert_eq!(mutex.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn set(&self, value: T) -> Result<(), PoisonError<T>> {
+        if mem::needs_drop::<T>() {
+            // If the contained value has non-trivial destructor, we
+            // call that destructor after the lock being released.
+            self.replace(value).map(drop)
+        } else {
+            match self.lock() {
+                Ok(mut guard) => {
+                    *guard = value;
+
+                    Ok(())
+                }
+                Err(_) => Err(PoisonError::new(value)),
+            }
+        }
+    }
+
+    /// Replaces the contained value with `value`, and returns the old contained value.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error containing the provided `value` instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.replace(11).unwrap(), 7);
+    /// assert_eq!(mutex.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn replace(&self, value: T) -> LockResult<T> {
+        match self.lock() {
+            Ok(mut guard) => Ok(mem::replace(&mut *guard, value)),
+            Err(_) => Err(PoisonError::new(value)),
+        }
+    }
 }
 
 impl<T: ?Sized> Mutex<T> {
@@ -290,7 +384,8 @@ impl<T: ?Sized> Mutex<T> {
     /// # Errors
     ///
     /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return an error once the mutex is acquired.
+    /// this call will return an error once the mutex is acquired. The acquired
+    /// mutex guard will be contained in the returned error.
     ///
     /// # Panics
     ///
@@ -331,7 +426,8 @@ impl<T: ?Sized> Mutex<T> {
     ///
     /// If another user of this mutex panicked while holding the mutex, then
     /// this call will return the [`Poisoned`] error if the mutex would
-    /// otherwise be acquired.
+    /// otherwise be acquired. An acquired lock guard will be contained
+    /// in the returned error.
     ///
     /// If the mutex could not be acquired because it is already locked, then
     /// this call will return the [`WouldBlock`] error.
@@ -438,7 +534,8 @@ impl<T: ?Sized> Mutex<T> {
     /// # Errors
     ///
     /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return an error instead.
+    /// this call will return an error containing the the underlying data
+    /// instead.
     ///
     /// # Examples
     ///
@@ -465,7 +562,8 @@ impl<T: ?Sized> Mutex<T> {
     /// # Errors
     ///
     /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return an error instead.
+    /// this call will return an error containing a mutable reference to the
+    /// underlying data instead.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs
index 19ec096c593..395c8aada08 100644
--- a/library/std/src/sync/mutex/tests.rs
+++ b/library/std/src/sync/mutex/tests.rs
@@ -1,13 +1,34 @@
+use crate::fmt::Debug;
+use crate::ops::FnMut;
+use crate::panic::{self, AssertUnwindSafe};
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::mpsc::channel;
 use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
-use crate::thread;
+use crate::{hint, mem, thread};
 
 struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
 
 #[derive(Eq, PartialEq, Debug)]
 struct NonCopy(i32);
 
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopyNeedsDrop(i32);
+
+impl Drop for NonCopyNeedsDrop {
+    fn drop(&mut self) {
+        hint::black_box(());
+    }
+}
+
+#[test]
+fn test_needs_drop() {
+    assert!(!mem::needs_drop::<NonCopy>());
+    assert!(mem::needs_drop::<NonCopyNeedsDrop>());
+}
+
+#[derive(Clone, Eq, PartialEq, Debug)]
+struct Cloneable(i32);
+
 #[test]
 fn smoke() {
     let m = Mutex::new(());
@@ -57,6 +78,21 @@ fn try_lock() {
     *m.try_lock().unwrap() = ();
 }
 
+fn new_poisoned_mutex<T>(value: T) -> Mutex<T> {
+    let mutex = Mutex::new(value);
+
+    let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| {
+        let _guard = mutex.lock().unwrap();
+
+        panic!("test panic to poison mutex");
+    }));
+
+    assert!(catch_unwind_result.is_err());
+    assert!(mutex.is_poisoned());
+
+    mutex
+}
+
 #[test]
 fn test_into_inner() {
     let m = Mutex::new(NonCopy(10));
@@ -83,22 +119,32 @@ fn test_into_inner_drop() {
 
 #[test]
 fn test_into_inner_poison() {
-    let m = Arc::new(Mutex::new(NonCopy(10)));
-    let m2 = m.clone();
-    let _ = thread::spawn(move || {
-        let _lock = m2.lock().unwrap();
-        panic!("test panic in inner thread to poison mutex");
-    })
-    .join();
+    let m = new_poisoned_mutex(NonCopy(10));
 
-    assert!(m.is_poisoned());
-    match Arc::try_unwrap(m).unwrap().into_inner() {
+    match m.into_inner() {
         Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
         Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"),
     }
 }
 
 #[test]
+fn test_get_cloned() {
+    let m = Mutex::new(Cloneable(10));
+
+    assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
+}
+
+#[test]
+fn test_get_cloned_poison() {
+    let m = new_poisoned_mutex(Cloneable(10));
+
+    match m.get_cloned() {
+        Err(e) => assert_eq!(e.into_inner(), ()),
+        Ok(x) => panic!("get of poisoned Mutex is Ok: {x:?}"),
+    }
+}
+
+#[test]
 fn test_get_mut() {
     let mut m = Mutex::new(NonCopy(10));
     *m.get_mut().unwrap() = NonCopy(20);
@@ -107,22 +153,91 @@ fn test_get_mut() {
 
 #[test]
 fn test_get_mut_poison() {
-    let m = Arc::new(Mutex::new(NonCopy(10)));
-    let m2 = m.clone();
-    let _ = thread::spawn(move || {
-        let _lock = m2.lock().unwrap();
-        panic!("test panic in inner thread to poison mutex");
-    })
-    .join();
+    let mut m = new_poisoned_mutex(NonCopy(10));
 
-    assert!(m.is_poisoned());
-    match Arc::try_unwrap(m).unwrap().get_mut() {
+    match m.get_mut() {
         Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
         Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"),
     }
 }
 
 #[test]
+fn test_set() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = Mutex::new(init());
+
+        assert_eq!(*m.lock().unwrap(), init());
+        m.set(value()).unwrap();
+        assert_eq!(*m.lock().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_set_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_mutex(init());
+
+        match m.set(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("set of poisoned Mutex is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = Mutex::new(init());
+
+        assert_eq!(*m.lock().unwrap(), init());
+        assert_eq!(m.replace(value()).unwrap(), init());
+        assert_eq!(*m.lock().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_mutex(init());
+
+        match m.replace(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("replace of poisoned Mutex is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
 fn test_mutex_arc_condvar() {
     let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
     let packet2 = Packet(packet.0.clone());
@@ -269,7 +384,7 @@ fn test_mapping_mapped_guard() {
 fn panic_while_mapping_unlocked_poison() {
     let lock = Mutex::new(());
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.lock().unwrap();
         let _guard = MutexGuard::map::<(), _>(guard, |_| panic!());
     });
@@ -282,7 +397,7 @@ fn panic_while_mapping_unlocked_poison() {
         Err(TryLockError::Poisoned(_)) => {}
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.lock().unwrap();
         let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!());
     });
@@ -295,7 +410,7 @@ fn panic_while_mapping_unlocked_poison() {
         Err(TryLockError::Poisoned(_)) => {}
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.lock().unwrap();
         let guard = MutexGuard::map::<(), _>(guard, |val| val);
         let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!());
@@ -309,7 +424,7 @@ fn panic_while_mapping_unlocked_poison() {
         Err(TryLockError::Poisoned(_)) => {}
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.lock().unwrap();
         let guard = MutexGuard::map::<(), _>(guard, |val| val);
         let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!());
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index da66a088e51..9eb900c2103 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -87,8 +87,8 @@ pub struct Guard {
 ///
 /// Both [`Mutex`]es and [`RwLock`]s are poisoned whenever a thread fails while the lock
 /// is held. The precise semantics for when a lock is poisoned is documented on
-/// each lock, but once a lock is poisoned then all future acquisitions will
-/// return this error.
+/// each lock. For a lock in the poisoned state, unless the state is cleared manually,
+/// all future acquisitions will return this error.
 ///
 /// # Examples
 ///
@@ -118,7 +118,7 @@ pub struct Guard {
 /// [`RwLock`]: crate::sync::RwLock
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct PoisonError<T> {
-    guard: T,
+    data: T,
     #[cfg(not(panic = "unwind"))]
     _never: !,
 }
@@ -147,14 +147,15 @@ pub enum TryLockError<T> {
 /// A type alias for the result of a lock method which can be poisoned.
 ///
 /// The [`Ok`] variant of this result indicates that the primitive was not
-/// poisoned, and the `Guard` is contained within. The [`Err`] variant indicates
+/// poisoned, and the operation result is contained within. The [`Err`] variant indicates
 /// that the primitive was poisoned. Note that the [`Err`] variant *also* carries
-/// the associated guard, and it can be acquired through the [`into_inner`]
-/// method.
+/// an associated value assigned by the lock method, and it can be acquired through the
+/// [`into_inner`] method. The semantics of the associated value depends on the corresponding
+/// lock method.
 ///
 /// [`into_inner`]: PoisonError::into_inner
 #[stable(feature = "rust1", since = "1.0.0")]
-pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
+pub type LockResult<T> = Result<T, PoisonError<T>>;
 
 /// A type alias for the result of a nonblocking locking method.
 ///
@@ -195,8 +196,8 @@ impl<T> PoisonError<T> {
     /// This method may panic if std was built with `panic="abort"`.
     #[cfg(panic = "unwind")]
     #[stable(feature = "sync_poison", since = "1.2.0")]
-    pub fn new(guard: T) -> PoisonError<T> {
-        PoisonError { guard }
+    pub fn new(data: T) -> PoisonError<T> {
+        PoisonError { data }
     }
 
     /// Creates a `PoisonError`.
@@ -208,12 +209,12 @@ impl<T> PoisonError<T> {
     #[cfg(not(panic = "unwind"))]
     #[stable(feature = "sync_poison", since = "1.2.0")]
     #[track_caller]
-    pub fn new(_guard: T) -> PoisonError<T> {
+    pub fn new(_data: T) -> PoisonError<T> {
         panic!("PoisonError created in a libstd built with panic=\"abort\"")
     }
 
     /// Consumes this error indicating that a lock is poisoned, returning the
-    /// underlying guard to allow access regardless.
+    /// associated data.
     ///
     /// # Examples
     ///
@@ -238,21 +239,21 @@ impl<T> PoisonError<T> {
     /// ```
     #[stable(feature = "sync_poison", since = "1.2.0")]
     pub fn into_inner(self) -> T {
-        self.guard
+        self.data
     }
 
     /// Reaches into this error indicating that a lock is poisoned, returning a
-    /// reference to the underlying guard to allow access regardless.
+    /// reference to the associated data.
     #[stable(feature = "sync_poison", since = "1.2.0")]
     pub fn get_ref(&self) -> &T {
-        &self.guard
+        &self.data
     }
 
     /// Reaches into this error indicating that a lock is poisoned, returning a
-    /// mutable reference to the underlying guard to allow access regardless.
+    /// mutable reference to the associated data.
     #[stable(feature = "sync_poison", since = "1.2.0")]
     pub fn get_mut(&mut self) -> &mut T {
-        &mut self.guard
+        &mut self.data
     }
 }
 
@@ -322,6 +323,6 @@ where
     match result {
         Ok(t) => Ok(f(t)),
         #[cfg(panic = "unwind")]
-        Err(PoisonError { guard }) => Err(PoisonError::new(f(guard))),
+        Err(PoisonError { data }) => Err(PoisonError::new(f(data))),
     }
 }
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index d55d1c80dca..1519baf99a8 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -4,7 +4,7 @@ mod tests;
 use crate::cell::UnsafeCell;
 use crate::fmt;
 use crate::marker::PhantomData;
-use crate::mem::{ManuallyDrop, forget};
+use crate::mem::{self, ManuallyDrop, forget};
 use crate::ops::{Deref, DerefMut};
 use crate::ptr::NonNull;
 use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison};
@@ -224,6 +224,103 @@ impl<T> RwLock<T> {
     pub const fn new(t: T) -> RwLock<T> {
         RwLock { inner: sys::RwLock::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
     }
+
+    /// Returns the contained value by cloning it.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::RwLock;
+    ///
+    /// let mut lock = RwLock::new(7);
+    ///
+    /// assert_eq!(lock.get_cloned().unwrap(), 7);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn get_cloned(&self) -> Result<T, PoisonError<()>>
+    where
+        T: Clone,
+    {
+        match self.read() {
+            Ok(guard) => Ok((*guard).clone()),
+            Err(_) => Err(PoisonError::new(())),
+        }
+    }
+
+    /// Sets the contained value.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error containing the provided `value` if
+    /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer
+    /// panics while holding an exclusive lock.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::RwLock;
+    ///
+    /// let mut lock = RwLock::new(7);
+    ///
+    /// assert_eq!(lock.get_cloned().unwrap(), 7);
+    /// lock.set(11).unwrap();
+    /// assert_eq!(lock.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn set(&self, value: T) -> Result<(), PoisonError<T>> {
+        if mem::needs_drop::<T>() {
+            // If the contained value has non-trivial destructor, we
+            // call that destructor after the lock being released.
+            self.replace(value).map(drop)
+        } else {
+            match self.write() {
+                Ok(mut guard) => {
+                    *guard = value;
+
+                    Ok(())
+                }
+                Err(_) => Err(PoisonError::new(value)),
+            }
+        }
+    }
+
+    /// Replaces the contained value with `value`, and returns the old contained value.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error containing the provided `value` if
+    /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer
+    /// panics while holding an exclusive lock.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::RwLock;
+    ///
+    /// let mut lock = RwLock::new(7);
+    ///
+    /// assert_eq!(lock.replace(11).unwrap(), 7);
+    /// assert_eq!(lock.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn replace(&self, value: T) -> LockResult<T> {
+        match self.write() {
+            Ok(mut guard) => Ok(mem::replace(&mut *guard, value)),
+            Err(_) => Err(PoisonError::new(value)),
+        }
+    }
 }
 
 impl<T: ?Sized> RwLock<T> {
@@ -244,7 +341,8 @@ impl<T: ?Sized> RwLock<T> {
     /// This function will return an error if the `RwLock` is poisoned. An
     /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
     /// lock. The failure will occur immediately after the lock has been
-    /// acquired.
+    /// acquired. The acquired lock guard will be contained in the returned
+    /// error.
     ///
     /// # Panics
     ///
@@ -292,7 +390,8 @@ impl<T: ?Sized> RwLock<T> {
     /// This function will return the [`Poisoned`] error if the `RwLock` is
     /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding
     /// an exclusive lock. `Poisoned` will only be returned if the lock would
-    /// have otherwise been acquired.
+    /// have otherwise been acquired. An acquired lock guard will be contained
+    /// in the returned error.
     ///
     /// This function will return the [`WouldBlock`] error if the `RwLock` could
     /// not be acquired because it was already locked exclusively.
@@ -337,7 +436,8 @@ impl<T: ?Sized> RwLock<T> {
     ///
     /// This function will return an error if the `RwLock` is poisoned. An
     /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
-    /// lock. An error will be returned when the lock is acquired.
+    /// lock. An error will be returned when the lock is acquired. The acquired
+    /// lock guard will be contained in the returned error.
     ///
     /// # Panics
     ///
@@ -380,7 +480,8 @@ impl<T: ?Sized> RwLock<T> {
     /// This function will return the [`Poisoned`] error if the `RwLock` is
     /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding
     /// an exclusive lock. `Poisoned` will only be returned if the lock would
-    /// have otherwise been acquired.
+    /// have otherwise been acquired. An acquired lock guard will be contained
+    /// in the returned error.
     ///
     /// This function will return the [`WouldBlock`] error if the `RwLock` could
     /// not be acquired because it was already locked exclusively.
@@ -481,10 +582,10 @@ impl<T: ?Sized> RwLock<T> {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the `RwLock` is poisoned. An
-    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
-    /// lock. An error will only be returned if the lock would have otherwise
-    /// been acquired.
+    /// This function will return an error containing the underlying data if
+    /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer
+    /// panics while holding an exclusive lock. An error will only be returned
+    /// if the lock would have otherwise been acquired.
     ///
     /// # Examples
     ///
@@ -514,10 +615,11 @@ impl<T: ?Sized> RwLock<T> {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the `RwLock` is poisoned. An
-    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
-    /// lock. An error will only be returned if the lock would have otherwise
-    /// been acquired.
+    /// This function will return an error containing a mutable reference to
+    /// the underlying data if the `RwLock` is poisoned. An `RwLock` is
+    /// poisoned whenever a writer panics while holding an exclusive lock.
+    /// An error will only be returned if the lock would have otherwise been
+    /// acquired.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index 48d442921f7..057c2f1a5d7 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -1,16 +1,37 @@
 use rand::Rng;
 
+use crate::fmt::Debug;
+use crate::ops::FnMut;
+use crate::panic::{self, AssertUnwindSafe};
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::mpsc::channel;
 use crate::sync::{
     Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
     TryLockError,
 };
-use crate::thread;
+use crate::{hint, mem, thread};
 
 #[derive(Eq, PartialEq, Debug)]
 struct NonCopy(i32);
 
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopyNeedsDrop(i32);
+
+impl Drop for NonCopyNeedsDrop {
+    fn drop(&mut self) {
+        hint::black_box(());
+    }
+}
+
+#[test]
+fn test_needs_drop() {
+    assert!(!mem::needs_drop::<NonCopy>());
+    assert!(mem::needs_drop::<NonCopyNeedsDrop>());
+}
+
+#[derive(Clone, Eq, PartialEq, Debug)]
+struct Cloneable(i32);
+
 #[test]
 fn smoke() {
     let l = RwLock::new(());
@@ -255,6 +276,21 @@ fn test_rwlock_try_write() {
     drop(mapped_read_guard);
 }
 
+fn new_poisoned_rwlock<T>(value: T) -> RwLock<T> {
+    let lock = RwLock::new(value);
+
+    let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| {
+        let _guard = lock.write().unwrap();
+
+        panic!("test panic to poison RwLock");
+    }));
+
+    assert!(catch_unwind_result.is_err());
+    assert!(lock.is_poisoned());
+
+    lock
+}
+
 #[test]
 fn test_into_inner() {
     let m = RwLock::new(NonCopy(10));
@@ -281,22 +317,32 @@ fn test_into_inner_drop() {
 
 #[test]
 fn test_into_inner_poison() {
-    let m = Arc::new(RwLock::new(NonCopy(10)));
-    let m2 = m.clone();
-    let _ = thread::spawn(move || {
-        let _lock = m2.write().unwrap();
-        panic!("test panic in inner thread to poison RwLock");
-    })
-    .join();
+    let m = new_poisoned_rwlock(NonCopy(10));
 
-    assert!(m.is_poisoned());
-    match Arc::try_unwrap(m).unwrap().into_inner() {
+    match m.into_inner() {
         Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
         Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"),
     }
 }
 
 #[test]
+fn test_get_cloned() {
+    let m = RwLock::new(Cloneable(10));
+
+    assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
+}
+
+#[test]
+fn test_get_cloned_poison() {
+    let m = new_poisoned_rwlock(Cloneable(10));
+
+    match m.get_cloned() {
+        Err(e) => assert_eq!(e.into_inner(), ()),
+        Ok(x) => panic!("get of poisoned RwLock is Ok: {x:?}"),
+    }
+}
+
+#[test]
 fn test_get_mut() {
     let mut m = RwLock::new(NonCopy(10));
     *m.get_mut().unwrap() = NonCopy(20);
@@ -305,22 +351,91 @@ fn test_get_mut() {
 
 #[test]
 fn test_get_mut_poison() {
-    let m = Arc::new(RwLock::new(NonCopy(10)));
-    let m2 = m.clone();
-    let _ = thread::spawn(move || {
-        let _lock = m2.write().unwrap();
-        panic!("test panic in inner thread to poison RwLock");
-    })
-    .join();
+    let mut m = new_poisoned_rwlock(NonCopy(10));
 
-    assert!(m.is_poisoned());
-    match Arc::try_unwrap(m).unwrap().get_mut() {
+    match m.get_mut() {
         Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
         Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"),
     }
 }
 
 #[test]
+fn test_set() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = RwLock::new(init());
+
+        assert_eq!(*m.read().unwrap(), init());
+        m.set(value()).unwrap();
+        assert_eq!(*m.read().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_set_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_rwlock(init());
+
+        match m.set(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("set of poisoned RwLock is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = RwLock::new(init());
+
+        assert_eq!(*m.read().unwrap(), init());
+        assert_eq!(m.replace(value()).unwrap(), init());
+        assert_eq!(*m.read().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_rwlock(init());
+
+        match m.replace(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("replace of poisoned RwLock is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
 fn test_read_guard_covariance() {
     fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {}
     let j: i32 = 5;
@@ -370,7 +485,7 @@ fn test_mapping_mapped_guard() {
 fn panic_while_mapping_read_unlocked_no_poison() {
     let lock = RwLock::new(());
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.read().unwrap();
         let _guard = RwLockReadGuard::map::<(), _>(guard, |_| panic!());
     });
@@ -385,7 +500,7 @@ fn panic_while_mapping_read_unlocked_no_poison() {
         }
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.read().unwrap();
         let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
     });
@@ -400,7 +515,7 @@ fn panic_while_mapping_read_unlocked_no_poison() {
         }
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.read().unwrap();
         let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
         let _guard = MappedRwLockReadGuard::map::<(), _>(guard, |_| panic!());
@@ -416,7 +531,7 @@ fn panic_while_mapping_read_unlocked_no_poison() {
         }
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.read().unwrap();
         let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
         let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
@@ -439,7 +554,7 @@ fn panic_while_mapping_read_unlocked_no_poison() {
 fn panic_while_mapping_write_unlocked_poison() {
     let lock = RwLock::new(());
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.write().unwrap();
         let _guard = RwLockWriteGuard::map::<(), _>(guard, |_| panic!());
     });
@@ -452,7 +567,7 @@ fn panic_while_mapping_write_unlocked_poison() {
         Err(TryLockError::Poisoned(_)) => {}
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.write().unwrap();
         let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
     });
@@ -467,7 +582,7 @@ fn panic_while_mapping_write_unlocked_poison() {
         Err(TryLockError::Poisoned(_)) => {}
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.write().unwrap();
         let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
         let _guard = MappedRwLockWriteGuard::map::<(), _>(guard, |_| panic!());
@@ -483,7 +598,7 @@ fn panic_while_mapping_write_unlocked_poison() {
         Err(TryLockError::Poisoned(_)) => {}
     }
 
-    let _ = crate::panic::catch_unwind(|| {
+    let _ = panic::catch_unwind(|| {
         let guard = lock.write().unwrap();
         let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
         let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index d140607869c..d73b9fd5eb8 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -81,6 +81,7 @@ impl Socket {
                     target_os = "netbsd",
                     target_os = "openbsd",
                     target_os = "nto",
+                    target_os = "solaris",
                 ))] {
                     // On platforms that support it we pass the SOCK_CLOEXEC
                     // flag to atomically create the socket and set it as
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 0a563b1df26..7d40f662ed0 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1626,10 +1626,7 @@ pub(crate) trait PrintWithSpace {
 
 impl PrintWithSpace for hir::Safety {
     fn print_with_space(&self) -> &str {
-        match self {
-            hir::Safety::Unsafe => "unsafe ",
-            hir::Safety::Safe => "",
-        }
+        self.prefix_str()
     }
 }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 4c8d704e65b..ced9ff2d685 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -469,7 +469,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
 
                 let unsafety_flag = match myitem.kind {
                     clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
-                        if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe =>
+                        if myitem.fn_header(tcx).unwrap().safety.is_unsafe() =>
                     {
                         "<sup title=\"unsafe function\">⚠</sup>"
                     }
@@ -1926,9 +1926,7 @@ fn item_static(
             buffer,
             "{vis}{safe}static {mutability}{name}: {typ}",
             vis = visibility_print_with_space(it, cx),
-            safe = safety
-                .map(|safe| if safe == hir::Safety::Unsafe { "unsafe " } else { "" })
-                .unwrap_or(""),
+            safe = safety.map(|safe| safe.prefix_str()).unwrap_or(""),
             mutability = s.mutability.print_with_space(),
             name = it.name.unwrap(),
             typ = s.type_.print(cx)
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index bb967b7f163..be39984c3da 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -639,7 +639,7 @@ impl FromClean<clean::BareFunctionDecl> for FunctionPointer {
         let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
         FunctionPointer {
             header: FunctionHeader {
-                is_unsafe: matches!(safety, rustc_hir::Safety::Unsafe),
+                is_unsafe: safety.is_unsafe(),
                 is_const: false,
                 is_async: false,
                 abi: convert_abi(abi),
@@ -669,7 +669,7 @@ impl FromClean<clean::Trait> for Trait {
     fn from_clean(trait_: clean::Trait, renderer: &JsonRenderer<'_>) -> Self {
         let tcx = renderer.tcx;
         let is_auto = trait_.is_auto(tcx);
-        let is_unsafe = trait_.safety(tcx) == rustc_hir::Safety::Unsafe;
+        let is_unsafe = trait_.safety(tcx).is_unsafe();
         let is_dyn_compatible = trait_.is_dyn_compatible(tcx);
         let clean::Trait { items, generics, bounds, .. } = trait_;
         Trait {
@@ -711,7 +711,7 @@ impl FromClean<clean::Impl> for Impl {
             ty::ImplPolarity::Negative => true,
         };
         Impl {
-            is_unsafe: safety == rustc_hir::Safety::Unsafe,
+            is_unsafe: safety.is_unsafe(),
             generics: generics.into_json(renderer),
             provided_trait_methods: provided_trait_methods
                 .into_iter()
@@ -840,7 +840,7 @@ fn convert_static(
     Static {
         type_: (*stat.type_).into_json(renderer),
         is_mutable: stat.mutability == ast::Mutability::Mut,
-        is_unsafe: safety == rustc_hir::Safety::Unsafe,
+        is_unsafe: safety.is_unsafe(),
         expr: stat
             .expr
             .map(|e| rendered_const(tcx, tcx.hir().body(e), tcx.hir().body_owner_def_id(e)))
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 8125dab8adf..f65edd36253 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item};
 use rustc_hir::{
-    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, Safety, UnsafeSource,
+    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
@@ -421,7 +421,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
         id: LocalDefId,
     ) -> Self::Result {
         if let Some(header) = kind.header()
-            && header.safety == Safety::Unsafe
+            && header.safety.is_unsafe()
         {
             ControlFlow::Break(())
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 8c22e43349f..2cd48ef98e5 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -281,7 +281,7 @@ fn check_inputs(
 }
 
 fn check_sig<'tcx>(closure_sig: FnSig<'tcx>, call_sig: FnSig<'tcx>) -> bool {
-    call_sig.safety == Safety::Safe && !has_late_bound_to_non_late_bound_regions(closure_sig, call_sig)
+    call_sig.safety.is_safe() && !has_late_bound_to_non_late_bound_regions(closure_sig, call_sig)
 }
 
 /// This walks through both signatures and checks for any time a late-bound region is expected by an
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index 2cbc4b07234..017571c38db 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Safety};
+use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Span;
@@ -34,7 +34,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
         ImplicitSelfKind::None => return,
     };
 
-    let name = if sig.header.safety == Safety::Unsafe {
+    let name = if sig.header.safety.is_unsafe() {
         name.strip_suffix("_unchecked").unwrap_or(name)
     } else {
         name
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 4986a311eba..3ded8dc3012 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -42,7 +42,7 @@ fn check_raw_ptr<'tcx>(
     body: &'tcx hir::Body<'tcx>,
     def_id: LocalDefId,
 ) {
-    if safety == hir::Safety::Safe && cx.effective_visibilities.is_exported(def_id) {
+    if safety.is_safe() && cx.effective_visibilities.is_exported(def_id) {
         let raw_ptrs = iter_input_pats(decl, body)
             .filter_map(|arg| raw_ptr_arg(cx, arg))
             .collect::<HirIdSet>();
@@ -58,7 +58,7 @@ fn check_raw_ptr<'tcx>(
                     },
                     hir::ExprKind::MethodCall(_, recv, args, _) => {
                         let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap();
-                        if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().safety == hir::Safety::Unsafe {
+                        if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().safety.is_unsafe() {
                             check_arg(cx, &raw_ptrs, recv);
                             for arg in args {
                                 check_arg(cx, &raw_ptrs, arg);
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index ec6174bc030..e096dd25175 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
 use clippy_utils::{return_ty, trait_ref_of_method};
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Safety};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
         if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // #11201
             && let header = signature.header
-            && header.safety == Safety::Safe
+            && header.safety.is_safe()
             && header.abi == Abi::Rust
             && impl_item.ident.name == sym::to_string
             && let decl = signature.decl
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 12bcc608174..79252bba74d 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::visitors::{Descend, Visitable, for_each_expr};
 use core::ops::ControlFlow::Continue;
 use hir::def::{DefKind, Res};
-use hir::{BlockCheckMode, ExprKind, QPath, Safety, UnOp};
+use hir::{BlockCheckMode, ExprKind, QPath, UnOp};
 use rustc_ast::Mutability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -133,7 +133,7 @@ fn collect_unsafe_exprs<'tcx>(
                     ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr),
                     _ => return Continue(Descend::Yes),
                 };
-                if sig.safety() == Safety::Unsafe {
+                if sig.safety().is_unsafe() {
                     unsafe_ops.push(("unsafe function call occurs here", expr.span));
                 }
             },
@@ -144,7 +144,7 @@ fn collect_unsafe_exprs<'tcx>(
                     .type_dependent_def_id(expr.hir_id)
                     .map(|def_id| cx.tcx.fn_sig(def_id))
                 {
-                    if sig.skip_binder().safety() == Safety::Unsafe {
+                    if sig.skip_binder().safety().is_unsafe() {
                         unsafe_ops.push(("unsafe method call occurs here", expr.span));
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index b60fea3f03e..abdce69e764 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                     if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
                         let name = impl_item.ident.name;
                         let id = impl_item.owner_id;
-                        if sig.header.safety == hir::Safety::Unsafe {
+                        if sig.header.safety.is_unsafe() {
                             // can't be implemented for unsafe new
                             return;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index dec4c18a309..44a8789462b 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -8,7 +8,7 @@ use rustc_hir::hir_id::{HirId, HirIdMap};
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{
     self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind,
-    ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, Safety, TraitFn, TraitItem, TraitItemKind, TyKind,
+    ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind,
 };
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{Obligation, ObligationCause};
@@ -541,7 +541,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
             .collect();
         if let Some(args) = args
             && !args.is_empty()
-            && body.is_none_or(|body| sig.header.safety == Safety::Unsafe || contains_unsafe_block(cx, body.value))
+            && body.is_none_or(|body| sig.header.safety.is_unsafe() || contains_unsafe_block(cx, body.value))
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index b79e59f857b..45d730985bb 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -203,7 +203,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
         let item_has_safety_comment = item_has_safety_comment(cx, item);
         match (&item.kind, item_has_safety_comment) {
             // lint unsafe impl without safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety == hir::Safety::Unsafe => {
+            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety.is_unsafe() => {
                 if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
                     && !is_unsafe_from_proc_macro(cx, item.span)
                 {
@@ -227,7 +227,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 }
             },
             // lint safe impl with unnecessary safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety == hir::Safety::Safe => {
+            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety.is_safe() => {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 3269bf758ac..b71b53ea3bb 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -373,7 +373,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
         TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
         TyKind::BareFn(bare_fn) => (
-            if bare_fn.safety == Safety::Unsafe {
+            if bare_fn.safety.is_unsafe() {
                 Pat::Str("unsafe")
             } else if bare_fn.abi != Abi::Rust {
                 Pat::Str("extern")
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 260d1b801e3..bc3c3ca5c21 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, FnDecl, LangItem, Safety, TyKind};
+use rustc_hir::{Expr, FnDecl, LangItem, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::ConstValue;
@@ -531,7 +531,7 @@ pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
 /// Returns `true` if the given type is an `unsafe` function.
 pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::FnDef(..) | ty::FnPtr(..) => ty.fn_sig(cx.tcx).safety() == Safety::Unsafe,
+        ty::FnDef(..) | ty::FnPtr(..) => ty.fn_sig(cx.tcx).safety().is_unsafe(),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index ff58c6358ba..71499b1293a 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr};
 use rustc_hir::{
     AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath,
-    Safety, Stmt, UnOp, UnsafeSource, StructTailExpr,
+    Stmt, UnOp, UnsafeSource, StructTailExpr,
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
@@ -426,15 +426,15 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .is_some_and(|id| self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe) =>
+                        .is_some_and(|id| self.cx.tcx.fn_sig(id).skip_binder().safety().is_unsafe()) =>
                 {
                     ControlFlow::Break(())
                 },
                 ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
-                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe => {
+                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().safety().is_unsafe() => {
                         ControlFlow::Break(())
                     },
-                    ty::FnPtr(_, hdr) if hdr.safety == Safety::Unsafe => ControlFlow::Break(()),
+                    ty::FnPtr(_, hdr) if hdr.safety.is_unsafe() => ControlFlow::Break(()),
                     _ => walk_expr(self, e),
                 },
                 ExprKind::Path(ref p)
@@ -458,7 +458,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
         }
         fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
             if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind
-                && i.safety == Safety::Unsafe
+                && i.safety.is_unsafe()
             {
                 ControlFlow::Break(())
             } else {
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index ffe10092cc2..8894ea7fb20 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -325,6 +325,12 @@ impl Rustc {
         self
     }
 
+    /// Pass the `--verbose` flag.
+    pub fn verbose(&mut self) -> &mut Self {
+        self.cmd.arg("--verbose");
+        self
+    }
+
     /// `EXTRARSCXXFLAGS`
     pub fn extra_rs_cxx_flags(&mut self) -> &mut Self {
         // Adapted from tools.mk (trimmed):
diff --git a/tests/run-make/link-args-order/rmake.rs b/tests/run-make/link-args-order/rmake.rs
index b7ef8333267..fe0d02926ef 100644
--- a/tests/run-make/link-args-order/rmake.rs
+++ b/tests/run-make/link-args-order/rmake.rs
@@ -15,8 +15,9 @@ fn main() {
         .link_args("b c")
         .link_args("d e")
         .link_arg("f")
+        .arg("--print=link-args")
         .run_fail()
-        .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
+        .assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
     rustc()
         .input("empty.rs")
         .linker_flavor(linker)
@@ -24,6 +25,7 @@ fn main() {
         .arg("-Zpre-link-args=b c")
         .arg("-Zpre-link-args=d e")
         .arg("-Zpre-link-arg=f")
+        .arg("--print=link-args")
         .run_fail()
-        .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
+        .assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
 }
diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs
index 6075f310954..f38603dee8c 100644
--- a/tests/run-make/link-dedup/rmake.rs
+++ b/tests/run-make/link-dedup/rmake.rs
@@ -14,13 +14,13 @@ fn main() {
     rustc().input("depb.rs").run();
     rustc().input("depc.rs").run();
 
-    let output = rustc().input("empty.rs").cfg("bar").run_fail();
-    output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
+    let output = rustc().input("empty.rs").cfg("bar").arg("--print=link-args").run_fail();
+    output.assert_stdout_contains(needle_from_libs(&["testa", "testb", "testa"]));
 
-    let output = rustc().input("empty.rs").run_fail();
-    output.assert_stderr_contains(needle_from_libs(&["testa"]));
-    output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
-    output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
+    let output = rustc().input("empty.rs").arg("--print=link-args").run_fail();
+    output.assert_stdout_contains(needle_from_libs(&["testa"]));
+    output.assert_stdout_not_contains(needle_from_libs(&["testb"]));
+    output.assert_stdout_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
     // Adjacent identical native libraries are no longer deduplicated if
     // they come from different crates (https://github.com/rust-lang/rust/pull/103311)
     // so the following will fail:
diff --git a/tests/run-make/linker-warning/fake-linker.rs b/tests/run-make/linker-warning/fake-linker.rs
new file mode 100644
index 00000000000..30497eea2cc
--- /dev/null
+++ b/tests/run-make/linker-warning/fake-linker.rs
@@ -0,0 +1,13 @@
+fn main() {
+    for arg in std::env::args() {
+        match &*arg {
+            "run_make_info" => println!("foo"),
+            "run_make_warn" => eprintln!("warning: bar"),
+            "run_make_error" => {
+                eprintln!("error: baz");
+                std::process::exit(1);
+            }
+            _ => (),
+        }
+    }
+}
diff --git a/tests/run-make/linker-warning/main.rs b/tests/run-make/linker-warning/main.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/linker-warning/main.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
new file mode 100644
index 00000000000..4d21c5ea569
--- /dev/null
+++ b/tests/run-make/linker-warning/rmake.rs
@@ -0,0 +1,28 @@
+use run_make_support::{Rustc, rustc};
+
+fn run_rustc() -> Rustc {
+    let mut rustc = rustc();
+    rustc.arg("main.rs").output("main").linker("./fake-linker");
+    rustc
+}
+
+fn main() {
+    // first, compile our linker
+    rustc().arg("fake-linker.rs").output("fake-linker").run();
+
+    // Make sure we don't show the linker args unless `--verbose` is passed
+    run_rustc()
+        .link_arg("run_make_error")
+        .verbose()
+        .run_fail()
+        .assert_stderr_contains_regex("fake-linker.*run_make_error")
+        .assert_stderr_not_contains("object files omitted")
+        .assert_stderr_contains_regex(r"lib(/|\\\\)libstd");
+    run_rustc()
+        .link_arg("run_make_error")
+        .run_fail()
+        .assert_stderr_contains("fake-linker")
+        .assert_stderr_contains("object files omitted")
+        .assert_stderr_contains_regex(r"\{")
+        .assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd");
+}
diff --git a/tests/ui/impl-trait/in-bindings/dont-make-def-id.rs b/tests/ui/impl-trait/in-bindings/dont-make-def-id.rs
new file mode 100644
index 00000000000..d159e9ab0f9
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/dont-make-def-id.rs
@@ -0,0 +1,10 @@
+//@ check-pass
+
+// Make sure we don't create an opaque def id for ITIB.
+
+#![crate_type = "lib"]
+#![feature(impl_trait_in_bindings)]
+
+fn foo() {
+    let _: impl Sized = 0;
+}