move some MIR const pretty-printing into pretty.rs
This commit is contained in:
parent
49f5b17cdb
commit
10a822be38
@ -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};
|
||||
|
||||
|
@ -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<Local, LocalDecl<'tcx>>;
|
||||
@ -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.
|
||||
|
@ -1085,6 +1085,159 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option<DefId>) -> Vec<DefId> {
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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<FmtPrinterData<'a, 'tcx>>);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user