diff --git a/Cargo.lock b/Cargo.lock index a29ab3edf7..b111c21377 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler" @@ -700,9 +700,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc_plugin" -version = "0.8.0-nightly-2024-01-06" +version = "0.11.0-nightly-2024-12-01" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3f5a9a92ee9d2031a03d687f9a784b991c2d2710f4b4cef6065bc68a9a4080" +checksum = "665358b6619ffa05c3fce0900fb6ae0bc661df03cbb959acdc1a59139631c477" dependencies = [ "cargo_metadata", "log", @@ -720,9 +720,9 @@ checksum = "b3c5a95edfa0c893236ae4778bb7c4752760e4c0d245e19b5eff33c5aa5eb9dc" [[package]] name = "rustc_utils" -version = "0.8.0-nightly-2024-01-06" +version = "0.11.0-nightly-2024-12-01" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed8a124410c95f01661cdbb4056389fe51bebf4bd2268a447b186de0dd0e4b7b" +checksum = "81511bc57827cf136f4e008b57b77e2dac1e6e058c2f275901d87cc729631847" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 0c7e60fdb1..8dafe9a459 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ exclude = ["ide/src/tests/mock_project"] resolver = "2" [workspace.dependencies] -rustc_plugin = "=0.8.0-nightly-2024-01-06" -rustc_utils = {version = "=0.8.0-nightly-2024-01-06", features = ["indexical"]} +rustc_plugin = "=0.11.0-nightly-2024-12-01" +rustc_utils = {version = "=0.11.0-nightly-2024-12-01", features = ["indexical"]} indexical = {version = "0.3.1", default-features = false, features = ["rustc"]} [profile.bench] diff --git a/crates/flowistry/benches/main.rs b/crates/flowistry/benches/main.rs index 2a007f3c58..0618837b9e 100644 --- a/crates/flowistry/benches/main.rs +++ b/crates/flowistry/benches/main.rs @@ -79,36 +79,35 @@ impl rustc_driver::Callbacks for Callbacks { config.override_queries = Some(borrowck_facts::override_queries); } - fn after_crate_root_parsing<'tcx>( + fn after_analysis<'tcx>( &mut self, _compiler: &rustc_interface::interface::Compiler, - queries: &'tcx rustc_interface::Queries<'tcx>, + tcx: TyCtxt<'tcx>, ) -> rustc_driver::Compilation { - queries.global_ctxt().unwrap().enter(|tcx| { - let hir = tcx.hir(); - let body_id = hir - .items() - .filter_map(|id| match hir.item(id).kind { - ItemKind::Fn(_, _, body) => Some(body), - _ => None, - }) - .next() - .unwrap(); + let hir = tcx.hir(); + let body_id = hir + .items() + .filter_map(|id| match hir.item(id).kind { + ItemKind::Fn(_, _, body) => Some(body), + _ => None, + }) + .next() + .unwrap(); - let def_id = hir.body_owner_def_id(body_id); - let body_with_facts = borrowck_facts::get_body_with_borrowck_facts(tcx, def_id); + let def_id = hir.body_owner_def_id(body_id); + let body_with_facts = borrowck_facts::get_body_with_borrowck_facts(tcx, def_id); - for analysis_ty in [AnalysisType::FlowOnly, AnalysisType::FlowAndDeps] { - let bench_id = match analysis_ty { - AnalysisType::FlowOnly => "Flow", - AnalysisType::FlowAndDeps => "Flow + Deps", - }; + for analysis_ty in [AnalysisType::FlowOnly, AnalysisType::FlowAndDeps] { + let bench_id = match analysis_ty { + AnalysisType::FlowOnly => "Flow", + AnalysisType::FlowAndDeps => "Flow + Deps", + }; + + self.group.0.bench_function(bench_id, |b| { + b.iter(|| analysis(tcx, body_id, body_with_facts, analysis_ty)) + }); + } - self.group.0.bench_function(bench_id, |b| { - b.iter(|| analysis(tcx, body_id, body_with_facts, analysis_ty)) - }); - } - }); rustc_driver::Compilation::Stop } } diff --git a/crates/flowistry/examples/example.rs b/crates/flowistry/examples/example.rs index c0d2088c75..11e9201a45 100644 --- a/crates/flowistry/examples/example.rs +++ b/crates/flowistry/examples/example.rs @@ -96,29 +96,28 @@ impl rustc_driver::Callbacks for Callbacks { config.override_queries = Some(borrowck_facts::override_queries); } - fn after_crate_root_parsing<'tcx>( + fn after_analysis<'tcx>( &mut self, _compiler: &rustc_interface::interface::Compiler, - queries: &'tcx rustc_interface::Queries<'tcx>, + tcx: TyCtxt<'tcx>, ) -> rustc_driver::Compilation { - queries.global_ctxt().unwrap().enter(|tcx| { - let hir = tcx.hir(); - - // Get the first body we can find - let body_id = hir - .items() - .filter_map(|id| match hir.item(id).kind { - ItemKind::Fn(_, _, body) => Some(body), - _ => None, - }) - .next() - .unwrap(); - - let def_id = hir.body_owner_def_id(body_id); - let body_with_facts = borrowck_facts::get_body_with_borrowck_facts(tcx, def_id); - - compute_dependencies(tcx, body_id, body_with_facts) - }); + let hir = tcx.hir(); + + // Get the first body we can find + let body_id = hir + .items() + .filter_map(|id| match hir.item(id).kind { + ItemKind::Fn(_, _, body) => Some(body), + _ => None, + }) + .next() + .unwrap(); + + let def_id = hir.body_owner_def_id(body_id); + let body_with_facts = borrowck_facts::get_body_with_borrowck_facts(tcx, def_id); + + compute_dependencies(tcx, body_id, body_with_facts); + rustc_driver::Compilation::Stop } } diff --git a/crates/flowistry/src/infoflow/analysis.rs b/crates/flowistry/src/infoflow/analysis.rs index 3ef8b4762c..5e1cb02de1 100644 --- a/crates/flowistry/src/infoflow/analysis.rs +++ b/crates/flowistry/src/infoflow/analysis.rs @@ -8,7 +8,7 @@ use rustc_middle::{ mir::{visit::Visitor, *}, ty::TyCtxt, }; -use rustc_mir_dataflow::{Analysis, AnalysisDomain}; +use rustc_mir_dataflow::Analysis; use rustc_utils::{ mir::{ control_dependencies::ControlDependencies, @@ -107,12 +107,15 @@ impl<'a, 'tcx> FlowAnalysis<'a, 'tcx> { .aliases(place) .iter() .flat_map(|alias| self.place_info.conflicts(*alias)); - let provenance = place.refs_in_projection().flat_map(|(place_ref, _)| { - self - .place_info - .aliases(Place::from_ref(place_ref, self.tcx)) - .iter() - }); + let provenance = + place + .refs_in_projection(self.body, self.tcx) + .flat_map(|(place_ref, _)| { + self + .place_info + .aliases(Place::from_ref(place_ref, self.tcx)) + .iter() + }); conflicts.chain(provenance).copied().collect() } @@ -231,7 +234,7 @@ impl<'a, 'tcx> FlowAnalysis<'a, 'tcx> { } } -impl<'a, 'tcx> AnalysisDomain<'tcx> for FlowAnalysis<'a, 'tcx> { +impl<'a, 'tcx> Analysis<'tcx> for FlowAnalysis<'a, 'tcx> { type Domain = FlowDomain<'tcx>; const NAME: &'static str = "FlowAnalysis"; @@ -251,9 +254,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for FlowAnalysis<'a, 'tcx> { } } } -} -impl<'a, 'tcx> Analysis<'tcx> for FlowAnalysis<'a, 'tcx> { fn apply_statement_effect( &mut self, state: &mut Self::Domain, diff --git a/crates/flowistry/src/infoflow/mod.rs b/crates/flowistry/src/infoflow/mod.rs index 9f952612c0..5bb5ca2612 100644 --- a/crates/flowistry/src/infoflow/mod.rs +++ b/crates/flowistry/src/infoflow/mod.rs @@ -63,7 +63,7 @@ pub type FlowResults<'a, 'tcx> = engine::AnalysisResults<'tcx, FlowAnalysis<'a, thread_local! { pub(super) static BODY_STACK: RefCell> = - RefCell::new(Vec::new()); + const { RefCell::new(Vec::new()) }; } /// Computes information flow for a MIR body. diff --git a/crates/flowistry/src/infoflow/recursive.rs b/crates/flowistry/src/infoflow/recursive.rs index 1eaf62d0f4..94139b8a41 100644 --- a/crates/flowistry/src/infoflow/recursive.rs +++ b/crates/flowistry/src/infoflow/recursive.rs @@ -80,11 +80,12 @@ impl<'tcx> FlowAnalysis<'_, 'tcx> { } }; - let unsafety = tcx.mir_unsafety_check_result(def_id.expect_local()); - if !unsafety.used_unsafe_blocks.is_empty() { - debug!(" Func contains unsafe blocks"); - return false; - } + // TODO(wcrichto, 2024-12-02): mir_unsafety_check_result got removed, need to find a replacement + // let unsafety = tcx.mir_unsafety_check_result(def_id.expect_local()); + // if !unsafety.used_unsafe_blocks.is_empty() { + // debug!(" Func contains unsafe blocks"); + // return false; + // } let parent_arg_places = utils::arg_places(parent_args); let any_closure_inputs = parent_arg_places.iter().any(|(_, place)| { @@ -168,7 +169,6 @@ impl<'tcx> FlowAnalysis<'_, 'tcx> { let mut projection = parent_toplevel_arg.projection.to_vec(); let mut ty = parent_toplevel_arg.ty(self.body.local_decls(), tcx); - let parent_param_env = tcx.param_env(self.def_id); log::debug!("Adding child {child:?} to parent {parent_toplevel_arg:?}"); for elem in child.projection.iter() { // Don't continue if we reach a private field @@ -183,7 +183,6 @@ impl<'tcx> FlowAnalysis<'_, 'tcx> { ty = ty.projection_ty_core( tcx, - parent_param_env, &elem, |_, field, _| ty.field_ty(tcx, field), |_, ty| ty, diff --git a/crates/flowistry/src/mir/aliases.rs b/crates/flowistry/src/mir/aliases.rs index 91ed9def75..506de4b73c 100644 --- a/crates/flowistry/src/mir/aliases.rs +++ b/crates/flowistry/src/mir/aliases.rs @@ -11,12 +11,12 @@ use rustc_data_structures::{ }; use rustc_hir::def_id::DefId; use rustc_index::{ - bit_set::{HybridBitSet, SparseBitMatrix}, + bit_set::{ChunkedBitSet, SparseBitMatrix}, IndexVec, }; use rustc_middle::{ mir::{visit::Visitor, *}, - ty::{Region, RegionKind, RegionVid, Ty, TyCtxt, TyKind, TypeAndMut}, + ty::{Region, RegionKind, RegionVid, Ty, TyCtxt, TyKind}, }; use rustc_utils::{mir::place::UNKNOWN_REGION, timer::elapsed, PlaceExt}; @@ -109,13 +109,12 @@ impl<'a, 'tcx> Aliases<'a, 'tcx> { let start = Instant::now(); let body = &body_with_facts.body; let static_region = RegionVid::from_usize(0); - let subset_base = &body_with_facts - .input_facts - .as_ref() - .unwrap() + let input_facts = &body_with_facts.input_facts.as_ref().unwrap(); + let subset_base = input_facts .subset_base .iter() .cloned() + .map(|(r1, r2, i)| (RegionVid::from(r1), RegionVid::from(r2), i)) .filter(|(r1, r2, i)| constraint_selector(*r1, *r2, *i)) .collect::>(); @@ -143,10 +142,10 @@ impl<'a, 'tcx> Aliases<'a, 'tcx> { // subset('a, 'b) :- subset_base('a, 'b, _). for (a, b, _) in subset_base { - if ignore_regions.contains(a) || ignore_regions.contains(b) { + if ignore_regions.contains(&a) || ignore_regions.contains(&b) { continue; } - subset.insert(*a, *b); + subset.insert(a, b); } // subset('static, 'a). @@ -186,19 +185,19 @@ impl<'a, 'tcx> Aliases<'a, 'tcx> { // If p = p^[* p2]: definite('a, ty(p2), p2^[]) // Else: definite('a, ty(p), p^[]). let mut gather_borrows = GatherBorrows::default(); - gather_borrows.visit_body(&body_with_facts.body); + gather_borrows.visit_body(body); for (region, kind, place) in gather_borrows.borrows { - if place.is_direct(body) { + if place.is_direct(body, tcx) { contains .entry(region) .or_default() .insert((place, kind.to_mutbl_lossy())); } - let def = match place.refs_in_projection().next() { + let def = match place.refs_in_projection(body, tcx).next() { Some((ptr, proj)) => { let ptr_ty = ptr.ty(body.local_decls(), tcx).ty; - (ptr_ty.builtin_deref(true).unwrap().ty, proj.to_vec()) + (ptr_ty.builtin_deref(true).unwrap(), proj.to_vec()) } None => ( body.local_decls()[place.local].ty, @@ -251,10 +250,12 @@ impl<'a, 'tcx> Aliases<'a, 'tcx> { .rows() .flat_map(|r1| subset.iter(r1).map(move |r2| (r1, r2))) .collect::>(); - let subset_graph = VecGraph::new(num_regions, edge_pairs); + let subset_graph = VecGraph::<_, false>::new(num_regions, edge_pairs); let subset_sccs = Sccs::::new(&subset_graph); - let mut scc_to_regions = - IndexVec::from_elem_n(HybridBitSet::new_empty(num_regions), subset_sccs.num_sccs()); + let mut scc_to_regions = IndexVec::from_elem_n( + ChunkedBitSet::new_empty(num_regions), + subset_sccs.num_sccs(), + ); for r in all_regions.clone() { let scc = subset_sccs.scc(r); scc_to_regions[scc].insert(r); @@ -344,6 +345,9 @@ impl<'a, 'tcx> Aliases<'a, 'tcx> { "Final places in loan set: {}", contains.values().map(|set| set.len()).sum::() ); + + log::trace!("contains: {contains:#?}"); + contains } @@ -368,24 +372,28 @@ impl<'a, 'tcx> Aliases<'a, 'tcx> { aliases.insert(place); // Places with no derefs, or derefs from arguments, have no aliases - if place.is_direct(self.body) { + if place.is_direct(self.body, self.tcx) { return aliases; } // place = after[*ptr] - let (ptr, after) = place.refs_in_projection().last().unwrap(); + let (ptr, after) = place + .refs_in_projection(self.body, self.tcx) + .last() + .unwrap(); // ptr : &'region orig_ty let ptr_ty = ptr.ty(self.body.local_decls(), self.tcx).ty; let (region, orig_ty) = match ptr_ty.kind() { - _ if ptr_ty.is_box() => (UNKNOWN_REGION, ptr_ty.boxed_ty()), - TyKind::RawPtr(TypeAndMut { ty, .. }) => (UNKNOWN_REGION, *ty), + _ if ptr_ty.is_box() => ( + UNKNOWN_REGION, + ptr_ty.boxed_ty().expect("Could not unbox boxed type??"), + ), + TyKind::RawPtr(ty, _) => (UNKNOWN_REGION, *ty), TyKind::Ref(Region(Interned(RegionKind::ReVar(region), _)), ty, _) => { (*region, *ty) } - _ => { - return aliases; - } + _ => return aliases, }; // For each p ∈ loans('region), diff --git a/crates/flowistry/src/mir/engine.rs b/crates/flowistry/src/mir/engine.rs index a6ad536813..07e34ad2f4 100644 --- a/crates/flowistry/src/mir/engine.rs +++ b/crates/flowistry/src/mir/engine.rs @@ -15,13 +15,13 @@ use std::rc::Rc; use either::Either; use indexical::ToIndex; -use rustc_data_structures::{graph::WithSuccessors, work_queue::WorkQueue}; +use rustc_data_structures::{graph::Successors, work_queue::WorkQueue}; use rustc_index::IndexVec; use rustc_middle::{ mir::{traversal, Body, Location}, ty::TyCtxt, }; -use rustc_mir_dataflow::{Analysis, Direction, JoinSemiLattice, ResultsVisitor}; +use rustc_mir_dataflow::{Analysis, Direction, JoinSemiLattice}; use rustc_utils::{ mir::location_or_arg::{ index::{LocationOrArgDomain, LocationOrArgIndex}, @@ -40,43 +40,6 @@ pub struct AnalysisResults<'tcx, A: Analysis<'tcx>> { } impl<'tcx, A: Analysis<'tcx>> AnalysisResults<'tcx, A> { - /// Same as [`rustc_mir_dataflow::Results::visit_reachable_with`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/struct.Results.html#method.visit_reachable_with). - pub fn visit_reachable_with<'mir, V>(&mut self, body: &'mir Body<'tcx>, visitor: &mut V) - where - V: ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, - { - for (block, data) in traversal::reachable(body) { - for statement_index in 0 ..= data.statements.len() { - let location = Location { - block, - statement_index, - }; - let loc_index = location.to_index(&self.location_domain); - let state = Rc::clone(&self.state[loc_index]); - - if statement_index == 0 { - visitor.visit_block_start(&state); - } - - if statement_index == data.statements.len() { - visitor.visit_terminator_after_primary_effect( - self, - &state, - data.terminator(), - location, - ) - } else { - visitor.visit_statement_after_primary_effect( - self, - &state, - &data.statements[statement_index], - location, - ) - } - } - } - } - /// Gets the computed [`AnalysisDomain`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.AnalysisDomain.html) /// at a given [`Location`]. pub fn state_at(&self, location: Location) -> &A::Domain { diff --git a/crates/flowistry/src/mir/placeinfo.rs b/crates/flowistry/src/mir/placeinfo.rs index f08a337d11..7c06f91e37 100644 --- a/crates/flowistry/src/mir/placeinfo.rs +++ b/crates/flowistry/src/mir/placeinfo.rs @@ -82,7 +82,7 @@ impl<'a, 'tcx> PlaceInfo<'a, 'tcx> { pub fn normalize(&self, place: Place<'tcx>) -> Place<'tcx> { self .normalized_cache - .get(place, |place| place.normalize(self.tcx, self.def_id)) + .get(&place, |place| place.normalize(self.tcx, self.def_id)) } /// Computes the aliases of a place (cached). @@ -94,7 +94,7 @@ impl<'a, 'tcx> PlaceInfo<'a, 'tcx> { // which contains region information self .aliases_cache - .get(self.normalize(place), move |_| self.aliases.aliases(place)) + .get(&self.normalize(place), move |_| self.aliases.aliases(place)) } /// Returns all reachable fields of `place` without going through references. @@ -104,16 +104,31 @@ impl<'a, 'tcx> PlaceInfo<'a, 'tcx> { PlaceSet::from_iter(place.interior_places(self.tcx, self.body, self.def_id)) } - /// Returns all places that conflict with `place`, i.e. that a mutation to `place` + /// Returns all places that *directly* conflict with `place`, i.e. that a mutation to `place` /// would also be a mutation to the conflicting place. /// /// For example, if `x = ((0, 1), 2)` then `conflicts(x.0) = {x, x.0, x.0.0, x.0.1}`, but not `x.1`. + /// + /// For indirect places, this function follows conflicting parents up until a reference point. + /// So if `x = (0, &(box 1, 2))` then conflicts(*(*(x.1).0)) = {*(*(x.1).0), *(x.1).0, *(x.1)} pub fn conflicts(&self, place: Place<'tcx>) -> &PlaceSet<'tcx> { - self.conflicts_cache.get(place, |place| { + self.conflicts_cache.get(&place, |place| { let children = self.children(place); let parents = place - .iter_projections() - .take_while(|(_, elem)| !matches!(elem, PlaceElem::Deref)) + .projection + .iter() + .enumerate() + .map(|(i, elem)| { + let place = PlaceRef { + local: place.local, + projection: &place.projection[.. i], + }; + (place, elem) + }) + .take_while(|(place, elem)| { + place.ty(self.body.local_decls(), self.tcx).ty.is_box() + || !matches!(elem, PlaceElem::Deref) + }) .map(|(place_ref, _)| Place::from_ref(place_ref, self.tcx)); children.into_iter().chain(parents).collect() }) @@ -129,20 +144,20 @@ impl<'a, 'tcx> PlaceInfo<'a, 'tcx> { place: Place<'tcx>, mutability: Mutability, ) -> &PlaceSet<'tcx> { - self.reachable_cache.get((place, mutability), |_| { + self.reachable_cache.get(&(place, mutability), |_| { let ty = place.ty(self.body.local_decls(), self.tcx).ty; let loans = self.collect_loans(ty, mutability); loans .into_iter() .chain([place]) .filter(|place| { - if let Some((place, _)) = place.refs_in_projection().last() { + if let Some((place, _)) = place.refs_in_projection(self.body, self.tcx).last() { let ty = place.ty(self.body.local_decls(), self.tcx).ty; if ty.is_box() || ty.is_unsafe_ptr() { return true; } } - place.is_direct(self.body) + place.is_direct(self.body, self.tcx) }) .collect() }) @@ -201,9 +216,9 @@ struct LoanCollector<'a, 'tcx> { } impl<'tcx> TypeVisitor> for LoanCollector<'_, 'tcx> { - type BreakTy = (); + type Result = ControlFlow<()>; - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { match ty.kind() { TyKind::Ref(_, _, mutability) => { self.stack.push(*mutability); @@ -221,7 +236,7 @@ impl<'tcx> TypeVisitor> for LoanCollector<'_, 'tcx> { ControlFlow::Continue(()) } - fn visit_region(&mut self, region: Region<'tcx>) -> ControlFlow { + fn visit_region(&mut self, region: Region<'tcx>) -> Self::Result { let region = match region.kind() { RegionKind::ReVar(region) => region, RegionKind::ReStatic => RegionVid::from_usize(0), diff --git a/crates/flowistry/src/mir/utils.rs b/crates/flowistry/src/mir/utils.rs index 073b562d64..6d4834b9e1 100644 --- a/crates/flowistry/src/mir/utils.rs +++ b/crates/flowistry/src/mir/utils.rs @@ -6,6 +6,7 @@ use rustc_middle::{ mir::*, ty::{GenericArgKind, RegionKind, RegionVid, Ty, TyCtxt}, }; +use rustc_span::source_map::Spanned; use rustc_utils::{BodyExt, OperandExt, PlaceExt}; use crate::extensions::{is_extension_active, MutabilityMode}; @@ -46,11 +47,11 @@ pub fn arg_mut_ptrs<'tcx>( } /// Given the arguments to a function, returns all places in the arguments. -pub fn arg_places<'tcx>(args: &[Operand<'tcx>]) -> Vec<(usize, Place<'tcx>)> { +pub fn arg_places<'tcx>(args: &[Spanned>]) -> Vec<(usize, Place<'tcx>)> { args .iter() .enumerate() - .filter_map(|(i, arg)| arg.as_place().map(move |place| (i, place))) + .filter_map(|(i, arg)| arg.node.as_place().map(move |place| (i, place))) .collect::>() } diff --git a/crates/flowistry/src/test_utils.rs b/crates/flowistry/src/test_utils.rs index 265dea3c02..416d5f5783 100644 --- a/crates/flowistry/src/test_utils.rs +++ b/crates/flowistry/src/test_utils.rs @@ -2,7 +2,7 @@ #![allow(missing_docs)] -use std::{fs, io, panic, path::Path}; +use std::{cell::RefCell, fs, io, panic, path::Path}; use anyhow::Result; use fluid_let::fluid_set; @@ -19,7 +19,7 @@ use rustc_utils::{ range::{ByteRange, CharPos, ToSpan}, spanner::Spanner, }, - test_utils, + test_utils::{self, CompileBuilder}, }; use crate::{ @@ -30,11 +30,16 @@ use crate::{ pub fn compile_body_with_range( input: impl Into, compute_target: impl FnOnce() -> ByteRange + Send, - callback: impl for<'tcx> FnOnce(TyCtxt<'tcx>, BodyId, &BodyWithBorrowckFacts<'tcx>, ByteRange) + callback: impl for<'tcx> FnOnce(TyCtxt<'tcx>, BodyId, &'tcx BodyWithBorrowckFacts<'tcx>, ByteRange) + Send, ) { borrowck_facts::enable_mir_simplification(); - test_utils::compile_body_with_range(input, compute_target, callback) + CompileBuilder::new(input).compile(|result| { + let target = compute_target(); + let tcx = result.tcx; + let (body_id, body_with_facts) = result.as_body_with_range(target); + callback(tcx, body_id, body_with_facts, target) + }) } pub fn compile_body( @@ -61,19 +66,30 @@ pub fn bless( .collect::>(); delims.sort_by_key(|(_, i)| (i.line, i.column)); - let mut output = String::new(); + let output = RefCell::new(String::new()); + let mut flush = |pos: CharPos| { + while !delims.is_empty() && delims[0].1 == pos { + let (delim, _) = delims.remove(0); + output.borrow_mut().push_str(delim); + } + }; + + let line_count = contents.lines().count(); for (line, line_str) in contents.lines().enumerate() { for (column, chr) in line_str.chars().enumerate() { - while delims.len() > 0 && delims[0].1 == (CharPos { line, column }) { - let (delim, _) = delims.remove(0); - output.push_str(delim); - } - output.push(chr); + flush(CharPos { line, column }); + output.borrow_mut().push(chr); + } + flush(CharPos { + line, + column: line_str.chars().count(), + }); + if line != line_count - 1 { + output.borrow_mut().push('\n'); } - output.push('\n'); } - fs::write(path.with_extension("txt.expected"), output)?; + fs::write(path.with_extension("txt.expected"), output.into_inner())?; Ok(()) } @@ -140,7 +156,7 @@ pub fn test_command_output( None => HashSet::default(), }; - compare_ranges(expected, actual, &input_clean); + compare_ranges(&expected, &actual, &input_clean); } Err(err) if matches!(err.kind(), io::ErrorKind::NotFound) => { println!("{}", fmt_ranges(&input_clean, &actual)); diff --git a/crates/flowistry/tests/backward_slice/enum_write_branch_read_branch.txt.expected b/crates/flowistry/tests/backward_slice/enum_write_branch_read_branch.txt.expected index c091b2b113..9dc20e8da9 100644 --- a/crates/flowistry/tests/backward_slice/enum_write_branch_read_branch.txt.expected +++ b/crates/flowistry/tests/backward_slice/enum_write_branch_read_branch.txt.expected @@ -9,7 +9,7 @@ fn main() { `[if let Foo::Y(z) = &mut x { *z += 1; }]` - `[if let Foo::X(z) = ]`x`[ { + `[if let Foo::X(z) = x { z; }]` } \ No newline at end of file diff --git a/crates/flowistry/tests/backward_slice/macro_rules.txt.expected b/crates/flowistry/tests/backward_slice/macro_rules.txt.expected index a3cfc0ab10..5ace97c1c4 100644 --- a/crates/flowistry/tests/backward_slice/macro_rules.txt.expected +++ b/crates/flowistry/tests/backward_slice/macro_rules.txt.expected @@ -6,4 +6,3 @@ fn test() { `[let x = 1;]` `[let y = foo!(x);]` } - diff --git a/crates/flowistry_ide/src/bin/cargo-flowistry.rs b/crates/flowistry_ide/src/bin/cargo-flowistry.rs index 28116b9d84..caf418f099 100644 --- a/crates/flowistry_ide/src/bin/cargo-flowistry.rs +++ b/crates/flowistry_ide/src/bin/cargo-flowistry.rs @@ -1,3 +1,5 @@ +#![feature(rustc_private)] + fn main() { env_logger::init(); rustc_plugin::cli_main(flowistry_ide::FlowistryPlugin); diff --git a/crates/flowistry_ide/src/bin/flowistry-driver.rs b/crates/flowistry_ide/src/bin/flowistry-driver.rs index 292272dcb6..0245bac7bf 100644 --- a/crates/flowistry_ide/src/bin/flowistry-driver.rs +++ b/crates/flowistry_ide/src/bin/flowistry-driver.rs @@ -1,3 +1,5 @@ +#![feature(rustc_private)] + fn main() { env_logger::init(); rustc_plugin::driver_main(flowistry_ide::FlowistryPlugin); diff --git a/crates/flowistry_ide/src/spans.rs b/crates/flowistry_ide/src/spans.rs index 988457b88a..d6e16c4843 100644 --- a/crates/flowistry_ide/src/spans.rs +++ b/crates/flowistry_ide/src/spans.rs @@ -1,3 +1,4 @@ +use rustc_middle::ty::TyCtxt; use rustc_utils::source_map::{ filename::Filename, find_bodies::find_bodies, range::CharRange, }; @@ -18,30 +19,27 @@ struct Callbacks { } impl rustc_driver::Callbacks for Callbacks { - fn after_crate_root_parsing<'tcx>( + fn after_analysis<'tcx>( &mut self, _compiler: &rustc_interface::interface::Compiler, - queries: &'tcx rustc_interface::Queries<'tcx>, + tcx: TyCtxt<'tcx>, ) -> rustc_driver::Compilation { - queries.global_ctxt().unwrap().enter(|tcx| { - let spans = find_bodies(tcx).into_iter().map(|(span, _)| span); - - self.output = Some((|| { - let source_map = tcx.sess.source_map(); - let source_file = Filename::intern(&self.filename) - .find_source_file(source_map) - .map_err(|_| FlowistryError::FileNotFound)?; - - let spans = spans - .into_iter() - .filter(|span| { - source_map.lookup_source_file(span.lo()).name == source_file.name - }) - .filter_map(|span| CharRange::from_span(span, source_map).ok()) - .collect::>(); - Ok(SpansOutput { spans }) - })()); - }); + let spans = find_bodies(tcx).into_iter().map(|(span, _)| span); + + self.output = Some((|| { + let source_map = tcx.sess.source_map(); + let source_file = Filename::intern(&self.filename) + .find_source_file(source_map) + .map_err(|_| FlowistryError::FileNotFound)?; + + let spans = spans + .into_iter() + .filter(|span| source_map.lookup_source_file(span.lo()).name == source_file.name) + .filter_map(|span| CharRange::from_span(span, source_map).ok()) + .collect::>(); + Ok(SpansOutput { spans }) + })()); + rustc_driver::Compilation::Stop } } diff --git a/crates/flowistry_ifc/src/analysis.rs b/crates/flowistry_ifc/src/analysis.rs index 205187c769..2fda1cc3d9 100644 --- a/crates/flowistry_ifc/src/analysis.rs +++ b/crates/flowistry_ifc/src/analysis.rs @@ -1,5 +1,4 @@ #![allow(dead_code)] -#![allow(dead_code)] use std::io::Write; @@ -10,7 +9,7 @@ use rustc_hir::{def::Res, def_id::DefId, BodyId}; use rustc_infer::traits::EvaluationResult; use rustc_middle::{ mir::*, - ty::{ParamEnv, Ty, TyCtxt}, + ty::{ParamEnv, Ty, TyCtxt, TypingMode}, }; use rustc_mir_dataflow::JoinSemiLattice; use rustc_span::FileName; @@ -24,7 +23,7 @@ fn implements_trait<'tcx>( ty: Ty<'tcx>, trait_def_id: DefId, ) -> bool { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ty = tcx.erase_regions(ty); let result = infcx.type_implements_trait(trait_def_id, [ty], param_env); matches!( diff --git a/crates/flowistry_ifc/src/bin/cargo-ifc.rs b/crates/flowistry_ifc/src/bin/cargo-ifc.rs index b4c6e79047..c3026a9785 100644 --- a/crates/flowistry_ifc/src/bin/cargo-ifc.rs +++ b/crates/flowistry_ifc/src/bin/cargo-ifc.rs @@ -1,3 +1,5 @@ +#![feature(rustc_private)] + fn main() { env_logger::init(); rustc_plugin::cli_main(flowistry_ifc::IfcPlugin); diff --git a/crates/flowistry_ifc/src/bin/ifc-driver.rs b/crates/flowistry_ifc/src/bin/ifc-driver.rs index 3733bc64f5..231ec33974 100644 --- a/crates/flowistry_ifc/src/bin/ifc-driver.rs +++ b/crates/flowistry_ifc/src/bin/ifc-driver.rs @@ -1,3 +1,5 @@ +#![feature(rustc_private)] + fn main() { env_logger::init(); rustc_plugin::driver_main(flowistry_ifc::IfcPlugin); diff --git a/crates/flowistry_ifc/src/lib.rs b/crates/flowistry_ifc/src/lib.rs index 43ee1b47f1..d602c29d6d 100644 --- a/crates/flowistry_ifc/src/lib.rs +++ b/crates/flowistry_ifc/src/lib.rs @@ -86,26 +86,24 @@ impl rustc_driver::Callbacks for Callbacks { config.override_queries = Some(borrowck_facts::override_queries); } - fn after_crate_root_parsing<'tcx>( + fn after_analysis( &mut self, _compiler: &rustc_interface::interface::Compiler, - queries: &'tcx rustc_interface::Queries<'tcx>, + tcx: TyCtxt, ) -> rustc_driver::Compilation { - queries.global_ctxt().unwrap().enter(|tcx| { - let mut visitor = IfcVisitor { - tcx, - issue_found: IssueFound::No, - }; - tcx.hir().visit_all_item_likes_in_crate(&mut visitor); - - if let IssueFound::No = visitor.issue_found { - let mut stdout = StandardStream::stderr(ColorChoice::Auto); - let mut green_spec = ColorSpec::new(); - green_spec.set_fg(Some(Color::Green)); - stdout.set_color(&green_spec).unwrap(); - writeln!(stdout, "No security issues found!",).unwrap(); - } - }); + let mut visitor = IfcVisitor { + tcx, + issue_found: IssueFound::No, + }; + tcx.hir().visit_all_item_likes_in_crate(&mut visitor); + + if let IssueFound::No = visitor.issue_found { + let mut stdout = StandardStream::stderr(ColorChoice::Auto); + let mut green_spec = ColorSpec::new(); + green_spec.set_fg(Some(Color::Green)); + stdout.set_color(&green_spec).unwrap(); + writeln!(stdout, "No security issues found!",).unwrap(); + } rustc_driver::Compilation::Stop } diff --git a/crates/flowistry_ifc_traits/src/lib.rs b/crates/flowistry_ifc_traits/src/lib.rs index f8c76e1b8b..5ab6213179 100644 --- a/crates/flowistry_ifc_traits/src/lib.rs +++ b/crates/flowistry_ifc_traits/src/lib.rs @@ -5,7 +5,7 @@ pub trait Insecure {} impl Secure for &T {} -impl<'a> Insecure for fmt::Arguments<'a> {} +impl Insecure for fmt::Arguments<'_> {} pub struct InsecureString(pub String); impl Insecure for InsecureString {} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 30b1f569d1..02579191fb 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-01-06" +channel = "nightly-2024-12-01" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] \ No newline at end of file