diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 84d5ffb947914..813ceaeb8da9f 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, @@ -55,7 +55,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, @@ -66,7 +66,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, @@ -77,7 +77,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, term: &'mir mir::Terminator<'tcx>, loc: Location, @@ -92,7 +92,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, _state: &mut Self::Domain, _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, @@ -533,7 +533,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -542,7 +542,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, @@ -590,7 +590,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, @@ -599,7 +599,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a57689a45b67b..d4d38301a1586 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -49,7 +49,7 @@ use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex, }; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results}; +use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use smallvec::SmallVec; @@ -537,13 +537,11 @@ fn borrowck_check_region_constraints<'tcx>( mbcx.report_region_errors(nll_errors); } - let (mut flow_analysis, flow_entry_states) = - get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); + let flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); visit_results( body, traversal::reverse_postorder(body).map(|(bb, _)| bb), - &mut flow_analysis, - &flow_entry_states, + &flow_results, &mut mbcx, ); @@ -604,7 +602,7 @@ fn get_flow_results<'a, 'tcx>( move_data: &'a MoveData<'tcx>, borrow_set: &'a BorrowSet<'tcx>, regioncx: &RegionInferenceContext<'tcx>, -) -> (Borrowck<'a, 'tcx>, Results) { +) -> Results<'tcx, Borrowck<'a, 'tcx>> { // 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( @@ -629,14 +627,14 @@ fn get_flow_results<'a, 'tcx>( ever_inits: ever_inits.analysis, }; - 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) + 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<_> = + itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states) .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) .collect(); - (analysis, results) + Results { analysis, entry_states } } pub(crate) struct BorrowckInferCtxt<'tcx> { @@ -790,7 +788,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, - _analysis: &mut Borrowck<'a, 'tcx>, + _analysis: &Borrowck<'a, 'tcx>, state: &BorrowckDomain, stmt: &Statement<'tcx>, location: Location, @@ -865,7 +863,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_early_terminator_effect( &mut self, - _analysis: &mut Borrowck<'a, 'tcx>, + _analysis: &Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, @@ -985,7 +983,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_primary_terminator_effect( &mut self, - _analysis: &mut Borrowck<'a, 'tcx>, + _analysis: &Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 664dda8701a63..e6e3948305af7 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -332,7 +332,7 @@ where } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -341,7 +341,7 @@ where } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -351,7 +351,7 @@ where } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 40b21c45bc564..3f13a102684e0 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -32,7 +32,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_macros::{TypeFoldable, TypeVisitable}; @@ -63,6 +63,7 @@ pub(crate) struct CastCheck<'tcx> { cast_ty: Ty<'tcx>, cast_span: Span, span: Span, + pub body_id: LocalDefId, } /// The kind of pointer and associated metadata (thin, length or vtable) - we @@ -244,7 +245,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { span: Span, ) -> Result, ErrorGuaranteed> { let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span); - let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span }; + let check = + CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, body_id: fcx.body_id }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 5bd730a811fff..0cbdd86768a67 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,5 +1,5 @@ use std::ops::Deref; -use std::{fmt, iter, mem}; +use std::{fmt, iter}; use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; @@ -72,16 +72,13 @@ pub(crate) enum DivergingBlockBehavior { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&mut self) { - // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors - // when writing to `self.param_env`. - let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut()); - + let mut deferred_cast_checks = self.root_ctxt.deferred_cast_checks.borrow_mut(); debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len()); for cast in deferred_cast_checks.drain(..) { + let body_id = std::mem::replace(&mut self.body_id, cast.body_id); cast.check(self); + self.body_id = body_id; } - - *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks; } pub(in super::super) fn check_asms(&self) { diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 3f6e7a0661921..3c56999fcbdc9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -1,8 +1,7 @@ //! Random access inspection of the results of a dataflow analysis. -use std::borrow::Cow; use std::cmp::Ordering; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; #[cfg(debug_assertions)] use rustc_index::bit_set::DenseBitSet; @@ -10,30 +9,20 @@ use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Effect, EffectIndex, Results}; -/// 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), +/// This is like `Cow`, but it lacks the `T: ToOwned` bound and doesn't support +/// `to_owned`/`into_owned`. +enum SimpleCow<'a, T> { + Borrowed(&'a T), Owned(T), } -impl Deref for CowMut<'_, T> { +impl Deref for SimpleCow<'_, T> { type Target = T; fn deref(&self) -> &T { match self { - CowMut::BorrowedMut(borrowed) => borrowed, - CowMut::Owned(owned) => owned, - } - } -} - -impl DerefMut for CowMut<'_, T> { - fn deref_mut(&mut self) -> &mut T { - match self { - CowMut::BorrowedMut(borrowed) => borrowed, - CowMut::Owned(owned) => owned, + SimpleCow::Borrowed(borrowed) => borrowed, + SimpleCow::Owned(owned) => owned, } } } @@ -53,8 +42,7 @@ where A: Analysis<'tcx>, { body: &'mir mir::Body<'tcx>, - analysis: CowMut<'mir, A>, - results: Cow<'mir, Results>, + results: SimpleCow<'mir, Results<'tcx, A>>, state: A::Domain, pos: CursorPosition, @@ -82,15 +70,10 @@ where self.body } - fn new( - body: &'mir mir::Body<'tcx>, - analysis: CowMut<'mir, A>, - results: Cow<'mir, Results>, - ) -> Self { - let bottom_value = analysis.bottom_value(body); + fn new(body: &'mir mir::Body<'tcx>, results: SimpleCow<'mir, Results<'tcx, A>>) -> Self { + let bottom_value = results.analysis.bottom_value(body); ResultsCursor { body, - analysis, results, // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that @@ -106,21 +89,13 @@ 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, - ) -> Self { - Self::new(body, CowMut::Owned(analysis), Cow::Owned(results)) + pub fn new_owning(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self { + Self::new(body, SimpleCow::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, - ) -> Self { - Self::new(body, CowMut::BorrowedMut(analysis), Cow::Borrowed(results)) + pub fn new_borrowing(body: &'mir mir::Body<'tcx>, results: &'mir Results<'tcx, A>) -> Self { + Self::new(body, SimpleCow::Borrowed(results)) } /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled. @@ -132,7 +107,7 @@ where /// Returns the `Analysis` used to generate the underlying `Results`. pub fn analysis(&self) -> &A { - &self.analysis + &self.results.analysis } /// Resets the cursor to hold the entry set for the given basic block. @@ -144,7 +119,7 @@ where #[cfg(debug_assertions)] assert!(self.reachable_blocks.contains(block)); - self.state.clone_from(&self.results[block]); + self.state.clone_from(&self.results.entry_states[block]); self.pos = CursorPosition::block_entry(block); self.state_needs_reset = false; } @@ -236,7 +211,7 @@ where let target_effect_index = effect.at_index(target.statement_index); A::Direction::apply_effects_in_range( - &mut *self.analysis, + &self.results.analysis, &mut self.state, target.block, block_data, @@ -251,8 +226,8 @@ 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.analysis, &mut self.state); + pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) { + f(&self.results.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 79c0db7d72831..b15b5c07ce382 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -14,7 +14,7 @@ pub trait Direction { /// Called by `iterate_to_fixpoint` during initial analysis computation. fn apply_effects_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, body: &mir::Body<'tcx>, state: &mut A::Domain, block: BasicBlock, @@ -28,7 +28,7 @@ pub trait Direction { /// /// `effects.start()` must precede or equal `effects.end()` in this direction. fn apply_effects_in_range<'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, @@ -40,10 +40,10 @@ pub trait Direction { /// all locations in a basic block (starting from `entry_state` and to /// visit them with `vis`. fn visit_results_in_block<'mir, 'tcx, A>( + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>; @@ -56,7 +56,7 @@ impl Direction for Backward { const IS_FORWARD: bool = false; fn apply_effects_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, body: &mir::Body<'tcx>, state: &mut A::Domain, block: BasicBlock, @@ -129,7 +129,7 @@ impl Direction for Backward { } fn apply_effects_in_range<'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, @@ -206,10 +206,10 @@ impl Direction for Backward { } fn visit_results_in_block<'mir, 'tcx, A>( + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, @@ -242,7 +242,7 @@ impl Direction for Forward { const IS_FORWARD: bool = true; fn apply_effects_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, body: &mir::Body<'tcx>, state: &mut A::Domain, block: BasicBlock, @@ -312,7 +312,7 @@ impl Direction for Forward { } fn apply_effects_in_range<'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, @@ -386,10 +386,10 @@ impl Direction for Forward { } fn visit_results_in_block<'mir, 'tcx, A>( + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index b85b82b8f6d92..22bff3806b156 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -1,7 +1,6 @@ //! A helpful diagram for debugging dataflow problems. use std::borrow::Cow; -use std::cell::RefCell; use std::ffi::OsString; use std::path::PathBuf; use std::sync::OnceLock; @@ -33,8 +32,7 @@ use crate::errors::{ pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - analysis: &mut A, - results: &Results, + results: &Results<'tcx, A>, pass_name: Option<&'static str>, ) -> std::io::Result<()> where @@ -81,7 +79,7 @@ where let mut buf = Vec::new(); - let graphviz = Formatter::new(body, analysis, results, style); + let graphviz = Formatter::new(body, 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 { @@ -206,12 +204,7 @@ where A: Analysis<'tcx>, { body: &'mir Body<'tcx>, - // The `RefCell` is used because `::node_label` - // 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`. - analysis: RefCell<&'mir mut A>, - results: &'mir Results, + results: &'mir Results<'tcx, A>, style: OutputStyle, reachable: DenseBitSet, } @@ -220,14 +213,9 @@ impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - fn new( - body: &'mir Body<'tcx>, - analysis: &'mir mut A, - results: &'mir Results, - style: OutputStyle, - ) -> Self { + fn new(body: &'mir Body<'tcx>, results: &'mir Results<'tcx, A>, style: OutputStyle) -> Self { let reachable = traversal::reachable_as_bitset(body); - Formatter { body, analysis: analysis.into(), results, style, reachable } + Formatter { body, results, style, reachable } } } @@ -265,12 +253,10 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let analysis = &mut **self.analysis.borrow_mut(); - - let diffs = StateDiffCollector::run(self.body, *block, analysis, self.results, self.style); + let diffs = StateDiffCollector::run(self.body, *block, self.results, self.style); let mut fmt = BlockFormatter { - cursor: ResultsCursor::new_borrowing(self.body, analysis, self.results), + cursor: ResultsCursor::new_borrowing(self.body, self.results), style: self.style, bg: Background::Light, }; @@ -698,8 +684,7 @@ impl StateDiffCollector { fn run<'tcx, A>( body: &Body<'tcx>, block: BasicBlock, - analysis: &mut A, - results: &Results, + results: &Results<'tcx, A>, style: OutputStyle, ) -> Self where @@ -707,12 +692,12 @@ impl StateDiffCollector { D: DebugWithContext, { let mut collector = StateDiffCollector { - prev_state: analysis.bottom_value(body), + prev_state: results.analysis.bottom_value(body), after: vec![], before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), }; - visit_results(body, std::iter::once(block), analysis, results, &mut collector); + visit_results(body, std::iter::once(block), results, &mut collector); collector } } @@ -736,7 +721,7 @@ where fn visit_after_early_statement_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -749,7 +734,7 @@ where fn visit_after_primary_statement_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -760,7 +745,7 @@ where fn visit_after_early_terminator_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -773,7 +758,7 @@ where fn visit_after_primary_terminator_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index b6a5603601959..60b3c15d80d79 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -58,8 +58,7 @@ mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; -pub(crate) use self::results::AnalysisAndResults; -pub use self::results::Results; +pub use self::results::{EntryStates, Results}; pub use self::visitor::{ResultsVisitor, visit_reachable_results, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -136,7 +135,7 @@ pub trait Analysis<'tcx> { /// analyses should not implement this without also implementing /// `apply_primary_statement_effect`. fn apply_early_statement_effect( - &mut self, + &self, _state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -145,7 +144,7 @@ pub trait Analysis<'tcx> { /// Updates the current dataflow state with the effect of evaluating a statement. fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -159,7 +158,7 @@ pub trait Analysis<'tcx> { /// analyses should not implement this without also implementing /// `apply_primary_terminator_effect`. fn apply_early_terminator_effect( - &mut self, + &self, _state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -173,7 +172,7 @@ pub trait Analysis<'tcx> { /// `InitializedPlaces` analyses, the return place for a function call is not marked as /// initialized here. fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, _state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, _location: Location, @@ -189,7 +188,7 @@ pub trait Analysis<'tcx> { /// This is separate from `apply_primary_terminator_effect` to properly track state across /// unwind edges. fn apply_call_return_effect( - &mut self, + &self, _state: &mut Self::Domain, _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, @@ -211,7 +210,7 @@ pub trait Analysis<'tcx> { /// engine doesn't need to clone the exit state for a block unless /// `get_switch_int_data` is actually called. fn get_switch_int_data( - &mut self, + &self, _block: mir::BasicBlock, _discr: &mir::Operand<'tcx>, ) -> Option { @@ -220,7 +219,7 @@ pub trait Analysis<'tcx> { /// See comments on `get_switch_int_data`. fn apply_switch_int_edge_effect( - &mut self, + &self, _data: &mut Self::SwitchIntData, _state: &mut Self::Domain, _value: SwitchTargetValue, @@ -245,19 +244,21 @@ pub trait Analysis<'tcx> { /// Without a `pass_name` to differentiates them, only the results for the latest run will be /// saved. fn iterate_to_fixpoint<'mir>( - mut self, + self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, pass_name: Option<&'static str>, - ) -> AnalysisAndResults<'tcx, Self> + ) -> Results<'tcx, Self> where Self: Sized, Self::Domain: DebugWithContext, { - 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]); + 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]); - if Self::Direction::IS_BACKWARD && results[mir::START_BLOCK] != self.bottom_value(body) { + if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body) + { bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } @@ -281,17 +282,17 @@ pub trait Analysis<'tcx> { 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 = - // results[bb].clone()`, but it saves an allocation, thus improving compile times. - state.clone_from(&results[bb]); + // entry_states[bb].clone()`, but it saves an allocation, thus improving compile times. + state.clone_from(&entry_states[bb]); Self::Direction::apply_effects_in_block( - &mut self, + &self, body, &mut state, bb, &body[bb], |target: BasicBlock, state: &Self::Domain| { - let set_changed = results[target].join(state); + let set_changed = entry_states[target].join(state); if set_changed { dirty_queue.insert(target); } @@ -299,14 +300,16 @@ pub trait Analysis<'tcx> { ); } + let results = Results { analysis: self, entry_states }; + if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let res = write_graphviz_results(tcx, body, &mut self, &results, pass_name); + let res = write_graphviz_results(tcx, body, &results, pass_name); if let Err(e) = res { error!("Failed to write graphviz dataflow results: {}", e); } } - AnalysisAndResults { analysis: self, results } + results } } diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index 7b7e981d3a554..76b6cc47dde4a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -5,26 +5,26 @@ use rustc_middle::mir::{BasicBlock, Body}; use super::{Analysis, ResultsCursor}; -/// 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 = IndexVec; +pub type EntryStates = IndexVec; -/// Utility type used in a few places where it's convenient to bundle an analysis with its results. -pub struct AnalysisAndResults<'tcx, A> +/// The results of a dataflow analysis that has converged to fixpoint. It holds the domain values +/// (states) 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). The +/// analysis is also present because it's often needed alongside the entry states. +pub struct Results<'tcx, A> where A: Analysis<'tcx>, { pub analysis: A, - pub results: Results, + pub entry_states: EntryStates, } -impl<'tcx, A> AnalysisAndResults<'tcx, A> +impl<'tcx, A> Results<'tcx, A> where A: Analysis<'tcx>, { /// 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_owning(body, self.analysis, self.results) + ResultsCursor::new_owning(body, self) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 23e28a11a452b..85f23b8332a1c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -71,15 +71,15 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { /// /// | Location | Before | After | /// |------------------------|-------------------|--------| -/// | (on_entry) | {102} || +/// | (on_entry) | {102} | | /// | statement 0 | +0 | +1 | /// | statement 1 | +2 | +3 | /// | `Call` terminator | +4 | +5 | -/// | (on unwind) | {102,0,1,2,3,4,5} || +/// | (on unwind) | {102,0,1,2,3,4,5} | | /// /// 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_results`, not from actually running `MockAnalysis` to fixpoint. +/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint. struct MockAnalysis<'tcx, D> { body: &'tcx mir::Body<'tcx>, dir: PhantomData, @@ -96,7 +96,7 @@ impl MockAnalysis<'_, D> { ret } - fn mock_results(&self) -> IndexVec> { + fn mock_entry_states(&self) -> IndexVec> { let empty = self.bottom_value(self.body); let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); @@ -175,7 +175,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -185,7 +185,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -195,7 +195,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, @@ -205,7 +205,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -255,7 +255,7 @@ fn test_cursor(analysis: MockAnalysis<'_, D>) { let body = analysis.body; let mut cursor = - AnalysisAndResults { results: analysis.mock_results(), analysis }.into_results_cursor(body); + Results { entry_states: analysis.mock_entry_states(), 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 fbb9e4108726d..46940c6ab62fc 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -7,13 +7,12 @@ use super::{Analysis, Direction, Results}; pub fn visit_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - analysis: &mut A, - results: &Results, + results: &Results<'tcx, A>, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - let mut state = analysis.bottom_value(body); + let mut state = results.analysis.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -23,22 +22,21 @@ pub fn visit_results<'mir, 'tcx, A>( assert!(reachable_blocks.contains(block)); let block_data = &body[block]; - state.clone_from(&results[block]); - A::Direction::visit_results_in_block(&mut state, block, block_data, analysis, vis); + state.clone_from(&results.entry_states[block]); + A::Direction::visit_results_in_block(&results.analysis, &mut state, block, block_data, 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, + results: &Results<'tcx, A>, 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) + visit_results(body, blocks, results, vis) } /// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in @@ -53,7 +51,7 @@ where /// Called after the "early" effect of the given statement is applied to `state`. fn visit_after_early_statement_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -63,7 +61,7 @@ where /// Called after the "primary" effect of the given statement is applied to `state`. fn visit_after_primary_statement_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -73,7 +71,7 @@ where /// Called after the "early" effect of the given terminator is applied to `state`. fn visit_after_early_terminator_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -85,7 +83,7 @@ where /// The `call_return_effect` (if one exists) will *not* be applied to `state`. fn visit_after_primary_terminator_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index a4e4e30a8bb6c..331e41bd126b7 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -11,7 +11,6 @@ use crate::{Analysis, GenKill}; /// At present, this is used as a very limited form of alias analysis. For example, /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for /// immovable coroutines. -#[derive(Clone)] pub struct MaybeBorrowedLocals; impl MaybeBorrowedLocals { @@ -34,7 +33,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, @@ -43,7 +42,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 5937d68f389e4..9216106b6eddc 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -376,7 +376,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -400,7 +400,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -429,7 +429,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -448,7 +448,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn get_switch_int_data( - &mut self, + &self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, ) -> Option { @@ -460,7 +460,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_switch_int_edge_effect( - &mut self, + &self, data: &mut Self::SwitchIntData, state: &mut Self::Domain, value: SwitchTargetValue, @@ -513,7 +513,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -527,7 +527,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -545,7 +545,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -564,7 +564,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn get_switch_int_data( - &mut self, + &self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, ) -> Option { @@ -580,7 +580,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_switch_int_edge_effect( - &mut self, + &self, data: &mut Self::SwitchIntData, state: &mut Self::Domain, value: SwitchTargetValue, @@ -627,7 +627,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { #[instrument(skip(self, state), level = "debug")] fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, @@ -652,7 +652,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { #[instrument(skip(self, state, terminator), level = "debug")] fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -674,7 +674,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, block: mir::BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 596da18e3d1b4..e439f2e052fe8 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -41,7 +41,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -50,7 +50,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -60,7 +60,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -278,7 +278,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -294,7 +294,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -304,7 +304,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 026826fc379c7..3702f7c55a431 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::cell::RefCell; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; @@ -53,7 +54,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location, @@ -97,7 +98,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location, @@ -115,12 +116,12 @@ type BorrowedLocalsResults<'mir, 'tcx> = ResultsCursor<'mir, 'tcx, MaybeBorrowed /// Dataflow analysis that determines whether each local requires storage at a /// given location; i.e. whether its storage can go away without being observed. pub struct MaybeRequiresStorage<'mir, 'tcx> { - borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>, + borrowed_locals: RefCell>, } impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { pub fn new(borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>) -> Self { - MaybeRequiresStorage { borrowed_locals } + MaybeRequiresStorage { borrowed_locals: RefCell::new(borrowed_locals) } } } @@ -143,7 +144,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &Statement<'tcx>, loc: Location, @@ -176,7 +177,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _: &Statement<'tcx>, loc: Location, @@ -187,7 +188,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, loc: Location, @@ -242,7 +243,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_primary_terminator_effect<'t>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'t Terminator<'tcx>, loc: Location, @@ -283,7 +284,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -294,9 +295,10 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { impl<'tcx> MaybeRequiresStorage<'_, 'tcx> { /// Kill locals that are fully moved and have not been borrowed. - fn check_for_move(&mut self, state: &mut >::Domain, loc: Location) { - let body = self.borrowed_locals.body(); - let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals }; + fn check_for_move(&self, state: &mut >::Domain, loc: Location) { + let mut borrowed_locals = self.borrowed_locals.borrow_mut(); + let body = borrowed_locals.body(); + let mut visitor = MoveVisitor { state, borrowed_locals: &mut borrowed_locals }; visitor.visit_location(body, loc); } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 2e8c916544160..485925e7b50cd 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -17,8 +17,9 @@ 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, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, - ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results, visit_results, + Analysis, Backward, Direction, EntryStates, 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_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 54ed2a95174ee..072733c97efb1 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -721,27 +721,13 @@ fn locals_live_across_suspend_points<'tcx>( // 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, - ); + let borrowed_locals_cursor1 = ResultsCursor::new_borrowing(body, &borrowed_locals); + let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing(body, &borrowed_locals); // Calculate the MIR locals that we need to keep storage around for. - let mut requires_storage = + let 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, - ); + let mut requires_storage_cursor = ResultsCursor::new_borrowing(body, &requires_storage); // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = @@ -813,8 +799,7 @@ fn locals_live_across_suspend_points<'tcx>( body, &saved_locals, always_live_locals.clone(), - &mut requires_storage.analysis, - &requires_storage.results, + &requires_storage, ); LivenessInfo { @@ -879,8 +864,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( body: &'mir Body<'tcx>, saved_locals: &'mir CoroutineSavedLocals, always_live_locals: DenseBitSet, - analysis: &mut MaybeRequiresStorage<'mir, 'tcx>, - results: &Results>, + results: &Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), saved_locals.domain_size()); @@ -900,7 +884,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()), }; - visit_reachable_results(body, analysis, results, &mut visitor); + visit_reachable_results(body, results, &mut visitor); let local_conflicts = visitor.local_conflicts; @@ -943,7 +927,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> { fn visit_after_early_statement_effect( &mut self, - _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, + _analysis: &MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _statement: &Statement<'tcx>, loc: Location, @@ -953,7 +937,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> fn visit_after_early_terminator_effect( &mut self, - _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, + _analysis: &MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _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 8bcda77f4bc32..8532e1e9d7cc9 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -3,6 +3,7 @@ //! Currently, this pass only propagates scalar values. use std::assert_matches::assert_matches; +use std::cell::RefCell; use std::fmt::Formatter; use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; @@ -60,14 +61,12 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { let map = Map::new(tcx, body, place_limit); // Perform the actual dataflow analysis. - let mut const_ = debug_span!("analyze") + let 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(|| { - visit_reachable_results(body, &mut const_.analysis, &const_.results, &mut visitor) - }); + debug_span!("collect").in_scope(|| visit_reachable_results(body, &const_, &mut visitor)); let mut patch = visitor.patch; debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body)); } @@ -85,7 +84,7 @@ struct ConstAnalysis<'a, 'tcx> { map: Map<'tcx>, tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, - ecx: InterpCx<'tcx, DummyMachine>, + ecx: RefCell>, typing_env: ty::TypingEnv<'tcx>, } @@ -111,7 +110,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location, @@ -122,7 +121,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, _location: Location, @@ -135,7 +134,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -153,7 +152,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { map, tcx, local_decls: &body.local_decls, - ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), + ecx: RefCell::new(InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine)), typing_env, } } @@ -410,6 +409,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx + .borrow() .int_to_int_or_float(&op, layout) .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), @@ -424,6 +424,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx + .borrow() .float_to_float_or_int(&op, layout) .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), @@ -454,6 +455,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { match self.eval_operand(operand, state) { FlatSet::Elem(value) => self .ecx + .borrow() .unary_op(*op, &value) .discard_err() .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), @@ -468,6 +470,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { let val = match null_op { NullOp::OffsetOf(fields) => self .ecx + .borrow() .tcx .offset_of_subfield(self.typing_env, layout, fields.iter()) .bytes(), @@ -556,8 +559,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Some(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() + if let Some(constant) = self + .ecx + .borrow() + .eval_mir_constant(&constant.const_, constant.span, None) + .discard_err() { self.assign_constant(state, place, constant, &[]); } @@ -587,7 +593,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return; } } - operand = if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_err() { + operand = if let Some(operand) = + self.ecx.borrow().project(&operand, proj_elem).discard_err() + { operand } else { return; @@ -598,17 +606,22 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { place, operand, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(), - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), + TrackElem::Field(idx) => self.ecx.borrow().project_field(op, idx).discard_err(), + TrackElem::Variant(idx) => { + self.ecx.borrow().project_downcast(op, idx).discard_err() + } TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).discard_err()?; - let discr_value = - self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?; + let variant = self.ecx.borrow().read_discriminant(op).discard_err()?; + let discr_value = self + .ecx + .borrow() + .discriminant_for_variant(op.layout.ty, variant) + .discard_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into(); - let len_usize = op.len(&self.ecx).discard_err()?; + let op: OpTy<'_> = self.ecx.borrow().deref_pointer(op).discard_err()?.into(); + let len_usize = op.len(&self.ecx.borrow()).discard_err()?; let layout = self .tcx .layout_of(self.typing_env.as_query_input(self.tcx.types.usize)) @@ -617,7 +630,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } }, &mut |place, op| { - if let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() + if let Some(imm) = self.ecx.borrow().read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() { let elem = self.wrap_immediate(*imm); @@ -641,7 +654,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { - match self.ecx.binary_op(op, &left, &right).discard_err() { + match self.ecx.borrow().binary_op(op, &left, &right).discard_err() { // Ideally this would return an Immediate, since it's sometimes // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. @@ -714,8 +727,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return None; } let enum_ty_layout = self.tcx.layout_of(self.typing_env.as_query_input(enum_ty)).ok()?; - let discr_value = - self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?; + let discr_value = self + .ecx + .borrow() + .discriminant_for_variant(enum_ty_layout.ty, variant_index) + .discard_err()?; Some(discr_value.to_scalar()) } @@ -946,7 +962,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_early_statement_effect( &mut self, - analysis: &mut ConstAnalysis<'_, 'tcx>, + analysis: &ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -956,7 +972,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut analysis.ecx, + ecx: &mut analysis.ecx.borrow_mut(), map: &analysis.map, } .visit_rvalue(rvalue, location); @@ -968,7 +984,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_primary_statement_effect( &mut self, - analysis: &mut ConstAnalysis<'_, 'tcx>, + analysis: &ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -978,9 +994,12 @@ 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 analysis.ecx, place, state, &analysis.map) - { + if let Some(value) = self.try_make_constant( + &mut analysis.ecx.borrow_mut(), + place, + state, + &analysis.map, + ) { self.patch.assignments.insert(location, value); } } @@ -990,13 +1009,18 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> fn visit_after_early_terminator_effect( &mut self, - analysis: &mut ConstAnalysis<'_, 'tcx>, + analysis: &ConstAnalysis<'_, 'tcx>, state: &State>, terminator: &Terminator<'tcx>, location: Location, ) { - OperandCollector { state, visitor: self, ecx: &mut analysis.ecx, map: &analysis.map } - .visit_terminator(terminator, location); + OperandCollector { + state, + visitor: self, + ecx: &mut analysis.ecx.borrow_mut(), + 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 a10e0b82467cc..8c2149ef96fb0 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -146,7 +146,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals}; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::{Analysis, Results}; +use rustc_mir_dataflow::{Analysis, EntryStates}; use tracing::{debug, trace}; pub(super) struct DestinationPropagation; @@ -173,7 +173,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { let points = DenseLocationMap::new(body); let mut relevant = RelevantLocals::compute(&candidates, body.local_decls.len()); - let mut live = save_as_intervals(&points, body, &relevant, live.results); + let mut live = save_as_intervals(&points, body, &relevant, live.entry_states); dest_prop_mir_dump(tcx, body, &points, &live, &relevant); @@ -506,7 +506,7 @@ fn save_as_intervals<'tcx>( elements: &DenseLocationMap, body: &Body<'tcx>, relevant: &RelevantLocals, - results: Results>, + entry_states: EntryStates>, ) -> SparseIntervalMatrix { let mut values = SparseIntervalMatrix::new(2 * elements.num_points()); let mut state = MaybeLiveLocals.bottom_value(body); @@ -529,7 +529,7 @@ fn save_as_intervals<'tcx>( continue; } - state.clone_from(&results[block]); + state.clone_from(&entry_states[block]); let block_data = &body.basic_blocks[block]; let loc = Location { block, statement_index: block_data.statements.len() }; diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 82f9dfe4745d2..840bb169a1fa3 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -1160,7 +1160,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, trans: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, @@ -1169,7 +1169,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, trans: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, @@ -1179,7 +1179,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, _trans: &mut Self::Domain, _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/src/bootstrap/src/core/builder/cli_paths.rs b/src/bootstrap/src/core/builder/cli_paths.rs new file mode 100644 index 0000000000000..aa81c4684eab3 --- /dev/null +++ b/src/bootstrap/src/core/builder/cli_paths.rs @@ -0,0 +1,245 @@ +//! Various pieces of code for dealing with "paths" passed to bootstrap on the +//! command-line, extracted from `core/builder/mod.rs` because that file is +//! large and hard to navigate. + +use std::fmt::{self, Debug}; +use std::path::PathBuf; + +use crate::core::builder::{Builder, Kind, PathSet, ShouldRun, StepDescription}; + +pub(crate) const PATH_REMAP: &[(&str, &[&str])] = &[ + // bootstrap.toml uses `rust-analyzer-proc-macro-srv`, but the + // actual path is `proc-macro-srv-cli` + ("rust-analyzer-proc-macro-srv", &["src/tools/rust-analyzer/crates/proc-macro-srv-cli"]), + // Make `x test tests` function the same as `x t tests/*` + ( + "tests", + &[ + // tidy-alphabetical-start + "tests/assembly-llvm", + "tests/codegen-llvm", + "tests/codegen-units", + "tests/coverage", + "tests/coverage-run-rustdoc", + "tests/crashes", + "tests/debuginfo", + "tests/incremental", + "tests/mir-opt", + "tests/pretty", + "tests/run-make", + "tests/run-make-cargo", + "tests/rustdoc", + "tests/rustdoc-gui", + "tests/rustdoc-js", + "tests/rustdoc-js-std", + "tests/rustdoc-json", + "tests/rustdoc-ui", + "tests/ui", + "tests/ui-fulldeps", + // tidy-alphabetical-end + ], + ), +]; + +pub(crate) fn remap_paths(paths: &mut Vec) { + let mut remove = vec![]; + let mut add = vec![]; + for (i, path) in paths.iter().enumerate().filter_map(|(i, path)| path.to_str().map(|s| (i, s))) + { + for &(search, replace) in PATH_REMAP { + // Remove leading and trailing slashes so `tests/` and `tests` are equivalent + if path.trim_matches(std::path::is_separator) == search { + remove.push(i); + add.extend(replace.iter().map(PathBuf::from)); + break; + } + } + } + remove.sort(); + remove.dedup(); + for idx in remove.into_iter().rev() { + paths.remove(idx); + } + paths.append(&mut add); +} + +#[derive(Clone, PartialEq)] +pub(crate) struct CLIStepPath { + pub(crate) path: PathBuf, + pub(crate) will_be_executed: bool, +} + +#[cfg(test)] +impl CLIStepPath { + pub(crate) fn will_be_executed(mut self, will_be_executed: bool) -> Self { + self.will_be_executed = will_be_executed; + self + } +} + +impl Debug for CLIStepPath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.path.display()) + } +} + +impl From for CLIStepPath { + fn from(path: PathBuf) -> Self { + Self { path, will_be_executed: false } + } +} + +/// Combines a `StepDescription` with its corresponding `ShouldRun`. +struct StepExtra<'a> { + desc: &'a StepDescription, + should_run: ShouldRun<'a>, +} + +struct StepToRun<'a> { + sort_index: usize, + desc: &'a StepDescription, + pathsets: Vec, +} + +pub(crate) fn match_paths_to_steps_and_run( + builder: &Builder<'_>, + step_descs: &[StepDescription], + paths: &[PathBuf], +) { + // Obtain `ShouldRun` information for each step, so that we know which + // paths to match it against. + let steps = step_descs + .iter() + .map(|desc| StepExtra { + desc, + should_run: (desc.should_run)(ShouldRun::new(builder, desc.kind)), + }) + .collect::>(); + + // FIXME(Zalathar): This particular check isn't related to path-to-step + // matching, and should probably be hoisted to somewhere much earlier. + if builder.download_rustc() && (builder.kind == Kind::Dist || builder.kind == Kind::Install) { + eprintln!( + "ERROR: '{}' subcommand is incompatible with `rust.download-rustc`.", + builder.kind.as_str() + ); + crate::exit!(1); + } + + // sanity checks on rules + for StepExtra { desc, should_run } in &steps { + assert!(!should_run.paths.is_empty(), "{:?} should have at least one pathset", desc.name); + } + + if paths.is_empty() || builder.config.include_default_paths { + for StepExtra { desc, should_run } in &steps { + if desc.default && should_run.is_really_default() { + desc.maybe_run(builder, should_run.paths.iter().cloned().collect()); + } + } + } + + // Attempt to resolve paths to be relative to the builder source directory. + let mut paths: Vec = paths + .iter() + .map(|original_path| { + let mut path = original_path.clone(); + + // Someone could run `x ` from a different repository than the source + // directory. + // In that case, we should not try to resolve the paths relative to the working + // directory, but rather relative to the source directory. + // So we forcefully "relocate" the path to the source directory here. + if !path.is_absolute() { + path = builder.src.join(path); + } + + // If the path does not exist, it may represent the name of a Step, such as `tidy` in `x test tidy` + if !path.exists() { + // Use the original path here + return original_path.clone(); + } + + // Make the path absolute, strip the prefix, and convert to a PathBuf. + match std::path::absolute(&path) { + Ok(p) => p.strip_prefix(&builder.src).unwrap_or(&p).to_path_buf(), + Err(e) => { + eprintln!("ERROR: {e:?}"); + panic!("Due to the above error, failed to resolve path: {path:?}"); + } + } + }) + .collect(); + + remap_paths(&mut paths); + + // Handle all test suite paths. + // (This is separate from the loop below to avoid having to handle multiple paths in `is_suite_path` somehow.) + paths.retain(|path| { + for StepExtra { desc, should_run } in &steps { + if let Some(suite) = should_run.is_suite_path(path) { + desc.maybe_run(builder, vec![suite.clone()]); + return false; + } + } + true + }); + + if paths.is_empty() { + return; + } + + let mut paths: Vec = paths.into_iter().map(|p| p.into()).collect(); + let mut path_lookup: Vec<(CLIStepPath, bool)> = + paths.clone().into_iter().map(|p| (p, false)).collect(); + + // Before actually running (non-suite) steps, collect them into a list of structs + // so that we can then sort the list to preserve CLI order as much as possible. + let mut steps_to_run = vec![]; + + for StepExtra { desc, should_run } in &steps { + let pathsets = should_run.pathset_for_paths_removing_matches(&mut paths, desc.kind); + + // This value is used for sorting the step execution order. + // By default, `usize::MAX` is used as the index for steps to assign them the lowest priority. + // + // If we resolve the step's path from the given CLI input, this value will be updated with + // the step's actual index. + let mut closest_index = usize::MAX; + + // Find the closest index from the original list of paths given by the CLI input. + for (index, (path, is_used)) in path_lookup.iter_mut().enumerate() { + if !*is_used && !paths.contains(path) { + closest_index = index; + *is_used = true; + break; + } + } + + steps_to_run.push(StepToRun { sort_index: closest_index, desc, pathsets }); + } + + // Sort the steps before running them to respect the CLI order. + steps_to_run.sort_by_key(|step| step.sort_index); + + // Handle all PathSets. + for StepToRun { sort_index: _, desc, pathsets } in steps_to_run { + if !pathsets.is_empty() { + desc.maybe_run(builder, pathsets); + } + } + + paths.retain(|p| !p.will_be_executed); + + if !paths.is_empty() { + eprintln!("ERROR: no `{}` rules matched {:?}", builder.kind.as_str(), paths); + eprintln!( + "HELP: run `x.py {} --help --verbose` to show a list of available paths", + builder.kind.as_str() + ); + eprintln!( + "NOTE: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`" + ); + crate::exit!(1); + } +} diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index b5d0f11236143..c7490c7072bda 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1,7 +1,7 @@ use std::any::{Any, type_name}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; -use std::fmt::{self, Debug, Write}; +use std::fmt::{Debug, Write}; use std::hash::Hash; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -20,6 +20,7 @@ use crate::core::build_steps::tool::RustcPrivateCompilers; use crate::core::build_steps::{ check, clean, clippy, compile, dist, doc, gcc, install, llvm, run, setup, test, tool, vendor, }; +use crate::core::builder::cli_paths::CLIStepPath; use crate::core::config::flags::Subcommand; use crate::core::config::{DryRun, TargetSelection}; use crate::utils::build_stamp::BuildStamp; @@ -29,7 +30,7 @@ use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linke use crate::{Build, Crate, trace}; mod cargo; - +mod cli_paths; #[cfg(test)] mod tests; @@ -424,88 +425,6 @@ impl PathSet { } } -const PATH_REMAP: &[(&str, &[&str])] = &[ - // bootstrap.toml uses `rust-analyzer-proc-macro-srv`, but the - // actual path is `proc-macro-srv-cli` - ("rust-analyzer-proc-macro-srv", &["src/tools/rust-analyzer/crates/proc-macro-srv-cli"]), - // Make `x test tests` function the same as `x t tests/*` - ( - "tests", - &[ - // tidy-alphabetical-start - "tests/assembly-llvm", - "tests/codegen-llvm", - "tests/codegen-units", - "tests/coverage", - "tests/coverage-run-rustdoc", - "tests/crashes", - "tests/debuginfo", - "tests/incremental", - "tests/mir-opt", - "tests/pretty", - "tests/run-make", - "tests/run-make-cargo", - "tests/rustdoc", - "tests/rustdoc-gui", - "tests/rustdoc-js", - "tests/rustdoc-js-std", - "tests/rustdoc-json", - "tests/rustdoc-ui", - "tests/ui", - "tests/ui-fulldeps", - // tidy-alphabetical-end - ], - ), -]; - -fn remap_paths(paths: &mut Vec) { - let mut remove = vec![]; - let mut add = vec![]; - for (i, path) in paths.iter().enumerate().filter_map(|(i, path)| path.to_str().map(|s| (i, s))) - { - for &(search, replace) in PATH_REMAP { - // Remove leading and trailing slashes so `tests/` and `tests` are equivalent - if path.trim_matches(std::path::is_separator) == search { - remove.push(i); - add.extend(replace.iter().map(PathBuf::from)); - break; - } - } - } - remove.sort(); - remove.dedup(); - for idx in remove.into_iter().rev() { - paths.remove(idx); - } - paths.append(&mut add); -} - -#[derive(Clone, PartialEq)] -struct CLIStepPath { - path: PathBuf, - will_be_executed: bool, -} - -#[cfg(test)] -impl CLIStepPath { - fn will_be_executed(mut self, will_be_executed: bool) -> Self { - self.will_be_executed = will_be_executed; - self - } -} - -impl Debug for CLIStepPath { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.path.display()) - } -} - -impl From for CLIStepPath { - fn from(path: PathBuf) -> Self { - Self { path, will_be_executed: false } - } -} - impl StepDescription { fn from(kind: Kind) -> StepDescription { StepDescription { @@ -554,144 +473,6 @@ impl StepDescription { } false } - - fn run(v: &[StepDescription], builder: &Builder<'_>, paths: &[PathBuf]) { - let should_runs = v - .iter() - .map(|desc| (desc.should_run)(ShouldRun::new(builder, desc.kind))) - .collect::>(); - - if builder.download_rustc() && (builder.kind == Kind::Dist || builder.kind == Kind::Install) - { - eprintln!( - "ERROR: '{}' subcommand is incompatible with `rust.download-rustc`.", - builder.kind.as_str() - ); - crate::exit!(1); - } - - // sanity checks on rules - for (desc, should_run) in v.iter().zip(&should_runs) { - assert!( - !should_run.paths.is_empty(), - "{:?} should have at least one pathset", - desc.name - ); - } - - if paths.is_empty() || builder.config.include_default_paths { - for (desc, should_run) in v.iter().zip(&should_runs) { - if desc.default && should_run.is_really_default() { - desc.maybe_run(builder, should_run.paths.iter().cloned().collect()); - } - } - } - - // Attempt to resolve paths to be relative to the builder source directory. - let mut paths: Vec = paths - .iter() - .map(|original_path| { - let mut path = original_path.clone(); - - // Someone could run `x ` from a different repository than the source - // directory. - // In that case, we should not try to resolve the paths relative to the working - // directory, but rather relative to the source directory. - // So we forcefully "relocate" the path to the source directory here. - if !path.is_absolute() { - path = builder.src.join(path); - } - - // If the path does not exist, it may represent the name of a Step, such as `tidy` in `x test tidy` - if !path.exists() { - // Use the original path here - return original_path.clone(); - } - - // Make the path absolute, strip the prefix, and convert to a PathBuf. - match std::path::absolute(&path) { - Ok(p) => p.strip_prefix(&builder.src).unwrap_or(&p).to_path_buf(), - Err(e) => { - eprintln!("ERROR: {e:?}"); - panic!("Due to the above error, failed to resolve path: {path:?}"); - } - } - }) - .collect(); - - remap_paths(&mut paths); - - // Handle all test suite paths. - // (This is separate from the loop below to avoid having to handle multiple paths in `is_suite_path` somehow.) - paths.retain(|path| { - for (desc, should_run) in v.iter().zip(&should_runs) { - if let Some(suite) = should_run.is_suite_path(path) { - desc.maybe_run(builder, vec![suite.clone()]); - return false; - } - } - true - }); - - if paths.is_empty() { - return; - } - - let mut paths: Vec = paths.into_iter().map(|p| p.into()).collect(); - let mut path_lookup: Vec<(CLIStepPath, bool)> = - paths.clone().into_iter().map(|p| (p, false)).collect(); - - // List of `(usize, &StepDescription, Vec)` where `usize` is the closest index of a path - // compared to the given CLI paths. So we can respect to the CLI order by using this value to sort - // the steps. - let mut steps_to_run = vec![]; - - for (desc, should_run) in v.iter().zip(&should_runs) { - let pathsets = should_run.pathset_for_paths_removing_matches(&mut paths, desc.kind); - - // This value is used for sorting the step execution order. - // By default, `usize::MAX` is used as the index for steps to assign them the lowest priority. - // - // If we resolve the step's path from the given CLI input, this value will be updated with - // the step's actual index. - let mut closest_index = usize::MAX; - - // Find the closest index from the original list of paths given by the CLI input. - for (index, (path, is_used)) in path_lookup.iter_mut().enumerate() { - if !*is_used && !paths.contains(path) { - closest_index = index; - *is_used = true; - break; - } - } - - steps_to_run.push((closest_index, desc, pathsets)); - } - - // Sort the steps before running them to respect the CLI order. - steps_to_run.sort_by_key(|(index, _, _)| *index); - - // Handle all PathSets. - for (_index, desc, pathsets) in steps_to_run { - if !pathsets.is_empty() { - desc.maybe_run(builder, pathsets); - } - } - - paths.retain(|p| !p.will_be_executed); - - if !paths.is_empty() { - eprintln!("ERROR: no `{}` rules matched {:?}", builder.kind.as_str(), paths); - eprintln!( - "HELP: run `x.py {} --help --verbose` to show a list of available paths", - builder.kind.as_str() - ); - eprintln!( - "NOTE: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`" - ); - crate::exit!(1); - } - } } enum ReallyDefault<'a> { @@ -1349,7 +1130,7 @@ impl<'a> Builder<'a> { } fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) { - StepDescription::run(v, self, paths); + cli_paths::match_paths_to_steps_and_run(self, v, paths); } /// Returns if `std` should be statically linked into `rustc_driver`. diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index e0eb38d04aad0..b8ba1b4c2c340 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -7,6 +7,7 @@ use llvm::prebuilt_llvm_config; use super::*; use crate::Flags; use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::builder::cli_paths::PATH_REMAP; use crate::core::config::Config; use crate::utils::cache::ExecutedStep; use crate::utils::helpers::get_host_target; diff --git a/tests/ui/traits/const-traits/issue-103677.rs b/tests/ui/traits/const-traits/issue-103677.rs index c032cc7a68803..8117e393753fd 100644 --- a/tests/ui/traits/const-traits/issue-103677.rs +++ b/tests/ui/traits/const-traits/issue-103677.rs @@ -1,5 +1,9 @@ //@ check-pass +//@ revisions: stock cnst +#![cfg_attr(cnst, feature(const_trait_impl))] -const _: fn(&String) = |s| { &*s as &str; }; +const _: fn(&String) = |s| { + &*s as &str; +}; fn main() {}