diff options
Diffstat (limited to 'compiler')
112 files changed, 1200 insertions, 1433 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 260c9fe44ba..cecf223b961 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -614,34 +614,34 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized { #[allow(clippy::mut_from_ref)] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; + fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self; #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, + fn allocate_from_iter( + arena: &'tcx Arena<'tcx>, iter: impl ::std::iter::IntoIterator<Item = Self>, - ) -> &'a mut [Self]; + ) -> &'tcx mut [Self]; } // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`. impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T { #[inline] #[allow(clippy::mut_from_ref)] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { + fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self { arena.dropless.alloc(self) } #[inline] #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, + fn allocate_from_iter( + arena: &'tcx Arena<'tcx>, iter: impl ::std::iter::IntoIterator<Item = Self>, - ) -> &'a mut [Self] { + ) -> &'tcx mut [Self] { arena.dropless.alloc_from_iter(iter) } } $( impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty { #[inline] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { + fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self { if !::std::mem::needs_drop::<Self>() { arena.dropless.alloc(self) } else { @@ -651,10 +651,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[inline] #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, + fn allocate_from_iter( + arena: &'tcx Arena<'tcx>, iter: impl ::std::iter::IntoIterator<Item = Self>, - ) -> &'a mut [Self] { + ) -> &'tcx mut [Self] { if !::std::mem::needs_drop::<Self>() { arena.dropless.alloc_from_iter(iter) } else { @@ -667,7 +667,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { impl<'tcx> Arena<'tcx> { #[inline] #[allow(clippy::mut_from_ref)] - pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&self, value: T) -> &mut T { + pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&'tcx self, value: T) -> &mut T { value.allocate_on(self) } @@ -691,7 +691,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[allow(clippy::mut_from_ref)] pub fn alloc_from_iter<T: ArenaAllocatable<'tcx, C>, C>( - &self, + &'tcx self, iter: impl ::std::iter::IntoIterator<Item = T>, ) -> &mut [T] { T::allocate_from_iter(self, iter) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 45e397a58c0..cfc534acd98 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -75,22 +75,9 @@ struct PostExpansionVisitor<'a> { impl<'a> PostExpansionVisitor<'a> { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) { + fn check_abi(&self, abi: ast::StrLit) { let ast::StrLit { symbol_unescaped, span, .. } = abi; - if let ast::Const::Yes(_) = constness { - match symbol_unescaped { - // Stable - sym::Rust | sym::C => {} - abi => gate!( - &self, - const_extern_fn, - span, - format!("`{}` as a `const fn` ABI is unstable", abi) - ), - } - } - match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) { Ok(()) => (), Err(abi::AbiDisabled::Unstable { feature, explain }) => { @@ -110,9 +97,9 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn check_extern(&self, ext: ast::Extern, constness: ast::Const) { + fn check_extern(&self, ext: ast::Extern) { if let ast::Extern::Explicit(abi, _) = ext { - self.check_abi(abi, constness); + self.check_abi(abi); } } @@ -239,7 +226,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match &i.kind { ast::ItemKind::ForeignMod(foreign_module) => { if let Some(abi) = foreign_module.abi { - self.check_abi(abi, ast::Const::No); + self.check_abi(abi); } } @@ -341,7 +328,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match &ty.kind { ast::TyKind::BareFn(bare_fn_ty) => { // Function pointers cannot be `const` - self.check_extern(bare_fn_ty.ext, ast::Const::No); + self.check_extern(bare_fn_ty.ext); self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); } ast::TyKind::Never => { @@ -446,7 +433,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let Some(header) = fn_kind.header() { // Stability of const fn methods are covered in `visit_assoc_item` below. - self.check_extern(header.ext, header.constness); + self.check_extern(header.ext); } if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind { diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 0ae837898b9..9d500586f08 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -97,11 +97,11 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> { /// Given the constraint set from which this graph was built /// creates a region graph so that you can iterate over *regions* /// and not constraints. - pub(crate) fn region_graph<'rg, 'tcx>( - &'rg self, - set: &'rg OutlivesConstraintSet<'tcx>, + pub(crate) fn region_graph<'a, 'tcx>( + &'a self, + set: &'a OutlivesConstraintSet<'tcx>, static_region: RegionVid, - ) -> RegionGraph<'rg, 'tcx, D> { + ) -> RegionGraph<'a, 'tcx, D> { RegionGraph::new(set, self, static_region) } @@ -130,15 +130,15 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> { } } -pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirection> { - graph: &'s ConstraintGraph<D>, - constraints: &'s OutlivesConstraintSet<'tcx>, +pub(crate) struct Edges<'a, 'tcx, D: ConstraintGraphDirection> { + graph: &'a ConstraintGraph<D>, + constraints: &'a OutlivesConstraintSet<'tcx>, pointer: Option<OutlivesConstraintIndex>, next_static_idx: Option<usize>, static_region: RegionVid, } -impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> { type Item = OutlivesConstraint<'tcx>; fn next(&mut self) -> Option<Self::Item> { @@ -171,20 +171,20 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> { /// This struct brings together a constraint set and a (normal, not /// reverse) constraint graph. It implements the graph traits and is /// usd for doing the SCC computation. -pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirection> { - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph<D>, +pub(crate) struct RegionGraph<'a, 'tcx, D: ConstraintGraphDirection> { + set: &'a OutlivesConstraintSet<'tcx>, + constraint_graph: &'a ConstraintGraph<D>, static_region: RegionVid, } -impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> RegionGraph<'a, 'tcx, D> { /// Creates a "dependency graph" where each region constraint `R1: /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error /// reporting. pub(crate) fn new( - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph<D>, + set: &'a OutlivesConstraintSet<'tcx>, + constraint_graph: &'a ConstraintGraph<D>, static_region: RegionVid, ) -> Self { Self { set, constraint_graph, static_region } @@ -192,18 +192,18 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> { /// Given a region `R`, iterate over all regions `R1` such that /// there exists a constraint `R: R1`. - pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> { + pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'a, 'tcx, D> { Successors { edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), } } } -pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirection> { - edges: Edges<'s, 'tcx, D>, +pub(crate) struct Successors<'a, 'tcx, D: ConstraintGraphDirection> { + edges: Edges<'a, 'tcx, D>, } -impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'a, 'tcx, D> { type Item = RegionVid; fn next(&mut self) -> Option<Self::Item> { @@ -211,7 +211,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> } } -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'a, 'tcx, D> { type Node = RegionVid; fn num_nodes(&self) -> usize { @@ -219,7 +219,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph } } -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> { +impl<'a, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'a, 'tcx, D> { fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { self.outgoing_regions(node) } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 39994ad784a..5e1043ec817 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; -use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, Results, ResultsVisitable}; +use rustc_mir_dataflow::{Analysis, AnalysisDomain, Forward, GenKill, Results, ResultsVisitable}; use tracing::debug; use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext}; @@ -23,26 +23,25 @@ pub(crate) struct BorrowckResults<'a, 'tcx> { /// The transient state of the dataflow analyses used by the borrow checker. #[derive(Debug)] -pub(crate) struct BorrowckFlowState<'a, 'tcx> { +pub(crate) struct BorrowckDomain<'a, 'tcx> { pub(crate) borrows: <Borrows<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain, pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain, pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain, } impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { - // All three analyses are forward, but we have to use just one here. - type Direction = <Borrows<'a, 'tcx> as AnalysisDomain<'tcx>>::Direction; - type FlowState = BorrowckFlowState<'a, 'tcx>; + type Direction = Forward; + type Domain = BorrowckDomain<'a, 'tcx>; - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - BorrowckFlowState { + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + BorrowckDomain { borrows: self.borrows.analysis.bottom_value(body), uninits: self.uninits.analysis.bottom_value(body), ever_inits: self.ever_inits.analysis.bottom_value(body), } } - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { state.borrows.clone_from(self.borrows.entry_set_for_block(block)); state.uninits.clone_from(self.uninits.entry_set_for_block(block)); state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block)); @@ -50,7 +49,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -61,7 +60,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -72,7 +71,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -83,7 +82,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -113,16 +112,16 @@ pub struct Borrows<'a, 'tcx> { borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>, } -struct OutOfScopePrecomputer<'mir, 'tcx> { +struct OutOfScopePrecomputer<'a, 'tcx> { visited: BitSet<mir::BasicBlock>, visit_stack: Vec<mir::BasicBlock>, - body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, + body: &'a Body<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>, } -impl<'mir, 'tcx> OutOfScopePrecomputer<'mir, 'tcx> { - fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self { +impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { OutOfScopePrecomputer { visited: BitSet::new_empty(body.basic_blocks.len()), visit_stack: vec![], @@ -225,17 +224,17 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>( prec.borrows_out_of_scope_at_location } -struct PoloniusOutOfScopePrecomputer<'mir, 'tcx> { +struct PoloniusOutOfScopePrecomputer<'a, 'tcx> { visited: BitSet<mir::BasicBlock>, visit_stack: Vec<mir::BasicBlock>, - body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, + body: &'a Body<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, loans_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>, } -impl<'mir, 'tcx> PoloniusOutOfScopePrecomputer<'mir, 'tcx> { - fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self { +impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { Self { visited: BitSet::new_empty(body.basic_blocks.len()), visit_stack: vec![], diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 4a31aee5c96..c7a5d516ad7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3553,7 +3553,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { location: Location, mpi: MovePathIndex, ) -> (Vec<MoveSite>, Vec<Location>) { - fn predecessor_locations<'tcx, 'a>( + fn predecessor_locations<'a, 'tcx>( body: &'a mir::Body<'tcx>, location: Location, ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a { diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index bea8d3bfdfb..d8fa5506a99 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -21,15 +21,15 @@ pub(crate) fn find<'tcx>( uf.find() } -struct UseFinder<'cx, 'tcx> { - body: &'cx Body<'tcx>, - regioncx: &'cx Rc<RegionInferenceContext<'tcx>>, +struct UseFinder<'a, 'tcx> { + body: &'a Body<'tcx>, + regioncx: &'a Rc<RegionInferenceContext<'tcx>>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, } -impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { +impl<'a, 'tcx> UseFinder<'a, 'tcx> { fn find(&mut self) -> Option<Cause> { let mut queue = VecDeque::new(); let mut visited = FxIndexSet::default(); @@ -93,8 +93,8 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { } } -struct DefUseVisitor<'cx, 'tcx> { - body: &'cx Body<'tcx>, +struct DefUseVisitor<'a, 'tcx> { + body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, def_use_result: Option<DefUseResult>, @@ -106,7 +106,7 @@ enum DefUseResult { UseDrop { local: Local }, } -impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for DefUseVisitor<'a, 'tcx> { fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { let local_ty = self.body.local_decls[local].ty; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 6e3fac1e680..2bbafb0163e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -558,7 +558,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ty: Ty<'tcx>, suggested: bool, } - impl<'a, 'cx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'cx, 'tcx> { + impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { hir::intravisit::walk_stmt(self, stmt); let expr = match stmt.kind { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d98c66b0f3b..58e73030749 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -83,7 +83,7 @@ mod util; pub mod consumers; use borrow_set::{BorrowData, BorrowSet}; -use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows}; +use dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows}; use nll::PoloniusOutput; use place_ext::PlaceExt; use places_conflict::{places_conflict, PlaceConflictBias}; @@ -602,25 +602,25 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> for MirBorrowckCtxt<'a, '_, 'tcx> { - type FlowState = Flows<'a, 'tcx>; + type Domain = BorrowckDomain<'a, 'tcx>; fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, stmt: &'a Statement<'tcx>, location: Location, ) { - debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, flow_state); + debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state); let span = stmt.source_info.span; - self.check_activations(location, span, flow_state); + self.check_activations(location, span, state); match &stmt.kind { StatementKind::Assign(box (lhs, rhs)) => { - self.consume_rvalue(location, (rhs, span), flow_state); + self.consume_rvalue(location, (rhs, span), state); - self.mutate_place(location, (*lhs, span), Shallow(None), flow_state); + self.mutate_place(location, (*lhs, span), Shallow(None), state); } StatementKind::FakeRead(box (_, place)) => { // Read for match doesn't access any memory and is used to @@ -637,11 +637,11 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } StatementKind::Intrinsic(box kind) => match kind { - NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state), + NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), state), NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( span, "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", @@ -662,7 +662,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> (Place::from(*local), span), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); } StatementKind::Nop @@ -677,18 +677,18 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, term: &'a Terminator<'tcx>, loc: Location, ) { - debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, flow_state); + debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state); let span = term.source_info.span; - self.check_activations(loc, span, flow_state); + self.check_activations(loc, span, state); match &term.kind { TerminatorKind::SwitchInt { discr, targets: _ } => { - self.consume_operand(loc, (discr, span), flow_state); + self.consume_operand(loc, (discr, span), state); } TerminatorKind::Drop { place, target: _, unwind: _, replace } => { debug!( @@ -704,7 +704,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> (*place, span), (AccessDepth::Drop, Write(write_kind)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); } TerminatorKind::Call { @@ -716,29 +716,29 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> call_source: _, fn_span: _, } => { - self.consume_operand(loc, (func, span), flow_state); + self.consume_operand(loc, (func, span), state); for arg in args { - self.consume_operand(loc, (&arg.node, arg.span), flow_state); + self.consume_operand(loc, (&arg.node, arg.span), state); } - self.mutate_place(loc, (*destination, span), Deep, flow_state); + self.mutate_place(loc, (*destination, span), Deep, state); } TerminatorKind::TailCall { func, args, fn_span: _ } => { - self.consume_operand(loc, (func, span), flow_state); + self.consume_operand(loc, (func, span), state); for arg in args { - self.consume_operand(loc, (&arg.node, arg.span), flow_state); + self.consume_operand(loc, (&arg.node, arg.span), state); } } TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.consume_operand(loc, (cond, span), flow_state); + self.consume_operand(loc, (cond, span), state); if let AssertKind::BoundsCheck { len, index } = &**msg { - self.consume_operand(loc, (len, span), flow_state); - self.consume_operand(loc, (index, span), flow_state); + self.consume_operand(loc, (len, span), state); + self.consume_operand(loc, (index, span), state); } } TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { - self.consume_operand(loc, (value, span), flow_state); - self.mutate_place(loc, (*resume_arg, span), Deep, flow_state); + self.consume_operand(loc, (value, span), state); + self.mutate_place(loc, (*resume_arg, span), Deep, state); } TerminatorKind::InlineAsm { @@ -752,22 +752,17 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> for op in operands { match op { InlineAsmOperand::In { reg: _, value } => { - self.consume_operand(loc, (value, span), flow_state); + self.consume_operand(loc, (value, span), state); } InlineAsmOperand::Out { reg: _, late: _, place, .. } => { if let Some(place) = place { - self.mutate_place(loc, (*place, span), Shallow(None), flow_state); + self.mutate_place(loc, (*place, span), Shallow(None), state); } } InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => { - self.consume_operand(loc, (in_value, span), flow_state); + self.consume_operand(loc, (in_value, span), state); if let &Some(out_place) = out_place { - self.mutate_place( - loc, - (out_place, span), - Shallow(None), - flow_state, - ); + self.mutate_place(loc, (out_place, span), Shallow(None), state); } } InlineAsmOperand::Const { value: _ } @@ -794,7 +789,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, term: &'a Terminator<'tcx>, loc: Location, ) { @@ -805,7 +800,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> if self.movable_coroutine { // Look for any active borrows to locals let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { + for i in state.borrows.iter() { let borrow = &borrow_set[i]; self.check_for_local_borrow(borrow, span); } @@ -821,7 +816,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { + for i in state.borrows.iter() { let borrow = &borrow_set[i]; self.check_for_invalidation_at_exit(loc, borrow, span); } @@ -989,7 +984,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { place_span: (Place<'tcx>, Span), kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { let (sd, rw) = kind; @@ -1020,11 +1015,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { place_span, rw, is_local_mutation_allowed, - flow_state, + state, location, ); - let conflict_error = - self.check_access_for_conflict(location, place_span, sd, rw, flow_state); + let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state); if conflict_error || mutability_error { debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind); @@ -1032,14 +1026,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - #[instrument(level = "debug", skip(self, flow_state))] + #[instrument(level = "debug", skip(self, state))] fn check_access_for_conflict( &mut self, location: Location, place_span: (Place<'tcx>, Span), sd: AccessDepth, rw: ReadOrWrite, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) -> bool { let mut error_reported = false; let borrow_set = Rc::clone(&self.borrow_set); @@ -1054,7 +1048,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } &polonius_output } else { - &flow_state.borrows + &state.borrows }; each_borrow_involving_path( @@ -1180,17 +1174,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, place_span: (Place<'tcx>, Span), kind: AccessDepth, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { // Write of P[i] or *P requires P init'd. - self.check_if_assigned_path_is_moved(location, place_span, flow_state); + self.check_if_assigned_path_is_moved(location, place_span, state); self.access_place( location, place_span, (kind, Write(WriteKind::Mutate)), LocalMutationIsAllowed::No, - flow_state, + state, ); } @@ -1198,7 +1192,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (rvalue, span): (&'a Rvalue<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { @@ -1224,7 +1218,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), access_kind, LocalMutationIsAllowed::No, - flow_state, + state, ); let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) { @@ -1237,7 +1231,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, action, (place.as_ref(), span), - flow_state, + state, ); } @@ -1257,14 +1251,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), access_kind, LocalMutationIsAllowed::No, - flow_state, + state, ); self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Borrow, (place.as_ref(), span), - flow_state, + state, ); } @@ -1275,7 +1269,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | Rvalue::UnaryOp(_ /*un_op*/, operand) | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) | Rvalue::ShallowInitBox(operand, _ /*ty*/) => { - self.consume_operand(location, (operand, span), flow_state) + self.consume_operand(location, (operand, span), state) } &Rvalue::CopyForDeref(place) => { @@ -1284,7 +1278,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1292,7 +1286,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } @@ -1307,19 +1301,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => { - self.consume_operand(location, (operand1, span), flow_state); - self.consume_operand(location, (operand2, span), flow_state); + self.consume_operand(location, (operand1, span), state); + self.consume_operand(location, (operand2, span), state); } Rvalue::NullaryOp(_op, _ty) => { @@ -1349,7 +1343,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } for operand in operands { - self.consume_operand(location, (operand, span), flow_state); + self.consume_operand(location, (operand, span), state); } } } @@ -1456,7 +1450,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (operand, span): (&'a Operand<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { match *operand { Operand::Copy(place) => { @@ -1467,7 +1461,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1475,7 +1469,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Operand::Move(place) => { @@ -1488,7 +1482,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Deep, Write(WriteKind::Move)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1496,7 +1490,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Operand::Constant(_) => {} @@ -1576,7 +1570,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'a, 'tcx>) { + fn check_activations( + &mut self, + location: Location, + span: Span, + state: &BorrowckDomain<'a, 'tcx>, + ) { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with // another borrow. @@ -1595,7 +1594,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (borrow.borrowed_place, span), (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), LocalMutationIsAllowed::No, - flow_state, + state, ); // We do not need to call `check_if_path_or_subpath_is_moved` // again, as we already called it when we made the @@ -1739,9 +1738,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Bad scenarios: // @@ -1844,9 +1843,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Bad scenarios: // @@ -1863,7 +1862,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // must have been initialized for the use to be sound. // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); + self.check_if_full_path_is_moved(location, desired_action, place_span, state); if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) = place_span.0.last_projection() @@ -1943,7 +1942,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (place, span): (Place<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); @@ -1965,7 +1964,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ProjectionElem::Deref => { self.check_if_full_path_is_moved( location, InitializationRequiringAction::Use, - (place_base, span), flow_state); + (place_base, span), state); // (base initialized; no need to // recur further) break; @@ -1985,7 +1984,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Assignment, - (place_base, span), flow_state); + (place_base, span), state); // (base initialized; no need to // recur further) @@ -1995,7 +1994,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Once `let s; s.x = V; read(s.x);`, // is allowed, remove this match arm. ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, location, place_base, span, flow_state); + check_parent_of_field(self, location, place_base, span, state); } _ => {} @@ -2009,7 +2008,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, base: PlaceRef<'tcx>, span: Span, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { // rust-lang/rust#21232: Until Rust allows reads from the // initialized parts of partially initialized structs, we @@ -2042,7 +2041,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Shallow so that we'll stop at any dereference; we'll // report errors about issues with such bases elsewhere. - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Find the shortest uninitialized prefix you can reach // without going over a Deref. @@ -2100,7 +2099,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span): (Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, location: Location, ) -> bool { debug!( @@ -2124,7 +2123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { }; match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { - self.add_used_mut(root_place, flow_state); + self.add_used_mut(root_place, state); return false; } Err(place_err) => { @@ -2136,7 +2135,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { - self.add_used_mut(root_place, flow_state); + self.add_used_mut(root_place, state); return false; } Err(place_err) => { @@ -2194,7 +2193,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // partial initialization, do not complain about mutability // errors except for actual mutation (as opposed to an attempt // to do a partial initialization). - let previously_initialized = self.is_local_ever_initialized(place.local, flow_state); + let previously_initialized = self.is_local_ever_initialized(place.local, state); // at this point, we have set up the error reporting state. if let Some(init_index) = previously_initialized { @@ -2216,22 +2215,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { fn is_local_ever_initialized( &self, local: Local, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) -> Option<InitIndex> { let mpi = self.move_data.rev_lookup.find_local(local)?; let ii = &self.move_data.init_path_map[mpi]; - ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied() + ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied() } /// Adds the place into the used mutable variables set - fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'a, 'tcx>) { + fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) { match root_place { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { // If the local may have been initialized, and it is now currently being // mutated, then it is justified to be annotated with the `mut` // keyword, since the mutation may be a possible reassignment. if is_local_mutation_allowed != LocalMutationIsAllowed::Yes - && self.is_local_ever_initialized(local, flow_state).is_some() + && self.is_local_ever_initialized(local, state).is_some() { self.used_mut.insert(local); } diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 0b9b8768b56..afd811a0efb 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -32,18 +32,18 @@ pub(super) fn emit_loan_invalidations<'tcx>( visitor.visit_body(body); } -struct LoanInvalidationsGenerator<'cx, 'tcx> { +struct LoanInvalidationsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - all_facts: &'cx mut AllFacts, - location_table: &'cx LocationTable, - body: &'cx Body<'tcx>, - dominators: &'cx Dominators<BasicBlock>, - borrow_set: &'cx BorrowSet<'tcx>, + all_facts: &'a mut AllFacts, + location_table: &'a LocationTable, + body: &'a Body<'tcx>, + dominators: &'a Dominators<BasicBlock>, + borrow_set: &'a BorrowSet<'tcx>, } /// Visits the whole MIR and generates `invalidates()` facts. /// Most of the code implementing this was stolen from `borrow_check/mod.rs`. -impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { self.check_activations(location); @@ -212,7 +212,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { } } -impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { +impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { /// Simulates mutation of a place. fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) { self.access_place( diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs index ed9f714e500..68e0865ab82 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_kills.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs @@ -25,15 +25,15 @@ pub(super) fn emit_loan_kills<'tcx>( } } -struct LoanKillsGenerator<'cx, 'tcx> { +struct LoanKillsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - all_facts: &'cx mut AllFacts, - location_table: &'cx LocationTable, - borrow_set: &'cx BorrowSet<'tcx>, - body: &'cx Body<'tcx>, + all_facts: &'a mut AllFacts, + location_table: &'a LocationTable, + borrow_set: &'a BorrowSet<'tcx>, + body: &'a Body<'tcx>, } -impl<'cx, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { // Also record CFG facts here. self.all_facts.cfg_edge.push(( diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 33cdb1b1f37..c711190cb97 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -181,12 +181,12 @@ impl UniversalRegionRelations<'_> { } } -struct UniversalRegionRelationsBuilder<'this, 'tcx> { - infcx: &'this InferCtxt<'tcx>, +struct UniversalRegionRelationsBuilder<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: Rc<UniversalRegions<'tcx>>, implicit_region_bound: ty::Region<'tcx>, - constraints: &'this mut MirTypeckRegionConstraints<'tcx>, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, // outputs: outlives: TransitiveRelationBuilder<RegionVid>, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 79db8f4252b..a73467824de 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -148,12 +148,12 @@ fn record_regular_live_regions<'tcx>( } /// Visitor looking for regions that should be live within rvalues or calls. -struct LiveVariablesVisitor<'cx, 'tcx> { +struct LiveVariablesVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, - liveness_constraints: &'cx mut LivenessValues, + liveness_constraints: &'a mut LivenessValues, } -impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> { /// We sometimes have `args` within an rvalue, or within a /// call. Make them live at the location where they appear. fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) { @@ -188,7 +188,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> { } } -impl<'cx, 'tcx> LiveVariablesVisitor<'cx, 'tcx> { +impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> { /// Some variable is "regular live" at `location` -- i.e., it may be used later. This means that /// all regions appearing in the type of `value` must be live at `location`. fn record_regions_live_at<T>(&mut self, value: T, location: Location) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index 7f6aabf8841..3a458731f28 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -11,13 +11,13 @@ use crate::location::{LocationIndex, LocationTable}; type VarPointRelation = Vec<(Local, LocationIndex)>; type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; -struct UseFactsExtractor<'me, 'tcx> { - var_defined_at: &'me mut VarPointRelation, - var_used_at: &'me mut VarPointRelation, - location_table: &'me LocationTable, - var_dropped_at: &'me mut VarPointRelation, - move_data: &'me MoveData<'tcx>, - path_accessed_at_base: &'me mut PathPointRelation, +struct UseFactsExtractor<'a, 'tcx> { + var_defined_at: &'a mut VarPointRelation, + var_used_at: &'a mut VarPointRelation, + location_table: &'a LocationTable, + var_dropped_at: &'a mut VarPointRelation, + move_data: &'a MoveData<'tcx>, + path_accessed_at_base: &'a mut PathPointRelation, } // A Visitor to walk through the MIR and extract point-wise facts diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 421f4e2efe0..71892a67ffc 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -58,8 +58,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } -struct NllTypeRelating<'me, 'bccx, 'tcx> { - type_checker: &'me mut TypeChecker<'bccx, 'tcx>, +struct NllTypeRelating<'a, 'b, 'tcx> { + type_checker: &'a mut TypeChecker<'b, 'tcx>, /// Where (and why) is this relation taking place? locations: Locations, @@ -82,9 +82,9 @@ struct NllTypeRelating<'me, 'bccx, 'tcx> { ambient_variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, } -impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { +impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { fn new( - type_checker: &'me mut TypeChecker<'bccx, 'tcx>, + type_checker: &'a mut TypeChecker<'b, 'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, universe_info: UniverseInfo<'tcx>, @@ -309,7 +309,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { } } -impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } @@ -520,7 +520,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx } } -impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> { fn span(&self) -> Span { self.locations.span(self.type_checker.body) } diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 734da318ac1..66df393b501 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -65,7 +65,7 @@ struct AllocFnFactory<'a, 'b> { span: Span, ty_span: Span, global: Ident, - cx: &'b ExtCtxt<'a>, + cx: &'a ExtCtxt<'b>, } impl AllocFnFactory<'_, '_> { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 604a88393fd..a5621aec244 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -180,34 +180,20 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - // Make sure this is actually an array, since typeck only checks the length-suffixed - // version of this intrinsic. + // Make sure this is actually a SIMD vector. let idx_ty = fx.monomorphize(idx.node.ty(fx.mir, fx.tcx)); - let n: u16 = match idx_ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len - .try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) - .unwrap_or_else(|| { - span_bug!(span, "could not evaluate shuffle index array length") - }) - .try_into() - .unwrap(), - _ if idx_ty.is_simd() - && matches!( - idx_ty.simd_size_and_type(fx.tcx).1.kind(), - ty::Uint(ty::UintTy::U32) - ) => - { - idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap() - } - _ => { - fx.tcx.dcx().span_err( - span, - format!("simd_shuffle index must be an array of `u32`, got `{}`", idx_ty), - ); - // Prevent verifier error - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - return; - } + let n: u16 = if idx_ty.is_simd() + && matches!(idx_ty.simd_size_and_type(fx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) + { + idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap() + } else { + fx.tcx.dcx().span_err( + span, + format!("simd_shuffle index must be a SIMD vector of `u32`, got `{}`", idx_ty), + ); + // Prevent verifier error + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + return; }; assert_eq!(x.layout(), y.layout()); diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 6ba678e2e7c..31d778823e0 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1939,33 +1939,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.int_type }; - let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() { - let mask_num_units = vector_type.get_num_units(); - let mut mask_elements = vec![]; - for i in 0..mask_num_units { - let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _); - mask_elements.push(self.context.new_cast( - self.location, - self.extract_element(mask, index).to_rvalue(), - mask_element_type, - )); - } - mask_elements - } else { - let struct_type = mask.get_type().is_struct().expect("mask should be of struct type"); - let mask_num_units = struct_type.get_field_count(); - let mut mask_elements = vec![]; - for i in 0..mask_num_units { - let field = struct_type.get_field(i as i32); - mask_elements.push(self.context.new_cast( - self.location, - mask.access_field(self.location, field).to_rvalue(), - mask_element_type, - )); - } - mask_elements - }; - let mask_num_units = mask_elements.len(); + let vector_type = + mask.get_type().dyncast_vector().expect("simd_shuffle mask should be of vector type"); + let mask_num_units = vector_type.get_num_units(); + let mut mask_elements = vec![]; + for i in 0..mask_num_units { + let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _); + mask_elements.push(self.context.new_cast( + self.location, + self.extract_element(mask, index).to_rvalue(), + mask_element_type, + )); + } // NOTE: the mask needs to be the same length as the input vectors, so add the missing // elements in the mask if needed. diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 96a833ccaf2..2eabc1430db 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -14,7 +14,6 @@ use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; #[cfg(feature = "master")] use rustc_hir as hir; use rustc_middle::mir::BinOp; -use rustc_middle::span_bug; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; use rustc_span::{sym, Span, Symbol}; @@ -353,24 +352,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } if name == sym::simd_shuffle { - // Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed - // version of this intrinsic. + // Make sure this is actually a SIMD vector. let idx_ty = args[2].layout.ty; - let n: u64 = match idx_ty.kind() { - ty::Array(ty, len) if matches!(*ty.kind(), ty::Uint(ty::UintTy::U32)) => { - len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( - || span_bug!(span, "could not evaluate shuffle index array length"), - ) - } - _ if idx_ty.is_simd() - && matches!( - idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), - ty::Uint(ty::UintTy::U32) - ) => - { - idx_ty.simd_size_and_type(bx.cx.tcx).0 - } - _ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }), + let n: u64 = if idx_ty.is_simd() + && matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) + { + idx_ty.simd_size_and_type(bx.cx.tcx).0 + } else { + return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }) }; require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty }); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 05fb77a193a..9705dd506b9 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -573,6 +573,8 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { span, ) { Ok(llval) => llval, + // If there was an error, just skip this invocation... we'll abort compilation anyway, + // but we can keep codegen'ing to find more errors. Err(()) => return Ok(()), } } @@ -1290,24 +1292,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_shuffle { - // Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed - // version of this intrinsic. + // Make sure this is actually a SIMD vector. let idx_ty = args[2].layout.ty; - let n: u64 = match idx_ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { - len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( - || span_bug!(span, "could not evaluate shuffle index array length"), - ) - } - _ if idx_ty.is_simd() - && matches!( - idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), - ty::Uint(ty::UintTy::U32) - ) => - { - idx_ty.simd_size_and_type(bx.cx.tcx).0 - } - _ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }), + let n: u64 = if idx_ty.is_simd() + && matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) + { + idx_ty.simd_size_and_type(bx.cx.tcx).0 + } else { + return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }) }; let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); @@ -1322,38 +1314,24 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let total_len = u128::from(in_len) * 2; - let vector = args[2].immediate(); - - let indices: Option<Vec<_>> = (0..n) - .map(|i| { - let arg_idx = i; - let val = bx.const_get_elt(vector, i as u64); - match bx.const_to_opt_u128(val, true) { - None => { - bug!("typeck should have already ensured that these are const") - } - Some(idx) if idx >= total_len => { - bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { - span, - name, - arg_idx, - total_len, - }); - None - } - Some(idx) => Some(bx.const_i32(idx as i32)), - } - }) - .collect(); - let Some(indices) = indices else { - return Ok(bx.const_null(llret_ty)); - }; + // Check that the indices are in-bounds. + let indices = args[2].immediate(); + for i in 0..n { + let val = bx.const_get_elt(indices, i as u64); + let idx = bx + .const_to_opt_u128(val, true) + .unwrap_or_else(|| bug!("typeck should have already ensured that these are const")); + if idx >= total_len { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { + span, + name, + arg_idx: i, + total_len, + }); + } + } - return Ok(bx.shuffle_vector( - args[0].immediate(), - args[1].immediate(), - bx.const_vector(&indices), - )); + return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), indices)); } if name == sym::simd_insert { @@ -1371,13 +1349,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>( .const_to_opt_u128(args[1].immediate(), false) .expect("typeck should have ensure that this is a const"); if idx >= in_len.into() { - bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { span, name, arg_idx: 1, total_len: in_len.into(), }); - return Ok(bx.const_null(llret_ty)); } return Ok(bx.insert_element( args[0].immediate(), @@ -1394,13 +1371,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>( .const_to_opt_u128(args[1].immediate(), false) .expect("typeck should have ensure that this is a const"); if idx >= in_len.into() { - bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { + return_error!(InvalidMonomorphization::SimdIndexOutOfBounds { span, name, arg_idx: 1, total_len: in_len.into(), }); - return Ok(bx.const_null(llret_ty)); } return Ok(bx.extract_element(args[0].immediate(), bx.const_i32(idx as i32))); } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 8a6a2acd87d..9091602d75b 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -132,7 +132,7 @@ codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of ` codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}` -codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` +codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be a SIMD vector of `u32`, got `{$ty}` codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}` diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 40eb35deea5..8b855bd0dd5 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3044,7 +3044,7 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootErro "iphonesimulator" if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => { } - "macosx10.15" + "macosx" if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") => {} "watchos" diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 817e2ca72ec..8f96c462240 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -915,32 +915,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; - let args: Vec<_> = args - .iter() - .enumerate() - .map(|(i, arg)| { - // The indices passed to simd_shuffle in the - // third argument must be constant. This is - // checked by the type-checker. - if i == 2 && intrinsic.name == sym::simd_shuffle { - // FIXME: the simd_shuffle argument is actually an array, - // not a vector, so we need this special hack to make sure - // it is passed as an immediate. We should pass the - // shuffle indices as a vector instead to avoid this hack. - if let mir::Operand::Constant(constant) = &arg.node { - let (llval, ty) = self.immediate_const_vector(bx, constant); - return OperandRef { - val: Immediate(llval), - layout: bx.layout_of(ty), - }; - } else { - span_bug!(span, "shuffle indices must be constant"); - } - } - - self.codegen_operand(bx, &arg.node) - }) - .collect(); + let args: Vec<_> = + args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { let location = self diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 0aa85b82038..8254fb3d866 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::HasTyCtxt; -use rustc_middle::ty::{self, Ty, ValTree}; +use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_target::abi::Abi; @@ -66,15 +66,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::ConstOperand<'tcx>, ) -> (Bx::Value, Ty<'tcx>) { let ty = self.monomorphize(constant.ty()); - let ty_is_simd = ty.is_simd(); - // FIXME: ideally we'd assert that this is a SIMD type, but simd_shuffle - // in its current form relies on a regular array being passed as an - // immediate argument. This hack can be removed once that is fixed. - let field_ty = if ty_is_simd { - ty.simd_size_and_type(bx.tcx()).1 - } else { - ty.builtin_index().unwrap() - }; + assert!(ty.is_simd()); + let field_ty = ty.simd_size_and_type(bx.tcx()).1; let val = self .eval_unevaluated_mir_constant_to_valtree(constant) @@ -82,19 +75,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .map(|x| x.ok()) .flatten() .map(|val| { - // Depending on whether this is a SIMD type with an array field - // or a type with many fields (one for each elements), the valtree - // is either a single branch with N children, or a root node - // with exactly one child which then in turn has many children. - // So we look at the first child to determine whether it is a - // leaf or whether we have to go one more layer down. - let branch_or_leaf = val.unwrap_branch(); - let first = branch_or_leaf.get(0).unwrap(); - let field_iter = match first { - ValTree::Branch(_) => first.unwrap_branch().iter(), - ValTree::Leaf(_) => branch_or_leaf.iter(), - }; - let values: Vec<_> = field_iter + // A SIMD type has a single field, which is an array. + let fields = val.unwrap_branch(); + assert_eq!(fields.len(), 1); + let array = fields[0].unwrap_branch(); + // Iterate over the array elements to obtain the values in the vector. + let values: Vec<_> = array + .iter() .map(|field| { if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); @@ -107,7 +94,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }) .collect(); - if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) } + bx.const_vector(&values) }) .unwrap_or_else(|| { bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span }); diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 8a6dfb89249..2dc9d57e3b5 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -134,9 +134,6 @@ const_eval_incompatible_return_types = const_eval_incompatible_types = calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} -const_eval_interior_mutability_borrow = - cannot borrow here, since the borrowed element may contain interior mutability - const_eval_interior_mutable_data_refer = {const_eval_const_context}s cannot refer to interior mutable data .label = this borrow of an interior mutable value may end up in the final value @@ -230,9 +227,6 @@ const_eval_memory_exhausted = const_eval_modified_global = modifying a static's initial value from another static's initializer -const_eval_mut_deref = - mutation through a reference is not allowed in {const_eval_const_context}s - const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead @@ -363,10 +357,6 @@ const_eval_too_generic = const_eval_too_many_caller_args = calling a function with more arguments than it expected -const_eval_transient_mut_borrow = mutable references are not allowed in {const_eval_const_context}s - -const_eval_transient_mut_raw = raw mutable pointers are not allowed in {const_eval_const_context}s - const_eval_try_block_from_output_non_const = `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 8be327a8b56..6d09ed5b4bf 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -11,18 +11,17 @@ use rustc_hir::{self as hir, LangItem}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::Analysis; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; -use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; use tracing::{debug, instrument, trace}; use super::ops::{self, NonConstOp, Status}; @@ -166,24 +165,6 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { } } -struct LocalReturnTyVisitor<'ck, 'mir, 'tcx> { - kind: LocalKind, - checker: &'ck mut Checker<'mir, 'tcx>, -} - -impl<'ck, 'mir, 'tcx> TypeVisitor<TyCtxt<'tcx>> for LocalReturnTyVisitor<'ck, 'mir, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) { - match t.kind() { - ty::FnPtr(..) => {} - ty::Ref(_, _, hir::Mutability::Mut) => { - self.checker.check_op(ops::mut_ref::MutRef(self.kind)); - t.super_visit_with(self) - } - _ => t.super_visit_with(self), - } - } -} - pub struct Checker<'mir, 'tcx> { ccx: &'mir ConstCx<'mir, 'tcx>, qualifs: Qualifs<'mir, 'tcx>, @@ -230,25 +211,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { return; } - // The local type and predicate checks are not free and only relevant for `const fn`s. - if self.const_kind() == hir::ConstContext::ConstFn { - for (idx, local) in body.local_decls.iter_enumerated() { - // Handle the return place below. - if idx == RETURN_PLACE { - continue; - } - - self.span = local.source_info.span; - self.check_local_or_return_ty(local.ty, idx); - } - - // impl trait is gone in MIR, so check the return type of a const fn by its signature - // instead of the type of the return place. - self.span = body.local_decls[RETURN_PLACE].source_info.span; - let return_ty = self.ccx.fn_sig().output(); - self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); - } - if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) { self.visit_body(body); } @@ -358,16 +320,11 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { self.check_op_spanned(ops::StaticAccess, span) } - fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { - let kind = self.body.local_kind(local); - - let mut visitor = LocalReturnTyVisitor { kind, checker: self }; - - visitor.visit_ty(ty); - } - - fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) { - match self.const_kind() { + /// Returns whether this place can possibly escape the evaluation of the current const/static + /// initializer. The check assumes that all already existing pointers and references point to + /// non-escaping places. + fn place_may_escape(&mut self, place: &Place<'_>) -> bool { + let is_transient = match self.const_kind() { // In a const fn all borrows are transient or point to the places given via // references in the arguments (so we already checked them with // TransientMutBorrow/MutBorrow as appropriate). @@ -375,7 +332,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // NOTE: Once we have heap allocations during CTFE we need to figure out // how to prevent `const fn` to create long-lived allocations that point // to mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), + hir::ConstContext::ConstFn => true, _ => { // For indirect places, we are not creating a new permanent borrow, it's just as // transient as the already existing one. For reborrowing references this is handled @@ -387,15 +344,16 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // value of the constant. // Note: This is only sound if every local that has a `StorageDead` has a // `StorageDead` in every control flow path leading to a `return` terminator. - // The good news is that interning will detect if any unexpected mutable - // pointer slips through. - if place.is_indirect() || self.local_is_transient(place.local) { - self.check_op(ops::TransientMutBorrow(kind)); - } else { - self.check_op(ops::MutBorrow(kind)); - } + // If anything slips through, there's no safety net -- safe code can create + // references to variants of `!Freeze` enums as long as that variant is `Freeze`, so + // interning can't protect us here. (There *is* a safety net for mutable references + // though, interning will ICE if we miss something here.) + place.is_indirect() || self.local_is_transient(place.local) } - } + }; + // Transient places cannot possibly escape because the place doesn't exist any more at the + // end of evaluation. + !is_transient } } @@ -420,47 +378,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); - // Special-case reborrows to be more like a copy of a reference. - // FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost - // projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`. - // All those cases are handled below with shared/mutable borrows. - // Once `const_mut_refs` is stable, we should be able to entirely remove this special case. - // (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.) - match *rvalue { - Rvalue::Ref(_, kind, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match kind { - BorrowKind::Shared => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) - } - BorrowKind::Fake(_) => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) - } - BorrowKind::Mut { .. } => { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - } - }; - self.visit_local(reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - Rvalue::RawPtr(mutbl, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match mutbl { - Mutability::Not => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) - } - Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::RawBorrow), - }; - self.visit_local(reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - _ => {} - } - self.super_rvalue(rvalue, location); match rvalue { @@ -494,15 +411,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let is_allowed = self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut); - if !is_allowed { - self.check_mut_borrow( - place, - if matches!(rvalue, Rvalue::Ref(..)) { - hir::BorrowKind::Ref - } else { - hir::BorrowKind::Raw - }, - ); + if !is_allowed && self.place_may_escape(place) { + self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) { + hir::BorrowKind::Ref + } else { + hir::BorrowKind::Raw + })); } } @@ -514,39 +428,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { place.as_ref(), ); - // If the place is indirect, this is basically a reborrow. We have a reborrow - // special case above, but for raw pointers and pointers/references to `static` and - // when the `*` is not the first projection, `place_as_reborrow` does not recognize - // them as such, so we end up here. This should probably be considered a - // `TransientCellBorrow` (we consider the equivalent mutable case a - // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and - // it is too much of a breaking change to take back. - if borrowed_place_has_mut_interior && !place.is_indirect() { - match self.const_kind() { - // In a const fn all borrows are transient or point to the places given via - // references in the arguments (so we already checked them with - // TransientCellBorrow/CellBorrow as appropriate). - // The borrow checker guarantees that no new non-transient borrows are created. - // NOTE: Once we have heap allocations during CTFE we need to figure out - // how to prevent `const fn` to create long-lived allocations that point - // to (interior) mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow), - _ => { - // Locals with StorageDead are definitely not part of the final constant value, and - // it is thus inherently safe to permit such locals to have their - // address taken as we can't end up with a reference to them in the - // final value. - // Note: This is only sound if every local that has a `StorageDead` has a - // `StorageDead` in every control flow path leading to a `return` terminator. - // The good news is that interning will detect if any unexpected mutable - // pointer slips through. - if self.local_is_transient(place.local) { - self.check_op(ops::TransientCellBorrow); - } else { - self.check_op(ops::CellBorrow); - } - } - } + if borrowed_place_has_mut_interior && self.place_may_escape(place) { + self.check_op(ops::EscapingCellBorrow); } } @@ -635,58 +518,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } } - fn visit_projection_elem( - &mut self, - place_ref: PlaceRef<'tcx>, - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - trace!( - "visit_projection_elem: place_ref={:?} elem={:?} \ - context={:?} location={:?}", - place_ref, elem, context, location, - ); - - self.super_projection_elem(place_ref, elem, context, location); - - match elem { - ProjectionElem::Deref => { - let base_ty = place_ref.ty(self.body, self.tcx).ty; - if base_ty.is_unsafe_ptr() { - if place_ref.projection.is_empty() { - let decl = &self.body.local_decls[place_ref.local]; - // If this is a static, then this is not really dereferencing a pointer, - // just directly accessing a static. That is not subject to any feature - // gates (except for the one about whether statics can even be used, but - // that is checked already by `visit_operand`). - if let LocalInfo::StaticRef { .. } = *decl.local_info() { - return; - } - } - - // `*const T` is stable, `*mut T` is not - if !base_ty.is_mutable_ptr() { - return; - } - - self.check_op(ops::RawMutPtrDeref); - } - - if context.is_mutating_use() { - self.check_op(ops::MutDeref); - } - } - - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Downcast(..) - | ProjectionElem::OpaqueCast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(..) - | ProjectionElem::Field(..) - | ProjectionElem::Index(_) => {} - } - } fn visit_source_info(&mut self, source_info: &SourceInfo) { trace!("visit_source_info: source_info={:?}", source_info); @@ -983,40 +814,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } -fn place_as_reborrow<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - place: Place<'tcx>, -) -> Option<PlaceRef<'tcx>> { - match place.as_ref().last_projection() { - Some((place_base, ProjectionElem::Deref)) => { - // FIXME: why do statics and raw pointers get excluded here? This makes - // some code involving mutable pointers unstable, but it is unclear - // why that code is treated differently from mutable references. - // Once TransientMutBorrow and TransientCellBorrow are stable, - // this can probably be cleaned up without any behavioral changes. - - // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` - // that points to the allocation for the static. Don't treat these as reborrows. - if body.local_decls[place_base.local].is_ref_to_static() { - None - } else { - // Ensure the type being derefed is a reference and not a raw pointer. - // This is sufficient to prevent an access to a `static mut` from being marked as a - // reborrow, even if the check above were to disappear. - let inner_ty = place_base.ty(body, tcx).ty; - - if let ty::Ref(..) = inner_ty.kind() { - return Some(place_base); - } else { - return None; - } - } - } - _ => None, - } -} - fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool { ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point() } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index e8f10c88408..a52fc6a077b 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; -use rustc_middle::mir::{self, CallSource}; +use rustc_middle::mir::CallSource; use rustc_middle::span_bug; use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _}; use rustc_middle::ty::{ @@ -392,26 +392,11 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> { } #[derive(Debug)] -/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to -/// the final value of the constant. -pub(crate) struct TransientCellBorrow; -impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_refs_to_cell) - } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx - .sess - .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) - } -} - -#[derive(Debug)] /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to /// the final value of the constant, and thus we cannot allow this (for now). We may allow /// it in the future for static items. -pub(crate) struct CellBorrow; -impl<'tcx> NonConstOp<'tcx> for CellBorrow { +pub(crate) struct EscapingCellBorrow; +impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { fn importance(&self) -> DiagImportance { // Most likely the code will try to do mutation with these borrows, which // triggers its own errors. Only show this one if that does not happen. @@ -431,9 +416,9 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { /// This op is for `&mut` borrows in the trailing expression of a constant /// which uses the "enclosing scopes rule" to leak its locals into anonymous /// static or const items. -pub(crate) struct MutBorrow(pub hir::BorrowKind); +pub(crate) struct EscapingMutBorrow(pub hir::BorrowKind); -impl<'tcx> NonConstOp<'tcx> for MutBorrow { +impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Forbidden } @@ -460,49 +445,6 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { } } -#[derive(Debug)] -pub(crate) struct TransientMutBorrow(pub hir::BorrowKind); - -impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let kind = ccx.const_kind(); - match self.0 { - hir::BorrowKind::Raw => ccx - .tcx - .sess - .create_feature_err(errors::TransientMutRawErr { span, kind }, sym::const_mut_refs), - hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err( - errors::TransientMutBorrowErr { span, kind }, - sym::const_mut_refs, - ), - } - } -} - -#[derive(Debug)] -pub(crate) struct MutDeref; -impl<'tcx> NonConstOp<'tcx> for MutDeref { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagImportance { - // Usually a side-effect of a `TransientMutBorrow` somewhere. - DiagImportance::Secondary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx.sess.create_feature_err( - errors::MutDerefErr { span, kind: ccx.const_kind() }, - sym::const_mut_refs, - ) - } -} - /// A call to a `panic()` lang item where the first argument is _not_ a `&str`. #[derive(Debug)] pub(crate) struct PanicNonStr; @@ -524,24 +466,6 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { } } -#[derive(Debug)] -pub(crate) struct RawMutPtrDeref; -impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_mut_refs, - span, - format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),), - ) - } -} - /// Casting raw pointer or function pointer to an integer. /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on /// allocation base addresses that are not known at compile-time. @@ -588,33 +512,3 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { ccx.dcx().create_err(errors::ThreadLocalAccessErr { span }) } } - -/// Types that cannot appear in the signature or locals of a `const fn`. -pub(crate) mod mut_ref { - use super::*; - - #[derive(Debug)] - pub(crate) struct MutRef(pub mir::LocalKind); - impl<'tcx> NonConstOp<'tcx> for MutRef { - fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagImportance { - match self.0 { - mir::LocalKind::Temp => DiagImportance::Secondary, - mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => DiagImportance::Primary, - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_mut_refs, - span, - format!("mutable references are not allowed in {}s", ccx.const_kind()), - ) - } - } -} diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index da4173f9032..337eab7a1c2 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -10,7 +10,6 @@ use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, Abi}; @@ -18,13 +17,12 @@ use tracing::{debug, instrument, trace}; use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; use crate::const_eval::CheckAlignment; -use crate::errors::{self, ConstEvalError, DanglingPtrInFinal}; use crate::interpret::{ create_static_alloc, eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust, CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, }; -use crate::CTRL_C_RECEIVED; +use crate::{errors, CTRL_C_RECEIVED}; // Returns a pointer to where the result lives #[instrument(level = "trace", skip(ecx, body))] @@ -100,18 +98,15 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( return Err(ecx .tcx .dcx() - .emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) + .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) .into()); } Err(InternResult::FoundBadMutablePointer) => { - // only report mutable pointers if there were no dangling pointers - let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }; - ecx.tcx.emit_node_span_lint( - lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - ecx.machine.best_lint_scope(*ecx.tcx), - err_diag.span, - err_diag, - ) + return Err(ecx + .tcx + .dcx() + .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }) + .into()); } } @@ -443,7 +438,12 @@ fn report_eval_error<'tcx>( error, DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, + |span, frames| errors::ConstEvalError { + span, + error_kind: kind, + instance, + frame_notes: frames, + }, ) } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7405ca09342..6a691abae02 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -718,16 +718,29 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { _kind: mir::RetagKind, val: &ImmTy<'tcx, CtfeProvenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, CtfeProvenance>> { - // If it's a frozen shared reference that's not already immutable, make it immutable. + // If it's a frozen shared reference that's not already immutable, potentially make it immutable. // (Do nothing on `None` provenance, that cannot store immutability anyway.) if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind() && *mutbl == Mutability::Not - && val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable()) - // That next check is expensive, that's why we have all the guards above. - && ty.is_freeze(*ecx.tcx, ecx.param_env) + && val + .to_scalar_and_meta() + .0 + .to_pointer(ecx)? + .provenance + .is_some_and(|p| !p.immutable()) { + // That next check is expensive, that's why we have all the guards above. + let is_immutable = ty.is_freeze(*ecx.tcx, ecx.param_env); let place = ecx.ref_to_mplace(val)?; - let new_place = place.map_provenance(CtfeProvenance::as_immutable); + let new_place = if is_immutable { + place.map_provenance(CtfeProvenance::as_immutable) + } else { + // Even if it is not immutable, remember that it is a shared reference. + // This allows it to become part of the final value of the constant. + // (See <https://github.com/rust-lang/rust/pull/128543> for why we allow this + // even when there is interior mutability.) + place.map_provenance(CtfeProvenance::as_shared_ref) + }; Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) } else { Ok(val.clone()) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 0b366b43f95..b66b5c0a00a 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -35,13 +35,10 @@ pub(crate) struct NestedStaticInThreadLocal { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag(const_eval_mutable_ptr_in_final)] pub(crate) struct MutablePtrInFinal { - // rust-lang/rust#122153: This was marked as `#[primary_span]` under - // `derive(Diagnostic)`. Since we expect we may hard-error in future, we are - // keeping the field (and skipping it under `derive(LintDiagnostic)`). - #[skip_arg] + #[primary_span] pub span: Span, pub kind: InternKind, } @@ -97,30 +94,6 @@ pub(crate) struct PanicNonStrErr { } #[derive(Diagnostic)] -#[diag(const_eval_mut_deref, code = E0658)] -pub(crate) struct MutDerefErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_transient_mut_borrow, code = E0658)] -pub(crate) struct TransientMutBorrowErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_transient_mut_raw, code = E0658)] -pub(crate) struct TransientMutRawErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] #[diag(const_eval_max_num_nodes_in_const)] pub(crate) struct MaxNumNodesInConstErr { #[primary_span] @@ -220,13 +193,6 @@ pub(crate) struct InteriorMutableDataRefer { pub teach: bool, } -#[derive(Diagnostic)] -#[diag(const_eval_interior_mutability_borrow)] -pub(crate) struct InteriorMutabilityBorrow { - #[primary_span] - pub span: Span, -} - #[derive(LintDiagnostic)] #[diag(const_eval_long_running)] #[note] diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8b0a2afa4d6..5df989b4c1d 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -20,6 +20,7 @@ use rustc_hir as hir; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; use rustc_middle::query::TyCtxtAt; +use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::LocalDefId; use rustc_span::sym; @@ -223,37 +224,52 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval continue; } - // Crucially, we check this *before* checking whether the `alloc_id` - // has already been interned. The point of this check is to ensure that when - // there are multiple pointers to the same allocation, they are *all* immutable. - // Therefore it would be bad if we only checked the first pointer to any given - // allocation. + // Ensure that this is derived from a shared reference. Crucially, we check this *before* + // checking whether the `alloc_id` has already been interned. The point of this check is to + // ensure that when there are multiple pointers to the same allocation, they are *all* + // derived from a shared reference. Therefore it would be bad if we only checked the first + // pointer to any given allocation. // (It is likely not possible to actually have multiple pointers to the same allocation, // so alternatively we could also check that and ICE if there are multiple such pointers.) + // See <https://github.com/rust-lang/rust/pull/128543> for why we are checking for "shared + // reference" and not "immutable", i.e., for why we are allowing interior-mutable shared + // references: they can actually be created in safe code while pointing to apparently + // "immutable" values, via promotion or tail expression lifetime extension of + // `&None::<Cell<T>>`. + // We also exclude promoteds from this as `&mut []` can be promoted, which is a mutable + // reference pointing to an immutable (zero-sized) allocation. We rely on the promotion + // analysis not screwing up to ensure that it is sound to intern promoteds as immutable. if intern_kind != InternKind::Promoted && inner_mutability == Mutability::Not - && !prov.immutable() + && !prov.shared_ref() { - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() - && !just_interned.contains(&alloc_id) - { + let is_already_global = ecx.tcx.try_get_global_alloc(alloc_id).is_some(); + if is_already_global && !just_interned.contains(&alloc_id) { // This is a pointer to some memory from another constant. We encounter mutable // pointers to such memory since we do not always track immutability through // these "global" pointers. Allowing them is harmless; the point of these checks // during interning is to justify why we intern the *new* allocations immutably, - // so we can completely ignore existing allocations. We also don't need to add - // this to the todo list, since after all it is already interned. + // so we can completely ignore existing allocations. + // We can also skip the rest of this loop iteration, since after all it is already + // interned. continue; } - // Found a mutable pointer inside a const where inner allocations should be - // immutable. We exclude promoteds from this, since things like `&mut []` and - // `&None::<Cell<i32>>` lead to promotion that can produce mutable pointers. We rely - // on the promotion analysis not screwing up to ensure that it is sound to intern - // promoteds as immutable. - trace!("found bad mutable pointer"); - // Prefer dangling pointer errors over mutable pointer errors - if result.is_ok() { - result = Err(InternResult::FoundBadMutablePointer); + // If this is a dangling pointer, that's actually fine -- the problematic case is + // when there is memory there that someone might expect to be mutable, but we make it immutable. + let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id); + if !dangling { + // Found a mutable reference inside a const where inner allocations should be + // immutable. + if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + span_bug!( + ecx.tcx.span, + "the static const safety checks accepted mutable references they should not have accepted" + ); + } + // Prefer dangling pointer errors over mutable pointer errors + if result.is_ok() { + result = Err(InternResult::FoundBadMutablePointer); + } } } if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { @@ -261,7 +277,6 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id)); continue; } - just_interned.insert(alloc_id); // We always intern with `inner_mutability`, and furthermore we ensured above that if // that is "immutable", then there are *no* mutable pointers anywhere in the newly // interned memory -- justifying that we can indeed intern immutably. However this also @@ -272,6 +287,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // pointers before deciding which allocations can be made immutable; but for now we are // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. + just_interned.insert(alloc_id); match intern_shallow(ecx, alloc_id, inner_mutability) { Ok(nested) => todo.extend(nested), Err(()) => { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 8cab3c34eed..67c99934059 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -540,10 +540,29 @@ pub trait Machine<'tcx>: Sized { Ok(ReturnAction::Normal) } + /// Called immediately after an "immediate" local variable is read + /// (i.e., this is called for reads that do not end up accessing addressable memory). + #[inline(always)] + fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> { + Ok(()) + } + + /// Called immediately after an "immediate" local variable is assigned a new value + /// (i.e., this is called for writes that do not end up in memory). + /// `storage_live` indicates whether this is the initial write upon `StorageLive`. + #[inline(always)] + fn after_local_write( + _ecx: &mut InterpCx<'tcx, Self>, + _local: mir::Local, + _storage_live: bool, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Called immediately after actual memory was allocated for a local /// but before the local's stack frame is updated to point to that memory. #[inline(always)] - fn after_local_allocated( + fn after_local_moved_to_memory( _ecx: &mut InterpCx<'tcx, Self>, _local: mir::Local, _mplace: &MPlaceTy<'tcx, Self::Provenance>, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 7b0b28a470d..b1d1dab7c16 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -7,7 +7,7 @@ //! short-circuiting the empty case! use std::assert_matches::assert_matches; -use std::borrow::Cow; +use std::borrow::{Borrow, Cow}; use std::collections::VecDeque; use std::{fmt, mem, ptr}; @@ -387,12 +387,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { size: Size, ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> { let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes - self.check_and_deref_ptr( + Self::check_and_deref_ptr( + self, ptr, size, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { - let (size, align) = self + |this, alloc_id, offset, prov| { + let (size, align) = this .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; Ok((size, align, (alloc_id, offset, prov))) }, @@ -409,8 +410,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes - self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| { - let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; + Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { + let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; Ok((size, align, ())) })?; Ok(()) @@ -425,8 +426,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { size: i64, msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { - self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| { - let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; + Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { + let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; Ok((size, align, ())) })?; Ok(()) @@ -440,12 +441,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// `alloc_size` will only get called for non-zero-sized accesses. /// /// Returns `None` if and only if the size is 0. - fn check_and_deref_ptr<T>( - &self, + fn check_and_deref_ptr<T, R: Borrow<Self>>( + this: R, ptr: Pointer<Option<M::Provenance>>, size: i64, msg: CheckInAllocMsg, alloc_size: impl FnOnce( + R, AllocId, Size, M::ProvenanceExtra, @@ -456,13 +458,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return Ok(None); } - Ok(match self.ptr_try_get_alloc_id(ptr, size) { + Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { Err(addr) => { // We couldn't get a proper allocation. throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg }); } Ok((alloc_id, offset, prov)) => { - let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; + let tcx = this.borrow().tcx; + let (alloc_size, _alloc_align, ret_val) = alloc_size(this, alloc_id, offset, prov)?; let offset = offset.bytes(); // Compute absolute begin and end of the range. let (begin, end) = if size >= 0 { @@ -476,7 +479,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(PointerOutOfBounds { alloc_id, alloc_size, - ptr_offset: self.sign_extend_to_target_isize(offset), + ptr_offset: tcx.sign_extend_to_target_isize(offset), inbounds_size: size, msg, }) @@ -670,12 +673,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes - let ptr_and_alloc = self.check_and_deref_ptr( + let ptr_and_alloc = Self::check_and_deref_ptr( + self, ptr, size_i64, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { - let alloc = self.get_alloc_raw(alloc_id)?; + |this, alloc_id, offset, prov| { + let alloc = this.get_alloc_raw(alloc_id)?; Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; @@ -727,7 +731,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We have "NLL problem case #3" here, which cannot be worked around without loss of // efficiency even for the common case where the key is in the map. // <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions> - // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.) + // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`, and that boils down to + // Miri's `adjust_alloc_root_pointer` needing to look up the size of the allocation. + // It could be avoided with a totally separate codepath in Miri for handling the absolute address + // of global allocations, but that's not worth it.) if self.memory.alloc_map.get_mut(id).is_none() { // Slow path. // Allocation not found locally, go look global. @@ -763,13 +770,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { size: Size, ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { - let parts = self.get_ptr_access(ptr, size)?; - if let Some((alloc_id, offset, prov)) = parts { - let tcx = self.tcx; - let validation_in_progress = self.memory.validation_in_progress; - // FIXME: can we somehow avoid looking up the allocation twice here? - // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. - let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?; + let tcx = self.tcx; + let validation_in_progress = self.memory.validation_in_progress; + + let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes + let ptr_and_alloc = Self::check_and_deref_ptr( + self, + ptr, + size_i64, + CheckInAllocMsg::MemoryAccessTest, + |this, alloc_id, offset, prov| { + let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?; + Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) + }, + )?; + + if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc { let range = alloc_range(offset, size); if !validation_in_progress { M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; @@ -1031,6 +1047,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ); res } + + pub(super) fn validation_in_progress(&self) -> bool { + self.memory.validation_in_progress + } } #[doc(hidden)] @@ -1115,7 +1135,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { } /// Reading and writing. -impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> +impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRefMut<'a, 'tcx, Prov, Extra, Bytes> { pub fn as_ref<'b>(&'b self) -> AllocRef<'b, 'tcx, Prov, Extra, Bytes> { @@ -1163,7 +1183,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> } } -impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> { +impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn read_scalar( &self, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 2e02d1001c8..ead3ef6861a 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -697,6 +697,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(op, Operand::Immediate(_)) { assert!(!layout.is_unsized()); } + M::after_local_read(self, local)?; Ok(OpTy { op, layout }) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 9dd9ca80385..e398c4c0742 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -500,15 +500,13 @@ where &self, local: mir::Local, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { - // Other parts of the system rely on `Place::Local` never being unsized. - // So we eagerly check here if this local has an MPlace, and if yes we use it. let frame = self.frame(); let layout = self.layout_of_local(frame, local, None)?; let place = if layout.is_sized() { // We can just always use the `Local` for sized values. Place::Local { local, offset: None, locals_addr: frame.locals_addr() } } else { - // Unsized `Local` isn't okay (we cannot store the metadata). + // Other parts of the system rely on `Place::Local` never being unsized. match frame.locals[local].access()? { Operand::Immediate(_) => bug!(), Operand::Indirect(mplace) => Place::Ptr(*mplace), @@ -562,7 +560,10 @@ where place: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult< 'tcx, - Either<MPlaceTy<'tcx, M::Provenance>, (&mut Immediate<M::Provenance>, TyAndLayout<'tcx>)>, + Either< + MPlaceTy<'tcx, M::Provenance>, + (&mut Immediate<M::Provenance>, TyAndLayout<'tcx>, mir::Local), + >, > { Ok(match place.to_place().as_mplace_or_local() { Left(mplace) => Left(mplace), @@ -581,7 +582,7 @@ where } Operand::Immediate(local_val) => { // The local still has the optimized representation. - Right((local_val, layout)) + Right((local_val, layout, local)) } } } @@ -643,9 +644,13 @@ where assert!(dest.layout().is_sized(), "Cannot write unsized immediate data"); match self.as_mplace_or_mutable_local(&dest.to_place())? { - Right((local_val, local_layout)) => { + Right((local_val, local_layout, local)) => { // Local can be updated in-place. *local_val = src; + // Call the machine hook (the data race detector needs to know about this write). + if !self.validation_in_progress() { + M::after_local_write(self, local, /*storage_live*/ false)?; + } // Double-check that the value we are storing and the local fit to each other. if cfg!(debug_assertions) { src.assert_matches_abi(local_layout.abi, self); @@ -714,8 +719,12 @@ where dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { match self.as_mplace_or_mutable_local(&dest.to_place())? { - Right((local_val, _local_layout)) => { + Right((local_val, _local_layout, local)) => { *local_val = Immediate::Uninit; + // Call the machine hook (the data race detector needs to know about this write). + if !self.validation_in_progress() { + M::after_local_write(self, local, /*storage_live*/ false)?; + } } Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { @@ -734,8 +743,12 @@ where dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { match self.as_mplace_or_mutable_local(&dest.to_place())? { - Right((local_val, _local_layout)) => { + Right((local_val, _local_layout, local)) => { local_val.clear_provenance()?; + // Call the machine hook (the data race detector needs to know about this write). + if !self.validation_in_progress() { + M::after_local_write(self, local, /*storage_live*/ false)?; + } } Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { @@ -941,7 +954,7 @@ where mplace.mplace, )?; } - M::after_local_allocated(self, local, &mplace)?; + M::after_local_moved_to_memory(self, local, &mplace)?; // Now we can call `access_mut` again, asserting it goes well, and actually // overwrite things. This points to the entire allocation, not just the part // the place refers to, i.e. we do this before we apply `offset`. diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 4e8b66907be..58ce44e4014 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -101,7 +101,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { } /// A type representing iteration over the elements of an array. -pub struct ArrayIterator<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> { +pub struct ArrayIterator<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> { base: &'a P, range: Range<u64>, stride: Size, @@ -109,7 +109,7 @@ pub struct ArrayIterator<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> _phantom: PhantomData<Prov>, // otherwise it says `Prov` is never used... } -impl<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'tcx, 'a, Prov, P> { +impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, 'tcx, Prov, P> { /// Should be the same `ecx` on each call, and match the one used to create the iterator. pub fn next<M: Machine<'tcx, Provenance = Prov>>( &mut self, @@ -290,7 +290,7 @@ where pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>( &self, base: &'a P, - ) -> InterpResult<'tcx, ArrayIterator<'tcx, 'a, M::Provenance, P>> { + ) -> InterpResult<'tcx, ArrayIterator<'a, 'tcx, M::Provenance, P>> { let abi::FieldsShape::Array { stride, .. } = base.layout().fields else { span_bug!(self.cur_span(), "project_array_fields: expected an array layout"); }; diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index b6e83715e39..db418c82f66 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -534,8 +534,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?; Operand::Indirect(*dest_place.mplace()) } else { - assert!(!meta.has_meta()); // we're dropping the metadata // Just make this an efficient immediate. + assert!(!meta.has_meta()); // we're dropping the metadata + // Make sure the machine knows this "write" is happening. (This is important so that + // races involving local variable allocation can be detected by Miri.) + M::after_local_write(self, local, /*storage_live*/ true)?; // Note that not calling `layout_of` here does have one real consequence: // if the type is too big, we'll only notice this when the local is actually initialized, // which is a bit too late -- we should ideally notice this already here, when the memory diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fb24f983ca9..469af35ec1b 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -14,7 +14,6 @@ use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_middle::bug; use rustc_middle::mir::interpret::ValidationErrorKind::{self, *}; use rustc_middle::mir::interpret::{ alloc_range, ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, @@ -22,6 +21,7 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{ Abi, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, @@ -617,6 +617,13 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not { + if !self.ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you + { + span_bug!( + self.ecx.tcx.span, + "the static const safety checks accepted mutable references they should not have accepted" + ); + } throw_validation_failure!(self.path, MutableRefToImmutable); } // In a const, everything must be completely immutable. diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1b7ca61cee8..9d4061d16a1 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -207,17 +207,17 @@ pub fn diagnostics_registry() -> Registry { } /// This is the primary entry point for rustc. -pub struct RunCompiler<'a, 'b> { +pub struct RunCompiler<'a> { at_args: &'a [String], - callbacks: &'b mut (dyn Callbacks + Send), + callbacks: &'a mut (dyn Callbacks + Send), file_loader: Option<Box<dyn FileLoader + Send + Sync>>, make_codegen_backend: Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>, using_internal_features: Arc<std::sync::atomic::AtomicBool>, } -impl<'a, 'b> RunCompiler<'a, 'b> { - pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self { +impl<'a> RunCompiler<'a> { + pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self { Self { at_args, callbacks, diff --git a/compiler/rustc_error_codes/src/error_codes/E0764.md b/compiler/rustc_error_codes/src/error_codes/E0764.md index 152627cf654..4d5091cd954 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0764.md +++ b/compiler/rustc_error_codes/src/error_codes/E0764.md @@ -3,8 +3,6 @@ A mutable reference was used in a constant. Erroneous code example: ```compile_fail,E0764 -#![feature(const_mut_refs)] - fn main() { const OH_NO: &'static mut usize = &mut 1; // error! } @@ -26,8 +24,6 @@ Remember: you cannot use a function call inside a constant or static. However, you can totally use it in constant functions: ``` -#![feature(const_mut_refs)] - const fn foo(x: usize) -> usize { let mut y = 1; let z = &mut y; diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 24f631ed5dc..d1dcec0cc15 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -43,9 +43,9 @@ pub struct BangProcMacro { } impl base::BangProcMacro for BangProcMacro { - fn expand<'cx>( + fn expand( &self, - ecx: &'cx mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, span: Span, input: TokenStream, ) -> Result<TokenStream, ErrorGuaranteed> { @@ -73,9 +73,9 @@ pub struct AttrProcMacro { } impl base::AttrProcMacro for AttrProcMacro { - fn expand<'cx>( + fn expand( &self, - ecx: &'cx mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, span: Span, annotation: TokenStream, annotated: TokenStream, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 8949fdffdae..0088a7bbc1e 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -115,6 +115,8 @@ declare_features! ( (accepted, conservative_impl_trait, "1.26.0", Some(34511)), /// Allows calling constructor functions in `const fn`. (accepted, const_constructor, "1.40.0", Some(61456)), + /// Allows the definition of `const extern fn` and `const unsafe extern fn`. + (accepted, const_extern_fn, "CURRENT_RUSTC_VERSION", Some(64926)), /// Allows basic arithmetic on floating point types in a `const fn`. (accepted, const_fn_floating_point_arithmetic, "1.82.0", Some(57241)), /// Allows using and casting function pointers in a `const fn`. @@ -141,10 +143,14 @@ declare_features! ( (accepted, const_let, "1.33.0", Some(48821)), /// Allows the use of `loop` and `while` in constants. (accepted, const_loop, "1.46.0", Some(52000)), + /// Allows using `&mut` in constant functions. + (accepted, const_mut_refs, "CURRENT_RUSTC_VERSION", Some(57349)), /// Allows panicking during const eval (producing compile-time errors). (accepted, const_panic, "1.57.0", Some(51999)), /// Allows dereferencing raw pointers during const eval. (accepted, const_raw_ptr_deref, "1.58.0", Some(51911)), + /// Allows references to types with interior mutability within constants + (accepted, const_refs_to_cell, "CURRENT_RUSTC_VERSION", Some(80384)), /// Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490)), /// Allows `crate` in paths. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 6ed5ea9f8bb..d0c0460ddfe 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -401,16 +401,10 @@ declare_features! ( (unstable, const_async_blocks, "1.53.0", Some(85368)), /// Allows `const || {}` closures in const contexts. (incomplete, const_closures, "1.68.0", Some(106003)), - /// Allows the definition of `const extern fn` and `const unsafe extern fn`. - (unstable, const_extern_fn, "1.40.0", Some(64926)), /// Allows `for _ in _` loops in const contexts. (unstable, const_for, "1.56.0", Some(87575)), - /// Allows using `&mut` in constant functions. - (unstable, const_mut_refs, "1.41.0", Some(57349)), /// Be more precise when looking for live drops in a const context. (unstable, const_precise_live_drops, "1.46.0", Some(73255)), - /// Allows references to types with interior mutability within constants - (unstable, const_refs_to_cell, "1.51.0", Some(80384)), /// Allows creating pointers and references to `static` items in constants. (unstable, const_refs_to_static, "1.78.0", Some(119618)), /// Allows `impl const Trait for T` syntax. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9863d036449..3dc8759a9ed 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -58,7 +58,7 @@ pub(crate) fn check_legal_trait_for_method_call( enum CallStep<'tcx> { Builtin(Ty<'tcx>), DeferredClosure(LocalDefId, ty::FnSig<'tcx>), - /// E.g., enum variant constructors. + /// Call overloading when callee implements one of the Fn* traits. Overloaded(MethodCallee<'tcx>), } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 4d2770d2e50..a692642ccfc 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -711,7 +711,7 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> { #[derive(Diagnostic)] #[diag(hir_typeck_pass_to_variadic_function, code = E0617)] -pub(crate) struct PassToVariadicFunction<'tcx, 'a> { +pub(crate) struct PassToVariadicFunction<'a, 'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 79b02a7f045..7a6ebf15fa9 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -603,12 +603,12 @@ fn compute_unsafe_infer_vars<'a, 'tcx>( root_ctxt.tcx.hir().maybe_body_owned_by(body_id).expect("body id must have an owner"); let mut res = UnordMap::default(); - struct UnsafeInferVarsVisitor<'a, 'tcx, 'r> { + struct UnsafeInferVarsVisitor<'a, 'tcx> { root_ctxt: &'a TypeckRootCtxt<'tcx>, - res: &'r mut UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>, + res: &'a mut UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>, } - impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_, '_> { + impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_> { fn visit_expr(&mut self, ex: &'_ hir::Expr<'_>) { let typeck_results = self.root_ctxt.typeck_results.borrow(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 178dc47aa1f..7318d02d24c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1234,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer_args_for_err: &'a FxHashSet<usize>, segments: &'tcx [hir::PathSegment<'tcx>], } - impl<'tcx, 'a> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> { + impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> { fn args_for_def_id( &mut self, def_id: DefId, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 21b040bd0bc..8348c6e9a16 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -506,6 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id, call_span, call_expr, + tuple_arguments, ); } } @@ -520,6 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id: Option<DefId>, call_span: Span, call_expr: &'tcx hir::Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, ) -> ErrorGuaranteed { // Next, let's construct the error let (error_span, call_ident, full_call_span, call_name, is_method) = match &call_expr.kind { @@ -865,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); suggest_confusable(&mut err); return err.emit(); @@ -1001,6 +1004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); suggest_confusable(&mut err); return err.emit(); @@ -1448,6 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); // And add a suggestion block for all of the parameters @@ -2219,21 +2224,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>, formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, is_method: bool, + tuple_arguments: TupleArgumentsFlag, ) { let Some(mut def_id) = callable_def_id else { return; }; + // If we're calling a method of a Fn/FnMut/FnOnce trait object implicitly + // (eg invoking a closure) we want to point at the underlying callable, + // not the method implicitly invoked (eg call_once). if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) - // Possibly points at either impl or trait item, so try to get it - // to point to trait item, then get the parent. - // This parent might be an impl in the case of an inherent function, - // but the next check will fail. + // Since this is an associated item, it might point at either an impl or a trait item. + // We want it to always point to the trait item. + // If we're pointing at an inherent function, we don't need to do anything, + // so we fetch the parent and verify if it's a trait item. && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id) && let Some(callee_ty) = callee_ty + // TupleArguments is set only when this is an implicit call (my_closure(...)) rather than explicit (my_closure.call(...)) + && tuple_arguments == TupleArguments { let callee_ty = callee_ty.peel_refs(); match *callee_ty.kind() { @@ -2303,166 +2314,173 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut spans: MultiSpan = def_span.into(); - let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); - let mut generics_with_unmatched_params = Vec::new(); + if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) + { + debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); - let check_for_matched_generics = || { - if matched_inputs.iter().any(|x| x.is_some()) - && params_with_generics.iter().any(|x| x.0.is_some()) - { - for (idx, (generic, _)) in params_with_generics.iter().enumerate() { - // Param has to have a generic and be matched to be relevant - if matched_inputs[idx.into()].is_none() { - continue; - } + let mut generics_with_unmatched_params = Vec::new(); - let Some(generic) = generic else { - continue; - }; + let check_for_matched_generics = || { + if matched_inputs.iter().any(|x| x.is_some()) + && params_with_generics.iter().any(|x| x.0.is_some()) + { + for (idx, (generic, _)) in params_with_generics.iter().enumerate() { + // Param has to have a generic and be matched to be relevant + if matched_inputs[idx.into()].is_none() { + continue; + } - for unmatching_idx in idx + 1..params_with_generics.len() { - if matched_inputs[unmatching_idx.into()].is_none() - && let Some(unmatched_idx_param_generic) = - params_with_generics[unmatching_idx].0 - && unmatched_idx_param_generic.name.ident() == generic.name.ident() - { - // We found a parameter that didn't match that needed to - return true; + let Some(generic) = generic else { + continue; + }; + + for unmatching_idx in idx + 1..params_with_generics.len() { + if matched_inputs[unmatching_idx.into()].is_none() + && let Some(unmatched_idx_param_generic) = + params_with_generics[unmatching_idx].0 + && unmatched_idx_param_generic.name.ident() + == generic.name.ident() + { + // We found a parameter that didn't match that needed to + return true; + } } } } - } - false - }; - - let check_for_matched_generics = check_for_matched_generics(); - - for (idx, (generic_param, param)) in - params_with_generics.iter().enumerate().filter(|(idx, _)| { - check_for_matched_generics - || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) - }) - { - let Some(generic_param) = generic_param else { - spans.push_span_label(param.span, ""); - continue; + false }; - let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics - .iter() - .enumerate() - .filter(|(other_idx, (other_generic_param, _))| { - if *other_idx == idx { - return false; - } - let Some(other_generic_param) = other_generic_param else { - return false; - }; - if matched_inputs[idx.into()].is_none() - && matched_inputs[(*other_idx).into()].is_none() - { - return false; - } - if matched_inputs[idx.into()].is_some() - && matched_inputs[(*other_idx).into()].is_some() - { - return false; - } - other_generic_param.name.ident() == generic_param.name.ident() + let check_for_matched_generics = check_for_matched_generics(); + + for (idx, (generic_param, param)) in + params_with_generics.iter().enumerate().filter(|(idx, _)| { + check_for_matched_generics + || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) }) - .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) - .collect(); + { + let Some(generic_param) = generic_param else { + spans.push_span_label(param.span, ""); + continue; + }; - if !other_params_matched.is_empty() { - let other_param_matched_names: Vec<String> = other_params_matched + let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics .iter() - .map(|(_, other_param)| { - if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() + .enumerate() + .filter(|(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[idx.into()].is_none() + && matched_inputs[(*other_idx).into()].is_none() + { + return false; } + if matched_inputs[idx.into()].is_some() + && matched_inputs[(*other_idx).into()].is_some() + { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() }) + .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) .collect(); - let matched_ty = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) - .sort_string(self.tcx); + if !other_params_matched.is_empty() { + let other_param_matched_names: Vec<String> = other_params_matched + .iter() + .map(|(_, other_param)| { + if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind + { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); - if matched_inputs[idx.into()].is_some() { - spans.push_span_label( - param.span, - format!( - "{} {} to match the {} type of this parameter", - display_list_with_comma_and(&other_param_matched_names), + let matched_ty = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); + + if matched_inputs[idx.into()].is_some() { + spans.push_span_label( + param.span, format!( - "need{}", - pluralize!(if other_param_matched_names.len() == 1 { - 0 - } else { - 1 - }) + "{} {} to match the {} type of this parameter", + display_list_with_comma_and(&other_param_matched_names), + format!( + "need{}", + pluralize!(if other_param_matched_names.len() == 1 { + 0 + } else { + 1 + }) + ), + matched_ty, ), - matched_ty, - ), - ); + ); + } else { + spans.push_span_label( + param.span, + format!( + "this parameter needs to match the {} type of {}", + matched_ty, + display_list_with_comma_and(&other_param_matched_names), + ), + ); + } + generics_with_unmatched_params.push(generic_param); } else { + spans.push_span_label(param.span, ""); + } + } + + for generic_param in self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.generics()) + .into_iter() + .flat_map(|x| x.params) + .filter(|x| { + generics_with_unmatched_params + .iter() + .any(|y| x.name.ident() == y.name.ident()) + }) + { + let param_idents_matching: Vec<String> = params_with_generics + .iter() + .filter(|(generic, _)| { + if let Some(generic) = generic { + generic.name.ident() == generic_param.name.ident() + } else { + false + } + }) + .map(|(_, param)| { + if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); + + if !param_idents_matching.is_empty() { spans.push_span_label( - param.span, + generic_param.span, format!( - "this parameter needs to match the {} type of {}", - matched_ty, - display_list_with_comma_and(&other_param_matched_names), + "{} all reference this parameter {}", + display_list_with_comma_and(¶m_idents_matching), + generic_param.name.ident().name, ), ); } - generics_with_unmatched_params.push(generic_param); - } else { - spans.push_span_label(param.span, ""); } } - - for generic_param in self - .tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.generics()) - .into_iter() - .flat_map(|x| x.params) - .filter(|x| { - generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident()) - }) - { - let param_idents_matching: Vec<String> = params_with_generics - .iter() - .filter(|(generic, _)| { - if let Some(generic) = generic { - generic.name.ident() == generic_param.name.ident() - } else { - false - } - }) - .map(|(_, param)| { - if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() - } - }) - .collect(); - - if !param_idents_matching.is_empty() { - spans.push_span_label( - generic_param.span, - format!( - "{} all reference this parameter {}", - display_list_with_comma_and(¶m_idents_matching), - generic_param.name.ident().name, - ), - ); - } - } - err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind @@ -2535,74 +2553,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); - - for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { - if matched_inputs[idx.into()].is_none() { - continue; - } + if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) { + debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); + for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { + if matched_inputs[idx.into()].is_none() { + continue; + } - let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { - continue; - }; + let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { + continue; + }; - let Some(generic_param) = generic_param else { - continue; - }; + let Some(generic_param) = generic_param else { + continue; + }; - let mut idxs_matched: Vec<usize> = vec![]; - for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( - |(other_idx, (other_generic_param, _))| { - if *other_idx == idx { - return false; - } - let Some(other_generic_param) = other_generic_param else { - return false; - }; - if matched_inputs[(*other_idx).into()].is_some() { - return false; - } - other_generic_param.name.ident() == generic_param.name.ident() - }, - ) { - idxs_matched.push(other_idx); - } + let mut idxs_matched: Vec<usize> = vec![]; + for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( + |(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[(*other_idx).into()].is_some() { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() + }, + ) { + idxs_matched.push(other_idx); + } - if idxs_matched.is_empty() { - continue; - } + if idxs_matched.is_empty() { + continue; + } - let expected_display_type = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) - .sort_string(self.tcx); - let label = if idxs_matched.len() == params_with_generics.len() - 1 { - format!( - "expected all arguments to be this {} type because they need to match the type of this parameter", - expected_display_type - ) - } else { - format!( - "expected some other arguments to be {} {} type to match the type of this parameter", - a_or_an(&expected_display_type), - expected_display_type, - ) - }; + let expected_display_type = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); + let label = if idxs_matched.len() == params_with_generics.len() - 1 { + format!( + "expected all arguments to be this {} type because they need to match the type of this parameter", + expected_display_type + ) + } else { + format!( + "expected some other arguments to be {} {} type to match the type of this parameter", + a_or_an(&expected_display_type), + expected_display_type, + ) + }; - err.span_label(*matched_arg_span, label); + err.span_label(*matched_arg_span, label); + } } } + /// Returns the parameters of a function, with their generic parameters if those are the full + /// type of that parameter. Returns `None` if the function body is unavailable (eg is an instrinsic). fn get_hir_params_with_generics( &self, def_id: DefId, is_method: bool, - ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> { - let fn_node = self.tcx.hir().get_if_local(def_id); + ) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> { + let fn_node = self.tcx.hir().get_if_local(def_id)?; let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node - .and_then(|node| node.fn_decl()) + .fn_decl()? + .inputs .into_iter() - .flat_map(|decl| decl.inputs) .skip(if is_method { 1 } else { 0 }) .map(|param| { if let hir::TyKind::Path(QPath::Resolved( @@ -2611,7 +2632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )) = param.kind { fn_node - .and_then(|node| node.generics()) + .generics() .into_iter() .flat_map(|generics| generics.params) .find(|param| ¶m.def_id.to_def_id() == res_def_id) @@ -2621,14 +2642,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(); - let params: Vec<&hir::Param<'_>> = fn_node - .and_then(|node| node.body_id()) + let params: Vec<&hir::Param<'_>> = self + .tcx + .hir() + .body(fn_node.body_id()?) + .params .into_iter() - .flat_map(|id| self.tcx.hir().body(id).params) .skip(if is_method { 1 } else { 0 }) .collect(); - generic_params.into_iter().zip(params).collect() + Some(generic_params.into_iter().zip_eq(params).collect()) } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 25f9340eeb7..c8c95ddcfce 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -83,7 +83,7 @@ struct TopInfo<'tcx> { } #[derive(Copy, Clone)] -struct PatInfo<'tcx, 'a> { +struct PatInfo<'a, 'tcx> { binding_mode: ByRef, max_ref_mutbl: MutblCap, top_info: &'a TopInfo<'tcx>, @@ -222,7 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] - fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) { + fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) { let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; let path_res = match &pat.kind { @@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ident: Ident, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info; @@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { @@ -1184,7 +1184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let on_error = |e| { @@ -1441,7 +1441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1479,7 +1479,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx; @@ -2070,7 +2070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = self @@ -2096,7 +2096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; // Register a `DerefPure` bound, which is required by all `deref!()` pats. @@ -2137,7 +2137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, pat_mutbl: Mutability, mut expected: Ty<'tcx>, - mut pat_info: PatInfo<'tcx, '_>, + mut pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let features = tcx.features(); @@ -2345,7 +2345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let expected = self.try_structurally_resolve_type(span, expected); @@ -2517,7 +2517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, expected_ty: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, + pat_info: PatInfo<'_, 'tcx>, ) -> ErrorGuaranteed { let PatInfo { top_info: ti, current_depth, .. } = pat_info; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c4a38047b5e..b93bc3ed84f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -788,7 +788,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { rustc_hir_analysis::check_crate(tcx); sess.time("MIR_coroutine_by_move_body", || { tcx.hir().par_body_owners(|def_id| { - if tcx.needs_coroutine_by_move_body_def_id(def_id) { + if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) { tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id); } }); diff --git a/compiler/rustc_lint/src/async_closures.rs b/compiler/rustc_lint/src/async_closures.rs index 33cc5738262..2a821b71103 100644 --- a/compiler/rustc_lint/src/async_closures.rs +++ b/compiler/rustc_lint/src/async_closures.rs @@ -12,6 +12,7 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(async_closure)] /// #![warn(closure_returning_async_block)] /// let c = |x: &str| async {}; /// ``` diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index a60fc0ffbbb..33b8b7c544b 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -3,8 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::query::Providers; -use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::FIRST_VARIANT; @@ -212,7 +211,17 @@ fn structurally_same_type<'tcx>( ckind: types::CItemKind, ) -> bool { let mut seen_types = UnordSet::default(); - structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind) + let result = structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind); + if cfg!(debug_assertions) && result { + // Sanity-check: must have same ABI, size and alignment. + // `extern` blocks cannot be generic, so we'll always get a layout here. + let a_layout = tcx.layout_of(param_env.and(a)).unwrap(); + let b_layout = tcx.layout_of(param_env.and(b)).unwrap(); + assert_eq!(a_layout.abi, b_layout.abi); + assert_eq!(a_layout.size, b_layout.size); + assert_eq!(a_layout.align, b_layout.align); + } + result } fn structurally_same_type_impl<'tcx>( @@ -266,30 +275,21 @@ fn structurally_same_type_impl<'tcx>( // Do a full, depth-first comparison between the two. use rustc_type_ir::TyKind::*; - let compare_layouts = |a, b| -> Result<bool, &'tcx LayoutError<'tcx>> { - debug!("compare_layouts({:?}, {:?})", a, b); - let a_layout = &tcx.layout_of(param_env.and(a))?.layout.abi(); - let b_layout = &tcx.layout_of(param_env.and(b))?.layout.abi(); - debug!( - "comparing layouts: {:?} == {:?} = {}", - a_layout, - b_layout, - a_layout == b_layout - ); - Ok(a_layout == b_layout) - }; - let is_primitive_or_pointer = |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), RawPtr(..) | Ref(..)); ensure_sufficient_stack(|| { match (a.kind(), b.kind()) { - (Adt(a_def, _), Adt(b_def, _)) => { - // We can immediately rule out these types as structurally same if - // their layouts differ. - match compare_layouts(a, b) { - Ok(false) => return false, - _ => (), // otherwise, continue onto the full, fields comparison + (&Adt(a_def, _), &Adt(b_def, _)) => { + // Only `repr(C)` types can be compared structurally. + if !(a_def.repr().c() && b_def.repr().c()) { + return false; + } + // If the types differ in their packed-ness, align, or simd-ness they conflict. + let repr_characteristica = + |def: AdtDef<'tcx>| (def.repr().pack, def.repr().align, def.repr().simd()); + if repr_characteristica(a_def) != repr_characteristica(b_def) { + return false; } // Grab a flattened representation of all fields. @@ -311,9 +311,9 @@ fn structurally_same_type_impl<'tcx>( }, ) } - (Array(a_ty, a_const), Array(b_ty, b_const)) => { - // For arrays, we also check the constness of the type. - a_const.kind() == b_const.kind() + (Array(a_ty, a_len), Array(b_ty, b_len)) => { + // For arrays, we also check the length. + a_len == b_len && structurally_same_type_impl( seen_types, tcx, param_env, *a_ty, *b_ty, ckind, ) @@ -357,10 +357,9 @@ fn structurally_same_type_impl<'tcx>( ckind, ) } - (Tuple(a_args), Tuple(b_args)) => { - a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| { - structurally_same_type_impl(seen_types, tcx, param_env, a_ty, b_ty, ckind) - }) + (Tuple(..), Tuple(..)) => { + // Tuples are not `repr(C)` so these cannot be compared structurally. + false } // For these, it's not quite as easy to define structural-sameness quite so easily. // For the purposes of this lint, take the conservative approach and mark them as @@ -380,24 +379,21 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. (Adt(..), _) if is_primitive_or_pointer(b) => { - if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, a, ckind) { - ty == b + if let Some(a_inner) = types::repr_nullable_ptr(tcx, param_env, a, ckind) { + a_inner == b } else { - compare_layouts(a, b).unwrap_or(false) + false } } (_, Adt(..)) if is_primitive_or_pointer(a) => { - if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, b, ckind) { - ty == a + if let Some(b_inner) = types::repr_nullable_ptr(tcx, param_env, b, ckind) { + b_inner == a } else { - compare_layouts(a, b).unwrap_or(false) + false } } - // Otherwise, just compare the layouts. This may fail to lint for some - // incompatible types, but at the very least, will stop reads into - // uninitialised memory. - _ => compare_layouts(a, b).unwrap_or(false), + _ => false, } }) } diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 5b65541bea6..7138d40a48f 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -24,7 +24,7 @@ declare_lint! { /// ### Example /// /// ```rust,edition2021 - /// #![feature(if_let_rescope)] + /// #![cfg_attr(not(bootstrap), feature(if_let_rescope))] // Simplify this in bootstrap bump. /// #![warn(if_let_rescope)] /// #![allow(unused_variables)] /// diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 65289de980e..796d66f13d4 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -255,11 +255,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { intravisit::walk_foreign_item(self, it); } - fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { - // We will call `add_id` when we walk - // the `StmtKind`. The outer statement itself doesn't - // define the lint levels. - intravisit::walk_stmt(self, e); + fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { + self.add_id(s.hir_id); + intravisit::walk_stmt(self, s); } fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0c32157758c..5c67e21687f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -579,6 +579,10 @@ fn register_builtins(store: &mut LintStore) { <https://github.com/rust-lang/rust/issues/107457> for more information", ); store.register_removed("writes_through_immutable_pointer", "converted into hard error"); + store.register_removed( + "const_eval_mutable_ptr_in_final_value", + "partially allowed now, otherwise turned into a hard error", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index e49b102cb39..a2ccb93347a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -267,16 +267,16 @@ pub(crate) struct MacroExprFragment2024 { pub suggestion: Span, } -pub(crate) struct BuiltinTypeAliasBounds<'a, 'hir> { +pub(crate) struct BuiltinTypeAliasBounds<'hir> { pub in_where_clause: bool, pub label: Span, pub enable_feat_help: bool, pub suggestions: Vec<(Span, String)>, pub preds: &'hir [hir::WherePredicate<'hir>], - pub ty: Option<&'a hir::Ty<'hir>>, + pub ty: Option<&'hir hir::Ty<'hir>>, } -impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_, '_> { +impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { diag.primary_message(if self.in_where_clause { fluent::lint_builtin_type_alias_bounds_where_clause diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs index f9ecc8c9806..91f3e2e3bb6 100644 --- a/compiler/rustc_lint/src/tail_expr_drop_order.rs +++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs @@ -143,18 +143,18 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { } } -struct LintVisitor<'tcx, 'a> { +struct LintVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, // We only record locals that have significant drops locals: Vec<Span>, } -struct LocalCollector<'tcx, 'a> { +struct LocalCollector<'a, 'tcx> { cx: &'a LateContext<'tcx>, locals: &'a mut Vec<Span>, } -impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for LocalCollector<'a, 'tcx> { type Result = (); fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind { @@ -171,7 +171,7 @@ impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> { } } -impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'tcx>) { let mut locals = <_>::default(); swap(&mut locals, &mut self.locals); @@ -183,7 +183,7 @@ impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> { } } -impl<'tcx, 'a> LintVisitor<'tcx, 'a> { +impl<'a, 'tcx> LintVisitor<'a, 'tcx> { fn check_block_inner(&mut self, block: &Block<'tcx>) { if !block.span.at_least_rust_2024() { // We only lint for Edition 2024 onwards @@ -205,13 +205,13 @@ impl<'tcx, 'a> LintVisitor<'tcx, 'a> { } } -struct LintTailExpr<'tcx, 'a> { +struct LintTailExpr<'a, 'tcx> { cx: &'a LateContext<'tcx>, is_root_tail_expr: bool, locals: &'a [Span], } -impl<'tcx, 'a> LintTailExpr<'tcx, 'a> { +impl<'a, 'tcx> LintTailExpr<'a, 'tcx> { fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool { loop { match expr.kind { @@ -239,7 +239,7 @@ impl<'tcx, 'a> LintTailExpr<'tcx, 'a> { } } -impl<'tcx, 'a> Visitor<'tcx> for LintTailExpr<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if self.is_root_tail_expr { self.is_root_tail_expr = false; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index b5e501b92f0..900c496e033 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1713,13 +1713,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { hir_ty: &hir::Ty<'tcx>, ty: Ty<'tcx>, ) -> Vec<(Ty<'tcx>, Span)> { - struct FnPtrFinder<'parent, 'a, 'tcx> { - visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>, + struct FnPtrFinder<'a, 'b, 'tcx> { + visitor: &'a ImproperCTypesVisitor<'b, 'tcx>, spans: Vec<Span>, tys: Vec<Ty<'tcx>>, } - impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> { + impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> { fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) { debug!(?ty); if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind @@ -1732,7 +1732,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'vis, 'a, 'tcx> { + impl<'a, 'b, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'a, 'b, 'tcx> { type Result = ControlFlow<Ty<'tcx>>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { @@ -1746,7 +1746,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() }; + let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() }; ty.visit_with(&mut visitor); hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 25d33126754..9b6d63c2ef4 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -29,7 +29,6 @@ declare_lint_pass! { CENUM_IMPL_DROP_CAST, COHERENCE_LEAK_CHECK, CONFLICTING_REPR_HINTS, - CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, DEAD_CODE, @@ -1871,6 +1870,7 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail + /// # #[cfg_attr(bootstrap)] compile_error!(); // Remove this in bootstrap bump. /// #![deny(elided_named_lifetimes)] /// struct Foo; /// impl Foo { @@ -2805,51 +2805,6 @@ declare_lint! { } declare_lint! { - /// The `const_eval_mutable_ptr_in_final_value` lint detects if a mutable pointer - /// has leaked into the final value of a const expression. - /// - /// ### Example - /// - /// ```rust - /// pub enum JsValue { - /// Undefined, - /// Object(std::cell::Cell<bool>), - /// } - /// - /// impl ::std::ops::Drop for JsValue { - /// fn drop(&mut self) {} - /// } - /// - /// const UNDEFINED: &JsValue = &JsValue::Undefined; - /// - /// fn main() { - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// In the 1.77 release, the const evaluation machinery adopted some - /// stricter rules to reject expressions with values that could - /// end up holding mutable references to state stored in static memory - /// (which is inherently immutable). - /// - /// This is a [future-incompatible] lint to ease the transition to an error. - /// See [issue #122153] for more details. - /// - /// [issue #122153]: https://github.com/rust-lang/rust/issues/122153 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - Warn, - "detects a mutable pointer that has leaked into final value of a const expression", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #122153 <https://github.com/rust-lang/rust/issues/122153>", - }; -} - -declare_lint! { /// The `const_evaluatable_unchecked` lint detects a generic constant used /// in a type. /// diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 6cfd07d699c..1700b0f02ec 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -80,14 +80,23 @@ pub trait Provenance: Copy + fmt::Debug + 'static { } /// The type of provenance in the compile-time interpreter. -/// This is a packed representation of an `AllocId` and an `immutable: bool`. +/// This is a packed representation of: +/// - an `AllocId` (non-zero) +/// - an `immutable: bool` +/// - a `shared_ref: bool` +/// +/// with the extra invariant that if `immutable` is `true`, then so +/// is `shared_ref`. #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct CtfeProvenance(NonZero<u64>); impl From<AllocId> for CtfeProvenance { fn from(value: AllocId) -> Self { let prov = CtfeProvenance(value.0); - assert!(!prov.immutable(), "`AllocId` with the highest bit set cannot be used in CTFE"); + assert!( + prov.alloc_id() == value, + "`AllocId` with the highest bits set cannot be used in CTFE" + ); prov } } @@ -103,12 +112,14 @@ impl fmt::Debug for CtfeProvenance { } const IMMUTABLE_MASK: u64 = 1 << 63; // the highest bit +const SHARED_REF_MASK: u64 = 1 << 62; +const ALLOC_ID_MASK: u64 = u64::MAX & !IMMUTABLE_MASK & !SHARED_REF_MASK; impl CtfeProvenance { /// Returns the `AllocId` of this provenance. #[inline(always)] pub fn alloc_id(self) -> AllocId { - AllocId(NonZero::new(self.0.get() & !IMMUTABLE_MASK).unwrap()) + AllocId(NonZero::new(self.0.get() & ALLOC_ID_MASK).unwrap()) } /// Returns whether this provenance is immutable. @@ -117,10 +128,38 @@ impl CtfeProvenance { self.0.get() & IMMUTABLE_MASK != 0 } + /// Returns whether this provenance is derived from a shared reference. + #[inline] + pub fn shared_ref(self) -> bool { + self.0.get() & SHARED_REF_MASK != 0 + } + + pub fn into_parts(self) -> (AllocId, bool, bool) { + (self.alloc_id(), self.immutable(), self.shared_ref()) + } + + pub fn from_parts((alloc_id, immutable, shared_ref): (AllocId, bool, bool)) -> Self { + let prov = CtfeProvenance::from(alloc_id); + if immutable { + // This sets both flags, so we don't even have to check `shared_ref`. + prov.as_immutable() + } else if shared_ref { + prov.as_shared_ref() + } else { + prov + } + } + /// Returns an immutable version of this provenance. #[inline] pub fn as_immutable(self) -> Self { - CtfeProvenance(self.0 | IMMUTABLE_MASK) + CtfeProvenance(self.0 | IMMUTABLE_MASK | SHARED_REF_MASK) + } + + /// Returns a "shared reference" (but not necessarily immutable!) version of this provenance. + #[inline] + pub fn as_shared_ref(self) -> Self { + CtfeProvenance(self.0 | SHARED_REF_MASK) } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 22a4b688c51..f5590aa2762 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1094,7 +1094,7 @@ pub struct Place<'tcx> { pub projection: &'tcx List<PlaceElem<'tcx>>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum ProjectionElem<V, T> { Deref, @@ -1468,7 +1468,7 @@ pub enum NullOp<'tcx> { UbChecks, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum UnOp { /// The `!` operator for logical inversion @@ -1486,7 +1486,7 @@ pub enum UnOp { PtrMetadata, } -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum BinOp { /// The `+` operator (addition) diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 46203ee150f..7e533bc4291 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -165,8 +165,7 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId { impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for CtfeProvenance { fn encode(&self, e: &mut E) { - self.alloc_id().encode(e); - self.immutable().encode(e); + self.into_parts().encode(e); } } @@ -295,10 +294,8 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId { impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CtfeProvenance { fn decode(decoder: &mut D) -> Self { - let alloc_id: AllocId = Decodable::decode(decoder); - let prov = CtfeProvenance::from(alloc_id); - let immutable: bool = Decodable::decode(decoder); - if immutable { prov.as_immutable() } else { prov } + let parts = Decodable::decode(decoder); + CtfeProvenance::from_parts(parts) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5ec7e80ee45..cd06d7b8e53 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3171,7 +3171,7 @@ impl<'tcx> TyCtxt<'tcx> { self.impl_trait_header(def_id).map_or(ty::ImplPolarity::Positive, |h| h.polarity) } - pub fn needs_coroutine_by_move_body_def_id(self, def_id: LocalDefId) -> bool { + pub fn needs_coroutine_by_move_body_def_id(self, def_id: DefId) -> bool { if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) = self.coroutine_kind(def_id) && let ty::Coroutine(_, args) = self.type_of(def_id).instantiate_identity().kind() diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index b5b7b8bcfef..5f6305bb48a 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -75,11 +75,9 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId { } } -// CtfeProvenance is an AllocId and a bool. impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::CtfeProvenance { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.alloc_id().hash_stable(hcx, hasher); - self.immutable().hash_stable(hcx, hasher); + self.into_parts().hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 7a10e627ccd..1c4e9fd11cb 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -338,6 +338,7 @@ mir_build_unreachable_pattern = unreachable pattern .unreachable_covered_by_catchall = matches any value .unreachable_covered_by_one = matches all the relevant values .unreachable_covered_by_many = multiple earlier patterns match some of the same values + .suggestion = remove the match arm mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index 28477e527c7..1e1fa21b5f3 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -134,13 +134,12 @@ fn parse_attribute(attr: &Attribute) -> MirPhase { MirPhase::parse(dialect, phase) } -struct ParseCtxt<'tcx, 'body> { +struct ParseCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - thir: &'body Thir<'tcx>, + thir: &'a Thir<'tcx>, source_scope: SourceScope, - - body: &'body mut Body<'tcx>, + body: &'a mut Body<'tcx>, local_map: FxHashMap<LocalVarId, Local>, block_map: FxHashMap<LocalVarId, BasicBlock>, } @@ -151,7 +150,7 @@ struct ParseError { expected: String, } -impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { +impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError { let expr = &self.thir[expr]; ParseError { diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index 1f186c8f99a..538068e1fac 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -68,7 +68,7 @@ macro_rules! parse_by_kind { } pub(crate) use parse_by_kind; -impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { +impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { /// Expressions should only ever be matched on after preparsing them. This removes extra scopes /// we don't care about. fn preparse(&self, expr_id: ExprId) -> ExprId { diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 0b13ceb574d..0cbd2da10db 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -12,7 +12,7 @@ use super::{parse_by_kind, PResult, ParseCtxt}; use crate::build::custom::ParseError; use crate::build::expr::as_constant::as_constant_inner; -impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { +impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { pub(crate) fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> { parse_by_kind!(self, expr_id, _, "statement", @call(mir_storage_live, args) => { diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 7f9eefd1d52..411e9420914 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -598,6 +598,8 @@ pub(crate) struct UnreachablePattern<'tcx> { #[note(mir_build_unreachable_covered_by_many)] pub(crate) covered_by_many: Option<MultiSpan>, pub(crate) covered_by_many_n_more_count: usize, + #[suggestion(code = "", applicability = "machine-applicable")] + pub(crate) suggest_remove: Option<Span>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 4c066a68ef9..3fde6466d8c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -413,7 +413,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // Emit lints in the order in which they occur in the file. redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span); for (pat, explanation) in redundant_subpats { - report_unreachable_pattern(cx, arm.arm_data, pat, &explanation) + report_unreachable_pattern(cx, arm.arm_data, pat, &explanation, None) } } } @@ -474,7 +474,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { hir::MatchSource::ForLoopDesugar | hir::MatchSource::Postfix | hir::MatchSource::Normal - | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report), + | hir::MatchSource::FormatArgs => { + let is_match_arm = + matches!(source, hir::MatchSource::Postfix | hir::MatchSource::Normal); + report_arm_reachability(&cx, &report, is_match_arm); + } // Unreachable patterns in try and await expressions occur when one of // the arms are an uninhabited type. Which is OK. hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar(_) => {} @@ -626,7 +630,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { ) -> Result<RefutableFlag, ErrorGuaranteed> { let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?; // Report if the pattern is unreachable, which can only occur when the type is uninhabited. - report_arm_reachability(&cx, &report); + report_arm_reachability(&cx, &report, false); // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is // irrefutable. Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable }) @@ -916,6 +920,7 @@ fn report_unreachable_pattern<'p, 'tcx>( hir_id: HirId, pat: &DeconstructedPat<'p, 'tcx>, explanation: &RedundancyExplanation<'p, 'tcx>, + whole_arm_span: Option<Span>, ) { static CAP_COVERED_BY_MANY: usize = 4; let pat_span = pat.data().span; @@ -928,6 +933,7 @@ fn report_unreachable_pattern<'p, 'tcx>( covered_by_one: None, covered_by_many: None, covered_by_many_n_more_count: 0, + suggest_remove: None, }; match explanation.covered_by.as_slice() { [] => { @@ -935,6 +941,7 @@ fn report_unreachable_pattern<'p, 'tcx>( lint.span = None; // Don't label the pattern itself lint.uninhabited_note = Some(()); // Give a link about empty types lint.matches_no_values = Some(pat_span); + lint.suggest_remove = whole_arm_span; // Suggest to remove the match arm pat.walk(&mut |subpat| { let ty = **subpat.ty(); if cx.is_uninhabited(ty) { @@ -982,10 +989,28 @@ fn report_unreachable_pattern<'p, 'tcx>( } /// Report unreachable arms, if any. -fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) { +fn report_arm_reachability<'p, 'tcx>( + cx: &PatCtxt<'p, 'tcx>, + report: &UsefulnessReport<'p, 'tcx>, + is_match_arm: bool, +) { + let sm = cx.tcx.sess.source_map(); for (arm, is_useful) in report.arm_usefulness.iter() { if let Usefulness::Redundant(explanation) = is_useful { - report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation) + let hir_id = arm.arm_data; + let arm_span = cx.tcx.hir().span(hir_id); + let whole_arm_span = if is_match_arm { + // If the arm is followed by a comma, extend the span to include it. + let with_whitespace = sm.span_extend_while_whitespace(arm_span); + if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) { + Some(arm_span.to(comma)) + } else { + Some(arm_span) + } + } else { + None + }; + report_unreachable_pattern(cx, hir_id, arm.pat, explanation, whole_arm_span) } } } diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index d7e738b8829..c4d06cbb1b0 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -155,11 +155,11 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug { } #[derive(Debug)] -struct DropCtxt<'l, 'b, 'tcx, D> +struct DropCtxt<'a, 'b, 'tcx, D> where D: DropElaborator<'b, 'tcx>, { - elaborator: &'l mut D, + elaborator: &'a mut D, source_info: SourceInfo, @@ -192,7 +192,7 @@ pub fn elaborate_drop<'b, 'tcx, D>( DropCtxt { elaborator, source_info, place, path, succ, unwind }.elaborate_drop(bb) } -impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> +impl<'a, 'b, 'tcx, D> DropCtxt<'a, 'b, 'tcx, D> where D: DropElaborator<'b, 'tcx>, 'tcx: 'b, diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index ba4a7d76511..88a9a78f8ad 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -42,14 +42,14 @@ pub trait Direction { ) where A: GenKillAnalysis<'tcx>; - fn visit_results_in_block<'mir, 'tcx, F, R>( - state: &mut F, + fn visit_results_in_block<'mir, 'tcx, D, R>( + state: &mut D, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>; + R: ResultsVisitable<'tcx, Domain = D>; fn join_state_into_successors_of<'tcx, A>( analysis: &mut A, @@ -186,14 +186,14 @@ impl Direction for Backward { analysis.apply_statement_effect(state, statement, location); } - fn visit_results_in_block<'mir, 'tcx, F, R>( - state: &mut F, + fn visit_results_in_block<'mir, 'tcx, D, R>( + state: &mut D, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = D>, { results.reset_to_block_entry(state, block); @@ -444,9 +444,9 @@ impl Direction for Forward { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = F>, { results.reset_to_block_entry(state, block); diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 0bab03b0271..54206501d9f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -57,7 +57,7 @@ where &mut self, body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator<Item = BasicBlock>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { visit_results(body, blocks, self, vis) } @@ -65,7 +65,7 @@ where pub fn visit_reachable_with<'mir>( &mut self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 2e860e2d841..e72dca2c834 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -544,15 +544,15 @@ where A: Analysis<'tcx>, A::Domain: DebugWithContext<A>, { - type FlowState = A::Domain; + type Domain = A::Domain; - fn visit_block_start(&mut self, state: &Self::FlowState) { + fn visit_block_start(&mut self, state: &Self::Domain) { if A::Direction::IS_FORWARD { self.prev_state.clone_from(state); } } - fn visit_block_end(&mut self, state: &Self::FlowState) { + fn visit_block_end(&mut self, state: &Self::Domain) { if A::Direction::IS_BACKWARD { self.prev_state.clone_from(state); } @@ -561,7 +561,7 @@ where fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -574,7 +574,7 @@ where fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -585,7 +585,7 @@ where fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { @@ -598,7 +598,7 @@ where fn visit_terminator_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 8b8a16bda99..3d6b008a684 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results}; /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the /// dataflow state at that location. -pub fn visit_results<'mir, 'tcx, F, R>( +pub fn visit_results<'mir, 'tcx, D, R>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator<Item = BasicBlock>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = D>, { - let mut state = results.new_flow_state(body); + let mut state = results.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -29,16 +29,16 @@ pub fn visit_results<'mir, 'tcx, F, R>( /// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being /// visited. pub trait ResultsVisitor<'mir, 'tcx, R> { - type FlowState; + type Domain; - fn visit_block_start(&mut self, _state: &Self::FlowState) {} + fn visit_block_start(&mut self, _state: &Self::Domain) {} /// Called with the `before_statement_effect` of the given statement applied to `state` but not /// its `statement_effect`. fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { @@ -49,7 +49,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_statement_after_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { @@ -60,7 +60,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { @@ -73,13 +73,13 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { } - fn visit_block_end(&mut self, _state: &Self::FlowState) {} + fn visit_block_end(&mut self, _state: &Self::Domain) {} } /// Things that can be visited by a `ResultsVisitor`. @@ -88,40 +88,40 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// simultaneously. pub trait ResultsVisitable<'tcx> { type Direction: Direction; - type FlowState; + type Domain; - /// Creates an empty `FlowState` to hold the transient state for these dataflow results. + /// Creates an empty `Domain` to hold the transient state for these dataflow results. /// - /// The value of the newly created `FlowState` will be overwritten by `reset_to_block_entry` + /// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry` /// before it can be observed by a `ResultsVisitor`. - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState; + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock); + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock); fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); @@ -131,21 +131,20 @@ impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> where A: Analysis<'tcx>, { - type FlowState = A::Domain; - + type Domain = A::Domain; type Direction = A::Direction; - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { self.analysis.bottom_value(body) } - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { state.clone_from(self.entry_set_for_block(block)); } fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -154,7 +153,7 @@ where fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -163,7 +162,7 @@ where fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -172,7 +171,7 @@ where fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index e8e78fb8a89..8b082ef2667 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -11,7 +11,7 @@ use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; /// 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, Copy)] +#[derive(Clone)] pub struct MaybeBorrowedLocals; impl MaybeBorrowedLocals { diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 24a4b32ceb7..1559c131a37 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -217,7 +217,6 @@ impl DefUse { /// This is basically written for dead store elimination and nothing else. /// /// All of the caveats of `MaybeLiveLocals` apply. -#[derive(Clone, Copy)] pub struct MaybeTransitiveLiveLocals<'a> { always_live: &'a BitSet<Local>, } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 9f2f0187698..34ac5809a2e 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -7,7 +7,6 @@ use rustc_middle::mir::*; use super::MaybeBorrowedLocals; use crate::{GenKill, ResultsCursor}; -#[derive(Clone)] pub struct MaybeStorageLive<'a> { always_live_locals: Cow<'a, BitSet<Local>>, } @@ -18,7 +17,7 @@ impl<'a> MaybeStorageLive<'a> { } } -impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { +impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { type Domain = BitSet<Local>; const NAME: &'static str = "maybe_storage_live"; @@ -40,7 +39,7 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { } } -impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { +impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { type Idx = Local; fn domain_size(&self, body: &Body<'tcx>) -> usize { @@ -80,7 +79,6 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { } } -#[derive(Clone)] pub struct MaybeStorageDead<'a> { always_live_locals: Cow<'a, BitSet<Local>>, } @@ -91,7 +89,7 @@ impl<'a> MaybeStorageDead<'a> { } } -impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { +impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { type Domain = BitSet<Local>; const NAME: &'static str = "maybe_storage_dead"; @@ -112,7 +110,7 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { } } -impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { +impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { type Idx = Local; fn domain_size(&self, body: &Body<'tcx>) -> usize { diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 4be7492366a..adfa94464a0 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -102,7 +102,7 @@ pub fn save_as_intervals<'tcx, N, R>( ) -> SparseIntervalMatrix<N, PointIndex> where N: Idx, - R: ResultsVisitable<'tcx, FlowState = BitSet<N>>, + R: ResultsVisitable<'tcx, Domain = BitSet<N>>, { let values = SparseIntervalMatrix::new(elements.num_points()); let mut visitor = Visitor { elements, values }; @@ -124,12 +124,12 @@ impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N> where N: Idx, { - type FlowState = BitSet<N>; + type Domain = BitSet<N>; fn visit_statement_after_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, location: Location, ) { @@ -143,7 +143,7 @@ where fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::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 8c3e6f49b16..ac9b853f21b 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -229,7 +229,7 @@ trait RustcPeekAt<'tcx>: Analysis<'tcx> { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &Self::Domain, + state: &Self::Domain, call: PeekCall, ); } @@ -243,12 +243,12 @@ where &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &Self::Domain, + state: &Self::Domain, call: PeekCall, ) { match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(peek_mpi) => { - let bit_state = flow_state.contains(peek_mpi); + let bit_state = state.contains(peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state); if !bit_state { tcx.dcx().emit_err(PeekBitNotSet { span: call.span }); @@ -267,7 +267,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &BitSet<Local>, + state: &BitSet<Local>, call: PeekCall, ) { info!(?place, "peek_at"); @@ -276,7 +276,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { return; }; - if !flow_state.contains(local) { + if !state.contains(local) { tcx.dcx().emit_err(PeekBitNotSet { span: call.span }); } } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index e1d5152ae51..a9600f77c0b 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -62,14 +62,14 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { } } -struct PointerFinder<'tcx, 'a> { +struct PointerFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a mut LocalDecls<'tcx>, param_env: ParamEnv<'tcx>, pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, } -impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { // We want to only check reads and writes to Places, so we specifically exclude // Borrow and RawBorrow. diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 90243cd2910..1fb74f5d82c 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -885,12 +885,12 @@ struct StorageConflictVisitor<'a, 'tcx> { impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> for StorageConflictVisitor<'a, 'tcx> { - type FlowState = BitSet<Local>; + type Domain = BitSet<Local>; fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _statement: &'a Statement<'tcx>, loc: Location, ) { @@ -900,7 +900,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &'a Terminator<'tcx>, loc: Location, ) { @@ -909,13 +909,13 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> } impl StorageConflictVisitor<'_, '_> { - fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) { + fn apply_state(&mut self, state: &BitSet<Local>, loc: Location) { // Ignore unreachable blocks. if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind { return; } - self.eligible_storage_live.clone_from(flow_state); + self.eligible_storage_live.clone_from(state); self.eligible_storage_live.intersect(&**self.saved_locals); for local in self.eligible_storage_live.iter() { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 7ac019ce812..997b8c06a96 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -554,13 +554,13 @@ impl<'tcx> Patch<'tcx> { } } -struct Collector<'tcx, 'locals> { +struct Collector<'a, 'tcx> { patch: Patch<'tcx>, - local_decls: &'locals LocalDecls<'tcx>, + local_decls: &'a LocalDecls<'tcx>, } -impl<'tcx, 'locals> Collector<'tcx, 'locals> { - pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self { +impl<'a, 'tcx> Collector<'a, 'tcx> { + pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>) -> Self { Self { patch: Patch::new(tcx), local_decls } } @@ -722,15 +722,15 @@ fn try_write_constant<'tcx>( impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>> - for Collector<'tcx, '_> + for Collector<'_, 'tcx> { - type FlowState = State<FlatSet<Scalar>>; + type Domain = State<FlatSet<Scalar>>; #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, - state: &Self::FlowState, + state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -752,7 +752,7 @@ impl<'mir, 'tcx> fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, - state: &Self::FlowState, + state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -777,7 +777,7 @@ impl<'mir, 'tcx> fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, - state: &Self::FlowState, + state: &Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, ) { @@ -839,9 +839,9 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> { } } -struct OperandCollector<'a, 'locals, 'tcx> { +struct OperandCollector<'a, 'b, 'tcx> { state: &'a State<FlatSet<Scalar>>, - visitor: &'a mut Collector<'tcx, 'locals>, + visitor: &'a mut Collector<'b, 'tcx>, ecx: &'a mut InterpCx<'tcx, DummyMachine>, map: &'a Map<'tcx>, } diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index ad204e76d0d..26b28c8c487 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -98,7 +98,7 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap<BasicBlock, BasicBlock> { duplicates } -struct BasicBlockHashable<'tcx, 'a> { +struct BasicBlockHashable<'a, 'tcx> { basic_block_data: &'a BasicBlockData<'tcx>, } diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index 367a8c07593..57f7a9ef7f5 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -38,7 +38,7 @@ pub(super) fn build_projection<'tcx>( ] } -struct ElaborateBoxDerefVisitor<'tcx, 'a> { +struct ElaborateBoxDerefVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, unique_did: DefId, nonnull_did: DefId, @@ -46,7 +46,7 @@ struct ElaborateBoxDerefVisitor<'tcx, 'a> { patch: MirPatch<'tcx>, } -impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { +impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 9a93c3a72b1..4550ef06315 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -89,7 +89,7 @@ pub(crate) struct FnItemRef { pub ident: String, } -pub(crate) struct MustNotSupend<'tcx, 'a> { +pub(crate) struct MustNotSupend<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, pub yield_sp: Span, pub reason: Option<MustNotSuspendReason>, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 598bf61483d..0f08d920c5e 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -875,6 +875,95 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { None } + fn try_as_place_elem( + &mut self, + proj: ProjectionElem<VnIndex, Ty<'tcx>>, + loc: Location, + ) -> Option<PlaceElem<'tcx>> { + Some(match proj { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Field(idx, ty) => ProjectionElem::Field(idx, ty), + ProjectionElem::Index(idx) => { + let Some(local) = self.try_as_local(idx, loc) else { + return None; + }; + self.reused_locals.insert(local); + ProjectionElem::Index(local) + } + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } + } + ProjectionElem::Subslice { from, to, from_end } => { + ProjectionElem::Subslice { from, to, from_end } + } + ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), + ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx), + ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx), + }) + } + + fn simplify_aggregate_to_copy( + &mut self, + rvalue: &mut Rvalue<'tcx>, + location: Location, + fields: &[VnIndex], + variant_index: VariantIdx, + ) -> Option<VnIndex> { + let Some(&first_field) = fields.first() else { + return None; + }; + let Value::Projection(copy_from_value, _) = *self.get(first_field) else { + return None; + }; + // All fields must correspond one-to-one and come from the same aggregate value. + if fields.iter().enumerate().any(|(index, &v)| { + if let Value::Projection(pointer, ProjectionElem::Field(from_index, _)) = *self.get(v) + && copy_from_value == pointer + && from_index.index() == index + { + return false; + } + true + }) { + return None; + } + + let mut copy_from_local_value = copy_from_value; + if let Value::Projection(pointer, proj) = *self.get(copy_from_value) + && let ProjectionElem::Downcast(_, read_variant) = proj + { + if variant_index == read_variant { + // When copying a variant, there is no need to downcast. + copy_from_local_value = pointer; + } else { + // The copied variant must be identical. + return None; + } + } + + let tcx = self.tcx; + let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new(); + loop { + if let Some(local) = self.try_as_local(copy_from_local_value, location) { + projection.reverse(); + let place = Place { local, projection: tcx.mk_place_elems(projection.as_slice()) }; + if rvalue.ty(self.local_decls, tcx) == place.ty(self.local_decls, tcx).ty { + self.reused_locals.insert(local); + *rvalue = Rvalue::Use(Operand::Copy(place)); + return Some(copy_from_value); + } + return None; + } else if let Value::Projection(pointer, proj) = *self.get(copy_from_local_value) + && let Some(proj) = self.try_as_place_elem(proj, location) + { + projection.push(proj); + copy_from_local_value = pointer; + } else { + return None; + } + } + } + fn simplify_aggregate( &mut self, rvalue: &mut Rvalue<'tcx>, @@ -971,6 +1060,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } + if let AggregateTy::Def(_, _) = ty + && let Some(value) = + self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index) + { + return Some(value); + } + Some(self.insert(Value::Aggregate(ty, variant_index, fields))) } @@ -1485,7 +1581,7 @@ impl<'tcx> VnState<'_, 'tcx> { } /// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`, - /// return it. + /// return it. If you used this local, add it to `reused_locals` to remove storage statements. fn try_as_local(&mut self, index: VnIndex, loc: Location) -> Option<Local> { let other = self.rev_locals.get(index)?; other diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 0b344f29b07..5c8958924fb 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -63,13 +63,13 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { } } -struct InstSimplifyContext<'tcx, 'a> { +struct InstSimplifyContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, param_env: ParamEnv<'tcx>, } -impl<'tcx> InstSimplifyContext<'tcx, '_> { +impl<'tcx> InstSimplifyContext<'_, 'tcx> { fn should_simplify(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool { self.should_simplify_custom(source_info, "Rvalue", rvalue) } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index d48df59ada8..1810569bc8e 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -117,7 +117,7 @@ struct ThreadingOpportunity { target: BasicBlock, } -struct TOFinder<'tcx, 'a> { +struct TOFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, @@ -183,7 +183,7 @@ impl<'a> ConditionSet<'a> { } } -impl<'tcx, 'a> TOFinder<'tcx, 'a> { +impl<'a, 'tcx> TOFinder<'a, 'tcx> { fn is_empty(&self, state: &State<ConditionSet<'a>>) -> bool { state.all_bottom() } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 84d07d38330..424e7008326 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -330,7 +330,7 @@ fn mir_promoted( tcx.ensure_with_value().has_ffi_unwind_calls(def); // the `by_move_body` query uses the raw mir, so make sure it is run. - if tcx.needs_coroutine_by_move_body_def_id(def) { + if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) { tcx.ensure_with_value().coroutine_by_move_body_def_id(def); } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 0f981425cfd..ad3126f66a6 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -295,7 +295,7 @@ struct SimplifyToExp { } #[derive(Clone, Copy)] -enum ExpectedTransformKind<'tcx, 'a> { +enum ExpectedTransformKind<'a, 'tcx> { /// Identical statements. Same(&'a StatementKind<'tcx>), /// Assignment statements have the same value. diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index cf8622cadd1..ba64216f9e1 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -235,7 +235,7 @@ impl SsaLocals { } } -struct SsaVisitor<'tcx, 'a> { +struct SsaVisitor<'a, 'tcx> { body: &'a Body<'tcx>, dominators: &'a Dominators<BasicBlock>, assignments: IndexVec<Local, Set1<DefLocation>>, @@ -261,7 +261,7 @@ impl SsaVisitor<'_, '_> { } } -impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> { +impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> { fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) { match ctxt { PlaceContext::MutatingUse(MutatingUseContext::Projection) diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 3b84755dded..e5837b1b475 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1,7 +1,6 @@ //! Validates the MIR to ensure that invariants are upheld. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; use rustc_hir::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; @@ -717,10 +716,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // first place. let layout = if def_id == self.caller_body.source.def_id() { self.caller_body.coroutine_layout_raw() - } else if let Some(hir::CoroutineKind::Desugared( - _, - hir::CoroutineSource::Closure, - )) = self.tcx.coroutine_kind(def_id) + } else if self.tcx.needs_coroutine_by_move_body_def_id(def_id) && let ty::ClosureKind::FnOnce = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() && self.caller_body.source.def_id() diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2d6edad2977..2d5a1914fa6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -49,7 +49,7 @@ enum DestructuredFloat { /// 1.2 | 1.2e3 MiddleDot(Symbol, Span, Span, Symbol, Span), /// Invalid - Error, + Error(ErrorGuaranteed), } impl<'a> Parser<'a> { @@ -1008,7 +1008,7 @@ impl<'a> Parser<'a> { self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None); self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix) } - DestructuredFloat::Error => base, + DestructuredFloat::Error(_) => base, }) } _ => { @@ -1018,7 +1018,7 @@ impl<'a> Parser<'a> { } } - fn error_unexpected_after_dot(&self) { + fn error_unexpected_after_dot(&self) -> ErrorGuaranteed { let actual = pprust::token_to_string(&self.token); let span = self.token.span; let sm = self.psess.source_map(); @@ -1028,17 +1028,19 @@ impl<'a> Parser<'a> { } _ => (span, actual), }; - self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual }); + self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual }) } - // We need an identifier or integer, but the next token is a float. - // Break the float into components to extract the identifier or integer. + /// We need an identifier or integer, but the next token is a float. + /// Break the float into components to extract the identifier or integer. + /// + /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`. + // // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2 - // parts unless those parts are processed immediately. `TokenCursor` should either - // support pushing "future tokens" (would be also helpful to `break_and_eat`), or - // we should break everything including floats into more basic proc-macro style - // tokens in the lexer (probably preferable). - // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`. + // parts unless those parts are processed immediately. `TokenCursor` should either + // support pushing "future tokens" (would be also helpful to `break_and_eat`), or + // we should break everything including floats into more basic proc-macro style + // tokens in the lexer (probably preferable). fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat { #[derive(Debug)] enum FloatComponent { @@ -1078,34 +1080,30 @@ impl<'a> Parser<'a> { DestructuredFloat::Single(Symbol::intern(i), span) } // 1. - [IdentLike(i), Punct('.')] => { - let (ident_span, dot_span) = if can_take_span_apart() { - let (span, ident_len) = (span.data(), BytePos::from_usize(i.len())); - let ident_span = span.with_hi(span.lo + ident_len); - let dot_span = span.with_lo(span.lo + ident_len); - (ident_span, dot_span) + [IdentLike(left), Punct('.')] => { + let (left_span, dot_span) = if can_take_span_apart() { + let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len())); + let dot_span = span.with_lo(left_span.hi()); + (left_span, dot_span) } else { (span, span) }; - let symbol = Symbol::intern(i); - DestructuredFloat::TrailingDot(symbol, ident_span, dot_span) + let left = Symbol::intern(left); + DestructuredFloat::TrailingDot(left, left_span, dot_span) } // 1.2 | 1.2e3 - [IdentLike(i1), Punct('.'), IdentLike(i2)] => { - let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() { - let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len())); - let ident1_span = span.with_hi(span.lo + ident1_len); - let dot_span = span - .with_lo(span.lo + ident1_len) - .with_hi(span.lo + ident1_len + BytePos(1)); - let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1)); - (ident1_span, dot_span, ident2_span) + [IdentLike(left), Punct('.'), IdentLike(right)] => { + let (left_span, dot_span, right_span) = if can_take_span_apart() { + let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len())); + let dot_span = span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1)); + let right_span = span.with_lo(dot_span.hi()); + (left_span, dot_span, right_span) } else { (span, span, span) }; - let symbol1 = Symbol::intern(i1); - let symbol2 = Symbol::intern(i2); - DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) + let left = Symbol::intern(left); + let right = Symbol::intern(right); + DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span) } // 1e+ | 1e- (recovered) [IdentLike(_), Punct('+' | '-')] | @@ -1116,8 +1114,8 @@ impl<'a> Parser<'a> { // 1.2e+3 | 1.2e-3 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => { // See the FIXME about `TokenCursor` above. - self.error_unexpected_after_dot(); - DestructuredFloat::Error + let guar = self.error_unexpected_after_dot(); + DestructuredFloat::Error(guar) } _ => panic!("unexpected components in a float token: {components:?}"), } @@ -1183,7 +1181,7 @@ impl<'a> Parser<'a> { fields.insert(start_idx, Ident::new(symbol2, span2)); fields.insert(start_idx, Ident::new(symbol1, span1)); } - DestructuredFloat::Error => { + DestructuredFloat::Error(_) => { trailing_dot = None; fields.insert(start_idx, Ident::new(symbol, self.prev_token.span)); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index dd1cc75c7ff..66019ffbc0a 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -607,9 +607,6 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; let whole_span = lo.to(self.prev_token.span); if let ast::Const::Yes(span) = constness { - // If we ever start to allow `const fn()`, then update - // feature gating for `#![feature(const_extern_fn)]` to - // cover it. self.dcx().emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span }); } if let Some(ast::CoroutineKind::Async { span, .. }) = coroutine_kind { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a985ecb019a..01052c60e94 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1012,12 +1012,12 @@ pub(crate) struct FeatureStableTwice { #[derive(Diagnostic)] #[diag(passes_feature_previously_declared, code = E0711)] -pub(crate) struct FeaturePreviouslyDeclared<'a, 'b> { +pub(crate) struct FeaturePreviouslyDeclared<'a> { #[primary_span] pub span: Span, pub feature: Symbol, pub declared: &'a str, - pub prev_declared: &'b str, + pub prev_declared: &'a str, } pub(crate) struct BreakNonLoop<'a> { diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index c11562ae39e..af932bd69ab 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -9,7 +9,6 @@ use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; -use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::{BytePos, Span}; use Context::*; @@ -64,8 +63,7 @@ impl fmt::Display for BreakContextKind { } #[derive(Clone)] -struct CheckLoopVisitor<'a, 'tcx> { - sess: &'a Session, +struct CheckLoopVisitor<'tcx> { tcx: TyCtxt<'tcx>, // Keep track of a stack of contexts, so that suggestions // are not made for contexts where it would be incorrect, @@ -76,12 +74,8 @@ struct CheckLoopVisitor<'a, 'tcx> { } fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - let mut check = CheckLoopVisitor { - sess: tcx.sess, - tcx, - cx_stack: vec![Normal], - block_breaks: Default::default(), - }; + let mut check = + CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() }; tcx.hir().visit_item_likes_in_module(module_def_id, &mut check); check.report_outside_loop_error(); } @@ -90,7 +84,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_loops, ..*providers }; } -impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { +impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { @@ -129,7 +123,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::If(cond, then, else_opt) => { self.visit_expr(cond); - let get_block = |ck_loop: &CheckLoopVisitor<'a, 'hir>, + let get_block = |ck_loop: &CheckLoopVisitor<'hir>, expr: &hir::Expr<'hir>| -> Option<&hir::Block<'hir>> { if let hir::ExprKind::Block(b, None) = expr.kind @@ -213,7 +207,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { Ok(loop_id) => Some(loop_id), Err(hir::LoopIdError::OutsideLoopScope) => None, Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.sess.dcx().emit_err(UnlabeledCfInWhileCondition { + self.tcx.dcx().emit_err(UnlabeledCfInWhileCondition { span: e.span, cf_type: "break", }); @@ -248,7 +242,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { .label .map_or_else(String::new, |l| format!(" {}", l.ident)) ); - self.sess.dcx().emit_err(BreakNonLoop { + self.tcx.dcx().emit_err(BreakNonLoop { span: e.span, head, kind: kind.name(), @@ -280,14 +274,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { match destination.target_id { Ok(loop_id) => { if let Node::Block(block) = self.tcx.hir_node(loop_id) { - self.sess.dcx().emit_err(ContinueLabeledBlock { + self.tcx.dcx().emit_err(ContinueLabeledBlock { span: e.span, block_span: block.span, }); } } Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.sess.dcx().emit_err(UnlabeledCfInWhileCondition { + self.tcx.dcx().emit_err(UnlabeledCfInWhileCondition { span: e.span, cf_type: "continue", }); @@ -306,10 +300,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } } -impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { +impl<'hir> CheckLoopVisitor<'hir> { fn with_context<F>(&mut self, cx: Context, f: F) where - F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>), + F: FnOnce(&mut CheckLoopVisitor<'hir>), { self.cx_stack.push(cx); f(self); @@ -326,7 +320,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { match self.cx_stack[cx_pos] { LabeledBlock | Loop(_) => {} Closure(closure_span) => { - self.sess.dcx().emit_err(BreakInsideClosure { + self.tcx.dcx().emit_err(BreakInsideClosure { span, closure_span, name: &br_cx_kind.to_string(), @@ -343,7 +337,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { hir::CoroutineSource::Closure => "closure", hir::CoroutineSource::Fn => "function", }; - self.sess.dcx().emit_err(BreakInsideCoroutine { + self.tcx.dcx().emit_err(BreakInsideCoroutine { span, coroutine_span, name: &br_cx_kind.to_string(), @@ -366,7 +360,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1); } Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => { - self.sess.dcx().emit_err(OutsideLoop { + self.tcx.dcx().emit_err(OutsideLoop { spans: vec![span], name: &br_cx_kind.to_string(), is_break: br_cx_kind == BreakContextKind::Break, @@ -386,7 +380,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { && self.cx_stack.last() == Some(&LabeledBlock) && label.label.is_none() { - self.sess.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type }); + self.tcx.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type }); return true; } false @@ -394,7 +388,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { fn report_outside_loop_error(&self) { for (s, block) in &self.block_breaks { - self.sess.dcx().emit_err(OutsideLoop { + self.tcx.dcx().emit_err(OutsideLoop { spans: block.spans.clone(), name: &block.name, is_break: true, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 572f71d7c77..c7078e1a27a 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -852,12 +852,12 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> //////////////////////////////////////////////////////////////////////////////// /// Visitor, used for EffectiveVisibilities table checking //////////////////////////////////////////////////////////////////////////////// -pub struct TestReachabilityVisitor<'tcx, 'a> { +pub struct TestReachabilityVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, effective_visibilities: &'a EffectiveVisibilities, } -impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { +impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) { let mut error_msg = String::new(); @@ -878,7 +878,7 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { } } -impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { +impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { self.effective_visibility_diagnostic(item.owner_id.def_id); @@ -1425,12 +1425,12 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { } } -struct PrivateItemsInPublicInterfacesChecker<'tcx, 'a> { +struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, effective_visibilities: &'a EffectiveVisibilities, } -impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> { +impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { fn check( &self, def_id: LocalDefId, diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 599316d0cad..536044298f0 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -19,18 +19,18 @@ impl QueryKeyStringCache { } } -struct QueryKeyStringBuilder<'p, 'tcx> { - profiler: &'p SelfProfiler, +struct QueryKeyStringBuilder<'a, 'tcx> { + profiler: &'a SelfProfiler, tcx: TyCtxt<'tcx>, - string_cache: &'p mut QueryKeyStringCache, + string_cache: &'a mut QueryKeyStringCache, } -impl<'p, 'tcx> QueryKeyStringBuilder<'p, 'tcx> { +impl<'a, 'tcx> QueryKeyStringBuilder<'a, 'tcx> { fn new( - profiler: &'p SelfProfiler, + profiler: &'a SelfProfiler, tcx: TyCtxt<'tcx>, - string_cache: &'p mut QueryKeyStringCache, - ) -> QueryKeyStringBuilder<'p, 'tcx> { + string_cache: &'a mut QueryKeyStringCache, + ) -> QueryKeyStringBuilder<'a, 'tcx> { QueryKeyStringBuilder { profiler, tcx, string_cache } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index d6c58e9d1be..1db31f5b0a7 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -340,4 +340,8 @@ impl ParseSess { pub fn dcx(&self) -> DiagCtxtHandle<'_> { self.dcx.handle() } + + pub fn set_dcx(&mut self, dcx: DiagCtxt) { + self.dcx = dcx; + } } diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs index 042a9a14071..762084291a6 100644 --- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs @@ -21,16 +21,16 @@ pub(crate) fn target() -> Target { linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - // The Cortex-R52 has two variants with respect to floating-point support: - // 1. fp-armv8, SP-only, with 16 DP (32 SP) registers - // 2. neon-fp-armv8, SP+DP, with 32 DP registers - // Use the lesser of these two options as the default, as it will produce code - // compatible with either variant. + // Armv8-R requires a minimum set of floating-point features equivalent to: + // fp-armv8, SP-only, with 16 DP (32 SP) registers + // LLVM defines Armv8-R to include these features automatically. + // + // The Cortex-R52 supports these default features and optionally includes: + // neon-fp-armv8, SP+DP, with 32 DP registers // // Reference: // Arm Cortex-R52 Processor Technical Reference Manual // - Chapter 15 Advanced SIMD and floating-point support - features: "+fp-armv8,-fp64,-d32".into(), max_atomic_width: Some(64), emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index d33c7af92c6..0bcbf655bd8 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, Target, TargetOptions}; +use crate::spec::{base, CodeModel, Target, TargetOptions}; pub(crate) fn target() -> Target { Target { @@ -13,6 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), arch: "loongarch64".into(), options: TargetOptions { + code_model: Some(CodeModel::Medium), cpu: "generic".into(), features: "+f,+d".into(), llvm_abiname: "lp64d".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs index 5540e71ad4f..223d979a06f 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, Target, TargetOptions}; +use crate::spec::{base, CodeModel, Target, TargetOptions}; pub(crate) fn target() -> Target { Target { @@ -13,6 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), arch: "loongarch64".into(), options: TargetOptions { + code_model: Some(CodeModel::Medium), cpu: "generic".into(), features: "+f,+d".into(), llvm_abiname: "lp64d".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index 56285190268..db527c8b636 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Small), + code_model: Some(CodeModel::Medium), ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index 7e57715ce7a..221ca02fe3e 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Small), + code_model: Some(CodeModel::Medium), ..Default::default() }, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 38d06f53fa6..b8ac83e8f96 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -842,14 +842,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { lifetime: Region<'tcx>, add_lt_suggs: &mut Vec<(Span, String)>, ) -> String { - struct LifetimeReplaceVisitor<'tcx, 'a> { + struct LifetimeReplaceVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, needle: hir::LifetimeName, new_lt: &'a str, add_lt_suggs: &'a mut Vec<(Span, String)>, } - impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> { + impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_, 'tcx> { fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) { if lt.res == self.needle { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 9aa6d1f3d46..752ef729113 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -344,7 +344,8 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti write!( w, - " {} for {}", + " {}{} for {}", + tcx.impl_polarity(impl_def_id).as_str(), trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id).instantiate_identity() ) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index b13aede509a..e2796c76412 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -61,9 +61,9 @@ pub enum CoroutineInteriorOrUpvar { // This type provides a uniform interface to retrieve data on coroutines, whether it originated from // the local crate being compiled or from a foreign crate. #[derive(Debug)] -struct CoroutineData<'tcx, 'a>(&'a TypeckResults<'tcx>); +struct CoroutineData<'a, 'tcx>(&'a TypeckResults<'tcx>); -impl<'tcx, 'a> CoroutineData<'tcx, 'a> { +impl<'a, 'tcx> CoroutineData<'a, 'tcx> { /// Try to get information about variables captured by the coroutine that matches a type we are /// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to /// meet an obligation diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index f1b524d1325..525fba69a87 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -25,7 +25,7 @@ use crate::traits::{ }; #[extension(pub trait QueryNormalizeExt<'tcx>)] -impl<'cx, 'tcx> At<'cx, 'tcx> { +impl<'a, 'tcx> At<'a, 'tcx> { /// Normalize `value` in the context of the inference context, /// yielding a resulting type, or an error if `value` cannot be /// normalized. If you don't care about regions, you should prefer @@ -160,9 +160,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor { } } -struct QueryNormalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, - cause: &'cx ObligationCause<'tcx>, +struct QueryNormalizer<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, obligations: Vec<PredicateObligation<'tcx>>, cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, @@ -170,7 +170,7 @@ struct QueryNormalizer<'cx, 'tcx> { universes: Vec<Option<ty::UniverseIndex>>, } -impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> { +impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> { type Error = NoSolution; fn cx(&self) -> TyCtxt<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 0fb13799e67..99445d03965 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -332,8 +332,8 @@ pub fn with_replaced_escaping_bound_vars< } } -pub struct BoundVarReplacer<'me, 'tcx> { - infcx: &'me InferCtxt<'tcx>, +pub struct BoundVarReplacer<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, // These three maps track the bound variable that were replaced by placeholders. It might be // nice to remove these since we already have the `kind` in the placeholder; we really just need // the `var` (but we *could* bring that into scope if we were to track them as we pass them). @@ -345,15 +345,15 @@ pub struct BoundVarReplacer<'me, 'tcx> { current_index: ty::DebruijnIndex, // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: // we don't actually create a universe until we see a bound var we have to replace. - universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>, + universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, } -impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { +impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> { /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that /// use a binding level above `universe_indices.len()`, we fail. pub fn replace_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>( - infcx: &'me InferCtxt<'tcx>, - universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>, + infcx: &'a InferCtxt<'tcx>, + universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, value: T, ) -> ( T, @@ -479,22 +479,22 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { } /// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. -pub struct PlaceholderReplacer<'me, 'tcx> { - infcx: &'me InferCtxt<'tcx>, +pub struct PlaceholderReplacer<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, - universe_indices: &'me [Option<ty::UniverseIndex>], + universe_indices: &'a [Option<ty::UniverseIndex>], current_index: ty::DebruijnIndex, } -impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { +impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> { pub fn replace_placeholders<T: TypeFoldable<TyCtxt<'tcx>>>( - infcx: &'me InferCtxt<'tcx>, + infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, - universe_indices: &'me [Option<ty::UniverseIndex>], + universe_indices: &'a [Option<ty::UniverseIndex>], value: T, ) -> T { let mut replacer = PlaceholderReplacer { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index c3fd771b797..b5ce465a173 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -175,7 +175,7 @@ pub(crate) mod rustc { use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::ErrorGuaranteed; use rustc_target::abi::{ - FieldIdx, FieldsShape, Layout, Size, TyAndLayout, VariantIdx, Variants, + FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants, }; use super::Tree; @@ -319,11 +319,17 @@ pub(crate) mod rustc { assert!(def.is_enum()); // Computes the variant of a given index. - let layout_of_variant = |index| { + let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| { let tag = cx.tcx.tag_for_variant((cx.tcx.erase_regions(ty), index)); let variant_def = Def::Variant(def.variant(index)); let variant_layout = ty_variant(cx, (ty, layout), index); - Self::from_variant(variant_def, tag, (ty, variant_layout), layout.size, cx) + Self::from_variant( + variant_def, + tag.map(|tag| (tag, index, encoding.unwrap())), + (ty, variant_layout), + layout.size, + cx, + ) }; // We consider three kinds of enums, each demanding a different @@ -345,9 +351,9 @@ pub(crate) mod rustc { Variants::Single { index } => { // `Variants::Single` on enums with variants denotes that // the enum delegates its layout to the variant at `index`. - layout_of_variant(*index) + layout_of_variant(*index, None) } - Variants::Multiple { tag_field, .. } => { + Variants::Multiple { tag, tag_encoding, tag_field, .. } => { // `Variants::Multiple` denotes an enum with multiple // variants. The layout of such an enum is the disjunction // of the layouts of its tagged variants. @@ -359,7 +365,7 @@ pub(crate) mod rustc { let variants = def.discriminants(cx.tcx()).try_fold( Self::uninhabited(), |variants, (idx, ref discriminant)| { - let variant = layout_of_variant(idx)?; + let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?; Result::<Self, Err>::Ok(variants.or(variant)) }, )?; @@ -380,7 +386,7 @@ pub(crate) mod rustc { /// `0`. fn from_variant( def: Def<'tcx>, - tag: Option<ScalarInt>, + tag: Option<(ScalarInt, VariantIdx, TagEncoding<VariantIdx>)>, (ty, layout): (Ty<'tcx>, Layout<'tcx>), total_size: Size, cx: LayoutCx<'tcx, TyCtxt<'tcx>>, @@ -400,9 +406,18 @@ pub(crate) mod rustc { let mut struct_tree = Self::def(def); // If a `tag` is provided, place it at the start of the layout. - if let Some(tag) = tag { - size += tag.size(); - struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx)); + if let Some((tag, index, encoding)) = &tag { + match encoding { + TagEncoding::Direct => { + size += tag.size(); + } + TagEncoding::Niche { niche_variants, .. } => { + if !niche_variants.contains(index) { + size += tag.size(); + } + } + } + struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx)); } // Append the fields, in memory order, to the layout. diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index 2223aca28d1..8378237fe2f 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -28,7 +28,7 @@ pub(super) fn sanity_check_layout<'tcx>( } /// Yields non-ZST fields of the type - fn non_zst_fields<'tcx, 'a>( + fn non_zst_fields<'a, 'tcx>( cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &'a TyAndLayout<'tcx>, ) -> impl Iterator<Item = (Size, TyAndLayout<'tcx>)> + 'a { diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index b30346ffc53..e4bf1e1379c 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -196,6 +196,17 @@ impl fmt::Display for ImplPolarity { } } +impl ImplPolarity { + /// The polarity marker in front of the impl trait ref if applicable. + pub fn as_str(self) -> &'static str { + match self { + Self::Positive => "", + Self::Negative => "!", + Self::Reservation => "", + } + } +} + /// Polarity for a trait predicate. May either be negative or positive. /// Distinguished from [`ImplPolarity`] since we never compute goals with /// "reservation" level. |
