From 10a822be385be021ee717adad58b6290f149d829 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Sep 2023 23:33:42 +0200 Subject: [PATCH] move some MIR const pretty-printing into pretty.rs --- compiler/rustc_middle/src/mir/consts.rs | 4 +- compiler/rustc_middle/src/mir/mod.rs | 181 +------------------ compiler/rustc_middle/src/mir/pretty.rs | 153 ++++++++++++++++ compiler/rustc_middle/src/ty/print/pretty.rs | 15 ++ 4 files changed, 176 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 92c6828a0b4..c80419d4c09 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -7,8 +7,8 @@ use rustc_span::Span; use rustc_target::abi::Size; use crate::mir::interpret::{ConstValue, ErrorHandled, GlobalAlloc, Scalar}; -use crate::mir::{interpret, pretty_print_const, pretty_print_const_value, Promoted}; -use crate::ty::{self, List, Ty, TyCtxt}; +use crate::mir::{interpret, pretty_print_const_value, Promoted}; +use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt}; use crate::ty::{GenericArgs, GenericArgsRef}; use crate::ty::{ScalarInt, UserTypeAnnotationIndex}; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3a79e1d31b4..fb6dbe34a89 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -6,7 +6,7 @@ use crate::mir::interpret::{AllocRange, ErrorHandled, ConstAllocation, ConstValu use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::ty::print::with_no_trimmed_paths; +use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, List, Ty, TyCtxt}; @@ -20,7 +20,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::{self, GeneratorKind, ImplicitSelfKind}; use rustc_hir::{self as hir, HirId}; use rustc_session::Session; -use rustc_target::abi::{FieldIdx, Size, VariantIdx}; +use rustc_target::abi::{FieldIdx, VariantIdx}; use polonius_engine::Atom; pub use rustc_ast::Mutability; @@ -46,7 +46,6 @@ pub use basic_blocks::BasicBlocks; mod basic_blocks; mod consts; -pub use consts::*; pub mod coverage; mod generic_graph; pub mod generic_graphviz; @@ -58,10 +57,8 @@ pub mod pretty; mod query; pub mod spanview; mod syntax; -pub use syntax::*; pub mod tcx; mod terminator; -pub use terminator::*; pub mod traversal; mod type_foldable; @@ -72,6 +69,10 @@ pub use self::graphviz::write_mir_graphviz; pub use self::pretty::{ create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere, }; +pub use consts::*; +pub use pretty::pretty_print_const_value; +pub use syntax::*; +pub use terminator::*; /// Types for locals pub type LocalDecls<'tcx> = IndexSlice>; @@ -2459,176 +2460,6 @@ rustc_index::newtype_index! { pub struct Promoted {} } -fn pretty_print_const<'tcx>( - c: ty::Const<'tcx>, - fmt: &mut Formatter<'_>, - print_types: bool, -) -> fmt::Result { - use crate::ty::print::PrettyPrinter; - ty::tls::with(|tcx| { - let literal = tcx.lift(c).unwrap(); - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - let cx = cx.pretty_print_const(literal, print_types)?; - fmt.write_str(&cx.into_buffer())?; - Ok(()) - }) -} - -fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result { - write!(fmt, "b\"{}\"", byte_str.escape_ascii()) -} - -fn comma_sep<'tcx>( - fmt: &mut Formatter<'_>, - elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>, -) -> fmt::Result { - let mut first = true; - for (ct, ty) in elems { - if !first { - fmt.write_str(", ")?; - } - pretty_print_const_value(ct, ty, fmt)?; - first = false; - } - Ok(()) -} - -// FIXME: Move that into `mir/pretty.rs`. -fn pretty_print_const_value<'tcx>( - ct: ConstValue<'tcx>, - ty: Ty<'tcx>, - fmt: &mut Formatter<'_>, -) -> fmt::Result { - use crate::ty::print::PrettyPrinter; - - ty::tls::with(|tcx| { - let ct = tcx.lift(ct).unwrap(); - let ty = tcx.lift(ty).unwrap(); - - if tcx.sess.verbose() { - fmt.write_str(&format!("ConstValue({ct:?}: {ty})"))?; - return Ok(()); - } - - let u8_type = tcx.types.u8; - match (ct, ty.kind()) { - // Byte/string slices, printed as (byte) string literals. - (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { - if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) { - fmt.write_str(&format!("{:?}", String::from_utf8_lossy(data)))?; - return Ok(()); - } - } - (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(t) if *t == u8_type) => { - if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) { - pretty_print_byte_str(fmt, data)?; - return Ok(()); - } - } - (ConstValue::Indirect { alloc_id, offset }, ty::Array(t, n)) if *t == u8_type => { - let n = n.try_to_target_usize(tcx).unwrap(); - let alloc = tcx.global_alloc(alloc_id).unwrap_memory(); - // cast is ok because we already checked for pointer size (32 or 64 bit) above - let range = AllocRange { start: offset, size: Size::from_bytes(n) }; - let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap(); - fmt.write_str("*")?; - pretty_print_byte_str(fmt, byte_str)?; - return Ok(()); - } - // Aggregates, printed as array/tuple/struct/variant construction syntax. - // - // NB: the `has_non_region_param` check ensures that we can use - // the `destructure_const` query with an empty `ty::ParamEnv` without - // introducing ICEs (e.g. via `layout_of`) from missing bounds. - // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` - // to be able to destructure the tuple into `(0u8, *mut T)` - (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => { - let ct = tcx.lift(ct).unwrap(); - let ty = tcx.lift(ty).unwrap(); - if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics((ct, ty)) { - let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec(); - match *ty.kind() { - ty::Array(..) => { - fmt.write_str("[")?; - comma_sep(fmt, fields)?; - fmt.write_str("]")?; - } - ty::Tuple(..) => { - fmt.write_str("(")?; - comma_sep(fmt, fields)?; - if contents.fields.len() == 1 { - fmt.write_str(",")?; - } - fmt.write_str(")")?; - } - ty::Adt(def, _) if def.variants().is_empty() => { - fmt.write_str(&format!("{{unreachable(): {ty}}}"))?; - } - ty::Adt(def, args) => { - let variant_idx = contents - .variant - .expect("destructed mir constant of adt without variant idx"); - let variant_def = &def.variant(variant_idx); - let args = tcx.lift(args).unwrap(); - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - let cx = cx.print_value_path(variant_def.def_id, args)?; - fmt.write_str(&cx.into_buffer())?; - - match variant_def.ctor_kind() { - Some(CtorKind::Const) => {} - Some(CtorKind::Fn) => { - fmt.write_str("(")?; - comma_sep(fmt, fields)?; - fmt.write_str(")")?; - } - None => { - fmt.write_str(" {{ ")?; - let mut first = true; - for (field_def, (ct, ty)) in - iter::zip(&variant_def.fields, fields) - { - if !first { - fmt.write_str(", ")?; - } - write!(fmt, "{}: ", field_def.name)?; - pretty_print_const_value(ct, ty, fmt)?; - first = false; - } - fmt.write_str(" }}")?; - } - } - } - _ => unreachable!(), - } - return Ok(()); - } - } - (ConstValue::Scalar(scalar), _) => { - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - let ty = tcx.lift(ty).unwrap(); - cx = cx.pretty_print_const_scalar(scalar, ty)?; - fmt.write_str(&cx.into_buffer())?; - return Ok(()); - } - (ConstValue::ZeroSized, ty::FnDef(d, s)) => { - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - let cx = cx.print_value_path(*d, s)?; - fmt.write_str(&cx.into_buffer())?; - return Ok(()); - } - // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading - // their fields instead of just dumping the memory. - _ => {} - } - // Fall back to debug pretty printing for invalid constants. - write!(fmt, "{ct:?}: {ty}") - }) -} - /// `Location` represents the position of the start of the statement; or, if /// `statement_index` equals the number of statements, then the start of the /// terminator. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index c4fae27a7a5..56b59fe5204 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1085,6 +1085,159 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { } } +fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result { + write!(fmt, "b\"{}\"", byte_str.escape_ascii()) +} + +fn comma_sep<'tcx>( + fmt: &mut Formatter<'_>, + elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>, +) -> fmt::Result { + let mut first = true; + for (ct, ty) in elems { + if !first { + fmt.write_str(", ")?; + } + pretty_print_const_value(ct, ty, fmt)?; + first = false; + } + Ok(()) +} + +pub fn pretty_print_const_value<'tcx>( + ct: ConstValue<'tcx>, + ty: Ty<'tcx>, + fmt: &mut Formatter<'_>, +) -> fmt::Result { + use crate::ty::print::PrettyPrinter; + + ty::tls::with(|tcx| { + let ct = tcx.lift(ct).unwrap(); + let ty = tcx.lift(ty).unwrap(); + + if tcx.sess.verbose() { + fmt.write_str(&format!("ConstValue({ct:?}: {ty})"))?; + return Ok(()); + } + + let u8_type = tcx.types.u8; + match (ct, ty.kind()) { + // Byte/string slices, printed as (byte) string literals. + (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { + if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) { + fmt.write_str(&format!("{:?}", String::from_utf8_lossy(data)))?; + return Ok(()); + } + } + (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(t) if *t == u8_type) => { + if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) { + pretty_print_byte_str(fmt, data)?; + return Ok(()); + } + } + (ConstValue::Indirect { alloc_id, offset }, ty::Array(t, n)) if *t == u8_type => { + let n = n.try_to_target_usize(tcx).unwrap(); + let alloc = tcx.global_alloc(alloc_id).unwrap_memory(); + // cast is ok because we already checked for pointer size (32 or 64 bit) above + let range = AllocRange { start: offset, size: Size::from_bytes(n) }; + let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap(); + fmt.write_str("*")?; + pretty_print_byte_str(fmt, byte_str)?; + return Ok(()); + } + // Aggregates, printed as array/tuple/struct/variant construction syntax. + // + // NB: the `has_non_region_param` check ensures that we can use + // the `destructure_const` query with an empty `ty::ParamEnv` without + // introducing ICEs (e.g. via `layout_of`) from missing bounds. + // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` + // to be able to destructure the tuple into `(0u8, *mut T)` + (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => { + let ct = tcx.lift(ct).unwrap(); + let ty = tcx.lift(ty).unwrap(); + if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics((ct, ty)) { + let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec(); + match *ty.kind() { + ty::Array(..) => { + fmt.write_str("[")?; + comma_sep(fmt, fields)?; + fmt.write_str("]")?; + } + ty::Tuple(..) => { + fmt.write_str("(")?; + comma_sep(fmt, fields)?; + if contents.fields.len() == 1 { + fmt.write_str(",")?; + } + fmt.write_str(")")?; + } + ty::Adt(def, _) if def.variants().is_empty() => { + fmt.write_str(&format!("{{unreachable(): {ty}}}"))?; + } + ty::Adt(def, args) => { + let variant_idx = contents + .variant + .expect("destructed mir constant of adt without variant idx"); + let variant_def = &def.variant(variant_idx); + let args = tcx.lift(args).unwrap(); + let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); + cx.print_alloc_ids = true; + let cx = cx.print_value_path(variant_def.def_id, args)?; + fmt.write_str(&cx.into_buffer())?; + + match variant_def.ctor_kind() { + Some(CtorKind::Const) => {} + Some(CtorKind::Fn) => { + fmt.write_str("(")?; + comma_sep(fmt, fields)?; + fmt.write_str(")")?; + } + None => { + fmt.write_str(" {{ ")?; + let mut first = true; + for (field_def, (ct, ty)) in + iter::zip(&variant_def.fields, fields) + { + if !first { + fmt.write_str(", ")?; + } + write!(fmt, "{}: ", field_def.name)?; + pretty_print_const_value(ct, ty, fmt)?; + first = false; + } + fmt.write_str(" }}")?; + } + } + } + _ => unreachable!(), + } + return Ok(()); + } + } + (ConstValue::Scalar(scalar), _) => { + let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); + cx.print_alloc_ids = true; + let ty = tcx.lift(ty).unwrap(); + cx = cx.pretty_print_const_scalar(scalar, ty)?; + fmt.write_str(&cx.into_buffer())?; + return Ok(()); + } + (ConstValue::ZeroSized, ty::FnDef(d, s)) => { + let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); + cx.print_alloc_ids = true; + let cx = cx.print_value_path(*d, s)?; + fmt.write_str(&cx.into_buffer())?; + return Ok(()); + } + // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading + // their fields instead of just dumping the memory. + _ => {} + } + // Fall back to debug pretty printing for invalid constants. + write!(fmt, "{ct:?}: {ty}") + }) +} + /// Calc converted u64 decimal into hex and return it's length in chars /// /// ```ignore (cannot-test-private-function) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index e1d4e43841d..d958e25e629 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1713,6 +1713,21 @@ pub trait PrettyPrinter<'tcx>: } } +pub fn pretty_print_const<'tcx>( + c: ty::Const<'tcx>, + fmt: &mut fmt::Formatter<'_>, + print_types: bool, +) -> fmt::Result { + ty::tls::with(|tcx| { + let literal = tcx.lift(c).unwrap(); + let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); + cx.print_alloc_ids = true; + let cx = cx.pretty_print_const(literal, print_types)?; + fmt.write_str(&cx.into_buffer())?; + Ok(()) + }) +} + // HACK(eddyb) boxed to avoid moving around a large struct by-value. pub struct FmtPrinter<'a, 'tcx>(Box>);