diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 2656e0bb6a452..eeba62bb14296 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -548,8 +548,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)
@@ -592,7 +609,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 decfab502bb59..fe904726c2891 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 35264bd1a7075..2031579dfd50a 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 6d32ee17f4c2a..5f9fa3612b8d1 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 75ee29c9d0d50..6ab09f731c078 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 502c868194af2..142ef8ba28eff 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 4e0b2a4e29681..dcc179030020d 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 c564d85616e25..62d49a62744e7 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 a2ef5588f48f8..45120324a0c0e 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,
@@ -564,8 +567,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/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 839d23fb9a78c..17786ed6d2fdb 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/ui/nll/get_default.legacy.stderr b/tests/ui/nll/get_default.legacy.stderr
new file mode 100644
index 0000000000000..699250312dc6b
--- /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
similarity index 87%
rename from tests/ui/nll/get_default.stderr
rename to tests/ui/nll/get_default.nll.stderr
index af79771e7e1b9..9b5976ca7170e 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 0000000000000..699250312dc6b
--- /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 ffac8a33da104..c3c09e9c2c553 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
similarity index 94%
rename from tests/ui/nll/issue-46589.stderr
rename to tests/ui/nll/issue-46589.nll.stderr
index abf62aaa51088..dc80c1d08deca 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 417d9cab657a1..10aff0d7b4ef9 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 182262e5c4b9b..56ea9c2f1f937 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
similarity index 92%
rename from tests/ui/nll/polonius/assignment-to-differing-field.stderr
rename to tests/ui/nll/polonius/assignment-to-differing-field.legacy.stderr
index c46d010e4f576..cf5594dbd0786 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 0000000000000..cf5594dbd0786
--- /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 fb6c956952543..9701cd2bb5e21 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 c02293c9a78aa..0657c42f48cda 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 af791f7e24ddd..0000000000000
--- 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 cb56c8f6deb4c..677b7aa1df860 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
similarity index 91%
rename from tests/ui/nll/polonius/polonius-smoke-test.stderr
rename to tests/ui/nll/polonius/polonius-smoke-test.legacy.stderr
index a8a8267290def..1268f6167f855 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 0000000000000..1268f6167f855
--- /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 ea5cdb263f5dd..7fbb3f9b47c3b 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 89cf919bb48e0..75a37e6ece575 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
similarity index 92%
rename from tests/ui/nll/polonius/subset-relations.stderr
rename to tests/ui/nll/polonius/subset-relations.legacy.stderr
index 9deca6449a8f1..10d42ca58d9df 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 0000000000000..10d42ca58d9df
--- /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 3c1af1983cfd0..d47e4e05533ee 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
 }