Auto merge of #74876 - oli-obk:lumberjack_disable, r=RalfJung

Replace all uses of `log::log_enabled` with `Debug` printers

cc @RalfJung this touches a bunch of logging in the miri engine. There are some visual changes, mainly that in several cases we stop prepending lines with the module path and just have a newline.
This commit is contained in:
bors 2020-07-30 03:54:05 +00:00
commit 1799d31847
11 changed files with 284 additions and 218 deletions

View File

@ -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<dyn Any> {
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) {

View File

@ -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,36 @@ 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);
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(
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 +876,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!("{:?}", CrateDump(&self.cstore));
self.report_unused_deps(krate);
}

View File

@ -9,6 +9,7 @@
#![feature(proc_macro_internals)]
#![feature(min_specialization)]
#![feature(stmt_expr_attributes)]
#![feature(try_blocks)]
#![feature(never_type)]
#![recursion_limit = "256"]

View File

@ -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,41 +1899,56 @@ macro_rules! sty_debug_print {
}
}
inner::go($ctxt)
inner::go($fmt, $ctxt)
}}
}
impl<'tcx> TyCtxt<'tcx> {
pub fn print_debug_stats(self) {
sty_debug_print!(
self,
Adt,
Array,
Slice,
RawPtr,
Ref,
FnDef,
FnPtr,
Placeholder,
Generator,
GeneratorWitness,
Dynamic,
Closure,
Tuple,
Bound,
Param,
Infer,
Projection,
Opaque,
Foreign
);
pub fn debug_stats(self) -> impl std::fmt::Debug + 'tcx {
struct DebugStats<'tcx>(TyCtxt<'tcx>);
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());
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)
}
}

View File

@ -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)
}

View File

@ -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<M::PointerTag>) {
// 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<M::PointerTag>) -> PlacePrinter<'a, 'mir, 'tcx, M> {
PlacePrinter { ecx: self, place }
}
#[must_use]
pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
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<M::PointerTag>,
}
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<StableHashingContext<'ctx>>
for Frame<'mir, 'tcx, Tag, Extra>
where

View File

@ -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)
}

View File

@ -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<AllocId>) {
// 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<AllocId>,
alloc: &Allocation<Tag, Extra>,
) {
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<AllocId>) -> 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,80 @@ 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<AllocId>,
}
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<AllocId>,
alloc: &Allocation<Tag, Extra>,
) -> std::fmt::Result {
for &(_, target_id) in alloc.relocations().values() {
allocs_to_print.push_back(target_id);
}
write!(fmt, "{}", pretty::display_allocation(tcx, alloc))
}
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.

View File

@ -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,

View File

@ -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(())
}

View File

@ -596,7 +596,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) {
@ -648,24 +648,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<Tag: Copy + Debug, Extra>(
pub fn display_allocation<Tag: Copy + Debug, Extra>(
tcx: TyCtxt<'tcx>,
alloc: &Allocation<Tag, Extra>,
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<Tag, Extra>,
) -> 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<Tag, Extra>,
}
impl<Tag: Copy + Debug, Extra> 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, " ")?;
}
@ -677,12 +689,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<Size> {
) -> Result<Size, std::fmt::Error> {
write_allocation_endline(w, ascii)?;
line_start += Size::from_bytes(BYTES_PER_LINE);
write!(w, "{}0x{:02$x} │ ", prefix, line_start.bytes(), pos_width)?;
@ -695,9 +707,9 @@ fn write_allocation_newline(
fn write_allocation_bytes<Tag: Copy + Debug, Extra>(
tcx: TyCtxt<'tcx>,
alloc: &Allocation<Tag, Extra>,
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();