From eb10db0a76fdacdbe6747431aea90f17ce4ec7c1 Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Wed, 11 Dec 2024 16:40:54 -0800 Subject: [PATCH 1/2] Make some types and methods related to Polonius + Miri public. --- compiler/rustc_borrowck/src/borrow_set.rs | 24 +++++++++---------- compiler/rustc_borrowck/src/consumers.rs | 4 ++-- .../rustc_const_eval/src/interpret/operand.rs | 24 +++++++++++++------ .../rustc_const_eval/src/interpret/stack.rs | 4 +++- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 16b3d901956cc..d66f613c71e0b 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -20,18 +20,18 @@ pub struct BorrowSet<'tcx> { /// by the `Location` of the assignment statement in which it /// appears on the right hand side. Thus the location is the map /// key, and its position in the map corresponds to `BorrowIndex`. - pub(crate) location_map: FxIndexMap>, + pub location_map: FxIndexMap>, /// Locations which activate borrows. /// NOTE: a given location may activate more than one borrow in the future /// when more general two-phase borrow support is introduced, but for now we /// only need to store one borrow index. - pub(crate) activation_map: FxIndexMap>, + pub activation_map: FxIndexMap>, /// Map from local to all the borrows on that local. - pub(crate) local_map: FxIndexMap>, + pub local_map: FxIndexMap>, - pub(crate) locals_state_at_exit: LocalsStateAtExit, + pub locals_state_at_exit: LocalsStateAtExit, } impl<'tcx> Index for BorrowSet<'tcx> { @@ -45,7 +45,7 @@ impl<'tcx> Index for BorrowSet<'tcx> { /// Location where a two-phase borrow is activated, if a borrow /// is in fact a two-phase borrow. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(crate) enum TwoPhaseActivation { +pub enum TwoPhaseActivation { NotTwoPhase, NotActivated, ActivatedAt(Location), @@ -55,17 +55,17 @@ pub(crate) enum TwoPhaseActivation { pub struct BorrowData<'tcx> { /// Location where the borrow reservation starts. /// In many cases, this will be equal to the activation location but not always. - pub(crate) reserve_location: Location, + pub reserve_location: Location, /// Location where the borrow is activated. - pub(crate) activation_location: TwoPhaseActivation, + pub activation_location: TwoPhaseActivation, /// What kind of borrow this is - pub(crate) kind: mir::BorrowKind, + pub kind: mir::BorrowKind, /// The region for which this borrow is live - pub(crate) region: RegionVid, + pub region: RegionVid, /// Place from which we are borrowing - pub(crate) borrowed_place: mir::Place<'tcx>, + pub borrowed_place: mir::Place<'tcx>, /// Place to which the borrow was stored - pub(crate) assigned_place: mir::Place<'tcx>, + pub assigned_place: mir::Place<'tcx>, } impl<'tcx> fmt::Display for BorrowData<'tcx> { @@ -120,7 +120,7 @@ impl LocalsStateAtExit { } impl<'tcx> BorrowSet<'tcx> { - pub(crate) fn build( + pub fn build( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, locals_are_invalidated_at_exit: bool, diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 7ace38c3e85ff..74de766ba2317 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -5,15 +5,15 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::{Body, Promoted}; use rustc_middle::ty::TyCtxt; +pub use super::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; pub use super::constraints::OutlivesConstraint; pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_at_location}; -pub use super::facts::{AllFacts as PoloniusInput, RustcFacts}; +pub use super::facts::{AllFacts as PoloniusInput, PoloniusRegionVid, RustcFacts}; pub use super::location::{LocationTable, RichLocation}; pub use super::nll::PoloniusOutput; pub use super::place_ext::PlaceExt; pub use super::places_conflict::{PlaceConflictBias, places_conflict}; pub use super::region_infer::RegionInferenceContext; -use crate::borrow_set::BorrowSet; /// Options determining the output behavior of [`get_body_with_borrowck_facts`]. /// diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 0157e6c2125e5..bd33e8d20c09b 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -15,9 +15,9 @@ use rustc_middle::{bug, mir, span_bug, ty}; use tracing::trace; use super::{ - CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, - PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout, - interp_ok, mir_assign_valid_types, throw_ub, + CtfeProvenance, Frame, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, + OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, + from_known_layout, interp_ok, mir_assign_valid_types, throw_ub, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -706,17 +706,27 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(str) } - /// Read from a local of the current frame. + /// Read from a local of the current frame. Convenience method for [`InterpCx::local_at_frame_to_op`]. + pub fn local_to_op( + &self, + local: mir::Local, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + self.local_at_frame_to_op(self.frame(), local, layout) + } + + /// Read from a local of a given frame. /// Will not access memory, instead an indirect `Operand` is returned. /// - /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an + /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) and + /// [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/) to get an /// OpTy from a local. - pub fn local_to_op( + pub fn local_at_frame_to_op( &self, + frame: &Frame<'tcx, M::Provenance, M::FrameExtra>, local: mir::Local, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - let frame = self.frame(); let layout = self.layout_of_local(frame, local, layout)?; let op = *frame.locals[local].access()?; if matches!(op, Operand::Immediate(_)) { diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index a9ebf38661703..6512675530a45 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -584,8 +584,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } + /// This is public because it is used by [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/) + /// to analyze all the locals in a stack frame. #[inline(always)] - pub(super) fn layout_of_local( + pub fn layout_of_local( &self, frame: &Frame<'tcx, M::Provenance, M::FrameExtra>, local: mir::Local, From 4d5d4700f3c7fa5151560d27f389c15a7a3047a0 Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Thu, 12 Dec 2024 12:34:43 -0800 Subject: [PATCH 2/2] Make BorrowSet/BorrowData fields accessible via public getters --- compiler/rustc_borrowck/src/borrow_set.rs | 66 ++++++++++++++++--- .../rustc_const_eval/src/interpret/machine.rs | 8 ++- .../rustc_const_eval/src/interpret/operand.rs | 7 +- src/tools/miri/src/machine.rs | 8 ++- 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index d66f613c71e0b..ff838fbbb8868 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -20,18 +20,37 @@ pub struct BorrowSet<'tcx> { /// by the `Location` of the assignment statement in which it /// appears on the right hand side. Thus the location is the map /// key, and its position in the map corresponds to `BorrowIndex`. - pub location_map: FxIndexMap>, + pub(crate) location_map: FxIndexMap>, /// Locations which activate borrows. /// NOTE: a given location may activate more than one borrow in the future /// when more general two-phase borrow support is introduced, but for now we /// only need to store one borrow index. - pub activation_map: FxIndexMap>, + pub(crate) activation_map: FxIndexMap>, /// Map from local to all the borrows on that local. - pub local_map: FxIndexMap>, + pub(crate) local_map: FxIndexMap>, - pub locals_state_at_exit: LocalsStateAtExit, + pub(crate) locals_state_at_exit: LocalsStateAtExit, +} + +// These methods are public to support borrowck consumers. +impl<'tcx> BorrowSet<'tcx> { + pub fn location_map(&self) -> &FxIndexMap> { + &self.location_map + } + + pub fn activation_map(&self) -> &FxIndexMap> { + &self.activation_map + } + + pub fn local_map(&self) -> &FxIndexMap> { + &self.local_map + } + + pub fn locals_state_at_exit(&self) -> &LocalsStateAtExit { + &self.locals_state_at_exit + } } impl<'tcx> Index for BorrowSet<'tcx> { @@ -55,17 +74,44 @@ pub enum TwoPhaseActivation { pub struct BorrowData<'tcx> { /// Location where the borrow reservation starts. /// In many cases, this will be equal to the activation location but not always. - pub reserve_location: Location, + pub(crate) reserve_location: Location, /// Location where the borrow is activated. - pub activation_location: TwoPhaseActivation, + pub(crate) activation_location: TwoPhaseActivation, /// What kind of borrow this is - pub kind: mir::BorrowKind, + pub(crate) kind: mir::BorrowKind, /// The region for which this borrow is live - pub region: RegionVid, + pub(crate) region: RegionVid, /// Place from which we are borrowing - pub borrowed_place: mir::Place<'tcx>, + pub(crate) borrowed_place: mir::Place<'tcx>, /// Place to which the borrow was stored - pub assigned_place: mir::Place<'tcx>, + pub(crate) assigned_place: mir::Place<'tcx>, +} + +// These methods are public to support borrowck consumers. +impl<'tcx> BorrowData<'tcx> { + pub fn reserve_location(&self) -> Location { + self.reserve_location + } + + pub fn activation_location(&self) -> TwoPhaseActivation { + self.activation_location + } + + pub fn kind(&self) -> mir::BorrowKind { + self.kind + } + + pub fn region(&self) -> RegionVid { + self.region + } + + pub fn borrowed_place(&self) -> mir::Place<'tcx> { + self.borrowed_place + } + + pub fn assigned_place(&self) -> mir::Place<'tcx> { + self.assigned_place + } } impl<'tcx> fmt::Display for BorrowData<'tcx> { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index a180d5da9418b..9ac2a024ccf37 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -540,10 +540,14 @@ pub trait Machine<'tcx>: Sized { interp_ok(ReturnAction::Normal) } - /// Called immediately after an "immediate" local variable is read + /// Called immediately after an "immediate" local variable is read in a given frame /// (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> { + fn after_local_read( + _ecx: &InterpCx<'tcx, Self>, + _frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>, + _local: mir::Local, + ) -> InterpResult<'tcx> { interp_ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index bd33e8d20c09b..9d2a7125f5105 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -718,9 +718,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Read from a local of a given frame. /// Will not access memory, instead an indirect `Operand` is returned. /// - /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) and - /// [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/) to get an - /// OpTy from a local. + /// This is public because it is used by [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/) + /// to get an OpTy from a local. pub fn local_at_frame_to_op( &self, frame: &Frame<'tcx, M::Provenance, M::FrameExtra>, @@ -732,7 +731,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(op, Operand::Immediate(_)) { assert!(!layout.is_unsized()); } - M::after_local_read(self, local)?; + M::after_local_read(self, frame, local)?; interp_ok(OpTy { op, layout }) } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 7cc22f83a24a6..ac26feb345c18 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1571,8 +1571,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { res } - fn after_local_read(ecx: &InterpCx<'tcx, Self>, local: mir::Local) -> InterpResult<'tcx> { - if let Some(data_race) = &ecx.frame().extra.data_race { + fn after_local_read( + ecx: &InterpCx<'tcx, Self>, + frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>, + local: mir::Local, + ) -> InterpResult<'tcx> { + if let Some(data_race) = &frame.extra.data_race { data_race.local_read(local, &ecx.machine); } interp_ok(())