about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-02-04 03:07:00 +0000
committerbors <bors@rust-lang.org>2025-02-04 03:07:00 +0000
commitc705b7d6f748823352f95247835a5839dcbd7bed (patch)
tree089bd9ceb827c1f18e3c49099da6560e718aef33
parentaffdb59607566c1615c829eea9e7b27a093994ec (diff)
parent1869633ea248d7e30002c6fb1bd23a567275872a (diff)
downloadrust-c705b7d6f748823352f95247835a5839dcbd7bed.tar.gz
rust-c705b7d6f748823352f95247835a5839dcbd7bed.zip
Auto merge of #136507 - matthiaskrgr:rollup-uzwv9mo, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #136289 (OnceCell & OnceLock docs: Using (un)initialized consistently)
 - #136299 (Ignore NLL boring locals in polonius diagnostics)
 - #136411 (Omit argument names from function pointers that do not have argument names)
 - #136430 (Use the type-level constant value `ty::Value` where needed)
 - #136476 (Remove generic `//@ ignore-{wasm,wasm32,emscripten}` in tests)
 - #136484 (Notes on types/traits used for in-memory query caching)
 - #136493 (platform-support: document CPU baseline for x86-32 targets)
 - #136498 (Update books)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs23
-rw-r--r--compiler/rustc_borrowck/src/lib.rs10
-rw-r--r--compiler/rustc_borrowck/src/nll.rs11
-rw-r--r--compiler/rustc_borrowck/src/polonius/dump.rs14
-rw-r--r--compiler/rustc_borrowck/src/polonius/liveness_constraints.rs24
-rw-r--r--compiler/rustc_borrowck/src/polonius/mod.rs87
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs37
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs25
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs42
-rw-r--r--compiler/rustc_const_eval/src/lib.rs10
-rw-r--r--compiler/rustc_data_structures/src/vec_cache.rs13
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs11
-rw-r--r--compiler/rustc_middle/src/query/keys.rs6
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs47
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs42
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs2
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs20
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs8
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs3
-rw-r--r--library/core/src/cell/once.rs53
-rw-r--r--library/std/src/sync/once_lock.rs65
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc/src/platform-support.md40
-rw-r--r--src/librustdoc/clean/mod.rs22
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--tests/rustdoc/assoc-consts.rs2
-rw-r--r--tests/rustdoc/fn-pointer-arg-name.rs8
-rw-r--r--tests/rustdoc/inherent-projections.rs2
-rw-r--r--tests/rustdoc/macro-higher-kinded-function.rs8
-rw-r--r--tests/ui/lifetimes/tail-expr-lock-poisoning.rs1
-rw-r--r--tests/ui/nll/get_default.legacy.stderr18
-rw-r--r--tests/ui/nll/get_default.nll.stderr (renamed from tests/ui/nll/get_default.stderr)10
-rw-r--r--tests/ui/nll/get_default.polonius.stderr18
-rw-r--r--tests/ui/nll/get_default.rs17
-rw-r--r--tests/ui/nll/issue-46589.nll.stderr (renamed from tests/ui/nll/issue-46589.stderr)2
-rw-r--r--tests/ui/nll/issue-46589.rs13
-rw-r--r--tests/ui/nll/polonius/assignment-kills-loans.rs5
-rw-r--r--tests/ui/nll/polonius/assignment-to-differing-field.legacy.stderr (renamed from tests/ui/nll/polonius/assignment-to-differing-field.stderr)8
-rw-r--r--tests/ui/nll/polonius/assignment-to-differing-field.polonius.stderr51
-rw-r--r--tests/ui/nll/polonius/assignment-to-differing-field.rs5
-rw-r--r--tests/ui/nll/polonius/call-kills-loans.rs5
-rw-r--r--tests/ui/nll/polonius/issue-46589.rs31
-rw-r--r--tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs6
-rw-r--r--tests/ui/nll/polonius/polonius-smoke-test.legacy.stderr (renamed from tests/ui/nll/polonius/polonius-smoke-test.stderr)8
-rw-r--r--tests/ui/nll/polonius/polonius-smoke-test.polonius.stderr59
-rw-r--r--tests/ui/nll/polonius/polonius-smoke-test.rs8
-rw-r--r--tests/ui/nll/polonius/storagedead-kills-loans.rs5
-rw-r--r--tests/ui/nll/polonius/subset-relations.legacy.stderr (renamed from tests/ui/nll/polonius/subset-relations.stderr)2
-rw-r--r--tests/ui/nll/polonius/subset-relations.polonius.stderr14
-rw-r--r--tests/ui/nll/polonius/subset-relations.rs7
-rw-r--r--tests/ui/panics/issue-47429-short-backtraces.rs2
-rw-r--r--tests/ui/panics/issue-47429-short-backtraces.run.stderr2
-rw-r--r--tests/ui/panics/runtime-switch.rs1
-rw-r--r--tests/ui/panics/runtime-switch.run.stderr2
-rw-r--r--tests/ui/panics/short-ice-remove-middle-frames-2.rs1
-rw-r--r--tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr2
-rw-r--r--tests/ui/panics/short-ice-remove-middle-frames.rs1
-rw-r--r--tests/ui/panics/short-ice-remove-middle-frames.run.stderr2
-rw-r--r--tests/ui/test-attrs/test-panic-abort-disabled.rs2
-rw-r--r--tests/ui/test-attrs/test-panic-abort-nocapture.rs2
-rw-r--r--tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr4
-rw-r--r--tests/ui/test-attrs/test-panic-abort.rs2
-rw-r--r--tests/ui/test-attrs/test-panic-abort.run.stdout2
69 files changed, 622 insertions, 340 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 841cb782bc3..3e474225afd 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -622,8 +622,25 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
             }
         }
 
+        // NLL doesn't consider boring locals for liveness, and wouldn't encounter a
+        // `Cause::LiveVar` for such a local. Polonius can't avoid computing liveness for boring
+        // locals yet, and will encounter them when trying to explain why a borrow contains a given
+        // point.
+        //
+        // We want to focus on relevant live locals in diagnostics, so when polonius is enabled, we
+        // ensure that we don't emit live boring locals as explanations.
+        let is_local_boring = |local| {
+            if let Some(polonius_diagnostics) = self.polonius_diagnostics {
+                polonius_diagnostics.boring_nll_locals.contains(&local)
+            } else {
+                assert!(!tcx.sess.opts.unstable_opts.polonius.is_next_enabled());
+
+                // Boring locals are never the cause of a borrow explanation in NLLs.
+                false
+            }
+        };
         match find_use::find(body, regioncx, tcx, region_sub, use_location) {
-            Some(Cause::LiveVar(local, location)) => {
+            Some(Cause::LiveVar(local, location)) if !is_local_boring(local) => {
                 let span = body.source_info(location).span;
                 let spans = self
                     .move_spans(Place::from(local).as_ref(), location)
@@ -666,7 +683,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
                 }
             }
 
-            None => {
+            Some(Cause::LiveVar(..)) | None => {
+                // Here, under NLL: no cause was found. Under polonius: no cause was found, or a
+                // boring local was found, which we ignore like NLLs do to match its diagnostics.
                 if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
                     let (category, from_closure, span, region_name, path) =
                         self.free_region_constraint_info(borrow_region_vid, region);
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 077d8f49df8..8ddc8add675 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -60,6 +60,7 @@ use crate::diagnostics::{
 use crate::path_utils::*;
 use crate::place_ext::PlaceExt;
 use crate::places_conflict::{PlaceConflictBias, places_conflict};
+use crate::polonius::PoloniusDiagnosticsContext;
 use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
 use crate::prefixes::PrefixSet;
 use crate::region_infer::RegionInferenceContext;
@@ -198,7 +199,7 @@ fn do_mir_borrowck<'tcx>(
         polonius_output,
         opt_closure_req,
         nll_errors,
-        localized_outlives_constraints,
+        polonius_diagnostics,
     } = nll::compute_regions(
         &infcx,
         free_regions,
@@ -270,6 +271,7 @@ fn do_mir_borrowck<'tcx>(
             polonius_output: None,
             move_errors: Vec::new(),
             diags_buffer,
+            polonius_diagnostics: polonius_diagnostics.as_ref(),
         };
         struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
             ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
@@ -308,6 +310,7 @@ fn do_mir_borrowck<'tcx>(
         polonius_output,
         move_errors: Vec::new(),
         diags_buffer,
+        polonius_diagnostics: polonius_diagnostics.as_ref(),
     };
 
     // Compute and report region errors, if any.
@@ -329,7 +332,7 @@ fn do_mir_borrowck<'tcx>(
         body,
         &regioncx,
         &borrow_set,
-        localized_outlives_constraints,
+        polonius_diagnostics.as_ref(),
         &opt_closure_req,
     );
 
@@ -579,6 +582,9 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
 
     diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
     move_errors: Vec<MoveError<'tcx>>,
+
+    /// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
+    polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
 }
 
 // Check that:
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 35264bd1a70..2031579dfd5 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -27,7 +27,7 @@ use tracing::{debug, instrument};
 use crate::borrow_set::BorrowSet;
 use crate::consumers::ConsumerOptions;
 use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
-use crate::polonius::LocalizedOutlivesConstraintSet;
+use crate::polonius::PoloniusDiagnosticsContext;
 use crate::polonius::legacy::{
     PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
 };
@@ -46,8 +46,9 @@ pub(crate) struct NllOutput<'tcx> {
     pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
     pub nll_errors: RegionErrors<'tcx>,
 
-    /// When using `-Zpolonius=next`: the localized typeck and liveness constraints.
-    pub localized_outlives_constraints: Option<LocalizedOutlivesConstraintSet>,
+    /// When using `-Zpolonius=next`: the data used to compute errors and diagnostics, e.g.
+    /// localized typeck and liveness constraints.
+    pub polonius_diagnostics: Option<PoloniusDiagnosticsContext>,
 }
 
 /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
@@ -144,7 +145,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
 
     // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
     // and use them to compute loan liveness.
-    let localized_outlives_constraints = polonius_context.as_ref().map(|polonius_context| {
+    let polonius_diagnostics = polonius_context.map(|polonius_context| {
         polonius_context.compute_loan_liveness(infcx.tcx, &mut regioncx, body, borrow_set)
     });
 
@@ -188,7 +189,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
         polonius_output,
         opt_closure_req: closure_region_requirements,
         nll_errors,
-        localized_outlives_constraints,
+        polonius_diagnostics,
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index 6d32ee17f4c..5f9fa3612b8 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -12,7 +12,9 @@ use rustc_session::config::MirIncludeSpans;
 
 use crate::borrow_set::BorrowSet;
 use crate::constraints::OutlivesConstraint;
-use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
+use crate::polonius::{
+    LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet, PoloniusDiagnosticsContext,
+};
 use crate::region_infer::values::LivenessValues;
 use crate::type_check::Locations;
 use crate::{BorrowckInferCtxt, RegionInferenceContext};
@@ -23,7 +25,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    localized_outlives_constraints: Option<LocalizedOutlivesConstraintSet>,
+    polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
 ) {
     let tcx = infcx.tcx;
@@ -35,8 +37,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
         return;
     }
 
-    let localized_outlives_constraints = localized_outlives_constraints
-        .expect("missing localized constraints with `-Zpolonius=next`");
+    let polonius_diagnostics =
+        polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`");
 
     let _: io::Result<()> = try {
         let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?;
@@ -45,7 +47,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
             body,
             regioncx,
             borrow_set,
-            localized_outlives_constraints,
+            &polonius_diagnostics.localized_outlives_constraints,
             closure_region_requirements,
             &mut file,
         )?;
@@ -63,7 +65,7 @@ fn emit_polonius_dump<'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    localized_outlives_constraints: LocalizedOutlivesConstraintSet,
+    localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
     closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
     out: &mut dyn io::Write,
 ) -> io::Result<()> {
diff --git a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs
index 75ee29c9d0d..6ab09f731c0 100644
--- a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs
+++ b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs
@@ -1,7 +1,6 @@
 use std::collections::BTreeMap;
 
 use rustc_index::bit_set::SparseBitMatrix;
-use rustc_index::interval::SparseIntervalMatrix;
 use rustc_middle::mir::{Body, Location};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
@@ -9,12 +8,12 @@ use rustc_mir_dataflow::points::PointIndex;
 
 use super::{
     ConstraintDirection, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
-    PoloniusContext,
+    PoloniusLivenessContext,
 };
 use crate::region_infer::values::LivenessValues;
 use crate::universal_regions::UniversalRegions;
 
-impl PoloniusContext {
+impl PoloniusLivenessContext {
     /// Record the variance of each region contained within the given value.
     pub(crate) fn record_live_region_variance<'tcx>(
         &mut self,
@@ -30,25 +29,6 @@ impl PoloniusContext {
         };
         extractor.relate(value, value).expect("Can't have a type error relating to itself");
     }
-
-    /// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
-    /// need to transpose the "points where each region is live" matrix to a "live regions per point"
-    /// matrix.
-    // FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
-    // borrowck.
-    pub(crate) fn record_live_regions_per_point(
-        &mut self,
-        num_regions: usize,
-        points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
-    ) {
-        let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
-        for region in points_per_live_region.rows() {
-            for point in points_per_live_region.row(region).unwrap().iter() {
-                live_regions_per_point.insert(point, region);
-            }
-        }
-        self.live_regions = Some(live_regions_per_point);
-    }
 }
 
 /// Propagate loans throughout the CFG: for each statement in the MIR, create localized outlives
diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs
index 502c868194a..142ef8ba28e 100644
--- a/compiler/rustc_borrowck/src/polonius/mod.rs
+++ b/compiler/rustc_borrowck/src/polonius/mod.rs
@@ -32,6 +32,16 @@
 //! - <https://smallcultfollowing.com/babysteps/blog/2023/09/22/polonius-part-1/>
 //! - <https://smallcultfollowing.com/babysteps/blog/2023/09/29/polonius-part-2/>
 //!
+//!
+//! Data flows like this:
+//! 1) during MIR typeck, record liveness data needed later: live region variances, as well as the
+//!    usual NLL liveness data (just computed on more locals). That's the [PoloniusLivenessContext].
+//! 2) once that is done, variance data is transferred, and the NLL region liveness is converted to
+//!    the polonius shape. That's the main [PoloniusContext].
+//! 3) during region inference, that data and the NLL outlives constraints are used to create the
+//!    localized outlives constraints, as described above. That's the [PoloniusDiagnosticsContext].
+//! 4) transfer this back to the main borrowck procedure: it handles computing errors and
+//!    diagnostics, debugging and MIR dumping concerns.
 
 mod constraints;
 mod dump;
@@ -42,8 +52,10 @@ mod typeck_constraints;
 
 use std::collections::BTreeMap;
 
+use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::SparseBitMatrix;
-use rustc_middle::mir::Body;
+use rustc_index::interval::SparseIntervalMatrix;
+use rustc_middle::mir::{Body, Local};
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::points::PointIndex;
 
@@ -57,15 +69,40 @@ use crate::{BorrowSet, RegionInferenceContext};
 
 pub(crate) type LiveLoans = SparseBitMatrix<PointIndex, BorrowIndex>;
 
-/// This struct holds the data needed to create the Polonius localized constraints.
+/// This struct holds the liveness data created during MIR typeck, and which will be used later in
+/// the process, to compute the polonius localized constraints.
+#[derive(Default)]
+pub(crate) struct PoloniusLivenessContext {
+    /// The expected edge direction per live region: the kind of directed edge we'll create as
+    /// liveness constraints depends on the variance of types with respect to each contained region.
+    live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
+
+    /// The regions that outlive free regions are used to distinguish relevant live locals from
+    /// boring locals. A boring local is one whose type contains only such regions. Polonius
+    /// currently has more boring locals than NLLs so we record the latter to use in errors and
+    /// diagnostics, to focus on the locals we consider relevant and match NLL diagnostics.
+    pub(crate) boring_nll_locals: FxHashSet<Local>,
+}
+
+/// This struct holds the data needed to create the Polonius localized constraints. Its data is
+/// transferred and converted from the [PoloniusLivenessContext] at the end of MIR typeck.
 pub(crate) struct PoloniusContext {
+    /// The liveness data we recorded during MIR typeck.
+    liveness_context: PoloniusLivenessContext,
+
     /// The set of regions that are live at a given point in the CFG, used to create localized
     /// outlives constraints between regions that are live at connected points in the CFG.
-    live_regions: Option<SparseBitMatrix<PointIndex, RegionVid>>,
+    live_regions: SparseBitMatrix<PointIndex, RegionVid>,
+}
 
-    /// The expected edge direction per live region: the kind of directed edge we'll create as
-    /// liveness constraints depends on the variance of types with respect to each contained region.
-    live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
+/// This struct holds the data needed by the borrowck error computation and diagnostics. Its data is
+/// computed from the [PoloniusContext] when computing NLL regions.
+pub(crate) struct PoloniusDiagnosticsContext {
+    /// The localized outlives constraints that were computed in the main analysis.
+    localized_outlives_constraints: LocalizedOutlivesConstraintSet,
+
+    /// The liveness data computed during MIR typeck: [PoloniusLivenessContext::boring_nll_locals].
+    pub(crate) boring_nll_locals: FxHashSet<Local>,
 }
 
 /// The direction a constraint can flow into. Used to create liveness constraints according to
@@ -83,8 +120,24 @@ enum ConstraintDirection {
 }
 
 impl PoloniusContext {
-    pub(crate) fn new() -> PoloniusContext {
-        Self { live_region_variances: BTreeMap::new(), live_regions: None }
+    /// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
+    /// need to transpose the "points where each region is live" matrix to a "live regions per point"
+    /// matrix.
+    // FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
+    // borrowck.
+    pub(crate) fn create_from_liveness(
+        liveness_context: PoloniusLivenessContext,
+        num_regions: usize,
+        points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
+    ) -> PoloniusContext {
+        let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
+        for region in points_per_live_region.rows() {
+            for point in points_per_live_region.row(region).unwrap().iter() {
+                live_regions_per_point.insert(point, region);
+            }
+        }
+
+        PoloniusContext { live_regions: live_regions_per_point, liveness_context }
     }
 
     /// Computes live loans using the set of loans model for `-Zpolonius=next`.
@@ -95,13 +148,18 @@ impl PoloniusContext {
     ///
     /// Then, this graph is traversed, and combined with kills, reachability is recorded as loan
     /// liveness, to be used by the loan scope and active loans computations.
+    ///
+    /// The constraint data will be used to compute errors and diagnostics.
     pub(crate) fn compute_loan_liveness<'tcx>(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         regioncx: &mut RegionInferenceContext<'tcx>,
         body: &Body<'tcx>,
         borrow_set: &BorrowSet<'tcx>,
-    ) -> LocalizedOutlivesConstraintSet {
+    ) -> PoloniusDiagnosticsContext {
+        let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
+            self.liveness_context;
+
         let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
         convert_typeck_constraints(
             tcx,
@@ -112,14 +170,11 @@ impl PoloniusContext {
             &mut localized_outlives_constraints,
         );
 
-        let live_regions = self.live_regions.as_ref().expect(
-            "live regions per-point data should have been created at the end of MIR typeck",
-        );
         create_liveness_constraints(
             body,
             regioncx.liveness_constraints(),
-            live_regions,
-            &self.live_region_variances,
+            &self.live_regions,
+            &live_region_variances,
             regioncx.universal_regions(),
             &mut localized_outlives_constraints,
         );
@@ -136,6 +191,6 @@ impl PoloniusContext {
         );
         regioncx.record_live_loans(live_loans);
 
-        localized_outlives_constraints
+        PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index 4e0b2a4e296..dcc17903002 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -14,7 +14,7 @@ use tracing::debug;
 
 use super::TypeChecker;
 use crate::constraints::OutlivesConstraintSet;
-use crate::polonius::PoloniusContext;
+use crate::polonius::PoloniusLivenessContext;
 use crate::region_infer::values::LivenessValues;
 use crate::universal_regions::UniversalRegions;
 
@@ -38,19 +38,24 @@ pub(super) fn generate<'a, 'tcx>(
 ) {
     debug!("liveness::generate");
 
+    let mut free_regions = regions_that_outlive_free_regions(
+        typeck.infcx.num_region_vars(),
+        &typeck.universal_regions,
+        &typeck.constraints.outlives_constraints,
+    );
+
     // NLLs can avoid computing some liveness data here because its constraints are
     // location-insensitive, but that doesn't work in polonius: locals whose type contains a region
     // that outlives a free region are not necessarily live everywhere in a flow-sensitive setting,
     // unlike NLLs.
-    let free_regions = if !typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
-        regions_that_outlive_free_regions(
-            typeck.infcx.num_region_vars(),
-            &typeck.universal_regions,
-            &typeck.constraints.outlives_constraints,
-        )
-    } else {
-        typeck.universal_regions.universal_regions_iter().collect()
-    };
+    // We do record these regions in the polonius context, since they're used to differentiate
+    // relevant and boring locals, which is a key distinction used later in diagnostics.
+    if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
+        let (_, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
+        typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals =
+            boring_locals.into_iter().collect();
+        free_regions = typeck.universal_regions.universal_regions_iter().collect();
+    }
     let (relevant_live_locals, boring_locals) =
         compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
 
@@ -70,7 +75,7 @@ pub(super) fn generate<'a, 'tcx>(
         typeck.tcx(),
         &mut typeck.constraints.liveness_constraints,
         &typeck.universal_regions,
-        &mut typeck.polonius_context,
+        &mut typeck.polonius_liveness,
         body,
     );
 }
@@ -147,11 +152,11 @@ fn record_regular_live_regions<'tcx>(
     tcx: TyCtxt<'tcx>,
     liveness_constraints: &mut LivenessValues,
     universal_regions: &UniversalRegions<'tcx>,
-    polonius_context: &mut Option<PoloniusContext>,
+    polonius_liveness: &mut Option<PoloniusLivenessContext>,
     body: &Body<'tcx>,
 ) {
     let mut visitor =
-        LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_context };
+        LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_liveness };
     for (bb, data) in body.basic_blocks.iter_enumerated() {
         visitor.visit_basic_block_data(bb, data);
     }
@@ -162,7 +167,7 @@ struct LiveVariablesVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     liveness_constraints: &'a mut LivenessValues,
     universal_regions: &'a UniversalRegions<'tcx>,
-    polonius_context: &'a mut Option<PoloniusContext>,
+    polonius_liveness: &'a mut Option<PoloniusLivenessContext>,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> {
@@ -214,8 +219,8 @@ impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {
         });
 
         // When using `-Zpolonius=next`, we record the variance of each live region.
-        if let Some(polonius_context) = self.polonius_context {
-            polonius_context.record_live_region_variance(self.tcx, self.universal_regions, value);
+        if let Some(polonius_liveness) = self.polonius_liveness {
+            polonius_liveness.record_live_region_variance(self.tcx, self.universal_regions, value);
         }
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index c564d85616e..62d49a62744 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -580,8 +580,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         });
 
         // When using `-Zpolonius=next`, we record the variance of each live region.
-        if let Some(polonius_context) = typeck.polonius_context {
-            polonius_context.record_live_region_variance(
+        if let Some(polonius_liveness) = typeck.polonius_liveness.as_mut() {
+            polonius_liveness.record_live_region_variance(
                 typeck.infcx.tcx,
                 typeck.universal_regions,
                 value,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 92492bfdb8d..78aa38e9e48 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -48,8 +48,8 @@ use crate::borrow_set::BorrowSet;
 use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
 use crate::diagnostics::UniverseInfo;
 use crate::member_constraints::MemberConstraintSet;
-use crate::polonius::PoloniusContext;
 use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
+use crate::polonius::{PoloniusContext, PoloniusLivenessContext};
 use crate::region_infer::TypeTest;
 use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
 use crate::renumber::RegionCtxt;
@@ -148,8 +148,8 @@ pub(crate) fn type_check<'a, 'tcx>(
 
     debug!(?normalized_inputs_and_output);
 
-    let mut polonius_context = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
-        Some(PoloniusContext::new())
+    let polonius_liveness = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
+        Some(PoloniusLivenessContext::default())
     } else {
         None
     };
@@ -168,7 +168,7 @@ pub(crate) fn type_check<'a, 'tcx>(
         polonius_facts,
         borrow_set,
         constraints: &mut constraints,
-        polonius_context: &mut polonius_context,
+        polonius_liveness,
     };
 
     typeck.check_user_type_annotations();
@@ -185,11 +185,14 @@ pub(crate) fn type_check<'a, 'tcx>(
     let opaque_type_values =
         opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
 
-    if let Some(polonius_context) = typeck.polonius_context.as_mut() {
-        let num_regions = infcx.num_region_vars();
-        let points_per_live_region = typeck.constraints.liveness_constraints.points();
-        polonius_context.record_live_regions_per_point(num_regions, points_per_live_region);
-    }
+    // We're done with typeck, we can finalize the polonius liveness context for region inference.
+    let polonius_context = typeck.polonius_liveness.take().map(|liveness_context| {
+        PoloniusContext::create_from_liveness(
+            liveness_context,
+            infcx.num_region_vars(),
+            typeck.constraints.liveness_constraints.points(),
+        )
+    });
 
     MirTypeckResults {
         constraints,
@@ -583,8 +586,8 @@ struct TypeChecker<'a, 'tcx> {
     polonius_facts: &'a mut Option<PoloniusFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
-    /// When using `-Zpolonius=next`, the helper data used to create polonius constraints.
-    polonius_context: &'a mut Option<PoloniusContext>,
+    /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints.
+    polonius_liveness: Option<PoloniusLivenessContext>,
 }
 
 /// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 4d625f76aba..c35910a706b 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -273,59 +273,63 @@ pub(crate) fn eval_to_valtree<'tcx>(
 /// Converts a `ValTree` to a `ConstValue`, which is needed after mir
 /// construction has finished.
 // FIXME(valtrees): Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
-// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
 #[instrument(skip(tcx), level = "debug", ret)]
 pub fn valtree_to_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
-    ty: Ty<'tcx>,
-    valtree: ty::ValTree<'tcx>,
+    cv: ty::Value<'tcx>,
 ) -> mir::ConstValue<'tcx> {
     // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
     // (those for constants with type bool, int, uint, float or char).
     // For all other types we create an `MPlace` and fill that by walking
     // the `ValTree` and using `place_projection` and `place_field` to
     // create inner `MPlace`s which are filled recursively.
-    // FIXME Does this need an example?
-    match *ty.kind() {
+    // FIXME: Does this need an example?
+    match *cv.ty.kind() {
         ty::FnDef(..) => {
-            assert!(valtree.unwrap_branch().is_empty());
+            assert!(cv.valtree.unwrap_branch().is_empty());
             mir::ConstValue::ZeroSized
         }
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_, _) => {
-            match valtree {
+            match cv.valtree {
                 ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
                 ty::ValTree::Branch(_) => bug!(
                     "ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf"
                 ),
             }
         }
-        ty::Pat(ty, _) => valtree_to_const_value(tcx, typing_env, ty, valtree),
+        ty::Pat(ty, _) => {
+            let cv = ty::Value { valtree: cv.valtree, ty };
+            valtree_to_const_value(tcx, typing_env, cv)
+        }
         ty::Ref(_, inner_ty, _) => {
             let mut ecx =
                 mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
-            let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
-            let imm =
-                ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap());
+            let imm = valtree_to_ref(&mut ecx, cv.valtree, inner_ty);
+            let imm = ImmTy::from_immediate(
+                imm,
+                tcx.layout_of(typing_env.as_query_input(cv.ty)).unwrap(),
+            );
             op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
         }
         ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
-            let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
+            let layout = tcx.layout_of(typing_env.as_query_input(cv.ty)).unwrap();
             if layout.is_zst() {
                 // Fast path to avoid some allocations.
                 return mir::ConstValue::ZeroSized;
             }
             if layout.backend_repr.is_scalar()
-                && (matches!(ty.kind(), ty::Tuple(_))
-                    || matches!(ty.kind(), ty::Adt(def, _) if def.is_struct()))
+                && (matches!(cv.ty.kind(), ty::Tuple(_))
+                    || matches!(cv.ty.kind(), ty::Adt(def, _) if def.is_struct()))
             {
                 // A Scalar tuple/struct; we can avoid creating an allocation.
-                let branches = valtree.unwrap_branch();
+                let branches = cv.valtree.unwrap_branch();
                 // Find the non-ZST field. (There can be aligned ZST!)
                 for (i, &inner_valtree) in branches.iter().enumerate() {
                     let field = layout.field(&LayoutCx::new(tcx, typing_env), i);
                     if !field.is_zst() {
-                        return valtree_to_const_value(tcx, typing_env, field.ty, inner_valtree);
+                        let cv = ty::Value { valtree: inner_valtree, ty: field.ty };
+                        return valtree_to_const_value(tcx, typing_env, cv);
                     }
                 }
                 bug!("could not find non-ZST field during in {layout:#?}");
@@ -335,9 +339,9 @@ pub fn valtree_to_const_value<'tcx>(
                 mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
 
             // Need to create a place for this valtree.
-            let place = create_valtree_place(&mut ecx, layout, valtree);
+            let place = create_valtree_place(&mut ecx, layout, cv.valtree);
 
-            valtree_into_mplace(&mut ecx, &place, valtree);
+            valtree_into_mplace(&mut ecx, &place, cv.valtree);
             dump_place(&ecx, &place);
             intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
 
@@ -362,7 +366,7 @@ pub fn valtree_to_const_value<'tcx>(
         | ty::Slice(_)
         | ty::Dynamic(..)
         | ty::UnsafeBinder(_) => {
-            bug!("no ValTree should have been created for type {:?}", ty.kind())
+            bug!("no ValTree should have been created for type {:?}", cv.ty.kind())
         }
     }
 }
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index ecf9745b779..b44d2a01d57 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -46,14 +46,8 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.hooks.try_destructure_mir_constant_for_user_output =
         const_eval::try_destructure_mir_constant_for_user_output;
-    providers.valtree_to_const_val = |tcx, cv| {
-        const_eval::valtree_to_const_value(
-            tcx,
-            ty::TypingEnv::fully_monomorphized(),
-            cv.ty,
-            cv.valtree,
-        )
-    };
+    providers.valtree_to_const_val =
+        |tcx, cv| const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), cv);
     providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
         util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
     };
diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs
index eb251b587c8..2ff60ab7f36 100644
--- a/compiler/rustc_data_structures/src/vec_cache.rs
+++ b/compiler/rustc_data_structures/src/vec_cache.rs
@@ -206,6 +206,19 @@ impl SlotIndex {
     }
 }
 
+/// In-memory cache for queries whose keys are densely-numbered IDs
+/// (e.g `CrateNum`, `LocalDefId`), and can therefore be used as indices
+/// into a dense vector of cached values.
+///
+/// (As of [#124780] the underlying storage is not an actual `Vec`, but rather
+/// a series of increasingly-large buckets, for improved performance when the
+/// parallel frontend is using multiple threads.)
+///
+/// Each entry in the cache stores the query's return value (`V`), and also
+/// an associated index (`I`), which in practice is a `DepNodeIndex` used for
+/// query dependency tracking.
+///
+/// [#124780]: https://github.com/rust-lang/rust/pull/124780
 pub struct VecCache<K: Idx, V, I> {
     // Entries per bucket:
     // Bucket  0:       4096 2^12
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 09d7e60e199..aa8ec3aff04 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -12,6 +12,7 @@ use rustc_middle::mir::interpret::{
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use tracing::trace;
+use ty::print::PrettyPrinter;
 
 use super::graphviz::write_mir_fn_graphviz;
 use crate::mir::interpret::ConstAllocation;
@@ -1439,10 +1440,10 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                 })
             };
 
-            // FIXME: call pretty_print_const_valtree?
-            let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
-                ty::ValTree::Leaf(leaf) => format!("Leaf({leaf:?})"),
-                ty::ValTree::Branch(_) => "Branch(..)".to_string(),
+            let fmt_valtree = |cv: &ty::Value<'tcx>| {
+                let mut cx = FmtPrinter::new(self.tcx, Namespace::ValueNS);
+                cx.pretty_print_const_valtree(*cv, /*print_ty*/ true).unwrap();
+                cx.into_buffer()
             };
 
             let val = match const_ {
@@ -1452,7 +1453,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                         format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
                     }
                     ty::ConstKind::Value(cv) => {
-                        format!("ty::Valtree({})", fmt_valtree(&cv.valtree))
+                        format!("ty::Valtree({})", fmt_valtree(&cv))
                     }
                     // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
                     ty::ConstKind::Error(_) => "Error".to_string(),
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 949d8303385..1489d57aba6 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -20,6 +20,12 @@ pub struct LocalCrate;
 /// The `Key` trait controls what types can legally be used as the key
 /// for a query.
 pub trait Key: Sized {
+    /// The type of in-memory cache to use for queries with this key type.
+    ///
+    /// In practice the cache type must implement [`QueryCache`], though that
+    /// constraint is not enforced here.
+    ///
+    /// [`QueryCache`]: rustc_query_system::query::QueryCache
     // N.B. Most of the keys down below have `type Cache<V> = DefaultCache<Self, V>;`,
     //      it would be reasonable to use associated type defaults, to remove the duplication...
     //
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index d914b7576dc..5905076c4d0 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -78,30 +78,6 @@ impl<'tcx> ValTree<'tcx> {
             Self::Branch(_) => None,
         }
     }
-
-    /// Get the values inside the ValTree as a slice of bytes. This only works for
-    /// constants with types &str, &[u8], or [u8; _].
-    pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
-        match ty.kind() {
-            ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
-                // `&str` can be interpreted as raw bytes
-                ty::Str => {}
-                // `&[u8]` can be interpreted as raw bytes
-                ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
-                // other `&_` can't be interpreted as raw bytes
-                _ => return None,
-            },
-            // `[u8; N]` can be interpreted as raw bytes
-            ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
-            // Otherwise, type cannot be interpreted as raw bytes
-            _ => return None,
-        }
-
-        Some(
-            tcx.arena
-                .alloc_from_iter(self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8())),
-        )
-    }
 }
 
 /// A type-level constant value.
@@ -143,6 +119,29 @@ impl<'tcx> Value<'tcx> {
         }
         self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
     }
+
+    /// Get the values inside the ValTree as a slice of bytes. This only works for
+    /// constants with types &str, &[u8], or [u8; _].
+    pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
+        match self.ty.kind() {
+            ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
+                // `&str` can be interpreted as raw bytes
+                ty::Str => {}
+                // `&[u8]` can be interpreted as raw bytes
+                ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
+                // other `&_` can't be interpreted as raw bytes
+                _ => return None,
+            },
+            // `[u8; N]` can be interpreted as raw bytes
+            ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
+            // Otherwise, type cannot be interpreted as raw bytes
+            _ => return None,
+        }
+
+        Some(tcx.arena.alloc_from_iter(
+            self.valtree.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8()),
+        ))
+    }
 }
 
 impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 6c8591dae89..3431081b189 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1487,7 +1487,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             },
             ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
             ty::ConstKind::Value(cv) => {
-                return self.pretty_print_const_valtree(cv.valtree, cv.ty, print_ty);
+                return self.pretty_print_const_valtree(cv, print_ty);
             }
 
             ty::ConstKind::Bound(debruijn, bound_var) => {
@@ -1787,48 +1787,47 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         Ok(())
     }
 
-    // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
     fn pretty_print_const_valtree(
         &mut self,
-        valtree: ty::ValTree<'tcx>,
-        ty: Ty<'tcx>,
+        cv: ty::Value<'tcx>,
         print_ty: bool,
     ) -> Result<(), PrintError> {
         define_scoped_cx!(self);
 
         if self.should_print_verbose() {
-            p!(write("ValTree({:?}: ", valtree), print(ty), ")");
+            p!(write("ValTree({:?}: ", cv.valtree), print(cv.ty), ")");
             return Ok(());
         }
 
         let u8_type = self.tcx().types.u8;
-        match (valtree, ty.kind()) {
+        match (cv.valtree, cv.ty.kind()) {
             (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
                 ty::Slice(t) if *t == u8_type => {
-                    let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+                    let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {
                         bug!(
                             "expected to convert valtree {:?} to raw bytes for type {:?}",
-                            valtree,
+                            cv.valtree,
                             t
                         )
                     });
                     return self.pretty_print_byte_str(bytes);
                 }
                 ty::Str => {
-                    let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
-                        bug!("expected to convert valtree to raw bytes for type {:?}", ty)
+                    let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {
+                        bug!("expected to convert valtree to raw bytes for type {:?}", cv.ty)
                     });
                     p!(write("{:?}", String::from_utf8_lossy(bytes)));
                     return Ok(());
                 }
                 _ => {
+                    let cv = ty::Value { valtree: cv.valtree, ty: *inner_ty };
                     p!("&");
-                    p!(pretty_print_const_valtree(valtree, *inner_ty, print_ty));
+                    p!(pretty_print_const_valtree(cv, print_ty));
                     return Ok(());
                 }
             },
             (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
-                let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+                let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {
                     bug!("expected to convert valtree to raw bytes for type {:?}", t)
                 });
                 p!("*");
@@ -1837,10 +1836,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             }
             // Aggregates, printed as array/tuple/struct/variant construction syntax.
             (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
-                let contents =
-                    self.tcx().destructure_const(ty::Const::new_value(self.tcx(), valtree, ty));
+                let contents = self.tcx().destructure_const(ty::Const::new_value(
+                    self.tcx(),
+                    cv.valtree,
+                    cv.ty,
+                ));
                 let fields = contents.fields.iter().copied();
-                match *ty.kind() {
+                match *cv.ty.kind() {
                     ty::Array(..) => {
                         p!("[", comma_sep(fields), "]");
                     }
@@ -1857,7 +1859,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                                 write!(this, "unreachable()")?;
                                 Ok(())
                             },
-                            |this| this.print_type(ty),
+                            |this| this.print_type(cv.ty),
                             ": ",
                         )?;
                     }
@@ -1894,7 +1896,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty);
             }
             (ty::ValTree::Leaf(leaf), _) => {
-                return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
+                return self.pretty_print_const_scalar_int(leaf, cv.ty, print_ty);
             }
             // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
             // their fields instead of just dumping the memory.
@@ -1902,13 +1904,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         }
 
         // fallback
-        if valtree == ty::ValTree::zst() {
+        if cv.valtree == ty::ValTree::zst() {
             p!(write("<ZST>"));
         } else {
-            p!(write("{:?}", valtree));
+            p!(write("{:?}", cv.valtree));
         }
         if print_ty {
-            p!(": ", print(ty));
+            p!(": ", print(cv.ty));
         }
         Ok(())
     }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 9e9de4fb064..03b26b44538 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -170,7 +170,7 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> {
                     bug!("we checked that this is a valtree")
                 };
                 let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
-                cx.pretty_print_const_valtree(cv.valtree, cv.ty, /*print_ty*/ true)?;
+                cx.pretty_print_const_valtree(cv, /*print_ty*/ true)?;
                 f.write_str(&cx.into_buffer())
             });
         }
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index e6f3d97742d..e11123dff26 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -11,18 +11,30 @@ use rustc_span::def_id::{DefId, DefIndex};
 
 use crate::dep_graph::DepNodeIndex;
 
+/// Trait for types that serve as an in-memory cache for query results,
+/// for a given key (argument) type and value (return) type.
+///
+/// Types implementing this trait are associated with actual key/value types
+/// by the `Cache` associated type of the `rustc_middle::query::Key` trait.
 pub trait QueryCache: Sized {
     type Key: Hash + Eq + Copy + Debug;
     type Value: Copy;
 
-    /// Checks if the query is already computed and in the cache.
+    /// Returns the cached value (and other information) associated with the
+    /// given key, if it is present in the cache.
     fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>;
 
+    /// Adds a key/value entry to this cache.
+    ///
+    /// Called by some part of the query system, after having obtained the
+    /// value by executing the query or loading a cached value from disk.
     fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex);
 
     fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex));
 }
 
+/// In-memory cache for queries whose keys aren't suitable for any of the
+/// more specialized kinds of cache. Backed by a sharded hashmap.
 pub struct DefaultCache<K, V> {
     cache: Sharded<FxHashMap<K, (V, DepNodeIndex)>>,
 }
@@ -67,6 +79,8 @@ where
     }
 }
 
+/// In-memory cache for queries whose key type only has one value (e.g. `()`).
+/// The cache therefore only needs to store one query return value.
 pub struct SingleCache<V> {
     cache: OnceLock<(V, DepNodeIndex)>,
 }
@@ -101,6 +115,10 @@ where
     }
 }
 
+/// In-memory cache for queries whose key is a [`DefId`].
+///
+/// Selects between one of two internal caches, depending on whether the key
+/// is a local ID or foreign-crate ID.
 pub struct DefIdCache<V> {
     /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is
     /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap.
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 6fb5e37d2d0..18aae8c00b2 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -222,10 +222,10 @@ pub struct CycleError {
     pub cycle: Vec<QueryInfo>,
 }
 
-/// Checks if the query is already computed and in the cache.
-/// It returns the shard index and a lock guard to the shard,
-/// which will be used if the query is not in the cache and we need
-/// to compute it.
+/// Checks whether there is already a value for this key in the in-memory
+/// query cache, returning that value if present.
+///
+/// (Also performs some associated bookkeeping, if a value was found.)
 #[inline(always)]
 pub fn try_get_cached<Tcx, C>(tcx: Tcx, cache: &C, key: &C::Key) -> Option<C::Value>
 where
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 7b040a8b2c4..0ac6f17b97b 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -649,7 +649,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 // HACK(jaic1): hide the `str` type behind a reference
                 // for the following transformation from valtree to raw bytes
                 let ref_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, ct_ty);
-                let slice = valtree.try_to_raw_bytes(tcx, ref_ty).unwrap_or_else(|| {
+                let cv = ty::Value { ty: ref_ty, valtree };
+                let slice = cv.try_to_raw_bytes(tcx).unwrap_or_else(|| {
                     bug!("expected to get raw bytes from valtree {:?} for type {:}", valtree, ct_ty)
                 });
                 let s = std::str::from_utf8(slice).expect("non utf8 str from MIR interpreter");
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index 6a85791916a..c6c96571d33 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -8,6 +8,9 @@ use crate::{fmt, mem};
 /// only immutable references can be obtained unless one has a mutable reference to the cell
 /// itself. In the same vein, the cell can only be re-initialized with such a mutable reference.
 ///
+/// A `OnceCell` can be thought of as a safe abstraction over uninitialized data that becomes
+/// initialized once written.
+///
 /// For a thread-safe version of this struct, see [`std::sync::OnceLock`].
 ///
 /// [`RefCell`]: crate::cell::RefCell
@@ -35,7 +38,7 @@ pub struct OnceCell<T> {
 }
 
 impl<T> OnceCell<T> {
-    /// Creates a new empty cell.
+    /// Creates a new uninitialized cell.
     #[inline]
     #[must_use]
     #[stable(feature = "once_cell", since = "1.70.0")]
@@ -46,7 +49,7 @@ impl<T> OnceCell<T> {
 
     /// Gets the reference to the underlying value.
     ///
-    /// Returns `None` if the cell is empty.
+    /// Returns `None` if the cell is uninitialized.
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
     pub fn get(&self) -> Option<&T> {
@@ -56,19 +59,19 @@ impl<T> OnceCell<T> {
 
     /// Gets the mutable reference to the underlying value.
     ///
-    /// Returns `None` if the cell is empty.
+    /// Returns `None` if the cell is uninitialized.
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
     pub fn get_mut(&mut self) -> Option<&mut T> {
         self.inner.get_mut().as_mut()
     }
 
-    /// Sets the contents of the cell to `value`.
+    /// Initializes the contents of the cell to `value`.
     ///
     /// # Errors
     ///
-    /// This method returns `Ok(())` if the cell was empty and `Err(value)` if
-    /// it was full.
+    /// This method returns `Ok(())` if the cell was uninitialized
+    /// and `Err(value)` if it was already initialized.
     ///
     /// # Examples
     ///
@@ -92,13 +95,13 @@ impl<T> OnceCell<T> {
         }
     }
 
-    /// Sets the contents of the cell to `value` if the cell was empty, then
-    /// returns a reference to it.
+    /// Initializes the contents of the cell to `value` if the cell was
+    /// uninitialized, then returns a reference to it.
     ///
     /// # Errors
     ///
-    /// This method returns `Ok(&value)` if the cell was empty and
-    /// `Err(&current_value, value)` if it was full.
+    /// This method returns `Ok(&value)` if the cell was uninitialized
+    /// and `Err((&current_value, value))` if it was already initialized.
     ///
     /// # Examples
     ///
@@ -130,12 +133,12 @@ impl<T> OnceCell<T> {
         Ok(slot.insert(value))
     }
 
-    /// Gets the contents of the cell, initializing it with `f`
-    /// if the cell was empty.
+    /// Gets the contents of the cell, initializing it to `f()`
+    /// if the cell was uninitialized.
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// If `f()` panics, the panic is propagated to the caller, and the cell
     /// remains uninitialized.
     ///
     /// It is an error to reentrantly initialize the cell from `f`. Doing
@@ -164,11 +167,11 @@ impl<T> OnceCell<T> {
     }
 
     /// Gets the mutable reference of the contents of the cell,
-    /// initializing it with `f` if the cell was empty.
+    /// initializing it to `f()` if the cell was uninitialized.
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// If `f()` panics, the panic is propagated to the caller, and the cell
     /// remains uninitialized.
     ///
     /// # Examples
@@ -199,13 +202,13 @@ impl<T> OnceCell<T> {
         }
     }
 
-    /// Gets the contents of the cell, initializing it with `f` if
-    /// the cell was empty. If the cell was empty and `f` failed, an
-    /// error is returned.
+    /// Gets the contents of the cell, initializing it to `f()` if
+    /// the cell was uninitialized. If the cell was uninitialized
+    /// and `f()` failed, an error is returned.
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// If `f()` panics, the panic is propagated to the caller, and the cell
     /// remains uninitialized.
     ///
     /// It is an error to reentrantly initialize the cell from `f`. Doing
@@ -239,12 +242,12 @@ impl<T> OnceCell<T> {
     }
 
     /// Gets the mutable reference of the contents of the cell, initializing
-    /// it with `f` if the cell was empty. If the cell was empty and `f` failed,
-    /// an error is returned.
+    /// it to `f()` if the cell was uninitialized. If the cell was uninitialized
+    /// and `f()` failed, an error is returned.
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// If `f()` panics, the panic is propagated to the caller, and the cell
     /// remains uninitialized.
     ///
     /// # Examples
@@ -256,7 +259,7 @@ impl<T> OnceCell<T> {
     ///
     /// let mut cell: OnceCell<u32> = OnceCell::new();
     ///
-    /// // Failed initializers do not change the value
+    /// // Failed attempts to initialize the cell do not change its contents
     /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err());
     /// assert!(cell.get().is_none());
     ///
@@ -295,7 +298,7 @@ impl<T> OnceCell<T> {
 
     /// Consumes the cell, returning the wrapped value.
     ///
-    /// Returns `None` if the cell was empty.
+    /// Returns `None` if the cell was uninitialized.
     ///
     /// # Examples
     ///
@@ -321,7 +324,7 @@ impl<T> OnceCell<T> {
 
     /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
     ///
-    /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
+    /// Has no effect and returns `None` if the `OnceCell` is uninitialized.
     ///
     /// Safety is guaranteed by requiring a mutable reference.
     ///
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index 6fc0abbed9e..8f769f2dca3 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -13,6 +13,9 @@ use crate::sync::Once;
 /// Where OnceLock shines is when LazyLock is too simple to support a given case, as LazyLock
 /// doesn't allow additional inputs to its function after you call [`LazyLock::new(|| ...)`].
 ///
+/// A `OnceLock` can be thought of as a safe abstraction over uninitialized data that becomes
+/// initialized once written.
+///
 /// [`OnceCell`]: crate::cell::OnceCell
 /// [`LazyLock<T, F>`]: crate::sync::LazyLock
 /// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new
@@ -126,7 +129,7 @@ pub struct OnceLock<T> {
 }
 
 impl<T> OnceLock<T> {
-    /// Creates a new empty cell.
+    /// Creates a new uninitialized cell.
     #[inline]
     #[must_use]
     #[stable(feature = "once_cell", since = "1.70.0")]
@@ -141,8 +144,8 @@ impl<T> OnceLock<T> {
 
     /// Gets the reference to the underlying value.
     ///
-    /// Returns `None` if the cell is empty, or being initialized. This
-    /// method never blocks.
+    /// Returns `None` if the cell is uninitialized, or being initialized.
+    /// This method never blocks.
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
     pub fn get(&self) -> Option<&T> {
@@ -156,7 +159,8 @@ impl<T> OnceLock<T> {
 
     /// Gets the mutable reference to the underlying value.
     ///
-    /// Returns `None` if the cell is empty. This method never blocks.
+    /// Returns `None` if the cell is uninitialized, or being initialized.
+    /// This method never blocks.
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
     pub fn get_mut(&mut self) -> Option<&mut T> {
@@ -194,12 +198,13 @@ impl<T> OnceLock<T> {
         unsafe { self.get_unchecked() }
     }
 
-    /// Sets the contents of this cell to `value`.
+    /// Initializes the contents of the cell to `value`.
     ///
     /// May block if another thread is currently attempting to initialize the cell. The cell is
-    /// guaranteed to contain a value when set returns, though not necessarily the one provided.
+    /// guaranteed to contain a value when `set` returns, though not necessarily the one provided.
     ///
-    /// Returns `Ok(())` if the cell's value was set by this call.
+    /// Returns `Ok(())` if the cell was uninitialized and
+    /// `Err(value)` if the cell was already initialized.
     ///
     /// # Examples
     ///
@@ -228,13 +233,15 @@ impl<T> OnceLock<T> {
         }
     }
 
-    /// Sets the contents of this cell to `value` if the cell was empty, then
-    /// returns a reference to it.
+    /// Initializes the contents of the cell to `value` if the cell was uninitialized,
+    /// then returns a reference to it.
     ///
     /// May block if another thread is currently attempting to initialize the cell. The cell is
-    /// guaranteed to contain a value when set returns, though not necessarily the one provided.
+    /// guaranteed to contain a value when `try_insert` returns, though not necessarily the
+    /// one provided.
     ///
-    /// Returns `Ok(&value)` if the cell was empty and `Err(&current_value, value)` if it was full.
+    /// Returns `Ok(&value)` if the cell was uninitialized and
+    /// `Err((&current_value, value))` if it was already initialized.
     ///
     /// # Examples
     ///
@@ -267,8 +274,8 @@ impl<T> OnceLock<T> {
         }
     }
 
-    /// Gets the contents of the cell, initializing it with `f` if the cell
-    /// was empty.
+    /// Gets the contents of the cell, initializing it to `f()` if the cell
+    /// was uninitialized.
     ///
     /// Many threads may call `get_or_init` concurrently with different
     /// initializing functions, but it is guaranteed that only one function
@@ -276,7 +283,7 @@ impl<T> OnceLock<T> {
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// If `f()` panics, the panic is propagated to the caller, and the cell
     /// remains uninitialized.
     ///
     /// It is an error to reentrantly initialize the cell from `f`. The
@@ -306,13 +313,13 @@ impl<T> OnceLock<T> {
     }
 
     /// Gets the mutable reference of the contents of the cell, initializing
-    /// it with `f` if the cell was empty.
+    /// it to `f()` if the cell was uninitialized.
     ///
     /// This method never blocks.
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// If `f()` panics, the panic is propagated to the caller, and the cell
     /// remains uninitialized.
     ///
     /// # Examples
@@ -343,13 +350,13 @@ impl<T> OnceLock<T> {
         }
     }
 
-    /// Gets the contents of the cell, initializing it with `f` if
-    /// the cell was empty. If the cell was empty and `f` failed, an
-    /// error is returned.
+    /// Gets the contents of the cell, initializing it to `f()` if
+    /// the cell was uninitialized. If the cell was uninitialized
+    /// and `f()` failed, an error is returned.
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and
+    /// If `f()` panics, the panic is propagated to the caller, and
     /// the cell remains uninitialized.
     ///
     /// It is an error to reentrantly initialize the cell from `f`.
@@ -395,14 +402,14 @@ impl<T> OnceLock<T> {
     }
 
     /// Gets the mutable reference of the contents of the cell, initializing
-    /// it with `f` if the cell was empty. If the cell was empty and `f` failed,
-    /// an error is returned.
+    /// it to `f()` if the cell was uninitialized. If the cell was uninitialized
+    /// and `f()` failed, an error is returned.
     ///
     /// This method never blocks.
     ///
     /// # Panics
     ///
-    /// If `f` panics, the panic is propagated to the caller, and
+    /// If `f()` panics, the panic is propagated to the caller, and
     /// the cell remains uninitialized.
     ///
     /// # Examples
@@ -414,7 +421,7 @@ impl<T> OnceLock<T> {
     ///
     /// let mut cell: OnceLock<u32> = OnceLock::new();
     ///
-    /// // Failed initializers do not change the value
+    /// // Failed attempts to initialize the cell do not change its contents
     /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err());
     /// assert!(cell.get().is_none());
     ///
@@ -438,7 +445,7 @@ impl<T> OnceLock<T> {
     }
 
     /// Consumes the `OnceLock`, returning the wrapped value. Returns
-    /// `None` if the cell was empty.
+    /// `None` if the cell was uninitialized.
     ///
     /// # Examples
     ///
@@ -460,7 +467,7 @@ impl<T> OnceLock<T> {
 
     /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state.
     ///
-    /// Has no effect and returns `None` if the `OnceLock` hasn't been initialized.
+    /// Has no effect and returns `None` if the `OnceLock` was uninitialized.
     ///
     /// Safety is guaranteed by requiring a mutable reference.
     ///
@@ -526,7 +533,7 @@ impl<T> OnceLock<T> {
 
     /// # Safety
     ///
-    /// The value must be initialized
+    /// The cell must be initialized
     #[inline]
     unsafe fn get_unchecked(&self) -> &T {
         debug_assert!(self.is_initialized());
@@ -535,7 +542,7 @@ impl<T> OnceLock<T> {
 
     /// # Safety
     ///
-    /// The value must be initialized
+    /// The cell must be initialized
     #[inline]
     unsafe fn get_unchecked_mut(&mut self) -> &mut T {
         debug_assert!(self.is_initialized());
@@ -560,7 +567,7 @@ impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
 
 #[stable(feature = "once_cell", since = "1.70.0")]
 impl<T> Default for OnceLock<T> {
-    /// Creates a new empty cell.
+    /// Creates a new uninitialized cell.
     ///
     /// # Example
     ///
diff --git a/src/doc/book b/src/doc/book
-Subproject fa312a343fbff01bc6cef393e326817f7071981
+Subproject e2fa4316c5a7c0d2499c5d6b799adcfad6ef7a4
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 4ed5a1a4a2a7ecc2e529a5baaef04f7bc7917ed
+Subproject f56aecc3b036dff16404b525a83b00f911b9bbe
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject bc2298865544695c63454fc1f9f98a3dc22e994
+Subproject 336f75835a6c0514852cc65aba9a698b699b13c
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 93b921c7d3213d38d920f7f905a3bec093d2217
+Subproject 4249fb411dd27f945e2881eb0378044b94cee06
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 054259ed1bf01cdee4309ee764c7e103f6df3de
+Subproject 743766929f1e53e72fab74394ae259bbfb4a761
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 8227dfa043e..3b6abdd8483 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -34,9 +34,9 @@ target | notes
 -------|-------
 [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
-`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
-`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
-`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]
+`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
+`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
+`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
 [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
 `x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+, Windows Server 2016+)
 `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+)
@@ -162,14 +162,14 @@ target | std | notes
 [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A
 [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R
 [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat
-`i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87]
-`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87]
-`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87]
-[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI]
-[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI]
-[`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD [^x86_32-floats-return-ABI]
-`i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI]
-[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI
+`i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87]
+`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87]
+`i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87]
+[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([PentiumPro with SSE](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI]
+[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI]
+[`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI]
+`i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI]
+[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? (Pentium 4, softfloat) | 32-bit UEFI
 [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI)
 [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI)
 [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
@@ -307,15 +307,15 @@ target | std | host | notes
 `csky-unknown-linux-gnuabiv2hf` | ✓ |  | C-SKY abiv2 Linux, hardfloat (little endian)
 [`hexagon-unknown-linux-musl`](platform-support/hexagon-unknown-linux-musl.md) | ✓ | | Hexagon Linux with musl 1.2.3
 [`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX)
-[`i386-apple-ios`](platform-support/apple-ios.md) | ✓ |  | 32-bit x86 iOS [^x86_32-floats-return-ABI]
-[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * |  | 32-bit x86 QNX Neutrino 7.0 RTOS  [^x86_32-floats-return-ABI]
-[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ |  | 32-bit x86, restricted to Pentium
-[`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI]
-`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku [^x86_32-floats-return-ABI]
-[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI]
-[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI]
-[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI]
-[`i686-unknown-redox`](platform-support/redox.md) | ✓ |  | i686 Redox OS
+[`i386-apple-ios`](platform-support/apple-ios.md) | ✓ |  | 32-bit x86 iOS (Penryn) [^x86_32-floats-return-ABI]
+[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * |  | 32-bit x86 QNX Neutrino 7.0 RTOS (Pentium 4) [^x86_32-floats-return-ABI]
+[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ |  | 32-bit x86 (original Pentium) [^x86_32-floats-x87]
+[`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI]
+`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI]
+[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (PentiumPro) [^x86_32-floats-x87]
+[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI]
+[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI]
+[`i686-unknown-redox`](platform-support/redox.md) | ✓ |  | i686 Redox OS (PentiumPro) [^x86_32-floats-x87]
 `i686-uwp-windows-gnu` | ✓ |  | [^x86_32-floats-return-ABI]
 [`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ |  | [^x86_32-floats-return-ABI]
 [`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7853e311a04..0d4ff6e7aa5 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1104,17 +1104,29 @@ fn clean_args_from_types_and_names<'tcx>(
     types: &[hir::Ty<'tcx>],
     names: &[Ident],
 ) -> Arguments {
+    fn nonempty_name(ident: &Ident) -> Option<Symbol> {
+        if ident.name == kw::Underscore || ident.name == kw::Empty {
+            None
+        } else {
+            Some(ident.name)
+        }
+    }
+
+    // If at least one argument has a name, use `_` as the name of unnamed
+    // arguments. Otherwise omit argument names.
+    let default_name = if names.iter().any(|ident| nonempty_name(ident).is_some()) {
+        kw::Underscore
+    } else {
+        kw::Empty
+    };
+
     Arguments {
         values: types
             .iter()
             .enumerate()
             .map(|(i, ty)| Argument {
                 type_: clean_ty(ty, cx),
-                name: names
-                    .get(i)
-                    .map(|ident| ident.name)
-                    .filter(|ident| !ident.is_empty())
-                    .unwrap_or(kw::Underscore),
+                name: names.get(i).and_then(nonempty_name).unwrap_or(default_name),
                 is_const: false,
             })
             .collect(),
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 20a8dc72491..ffd457c8273 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1408,7 +1408,9 @@ impl clean::Arguments {
     ) -> impl Display + 'a + Captures<'tcx> {
         fmt::from_fn(move |f| {
             for (i, input) in self.values.iter().enumerate() {
-                write!(f, "{}: ", input.name)?;
+                if !input.name.is_empty() {
+                    write!(f, "{}: ", input.name)?;
+                }
                 input.type_.print(cx).fmt(f)?;
                 if i + 1 < self.values.len() {
                     write!(f, ", ")?;
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 839d23fb9a7..17786ed6d2f 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -3146,7 +3146,6 @@ ui/nll/issue-97997.rs
 ui/nll/issue-98170.rs
 ui/nll/issue-98589-closures-relate-named-regions.rs
 ui/nll/issue-98693.rs
-ui/nll/polonius/issue-46589.rs
 ui/nll/relate_tys/issue-48071.rs
 ui/nll/ty-outlives/issue-53789-1.rs
 ui/nll/ty-outlives/issue-53789-2.rs
diff --git a/tests/rustdoc/assoc-consts.rs b/tests/rustdoc/assoc-consts.rs
index cb8e839541c..247b5b180a8 100644
--- a/tests/rustdoc/assoc-consts.rs
+++ b/tests/rustdoc/assoc-consts.rs
@@ -45,7 +45,7 @@ pub fn f(_: &(ToString + 'static)) {}
 
 impl Bar {
     //@ has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \
-    //      "const F: fn(_: &(dyn ToString + 'static))"
+    //      "const F: fn(&(dyn ToString + 'static))"
     pub const F: fn(_: &(ToString + 'static)) = f;
 }
 
diff --git a/tests/rustdoc/fn-pointer-arg-name.rs b/tests/rustdoc/fn-pointer-arg-name.rs
index 3bde6e9ecfa..0ee1964511a 100644
--- a/tests/rustdoc/fn-pointer-arg-name.rs
+++ b/tests/rustdoc/fn-pointer-arg-name.rs
@@ -3,3 +3,11 @@
 //@ has foo/fn.f.html
 //@ has - '//pre[@class="rust item-decl"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
 pub fn f(callback: fn(len: usize, foo: u32)) {}
+
+//@ has foo/fn.g.html
+//@ has - '//pre[@class="rust item-decl"]' 'pub fn g(_: fn(usize, u32))'
+pub fn g(_: fn(usize, _: u32)) {}
+
+//@ has foo/fn.mixed.html
+//@ has - '//pre[@class="rust item-decl"]' 'pub fn mixed(_: fn(_: usize, foo: u32))'
+pub fn mixed(_: fn(usize, foo: u32)) {}
diff --git a/tests/rustdoc/inherent-projections.rs b/tests/rustdoc/inherent-projections.rs
index 4fc769f70f5..ced4db9a490 100644
--- a/tests/rustdoc/inherent-projections.rs
+++ b/tests/rustdoc/inherent-projections.rs
@@ -13,7 +13,7 @@ impl Owner {
 }
 
 // Make sure we handle bound vars correctly.
-//@ has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(_: Carrier<'a>::Focus))"
+//@ has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(Carrier<'a>::Focus))"
 pub fn user(_: for<'a> fn(Carrier<'a>::Focus)) {}
 
 pub struct Carrier<'a>(&'a ());
diff --git a/tests/rustdoc/macro-higher-kinded-function.rs b/tests/rustdoc/macro-higher-kinded-function.rs
index f14125d1309..738ea8fb3f1 100644
--- a/tests/rustdoc/macro-higher-kinded-function.rs
+++ b/tests/rustdoc/macro-higher-kinded-function.rs
@@ -11,10 +11,10 @@ macro_rules! gen {
 }
 
 //@ has 'foo/struct.Providers.html'
-//@ has - '//*[@class="rust item-decl"]//code' "pub a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8,"
-//@ has - '//*[@class="rust item-decl"]//code' "pub b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16,"
-//@ has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8"
-//@ has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16"
+//@ has - '//*[@class="rust item-decl"]//code' "pub a: for<'tcx> fn(TyCtxt<'tcx>, u8) -> i8,"
+//@ has - '//*[@class="rust item-decl"]//code' "pub b: for<'tcx> fn(TyCtxt<'tcx>, u16) -> i16,"
+//@ has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(TyCtxt<'tcx>, u8) -> i8"
+//@ has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(TyCtxt<'tcx>, u16) -> i16"
 gen! {
     (a, 'tcx, [u8], [i8])
     (b, 'tcx, [u16], [i16])
diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
index d7c7b2e2414..1c838a9e5e1 100644
--- a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
+++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
@@ -1,5 +1,4 @@
 //@ revisions: edition2021 edition2024
-//@ ignore-wasm no panic support
 //@ needs-subprocess
 //@ [edition2024] edition: 2024
 //@ run-pass
diff --git a/tests/ui/nll/get_default.legacy.stderr b/tests/ui/nll/get_default.legacy.stderr
new file mode 100644
index 00000000000..699250312dc
--- /dev/null
+++ b/tests/ui/nll/get_default.legacy.stderr
@@ -0,0 +1,18 @@
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:35:17
+   |
+LL | fn err(map: &mut Map) -> &String {
+   |             - let's call the lifetime of this reference `'1`
+LL |     loop {
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+LL |             Some(v) => {
+LL |                 map.set(String::new()); // We always expect an error here.
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |                 return v;
+   |                        - returning this value requires that `*map` is borrowed for `'1`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/nll/get_default.stderr b/tests/ui/nll/get_default.nll.stderr
index af79771e7e1..9b5976ca717 100644
--- a/tests/ui/nll/get_default.stderr
+++ b/tests/ui/nll/get_default.nll.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
-  --> $DIR/get_default.rs:21:17
+  --> $DIR/get_default.rs:24:17
    |
 LL | fn ok(map: &mut Map) -> &String {
    |            - let's call the lifetime of this reference `'1`
@@ -14,7 +14,7 @@ LL |                 map.set(String::new()); // Ideally, this would not error.
    |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
-  --> $DIR/get_default.rs:32:17
+  --> $DIR/get_default.rs:35:17
    |
 LL | fn err(map: &mut Map) -> &String {
    |             - let's call the lifetime of this reference `'1`
@@ -22,14 +22,14 @@ LL |     loop {
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 LL |             Some(v) => {
-LL |                 map.set(String::new()); // Both AST and MIR error here
+LL |                 map.set(String::new()); // We always expect an error here.
    |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 LL |
 LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
-  --> $DIR/get_default.rs:37:17
+  --> $DIR/get_default.rs:40:17
    |
 LL | fn err(map: &mut Map) -> &String {
    |             - let's call the lifetime of this reference `'1`
@@ -40,7 +40,7 @@ LL |         match map.get() {
 LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 ...
-LL |                 map.set(String::new()); // Ideally, just AST would error here
+LL |                 map.set(String::new()); // Ideally, this would not error.
    |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/nll/get_default.polonius.stderr b/tests/ui/nll/get_default.polonius.stderr
new file mode 100644
index 00000000000..699250312dc
--- /dev/null
+++ b/tests/ui/nll/get_default.polonius.stderr
@@ -0,0 +1,18 @@
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:35:17
+   |
+LL | fn err(map: &mut Map) -> &String {
+   |             - let's call the lifetime of this reference `'1`
+LL |     loop {
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+LL |             Some(v) => {
+LL |                 map.set(String::new()); // We always expect an error here.
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |                 return v;
+   |                        - returning this value requires that `*map` is borrowed for `'1`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/tests/ui/nll/get_default.rs b/tests/ui/nll/get_default.rs
index ffac8a33da1..c3c09e9c2c5 100644
--- a/tests/ui/nll/get_default.rs
+++ b/tests/ui/nll/get_default.rs
@@ -1,7 +1,10 @@
 // Basic test for free regions in the NLL code. This test ought to
-// report an error due to a reborrowing constraint. Right now, we get
-// a variety of errors from the older, AST-based machinery (notably
-// borrowck), and then we get the NLL error at the end.
+// report an error due to a reborrowing constraint.
+
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: nll polonius legacy
+//@ [polonius] compile-flags: -Z polonius=next
+//@ [legacy] compile-flags: -Z polonius=legacy
 
 struct Map {
 }
@@ -19,7 +22,7 @@ fn ok(map: &mut Map) -> &String {
             }
             None => {
                 map.set(String::new()); // Ideally, this would not error.
-                //~^ ERROR borrowed as immutable
+                //[nll]~^ ERROR borrowed as immutable
             }
         }
     }
@@ -29,13 +32,13 @@ fn err(map: &mut Map) -> &String {
     loop {
         match map.get() {
             Some(v) => {
-                map.set(String::new()); // Both AST and MIR error here
+                map.set(String::new()); // We always expect an error here.
                 //~^ ERROR borrowed as immutable
                 return v;
             }
             None => {
-                map.set(String::new()); // Ideally, just AST would error here
-                //~^ ERROR borrowed as immutable
+                map.set(String::new()); // Ideally, this would not error.
+                //[nll]~^ ERROR borrowed as immutable
             }
         }
     }
diff --git a/tests/ui/nll/issue-46589.stderr b/tests/ui/nll/issue-46589.nll.stderr
index abf62aaa510..dc80c1d08de 100644
--- a/tests/ui/nll/issue-46589.stderr
+++ b/tests/ui/nll/issue-46589.nll.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `**other` as mutable more than once at a time
-  --> $DIR/issue-46589.rs:23:21
+  --> $DIR/issue-46589.rs:24:21
    |
 LL |         *other = match (*other).get_self() {
    |                        -------- first mutable borrow occurs here
diff --git a/tests/ui/nll/issue-46589.rs b/tests/ui/nll/issue-46589.rs
index 417d9cab657..10aff0d7b4e 100644
--- a/tests/ui/nll/issue-46589.rs
+++ b/tests/ui/nll/issue-46589.rs
@@ -1,8 +1,9 @@
-// This tests passes in Polonius mode, so is skipped in the automated compare-mode.
-// We will manually check it passes in Polonius tests, as we can't have a test here
-// which conditionally passes depending on a test revision/compile-flags.
-
-//@ ignore-compare-mode-polonius
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: nll polonius_next polonius
+//@ [polonius_next] check-pass
+//@ [polonius_next] compile-flags: -Zpolonius=next
+//@ [polonius] check-pass
+//@ [polonius] compile-flags: -Zpolonius
 
 struct Foo;
 
@@ -21,7 +22,7 @@ impl Foo {
         *other = match (*other).get_self() {
             Some(s) => s,
             None => (*other).new_self()
-            //~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499]
+            //[nll]~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499]
         };
 
         let c = other;
diff --git a/tests/ui/nll/polonius/assignment-kills-loans.rs b/tests/ui/nll/polonius/assignment-kills-loans.rs
index 182262e5c4b..56ea9c2f1f9 100644
--- a/tests/ui/nll/polonius/assignment-kills-loans.rs
+++ b/tests/ui/nll/polonius/assignment-kills-loans.rs
@@ -4,8 +4,11 @@
 // facts only on simple assignments, but not projections, incorrectly causing errors to be emitted
 // for code accepted by NLL. They are all variations from example code in the NLL RFC.
 
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: polonius_next polonius
 //@ check-pass
-//@ compile-flags: -Z polonius
+//@ [polonius_next] compile-flags: -Z polonius=next
+//@ [polonius] compile-flags: -Z polonius
 
 struct List<T> {
     value: T,
diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.stderr b/tests/ui/nll/polonius/assignment-to-differing-field.legacy.stderr
index c46d010e4f5..cf5594dbd07 100644
--- a/tests/ui/nll/polonius/assignment-to-differing-field.stderr
+++ b/tests/ui/nll/polonius/assignment-to-differing-field.legacy.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time
-  --> $DIR/assignment-to-differing-field.rs:20:21
+  --> $DIR/assignment-to-differing-field.rs:23:21
    |
 LL | fn assignment_to_field_projection<'a, T>(
    |                                   -- lifetime `'a` defined here
@@ -11,7 +11,7 @@ LL |             return result;
    |                    ------ returning this value requires that `list.0.value` is borrowed for `'a`
 
 error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time
-  --> $DIR/assignment-to-differing-field.rs:23:26
+  --> $DIR/assignment-to-differing-field.rs:26:26
    |
 LL | fn assignment_to_field_projection<'a, T>(
    |                                   -- lifetime `'a` defined here
@@ -23,7 +23,7 @@ LL |             list.1 = n;
    |             ---------- assignment requires that `list.0.next` is borrowed for `'a`
 
 error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time
-  --> $DIR/assignment-to-differing-field.rs:37:21
+  --> $DIR/assignment-to-differing-field.rs:40:21
    |
 LL | fn assignment_through_projection_chain<'a, T>(
    |                                        -- lifetime `'a` defined here
@@ -35,7 +35,7 @@ LL |             return result;
    |                    ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a`
 
 error[E0499]: cannot borrow `list.0.0.0.0.0.next` as mutable more than once at a time
-  --> $DIR/assignment-to-differing-field.rs:40:26
+  --> $DIR/assignment-to-differing-field.rs:43:26
    |
 LL | fn assignment_through_projection_chain<'a, T>(
    |                                        -- lifetime `'a` defined here
diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.polonius.stderr b/tests/ui/nll/polonius/assignment-to-differing-field.polonius.stderr
new file mode 100644
index 00000000000..cf5594dbd07
--- /dev/null
+++ b/tests/ui/nll/polonius/assignment-to-differing-field.polonius.stderr
@@ -0,0 +1,51 @@
+error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time
+  --> $DIR/assignment-to-differing-field.rs:23:21
+   |
+LL | fn assignment_to_field_projection<'a, T>(
+   |                                   -- lifetime `'a` defined here
+...
+LL |         result.push(&mut (list.0).value);
+   |                     ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop
+...
+LL |             return result;
+   |                    ------ returning this value requires that `list.0.value` is borrowed for `'a`
+
+error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time
+  --> $DIR/assignment-to-differing-field.rs:26:26
+   |
+LL | fn assignment_to_field_projection<'a, T>(
+   |                                   -- lifetime `'a` defined here
+...
+LL |         if let Some(n) = (list.0).next.as_mut() {
+   |                          ^^^^^^^^^^^^^ `list.0.next` was mutably borrowed here in the previous iteration of the loop
+LL |
+LL |             list.1 = n;
+   |             ---------- assignment requires that `list.0.next` is borrowed for `'a`
+
+error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time
+  --> $DIR/assignment-to-differing-field.rs:40:21
+   |
+LL | fn assignment_through_projection_chain<'a, T>(
+   |                                        -- lifetime `'a` defined here
+...
+LL |         result.push(&mut ((((list.0).0).0).0).0.value);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.value` was mutably borrowed here in the previous iteration of the loop
+...
+LL |             return result;
+   |                    ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a`
+
+error[E0499]: cannot borrow `list.0.0.0.0.0.next` as mutable more than once at a time
+  --> $DIR/assignment-to-differing-field.rs:43:26
+   |
+LL | fn assignment_through_projection_chain<'a, T>(
+   |                                        -- lifetime `'a` defined here
+...
+LL |         if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop
+LL |
+LL |             *((((list.0).0).0).0).1 = n;
+   |             --------------------------- assignment requires that `list.0.0.0.0.0.next` is borrowed for `'a`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.rs b/tests/ui/nll/polonius/assignment-to-differing-field.rs
index fb6c9569525..9701cd2bb5e 100644
--- a/tests/ui/nll/polonius/assignment-to-differing-field.rs
+++ b/tests/ui/nll/polonius/assignment-to-differing-field.rs
@@ -4,7 +4,10 @@
 // that we do not kill too many borrows. Assignments to the `.1`
 // field projections should leave the borrows on `.0` intact.
 
-//@ compile-flags: -Z polonius
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: polonius legacy
+//@ [polonius] compile-flags: -Z polonius=next
+//@ [legacy] compile-flags: -Z polonius=legacy
 
 struct List<T> {
     value: T,
diff --git a/tests/ui/nll/polonius/call-kills-loans.rs b/tests/ui/nll/polonius/call-kills-loans.rs
index c02293c9a78..0657c42f48c 100644
--- a/tests/ui/nll/polonius/call-kills-loans.rs
+++ b/tests/ui/nll/polonius/call-kills-loans.rs
@@ -4,8 +4,11 @@
 // by NLL but was incorrectly rejected by Polonius because of these
 // missing `killed` facts.
 
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: polonius_next polonius
 //@ check-pass
-//@ compile-flags: -Z polonius
+//@ [polonius_next] compile-flags: -Z polonius=next
+//@ [polonius] compile-flags: -Z polonius
 
 struct Thing;
 
diff --git a/tests/ui/nll/polonius/issue-46589.rs b/tests/ui/nll/polonius/issue-46589.rs
deleted file mode 100644
index af791f7e24d..00000000000
--- a/tests/ui/nll/polonius/issue-46589.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// This test is a copy of `ui/nll/issue-46589.rs` which fails in NLL but succeeds in Polonius.
-// As we can't have a test here which conditionally passes depending on a test
-// revision/compile-flags. We ensure here that it passes in Polonius mode.
-
-//@ check-pass
-//@ compile-flags: -Z polonius
-
-struct Foo;
-
-impl Foo {
-    fn get_self(&mut self) -> Option<&mut Self> {
-        Some(self)
-    }
-
-    fn new_self(&mut self) -> &mut Self {
-        self
-    }
-
-    fn trigger_bug(&mut self) {
-        let other = &mut (&mut *self);
-
-        *other = match (*other).get_self() {
-            Some(s) => s,
-            None => (*other).new_self()
-        };
-
-        let c = other;
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs b/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs
index cb56c8f6deb..677b7aa1df8 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs
@@ -5,9 +5,11 @@
 // than `liveness::trace`, on some specific CFGs shapes: a variable was dead during tracing but its
 // regions were marked live later, and live loans were not recomputed at this point.
 
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: polonius_next polonius
 //@ check-pass
-//@ revisions: nll polonius
-//@ [polonius] compile-flags: -Zpolonius=next
+//@ [polonius_next] compile-flags: -Z polonius=next
+//@ [polonius] compile-flags: -Z polonius
 
 // minimized from wavefc-cli-3.0.0
 fn repro1() {
diff --git a/tests/ui/nll/polonius/polonius-smoke-test.stderr b/tests/ui/nll/polonius/polonius-smoke-test.legacy.stderr
index a8a8267290d..1268f6167f8 100644
--- a/tests/ui/nll/polonius/polonius-smoke-test.stderr
+++ b/tests/ui/nll/polonius/polonius-smoke-test.legacy.stderr
@@ -1,11 +1,11 @@
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/polonius-smoke-test.rs:6:5
+  --> $DIR/polonius-smoke-test.rs:10:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
 error[E0503]: cannot use `x` because it was mutably borrowed
-  --> $DIR/polonius-smoke-test.rs:12:13
+  --> $DIR/polonius-smoke-test.rs:16:13
    |
 LL |     let y = &mut x;
    |             ------ `x` is borrowed here
@@ -15,7 +15,7 @@ LL |     let w = y;
    |             - borrow later used here
 
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/polonius-smoke-test.rs:18:13
+  --> $DIR/polonius-smoke-test.rs:22:13
    |
 LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 {
    |                         -  - let's call the lifetime of this reference `'1`
@@ -35,7 +35,7 @@ LL +     let y = &mut x.clone();
    |
 
 error[E0505]: cannot move out of `s` because it is borrowed
-  --> $DIR/polonius-smoke-test.rs:42:5
+  --> $DIR/polonius-smoke-test.rs:46:5
    |
 LL |     let s = &mut 1;
    |         - binding `s` declared here
diff --git a/tests/ui/nll/polonius/polonius-smoke-test.polonius.stderr b/tests/ui/nll/polonius/polonius-smoke-test.polonius.stderr
new file mode 100644
index 00000000000..1268f6167f8
--- /dev/null
+++ b/tests/ui/nll/polonius/polonius-smoke-test.polonius.stderr
@@ -0,0 +1,59 @@
+error[E0515]: cannot return reference to local variable `x`
+  --> $DIR/polonius-smoke-test.rs:10:5
+   |
+LL |     &x
+   |     ^^ returns a reference to data owned by the current function
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+  --> $DIR/polonius-smoke-test.rs:16:13
+   |
+LL |     let y = &mut x;
+   |             ------ `x` is borrowed here
+LL |     let z = x;
+   |             ^ use of borrowed `x`
+LL |     let w = y;
+   |             - borrow later used here
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/polonius-smoke-test.rs:22:13
+   |
+LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 {
+   |                         -  - let's call the lifetime of this reference `'1`
+   |                         |
+   |                         binding `x` declared here
+LL |     let y = &mut *x;
+   |             ------- borrow of `*x` occurs here
+LL |     let z = x;
+   |             ^ move out of `x` occurs here
+LL |     y
+   |     - returning this value requires that `*x` is borrowed for `'1`
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let y = &mut *x;
+LL +     let y = &mut x.clone();
+   |
+
+error[E0505]: cannot move out of `s` because it is borrowed
+  --> $DIR/polonius-smoke-test.rs:46:5
+   |
+LL |     let s = &mut 1;
+   |         - binding `s` declared here
+LL |     let r = &mut *s;
+   |             ------- borrow of `*s` occurs here
+LL |     let tmp = foo(&r);
+LL |     s;
+   |     ^ move out of `s` occurs here
+LL |     tmp;
+   |     --- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL -     let r = &mut *s;
+LL +     let r = &mut s.clone();
+   |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0503, E0505, E0515.
+For more information about an error, try `rustc --explain E0503`.
diff --git a/tests/ui/nll/polonius/polonius-smoke-test.rs b/tests/ui/nll/polonius/polonius-smoke-test.rs
index ea5cdb263f5..7fbb3f9b47c 100644
--- a/tests/ui/nll/polonius/polonius-smoke-test.rs
+++ b/tests/ui/nll/polonius/polonius-smoke-test.rs
@@ -1,5 +1,9 @@
-// Check that Polonius borrow check works for simple cases.
-//@ compile-flags: -Z polonius
+// Check that Polonius works for simple cases.
+
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: polonius legacy
+//@ [polonius] compile-flags: -Z polonius=next
+//@ [legacy] compile-flags: -Z polonius=legacy
 
 pub fn return_ref_to_local() -> &'static i32 {
     let x = 0;
diff --git a/tests/ui/nll/polonius/storagedead-kills-loans.rs b/tests/ui/nll/polonius/storagedead-kills-loans.rs
index 89cf919bb48..75a37e6ece5 100644
--- a/tests/ui/nll/polonius/storagedead-kills-loans.rs
+++ b/tests/ui/nll/polonius/storagedead-kills-loans.rs
@@ -3,8 +3,11 @@
 // is correctly accepted by NLL but was incorrectly rejected by
 // Polonius because of these missing `killed` facts.
 
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: polonius_next polonius
 //@ check-pass
-//@ compile-flags: -Z polonius
+//@ [polonius_next] compile-flags: -Z polonius=next
+//@ [polonius] compile-flags: -Z polonius
 
 use std::{io, mem};
 use std::io::Read;
diff --git a/tests/ui/nll/polonius/subset-relations.stderr b/tests/ui/nll/polonius/subset-relations.legacy.stderr
index 9deca6449a8..10d42ca58d9 100644
--- a/tests/ui/nll/polonius/subset-relations.stderr
+++ b/tests/ui/nll/polonius/subset-relations.legacy.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/subset-relations.rs:10:5
+  --> $DIR/subset-relations.rs:13:5
    |
 LL | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
    |                   --  -- lifetime `'b` defined here
diff --git a/tests/ui/nll/polonius/subset-relations.polonius.stderr b/tests/ui/nll/polonius/subset-relations.polonius.stderr
new file mode 100644
index 00000000000..10d42ca58d9
--- /dev/null
+++ b/tests/ui/nll/polonius/subset-relations.polonius.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/subset-relations.rs:13:5
+   |
+LL | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+LL |     y
+   |     ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/nll/polonius/subset-relations.rs b/tests/ui/nll/polonius/subset-relations.rs
index 3c1af1983cf..d47e4e05533 100644
--- a/tests/ui/nll/polonius/subset-relations.rs
+++ b/tests/ui/nll/polonius/subset-relations.rs
@@ -3,7 +3,10 @@
 // two free regions outlive each other, without any evidence that this
 // relation holds.
 
-//@ compile-flags: -Z polonius
+//@ ignore-compare-mode-polonius (explicit revisions)
+//@ revisions: polonius legacy
+//@ [polonius] compile-flags: -Z polonius=next
+//@ [legacy] compile-flags: -Z polonius=legacy
 
 // returning `y` requires that `'b: 'a`, but it's not known to be true
 fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
@@ -22,7 +25,7 @@ fn implied_bounds_subset<'a, 'b>(x: &'a &'b mut u32) -> &'a u32 {
 
 // `'b: 'a` is declared, and `'a: 'c` is known via implied bounds:
 // `'b: 'c` is therefore known to hold transitively
-fn transitively_valid_subset<'a, 'b: 'a, 'c>(x: &'c &'a u32, y: &'b u32) -> &'c u32  {
+fn transitively_valid_subset<'a, 'b: 'a, 'c>(x: &'c &'a u32, y: &'b u32) -> &'c u32 {
     y
 }
 
diff --git a/tests/ui/panics/issue-47429-short-backtraces.rs b/tests/ui/panics/issue-47429-short-backtraces.rs
index 4a73ebe8712..378ade67bfd 100644
--- a/tests/ui/panics/issue-47429-short-backtraces.rs
+++ b/tests/ui/panics/issue-47429-short-backtraces.rs
@@ -17,8 +17,6 @@
 //@ ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
 //@ ignore-android FIXME #17520
 //@ ignore-openbsd no support for libbacktrace without filename
-//@ ignore-wasm no panic support
-//@ ignore-emscripten no panic support
 //@ ignore-fuchsia Backtraces not symbolized
 //@ needs-subprocess
 
diff --git a/tests/ui/panics/issue-47429-short-backtraces.run.stderr b/tests/ui/panics/issue-47429-short-backtraces.run.stderr
index c6e2d13fb5d..32dc6592271 100644
--- a/tests/ui/panics/issue-47429-short-backtraces.run.stderr
+++ b/tests/ui/panics/issue-47429-short-backtraces.run.stderr
@@ -1,5 +1,5 @@
 
-thread 'main' panicked at $DIR/issue-47429-short-backtraces.rs:26:5:
+thread 'main' panicked at $DIR/issue-47429-short-backtraces.rs:24:5:
 explicit panic
 stack backtrace:
    0: std::panicking::begin_panic
diff --git a/tests/ui/panics/runtime-switch.rs b/tests/ui/panics/runtime-switch.rs
index 9f0be8c7ddf..7d5b4169340 100644
--- a/tests/ui/panics/runtime-switch.rs
+++ b/tests/ui/panics/runtime-switch.rs
@@ -18,7 +18,6 @@
 //@ ignore-android FIXME #17520
 //@ ignore-openbsd no support for libbacktrace without filename
 //@ ignore-wasm no backtrace support
-//@ ignore-emscripten no panic support
 //@ ignore-fuchsia Backtrace not symbolized
 //@ needs-subprocess
 
diff --git a/tests/ui/panics/runtime-switch.run.stderr b/tests/ui/panics/runtime-switch.run.stderr
index 458a0ee534a..70ed127af86 100644
--- a/tests/ui/panics/runtime-switch.run.stderr
+++ b/tests/ui/panics/runtime-switch.run.stderr
@@ -1,5 +1,5 @@
 
-thread 'main' panicked at $DIR/runtime-switch.rs:29:5:
+thread 'main' panicked at $DIR/runtime-switch.rs:28:5:
 explicit panic
 stack backtrace:
    0: std::panicking::begin_panic
diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.rs b/tests/ui/panics/short-ice-remove-middle-frames-2.rs
index 48f60b14170..660530f0ead 100644
--- a/tests/ui/panics/short-ice-remove-middle-frames-2.rs
+++ b/tests/ui/panics/short-ice-remove-middle-frames-2.rs
@@ -5,7 +5,6 @@
 //@ needs-unwind
 //@ ignore-android FIXME #17520
 //@ ignore-openbsd no support for libbacktrace without filename
-//@ ignore-emscripten no panic
 //@ ignore-sgx Backtraces not symbolized
 //@ ignore-fuchsia Backtraces not symbolized
 //@ ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable.
diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr
index 1fddcca6951..664d51e185d 100644
--- a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr
+++ b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr
@@ -1,5 +1,5 @@
 
-thread 'main' panicked at $DIR/short-ice-remove-middle-frames-2.rs:63:5:
+thread 'main' panicked at $DIR/short-ice-remove-middle-frames-2.rs:62:5:
 debug!!!
 stack backtrace:
    0: std::panicking::begin_panic
diff --git a/tests/ui/panics/short-ice-remove-middle-frames.rs b/tests/ui/panics/short-ice-remove-middle-frames.rs
index 216c5127799..41fb6e9950e 100644
--- a/tests/ui/panics/short-ice-remove-middle-frames.rs
+++ b/tests/ui/panics/short-ice-remove-middle-frames.rs
@@ -5,7 +5,6 @@
 //@ needs-unwind
 //@ ignore-android FIXME #17520
 //@ ignore-openbsd no support for libbacktrace without filename
-//@ ignore-emscripten no panic
 //@ ignore-sgx Backtraces not symbolized
 //@ ignore-fuchsia Backtraces not symbolized
 //@ ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable.
diff --git a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr
index 630b09d8d1e..e966462331f 100644
--- a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr
+++ b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr
@@ -1,5 +1,5 @@
 
-thread 'main' panicked at $DIR/short-ice-remove-middle-frames.rs:59:5:
+thread 'main' panicked at $DIR/short-ice-remove-middle-frames.rs:58:5:
 debug!!!
 stack backtrace:
    0: std::panicking::begin_panic
diff --git a/tests/ui/test-attrs/test-panic-abort-disabled.rs b/tests/ui/test-attrs/test-panic-abort-disabled.rs
index 05dd9395c2b..e83be65f925 100644
--- a/tests/ui/test-attrs/test-panic-abort-disabled.rs
+++ b/tests/ui/test-attrs/test-panic-abort-disabled.rs
@@ -4,8 +4,6 @@
 //@ run-flags: --test-threads=1
 
 //@ needs-unwind
-//@ ignore-wasm no panic support
-//@ ignore-emscripten no panic support
 //@ needs-subprocess
 
 #![cfg(test)]
diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs
index f7e15dbdbc3..6a1025ea087 100644
--- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs
+++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs
@@ -7,8 +7,6 @@
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 //@ ignore-android #120567
-//@ ignore-wasm no panic support
-//@ ignore-emscripten no panic support
 //@ needs-subprocess
 
 #![cfg(test)]
diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
index 25681171170..b9f267838b1 100644
--- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
+++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
@@ -1,11 +1,11 @@
 
-thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5:
+thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:32:5:
 assertion `left == right` failed
   left: 2
  right: 4
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
-thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5:
+thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:26:5:
 assertion `left == right` failed
   left: 2
  right: 4
diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs
index 951cf54346b..6c9b641fb6f 100644
--- a/tests/ui/test-attrs/test-panic-abort.rs
+++ b/tests/ui/test-attrs/test-panic-abort.rs
@@ -7,8 +7,6 @@
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 //@ ignore-android #120567
-//@ ignore-wasm no panic support
-//@ ignore-emscripten no panic support
 //@ needs-subprocess
 
 #![cfg(test)]
diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout
index 844808e8637..0faa7f0dfce 100644
--- a/tests/ui/test-attrs/test-panic-abort.run.stdout
+++ b/tests/ui/test-attrs/test-panic-abort.run.stdout
@@ -18,7 +18,7 @@ testing123
 ---- it_fails stderr ----
 testing321
 
-thread 'main' panicked at $DIR/test-panic-abort.rs:39:5:
+thread 'main' panicked at $DIR/test-panic-abort.rs:37:5:
 assertion `left == right` failed
   left: 2
  right: 5