about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-05-07 23:03:25 +0000
committerbors <bors@rust-lang.org>2025-05-07 23:03:25 +0000
commitae3e8c6191fb2bf9394ea4201adaf7b1ac496120 (patch)
tree382cf80145b1f54cbb94e47671ab3cb4f7306108
parente9f8103f93f8ce2fa2c15c0c6796ec821f8ae15d (diff)
parent5e5043d7331f992ad91d199f9f89c4914edad043 (diff)
downloadrust-ae3e8c6191fb2bf9394ea4201adaf7b1ac496120.tar.gz
rust-ae3e8c6191fb2bf9394ea4201adaf7b1ac496120.zip
Auto merge of #140751 - GuillaumeGomez:rollup-eahw4ta, r=GuillaumeGomez
Rollup of 8 pull requests

Successful merges:

 - #140234 (Separate dataflow analysis and results)
 - #140614 (Correct warning message in restricted visibility)
 - #140671 (Parser: Recover error from named params while parse_path)
 - #140700 (Don't crash on error codes passed to `--explain` which exceed our internal limit of 9999 )
 - #140706 ([rustdoc] Ensure that temporary doctest folder is correctly removed even if doctests failed)
 - #140734 (Fix regression from #140393 for espidf / horizon / nuttx / vita)
 - #140741 (add armv5te-unknown-linux-gnueabi target maintainer)
 - #140745 (run-make-support: set rustc dylib path for cargo wrapper)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/lib.rs26
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs5
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/cursor.rs78
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs48
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs48
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs30
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs57
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs31
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs10
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs20
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs51
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs43
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs5
-rw-r--r--compiler/rustc_parse/messages.ftl10
-rw-r--r--compiler/rustc_parse/src/errors.rs24
-rw-r--r--compiler/rustc_parse/src/parser/item.rs15
-rw-r--r--compiler/rustc_parse/src/parser/path.rs29
-rw-r--r--library/std/src/sys/process/unix/mod.rs1
-rw-r--r--library/test/src/lib.rs10
-rw-r--r--src/doc/rustc-dev-guide/src/mir/dataflow.md3
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md29
-rw-r--r--src/librustdoc/doctest.rs23
-rw-r--r--src/librustdoc/doctest/markdown.rs1
-rw-r--r--src/tools/run-make-support/src/external_deps/cargo.rs5
-rw-r--r--tests/run-make/rustdoc-tempdir-removal/compile-error.rs5
-rw-r--r--tests/run-make/rustdoc-tempdir-removal/rmake.rs34
-rw-r--r--tests/run-make/rustdoc-tempdir-removal/run-error.rs3
-rw-r--r--tests/ui/explain/basic.rs (renamed from tests/ui/explain.rs)0
-rw-r--r--tests/ui/explain/basic.stdout (renamed from tests/ui/explain.stdout)0
-rw-r--r--tests/ui/explain/error-with-no-explanation.rs3
-rw-r--r--tests/ui/explain/error-with-no-explanation.stderr2
-rw-r--r--tests/ui/explain/invalid-error-code.rs2
-rw-r--r--tests/ui/explain/invalid-error-code.stderr2
-rw-r--r--tests/ui/explain/no-E-prefix.rs2
-rw-r--r--tests/ui/explain/no-E-prefix.stdout57
-rw-r--r--tests/ui/explain/overflow-error-code.rs4
-rw-r--r--tests/ui/explain/overflow-error-code.stderr2
-rw-r--r--tests/ui/fn/fn-trait-use-named-params-issue-140169.rs12
-rw-r--r--tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr38
-rw-r--r--tests/ui/imports/reexports.stderr2
-rw-r--r--tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs8
-rw-r--r--tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr45
-rw-r--r--tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs5
-rw-r--r--tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr39
-rw-r--r--tests/ui/pub/pub-restricted-warning.rs25
-rw-r--r--tests/ui/pub/pub-restricted-warning.stderr27
52 files changed, 643 insertions, 292 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index f9d8d858f16..3e075d420a3 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -47,7 +47,7 @@ use rustc_mir_dataflow::impls::{
 use rustc_mir_dataflow::move_paths::{
     InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
 };
-use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
+use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
 use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
 use smallvec::SmallVec;
@@ -469,11 +469,13 @@ fn do_mir_borrowck<'tcx>(
     // Compute and report region errors, if any.
     mbcx.report_region_errors(nll_errors);
 
-    let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
+    let (mut flow_analysis, flow_entry_states) =
+        get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
     visit_results(
         body,
         traversal::reverse_postorder(body).map(|(bb, _)| bb),
-        &mut flow_results,
+        &mut flow_analysis,
+        &flow_entry_states,
         &mut mbcx,
     );
 
@@ -533,7 +535,7 @@ fn get_flow_results<'a, 'tcx>(
     move_data: &'a MoveData<'tcx>,
     borrow_set: &'a BorrowSet<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
-) -> Results<'tcx, Borrowck<'a, 'tcx>> {
+) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
     // We compute these three analyses individually, but them combine them into
     // a single results so that `mbcx` can visit them all together.
     let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
@@ -558,14 +560,14 @@ fn get_flow_results<'a, 'tcx>(
         ever_inits: ever_inits.analysis,
     };
 
-    assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
-    assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
-    let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
-        itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
+    assert_eq!(borrows.results.len(), uninits.results.len());
+    assert_eq!(borrows.results.len(), ever_inits.results.len());
+    let results: Results<_> =
+        itertools::izip!(borrows.results, uninits.results, ever_inits.results)
             .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
             .collect();
 
-    Results { analysis, entry_states }
+    (analysis, results)
 }
 
 pub(crate) struct BorrowckInferCtxt<'tcx> {
@@ -713,7 +715,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
 impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
     fn visit_after_early_statement_effect(
         &mut self,
-        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
+        _analysis: &mut Borrowck<'a, 'tcx>,
         state: &BorrowckDomain,
         stmt: &Statement<'tcx>,
         location: Location,
@@ -789,7 +791,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
 
     fn visit_after_early_terminator_effect(
         &mut self,
-        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
+        _analysis: &mut Borrowck<'a, 'tcx>,
         state: &BorrowckDomain,
         term: &Terminator<'tcx>,
         loc: Location,
@@ -909,7 +911,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
 
     fn visit_after_primary_terminator_effect(
         &mut self,
-        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
+        _analysis: &mut Borrowck<'a, 'tcx>,
         state: &BorrowckDomain,
         term: &Terminator<'tcx>,
         loc: Location,
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index fdf8053b15a..95cfe221d3f 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -463,6 +463,7 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col
     // Allow "E0123" or "0123" form.
     let upper_cased_code = code.to_ascii_uppercase();
     if let Ok(code) = upper_cased_code.strip_prefix('E').unwrap_or(&upper_cased_code).parse::<u32>()
+        && code <= ErrCode::MAX_AS_U32
         && let Ok(description) = registry.try_find_description(ErrCode::from_u32(code))
     {
         let mut is_in_code_block = false;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c4ddaca26b2..2d69a1c2b55 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -309,7 +309,10 @@ impl Visibility {
                 } else if restricted_id == tcx.parent_module_from_def_id(def_id).to_local_def_id() {
                     "pub(self)".to_string()
                 } else {
-                    format!("pub({})", tcx.item_name(restricted_id.to_def_id()))
+                    format!(
+                        "pub(in crate{})",
+                        tcx.def_path(restricted_id.to_def_id()).to_string_no_crate_verbose()
+                    )
                 }
             }
             ty::Visibility::Public => "pub".to_string(),
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index d5005768b80..3f6e7a06619 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -1,5 +1,6 @@
 //! Random access inspection of the results of a dataflow analysis.
 
+use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::ops::{Deref, DerefMut};
 
@@ -9,38 +10,30 @@ use rustc_middle::mir::{self, BasicBlock, Location};
 
 use super::{Analysis, Direction, Effect, EffectIndex, Results};
 
-/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either
-/// mutable or immutably. This type allows all of the above. It's similar to `Cow`.
-pub enum ResultsHandle<'a, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    BorrowedMut(&'a mut Results<'tcx, A>),
-    Owned(Results<'tcx, A>),
+/// Some `ResultsCursor`s want to own an `Analysis`, and some want to borrow an `Analysis`, either
+/// mutable or immutably. This type allows all of the above. It's similar to `Cow`, but `Cow`
+/// doesn't allow mutable borrowing.
+enum CowMut<'a, T> {
+    BorrowedMut(&'a mut T),
+    Owned(T),
 }
 
-impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    type Target = Results<'tcx, A>;
+impl<T> Deref for CowMut<'_, T> {
+    type Target = T;
 
-    fn deref(&self) -> &Results<'tcx, A> {
+    fn deref(&self) -> &T {
         match self {
-            ResultsHandle::BorrowedMut(borrowed) => borrowed,
-            ResultsHandle::Owned(owned) => owned,
+            CowMut::BorrowedMut(borrowed) => borrowed,
+            CowMut::Owned(owned) => owned,
         }
     }
 }
 
-impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    fn deref_mut(&mut self) -> &mut Results<'tcx, A> {
+impl<T> DerefMut for CowMut<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
         match self {
-            ResultsHandle::BorrowedMut(borrowed) => borrowed,
-            ResultsHandle::Owned(owned) => owned,
+            CowMut::BorrowedMut(borrowed) => borrowed,
+            CowMut::Owned(owned) => owned,
         }
     }
 }
@@ -60,7 +53,8 @@ where
     A: Analysis<'tcx>,
 {
     body: &'mir mir::Body<'tcx>,
-    results: ResultsHandle<'mir, 'tcx, A>,
+    analysis: CowMut<'mir, A>,
+    results: Cow<'mir, Results<A::Domain>>,
     state: A::Domain,
 
     pos: CursorPosition,
@@ -88,11 +82,15 @@ where
         self.body
     }
 
-    /// Returns a new cursor that can inspect `results`.
-    pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self {
-        let bottom_value = results.analysis.bottom_value(body);
+    fn new(
+        body: &'mir mir::Body<'tcx>,
+        analysis: CowMut<'mir, A>,
+        results: Cow<'mir, Results<A::Domain>>,
+    ) -> Self {
+        let bottom_value = analysis.bottom_value(body);
         ResultsCursor {
             body,
+            analysis,
             results,
 
             // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that
@@ -107,6 +105,24 @@ where
         }
     }
 
+    /// Returns a new cursor that takes ownership of and inspects analysis results.
+    pub fn new_owning(
+        body: &'mir mir::Body<'tcx>,
+        analysis: A,
+        results: Results<A::Domain>,
+    ) -> Self {
+        Self::new(body, CowMut::Owned(analysis), Cow::Owned(results))
+    }
+
+    /// Returns a new cursor that borrows and inspects analysis results.
+    pub fn new_borrowing(
+        body: &'mir mir::Body<'tcx>,
+        analysis: &'mir mut A,
+        results: &'mir Results<A::Domain>,
+    ) -> Self {
+        Self::new(body, CowMut::BorrowedMut(analysis), Cow::Borrowed(results))
+    }
+
     /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled.
     #[cfg(test)]
     pub(crate) fn allow_unreachable(&mut self) {
@@ -116,7 +132,7 @@ where
 
     /// Returns the `Analysis` used to generate the underlying `Results`.
     pub fn analysis(&self) -> &A {
-        &self.results.analysis
+        &self.analysis
     }
 
     /// Resets the cursor to hold the entry set for the given basic block.
@@ -128,7 +144,7 @@ where
         #[cfg(debug_assertions)]
         assert!(self.reachable_blocks.contains(block));
 
-        self.state.clone_from(self.results.entry_set_for_block(block));
+        self.state.clone_from(&self.results[block]);
         self.pos = CursorPosition::block_entry(block);
         self.state_needs_reset = false;
     }
@@ -220,7 +236,7 @@ where
         let target_effect_index = effect.at_index(target.statement_index);
 
         A::Direction::apply_effects_in_range(
-            &mut self.results.analysis,
+            &mut *self.analysis,
             &mut self.state,
             target.block,
             block_data,
@@ -236,7 +252,7 @@ where
     /// This can be used, e.g., to apply the call return effect directly to the cursor without
     /// creating an extra copy of the dataflow state.
     pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) {
-        f(&mut self.results.analysis, &mut self.state);
+        f(&mut self.analysis, &mut self.state);
         self.state_needs_reset = true;
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index b8c26dad59f..e955e38ad10 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -5,7 +5,7 @@ use rustc_middle::mir::{
 };
 
 use super::visitor::ResultsVisitor;
-use super::{Analysis, Effect, EffectIndex, Results};
+use super::{Analysis, Effect, EffectIndex};
 
 pub trait Direction {
     const IS_FORWARD: bool;
@@ -36,13 +36,13 @@ pub trait Direction {
         A: Analysis<'tcx>;
 
     /// Called by `ResultsVisitor` to recompute the analysis domain values for
-    /// all locations in a basic block (starting from the entry value stored
-    /// in `Results`) and to visit them with `vis`.
+    /// all locations in a basic block (starting from `entry_state` and to
+    /// visit them with `vis`.
     fn visit_results_in_block<'mir, 'tcx, A>(
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
         vis: &mut impl ResultsVisitor<'tcx, A>,
     ) where
         A: Analysis<'tcx>;
@@ -211,28 +211,26 @@ impl Direction for Backward {
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
         vis: &mut impl ResultsVisitor<'tcx, A>,
     ) where
         A: Analysis<'tcx>,
     {
-        state.clone_from(results.entry_set_for_block(block));
-
         vis.visit_block_end(state);
 
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.analysis.apply_early_terminator_effect(state, term, loc);
-        vis.visit_after_early_terminator_effect(results, state, term, loc);
-        results.analysis.apply_primary_terminator_effect(state, term, loc);
-        vis.visit_after_primary_terminator_effect(results, state, term, loc);
+        analysis.apply_early_terminator_effect(state, term, loc);
+        vis.visit_after_early_terminator_effect(analysis, state, term, loc);
+        analysis.apply_primary_terminator_effect(state, term, loc);
+        vis.visit_after_primary_terminator_effect(analysis, state, term, loc);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
             let loc = Location { block, statement_index };
-            results.analysis.apply_early_statement_effect(state, stmt, loc);
-            vis.visit_after_early_statement_effect(results, state, stmt, loc);
-            results.analysis.apply_primary_statement_effect(state, stmt, loc);
-            vis.visit_after_primary_statement_effect(results, state, stmt, loc);
+            analysis.apply_early_statement_effect(state, stmt, loc);
+            vis.visit_after_early_statement_effect(analysis, state, stmt, loc);
+            analysis.apply_primary_statement_effect(state, stmt, loc);
+            vis.visit_after_primary_statement_effect(analysis, state, stmt, loc);
         }
 
         vis.visit_block_start(state);
@@ -393,29 +391,27 @@ impl Direction for Forward {
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
         vis: &mut impl ResultsVisitor<'tcx, A>,
     ) where
         A: Analysis<'tcx>,
     {
-        state.clone_from(results.entry_set_for_block(block));
-
         vis.visit_block_start(state);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate() {
             let loc = Location { block, statement_index };
-            results.analysis.apply_early_statement_effect(state, stmt, loc);
-            vis.visit_after_early_statement_effect(results, state, stmt, loc);
-            results.analysis.apply_primary_statement_effect(state, stmt, loc);
-            vis.visit_after_primary_statement_effect(results, state, stmt, loc);
+            analysis.apply_early_statement_effect(state, stmt, loc);
+            vis.visit_after_early_statement_effect(analysis, state, stmt, loc);
+            analysis.apply_primary_statement_effect(state, stmt, loc);
+            vis.visit_after_primary_statement_effect(analysis, state, stmt, loc);
         }
 
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.analysis.apply_early_terminator_effect(state, term, loc);
-        vis.visit_after_early_terminator_effect(results, state, term, loc);
-        results.analysis.apply_primary_terminator_effect(state, term, loc);
-        vis.visit_after_primary_terminator_effect(results, state, term, loc);
+        analysis.apply_early_terminator_effect(state, term, loc);
+        vis.visit_after_early_terminator_effect(analysis, state, term, loc);
+        analysis.apply_primary_terminator_effect(state, term, loc);
+        vis.visit_after_primary_terminator_effect(analysis, state, term, loc);
 
         vis.visit_block_end(state);
     }
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index b5e9a0b8932..a7d5422a3d7 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -21,7 +21,9 @@ use tracing::debug;
 use {rustc_ast as ast, rustc_graphviz as dot};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
-use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor};
+use super::{
+    Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor, visit_results,
+};
 use crate::errors::{
     DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
 };
@@ -32,7 +34,8 @@ use crate::errors::{
 pub(super) fn write_graphviz_results<'tcx, A>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    results: &mut Results<'tcx, A>,
+    analysis: &mut A,
+    results: &Results<A::Domain>,
     pass_name: Option<&'static str>,
 ) -> std::io::Result<()>
 where
@@ -77,7 +80,7 @@ where
 
     let mut buf = Vec::new();
 
-    let graphviz = Formatter::new(body, results, style);
+    let graphviz = Formatter::new(body, analysis, results, style);
     let mut render_opts =
         vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
     if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
@@ -203,10 +206,11 @@ where
 {
     body: &'mir Body<'tcx>,
     // The `RefCell` is used because `<Formatter as Labeller>::node_label`
-    // takes `&self`, but it needs to modify the results. This is also the
+    // takes `&self`, but it needs to modify the analysis. This is also the
     // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has
     // the operations that involve the mutation, i.e. within the `borrow_mut`.
-    results: RefCell<&'mir mut Results<'tcx, A>>,
+    analysis: RefCell<&'mir mut A>,
+    results: &'mir Results<A::Domain>,
     style: OutputStyle,
     reachable: DenseBitSet<BasicBlock>,
 }
@@ -217,11 +221,12 @@ where
 {
     fn new(
         body: &'mir Body<'tcx>,
-        results: &'mir mut Results<'tcx, A>,
+        analysis: &'mir mut A,
+        results: &'mir Results<A::Domain>,
         style: OutputStyle,
     ) -> Self {
         let reachable = traversal::reachable_as_bitset(body);
-        Formatter { body, results: results.into(), style, reachable }
+        Formatter { body, analysis: analysis.into(), results, style, reachable }
     }
 }
 
@@ -259,12 +264,12 @@ where
     }
 
     fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
-        let mut results = self.results.borrow_mut();
+        let analysis = &mut **self.analysis.borrow_mut();
 
-        let diffs = StateDiffCollector::run(self.body, *block, *results, self.style);
+        let diffs = StateDiffCollector::run(self.body, *block, analysis, self.results, self.style);
 
         let mut fmt = BlockFormatter {
-            cursor: results.as_results_cursor(self.body),
+            cursor: ResultsCursor::new_borrowing(self.body, analysis, self.results),
             style: self.style,
             bg: Background::Light,
         };
@@ -692,7 +697,8 @@ impl<D> StateDiffCollector<D> {
     fn run<'tcx, A>(
         body: &Body<'tcx>,
         block: BasicBlock,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
+        results: &Results<A::Domain>,
         style: OutputStyle,
     ) -> Self
     where
@@ -700,12 +706,12 @@ impl<D> StateDiffCollector<D> {
         D: DebugWithContext<A>,
     {
         let mut collector = StateDiffCollector {
-            prev_state: results.analysis.bottom_value(body),
+            prev_state: analysis.bottom_value(body),
             after: vec![],
             before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
         };
 
-        results.visit_with(body, std::iter::once(block), &mut collector);
+        visit_results(body, std::iter::once(block), analysis, results, &mut collector);
         collector
     }
 }
@@ -729,49 +735,49 @@ where
 
     fn visit_after_early_statement_effect(
         &mut self,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
         state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
         if let Some(before) = self.before.as_mut() {
-            before.push(diff_pretty(state, &self.prev_state, &results.analysis));
+            before.push(diff_pretty(state, &self.prev_state, analysis));
             self.prev_state.clone_from(state)
         }
     }
 
     fn visit_after_primary_statement_effect(
         &mut self,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
         state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
-        self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
+        self.after.push(diff_pretty(state, &self.prev_state, analysis));
         self.prev_state.clone_from(state)
     }
 
     fn visit_after_early_terminator_effect(
         &mut self,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
         state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
         if let Some(before) = self.before.as_mut() {
-            before.push(diff_pretty(state, &self.prev_state, &results.analysis));
+            before.push(diff_pretty(state, &self.prev_state, analysis));
             self.prev_state.clone_from(state)
         }
     }
 
     fn visit_after_primary_terminator_effect(
         &mut self,
-        results: &mut Results<'tcx, A>,
+        analysis: &mut A,
         state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
-        self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
+        self.after.push(diff_pretty(state, &self.prev_state, analysis));
         self.prev_state.clone_from(state)
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 09f6cdb5c4a..9cadec100b5 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -58,8 +58,9 @@ mod visitor;
 pub use self::cursor::ResultsCursor;
 pub use self::direction::{Backward, Direction, Forward};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
-pub use self::results::{EntryStates, Results};
-pub use self::visitor::{ResultsVisitor, visit_results};
+pub(crate) use self::results::AnalysisAndResults;
+pub use self::results::Results;
+pub use self::visitor::{ResultsVisitor, visit_reachable_results, visit_results};
 
 /// Analysis domains are all bitsets of various kinds. This trait holds
 /// operations needed by all of them.
@@ -247,17 +248,15 @@ pub trait Analysis<'tcx> {
         tcx: TyCtxt<'tcx>,
         body: &'mir mir::Body<'tcx>,
         pass_name: Option<&'static str>,
-    ) -> Results<'tcx, Self>
+    ) -> AnalysisAndResults<'tcx, Self>
     where
         Self: Sized,
         Self::Domain: DebugWithContext<Self>,
     {
-        let mut entry_states =
-            IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
-        self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]);
+        let mut results = IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
+        self.initialize_start_block(body, &mut results[mir::START_BLOCK]);
 
-        if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body)
-        {
+        if Self::Direction::IS_BACKWARD && results[mir::START_BLOCK] != self.bottom_value(body) {
             bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
         }
 
@@ -280,10 +279,9 @@ pub trait Analysis<'tcx> {
         // every iteration.
         let mut state = self.bottom_value(body);
         while let Some(bb) = dirty_queue.pop() {
-            // Set the state to the entry state of the block.
-            // This is equivalent to `state = entry_states[bb].clone()`,
-            // but it saves an allocation, thus improving compile times.
-            state.clone_from(&entry_states[bb]);
+            // Set the state to the entry state of the block. This is equivalent to `state =
+            // results[bb].clone()`, but it saves an allocation, thus improving compile times.
+            state.clone_from(&results[bb]);
 
             Self::Direction::apply_effects_in_block(
                 &mut self,
@@ -292,7 +290,7 @@ pub trait Analysis<'tcx> {
                 bb,
                 &body[bb],
                 |target: BasicBlock, state: &Self::Domain| {
-                    let set_changed = entry_states[target].join(state);
+                    let set_changed = results[target].join(state);
                     if set_changed {
                         dirty_queue.insert(target);
                     }
@@ -300,16 +298,14 @@ pub trait Analysis<'tcx> {
             );
         }
 
-        let mut results = Results { analysis: self, entry_states };
-
         if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
-            let res = write_graphviz_results(tcx, body, &mut results, pass_name);
+            let res = write_graphviz_results(tcx, body, &mut self, &results, pass_name);
             if let Err(e) = res {
                 error!("Failed to write graphviz dataflow results: {}", e);
             }
         }
 
-        results
+        AnalysisAndResults { analysis: self, results }
     }
 }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index 93dfc06a878..7b7e981d3a5 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -1,63 +1,30 @@
 //! Dataflow analysis results.
 
 use rustc_index::IndexVec;
-use rustc_middle::mir::{BasicBlock, Body, traversal};
+use rustc_middle::mir::{BasicBlock, Body};
 
-use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
-use crate::framework::cursor::ResultsHandle;
+use super::{Analysis, ResultsCursor};
 
-pub type EntryStates<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
+/// The results of a dataflow analysis that has converged to fixpoint. It only holds the domain
+/// values at the entry of each basic block. Domain values in other parts of the block are
+/// recomputed on the fly by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls).
+pub type Results<D> = IndexVec<BasicBlock, D>;
 
-/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
-/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
-/// by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls).
-#[derive(Clone)]
-pub struct Results<'tcx, A>
+/// Utility type used in a few places where it's convenient to bundle an analysis with its results.
+pub struct AnalysisAndResults<'tcx, A>
 where
     A: Analysis<'tcx>,
 {
     pub analysis: A,
-    pub entry_states: EntryStates<'tcx, A>,
+    pub results: Results<A::Domain>,
 }
 
-impl<'tcx, A> Results<'tcx, A>
+impl<'tcx, A> AnalysisAndResults<'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    /// Creates a `ResultsCursor` that mutably borrows the `Results`, which is appropriate when the
-    /// `Results` is also used outside the cursor.
-    pub fn as_results_cursor<'mir>(
-        &'mir mut self,
-        body: &'mir Body<'tcx>,
-    ) -> ResultsCursor<'mir, 'tcx, A> {
-        ResultsCursor::new(body, ResultsHandle::BorrowedMut(self))
-    }
-
-    /// Creates a `ResultsCursor` that takes ownership of the `Results`.
+    /// Creates a `ResultsCursor` that takes ownership of `self`.
     pub fn into_results_cursor<'mir>(self, body: &'mir Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
-        ResultsCursor::new(body, ResultsHandle::Owned(self))
-    }
-
-    /// Gets the dataflow state for the given block.
-    pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
-        &self.entry_states[block]
-    }
-
-    pub fn visit_with<'mir>(
-        &mut self,
-        body: &'mir Body<'tcx>,
-        blocks: impl IntoIterator<Item = BasicBlock>,
-        vis: &mut impl ResultsVisitor<'tcx, A>,
-    ) {
-        visit_results(body, blocks, self, vis)
-    }
-
-    pub fn visit_reachable_with<'mir>(
-        &mut self,
-        body: &'mir Body<'tcx>,
-        vis: &mut impl ResultsVisitor<'tcx, A>,
-    ) {
-        let blocks = traversal::reachable(body);
-        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
+        ResultsCursor::new_owning(body, self.analysis, self.results)
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index ae0f1179e6f..8602bb55765 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -79,7 +79,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
 ///
 /// The `102` in the block's entry set is derived from the basic block index and ensures that the
 /// expected state is unique across all basic blocks. Remember, it is generated by
-/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint.
+/// `mock_results`, not from actually running `MockAnalysis` to fixpoint.
 struct MockAnalysis<'tcx, D> {
     body: &'tcx mir::Body<'tcx>,
     dir: PhantomData<D>,
@@ -96,7 +96,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
         ret
     }
 
-    fn mock_entry_states(&self) -> IndexVec<BasicBlock, DenseBitSet<usize>> {
+    fn mock_results(&self) -> IndexVec<BasicBlock, DenseBitSet<usize>> {
         let empty = self.bottom_value(self.body);
         let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks);
 
@@ -255,7 +255,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
     let body = analysis.body;
 
     let mut cursor =
-        Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body);
+        AnalysisAndResults { results: analysis.mock_results(), analysis }.into_results_cursor(body);
 
     cursor.allow_unreachable();
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index c9fdf46c4f5..fbb9e410872 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -1,4 +1,4 @@
-use rustc_middle::mir::{self, BasicBlock, Location};
+use rustc_middle::mir::{self, BasicBlock, Location, traversal};
 
 use super::{Analysis, Direction, Results};
 
@@ -7,12 +7,13 @@ use super::{Analysis, Direction, Results};
 pub fn visit_results<'mir, 'tcx, A>(
     body: &'mir mir::Body<'tcx>,
     blocks: impl IntoIterator<Item = BasicBlock>,
-    results: &mut Results<'tcx, A>,
+    analysis: &mut A,
+    results: &Results<A::Domain>,
     vis: &mut impl ResultsVisitor<'tcx, A>,
 ) where
     A: Analysis<'tcx>,
 {
-    let mut state = results.analysis.bottom_value(body);
+    let mut state = analysis.bottom_value(body);
 
     #[cfg(debug_assertions)]
     let reachable_blocks = mir::traversal::reachable_as_bitset(body);
@@ -22,10 +23,24 @@ pub fn visit_results<'mir, 'tcx, A>(
         assert!(reachable_blocks.contains(block));
 
         let block_data = &body[block];
-        A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
+        state.clone_from(&results[block]);
+        A::Direction::visit_results_in_block(&mut state, block, block_data, analysis, vis);
     }
 }
 
+/// Like `visit_results`, but only for reachable blocks.
+pub fn visit_reachable_results<'mir, 'tcx, A>(
+    body: &'mir mir::Body<'tcx>,
+    analysis: &mut A,
+    results: &Results<A::Domain>,
+    vis: &mut impl ResultsVisitor<'tcx, A>,
+) where
+    A: Analysis<'tcx>,
+{
+    let blocks = traversal::reachable(body).map(|(bb, _)| bb);
+    visit_results(body, blocks, analysis, results, vis)
+}
+
 /// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in
 /// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain
 /// locations.
@@ -38,7 +53,7 @@ where
     /// Called after the "early" effect of the given statement is applied to `state`.
     fn visit_after_early_statement_effect(
         &mut self,
-        _results: &mut Results<'tcx, A>,
+        _analysis: &mut A,
         _state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
@@ -48,7 +63,7 @@ where
     /// Called after the "primary" effect of the given statement is applied to `state`.
     fn visit_after_primary_statement_effect(
         &mut self,
-        _results: &mut Results<'tcx, A>,
+        _analysis: &mut A,
         _state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
@@ -58,7 +73,7 @@ where
     /// Called after the "early" effect of the given terminator is applied to `state`.
     fn visit_after_early_terminator_effect(
         &mut self,
-        _results: &mut Results<'tcx, A>,
+        _analysis: &mut A,
         _state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
@@ -70,7 +85,7 @@ where
     /// The `call_return_effect` (if one exists) will *not* be applied to `state`.
     fn visit_after_primary_terminator_effect(
         &mut self,
-        _results: &mut Results<'tcx, A>,
+        _analysis: &mut A,
         _state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 38f82b12746..658fbf505e4 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{
     move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
 };
 pub use self::framework::{
-    Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable,
-    Results, ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_results,
+    Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
+    ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results, visit_results,
 };
 use self::move_paths::MoveData;
 
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index 21590ff1bba..70d1a34b5fb 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -98,7 +98,8 @@ rustc_index::newtype_index! {
 pub fn save_as_intervals<'tcx, N, A>(
     elements: &DenseLocationMap,
     body: &mir::Body<'tcx>,
-    mut results: Results<'tcx, A>,
+    mut analysis: A,
+    results: Results<A::Domain>,
 ) -> SparseIntervalMatrix<N, PointIndex>
 where
     N: Idx,
@@ -109,7 +110,8 @@ where
     visit_results(
         body,
         body.basic_blocks.reverse_postorder().iter().copied(),
-        &mut results,
+        &mut analysis,
+        &results,
         &mut visitor,
     );
     visitor.values
@@ -127,7 +129,7 @@ where
 {
     fn visit_after_primary_statement_effect<'mir>(
         &mut self,
-        _results: &mut Results<'tcx, A>,
+        _analysis: &mut A,
         state: &A::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         location: Location,
@@ -141,7 +143,7 @@ where
 
     fn visit_after_primary_terminator_effect<'mir>(
         &mut self,
-        _results: &mut Results<'tcx, A>,
+        _analysis: &mut A,
         state: &A::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 399141aa921..303fc767b9a 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -39,23 +39,23 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let move_data = MoveData::gather_moves(body, tcx, |_| true);
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
-        let flow_inits =
-            MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None);
-
-        sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
+        let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
+            .iterate_to_fixpoint(tcx, body, None)
+            .into_results_cursor(body);
+        sanity_check_via_rustc_peek(tcx, flow_inits);
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
         let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
-            .iterate_to_fixpoint(tcx, body, None);
-
-        sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
+            .iterate_to_fixpoint(tcx, body, None)
+            .into_results_cursor(body);
+        sanity_check_via_rustc_peek(tcx, flow_uninits);
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
-        let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);
-
-        sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
+        let flow_liveness =
+            MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body);
+        sanity_check_via_rustc_peek(tcx, flow_liveness);
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 66f106bec6f..cddb2f84778 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -79,7 +79,9 @@ use rustc_mir_dataflow::impls::{
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
     always_storage_live_locals,
 };
-use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
+use rustc_mir_dataflow::{
+    Analysis, Results, ResultsCursor, ResultsVisitor, visit_reachable_results,
+};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::source_map::dummy_spanned;
 use rustc_span::symbol::sym;
@@ -680,18 +682,29 @@ fn locals_live_across_suspend_points<'tcx>(
         .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
-    // Calculate the MIR locals which have been previously
-    // borrowed (even if they are still active).
-    let borrowed_locals_results =
-        MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine"));
-
-    let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
+    // Calculate the MIR locals that have been previously borrowed (even if they are still active).
+    let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine"));
+    let mut borrowed_locals_analysis1 = borrowed_locals.analysis;
+    let mut borrowed_locals_analysis2 = borrowed_locals_analysis1.clone(); // trivial
+    let borrowed_locals_cursor1 = ResultsCursor::new_borrowing(
+        body,
+        &mut borrowed_locals_analysis1,
+        &borrowed_locals.results,
+    );
+    let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing(
+        body,
+        &mut borrowed_locals_analysis2,
+        &borrowed_locals.results,
+    );
 
     // Calculate the MIR locals that we need to keep storage around for.
-    let mut requires_storage_results =
-        MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
-            .iterate_to_fixpoint(tcx, body, None);
-    let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body);
+    let mut requires_storage =
+        MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None);
+    let mut requires_storage_cursor = ResultsCursor::new_borrowing(
+        body,
+        &mut requires_storage.analysis,
+        &requires_storage.results,
+    );
 
     // Calculate the liveness of MIR locals ignoring borrows.
     let mut liveness =
@@ -720,8 +733,8 @@ fn locals_live_across_suspend_points<'tcx>(
                 // If a borrow is converted to a raw reference, we must also assume that it lives
                 // forever. Note that the final liveness is still bounded by the storage liveness
                 // of the local, which happens using the `intersect` operation below.
-                borrowed_locals_cursor.seek_before_primary_effect(loc);
-                live_locals.union(borrowed_locals_cursor.get());
+                borrowed_locals_cursor2.seek_before_primary_effect(loc);
+                live_locals.union(borrowed_locals_cursor2.get());
             }
 
             // Store the storage liveness for later use so we can restore the state
@@ -763,7 +776,8 @@ fn locals_live_across_suspend_points<'tcx>(
         body,
         &saved_locals,
         always_live_locals.clone(),
-        requires_storage_results,
+        &mut requires_storage.analysis,
+        &requires_storage.results,
     );
 
     LivenessInfo {
@@ -828,7 +842,8 @@ fn compute_storage_conflicts<'mir, 'tcx>(
     body: &'mir Body<'tcx>,
     saved_locals: &'mir CoroutineSavedLocals,
     always_live_locals: DenseBitSet<Local>,
-    mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
+    analysis: &mut MaybeRequiresStorage<'mir, 'tcx>,
+    results: &Results<DenseBitSet<Local>>,
 ) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
@@ -848,7 +863,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
         eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()),
     };
 
-    requires_storage.visit_reachable_with(body, &mut visitor);
+    visit_reachable_results(body, analysis, results, &mut visitor);
 
     let local_conflicts = visitor.local_conflicts;
 
@@ -891,7 +906,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>>
 {
     fn visit_after_early_statement_effect(
         &mut self,
-        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        _analysis: &mut MaybeRequiresStorage<'a, 'tcx>,
         state: &DenseBitSet<Local>,
         _statement: &Statement<'tcx>,
         loc: Location,
@@ -901,7 +916,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>>
 
     fn visit_after_early_terminator_effect(
         &mut self,
-        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        _analysis: &mut MaybeRequiresStorage<'a, 'tcx>,
         state: &DenseBitSet<Local>,
         _terminator: &Terminator<'tcx>,
         loc: Location,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index a2103a004d2..99b95e7312b 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -23,7 +23,7 @@ use rustc_mir_dataflow::lattice::{FlatSet, HasBottom};
 use rustc_mir_dataflow::value_analysis::{
     Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context,
 };
-use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
+use rustc_mir_dataflow::{Analysis, ResultsVisitor, visit_reachable_results};
 use rustc_span::DUMMY_SP;
 use tracing::{debug, debug_span, instrument};
 
@@ -61,13 +61,14 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
         let map = Map::new(tcx, body, place_limit);
 
         // Perform the actual dataflow analysis.
-        let analysis = ConstAnalysis::new(tcx, body, map);
-        let mut results =
-            debug_span!("analyze").in_scope(|| analysis.iterate_to_fixpoint(tcx, body, None));
+        let mut const_ = debug_span!("analyze")
+            .in_scope(|| ConstAnalysis::new(tcx, body, map).iterate_to_fixpoint(tcx, body, None));
 
         // Collect results and patch the body afterwards.
         let mut visitor = Collector::new(tcx, &body.local_decls);
-        debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor));
+        debug_span!("collect").in_scope(|| {
+            visit_reachable_results(body, &mut const_.analysis, &const_.results, &mut visitor)
+        });
         let mut patch = visitor.patch;
         debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
     }
@@ -959,10 +960,10 @@ fn try_write_constant<'tcx>(
 }
 
 impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
-    #[instrument(level = "trace", skip(self, results, statement))]
+    #[instrument(level = "trace", skip(self, analysis, statement))]
     fn visit_after_early_statement_effect(
         &mut self,
-        results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
+        analysis: &mut ConstAnalysis<'_, 'tcx>,
         state: &State<FlatSet<Scalar>>,
         statement: &Statement<'tcx>,
         location: Location,
@@ -972,8 +973,8 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
                 OperandCollector {
                     state,
                     visitor: self,
-                    ecx: &mut results.analysis.ecx,
-                    map: &results.analysis.map,
+                    ecx: &mut analysis.ecx,
+                    map: &analysis.map,
                 }
                 .visit_rvalue(rvalue, location);
             }
@@ -981,10 +982,10 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
         }
     }
 
-    #[instrument(level = "trace", skip(self, results, statement))]
+    #[instrument(level = "trace", skip(self, analysis, statement))]
     fn visit_after_primary_statement_effect(
         &mut self,
-        results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
+        analysis: &mut ConstAnalysis<'_, 'tcx>,
         state: &State<FlatSet<Scalar>>,
         statement: &Statement<'tcx>,
         location: Location,
@@ -994,12 +995,9 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
                 // Don't overwrite the assignment if it already uses a constant (to keep the span).
             }
             StatementKind::Assign(box (place, _)) => {
-                if let Some(value) = self.try_make_constant(
-                    &mut results.analysis.ecx,
-                    place,
-                    state,
-                    &results.analysis.map,
-                ) {
+                if let Some(value) =
+                    self.try_make_constant(&mut analysis.ecx, place, state, &analysis.map)
+                {
                     self.patch.assignments.insert(location, value);
                 }
             }
@@ -1009,18 +1007,13 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx>
 
     fn visit_after_early_terminator_effect(
         &mut self,
-        results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
+        analysis: &mut ConstAnalysis<'_, 'tcx>,
         state: &State<FlatSet<Scalar>>,
         terminator: &Terminator<'tcx>,
         location: Location,
     ) {
-        OperandCollector {
-            state,
-            visitor: self,
-            ecx: &mut results.analysis.ecx,
-            map: &results.analysis.map,
-        }
-        .visit_terminator(terminator, location);
+        OperandCollector { state, visitor: self, ecx: &mut analysis.ecx, map: &analysis.map }
+            .visit_terminator(terminator, location);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 7395ad496db..4c94a6c524e 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -171,7 +171,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
 
         let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp"));
         let points = DenseLocationMap::new(body);
-        let mut live = save_as_intervals(&points, body, live);
+        let mut live = save_as_intervals(&points, body, live.analysis, live.results);
 
         // In order to avoid having to collect data for every single pair of locals in the body, we
         // do not allow doing more than one merge for places that are derived from the same local at
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
index b8cb101f93c..75f351f05c3 100644
--- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -235,8 +235,9 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
     // When we encounter a DROP of some place P we only care
     // about the drop if `P` may be initialized.
     let move_data = MoveData::gather_moves(body, tcx, |_| true);
-    let maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data);
-    let mut maybe_init = maybe_init.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body);
+    let mut maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data)
+        .iterate_to_fixpoint(tcx, body, None)
+        .into_results_cursor(body);
     let mut block_drop_value_info =
         IndexVec::from_elem_n(MovePathIndexAtBlock::Unknown, body.basic_blocks.len());
     for (&block, candidates) in &bid_per_block {
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 3e953e6c855..3d7e0fcc308 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -715,6 +715,16 @@ parse_parenthesized_lifetime_suggestion = remove the parentheses
 parse_path_double_colon = path separator must be a double colon
     .suggestion = use a double colon instead
 
+
+parse_path_found_attribute_in_params = `Trait(...)` syntax does not support attributes in parameters
+    .suggestion = remove the attributes
+
+parse_path_found_c_variadic_params = `Trait(...)` syntax does not support c_variadic parameters
+    .suggestion = remove the `...`
+
+parse_path_found_named_params = `Trait(...)` syntax does not support named parameters
+    .suggestion = remove the parameter name
+
 parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
     .suggestion = give this argument a name or use an underscore to ignore it
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 9e5c81d44a5..766baf6f80c 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1647,6 +1647,30 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_path_found_named_params)]
+pub(crate) struct FnPathFoundNamedParams {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub named_param_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_path_found_c_variadic_params)]
+pub(crate) struct PathFoundCVariadicParams {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_path_found_attribute_in_params)]
+pub(crate) struct PathFoundAttributeInParams {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_path_double_colon)]
 pub(crate) struct PathSingleColon {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 4be8a90368d..babc55ccc0f 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2894,7 +2894,7 @@ impl<'a> Parser<'a> {
         let (mut params, _) = self.parse_paren_comma_seq(|p| {
             p.recover_vcs_conflict_marker();
             let snapshot = p.create_snapshot_for_diagnostic();
-            let param = p.parse_param_general(req_name, first_param).or_else(|e| {
+            let param = p.parse_param_general(req_name, first_param, true).or_else(|e| {
                 let guar = e.emit();
                 // When parsing a param failed, we should check to make the span of the param
                 // not contain '(' before it.
@@ -2922,7 +2922,13 @@ impl<'a> Parser<'a> {
     /// Parses a single function parameter.
     ///
     /// - `self` is syntactically allowed when `first_param` holds.
-    fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> {
+    /// - `recover_arg_parse` is used to recover from a failed argument parse.
+    pub(super) fn parse_param_general(
+        &mut self,
+        req_name: ReqName,
+        first_param: bool,
+        recover_arg_parse: bool,
+    ) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
         self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
@@ -2990,12 +2996,13 @@ impl<'a> Parser<'a> {
                     // If this is a C-variadic argument and we hit an error, return the error.
                     Err(err) if this.token == token::DotDotDot => return Err(err),
                     Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err),
-                    // Recover from attempting to parse the argument as a type without pattern.
-                    Err(err) => {
+                    Err(err) if recover_arg_parse => {
+                        // Recover from attempting to parse the argument as a type without pattern.
                         err.cancel();
                         this.restore_snapshot(parser_snapshot_before_ty);
                         this.recover_arg_parse()?
                     }
+                    Err(err) => return Err(err),
                 }
             };
 
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 1093e4f4af0..9bce2fa74ca 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -15,7 +15,11 @@ use tracing::debug;
 
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{Parser, Restrictions, TokenType};
-use crate::errors::{self, PathSingleColon, PathTripleColon};
+use crate::ast::{PatKind, TyKind};
+use crate::errors::{
+    self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams,
+    PathSingleColon, PathTripleColon,
+};
 use crate::exp;
 use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
 
@@ -396,7 +400,28 @@ impl<'a> Parser<'a> {
                         snapshot = Some(self.create_snapshot_for_diagnostic());
                     }
 
-                    let (inputs, _) = match self.parse_paren_comma_seq(|p| p.parse_ty()) {
+                    let dcx = self.dcx();
+                    let parse_params_result = self.parse_paren_comma_seq(|p| {
+                        let param = p.parse_param_general(|_| false, false, false);
+                        param.map(move |param| {
+                            if !matches!(param.pat.kind, PatKind::Missing) {
+                                dcx.emit_err(FnPathFoundNamedParams {
+                                    named_param_span: param.pat.span,
+                                });
+                            }
+                            if matches!(param.ty.kind, TyKind::CVarArgs) {
+                                dcx.emit_err(PathFoundCVariadicParams { span: param.pat.span });
+                            }
+                            if !param.attrs.is_empty() {
+                                dcx.emit_err(PathFoundAttributeInParams {
+                                    span: param.attrs[0].span,
+                                });
+                            }
+                            param.ty
+                        })
+                    });
+
+                    let (inputs, _) = match parse_params_result {
                         Ok(output) => output,
                         Err(mut error) if prev_token_before_parsing == token::PathSep => {
                             error.span_label(
diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs
index 2e8b38f7de1..ee8fd8b2ca3 100644
--- a/library/std/src/sys/process/unix/mod.rs
+++ b/library/std/src/sys/process/unix/mod.rs
@@ -11,6 +11,7 @@ cfg_if::cfg_if! {
     } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] {
         mod unsupported;
         use unsupported as imp;
+        pub use unsupported::output;
     } else {
         mod unix;
         use unix as imp;
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index acaf026c679..7f56d1e3626 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -98,6 +98,15 @@ const SECONDARY_TEST_BENCH_BENCHMARKS_VAR: &str = "__RUST_TEST_BENCH_BENCHMARKS"
 // The default console test runner. It accepts the command line
 // arguments and a vector of test_descs.
 pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Options>) {
+    test_main_with_exit_callback(args, tests, options, || {})
+}
+
+pub fn test_main_with_exit_callback<F: FnOnce()>(
+    args: &[String],
+    tests: Vec<TestDescAndFn>,
+    options: Option<Options>,
+    exit_callback: F,
+) {
     let mut opts = match cli::parse_opts(args) {
         Some(Ok(o)) => o,
         Some(Err(msg)) => {
@@ -151,6 +160,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
         let res = console::run_tests_console(&opts, tests);
         // Prevent Valgrind from reporting reachable blocks in users' unit tests.
         drop(panic::take_hook());
+        exit_callback();
         match res {
             Ok(true) => {}
             Ok(false) => process::exit(ERROR_EXIT_CODE),
diff --git a/src/doc/rustc-dev-guide/src/mir/dataflow.md b/src/doc/rustc-dev-guide/src/mir/dataflow.md
index f31da5ca22e..85e57dd839b 100644
--- a/src/doc/rustc-dev-guide/src/mir/dataflow.md
+++ b/src/doc/rustc-dev-guide/src/mir/dataflow.md
@@ -148,8 +148,7 @@ whereas this code uses [`ResultsCursor`]:
 
 ```rust,ignore
 let mut results = MyAnalysis::new()
-    .into_engine(tcx, body, def_id)
-    .iterate_to_fixpoint()
+    .iterate_to_fixpoint(tcx, body, None);
     .into_results_cursor(body);
 
 // Inspect the fixpoint state immediately before each `Drop` terminator.
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index cf41f5b86a8..a3939e5a5c4 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -58,6 +58,7 @@
       - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md)
       - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md)
       - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md)
+    - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 50c7ae3ef8d..60002a5f9e5 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -156,7 +156,7 @@ target | std | notes
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
 [`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
 [`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
-`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
+[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
 `armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27)
diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
new file mode 100644
index 00000000000..1baf1049994
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
@@ -0,0 +1,29 @@
+# `armv5te-unknown-linux-gnueabi`
+
+**Tier: 2**
+
+This target supports Linux programs with glibc on ARMv5TE CPUs without
+floating-point units.
+
+## Target maintainers
+
+[@koalatux](https://github.com/koalatux)
+
+## Requirements
+
+The target is for cross-compilation only. Host tools are not supported.
+std is fully supported.
+
+## Building the target
+
+Because this target is tier 2, artifacts are available from rustup.
+
+## Building Rust programs
+
+For building rust programs, you might want to specify GCC as linker in
+`.cargo/config.toml` as follows:
+
+```toml
+[target.armv5te-unknown-linux-gnueabi]
+linker = "arm-linux-gnueabi-gcc"
+```
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 829a9ca6e7d..0cdf2f92a89 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -262,11 +262,21 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
         Ok(None) => return,
         Err(error) => {
             eprintln!("{error}");
+            // Since some files in the temporary folder are still owned and alive, we need
+            // to manually remove the folder.
+            let _ = std::fs::remove_dir_all(temp_dir.path());
             std::process::exit(1);
         }
     };
 
-    run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests);
+    run_tests(
+        opts,
+        &rustdoc_options,
+        &unused_extern_reports,
+        standalone_tests,
+        mergeable_tests,
+        Some(temp_dir),
+    );
 
     let compiling_test_count = compiling_test_count.load(Ordering::SeqCst);
 
@@ -316,6 +326,8 @@ pub(crate) fn run_tests(
     unused_extern_reports: &Arc<Mutex<Vec<UnusedExterns>>>,
     mut standalone_tests: Vec<test::TestDescAndFn>,
     mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
+    // We pass this argument so we can drop it manually before using `exit`.
+    mut temp_dir: Option<TempDir>,
 ) {
     let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1);
     test_args.insert(0, "rustdoctest".to_string());
@@ -382,9 +394,14 @@ pub(crate) fn run_tests(
     // `running 0 tests...`.
     if ran_edition_tests == 0 || !standalone_tests.is_empty() {
         standalone_tests.sort_by(|a, b| a.desc.name.as_slice().cmp(b.desc.name.as_slice()));
-        test::test_main(&test_args, standalone_tests, None);
+        test::test_main_with_exit_callback(&test_args, standalone_tests, None, || {
+            // We ensure temp dir destructor is called.
+            std::mem::drop(temp_dir.take());
+        });
     }
     if nb_errors != 0 {
+        // We ensure temp dir destructor is called.
+        std::mem::drop(temp_dir);
         // libtest::ERROR_EXIT_CODE is not public but it's the same value.
         std::process::exit(101);
     }
@@ -450,7 +467,7 @@ enum TestFailure {
 }
 
 enum DirState {
-    Temp(tempfile::TempDir),
+    Temp(TempDir),
     Perm(PathBuf),
 }
 
diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs
index 497a8d7c4a7..b3a3ce08a05 100644
--- a/src/librustdoc/doctest/markdown.rs
+++ b/src/librustdoc/doctest/markdown.rs
@@ -116,6 +116,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> {
         &Arc::new(Mutex::new(Vec::new())),
         standalone_tests,
         mergeable_tests,
+        None,
     );
     Ok(())
 }
diff --git a/src/tools/run-make-support/src/external_deps/cargo.rs b/src/tools/run-make-support/src/external_deps/cargo.rs
index e91d101cb99..8da9f002c41 100644
--- a/src/tools/run-make-support/src/external_deps/cargo.rs
+++ b/src/tools/run-make-support/src/external_deps/cargo.rs
@@ -1,8 +1,11 @@
 use crate::command::Command;
 use crate::env_var;
+use crate::util::set_host_compiler_dylib_path;
 
 /// Returns a command that can be used to invoke cargo. The cargo is provided by compiletest
 /// through the `CARGO` env var.
 pub fn cargo() -> Command {
-    Command::new(env_var("CARGO"))
+    let mut cmd = Command::new(env_var("CARGO"));
+    set_host_compiler_dylib_path(&mut cmd);
+    cmd
 }
diff --git a/tests/run-make/rustdoc-tempdir-removal/compile-error.rs b/tests/run-make/rustdoc-tempdir-removal/compile-error.rs
new file mode 100644
index 00000000000..66a3b3f270b
--- /dev/null
+++ b/tests/run-make/rustdoc-tempdir-removal/compile-error.rs
@@ -0,0 +1,5 @@
+#![doc(test(attr(deny(warnings))))]
+
+//! ```
+//! let a = 12;
+//! ```
diff --git a/tests/run-make/rustdoc-tempdir-removal/rmake.rs b/tests/run-make/rustdoc-tempdir-removal/rmake.rs
new file mode 100644
index 00000000000..bd87f05b7cf
--- /dev/null
+++ b/tests/run-make/rustdoc-tempdir-removal/rmake.rs
@@ -0,0 +1,34 @@
+// This test ensures that no temporary folder is "left behind" when doctests fail for any reason.
+
+//@ only-linux
+
+use std::path::Path;
+
+use run_make_support::{path, rfs, rustdoc};
+
+fn run_doctest_and_check_tmpdir(tmp_dir: &Path, doctest: &str, edition: &str) {
+    let output =
+        rustdoc().input(doctest).env("TMPDIR", tmp_dir).arg("--test").edition(edition).run_fail();
+
+    output.assert_exit_code(101).assert_stdout_contains(
+        "test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out",
+    );
+
+    rfs::read_dir_entries(tmp_dir, |entry| {
+        panic!("Found an item inside the temporary folder: {entry:?}");
+    });
+}
+
+fn run_doctest_and_check_tmpdir_for_edition(tmp_dir: &Path, edition: &str) {
+    run_doctest_and_check_tmpdir(tmp_dir, "compile-error.rs", edition);
+    run_doctest_and_check_tmpdir(tmp_dir, "run-error.rs", edition);
+}
+
+fn main() {
+    let tmp_dir = path("tmp");
+    rfs::create_dir(&tmp_dir);
+
+    run_doctest_and_check_tmpdir_for_edition(&tmp_dir, "2018");
+    // We use the 2024 edition to check that it's also working for merged doctests.
+    run_doctest_and_check_tmpdir_for_edition(&tmp_dir, "2024");
+}
diff --git a/tests/run-make/rustdoc-tempdir-removal/run-error.rs b/tests/run-make/rustdoc-tempdir-removal/run-error.rs
new file mode 100644
index 00000000000..4ac95f6dd61
--- /dev/null
+++ b/tests/run-make/rustdoc-tempdir-removal/run-error.rs
@@ -0,0 +1,3 @@
+//! ```
+//! panic!();
+//! ```
diff --git a/tests/ui/explain.rs b/tests/ui/explain/basic.rs
index 1206c4f95eb..1206c4f95eb 100644
--- a/tests/ui/explain.rs
+++ b/tests/ui/explain/basic.rs
diff --git a/tests/ui/explain.stdout b/tests/ui/explain/basic.stdout
index ef1d866c3ff..ef1d866c3ff 100644
--- a/tests/ui/explain.stdout
+++ b/tests/ui/explain/basic.stdout
diff --git a/tests/ui/explain/error-with-no-explanation.rs b/tests/ui/explain/error-with-no-explanation.rs
new file mode 100644
index 00000000000..383820eb458
--- /dev/null
+++ b/tests/ui/explain/error-with-no-explanation.rs
@@ -0,0 +1,3 @@
+// It's a valid error with no added explanation
+//@ compile-flags: --explain E9999
+//~? ERROR: E9999 is not a valid error code
diff --git a/tests/ui/explain/error-with-no-explanation.stderr b/tests/ui/explain/error-with-no-explanation.stderr
new file mode 100644
index 00000000000..afb738cfecb
--- /dev/null
+++ b/tests/ui/explain/error-with-no-explanation.stderr
@@ -0,0 +1,2 @@
+error: E9999 is not a valid error code
+
diff --git a/tests/ui/explain/invalid-error-code.rs b/tests/ui/explain/invalid-error-code.rs
new file mode 100644
index 00000000000..114118d5196
--- /dev/null
+++ b/tests/ui/explain/invalid-error-code.rs
@@ -0,0 +1,2 @@
+//@ compile-flags: --explain error_code
+//~? ERROR: error_code is not a valid error code
diff --git a/tests/ui/explain/invalid-error-code.stderr b/tests/ui/explain/invalid-error-code.stderr
new file mode 100644
index 00000000000..c33122ea88c
--- /dev/null
+++ b/tests/ui/explain/invalid-error-code.stderr
@@ -0,0 +1,2 @@
+error: error_code is not a valid error code
+
diff --git a/tests/ui/explain/no-E-prefix.rs b/tests/ui/explain/no-E-prefix.rs
new file mode 100644
index 00000000000..39c9122bfe1
--- /dev/null
+++ b/tests/ui/explain/no-E-prefix.rs
@@ -0,0 +1,2 @@
+//@ compile-flags: --explain 425
+//@ check-pass
diff --git a/tests/ui/explain/no-E-prefix.stdout b/tests/ui/explain/no-E-prefix.stdout
new file mode 100644
index 00000000000..756b970aa7e
--- /dev/null
+++ b/tests/ui/explain/no-E-prefix.stdout
@@ -0,0 +1,57 @@
+An unresolved name was used.
+
+Erroneous code examples:
+
+```
+something_that_doesnt_exist::foo;
+// error: unresolved name `something_that_doesnt_exist::foo`
+
+// or:
+
+trait Foo {
+    fn bar() {
+        Self; // error: unresolved name `Self`
+    }
+}
+
+// or:
+
+let x = unknown_variable;  // error: unresolved name `unknown_variable`
+```
+
+Please verify that the name wasn't misspelled and ensure that the
+identifier being referred to is valid for the given situation. Example:
+
+```
+enum something_that_does_exist {
+    Foo,
+}
+```
+
+Or:
+
+```
+mod something_that_does_exist {
+    pub static foo : i32 = 0i32;
+}
+
+something_that_does_exist::foo; // ok!
+```
+
+Or:
+
+```
+let unknown_variable = 12u32;
+let x = unknown_variable; // ok!
+```
+
+If the item is not defined in the current module, it must be imported using a
+`use` statement, like so:
+
+```
+use foo::bar;
+bar();
+```
+
+If the item you are importing is not defined in some super-module of the
+current module, then it must also be declared as public (e.g., `pub fn`).
diff --git a/tests/ui/explain/overflow-error-code.rs b/tests/ui/explain/overflow-error-code.rs
new file mode 100644
index 00000000000..284d5cddb35
--- /dev/null
+++ b/tests/ui/explain/overflow-error-code.rs
@@ -0,0 +1,4 @@
+// Check that we don't crash on error codes exceeding our internal limit.
+// issue: <https://github.com/rust-lang/rust/issues/140647>
+//@ compile-flags: --explain E10000
+//~? ERROR: E10000 is not a valid error code
diff --git a/tests/ui/explain/overflow-error-code.stderr b/tests/ui/explain/overflow-error-code.stderr
new file mode 100644
index 00000000000..67e584ea32e
--- /dev/null
+++ b/tests/ui/explain/overflow-error-code.stderr
@@ -0,0 +1,2 @@
+error: E10000 is not a valid error code
+
diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs
new file mode 100644
index 00000000000..218450abd49
--- /dev/null
+++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs
@@ -0,0 +1,12 @@
+fn f1(_: fn(a: u8)) {}
+fn f2(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters
+fn f3(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters
+fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {}
+//~^ ERROR `Trait(...)` syntax does not support named parameters
+//~| ERROR `Trait(...)` syntax does not support named parameters
+fn f5(_: impl Fn(u8, ...)) {}
+//~^ ERROR `Trait(...)` syntax does not support c_variadic parameters
+fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {}
+//~^ ERROR `Trait(...)` syntax does not support attributes in parameters
+
+fn main(){}
diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr
new file mode 100644
index 00000000000..b72d5b7b3bc
--- /dev/null
+++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr
@@ -0,0 +1,38 @@
+error: `Trait(...)` syntax does not support named parameters
+  --> $DIR/fn-trait-use-named-params-issue-140169.rs:2:22
+   |
+LL | fn f2(_: impl Fn(u8, vvvv: u8)) {}
+   |                      ^^^^ help: remove the parameter name
+
+error: `Trait(...)` syntax does not support named parameters
+  --> $DIR/fn-trait-use-named-params-issue-140169.rs:3:18
+   |
+LL | fn f3(_: impl Fn(aaaa: u8, u8)) {}
+   |                  ^^^^ help: remove the parameter name
+
+error: `Trait(...)` syntax does not support named parameters
+  --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:18
+   |
+LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {}
+   |                  ^^^^ help: remove the parameter name
+
+error: `Trait(...)` syntax does not support named parameters
+  --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:28
+   |
+LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {}
+   |                            ^^^^ help: remove the parameter name
+
+error: `Trait(...)` syntax does not support c_variadic parameters
+  --> $DIR/fn-trait-use-named-params-issue-140169.rs:7:22
+   |
+LL | fn f5(_: impl Fn(u8, ...)) {}
+   |                      ^^^ help: remove the `...`
+
+error: `Trait(...)` syntax does not support attributes in parameters
+  --> $DIR/fn-trait-use-named-params-issue-140169.rs:9:22
+   |
+LL | fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {}
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the attributes
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr
index bf4ba474875..fa05c0c0f8e 100644
--- a/tests/ui/imports/reexports.stderr
+++ b/tests/ui/imports/reexports.stderr
@@ -62,7 +62,7 @@ warning: glob import doesn't reexport anything with visibility `pub` because no
 LL |         pub use super::*;
    |                 ^^^^^^^^
    |
-note: the most public imported item is `pub(a)`
+note: the most public imported item is `pub(in crate::a)`
   --> $DIR/reexports.rs:11:17
    |
 LL |         pub use super::*;
diff --git a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs
index 6bfe16ae37d..db25ce44089 100644
--- a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs
+++ b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs
@@ -2,8 +2,10 @@
 
 fn main() {
     unsafe {
-        dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
-        //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
-        //~| NOTE while parsing this parenthesized list of type arguments starting here
+        dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR `Trait(...)` syntax does not support named parameters
+        //~^ ERROR cannot find function `dealloc` in this scope [E0425]
+        //~| ERROR cannot find value `ptr2` in this scope [E0425]
+        //~| ERROR the `!` type is experimental [E0658]
+        //~| ERROR cannot find function, tuple struct or tuple variant `Layout` in this scope [E0425]
     }
 }
diff --git a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr
index c12bf7f9e3f..a083883af21 100644
--- a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr
+++ b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr
@@ -1,16 +1,43 @@
-error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
-  --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:33
+error: `Trait(...)` syntax does not support named parameters
+  --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:32
    |
 LL |         dealloc(ptr2, Layout::(x: !)(1, 1));
-   |                             --- ^ expected one of 7 possible tokens
-   |                             |
-   |                             while parsing this parenthesized list of type arguments starting here
+   |                                ^ help: remove the parameter name
 
-error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
-  --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:43
+error[E0425]: cannot find function `dealloc` in this scope
+  --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:9
    |
 LL |         dealloc(ptr2, Layout::(x: !)(1, 1));
-   |                                           ^ expected one of `.`, `;`, `?`, `}`, or an operator
+   |         ^^^^^^^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL + use std::alloc::dealloc;
+   |
+
+error[E0425]: cannot find value `ptr2` in this scope
+  --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:17
+   |
+LL |         dealloc(ptr2, Layout::(x: !)(1, 1));
+   |                 ^^^^ not found in this scope
+
+error[E0658]: the `!` type is experimental
+  --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:35
+   |
+LL |         dealloc(ptr2, Layout::(x: !)(1, 1));
+   |                                   ^
+   |
+   = note: see issue #35121 <https://github.com/rust-lang/rust/issues/35121> for more information
+   = help: add `#![feature(never_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0425]: cannot find function, tuple struct or tuple variant `Layout` in this scope
+  --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:23
+   |
+LL |         dealloc(ptr2, Layout::(x: !)(1, 1));
+   |                       ^^^^^^ not found in this scope
 
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
 
+Some errors have detailed explanations: E0425, E0658.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs
index 1c28c0632fa..60dd88e6540 100644
--- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs
+++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs
@@ -2,7 +2,4 @@
 
 struct Apple((Apple, Option(Banana ? Citron)));
 //~^ ERROR invalid `?` in type
-//~| ERROR expected one of `)` or `,`, found `Citron`
-//~| ERROR cannot find type `Citron` in this scope [E0412]
-//~| ERROR parenthesized type parameters may only be used with a `Fn` trait [E0214]
-//~| ERROR `Apple` has infinite size
+//~| ERROR unexpected token: `Citron`
diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr
index 97a73b4fd5e..c92535c3906 100644
--- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr
+++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr
@@ -10,44 +10,11 @@ LL - struct Apple((Apple, Option(Banana ? Citron)));
 LL + struct Apple((Apple, Option(Option<Banana > Citron)));
    |
 
-error: expected one of `)` or `,`, found `Citron`
+error: unexpected token: `Citron`
   --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38
    |
 LL | struct Apple((Apple, Option(Banana ? Citron)));
-   |                                     -^^^^^^ expected one of `)` or `,`
-   |                                     |
-   |                                     help: missing `,`
+   |                                      ^^^^^^ unexpected token after this
 
-error[E0412]: cannot find type `Citron` in this scope
-  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38
-   |
-LL | struct Apple((Apple, Option(Banana ? Citron)));
-   |                                      ^^^^^^ not found in this scope
-
-error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:22
-   |
-LL | struct Apple((Apple, Option(Banana ? Citron)));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
-   |
-help: use angle brackets instead
-   |
-LL - struct Apple((Apple, Option(Banana ? Citron)));
-LL + struct Apple((Apple, Option<Banana ? Citron>));
-   |
-
-error[E0072]: recursive type `Apple` has infinite size
-  --> $DIR/issue-103748-ICE-wrong-braces.rs:3:1
-   |
-LL | struct Apple((Apple, Option(Banana ? Citron)));
-   | ^^^^^^^^^^^^  ----- recursive without indirection
-   |
-help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
-   |
-LL | struct Apple((Box<Apple>, Option(Banana ? Citron)));
-   |               ++++     +
-
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0072, E0214, E0412.
-For more information about an error, try `rustc --explain E0072`.
diff --git a/tests/ui/pub/pub-restricted-warning.rs b/tests/ui/pub/pub-restricted-warning.rs
new file mode 100644
index 00000000000..80384afbb00
--- /dev/null
+++ b/tests/ui/pub/pub-restricted-warning.rs
@@ -0,0 +1,25 @@
+//@ check-pass
+
+#![allow(dead_code)]
+
+mod outer {
+    pub mod inner {
+        pub(in crate::outer) struct Foo;
+        pub fn bar() -> Foo {
+            //~^ WARNING type `Foo` is more private than the item `outer::inner::bar` [private_interfaces]
+            Foo
+        }
+    }
+
+    pub mod nested {
+        pub mod inner {
+            pub(in crate::outer::nested) struct NestedFoo;
+            pub fn bar() -> NestedFoo {
+                //~^ WARNING type `NestedFoo` is more private than the item `nested::inner::bar` [private_interfaces]
+                NestedFoo
+            }
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/pub/pub-restricted-warning.stderr b/tests/ui/pub/pub-restricted-warning.stderr
new file mode 100644
index 00000000000..74f32d3de3c
--- /dev/null
+++ b/tests/ui/pub/pub-restricted-warning.stderr
@@ -0,0 +1,27 @@
+warning: type `Foo` is more private than the item `outer::inner::bar`
+  --> $DIR/pub-restricted-warning.rs:8:9
+   |
+LL |         pub fn bar() -> Foo {
+   |         ^^^^^^^^^^^^^^^^^^^ function `outer::inner::bar` is reachable at visibility `pub(crate)`
+   |
+note: but type `Foo` is only usable at visibility `pub(in crate::outer)`
+  --> $DIR/pub-restricted-warning.rs:7:9
+   |
+LL |         pub(in crate::outer) struct Foo;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(private_interfaces)]` on by default
+
+warning: type `NestedFoo` is more private than the item `nested::inner::bar`
+  --> $DIR/pub-restricted-warning.rs:17:13
+   |
+LL |             pub fn bar() -> NestedFoo {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ function `nested::inner::bar` is reachable at visibility `pub(crate)`
+   |
+note: but type `NestedFoo` is only usable at visibility `pub(in crate::outer::nested)`
+  --> $DIR/pub-restricted-warning.rs:16:13
+   |
+LL |             pub(in crate::outer::nested) struct NestedFoo;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+