Skip to content

Commit bd8aabe

Browse files
committed
Auto merge of #113291 - oli-obk:pretty_print_mir_const, r=RalfJung
Specialize `try_destructure_mir_constant` for its sole user (pretty printing) We can't remove the query, as we need to invoke it from rustc_middle, but can only implement it in mir interpretation/const eval. r? `@RalfJung` for a first round. While we could move all the logic into pretty printing, that would end up duplicating a bit of code with const eval, which doesn't seem great either.
2 parents d9c13cd + 3dfc7ec commit bd8aabe

File tree

9 files changed

+72
-86
lines changed

9 files changed

+72
-86
lines changed

compiler/rustc_const_eval/src/const_eval/mod.rs

+16-17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
// Not in interpret to make sure we do not use private implementation details
22

33
use crate::errors::MaxNumNodesInConstErr;
4-
use crate::interpret::{
5-
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, Scalar,
6-
};
4+
use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, Scalar};
75
use rustc_middle::mir;
86
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
9-
use rustc_middle::ty::{self, TyCtxt};
7+
use rustc_middle::ty::{self, Ty, TyCtxt};
108
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
119

1210
mod error;
@@ -87,23 +85,24 @@ pub(crate) fn eval_to_valtree<'tcx>(
8785
}
8886

8987
#[instrument(skip(tcx), level = "debug")]
90-
pub(crate) fn try_destructure_mir_constant<'tcx>(
88+
pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>(
9189
tcx: TyCtxt<'tcx>,
92-
param_env: ty::ParamEnv<'tcx>,
93-
val: mir::ConstantKind<'tcx>,
94-
) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
90+
val: ConstValue<'tcx>,
91+
ty: Ty<'tcx>,
92+
) -> Option<mir::DestructuredConstant<'tcx>> {
93+
let param_env = ty::ParamEnv::reveal_all();
9594
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
96-
let op = ecx.eval_mir_constant(&val, None, None)?;
95+
let op = ecx.const_val_to_op(val, ty, None).ok()?;
9796

9897
// We go to `usize` as we cannot allocate anything bigger anyway.
99-
let (field_count, variant, down) = match val.ty().kind() {
98+
let (field_count, variant, down) = match ty.kind() {
10099
ty::Array(_, len) => (len.eval_target_usize(tcx, param_env) as usize, None, op),
101100
ty::Adt(def, _) if def.variants().is_empty() => {
102-
throw_ub!(Unreachable)
101+
return None;
103102
}
104103
ty::Adt(def, _) => {
105-
let variant = ecx.read_discriminant(&op)?.1;
106-
let down = ecx.operand_downcast(&op, variant)?;
104+
let variant = ecx.read_discriminant(&op).ok()?.1;
105+
let down = ecx.operand_downcast(&op, variant).ok()?;
107106
(def.variants()[variant].fields.len(), Some(variant), down)
108107
}
109108
ty::Tuple(substs) => (substs.len(), None, op),
@@ -112,12 +111,12 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
112111

113112
let fields_iter = (0..field_count)
114113
.map(|i| {
115-
let field_op = ecx.operand_field(&down, i)?;
114+
let field_op = ecx.operand_field(&down, i).ok()?;
116115
let val = op_to_const(&ecx, &field_op);
117-
Ok(mir::ConstantKind::Val(val, field_op.layout.ty))
116+
Some((val, field_op.layout.ty))
118117
})
119-
.collect::<InterpResult<'tcx, Vec<_>>>()?;
118+
.collect::<Option<Vec<_>>>()?;
120119
let fields = tcx.arena.alloc_from_iter(fields_iter);
121120

122-
Ok(mir::DestructuredConstant { variant, fields })
121+
Some(mir::DestructuredConstant { variant, fields })
123122
}

compiler/rustc_const_eval/src/interpret/operand.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
106106
// Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to
107107
// print what is points to, which would fail since it has no access to the local
108108
// memory.
109-
cx.pretty_print_const_pointer(ptr, ty, true)
109+
cx.pretty_print_const_pointer(ptr, ty)
110110
}
111111
}
112112
}
@@ -633,7 +633,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
633633
}
634634
}
635635

636-
pub(super) fn const_val_to_op(
636+
pub(crate) fn const_val_to_op(
637637
&self,
638638
val_val: ConstValue<'tcx>,
639639
ty: Ty<'tcx>,

compiler/rustc_const_eval/src/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,8 @@ pub fn provide(providers: &mut Providers) {
5252
let (param_env, raw) = param_env_and_value.into_parts();
5353
const_eval::eval_to_valtree(tcx, param_env, raw)
5454
};
55-
providers.try_destructure_mir_constant = |tcx, param_env_and_value| {
56-
let (param_env, value) = param_env_and_value.into_parts();
57-
const_eval::try_destructure_mir_constant(tcx, param_env, value).ok()
58-
};
55+
providers.try_destructure_mir_constant_for_diagnostics =
56+
|tcx, (cv, ty)| const_eval::try_destructure_mir_constant_for_diagnostics(tcx, cv, ty);
5957
providers.valtree_to_const_val = |tcx, (ty, valtree)| {
6058
const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree)
6159
};

compiler/rustc_middle/src/mir/mod.rs

+17-29
Original file line numberDiff line numberDiff line change
@@ -2776,7 +2776,7 @@ impl<'tcx> Display for ConstantKind<'tcx> {
27762776
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
27772777
match *self {
27782778
ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
2779-
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true),
2779+
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
27802780
// FIXME(valtrees): Correctly print mir constants.
27812781
ConstantKind::Unevaluated(..) => {
27822782
fmt.write_str("_")?;
@@ -2806,13 +2806,16 @@ fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Resul
28062806
write!(fmt, "b\"{}\"", byte_str.escape_ascii())
28072807
}
28082808

2809-
fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result {
2809+
fn comma_sep<'tcx>(
2810+
fmt: &mut Formatter<'_>,
2811+
elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>,
2812+
) -> fmt::Result {
28102813
let mut first = true;
2811-
for elem in elems {
2814+
for (ct, ty) in elems {
28122815
if !first {
28132816
fmt.write_str(", ")?;
28142817
}
2815-
fmt.write_str(&format!("{}", elem))?;
2818+
pretty_print_const_value(ct, ty, fmt)?;
28162819
first = false;
28172820
}
28182821
Ok(())
@@ -2823,7 +2826,6 @@ fn pretty_print_const_value<'tcx>(
28232826
ct: ConstValue<'tcx>,
28242827
ty: Ty<'tcx>,
28252828
fmt: &mut Formatter<'_>,
2826-
print_ty: bool,
28272829
) -> fmt::Result {
28282830
use crate::ty::print::PrettyPrinter;
28292831

@@ -2882,16 +2884,11 @@ fn pretty_print_const_value<'tcx>(
28822884
// introducing ICEs (e.g. via `layout_of`) from missing bounds.
28832885
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
28842886
// to be able to destructure the tuple into `(0u8, *mut T)`
2885-
//
2886-
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
2887-
// correct `ty::ParamEnv` to allow printing *all* constant values.
28882887
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => {
28892888
let ct = tcx.lift(ct).unwrap();
28902889
let ty = tcx.lift(ty).unwrap();
2891-
if let Some(contents) = tcx.try_destructure_mir_constant(
2892-
ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)),
2893-
) {
2894-
let fields = contents.fields.to_vec();
2890+
if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics((ct, ty)) {
2891+
let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec();
28952892
match *ty.kind() {
28962893
ty::Array(..) => {
28972894
fmt.write_str("[")?;
@@ -2930,12 +2927,14 @@ fn pretty_print_const_value<'tcx>(
29302927
None => {
29312928
fmt.write_str(" {{ ")?;
29322929
let mut first = true;
2933-
for (field_def, field) in iter::zip(&variant_def.fields, fields)
2930+
for (field_def, (ct, ty)) in
2931+
iter::zip(&variant_def.fields, fields)
29342932
{
29352933
if !first {
29362934
fmt.write_str(", ")?;
29372935
}
2938-
fmt.write_str(&format!("{}: {}", field_def.name, field))?;
2936+
write!(fmt, "{}: ", field_def.name)?;
2937+
pretty_print_const_value(ct, ty, fmt)?;
29392938
first = false;
29402939
}
29412940
fmt.write_str(" }}")?;
@@ -2945,20 +2944,13 @@ fn pretty_print_const_value<'tcx>(
29452944
_ => unreachable!(),
29462945
}
29472946
return Ok(());
2948-
} else {
2949-
// Fall back to debug pretty printing for invalid constants.
2950-
fmt.write_str(&format!("{:?}", ct))?;
2951-
if print_ty {
2952-
fmt.write_str(&format!(": {}", ty))?;
2953-
}
2954-
return Ok(());
2955-
};
2947+
}
29562948
}
29572949
(ConstValue::Scalar(scalar), _) => {
29582950
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
29592951
cx.print_alloc_ids = true;
29602952
let ty = tcx.lift(ty).unwrap();
2961-
cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?;
2953+
cx = cx.pretty_print_const_scalar(scalar, ty)?;
29622954
fmt.write_str(&cx.into_buffer())?;
29632955
return Ok(());
29642956
}
@@ -2973,12 +2965,8 @@ fn pretty_print_const_value<'tcx>(
29732965
// their fields instead of just dumping the memory.
29742966
_ => {}
29752967
}
2976-
// fallback
2977-
fmt.write_str(&format!("{:?}", ct))?;
2978-
if print_ty {
2979-
fmt.write_str(&format!(": {}", ty))?;
2980-
}
2981-
Ok(())
2968+
// Fall back to debug pretty printing for invalid constants.
2969+
write!(fmt, "{ct:?}: {ty}")
29822970
})
29832971
}
29842972

compiler/rustc_middle/src/mir/query.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Values computed by queries that use MIR.
22
3-
use crate::mir::ConstantKind;
3+
use crate::mir::interpret::ConstValue;
44
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
55
use rustc_data_structures::fx::FxIndexMap;
66
use rustc_data_structures::unord::UnordSet;
@@ -444,7 +444,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
444444
#[derive(Copy, Clone, Debug, HashStable)]
445445
pub struct DestructuredConstant<'tcx> {
446446
pub variant: Option<VariantIdx>,
447-
pub fields: &'tcx [ConstantKind<'tcx>],
447+
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
448448
}
449449

450450
/// Coverage information summarized from a MIR if instrumented for source code coverage (see

compiler/rustc_middle/src/query/keys.rs

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::infer::canonical::Canonical;
44
use crate::mir;
5+
use crate::mir::interpret::ConstValue;
56
use crate::traits;
67
use crate::ty::fast_reject::SimplifiedType;
78
use crate::ty::layout::{TyAndLayout, ValidityRequirement};
@@ -333,6 +334,14 @@ impl<'tcx> Key for (ty::Const<'tcx>, FieldIdx) {
333334
}
334335
}
335336

337+
impl<'tcx> Key for (ConstValue<'tcx>, Ty<'tcx>) {
338+
type CacheSelector = DefaultCacheSelector<Self>;
339+
340+
fn default_span(&self, _: TyCtxt<'_>) -> Span {
341+
DUMMY_SP
342+
}
343+
}
344+
336345
impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
337346
type CacheSelector = DefaultCacheSelector<Self>;
338347

compiler/rustc_middle/src/query/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1087,11 +1087,13 @@ rustc_queries! {
10871087
}
10881088

10891089
/// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
1090-
/// and its field values.
1091-
query try_destructure_mir_constant(
1092-
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
1090+
/// and its field values. This should only be used for pretty printing.
1091+
query try_destructure_mir_constant_for_diagnostics(
1092+
key: (ConstValue<'tcx>, Ty<'tcx>)
10931093
) -> Option<mir::DestructuredConstant<'tcx>> {
10941094
desc { "destructuring MIR constant"}
1095+
no_hash
1096+
eval_always
10951097
}
10961098

10971099
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {

compiler/rustc_middle/src/ty/print/pretty.rs

+15-26
Original file line numberDiff line numberDiff line change
@@ -1393,19 +1393,19 @@ pub trait PrettyPrinter<'tcx>:
13931393
self,
13941394
scalar: Scalar,
13951395
ty: Ty<'tcx>,
1396-
print_ty: bool,
13971396
) -> Result<Self::Const, Self::Error> {
13981397
match scalar {
1399-
Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty),
1400-
Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty),
1398+
Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty),
1399+
Scalar::Int(int) => {
1400+
self.pretty_print_const_scalar_int(int, ty, /* print_ty */ true)
1401+
}
14011402
}
14021403
}
14031404

14041405
fn pretty_print_const_scalar_ptr(
14051406
mut self,
14061407
ptr: Pointer,
14071408
ty: Ty<'tcx>,
1408-
print_ty: bool,
14091409
) -> Result<Self::Const, Self::Error> {
14101410
define_scoped_cx!(self);
14111411

@@ -1459,7 +1459,7 @@ pub trait PrettyPrinter<'tcx>:
14591459
_ => {}
14601460
}
14611461
// Any pointer values not covered by a branch above
1462-
self = self.pretty_print_const_pointer(ptr, ty, print_ty)?;
1462+
self = self.pretty_print_const_pointer(ptr, ty)?;
14631463
Ok(self)
14641464
}
14651465

@@ -1527,24 +1527,18 @@ pub trait PrettyPrinter<'tcx>:
15271527
/// This is overridden for MIR printing because we only want to hide alloc ids from users, not
15281528
/// from MIR where it is actually useful.
15291529
fn pretty_print_const_pointer<Prov: Provenance>(
1530-
mut self,
1530+
self,
15311531
_: Pointer<Prov>,
15321532
ty: Ty<'tcx>,
1533-
print_ty: bool,
15341533
) -> Result<Self::Const, Self::Error> {
1535-
if print_ty {
1536-
self.typed_value(
1537-
|mut this| {
1538-
this.write_str("&_")?;
1539-
Ok(this)
1540-
},
1541-
|this| this.print_type(ty),
1542-
": ",
1543-
)
1544-
} else {
1545-
self.write_str("&_")?;
1546-
Ok(self)
1547-
}
1534+
self.typed_value(
1535+
|mut this| {
1536+
this.write_str("&_")?;
1537+
Ok(this)
1538+
},
1539+
|this| this.print_type(ty),
1540+
": ",
1541+
)
15481542
}
15491543

15501544
fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
@@ -2156,7 +2150,6 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
21562150
self,
21572151
p: Pointer<Prov>,
21582152
ty: Ty<'tcx>,
2159-
print_ty: bool,
21602153
) -> Result<Self::Const, Self::Error> {
21612154
let print = |mut this: Self| {
21622155
define_scoped_cx!(this);
@@ -2167,11 +2160,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
21672160
}
21682161
Ok(this)
21692162
};
2170-
if print_ty {
2171-
self.typed_value(print, |this| this.print_type(ty), ": ")
2172-
} else {
2173-
print(self)
2174-
}
2163+
self.typed_value(print, |this| this.print_type(ty), ": ")
21752164
}
21762165
}
21772166

src/tools/clippy/clippy_utils/src/consts.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -725,13 +725,14 @@ fn field_of_struct<'tcx>(
725725
result: mir::ConstantKind<'tcx>,
726726
field: &Ident,
727727
) -> Option<mir::ConstantKind<'tcx>> {
728-
if let Some(dc) = lcx.tcx.try_destructure_mir_constant(lcx.param_env.and(result))
728+
if let mir::ConstantKind::Val(result, ty) = result
729+
&& let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty))
729730
&& let Some(dc_variant) = dc.variant
730731
&& let Some(variant) = adt_def.variants().get(dc_variant)
731732
&& let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
732-
&& let Some(dc_field) = dc.fields.get(field_idx)
733+
&& let Some(&(val, ty)) = dc.fields.get(field_idx)
733734
{
734-
Some(*dc_field)
735+
Some(mir::ConstantKind::Val(val, ty))
735736
}
736737
else {
737738
None

0 commit comments

Comments
 (0)