From 5e96bb459377896a85be4a192e16feca4c1d4aaf Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 28 Jul 2020 16:15:40 +0200 Subject: [PATCH 1/3] Replace all uses of `log::log_enabled` with `Debug` printers --- src/librustc_interface/passes.rs | 12 +- src/librustc_metadata/creader.rs | 56 +++++--- src/librustc_metadata/lib.rs | 1 + src/librustc_middle/ty/context.rs | 43 +++--- src/librustc_mir/const_eval/machine.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 142 ++++++++++--------- src/librustc_mir/interpret/intrinsics.rs | 2 +- src/librustc_mir/interpret/memory.rs | 152 ++++++++++++--------- src/librustc_mir/interpret/place.rs | 2 +- src/librustc_mir/interpret/step.rs | 2 +- 10 files changed, 236 insertions(+), 178 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index f1b9fafc781..125a020de37 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -2,7 +2,7 @@ use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; -use log::{info, log_enabled, warn}; +use log::{info, warn}; use once_cell::sync::Lazy; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self, ast, visit}; @@ -1015,10 +1015,7 @@ pub fn start_codegen<'tcx>( tcx: TyCtxt<'tcx>, outputs: &OutputFilenames, ) -> Box { - if log_enabled!(::log::Level::Info) { - println!("Pre-codegen"); - tcx.print_debug_stats(); - } + info!("Pre-codegen\n{:?}", tcx.debug_stats()); let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs); @@ -1026,10 +1023,7 @@ pub fn start_codegen<'tcx>( codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); - if log_enabled!(::log::Level::Info) { - println!("Post-codegen"); - tcx.print_debug_stats(); - } + info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 724b4123fab..bb1370fabef 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -26,7 +26,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::{PanicStrategy, TargetTriple}; -use log::{debug, info, log_enabled}; +use log::{debug, info}; use proc_macro::bridge::client::ProcMacro; use std::path::Path; use std::{cmp, env, fs}; @@ -82,24 +82,38 @@ impl std::ops::Deref for CrateMetadataRef<'_> { } } -fn dump_crates(cstore: &CStore) { - info!("resolved crates:"); - cstore.iter_crate_data(|cnum, data| { - info!(" name: {}", data.name()); - info!(" cnum: {}", cnum); - info!(" hash: {}", data.hash()); - info!(" reqd: {:?}", data.dep_kind()); - let CrateSource { dylib, rlib, rmeta } = data.source(); - if let Some(dylib) = dylib { - info!(" dylib: {}", dylib.0.display()); - } - if let Some(rlib) = rlib { - info!(" rlib: {}", rlib.0.display()); - } - if let Some(rmeta) = rmeta { - info!(" rmeta: {}", rmeta.0.display()); - } - }); +struct CrateDump<'a>(&'a CStore); + +fn crate_dump(cstore: &'a CStore) -> impl std::fmt::Debug + 'a { + CrateDump(cstore) +} + +impl<'a> std::fmt::Debug for CrateDump<'a> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(fmt, "resolved crates:")?; + let mut res = Ok(()); + self.0.iter_crate_data(|cnum, data| { + res = res.and( + try { + writeln!(fmt, " name: {}", data.name())?; + writeln!(fmt, " cnum: {}", cnum)?; + writeln!(fmt, " hash: {}", data.hash())?; + writeln!(fmt, " reqd: {:?}", data.dep_kind())?; + let CrateSource { dylib, rlib, rmeta } = data.source(); + if let Some(dylib) = dylib { + writeln!(fmt, " dylib: {}", dylib.0.display())?; + } + if let Some(rlib) = rlib { + writeln!(fmt, " rlib: {}", rlib.0.display())?; + } + if let Some(rmeta) = rmeta { + writeln!(fmt, " rmeta: {}", rmeta.0.display())?; + } + }, + ); + }); + res + } } impl CStore { @@ -864,9 +878,7 @@ impl<'a> CrateLoader<'a> { self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); - if log_enabled!(log::Level::Info) { - dump_crates(&self.cstore); - } + info!("{:?}", crate_dump(&self.cstore)); self.report_unused_deps(krate); } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index d4add2ab7ad..059ae340bcf 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -9,6 +9,7 @@ #![feature(proc_macro_internals)] #![feature(min_specialization)] #![feature(stmt_expr_attributes)] +#![feature(try_blocks)] #![feature(never_type)] #![recursion_limit = "256"] diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index eeb58a0c55a..7b7db945324 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1831,7 +1831,7 @@ pub mod tls { } macro_rules! sty_debug_print { - ($ctxt: expr, $($variant: ident),*) => {{ + ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{ // Curious inner module to allow variant names to be used as // variable names. #[allow(non_snake_case)] @@ -1848,7 +1848,7 @@ macro_rules! sty_debug_print { all_infer: usize, } - pub fn go(tcx: TyCtxt<'_>) { + pub fn go(fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'_>) -> std::fmt::Result { let mut total = DebugStat { total: 0, lt_infer: 0, @@ -1878,8 +1878,8 @@ macro_rules! sty_debug_print { if ct { total.ct_infer += 1; variant.ct_infer += 1 } if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 } } - println!("Ty interner total ty lt ct all"); - $(println!(" {:18}: {uses:6} {usespc:4.1}%, \ + writeln!(fmt, "Ty interner total ty lt ct all")?; + $(writeln!(fmt, " {:18}: {uses:6} {usespc:4.1}%, \ {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%", stringify!($variant), uses = $variant.total, @@ -1887,9 +1887,9 @@ macro_rules! sty_debug_print { ty = $variant.ty_infer as f64 * 100.0 / total.total as f64, lt = $variant.lt_infer as f64 * 100.0 / total.total as f64, ct = $variant.ct_infer as f64 * 100.0 / total.total as f64, - all = $variant.all_infer as f64 * 100.0 / total.total as f64); + all = $variant.all_infer as f64 * 100.0 / total.total as f64)?; )* - println!(" total {uses:6} \ + writeln!(fmt, " total {uses:6} \ {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%", uses = total.total, ty = total.ty_infer as f64 * 100.0 / total.total as f64, @@ -1899,14 +1899,23 @@ macro_rules! sty_debug_print { } } - inner::go($ctxt) + inner::go($fmt, $ctxt) }} } impl<'tcx> TyCtxt<'tcx> { - pub fn print_debug_stats(self) { + pub fn debug_stats(self) -> impl std::fmt::Debug + 'tcx { + DebugStats(self) + } +} + +struct DebugStats<'tcx>(TyCtxt<'tcx>); + +impl std::fmt::Debug for DebugStats<'tcx> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { sty_debug_print!( - self, + fmt, + self.0, Adt, Array, Slice, @@ -1926,14 +1935,16 @@ impl<'tcx> TyCtxt<'tcx> { Projection, Opaque, Foreign - ); + )?; - println!("InternalSubsts interner: #{}", self.interners.substs.len()); - println!("Region interner: #{}", self.interners.region.len()); - println!("Stability interner: #{}", self.stability_interner.len()); - println!("Const Stability interner: #{}", self.const_stability_interner.len()); - println!("Allocation interner: #{}", self.allocation_interner.len()); - println!("Layout interner: #{}", self.layout_interner.len()); + writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?; + writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?; + writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?; + writeln!(fmt, "Const Stability interner: #{}", self.0.const_stability_interner.len())?; + writeln!(fmt, "Allocation interner: #{}", self.0.allocation_interner.len())?; + writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?; + + Ok(()) } } diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 6453630bb92..0dac8b64910 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -56,7 +56,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { self.copy_op(place.into(), dest)?; self.return_to_block(ret.map(|r| r.1))?; - self.dump_place(*dest); + trace!("{:?}", self.dump_place(*dest)); Ok(true) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3d3d756cffe..630b2890835 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1,5 +1,4 @@ use std::cell::Cell; -use std::fmt::Write; use std::mem; use rustc_data_structures::fx::FxHashMap; @@ -728,7 +727,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(return_place) = frame.return_place { let op = self.access_local(&frame, mir::RETURN_PLACE, None)?; self.copy_op_transmute(op, return_place)?; - self.dump_place(*return_place); + trace!("{:?}", self.dump_place(*return_place)); } else { throw_ub!(Unreachable); } @@ -823,9 +822,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // All locals have a backing allocation, even if the allocation is empty // due to the local having ZST type. let ptr = ptr.assert_ptr(); - if log_enabled!(::log::Level::Trace) { - self.memory.dump_alloc(ptr.alloc_id); - } + trace!("{:?}", self.memory.dump_alloc(ptr.alloc_id)); self.memory.deallocate_local(ptr)?; }; Ok(()) @@ -881,69 +878,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.raw_const_to_mplace(val) } - pub fn dump_place(&self, place: Place) { - // Debug output - if !log_enabled!(::log::Level::Trace) { - return; - } - match place { - Place::Local { frame, local } => { - let mut allocs = Vec::new(); - let mut msg = format!("{:?}", local); - if frame != self.frame_idx() { - write!(msg, " ({} frames up)", self.frame_idx() - frame).unwrap(); - } - write!(msg, ":").unwrap(); - - match self.stack()[frame].locals[local].value { - LocalValue::Dead => write!(msg, " is dead").unwrap(), - LocalValue::Uninitialized => write!(msg, " is uninitialized").unwrap(), - LocalValue::Live(Operand::Indirect(mplace)) => match mplace.ptr { - Scalar::Ptr(ptr) => { - write!( - msg, - " by align({}){} ref:", - mplace.align.bytes(), - match mplace.meta { - MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), - MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), - } - ) - .unwrap(); - allocs.push(ptr.alloc_id); - } - ptr => write!(msg, " by integral ref: {:?}", ptr).unwrap(), - }, - LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { - write!(msg, " {:?}", val).unwrap(); - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val { - allocs.push(ptr.alloc_id); - } - } - LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { - write!(msg, " ({:?}, {:?})", val1, val2).unwrap(); - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val1 { - allocs.push(ptr.alloc_id); - } - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val2 { - allocs.push(ptr.alloc_id); - } - } - } - - trace!("{}", msg); - self.memory.dump_allocs(allocs); - } - Place::Ptr(mplace) => match mplace.ptr { - Scalar::Ptr(ptr) => { - trace!("by align({}) ref:", mplace.align.bytes()); - self.memory.dump_alloc(ptr.alloc_id); - } - ptr => trace!(" integral by ref: {:?}", ptr), - }, - } + #[must_use] + pub fn dump_place(&'a self, place: Place) -> PlacePrinter<'a, 'mir, 'tcx, M> { + PlacePrinter { ecx: self, place } } + #[must_use] pub fn generate_stacktrace(&self) -> Vec> { let mut frames = Vec::new(); for frame in self.stack().iter().rev() { @@ -963,6 +903,76 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } +#[doc(hidden)] +/// Helper struct for the `dump_place` function. +pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { + ecx: &'a InterpCx<'mir, 'tcx, M>, + place: Place, +} + +impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug + for PlacePrinter<'a, 'mir, 'tcx, M> +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.place { + Place::Local { frame, local } => { + let mut allocs = Vec::new(); + write!(fmt, "{:?}", local)?; + if frame != self.ecx.frame_idx() { + write!(fmt, " ({} frames up)", self.ecx.frame_idx() - frame)?; + } + write!(fmt, ":")?; + + match self.ecx.stack()[frame].locals[local].value { + LocalValue::Dead => write!(fmt, " is dead")?, + LocalValue::Uninitialized => write!(fmt, " is uninitialized")?, + LocalValue::Live(Operand::Indirect(mplace)) => match mplace.ptr { + Scalar::Ptr(ptr) => { + write!( + fmt, + " by align({}){} ref:", + mplace.align.bytes(), + match mplace.meta { + MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), + MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), + } + )?; + allocs.push(ptr.alloc_id); + } + ptr => write!(fmt, " by integral ref: {:?}", ptr)?, + }, + LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { + write!(fmt, " {:?}", val)?; + if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val { + allocs.push(ptr.alloc_id); + } + } + LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { + write!(fmt, " ({:?}, {:?})", val1, val2)?; + if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val1 { + allocs.push(ptr.alloc_id); + } + if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr)) = val2 { + allocs.push(ptr.alloc_id); + } + } + } + + write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs)) + } + Place::Ptr(mplace) => match mplace.ptr { + Scalar::Ptr(ptr) => write!( + fmt, + "by align({}) ref: {:?}", + mplace.align.bytes(), + self.ecx.memory.dump_alloc(ptr.alloc_id) + ), + ptr => write!(fmt, " integral by ref: {:?}", ptr), + }, + } + } +} + impl<'ctx, 'mir, 'tcx, Tag, Extra> HashStable> for Frame<'mir, 'tcx, Tag, Extra> where diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 39ed3b60793..6681c4c7b82 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -430,7 +430,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => return Ok(false), } - self.dump_place(*dest); + trace!("{:?}", self.dump_place(*dest)); self.go_to_block(ret); Ok(true) } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index ea7a1c6cffa..0194c273f22 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -667,69 +667,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Ok(()) } - /// Print an allocation and all allocations it points to, recursively. - /// This prints directly to stderr, ignoring RUSTC_LOG! It is up to the caller to - /// control for this. - pub fn dump_alloc(&self, id: AllocId) { - self.dump_allocs(vec![id]); + /// Create a lazy debug printer that prints the given allocation and all allocations it points + /// to, recursively. + #[must_use] + pub fn dump_alloc<'a>(&'a self, id: AllocId) -> DumpAllocs<'a, 'mir, 'tcx, M> { + self.dump_allocs(vec![id]) } - /// Print a list of allocations and all allocations they point to, recursively. - /// This prints directly to stderr, ignoring RUSTC_LOG! It is up to the caller to - /// control for this. - pub fn dump_allocs(&self, mut allocs: Vec) { - // Cannot be a closure because it is generic in `Tag`, `Extra`. - fn write_allocation_track_relocs<'tcx, Tag: Copy + fmt::Debug, Extra>( - tcx: TyCtxt<'tcx>, - allocs_to_print: &mut VecDeque, - alloc: &Allocation, - ) { - for &(_, target_id) in alloc.relocations().values() { - allocs_to_print.push_back(target_id); - } - pretty::write_allocation(tcx, alloc, &mut std::io::stderr()).unwrap(); - } - + /// Create a lazy debug printer for a list of allocations and all allocations they point to, + /// recursively. + #[must_use] + pub fn dump_allocs<'a>(&'a self, mut allocs: Vec) -> DumpAllocs<'a, 'mir, 'tcx, M> { allocs.sort(); allocs.dedup(); - let mut allocs_to_print = VecDeque::from(allocs); - // `allocs_printed` contains all allocations that we have already printed. - let mut allocs_printed = FxHashSet::default(); - - while let Some(id) = allocs_to_print.pop_front() { - if !allocs_printed.insert(id) { - // Already printed, so skip this. - continue; - } - - eprint!("{}", id); - match self.alloc_map.get(id) { - Some(&(kind, ref alloc)) => { - // normal alloc - eprint!(" ({}, ", kind); - write_allocation_track_relocs(self.tcx, &mut allocs_to_print, alloc); - } - None => { - // global alloc - match self.tcx.get_global_alloc(id) { - Some(GlobalAlloc::Memory(alloc)) => { - eprint!(" (unchanged global, "); - write_allocation_track_relocs(self.tcx, &mut allocs_to_print, alloc); - } - Some(GlobalAlloc::Function(func)) => { - eprint!(" (fn: {})", func); - } - Some(GlobalAlloc::Static(did)) => { - eprint!(" (static: {})", self.tcx.def_path_str(did)); - } - None => { - eprint!(" (deallocated)"); - } - } - } - } - eprintln!(); - } + DumpAllocs { mem: self, allocs } } /// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation @@ -760,8 +711,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { }); let n = leaks.len(); if n > 0 { - eprintln!("The following memory was leaked:"); - self.dump_allocs(leaks); + eprintln!("The following memory was leaked: {:?}", self.dump_allocs(leaks)); } n } @@ -772,6 +722,86 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } } +#[doc(hidden)] +/// There's no way to use this directly, it's just a helper struct for the `dump_alloc(s)` methods. +pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { + mem: &'a Memory<'mir, 'tcx, M>, + allocs: Vec, +} + +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Cannot be a closure because it is generic in `Tag`, `Extra`. + fn write_allocation_track_relocs<'tcx, Tag: Copy + fmt::Debug, Extra>( + fmt: &mut std::fmt::Formatter<'_>, + tcx: TyCtxt<'tcx>, + allocs_to_print: &mut VecDeque, + alloc: &Allocation, + ) -> std::fmt::Result { + for &(_, target_id) in alloc.relocations().values() { + allocs_to_print.push_back(target_id); + } + // This vec dance is necessary, because there is no trait + // that supports writing to files and to `std::fmt::Formatter` at the + // same time. + let mut v = Vec::new(); + pretty::write_allocation(tcx, alloc, &mut v).unwrap(); + let s = String::from_utf8(v).unwrap(); + fmt.write_str(&s) + } + + let mut allocs_to_print: VecDeque<_> = self.allocs.iter().copied().collect(); + // `allocs_printed` contains all allocations that we have already printed. + let mut allocs_printed = FxHashSet::default(); + + while let Some(id) = allocs_to_print.pop_front() { + if !allocs_printed.insert(id) { + // Already printed, so skip this. + continue; + } + + write!(fmt, "{}", id)?; + match self.mem.alloc_map.get(id) { + Some(&(kind, ref alloc)) => { + // normal alloc + write!(fmt, " ({}, ", kind)?; + write_allocation_track_relocs( + &mut *fmt, + self.mem.tcx, + &mut allocs_to_print, + alloc, + )?; + } + None => { + // global alloc + match self.mem.tcx.get_global_alloc(id) { + Some(GlobalAlloc::Memory(alloc)) => { + write!(fmt, " (unchanged global, ")?; + write_allocation_track_relocs( + &mut *fmt, + self.mem.tcx, + &mut allocs_to_print, + alloc, + )?; + } + Some(GlobalAlloc::Function(func)) => { + write!(fmt, " (fn: {})", func)?; + } + Some(GlobalAlloc::Static(did)) => { + write!(fmt, " (static: {})", self.mem.tcx.def_path_str(did))?; + } + None => { + write!(fmt, " (deallocated)")?; + } + } + } + } + writeln!(fmt)?; + } + Ok(()) + } +} + /// Reading and writing. impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// Reads the given number of bytes from memory. Returns them as a slice. diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c5d17273225..15e341d9c4c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -648,7 +648,7 @@ where place_ty = self.place_projection(place_ty, &elem)? } - self.dump_place(place_ty.place); + trace!("{:?}", self.dump_place(place_ty.place)); // Sanity-check the type we ended up with. debug_assert!(mir_assign_valid_types( *self.tcx, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 3d1e3eccc61..fcd26c86c47 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -271,7 +271,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - self.dump_place(*dest); + trace!("{:?}", self.dump_place(*dest)); Ok(()) } From 7d67a1b871c41fb498eeffcadfa33f1fa4c35774 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 28 Jul 2020 19:16:09 +0200 Subject: [PATCH 2/3] Replace write-to-vec hack by introducing a display renderer for allocations --- src/librustc_mir/interpret/memory.rs | 8 +---- src/librustc_mir/util/pretty.rs | 52 +++++++++++++++++----------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 0194c273f22..a9e6e324eb2 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -741,13 +741,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, for &(_, target_id) in alloc.relocations().values() { allocs_to_print.push_back(target_id); } - // This vec dance is necessary, because there is no trait - // that supports writing to files and to `std::fmt::Formatter` at the - // same time. - let mut v = Vec::new(); - pretty::write_allocation(tcx, alloc, &mut v).unwrap(); - let s = String::from_utf8(v).unwrap(); - fmt.write_str(&s) + write!(fmt, "{}", pretty::display_allocation(tcx, alloc)) } let mut allocs_to_print: VecDeque<_> = self.allocs.iter().copied().collect(); diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 990bfc064c2..bed8672d911 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -588,7 +588,7 @@ pub fn write_allocations<'tcx>( todo.push(id); } } - write_allocation(tcx, alloc, w) + write!(w, "{}", display_allocation(tcx, alloc)) }; write!(w, "\n{}", id)?; match tcx.get_global_alloc(id) { @@ -640,24 +640,36 @@ pub fn write_allocations<'tcx>( /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control /// characters or characters whose value is larger than 127) with a `.` /// This also prints relocations adequately. -pub fn write_allocation( +pub fn display_allocation( tcx: TyCtxt<'tcx>, - alloc: &Allocation, - w: &mut dyn Write, -) -> io::Result<()> { - write!(w, "size: {}, align: {})", alloc.size.bytes(), alloc.align.bytes())?; - if alloc.size == Size::ZERO { - // We are done. - return write!(w, " {{}}"); - } - // Write allocation bytes. - writeln!(w, " {{")?; - write_allocation_bytes(tcx, alloc, w, " ")?; - write!(w, "}}")?; - Ok(()) + alloc: &'a Allocation, +) -> RenderAllocation<'a, 'tcx, Tag, Extra> { + RenderAllocation { tcx, alloc } } -fn write_allocation_endline(w: &mut dyn Write, ascii: &str) -> io::Result<()> { +#[doc(hidden)] +pub struct RenderAllocation<'a, 'tcx, Tag, Extra> { + tcx: TyCtxt<'tcx>, + alloc: &'a Allocation, +} + +impl std::fmt::Display for RenderAllocation<'a, 'tcx, Tag, Extra> { + fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let RenderAllocation { tcx, alloc } = *self; + write!(w, "size: {}, align: {})", alloc.size.bytes(), alloc.align.bytes())?; + if alloc.size == Size::ZERO { + // We are done. + return write!(w, " {{}}"); + } + // Write allocation bytes. + writeln!(w, " {{")?; + write_allocation_bytes(tcx, alloc, w, " ")?; + write!(w, "}}")?; + Ok(()) + } +} + +fn write_allocation_endline(w: &mut dyn std::fmt::Write, ascii: &str) -> std::fmt::Result { for _ in 0..(BYTES_PER_LINE - ascii.chars().count()) { write!(w, " ")?; } @@ -669,12 +681,12 @@ 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, + w: &mut dyn std::fmt::Write, mut line_start: Size, ascii: &str, pos_width: usize, prefix: &str, -) -> io::Result { +) -> Result { write_allocation_endline(w, ascii)?; line_start += Size::from_bytes(BYTES_PER_LINE); write!(w, "{}0x{:02$x} │ ", prefix, line_start.bytes(), pos_width)?; @@ -687,9 +699,9 @@ fn write_allocation_newline( fn write_allocation_bytes( tcx: TyCtxt<'tcx>, alloc: &Allocation, - w: &mut dyn Write, + w: &mut dyn std::fmt::Write, prefix: &str, -) -> io::Result<()> { +) -> std::fmt::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(); From b81d164f61804764c9e7f8f670bb7a79644c4c1a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 29 Jul 2020 11:37:33 +0200 Subject: [PATCH 3/3] Address review comments --- src/librustc_metadata/creader.rs | 8 ++- src/librustc_middle/ty/context.rs | 82 ++++++++++++++++--------------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index bb1370fabef..25320a8d6a7 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -84,13 +84,11 @@ impl std::ops::Deref for CrateMetadataRef<'_> { struct CrateDump<'a>(&'a CStore); -fn crate_dump(cstore: &'a CStore) -> impl std::fmt::Debug + 'a { - CrateDump(cstore) -} - impl<'a> std::fmt::Debug for CrateDump<'a> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(fmt, "resolved crates:")?; + // `iter_crate_data` does not allow returning values. Thus we use a mutable variable here + // that aggregates the value (and any errors that could happen). let mut res = Ok(()); self.0.iter_crate_data(|cnum, data| { res = res.and( @@ -878,7 +876,7 @@ impl<'a> CrateLoader<'a> { self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); - info!("{:?}", crate_dump(&self.cstore)); + info!("{:?}", CrateDump(&self.cstore)); self.report_unused_deps(krate); } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 7b7db945324..d307131a990 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1905,49 +1905,53 @@ macro_rules! sty_debug_print { impl<'tcx> TyCtxt<'tcx> { pub fn debug_stats(self) -> impl std::fmt::Debug + 'tcx { + struct DebugStats<'tcx>(TyCtxt<'tcx>); + + impl std::fmt::Debug for DebugStats<'tcx> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + sty_debug_print!( + fmt, + self.0, + Adt, + Array, + Slice, + RawPtr, + Ref, + FnDef, + FnPtr, + Placeholder, + Generator, + GeneratorWitness, + Dynamic, + Closure, + Tuple, + Bound, + Param, + Infer, + Projection, + Opaque, + Foreign + )?; + + writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?; + writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?; + writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?; + writeln!( + fmt, + "Const Stability interner: #{}", + self.0.const_stability_interner.len() + )?; + writeln!(fmt, "Allocation interner: #{}", self.0.allocation_interner.len())?; + writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?; + + Ok(()) + } + } + DebugStats(self) } } -struct DebugStats<'tcx>(TyCtxt<'tcx>); - -impl std::fmt::Debug for DebugStats<'tcx> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - sty_debug_print!( - fmt, - self.0, - Adt, - Array, - Slice, - RawPtr, - Ref, - FnDef, - FnPtr, - Placeholder, - Generator, - GeneratorWitness, - Dynamic, - Closure, - Tuple, - Bound, - Param, - Infer, - Projection, - Opaque, - Foreign - )?; - - writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?; - writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?; - writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?; - writeln!(fmt, "Const Stability interner: #{}", self.0.const_stability_interner.len())?; - writeln!(fmt, "Allocation interner: #{}", self.0.allocation_interner.len())?; - writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?; - - Ok(()) - } -} - /// An entry in an interner. struct Interned<'tcx, T: ?Sized>(&'tcx T);