diff --git a/crates/rustc_plugin/Cargo.toml b/crates/rustc_plugin/Cargo.toml index 631ebb5d6..b4e4bd72b 100644 --- a/crates/rustc_plugin/Cargo.toml +++ b/crates/rustc_plugin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustc_plugin" -version = "0.7.4-nightly-2023-08-25" +version = "0.8.0-nightly-2023-12-04" edition = "2021" authors = ["Will Crichton "] description = "A framework for writing plugins that integrate with the Rust compiler" diff --git a/crates/rustc_plugin/examples/print-all-items/src/lib.rs b/crates/rustc_plugin/examples/print-all-items/src/lib.rs index 7709dc0d6..37c618799 100644 --- a/crates/rustc_plugin/examples/print-all-items/src/lib.rs +++ b/crates/rustc_plugin/examples/print-all-items/src/lib.rs @@ -77,7 +77,6 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { // all the type-checking has completed. fn after_analysis<'tcx>( &mut self, - _handler: &rustc_session::EarlyErrorHandler, _compiler: &rustc_interface::interface::Compiler, queries: &'tcx rustc_interface::Queries<'tcx>, ) -> rustc_driver::Compilation { diff --git a/crates/rustc_plugin/src/driver.rs b/crates/rustc_plugin/src/driver.rs index ca2a826df..e9ff3dbb8 100644 --- a/crates/rustc_plugin/src/driver.rs +++ b/crates/rustc_plugin/src/driver.rs @@ -5,7 +5,7 @@ use std::{ process::{exit, Command}, }; -use rustc_session::{config::ErrorOutputType, EarlyErrorHandler}; +use rustc_session::{config::ErrorOutputType, EarlyDiagCtxt}; use rustc_tools_util::VersionInfo; use super::plugin::{RustcPlugin, PLUGIN_ARGS}; @@ -100,8 +100,8 @@ impl rustc_driver::Callbacks for DefaultCallbacks {} /// The top-level function that should be called by your internal driver binary. pub fn driver_main(plugin: T) { - let handler = EarlyErrorHandler::new(ErrorOutputType::default()); - rustc_driver::init_rustc_env_logger(&handler); + let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); + rustc_driver::init_rustc_env_logger(&early_dcx); exit(rustc_driver::catch_with_exit_code(move || { let mut orig_args: Vec = env::args().collect(); diff --git a/crates/rustc_utils/Cargo.toml b/crates/rustc_utils/Cargo.toml index 19405ee82..b4f4aa5f5 100644 --- a/crates/rustc_utils/Cargo.toml +++ b/crates/rustc_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustc_utils" -version = "0.7.4-nightly-2023-08-25" +version = "0.8.0-nightly-2023-12-04" edition = "2021" authors = ["Will Crichton "] description = "Utilities for working with the Rust compiler" diff --git a/crates/rustc_utils/src/lib.rs b/crates/rustc_utils/src/lib.rs index 1b21a871c..4f1d8bcd0 100644 --- a/crates/rustc_utils/src/lib.rs +++ b/crates/rustc_utils/src/lib.rs @@ -35,7 +35,6 @@ extern crate rustc_index; extern crate rustc_infer; extern crate rustc_interface; extern crate rustc_macros; -#[macro_use] extern crate rustc_middle; extern crate rustc_mir_dataflow; extern crate rustc_mir_transform; diff --git a/crates/rustc_utils/src/mir/body.rs b/crates/rustc_utils/src/mir/body.rs index 67ef5e15f..395f63036 100644 --- a/crates/rustc_utils/src/mir/body.rs +++ b/crates/rustc_utils/src/mir/body.rs @@ -7,14 +7,12 @@ use std::{ }; use anyhow::{ensure, Result}; -use cfg_if::cfg_if; use rustc_data_structures::{captures::Captures, fx::FxHashMap as HashMap}; -use rustc_hir::{def_id::DefId, GeneratorKind, HirId}; +use rustc_hir::{def_id::DefId, CoroutineDesugaring, CoroutineKind, HirId}; use rustc_middle::{ mir::{pretty::write_mir_fn, *}, ty::{Region, Ty, TyCtxt}, }; -use rustc_mir_dataflow::{fmt::DebugWithContext, Analysis, Results}; use smallvec::SmallVec; use super::control_dependencies::ControlDependencies; @@ -83,18 +81,6 @@ pub trait BodyExt<'tcx> { /// Returns an iterator over all the regions that appear in the body's return type. fn regions_in_return(&self) -> Self::ReturnRegionsIter; - - /// Visualizes analysis results using graphviz/dot and writes them to - /// a file in the `target/` directory named `.pdf`. - fn write_analysis_results( - &self, - results: &mut Results<'tcx, A>, - def_id: DefId, - tcx: TyCtxt<'tcx>, - ) -> Result<()> - where - A: Analysis<'tcx>, - A::Domain: DebugWithContext; } impl<'tcx> BodyExt<'tcx> for Body<'tcx> { @@ -170,7 +156,10 @@ impl<'tcx> BodyExt<'tcx> for Body<'tcx> { } fn async_context(&self, tcx: TyCtxt<'tcx>, def_id: DefId) -> Option> { - if matches!(tcx.generator_kind(def_id), Some(GeneratorKind::Async(..))) { + if matches!( + tcx.coroutine_kind(def_id), + Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) + ) { Some(self.local_decls[Local::from_usize(2)].ty) } else { None @@ -204,38 +193,6 @@ impl<'tcx> BodyExt<'tcx> for Body<'tcx> { Place::from_local(local, tcx).interior_paths(tcx, self, def_id) }) } - - #[allow(unused)] - fn write_analysis_results( - &self, - results: &mut Results<'tcx, A>, - def_id: DefId, - tcx: TyCtxt<'tcx>, - ) -> Result<()> - where - A: Analysis<'tcx>, - A::Domain: DebugWithContext, - { - cfg_if! { - if #[cfg(feature = "graphviz")] { - use rustc_graphviz as dot; - use rustc_mir_dataflow::graphviz; - - let graphviz = - graphviz::Formatter::new(self, results, graphviz::OutputStyle::AfterOnly); - let mut buf = Vec::new(); - dot::render(&graphviz, &mut buf)?; - - let output_dir = Path::new("target"); - let fname = tcx.def_path_debug_str(def_id); - let output_path = output_dir.join(format!("{fname}.pdf")); - - run_dot(&output_path, buf) - } else { - anyhow::bail!("graphviz feature is not enabled") - } - } - } } pub fn run_dot(path: &Path, buf: Vec) -> Result<()> { diff --git a/crates/rustc_utils/src/mir/borrowck_facts.rs b/crates/rustc_utils/src/mir/borrowck_facts.rs index b9962d2d2..55c9db4ba 100644 --- a/crates/rustc_utils/src/mir/borrowck_facts.rs +++ b/crates/rustc_utils/src/mir/borrowck_facts.rs @@ -7,8 +7,8 @@ use rustc_data_structures::fx::FxHashSet as HashSet; use rustc_hir::def_id::LocalDefId; use rustc_middle::{ mir::{Body, BorrowCheckResult, MirPass, StatementKind, TerminatorKind}, - query::{ExternProviders, Providers}, ty::TyCtxt, + util::Providers, }; use crate::{block_timer, cache::Cache, BodyExt}; @@ -65,11 +65,7 @@ pub fn enable_mir_simplification() { /// /// For why we need to do override mir_borrowck, see: /// -pub fn override_queries( - _session: &rustc_session::Session, - local: &mut Providers, - _external: &mut ExternProviders, -) { +pub fn override_queries(_session: &rustc_session::Session, local: &mut Providers) { local.mir_borrowck = mir_borrowck; } diff --git a/crates/rustc_utils/src/mir/control_dependencies.rs b/crates/rustc_utils/src/mir/control_dependencies.rs index e846a80ac..4a730bcfc 100644 --- a/crates/rustc_utils/src/mir/control_dependencies.rs +++ b/crates/rustc_utils/src/mir/control_dependencies.rs @@ -8,11 +8,7 @@ use std::fmt; -use rustc_data_structures::graph::{ - dominators::{Dominators, Iter as DominatorsIter}, - vec_graph::VecGraph, - *, -}; +use rustc_data_structures::graph::{dominators::Dominators, vec_graph::VecGraph, *}; use rustc_index::{ bit_set::{BitSet, HybridBitSet, SparseBitMatrix}, Idx, @@ -77,15 +73,19 @@ impl WithPredecessors for ReversedGraph<'_, G> { } /// Represents the post-dominators of a graph's nodes with respect to a particular exit. -pub struct PostDominators(Dominators); +pub struct PostDominators { + dominators: Dominators, + num_nodes: usize, +} impl PostDominators { /// Constructs the post-dominators by computing the dominators on a reversed graph. pub fn build>(graph: &G, exit: Node) -> Self { + let num_nodes = graph.num_nodes(); let mut reversed = ReversedGraph { graph, exit, - unreachable: BitSet::new_empty(graph.num_nodes()), + unreachable: BitSet::new_empty(num_nodes), }; let reachable = iterate::post_order_from(&reversed, exit); @@ -95,18 +95,25 @@ impl PostDominators { } let dominators = dominators::dominators(&reversed); - PostDominators::(dominators) + PostDominators { + dominators, + num_nodes, + } } /// Gets the node that immediately post-dominators `node`, if one exists. pub fn immediate_post_dominator(&self, node: Node) -> Option { - self.0.immediate_dominator(node) + self.dominators.immediate_dominator(node) } /// Gets all nodes that post-dominate `node`, if they exist. - pub fn post_dominators(&self, node: Node) -> Option> { - let reachable = self.0.is_reachable(node); - reachable.then(|| self.0.dominators(node)) + pub fn post_dominators(&self, node: Node) -> Option + '_> { + let reachable = self.dominators.is_reachable(node); + reachable.then(move || { + (0 .. self.num_nodes) + .map(Node::new) + .filter(move |other| self.dominators.dominates(*other, node)) + }) } } diff --git a/crates/rustc_utils/src/mir/mod.rs b/crates/rustc_utils/src/mir/mod.rs index bbb12892f..1b4c3b59c 100644 --- a/crates/rustc_utils/src/mir/mod.rs +++ b/crates/rustc_utils/src/mir/mod.rs @@ -8,6 +8,3 @@ pub mod location_or_arg; pub mod mutability; pub mod operand; pub mod place; - -#[allow(clippy::all, clippy::pedantic)] -pub mod places_conflict; diff --git a/crates/rustc_utils/src/mir/place.rs b/crates/rustc_utils/src/mir/place.rs index fdc962370..f2ff19e9d 100644 --- a/crates/rustc_utils/src/mir/place.rs +++ b/crates/rustc_utils/src/mir/place.rs @@ -526,7 +526,7 @@ impl<'tcx> TypeVisitor> for CollectRegions<'tcx> { StoppingCondition::BeforeRefs => {} }, - TyKind::Closure(_, substs) | TyKind::Generator(_, substs, _) => { + TyKind::Closure(_, substs) | TyKind::Coroutine(_, substs) => { self.visit_ty(substs.as_closure().tupled_upvars_ty()); } @@ -595,7 +595,7 @@ impl<'tcx> TypeVisitor> for CollectRegions<'tcx> { let region = match region.kind() { RegionKind::ReVar(region) => region, RegionKind::ReStatic => RegionVid::from_usize(0), - RegionKind::ReErased | RegionKind::ReLateBound(_, _) => { + RegionKind::ReErased | RegionKind::ReLateParam(_) => { return ControlFlow::Continue(()); } _ => unreachable!("{:?}: {:?}", self.ty_stack.first().unwrap(), region), diff --git a/crates/rustc_utils/src/mir/places_conflict.rs b/crates/rustc_utils/src/mir/places_conflict.rs deleted file mode 100644 index 4e80b38c3..000000000 --- a/crates/rustc_utils/src/mir/places_conflict.rs +++ /dev/null @@ -1,661 +0,0 @@ -//! Computes whether two places conflict with each other. -//! -//! Copied with no modifications from the Rust compiler. - -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] -use std::{cmp::max, iter}; - -use log::debug; -use rustc_hir as hir; -use rustc_middle::{ - mir::{ - Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, - }, - ty::{self, TyCtxt}, -}; - -#[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum ArtificialField { - ArrayLength, - ShallowBorrow, -} - -#[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum Overlap { - Arbitrary, - EqualOrDisjoint, - Disjoint, -} - -#[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum AccessDepth { - Shallow(Option), - Deep, - Drop, -} - -use AccessDepth::{Deep, Shallow}; - -/// When checking if a place conflicts with another place, this enum is used to influence decisions -/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`. -/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these -/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate -/// being run in the calling context, the conservative choice is to assume the compared indices -/// are disjoint (and therefore, do not overlap). -#[allow(dead_code)] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum PlaceConflictBias { - Overlap, - NoOverlap, -} - -/// Helper function for checking if places conflict with a mutable borrow and deep access depth. -/// This is used to check for places conflicting outside of the borrow checking code (such as in -/// dataflow). -#[allow(dead_code)] -pub fn places_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - access_place: Place<'tcx>, - bias: PlaceConflictBias, -) -> bool { - borrow_conflicts_with_place( - tcx, - body, - borrow_place, - BorrowKind::Mut { - kind: MutBorrowKind::TwoPhaseBorrow, - }, - access_place.as_ref(), - AccessDepth::Deep, - bias, - ) -} - -/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and -/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime -/// array indices, for example) should be interpreted - this depends on what the caller wants in -/// order to make the conservative choice and preserve soundness. -pub fn borrow_conflicts_with_place<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - borrow_kind: BorrowKind, - access_place: PlaceRef<'tcx>, - access: AccessDepth, - bias: PlaceConflictBias, -) -> bool { - // This Local/Local case is handled by the more general code below, but - // it's so common that it's a speed win to check for it first. - if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() { - return l1 == l2; - } - - place_components_conflict( - tcx, - body, - borrow_place, - borrow_kind, - access_place, - access, - bias, - ) -} - -fn place_components_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - borrow_kind: BorrowKind, - access_place: PlaceRef<'tcx>, - access: AccessDepth, - bias: PlaceConflictBias, -) -> bool { - // The borrowck rules for proving disjointness are applied from the "root" of the - // borrow forwards, iterating over "similar" projections in lockstep until - // we can prove overlap one way or another. Essentially, we treat `Overlap` as - // a monoid and report a conflict if the product ends up not being `Disjoint`. - // - // At each step, if we didn't run out of borrow or place, we know that our elements - // have the same type, and that they only overlap if they are the identical. - // - // For example, if we are comparing these: - // BORROW: (*x1[2].y).z.a - // ACCESS: (*x1[i].y).w.b - // - // Then our steps are: - // x1 | x1 -- places are the same - // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) - // x1[2].y | x1[i].y -- equal or disjoint - // *x1[2].y | *x1[i].y -- equal or disjoint - // (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more! - // - // Because `zip` does potentially bad things to the iterator inside, this loop - // also handles the case where the access might be a *prefix* of the borrow, e.g. - // - // BORROW: (*x1[2].y).z.a - // ACCESS: x1[i].y - // - // Then our steps are: - // x1 | x1 -- places are the same - // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) - // x1[2].y | x1[i].y -- equal or disjoint - // - // -- here we run out of access - the borrow can access a part of it. If this - // is a full deep access, then we *know* the borrow conflicts with it. However, - // if the access is shallow, then we can proceed: - // - // x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we - // are disjoint - // - // Our invariant is, that at each step of the iteration: - // - If we didn't run out of access to match, our borrow and access are comparable - // and either equal or disjoint. - // - If we did run out of access, the borrow can access a part of it. - - let borrow_local = borrow_place.local; - let access_local = access_place.local; - - match place_base_conflict(borrow_local, access_local) { - Overlap::Arbitrary => { - bug!("Two base can't return Arbitrary"); - } - Overlap::EqualOrDisjoint => { - // This is the recursive case - proceed to the next element. - } - Overlap::Disjoint => { - // We have proven the borrow disjoint - further - // projections will remain disjoint. - // debug!("borrow_conflicts_with_place: disjoint"); - return false; - } - } - - // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - for (i, (borrow_c, &access_c)) in - iter::zip(borrow_place.projection, access_place.projection).enumerate() - { - // debug!("{:?} {:?}", borrow_c, access_c); - - let borrow_proj_base = &borrow_place.projection[.. i]; - - // Borrow and access path both have more components. - // - // Examples: - // - // - borrow of `a.(...)`, access to `a.(...)` - // - borrow of `a.(...)`, access to `b.(...)` - // - // Here we only see the components we have checked so - // far (in our examples, just the first component). We - // check whether the components being borrowed vs - // accessed are disjoint (as in the second example, - // but not the first). - match place_projection_conflict( - tcx, - body, - borrow_local, - borrow_proj_base, - borrow_c, - access_c, - bias, - ) { - Overlap::Arbitrary => { - // We have encountered different fields of potentially - // the same union - the borrow now partially overlaps. - // - // There is no *easy* way of comparing the fields - // further on, because they might have different types - // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and - // `.y` come from different structs). - // - // We could try to do some things here - e.g., count - // dereferences - but that's probably not a good - // idea, at least for now, so just give up and - // report a conflict. This is unsafe code anyway so - // the user could always use raw pointers. - // debug!("arbitrary -> conflict"); - return true; - } - Overlap::EqualOrDisjoint => { - // This is the recursive case - proceed to the next element. - } - Overlap::Disjoint => { - // We have proven the borrow disjoint - further - // projections will remain disjoint. - // debug!("disjoint"); - return false; - } - } - } - - if borrow_place.projection.len() > access_place.projection.len() { - for (i, elem) in borrow_place.projection[access_place.projection.len() ..] - .iter() - .enumerate() - { - // Borrow path is longer than the access path. Examples: - // - // - borrow of `a.b.c`, access to `a.b` - // - // Here, we know that the borrow can access a part of - // our place. This is a conflict if that is a part our - // access cares about. - - let proj_base = &borrow_place.projection[.. access_place.projection.len() + i]; - let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty; - - match (elem, &base_ty.kind(), access) { - (_, _, Shallow(Some(ArtificialField::ArrayLength))) - | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { - // The array length is like additional fields on the - // type; it does not overlap any existing data there. - // Furthermore, if cannot actually be a prefix of any - // borrowed place (at least in MIR as it is currently.) - // - // e.g., a (mutable) borrow of `a[5]` while we read the - // array length of `a`. - // debug!("borrow_conflicts_with_place: implicit field"); - return false; - } - - (ProjectionElem::Deref, _, Shallow(None)) => { - // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some - // prefix thereof - the shallow access can't touch anything behind - // the pointer. - // debug!("borrow_conflicts_with_place: shallow access behind ptr"); - return false; - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Not), _) => { - // Shouldn't be tracked - bug!("Tracking borrow behind shared reference."); - } - ( - ProjectionElem::Deref, - ty::Ref(_, _, hir::Mutability::Mut), - AccessDepth::Drop, - ) => { - // Values behind a mutable reference are not access either by dropping a - // value, or by StorageDead - // debug!("borrow_conflicts_with_place: drop access behind ptr"); - return false; - } - - (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { - // Drop can read/write arbitrary projections, so places - // conflict regardless of further projections. - if def.has_dtor(tcx) { - return true; - } - } - - (ProjectionElem::Deref, _, Deep) - | (ProjectionElem::Deref, _, AccessDepth::Drop) - | (ProjectionElem::Field { .. }, _, _) - | (ProjectionElem::Index { .. }, _, _) - | (ProjectionElem::ConstantIndex { .. }, _, _) - | (ProjectionElem::Subslice { .. }, _, _) - | (ProjectionElem::OpaqueCast { .. }, _, _) - | (ProjectionElem::Downcast { .. }, _, _) => { - // Recursive case. This can still be disjoint on a - // further iteration if this a shallow access and - // there's a deref later on, e.g., a borrow - // of `*x.y` while accessing `x`. - } - } - } - } - - // Borrow path ran out but access path may not - // have. Examples: - // - // - borrow of `a.b`, access to `a.b.c` - // - borrow of `a.b`, access to `a.b` - // - // In the first example, where we didn't run out of - // access, the borrow can access all of our place, so we - // have a conflict. - // - // If the second example, where we did, then we still know - // that the borrow can access a *part* of our place that - // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Shallow - && borrow_place.projection.len() < access_place.projection.len() - { - // debug!("borrow_conflicts_with_place: shallow borrow"); - false - } else { - // debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); - true - } -} - -// Given that the bases of `elem1` and `elem2` are always either equal -// or disjoint (and have the same type!), return the overlap situation -// between `elem1` and `elem2`. -fn place_base_conflict(l1: Local, l2: Local) -> Overlap { - if l1 == l2 { - // the same local - base case, equal - // debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL"); - Overlap::EqualOrDisjoint - } else { - // different locals - base case, disjoint - // debug!("place_element_conflict: DISJOINT-LOCAL"); - Overlap::Disjoint - } -} - -// Given that the bases of `elem1` and `elem2` are always either equal -// or disjoint (and have the same type!), return the overlap situation -// between `elem1` and `elem2`. -fn place_projection_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - pi1_local: Local, - pi1_proj_base: &[PlaceElem<'tcx>], - pi1_elem: PlaceElem<'tcx>, - pi2_elem: PlaceElem<'tcx>, - bias: PlaceConflictBias, -) -> Overlap { - match (pi1_elem, pi2_elem) { - (ProjectionElem::Deref, ProjectionElem::Deref) => { - // derefs (e.g., `*x` vs. `*x`) - recur. - // debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); - Overlap::EqualOrDisjoint - } - (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => { - if v1 == v2 { - // same type - recur. - // debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE"); - Overlap::EqualOrDisjoint - } else { - // Different types. Disjoint! - // debug!("place_element_conflict: DISJOINT-OPAQUE"); - Overlap::Disjoint - } - } - (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { - if f1 == f2 { - // same field (e.g., `a.y` vs. `a.y`) - recur. - // debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { - let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; - if ty.is_union() { - // Different fields of a union, we are basically stuck. - // debug!("place_element_conflict: STUCK-UNION"); - Overlap::Arbitrary - } else { - // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! - // debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } - } - (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { - // different variants are treated as having disjoint fields, - // even if they occupy the same "space", because it's - // impossible for 2 variants of the same enum to exist - // (and therefore, to be borrowed) at the same time. - // - // Note that this is different from unions - we *do* allow - // this code to compile: - // - // ``` - // fn foo(x: &mut Result) { - // let mut v = None; - // if let Ok(ref mut a) = *x { - // v = Some(a); - // } - // // here, you would *think* that the - // // *entirety* of `x` would be borrowed, - // // but in fact only the `Ok` variant is, - // // so the `Err` variant is *entirely free*: - // if let Err(ref mut a) = *x { - // v = Some(a); - // } - // drop(v); - // } - // ``` - if v1 == v2 { - // debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { - // debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } - ( - ProjectionElem::Index(..), - ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. }, - ) - | ( - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }, - ProjectionElem::Index(..), - ) => { - // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint - // (if the indexes differ) or equal (if they are the same). - match bias { - PlaceConflictBias::Overlap => { - // If we are biased towards overlapping, then this is the recursive - // case that gives "equal *or* disjoint" its meaning. - // debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); - Overlap::EqualOrDisjoint - } - PlaceConflictBias::NoOverlap => { - // If we are biased towards no overlapping, then this is disjoint. - // debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); - Overlap::Disjoint - } - } - } - ( - ProjectionElem::ConstantIndex { - offset: o1, - min_length: _, - from_end: false, - }, - ProjectionElem::ConstantIndex { - offset: o2, - min_length: _, - from_end: false, - }, - ) - | ( - ProjectionElem::ConstantIndex { - offset: o1, - min_length: _, - from_end: true, - }, - ProjectionElem::ConstantIndex { - offset: o2, - min_length: _, - from_end: true, - }, - ) => { - if o1 == o2 { - // debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); - Overlap::EqualOrDisjoint - } else { - // debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { - offset: offset_from_begin, - min_length: min_length1, - from_end: false, - }, - ProjectionElem::ConstantIndex { - offset: offset_from_end, - min_length: min_length2, - from_end: true, - }, - ) - | ( - ProjectionElem::ConstantIndex { - offset: offset_from_end, - min_length: min_length1, - from_end: true, - }, - ProjectionElem::ConstantIndex { - offset: offset_from_begin, - min_length: min_length2, - from_end: false, - }, - ) => { - // both patterns matched so it must be at least the greater of the two - let min_length = max(min_length1, min_length2); - // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last - // element (like -1 in Python) and `min_length` the first. - // Therefore, `min_length - offset_from_end` gives the minimal possible - // offset from the beginning - if offset_from_begin >= min_length - offset_from_end { - // debug!( - // "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE" - // ); - Overlap::EqualOrDisjoint - } else { - // debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { - offset, - min_length: _, - from_end: false, - }, - ProjectionElem::Subslice { - from, - to, - from_end: false, - }, - ) - | ( - ProjectionElem::Subslice { - from, - to, - from_end: false, - }, - ProjectionElem::ConstantIndex { - offset, - min_length: _, - from_end: false, - }, - ) => { - if (from .. to).contains(&offset) { - // debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - // debug!( - // "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE" - // ); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { - offset, - min_length: _, - from_end: false, - }, - ProjectionElem::Subslice { from, .. }, - ) - | ( - ProjectionElem::Subslice { from, .. }, - ProjectionElem::ConstantIndex { - offset, - min_length: _, - from_end: false, - }, - ) => { - if offset >= from { - // debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - // debug!( - // "place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE" - // ); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { - offset, - min_length: _, - from_end: true, - }, - ProjectionElem::Subslice { - to, from_end: true, .. - }, - ) - | ( - ProjectionElem::Subslice { - to, from_end: true, .. - }, - ProjectionElem::ConstantIndex { - offset, - min_length: _, - from_end: true, - }, - ) => { - if offset > to { - // debug!( - // "place_element_conflict: \ - // DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE" - // ); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::Subslice { - from: f1, - to: t1, - from_end: false, - }, - ProjectionElem::Subslice { - from: f2, - to: t2, - from_end: false, - }, - ) => { - if f2 >= t1 || f1 >= t2 { - // debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES"); - Overlap::Disjoint - } else { - // debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); - Overlap::EqualOrDisjoint - } - } - (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { - // debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES"); - Overlap::EqualOrDisjoint - } - ( - ProjectionElem::Deref - | ProjectionElem::Field(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::OpaqueCast { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..), - _, - ) => bug!( - "mismatched projections in place_element_conflict: {:?} and {:?}", - pi1_elem, - pi2_elem - ), - } -} diff --git a/crates/rustc_utils/src/source_map/range.rs b/crates/rustc_utils/src/source_map/range.rs index 5012842d8..921588077 100644 --- a/crates/rustc_utils/src/source_map/range.rs +++ b/crates/rustc_utils/src/source_map/range.rs @@ -276,7 +276,7 @@ impl ByteRange { }; ensure!( - source_map.ensure_source_file_source_present(file.clone()), + source_map.ensure_source_file_source_present(&file), "Could not load source for file: {:?}", file.name ); diff --git a/crates/rustc_utils/src/source_map/span.rs b/crates/rustc_utils/src/source_map/span.rs index c39b4be42..ebf6845ac 100644 --- a/crates/rustc_utils/src/source_map/span.rs +++ b/crates/rustc_utils/src/source_map/span.rs @@ -184,7 +184,7 @@ mod test { #[test] fn test_span_subtract() { - rustc_span::create_default_session_if_not_set_then(|_| { + rustc_span::create_default_session_globals_then(|| { let mk = |lo, hi| Span::with_root_ctxt(BytePos(lo), BytePos(hi)); let outer = mk(1, 10); let inner: Vec = vec![mk(0, 2), mk(3, 4), mk(3, 5), mk(7, 8), mk(9, 13)]; diff --git a/crates/rustc_utils/src/source_map/spanner/hir_span.rs b/crates/rustc_utils/src/source_map/spanner/hir_span.rs index 53bb219e0..326309e9e 100644 --- a/crates/rustc_utils/src/source_map/spanner/hir_span.rs +++ b/crates/rustc_utils/src/source_map/spanner/hir_span.rs @@ -88,7 +88,7 @@ impl<'tcx> Spanner<'tcx> { pub fn hir_spans(&self, id: HirId, mode: EnclosingHirSpans) -> Option> { let hir = self.tcx.hir(); let span = try_span!(self, hir.span(id)); - let inner_spans = match hir.get(id) { + let inner_spans = match self.tcx.hir_node(id) { Node::Expr(expr) => match expr.kind { ExprKind::Loop(_, _, loop_source, header) => match loop_source { LoopSource::ForLoop | LoopSource::While => { diff --git a/crates/rustc_utils/src/source_map/spanner/span_tree.rs b/crates/rustc_utils/src/source_map/spanner/span_tree.rs index 3d95a5145..46ab60170 100644 --- a/crates/rustc_utils/src/source_map/spanner/span_tree.rs +++ b/crates/rustc_utils/src/source_map/spanner/span_tree.rs @@ -45,7 +45,7 @@ mod test { #[test] fn span_tree_test() { - rustc_span::create_default_session_if_not_set_then(|_| { + rustc_span::create_default_session_globals_then(|| { let mk_span = |lo, hi| SpanData { lo: BytePos(lo), hi: BytePos(hi), diff --git a/crates/rustc_utils/src/test_utils.rs b/crates/rustc_utils/src/test_utils.rs index 77a286955..f525a2775 100644 --- a/crates/rustc_utils/src/test_utils.rs +++ b/crates/rustc_utils/src/test_utils.rs @@ -7,7 +7,10 @@ use std::{ use anyhow::{anyhow, ensure, Context, Result}; use log::debug; use rustc_borrowck::consumers::BodyWithBorrowckFacts; -use rustc_data_structures::fx::{FxHashMap as HashMap, FxHashSet as HashSet}; +use rustc_data_structures::{ + fx::{FxHashMap as HashMap, FxHashSet as HashSet}, + sync::Lrc, +}; use rustc_hir::{BodyId, ItemKind}; use rustc_middle::{ mir::{Body, HasLocalDecls, Local, Place}, @@ -36,8 +39,8 @@ impl FileLoader for StringLoader { Ok(self.0.clone()) } - fn read_binary_file(&self, path: &Path) -> io::Result> { - fs::read(path) + fn read_binary_file(&self, path: &Path) -> io::Result> { + Ok(fs::read(path)?.into()) } } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c96eaf3b4..5972c366d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-08-25" +channel = "nightly-2024-01-06" components = ["clippy", "rust-src", "rustc-dev", "llvm-tools-preview"] \ No newline at end of file