Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 02dbb35

Browse files
committed
Deduplicate and clean up pretty printing logic
1 parent 1581278 commit 02dbb35

File tree

12 files changed

+286
-147
lines changed

12 files changed

+286
-147
lines changed

src/librustc/mir/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2562,15 +2562,15 @@ impl<'tcx> Debug for Constant<'tcx> {
25622562

25632563
impl<'tcx> Display for Constant<'tcx> {
25642564
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
2565+
use crate::ty::print::PrettyPrinter;
25652566
write!(fmt, "const ")?;
2566-
// FIXME make the default pretty printing of raw pointers more detailed. Here we output the
2567-
// debug representation of raw pointers, so that the raw pointers in the mir dump output are
2568-
// detailed and just not '{pointer}'.
2569-
if let ty::RawPtr(_) = self.literal.ty.kind {
2570-
write!(fmt, "{:?} : {}", self.literal.val, self.literal.ty)
2571-
} else {
2572-
write!(fmt, "{}", self.literal)
2573-
}
2567+
ty::tls::with(|tcx| {
2568+
let literal = tcx.lift(&self.literal).unwrap();
2569+
let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS);
2570+
cx.print_alloc_ids = true;
2571+
cx.pretty_print_const(literal, true)?;
2572+
Ok(())
2573+
})
25742574
}
25752575
}
25762576

src/librustc/ty/print/pretty.rs

Lines changed: 215 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
22
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
33
use crate::middle::region;
4-
use crate::mir::interpret::{sign_extend, truncate, ConstValue, Scalar};
4+
use crate::mir::interpret::{sign_extend, truncate, AllocId, ConstValue, Pointer, Scalar};
55
use crate::ty::layout::{Integer, IntegerExt, Size};
66
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
77
use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
@@ -457,6 +457,22 @@ pub trait PrettyPrinter<'tcx>:
457457
})
458458
}
459459

460+
fn print_type_ascribed(
461+
mut self,
462+
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
463+
ty: Ty<'tcx>,
464+
print_ty: bool,
465+
) -> Result<Self::Const, Self::Error> {
466+
self.write_str("{")?;
467+
self = f(self)?;
468+
if print_ty {
469+
self.write_str(": ")?;
470+
self = self.print_type(ty)?;
471+
}
472+
self.write_str("}")?;
473+
Ok(self)
474+
}
475+
460476
fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
461477
define_scoped_cx!(self);
462478

@@ -893,32 +909,49 @@ pub trait PrettyPrinter<'tcx>:
893909
Ok(self)
894910
}
895911

896-
fn pretty_print_const_value(
912+
fn pretty_print_const_scalar(
897913
mut self,
898-
ct: ConstValue<'tcx>,
914+
scalar: Scalar,
899915
ty: Ty<'tcx>,
900916
print_ty: bool,
901917
) -> Result<Self::Const, Self::Error> {
902918
define_scoped_cx!(self);
903919

904-
if self.tcx().sess.verbose() {
905-
p!(write("ConstValue({:?}: {:?})", ct, ty));
906-
return Ok(self);
907-
}
908-
909-
let u8 = self.tcx().types.u8;
910-
911-
match (ct, &ty.kind) {
912-
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) => {
913-
p!(write("{}", if data == 0 { "false" } else { "true" }))
914-
}
915-
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) => {
920+
match (scalar, &ty.kind) {
921+
// Single element arrays print their element (they are `#[transparent]`) enclosed in
922+
// square brackets.
923+
(_, ty::Array(t, n)) if n.eval_usize(self.tcx(), ty::ParamEnv::empty()) == 1 => {
924+
p!(write("["));
925+
self = self.pretty_print_const_scalar(scalar, t, print_ty)?;
926+
p!(write("]"));
927+
}
928+
// Byte strings (&[u8; N])
929+
(Scalar::Ptr(ptr), ty::Ref(_, ty::TyS { kind: ty::Array(t, n), .. }, _))
930+
if *t == self.tcx().types.u8 =>
931+
{
932+
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
933+
let byte_str = self
934+
.tcx()
935+
.alloc_map
936+
.lock()
937+
.unwrap_memory(ptr.alloc_id)
938+
.get_bytes(&self.tcx(), ptr, Size::from_bytes(n))
939+
.unwrap();
940+
p!(pretty_print_byte_str(byte_str));
941+
}
942+
// Bool
943+
(Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")),
944+
(Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")),
945+
(Scalar::Raw { data, .. }, ty::Bool) => p!(write("{}_bool", data)),
946+
// Float
947+
(Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F32)) => {
916948
p!(write("{}f32", Single::from_bits(data)))
917949
}
918-
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) => {
950+
(Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F64)) => {
919951
p!(write("{}f64", Double::from_bits(data)))
920952
}
921-
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => {
953+
// Int
954+
(Scalar::Raw { data, .. }, ty::Uint(ui)) => {
922955
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
923956
let max = truncate(u128::MAX, bit_size);
924957

@@ -929,7 +962,7 @@ pub trait PrettyPrinter<'tcx>:
929962
p!(write("{}{}", data, ui_str))
930963
};
931964
}
932-
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => {
965+
(Scalar::Raw { data, .. }, ty::Int(i)) => {
933966
let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size().bits() as u128;
934967
let min = 1u128 << (bit_size - 1);
935968
let max = min - 1;
@@ -943,76 +976,140 @@ pub trait PrettyPrinter<'tcx>:
943976
_ => p!(write("{}{}", sign_extend(data, size) as i128, i_str)),
944977
}
945978
}
946-
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => {
947-
p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap()))
979+
// Char
980+
(Scalar::Raw { data, .. }, ty::Char) => match ::std::char::from_u32(data as u32) {
981+
Some(c) => p!(write("{:?}", c)),
982+
None => p!(write("{}_char", data)),
983+
},
984+
// References and pointers
985+
(Scalar::Raw { data: 0, .. }, ty::RawPtr(_)) => p!(write("{{null pointer}}")),
986+
// This is UB, but we still print it
987+
(Scalar::Raw { data: 0, .. }, ty::Ref(_, ty, _)) => {
988+
p!(write("{{null reference to "), print(ty), write("}}"))
948989
}
949-
(ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")),
950-
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => {
990+
(Scalar::Raw { data, .. }, ty::Ref(..)) | (Scalar::Raw { data, .. }, ty::RawPtr(_)) => {
991+
let pointer_width = self.tcx().data_layout.pointer_size.bytes();
992+
p!(write("0x{:01$x}", data, pointer_width as usize * 2))
993+
}
994+
(Scalar::Ptr(ptr), ty::FnPtr(_)) => {
951995
let instance = {
952996
let alloc_map = self.tcx().alloc_map.lock();
953997
alloc_map.unwrap_fn(ptr.alloc_id)
954998
};
955999
p!(print_value_path(instance.def_id(), instance.substs));
9561000
}
957-
_ => {
958-
let printed = if let ty::Ref(_, ref_ty, _) = ty.kind {
959-
let byte_str = match (ct, &ref_ty.kind) {
960-
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
961-
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
962-
Some(
963-
self.tcx()
964-
.alloc_map
965-
.lock()
966-
.unwrap_memory(ptr.alloc_id)
967-
.get_bytes(&self.tcx(), ptr, Size::from_bytes(n))
968-
.unwrap(),
969-
)
970-
}
971-
(ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
972-
// The `inspect` here is okay since we checked the bounds, and there are
973-
// no relocations (we have an active slice reference here). We don't use
974-
// this result to affect interpreter execution.
975-
Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
976-
}
977-
_ => None,
978-
};
1001+
// For zsts just print their type as their value gives no extra information
1002+
(Scalar::Raw { size: 0, .. }, _) => p!(print(ty)),
1003+
// Nontrivial types with scalar bit representation
1004+
(Scalar::Raw { data, size }, _) => {
1005+
self = self.print_type_ascribed(
1006+
|mut this| {
1007+
write!(this, "0x{:01$x}", data, size as usize * 2)?;
1008+
Ok(this)
1009+
},
1010+
ty,
1011+
print_ty,
1012+
)?
1013+
}
1014+
// Any pointer values not covered by a branch above
1015+
(Scalar::Ptr(p), _) => {
1016+
self = self.pretty_print_const_pointer(p, ty, print_ty)?;
1017+
}
1018+
}
1019+
Ok(self)
1020+
}
9791021

980-
if let Some(byte_str) = byte_str {
981-
p!(write("b\""));
982-
for &c in byte_str {
983-
for e in std::ascii::escape_default(c) {
984-
self.write_char(e as char)?;
985-
}
986-
}
987-
p!(write("\""));
988-
true
989-
} else if let (ConstValue::Slice { data, start, end }, ty::Str) =
990-
(ct, &ref_ty.kind)
991-
{
992-
// The `inspect` here is okay since we checked the bounds, and there are no
993-
// relocations (we have an active `str` reference here). We don't use this
994-
// result to affect interpreter execution.
995-
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
996-
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
997-
p!(write("{:?}", s));
998-
true
999-
} else {
1000-
false
1001-
}
1002-
} else {
1003-
false
1004-
};
1005-
if !printed {
1006-
// fallback
1007-
p!(write("{:?}", ct));
1008-
if print_ty {
1009-
p!(write(": "), print(ty));
1010-
}
1011-
}
1022+
/// This is overridden for MIR printing because we only want to hide alloc ids from users, not
1023+
/// from MIR where it is actually useful.
1024+
fn pretty_print_const_pointer(
1025+
self,
1026+
_: Pointer,
1027+
ty: Ty<'tcx>,
1028+
print_ty: bool,
1029+
) -> Result<Self::Const, Self::Error> {
1030+
self.print_type_ascribed(
1031+
|mut this| {
1032+
this.write_str("pointer")?;
1033+
Ok(this)
1034+
},
1035+
ty,
1036+
print_ty,
1037+
)
1038+
}
1039+
1040+
fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
1041+
define_scoped_cx!(self);
1042+
p!(write("b\""));
1043+
for &c in byte_str {
1044+
for e in std::ascii::escape_default(c) {
1045+
self.write_char(e as char)?;
10121046
}
1013-
};
1047+
}
1048+
p!(write("\""));
10141049
Ok(self)
10151050
}
1051+
1052+
fn pretty_print_const_value(
1053+
mut self,
1054+
ct: ConstValue<'tcx>,
1055+
ty: Ty<'tcx>,
1056+
print_ty: bool,
1057+
) -> Result<Self::Const, Self::Error> {
1058+
define_scoped_cx!(self);
1059+
1060+
if self.tcx().sess.verbose() {
1061+
p!(write("ConstValue({:?}: {:?})", ct, ty));
1062+
return Ok(self);
1063+
}
1064+
1065+
let u8_type = self.tcx().types.u8;
1066+
1067+
match (ct, &ty.kind) {
1068+
(ConstValue::Scalar(scalar), _) => self.pretty_print_const_scalar(scalar, ty, print_ty),
1069+
(
1070+
ConstValue::Slice { data, start, end },
1071+
ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _),
1072+
) if *t == u8_type => {
1073+
// The `inspect` here is okay since we checked the bounds, and there are
1074+
// no relocations (we have an active slice reference here). We don't use
1075+
// this result to affect interpreter execution.
1076+
let byte_str = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
1077+
self.pretty_print_byte_str(byte_str)
1078+
}
1079+
(
1080+
ConstValue::Slice { data, start, end },
1081+
ty::Ref(_, ty::TyS { kind: ty::Str, .. }, _),
1082+
) => {
1083+
// The `inspect` here is okay since we checked the bounds, and there are no
1084+
// relocations (we have an active `str` reference here). We don't use this
1085+
// result to affect interpreter execution.
1086+
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
1087+
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
1088+
p!(write("{:?}", s));
1089+
Ok(self)
1090+
}
1091+
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
1092+
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
1093+
let n = Size::from_bytes(n);
1094+
let ptr = Pointer::new(AllocId(0), offset);
1095+
1096+
let byte_str = alloc.get_bytes(&self.tcx(), ptr, n).unwrap();
1097+
p!(write("*"));
1098+
p!(pretty_print_byte_str(byte_str));
1099+
Ok(self)
1100+
}
1101+
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
1102+
// their fields instead of just dumping the memory.
1103+
_ => {
1104+
// fallback
1105+
p!(write("{:?}", ct));
1106+
if print_ty {
1107+
p!(write(": "), print(ty));
1108+
}
1109+
Ok(self)
1110+
}
1111+
}
1112+
}
10161113
}
10171114

10181115
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
@@ -1024,6 +1121,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> {
10241121

10251122
empty_path: bool,
10261123
in_value: bool,
1124+
pub print_alloc_ids: bool,
10271125

10281126
used_region_names: FxHashSet<Symbol>,
10291127
region_index: usize,
@@ -1054,6 +1152,7 @@ impl<F> FmtPrinter<'a, 'tcx, F> {
10541152
fmt,
10551153
empty_path: false,
10561154
in_value: ns == Namespace::ValueNS,
1155+
print_alloc_ids: false,
10571156
used_region_names: Default::default(),
10581157
region_index: 0,
10591158
binder_depth: 0,
@@ -1382,6 +1481,45 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
13821481
ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true,
13831482
}
13841483
}
1484+
1485+
fn pretty_print_const_pointer(
1486+
self,
1487+
p: Pointer,
1488+
ty: Ty<'tcx>,
1489+
print_ty: bool,
1490+
) -> Result<Self::Const, Self::Error> {
1491+
self.print_type_ascribed(
1492+
|mut this| {
1493+
define_scoped_cx!(this);
1494+
if this.print_alloc_ids {
1495+
p!(write("{:?}", p));
1496+
} else {
1497+
p!(write("pointer"));
1498+
}
1499+
Ok(this)
1500+
},
1501+
ty,
1502+
print_ty,
1503+
)
1504+
}
1505+
1506+
fn print_type_ascribed(
1507+
mut self,
1508+
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
1509+
ty: Ty<'tcx>,
1510+
print_ty: bool,
1511+
) -> Result<Self::Const, Self::Error> {
1512+
self.write_str("{")?;
1513+
self = f(self)?;
1514+
if print_ty {
1515+
self.write_str(": ")?;
1516+
let was_in_value = std::mem::replace(&mut self.in_value, false);
1517+
self = self.print_type(ty)?;
1518+
self.in_value = was_in_value;
1519+
}
1520+
self.write_str("}")?;
1521+
Ok(self)
1522+
}
13851523
}
13861524

13871525
// HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.

0 commit comments

Comments
 (0)