diff options
Diffstat (limited to 'src/librustc_mir/util')
| -rw-r--r-- | src/librustc_mir/util/aggregate.rs | 6 | ||||
| -rw-r--r-- | src/librustc_mir/util/alignment.rs | 8 | ||||
| -rw-r--r-- | src/librustc_mir/util/borrowck_errors.rs | 37 | ||||
| -rw-r--r-- | src/librustc_mir/util/collect_writes.rs | 11 | ||||
| -rw-r--r-- | src/librustc_mir/util/def_use.rs | 10 | ||||
| -rw-r--r-- | src/librustc_mir/util/elaborate_drops.rs | 103 | ||||
| -rw-r--r-- | src/librustc_mir/util/graphviz.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/util/liveness.rs | 18 | ||||
| -rw-r--r-- | src/librustc_mir/util/patch.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/util/pretty.rs | 321 |
10 files changed, 380 insertions, 142 deletions
diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs index 927c8f6dfb2..e77d264b7ce 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/src/librustc_mir/util/aggregate.rs @@ -1,7 +1,7 @@ -use rustc::mir::*; -use rustc::ty::layout::VariantIdx; -use rustc::ty::{Ty, TyCtxt}; use rustc_index::vec::Idx; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_target::abi::VariantIdx; use std::iter::TrustedLen; diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index d7f2abfbe99..202e5e27f1d 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -1,5 +1,5 @@ -use rustc::mir::*; -use rustc::ty::{self, TyCtxt}; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; /// Returns `true` if this place is allowed to be less aligned /// than its containing struct (because it is within a packed @@ -8,7 +8,7 @@ pub fn is_disaligned<'tcx, L>( tcx: TyCtxt<'tcx>, local_decls: &L, param_env: ty::ParamEnv<'tcx>, - place: &Place<'tcx>, + place: Place<'tcx>, ) -> bool where L: HasLocalDecls<'tcx>, @@ -34,7 +34,7 @@ where } } -fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'tcx>) -> bool +fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>) -> bool where L: HasLocalDecls<'tcx>, { diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index d8ee059f1a6..808dd833774 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -1,10 +1,10 @@ -use rustc::ty::{self, Ty, TyCtxt}; use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{MultiSpan, Span}; impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { crate fn cannot_move_when_borrowed(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, span, E0505, "cannot move out of `{}` because it is borrowed", desc,) + struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,) } crate fn cannot_use_when_mutably_borrowed( @@ -18,12 +18,12 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { self, span, E0503, - "cannot use `{}` because it was mutably borrowed", + "cannot use {} because it was mutably borrowed", desc, ); - err.span_label(borrow_span, format!("borrow of `{}` occurs here", borrow_desc)); - err.span_label(span, format!("use of borrowed `{}`", borrow_desc)); + err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc)); + err.span_label(span, format!("use of borrowed {}", borrow_desc)); err } @@ -53,12 +53,12 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { old_load_end_span: Option<Span>, ) -> DiagnosticBuilder<'cx> { let via = - |msg: &str| if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) }; + |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; let mut err = struct_span_err!( self, new_loan_span, E0499, - "cannot borrow `{}`{} as mutable more than once at a time", + "cannot borrow {}{} as mutable more than once at a time", desc, via(opt_via), ); @@ -103,7 +103,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { self, new_loan_span, E0524, - "two closures require unique access to `{}` at the same time", + "two closures require unique access to {} at the same time", desc, ); if old_loan_span == new_loan_span { @@ -136,7 +136,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { self, new_loan_span, E0500, - "closure requires unique access to `{}` but {} is already borrowed{}", + "closure requires unique access to {} but {} is already borrowed{}", desc_new, noun_old, old_opt_via, @@ -168,7 +168,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { self, new_loan_span, E0501, - "cannot borrow `{}`{} as {} because previous closure \ + "cannot borrow {}{} as {} because previous closure \ requires unique access", desc_new, opt_via, @@ -201,13 +201,12 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { old_load_end_span: Option<Span>, ) -> DiagnosticBuilder<'cx> { let via = - |msg: &str| if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) }; + |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; let mut err = struct_span_err!( self, span, E0502, - "cannot borrow `{}`{} as {} because {} is also borrowed \ - as {}{}", + "cannot borrow {}{} as {} because {} is also borrowed as {}{}", desc_new, via(msg_new), kind_new, @@ -225,7 +224,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { err.span_label( span, format!( - "{} borrow of `{}` -- which overlaps with `{}` -- occurs here", + "{} borrow of {} -- which overlaps with {} -- occurs here", kind_new, msg_new, msg_old, ), ); @@ -248,12 +247,12 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { self, span, E0506, - "cannot assign to `{}` because it is borrowed", + "cannot assign to {} because it is borrowed", desc, ); - err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc)); - err.span_label(span, format!("assignment to borrowed `{}` occurs here", desc)); + err.span_label(borrow_span, format!("borrow of {} occurs here", desc)); + err.span_label(span, format!("assignment to borrowed {} occurs here", desc)); err } @@ -264,7 +263,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { is_arg: bool, ) -> DiagnosticBuilder<'cx> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; - struct_span_err!(self, span, E0384, "cannot assign {} `{}`", msg, desc,) + struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc) } crate fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { @@ -362,7 +361,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { self, mutate_span, E0510, - "cannot {} `{}` in {}", + "cannot {} {} in {}", action, immutable_place, immutable_section, diff --git a/src/librustc_mir/util/collect_writes.rs b/src/librustc_mir/util/collect_writes.rs index 6cd21316496..ecf3b08a96e 100644 --- a/src/librustc_mir/util/collect_writes.rs +++ b/src/librustc_mir/util/collect_writes.rs @@ -1,7 +1,6 @@ -use rustc::mir::visit::PlaceContext; -use rustc::mir::visit::Visitor; -use rustc::mir::ReadOnlyBodyAndCache; -use rustc::mir::{Local, Location}; +use rustc_middle::mir::visit::PlaceContext; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{Body, Local, Location}; crate trait FindAssignments { // Finds all statements that assign directly to local (i.e., X = ...) @@ -9,10 +8,10 @@ crate trait FindAssignments { fn find_assignments(&self, local: Local) -> Vec<Location>; } -impl<'a, 'tcx> FindAssignments for ReadOnlyBodyAndCache<'a, 'tcx> { +impl<'tcx> FindAssignments for Body<'tcx> { fn find_assignments(&self, local: Local) -> Vec<Location> { let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; - visitor.visit_body(*self); + visitor.visit_body(self); visitor.locations } } diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index aa9ddbdbda9..6b5f6aa991c 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -1,11 +1,11 @@ //! Def-use analysis. -use rustc::mir::visit::{MutVisitor, PlaceContext, Visitor}; -use rustc::mir::{ +use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::{ Body, BodyAndCache, Local, Location, PlaceElem, ReadOnlyBodyAndCache, VarDebugInfo, }; -use rustc::ty::TyCtxt; -use rustc_index::vec::IndexVec; +use rustc_middle::ty::TyCtxt; use std::mem; pub struct DefUseAnalysis { @@ -38,7 +38,7 @@ impl DefUseAnalysis { var_debug_info_index: 0, in_var_debug_info: false, }; - finder.visit_body(body); + finder.visit_body(&body); self.info = finder.info } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index f7239ae55fa..e3a96ca7896 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -1,13 +1,13 @@ use crate::util::patch::MirPatch; -use rustc::middle::lang_items; -use rustc::mir::*; -use rustc::traits::Reveal; -use rustc::ty::layout::VariantIdx; -use rustc::ty::subst::SubstsRef; -use rustc::ty::util::IntTypeExt; -use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; +use rustc_hir::lang_items; use rustc_index::vec::Idx; +use rustc_middle::mir::*; +use rustc_middle::traits::Reveal; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::util::IntTypeExt; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_target::abi::VariantIdx; use std::fmt; use std::convert::TryInto; @@ -100,7 +100,7 @@ where source_info: SourceInfo, - place: &'l Place<'tcx>, + place: Place<'tcx>, path: D::Path, succ: BasicBlock, unwind: Unwind, @@ -109,7 +109,7 @@ where pub fn elaborate_drop<'b, 'tcx, D>( elaborator: &mut D, source_info: SourceInfo, - place: &Place<'tcx>, + place: Place<'tcx>, path: D::Path, succ: BasicBlock, unwind: Unwind, @@ -126,7 +126,7 @@ where D: DropElaborator<'b, 'tcx>, 'tcx: 'b, { - fn place_ty(&self, place: &Place<'tcx>) -> Ty<'tcx> { + fn place_ty(&self, place: Place<'tcx>) -> Ty<'tcx> { place.ty(self.elaborator.body(), self.tcx()).ty } @@ -168,7 +168,7 @@ where self.elaborator.patch().patch_terminator( bb, TerminatorKind::Drop { - location: *self.place, + location: self.place, target: self.succ, unwind: self.unwind.into_option(), }, @@ -195,7 +195,7 @@ where /// (the move path is `None` if the field is a rest field). fn move_paths_for_fields( &self, - base_place: &Place<'tcx>, + base_place: Place<'tcx>, variant_path: D::Path, variant: &'tcx ty::VariantDef, substs: SubstsRef<'tcx>, @@ -219,7 +219,7 @@ where fn drop_subpath( &mut self, - place: &Place<'tcx>, + place: Place<'tcx>, path: Option<D::Path>, succ: BasicBlock, unwind: Unwind, @@ -267,12 +267,10 @@ where ) -> Vec<BasicBlock> { Some(succ) .into_iter() - .chain(fields.iter().rev().zip(unwind_ladder).map( - |(&(ref place, path), &unwind_succ)| { - succ = self.drop_subpath(place, path, succ, unwind_succ); - succ - }, - )) + .chain(fields.iter().rev().zip(unwind_ladder).map(|(&(place, path), &unwind_succ)| { + succ = self.drop_subpath(place, path, succ, unwind_succ); + succ + })) .collect() } @@ -315,7 +313,7 @@ where debug!("drop_ladder({:?}, {:?})", self, fields); let mut fields = fields; - fields.retain(|&(ref place, _)| { + fields.retain(|&(place, _)| { self.place_ty(place).needs_drop(self.tcx(), self.elaborator.param_env()) }); @@ -364,7 +362,7 @@ where let unwind_succ = self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup)); - self.drop_subpath(&interior, interior_path, succ, unwind_succ) + self.drop_subpath(interior, interior_path, succ, unwind_succ) } fn open_drop_for_adt(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { @@ -439,8 +437,7 @@ where self.place.clone(), ProjectionElem::Downcast(Some(variant.ident.name), variant_index), ); - let fields = - self.move_paths_for_fields(&base_place, variant_path, &variant, substs); + let fields = self.move_paths_for_fields(base_place, variant_path, &variant, substs); values.push(discr.val); if let Unwind::To(unwind) = unwind { // We can't use the half-ladder from the original @@ -527,9 +524,9 @@ where // way lies only trouble. let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); let discr = Place::from(self.new_temp(discr_ty)); - let discr_rv = Rvalue::Discriminant(*self.place); + let discr_rv = Rvalue::Discriminant(self.place); let switch_block = BasicBlockData { - statements: vec![self.assign(&discr, discr_rv)], + statements: vec![self.assign(discr, discr_rv)], terminator: Some(Terminator { source_info: self.source_info, kind: TerminatorKind::SwitchInt { @@ -549,7 +546,7 @@ where debug!("destructor_call_block({:?}, {:?})", self, succ); let tcx = self.tcx(); let drop_trait = tcx.lang_items().drop_trait().unwrap(); - let drop_fn = tcx.associated_items(drop_trait).in_definition_order().nth(0).unwrap(); + let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap(); let ty = self.place_ty(self.place); let substs = tcx.mk_substs_trait(ty, &[]); @@ -560,11 +557,11 @@ where let result = BasicBlockData { statements: vec![self.assign( - &Place::from(ref_place), + Place::from(ref_place), Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, - *self.place, + self.place, ), )], terminator: Some(Terminator { @@ -607,7 +604,7 @@ where &mut self, succ: BasicBlock, cur: Local, - length_or_end: &Place<'tcx>, + length_or_end: Place<'tcx>, ety: Ty<'tcx>, unwind: Unwind, ptr_based: bool, @@ -617,7 +614,7 @@ where let tcx = self.tcx(); let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut }); - let ptr = &Place::from(self.new_temp(ptr_ty)); + let ptr = Place::from(self.new_temp(ptr_ty)); let can_go = Place::from(self.new_temp(tcx.types.bool)); let one = self.constant_usize(1); @@ -631,7 +628,7 @@ where }; let drop_block = BasicBlockData { - statements: vec![self.assign(ptr, ptr_next), self.assign(&Place::from(cur), cur_next)], + statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { source_info: self.source_info, @@ -643,8 +640,8 @@ where let loop_block = BasicBlockData { statements: vec![self.assign( - &can_go, - Rvalue::BinaryOp(BinOp::Eq, copy(Place::from(cur)), copy(*length_or_end)), + can_go, + Rvalue::BinaryOp(BinOp::Eq, copy(Place::from(cur)), copy(length_or_end)), )], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { @@ -703,16 +700,16 @@ where } } - let move_ = |place: &Place<'tcx>| Operand::Move(*place); - let elem_size = &Place::from(self.new_temp(tcx.types.usize)); - let len = &Place::from(self.new_temp(tcx.types.usize)); + let move_ = |place: Place<'tcx>| Operand::Move(place); + let elem_size = Place::from(self.new_temp(tcx.types.usize)); + let len = Place::from(self.new_temp(tcx.types.usize)); static USIZE_SWITCH_ZERO: &[u128] = &[0]; let base_block = BasicBlockData { statements: vec![ self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), - self.assign(len, Rvalue::Len(*self.place)), + self.assign(len, Rvalue::Len(self.place)), ], is_cleanup: self.unwind.is_cleanup(), terminator: Some(Terminator { @@ -731,7 +728,7 @@ where self.elaborator.patch().new_block(base_block) } - /// Ceates a pair of drop-loops of `place`, which drops its contents, even + /// Creates a pair of drop-loops of `place`, which drops its contents, even /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, /// otherwise create an index loop. fn drop_loop_pair( @@ -748,10 +745,10 @@ where let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length }; let unwind = self.unwind.map(|unwind| { - self.drop_loop(unwind, cur, &length_or_end, ety, Unwind::InCleanup, ptr_based) + self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based) }); - let loop_block = self.drop_loop(self.succ, cur, &length_or_end, ety, unwind, ptr_based); + let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based); let cur = Place::from(cur); let drop_block_stmts = if ptr_based { @@ -761,17 +758,17 @@ where // cur = tmp as *mut T; // end = Offset(cur, len); vec![ - self.assign(&tmp, Rvalue::AddressOf(Mutability::Mut, *self.place)), - self.assign(&cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)), + self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)), + self.assign(cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)), self.assign( - &length_or_end, + length_or_end, Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length)), ), ] } else { // cur = 0 (length already pushed) let zero = self.constant_usize(0); - vec![self.assign(&cur, Rvalue::Use(zero))] + vec![self.assign(cur, Rvalue::Use(zero))] }; let drop_block = self.elaborator.patch().new_block(BasicBlockData { statements: drop_block_stmts, @@ -798,8 +795,8 @@ where fn open_drop(&mut self) -> BasicBlock { let ty = self.place_ty(self.place); match ty.kind { - ty::Closure(def_id, substs) => { - let tys: Vec<_> = substs.as_closure().upvar_tys(def_id, self.tcx()).collect(); + ty::Closure(_, substs) => { + let tys: Vec<_> = substs.as_closure().upvar_tys().collect(); self.open_drop_for_tuple(&tys) } // Note that `elaborate_drops` only drops the upvars of a generator, @@ -808,8 +805,8 @@ where // This should only happen for the self argument on the resume function. // It effetively only contains upvars until the generator transformation runs. // See librustc_body/transform/generator.rs for more details. - ty::Generator(def_id, substs, _) => { - let tys: Vec<_> = substs.as_generator().upvar_tys(def_id, self.tcx()).collect(); + ty::Generator(_, substs, _) => { + let tys: Vec<_> = substs.as_generator().upvar_tys().collect(); self.open_drop_for_tuple(&tys) } ty::Tuple(..) => { @@ -872,7 +869,7 @@ where debug!("drop_flag_reset_block({:?},{:?})", self, mode); let block = self.new_block(unwind, TerminatorKind::Goto { target: succ }); - let block_start = Location { block: block, statement_index: 0 }; + let block_start = Location { block, statement_index: 0 }; self.elaborator.clear_drop_flag(block_start, self.path, mode); block } @@ -921,7 +918,7 @@ where let call = TerminatorKind::Call { func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), - args: args, + args, destination: Some((unit_temp, target)), cleanup: None, from_hir_call: false, @@ -935,7 +932,7 @@ where fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { let block = - TerminatorKind::Drop { location: *self.place, target, unwind: unwind.into_option() }; + TerminatorKind::Drop { location: self.place, target, unwind: unwind.into_option() }; self.new_block(unwind, block) } @@ -992,7 +989,7 @@ where }) } - fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { - Statement { source_info: self.source_info, kind: StatementKind::Assign(box (*lhs, rhs)) } + fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { + Statement { source_info: self.source_info, kind: StatementKind::Assign(box (lhs, rhs)) } } } diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index 8291bc95880..aed29a076a4 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -1,7 +1,7 @@ -use rustc::mir::*; -use rustc::ty::TyCtxt; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; use std::fmt::Debug; use std::io::{self, Write}; diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index b12ad1e4c15..a1b7634f0c6 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -26,15 +26,15 @@ use crate::transform::MirSource; use crate::util::pretty::{dump_enabled, write_basic_block, write_mir_intro}; -use rustc::mir::visit::{ - MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor, -}; -use rustc::mir::Local; -use rustc::mir::*; -use rustc::ty::{self, TyCtxt}; use rustc_data_structures::work_queue::WorkQueue; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::visit::{ + MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor, +}; +use rustc_middle::mir::Local; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; use std::fs; use std::io::{self, BufWriter, Write}; use std::path::{Path, PathBuf}; @@ -265,7 +265,7 @@ pub fn dump_mir<'tcx>( body: &Body<'tcx>, result: &LivenessResult, ) { - if !dump_enabled(tcx, pass_name, source) { + if !dump_enabled(tcx, pass_name, source.def_id()) { return; } let node_path = ty::print::with_forced_impl_filename_line(|| { @@ -293,7 +293,7 @@ fn dump_matched_mir_node<'tcx>( writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?; writeln!(file, "// source = {:?}", source)?; writeln!(file, "// pass_name = {}", pass_name)?; - writeln!(file, "")?; + writeln!(file)?; write_mir_fn(tcx, source, body, &mut file, result)?; Ok(()) }); @@ -316,7 +316,7 @@ pub fn write_mir_fn<'tcx>( write_basic_block(tcx, block, body, &mut |_, _| Ok(()), w)?; print(w, " ", &result.outs)?; if block.index() + 1 != body.basic_blocks().len() { - writeln!(w, "")?; + writeln!(w)?; } } diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 473692a43f3..46f42f4db05 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -1,6 +1,6 @@ -use rustc::mir::*; -use rustc::ty::Ty; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::*; +use rustc_middle::ty::Ty; use rustc_span::Span; /// This struct represents a patch to MIR, which can add diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 6fd8f06fe8f..a81fcb54580 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -1,11 +1,17 @@ use super::graphviz::write_mir_fn_graphviz; use crate::transform::MirSource; -use rustc::mir::visit::Visitor; -use rustc::mir::*; -use rustc::ty::{self, TyCtxt}; +use either::Either; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_index::vec::Idx; +use rustc_middle::mir::interpret::{ + read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, +}; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_target::abi::Size; +use std::collections::BTreeSet; use std::fmt::Display; use std::fmt::Write as _; use std::fs; @@ -73,34 +79,21 @@ pub fn dump_mir<'tcx, F>( ) where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { - if !dump_enabled(tcx, pass_name, source) { + if !dump_enabled(tcx, pass_name, source.def_id()) { return; } - let node_path = ty::print::with_forced_impl_filename_line(|| { - // see notes on #41697 below - tcx.def_path_str(source.def_id()) - }); - dump_matched_mir_node( - tcx, - pass_num, - pass_name, - &node_path, - disambiguator, - source, - body, - extra_data, - ); + dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, source, body, extra_data); } -pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, source: MirSource<'tcx>) -> bool { +pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> bool { let filters = match tcx.sess.opts.debugging_opts.dump_mir { None => return false, Some(ref filters) => filters, }; let node_path = ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 below - tcx.def_path_str(source.def_id()) + tcx.def_path_str(def_id) }); filters.split('|').any(|or_filter| { or_filter.split('&').all(|and_filter| { @@ -117,7 +110,6 @@ fn dump_matched_mir_node<'tcx, F>( tcx: TyCtxt<'tcx>, pass_num: Option<&dyn Display>, pass_name: &str, - node_path: &str, disambiguator: &dyn Display, source: MirSource<'tcx>, body: &Body<'tcx>, @@ -127,14 +119,20 @@ fn dump_matched_mir_node<'tcx, F>( { let _: io::Result<()> = try { let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?; - writeln!(file, "// MIR for `{}`", node_path)?; - writeln!(file, "// source = {:?}", source)?; - writeln!(file, "// pass_name = {}", pass_name)?; - writeln!(file, "// disambiguator = {}", disambiguator)?; + let def_path = ty::print::with_forced_impl_filename_line(|| { + // see notes on #41697 above + tcx.def_path_str(source.def_id()) + }); + write!(file, "// MIR for `{}", def_path)?; + match source.promoted { + None => write!(file, "`")?, + Some(promoted) => write!(file, "::{:?}`", promoted)?, + } + writeln!(file, " {} {}", disambiguator, pass_name)?; if let Some(ref layout) = body.generator_layout { writeln!(file, "// generator_layout = {:?}", layout)?; } - writeln!(file, "")?; + writeln!(file)?; extra_data(PassWhere::BeforeCFG, &mut file)?; write_user_type_annotations(body, &mut file)?; write_mir_fn(tcx, source, body, &mut extra_data, &mut file)?; @@ -242,13 +240,13 @@ pub fn write_mir_pretty<'tcx>( first = false; } else { // Put empty lines between all items - writeln!(w, "")?; + writeln!(w)?; } write_mir_fn(tcx, MirSource::item(def_id), body, &mut |_, _| Ok(()), w)?; for (i, body) in tcx.promoted_mir(def_id).iter_enumerated() { - writeln!(w, "")?; + writeln!(w)?; let src = MirSource { instance: ty::InstanceDef::Item(def_id), promoted: Some(i) }; write_mir_fn(tcx, src, body, &mut |_, _| Ok(()), w)?; } @@ -271,11 +269,14 @@ where extra_data(PassWhere::BeforeBlock(block), w)?; write_basic_block(tcx, block, body, extra_data, w)?; if block.index() + 1 != body.basic_blocks().len() { - writeln!(w, "")?; + writeln!(w)?; } } writeln!(w, "}}")?; + + write_allocations(tcx, body, w)?; + Ok(()) } @@ -297,7 +298,7 @@ where writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?; // List of statements in the middle. - let mut current_location = Location { block: block, statement_index: 0 }; + let mut current_location = Location { block, statement_index: 0 }; for statement in &data.statements { extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_body = format!("{0}{0}{1:?};", INDENT, statement); @@ -391,8 +392,8 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - match rvalue { - Rvalue::Aggregate(kind, _) => match **kind { + if let Rvalue::Aggregate(kind, _) = rvalue { + match **kind { AggregateKind::Closure(def_id, substs) => { self.push("closure"); self.push(&format!("+ def_id: {:?}", def_id)); @@ -412,9 +413,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { } _ => {} - }, - - _ => {} + } } } } @@ -490,7 +489,7 @@ fn write_scope_tree( } let children = match scope_tree.get(&parent) { - Some(childs) => childs, + Some(children) => children, None => return Ok(()), }; @@ -529,7 +528,251 @@ pub fn write_mir_intro<'tcx>( write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; // Add an empty line before the first block is printed. - writeln!(w, "")?; + writeln!(w)?; + + Ok(()) +} + +/// Find all `AllocId`s mentioned (recursively) in the MIR body and print their corresponding +/// allocations. +pub fn write_allocations<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'_>, + w: &mut dyn Write, +) -> io::Result<()> { + fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator<Item = AllocId> + '_ { + alloc.relocations().values().map(|(_, id)| *id) + } + fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ { + match val { + ConstValue::Scalar(interpret::Scalar::Ptr(ptr)) => { + Either::Left(Either::Left(std::iter::once(ptr.alloc_id))) + } + ConstValue::Scalar(interpret::Scalar::Raw { .. }) => { + Either::Left(Either::Right(std::iter::empty())) + } + ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => { + Either::Right(alloc_ids_from_alloc(alloc)) + } + } + } + struct CollectAllocIds(BTreeSet<AllocId>); + impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ty::ConstKind::Value(val) = c.val { + self.0.extend(alloc_ids_from_const(val)); + } + c.super_visit_with(self) + } + } + let mut visitor = CollectAllocIds(Default::default()); + body.visit_with(&mut visitor); + let mut seen = visitor.0; + let mut todo: Vec<_> = seen.iter().copied().collect(); + while let Some(id) = todo.pop() { + let mut write_header_and_allocation = + |w: &mut dyn Write, alloc: &Allocation| -> io::Result<()> { + write!(w, "size: {}, align: {})", alloc.size.bytes(), alloc.align.bytes())?; + if alloc.size == Size::ZERO { + write!(w, " {{}}")?; + } else { + writeln!(w, " {{")?; + write_allocation(tcx, alloc, w, " ")?; + write!(w, "}}")?; + // `.rev()` because we are popping them from the back of the `todo` vector. + for id in alloc_ids_from_alloc(alloc).rev() { + if seen.insert(id) { + todo.push(id); + } + } + } + Ok(()) + }; + write!(w, "\n{}", id)?; + let alloc = tcx.alloc_map.lock().get(id); + match alloc { + // This can't really happen unless there are bugs, but it doesn't cost us anything to + // gracefully handle it and allow buggy rustc to be debugged via allocation printing. + None => write!(w, " (deallocated)")?, + Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?, + Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { + match tcx.const_eval_poly(did) { + Ok(ConstValue::ByRef { alloc, .. }) => { + write!(w, " (static: {}, ", tcx.def_path_str(did))?; + write_header_and_allocation(w, alloc)?; + } + Ok(_) => { + span_bug!(tcx.def_span(did), " static item without `ByRef` initializer") + } + Err(_) => write!( + w, + " (static: {}, error during initializer evaluation)", + tcx.def_path_str(did) + )?, + } + } + Some(GlobalAlloc::Static(did)) => { + write!(w, " (extern static: {})", tcx.def_path_str(did))? + } + Some(GlobalAlloc::Memory(alloc)) => { + write!(w, " (")?; + write_header_and_allocation(w, alloc)? + } + } + + writeln!(w)?; + } + Ok(()) +} + +fn write_allocation_endline(w: &mut dyn Write, ascii: &str) -> io::Result<()> { + for _ in 0..(BYTES_PER_LINE - ascii.chars().count()) { + write!(w, " ")?; + } + writeln!(w, " │ {}", ascii) +} + +/// Number of bytes to print per allocation hex dump line. +const BYTES_PER_LINE: usize = 16; + +/// Prints the line start address and returns the new line start address. +fn write_allocation_newline( + w: &mut dyn Write, + mut line_start: Size, + ascii: &str, + pos_width: usize, + prefix: &str, +) -> io::Result<Size> { + write_allocation_endline(w, ascii)?; + line_start += Size::from_bytes(BYTES_PER_LINE); + write!(w, "{}0x{:02$x} │ ", prefix, line_start.bytes(), pos_width)?; + Ok(line_start) +} + +/// Dumps the bytes of an allocation to the given writer. This also prints relocations instead of +/// the raw bytes where applicable. +/// The byte format is similar to how hex editors print bytes. Each line starts with the address of +/// the start of the line, followed by all bytes in hex format (space separated). +/// If the allocation is small enough to fit into a single line, no start address is given. +/// After the hex dump, an ascii dump follows, replacing all unprintable characters (control +/// characters or characters whose value is larger than 127) with a `.` +/// +/// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there +/// is only one line). Note that your prefix should contain a trailing space as the lines are +/// printed directly after it. +pub fn write_allocation<Tag, Extra>( + tcx: TyCtxt<'tcx>, + alloc: &Allocation<Tag, Extra>, + w: &mut dyn Write, + prefix: &str, +) -> io::Result<()> { + let num_lines = alloc.size.bytes_usize().saturating_sub(BYTES_PER_LINE); + // Number of chars needed to represent all line numbers. + let pos_width = format!("{:x}", alloc.size.bytes()).len(); + + if num_lines > 0 { + write!(w, "{}0x{:02$x} │ ", prefix, 0, pos_width)?; + } else { + write!(w, "{}", prefix)?; + } + + let mut i = Size::ZERO; + let mut line_start = Size::ZERO; + + let ptr_size = tcx.data_layout.pointer_size; + + let mut ascii = String::new(); + + let oversized_ptr = |target: &mut String, width| { + if target.len() > width { + write!(target, " ({} ptr bytes)", ptr_size.bytes()).unwrap(); + } + }; + + while i < alloc.size { + // The line start already has a space. While we could remove that space from the line start + // printing and unconditionally print a space here, that would cause the single-line case + // to have a single space before it, which looks weird. + if i != line_start { + write!(w, " ")?; + } + if let Some(&(_, target_id)) = alloc.relocations().get(&i) { + // Memory with a relocation must be defined + let j = i.bytes_usize(); + let offset = + alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize()); + let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap(); + let relocation_width = |bytes| bytes * 3; + let mut target = format!("{}+{}", target_id, offset); + if ((i - line_start) + ptr_size).bytes_usize() > BYTES_PER_LINE { + // This branch handles the situation where a relocation starts in the current line + // but ends in the next one. + let remainder = Size::from_bytes(BYTES_PER_LINE) - (i - line_start); + let overflow = ptr_size - remainder; + let remainder_width = relocation_width(remainder.bytes_usize()) - 2; + let overflow_width = relocation_width(overflow.bytes_usize() - 1) + 1; + ascii.push('╾'); + for _ in 0..remainder.bytes() - 1 { + ascii.push('─'); + } + if overflow_width > remainder_width && overflow_width >= target.len() { + // The case where the relocation fits into the part in the next line + write!(w, "╾{0:─^1$}", "", remainder_width)?; + line_start = + write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; + ascii.clear(); + write!(w, "{0:─^1$}╼", target, overflow_width)?; + } else { + oversized_ptr(&mut target, remainder_width); + write!(w, "╾{0:─^1$}", target, remainder_width)?; + line_start = + write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; + write!(w, "{0:─^1$}╼", "", overflow_width)?; + ascii.clear(); + } + for _ in 0..overflow.bytes() - 1 { + ascii.push('─'); + } + ascii.push('╼'); + i += ptr_size; + continue; + } else { + // This branch handles a relocation that starts and ends in the current line. + let relocation_width = relocation_width(ptr_size.bytes_usize() - 1); + oversized_ptr(&mut target, relocation_width); + ascii.push('╾'); + write!(w, "╾{0:─^1$}╼", target, relocation_width)?; + for _ in 0..ptr_size.bytes() - 2 { + ascii.push('─'); + } + ascii.push('╼'); + i += ptr_size; + } + } else if alloc.undef_mask().is_range_defined(i, i + Size::from_bytes(1)).is_ok() { + let j = i.bytes_usize(); + + // Checked definedness (and thus range) and relocations. This access also doesn't + // influence interpreter execution but is only for debugging. + let c = alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + 1)[0]; + write!(w, "{:02x}", c)?; + if c.is_ascii_control() || c >= 0x80 { + ascii.push('.'); + } else { + ascii.push(char::from(c)); + } + i += Size::from_bytes(1); + } else { + write!(w, "__")?; + ascii.push('░'); + i += Size::from_bytes(1); + } + // Print a new line header if the next line still has some bytes to print. + if i == line_start + Size::from_bytes(BYTES_PER_LINE) && i != alloc.size { + line_start = write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; + ascii.clear(); + } + } + write_allocation_endline(w, &ascii)?; Ok(()) } @@ -545,7 +788,7 @@ fn write_mir_sig( trace!("write_mir_sig: {:?}", src.instance); let kind = tcx.def_kind(src.def_id()); let is_function = match kind { - Some(DefKind::Fn) | Some(DefKind::Method) | Some(DefKind::Ctor(..)) => true, + Some(DefKind::Fn) | Some(DefKind::AssocFn) | Some(DefKind::Ctor(..)) => true, _ => tcx.is_closure(src.def_id()), }; match (kind, src.promoted) { @@ -561,7 +804,7 @@ fn write_mir_sig( ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere - write!(w, " {}", tcx.def_path_str(src.def_id())) + write!(w, "{}", tcx.def_path_str(src.def_id())) })?; if src.promoted.is_none() && is_function { |
