Skip to content

Commit e437e57

Browse files
committed
Auto merge of #115804 - RalfJung:valtree-to-const-val, r=oli-obk
consistently pass ty::Const through valtrees Some drive-by things extracted from #115748.
2 parents 5e71913 + 19fb2c7 commit e437e57

File tree

4 files changed

+78
-106
lines changed

4 files changed

+78
-106
lines changed

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+52-51
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::interpret::{
77
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
88
MemoryKind, PlaceTy, Projectable, Scalar,
99
};
10-
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
10+
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
1111
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
1212
use rustc_span::source_map::DUMMY_SP;
1313
use rustc_target::abi::VariantIdx;
@@ -189,12 +189,11 @@ fn reconstruct_place_meta<'tcx>(
189189
}
190190

191191
#[instrument(skip(ecx), level = "debug", ret)]
192-
fn create_pointee_place<'tcx>(
192+
fn create_valtree_place<'tcx>(
193193
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
194-
ty: Ty<'tcx>,
194+
layout: TyAndLayout<'tcx>,
195195
valtree: ty::ValTree<'tcx>,
196196
) -> MPlaceTy<'tcx> {
197-
let layout = ecx.layout_of(ty).unwrap();
198197
let meta = reconstruct_place_meta(layout, valtree, ecx.tcx.tcx);
199198
ecx.allocate_dyn(layout, MemoryKind::Stack, meta).unwrap()
200199
}
@@ -216,11 +215,6 @@ pub fn valtree_to_const_value<'tcx>(
216215
// FIXME Does this need an example?
217216

218217
let (param_env, ty) = param_env_ty.into_parts();
219-
let mut ecx: crate::interpret::InterpCx<
220-
'_,
221-
'_,
222-
crate::const_eval::CompileTimeInterpreter<'_, '_>,
223-
> = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
224218

225219
match ty.kind() {
226220
ty::FnDef(..) => {
@@ -233,33 +227,44 @@ pub fn valtree_to_const_value<'tcx>(
233227
"ValTrees for Bool, Int, Uint, Float or Char should have the form ValTree::Leaf"
234228
),
235229
},
236-
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
237-
let place = match ty.kind() {
238-
ty::Ref(_, inner_ty, _) => {
239-
// Need to create a place for the pointee (the reference itself will be an immediate)
240-
create_pointee_place(&mut ecx, *inner_ty, valtree)
241-
}
242-
_ => {
243-
// Need to create a place for this valtree.
244-
create_pointee_place(&mut ecx, ty, valtree)
230+
ty::Ref(_, inner_ty, _) => {
231+
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
232+
let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
233+
let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
234+
op_to_const(&ecx, &imm.into())
235+
}
236+
ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
237+
let layout = tcx.layout_of(param_env_ty).unwrap();
238+
if layout.is_zst() {
239+
// Fast path to avoid some allocations.
240+
return ConstValue::ZeroSized;
241+
}
242+
if layout.abi.is_scalar()
243+
&& (matches!(ty.kind(), ty::Tuple(_))
244+
|| matches!(ty.kind(), ty::Adt(def, _) if def.is_struct()))
245+
{
246+
// A Scalar tuple/struct; we can avoid creating an allocation.
247+
let branches = valtree.unwrap_branch();
248+
// Find the non-ZST field. (There can be aligned ZST!)
249+
for (i, &inner_valtree) in branches.iter().enumerate() {
250+
let field = layout.field(&LayoutCx { tcx, param_env }, i);
251+
if !field.is_zst() {
252+
return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree);
253+
}
245254
}
246-
};
247-
debug!(?place);
255+
bug!("could not find non-ZST field during in {layout:#?}");
256+
}
257+
258+
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
259+
260+
// Need to create a place for this valtree.
261+
let place = create_valtree_place(&mut ecx, layout, valtree);
248262

249263
valtree_into_mplace(&mut ecx, &place, valtree);
250264
dump_place(&ecx, &place);
251265
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
252266

253-
match ty.kind() {
254-
ty::Ref(_, _, _) => {
255-
let ref_place = place.to_ref(&tcx);
256-
let imm =
257-
ImmTy::from_immediate(ref_place, tcx.layout_of(param_env_ty).unwrap());
258-
259-
op_to_const(&ecx, &imm.into())
260-
}
261-
_ => op_to_const(&ecx, &place.into()),
262-
}
267+
op_to_const(&ecx, &place.into())
263268
}
264269
ty::Never
265270
| ty::Error(_)
@@ -283,6 +288,22 @@ pub fn valtree_to_const_value<'tcx>(
283288
}
284289
}
285290

291+
/// Put a valtree into memory and return a reference to that.
292+
fn valtree_to_ref<'tcx>(
293+
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
294+
valtree: ty::ValTree<'tcx>,
295+
pointee_ty: Ty<'tcx>,
296+
) -> Immediate {
297+
let pointee_place = create_valtree_place(ecx, ecx.layout_of(pointee_ty).unwrap(), valtree);
298+
debug!(?pointee_place);
299+
300+
valtree_into_mplace(ecx, &pointee_place, valtree);
301+
dump_place(ecx, &pointee_place);
302+
intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
303+
304+
pointee_place.to_ref(&ecx.tcx)
305+
}
306+
286307
#[instrument(skip(ecx), level = "debug")]
287308
fn valtree_into_mplace<'tcx>(
288309
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
@@ -292,7 +313,6 @@ fn valtree_into_mplace<'tcx>(
292313
// This will match on valtree and write the value(s) corresponding to the ValTree
293314
// inside the place recursively.
294315

295-
let tcx = ecx.tcx.tcx;
296316
let ty = place.layout.ty;
297317

298318
match ty.kind() {
@@ -305,27 +325,8 @@ fn valtree_into_mplace<'tcx>(
305325
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap();
306326
}
307327
ty::Ref(_, inner_ty, _) => {
308-
let pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
309-
debug!(?pointee_place);
310-
311-
valtree_into_mplace(ecx, &pointee_place, valtree);
312-
dump_place(ecx, &pointee_place);
313-
intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
314-
315-
let imm = match inner_ty.kind() {
316-
ty::Slice(_) | ty::Str => {
317-
let len = valtree.unwrap_branch().len();
318-
let len_scalar = Scalar::from_target_usize(len as u64, &tcx);
319-
320-
Immediate::ScalarPair(
321-
Scalar::from_maybe_pointer(pointee_place.ptr(), &tcx),
322-
len_scalar,
323-
)
324-
}
325-
_ => pointee_place.to_ref(&tcx),
326-
};
328+
let imm = valtree_to_ref(ecx, valtree, *inner_ty);
327329
debug!(?imm);
328-
329330
ecx.write_immediate(imm, place).unwrap();
330331
}
331332
ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {

compiler/rustc_middle/src/mir/mod.rs

+17-17
Original file line numberDiff line numberDiff line change
@@ -2297,7 +2297,11 @@ pub struct Constant<'tcx> {
22972297
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
22982298
#[derive(Lift, TypeFoldable, TypeVisitable)]
22992299
pub enum ConstantKind<'tcx> {
2300-
/// This constant came from the type system
2300+
/// This constant came from the type system.
2301+
///
2302+
/// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
2303+
/// this ensures that we consistently produce "clean" values without data in the padding or
2304+
/// anything like that.
23012305
Ty(ty::Const<'tcx>),
23022306

23032307
/// An unevaluated mir constant which is not part of the type system.
@@ -2373,23 +2377,19 @@ impl<'tcx> ConstantKind<'tcx> {
23732377
param_env: ty::ParamEnv<'tcx>,
23742378
span: Option<Span>,
23752379
) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
2376-
let (uneval, param_env) = match self {
2380+
match self {
23772381
ConstantKind::Ty(c) => {
2378-
if let ty::ConstKind::Unevaluated(uneval) = c.kind() {
2379-
// Avoid the round-trip via valtree, evaluate directly to ConstValue.
2380-
let (param_env, uneval) = uneval.prepare_for_eval(tcx, param_env);
2381-
(uneval.expand(), param_env)
2382-
} else {
2383-
// It's already a valtree, or an error.
2384-
let val = c.eval(tcx, param_env, span)?;
2385-
return Ok(tcx.valtree_to_const_val((self.ty(), val)));
2386-
}
2382+
// We want to consistently have a "clean" value for type system constants (i.e., no
2383+
// data hidden in the padding), so we always go through a valtree here.
2384+
let val = c.eval(tcx, param_env, span)?;
2385+
Ok(tcx.valtree_to_const_val((self.ty(), val)))
23872386
}
2388-
ConstantKind::Unevaluated(uneval, _) => (uneval, param_env),
2389-
ConstantKind::Val(val, _) => return Ok(val),
2390-
};
2391-
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
2392-
tcx.const_eval_resolve(param_env, uneval, span)
2387+
ConstantKind::Unevaluated(uneval, _) => {
2388+
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
2389+
tcx.const_eval_resolve(param_env, uneval, span)
2390+
}
2391+
ConstantKind::Val(val, _) => Ok(val),
2392+
}
23932393
}
23942394

23952395
/// Normalizes the constant to a value or an error if possible.
@@ -2605,10 +2605,10 @@ impl<'tcx> ConstantKind<'tcx> {
26052605
pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
26062606
match c.kind() {
26072607
ty::ConstKind::Value(valtree) => {
2608+
// Make sure that if `c` is normalized, then the return value is normalized.
26082609
let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
26092610
Self::Val(const_val, c.ty())
26102611
}
2611-
ty::ConstKind::Unevaluated(uv) => Self::Unevaluated(uv.expand(), c.ty()),
26122612
_ => Self::Ty(c),
26132613
}
26142614
}

compiler/rustc_middle/src/ty/consts/kind.rs

-5
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ impl rustc_errors::IntoDiagnosticArg for UnevaluatedConst<'_> {
2222
}
2323

2424
impl<'tcx> UnevaluatedConst<'tcx> {
25-
#[inline]
26-
pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
27-
mir::UnevaluatedConst { def: self.def, args: self.args, promoted: None }
28-
}
29-
3025
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
3126
/// hurts performance.
3227
#[inline]

compiler/rustc_monomorphize/src/collector.rs

+9-33
Original file line numberDiff line numberDiff line change
@@ -749,39 +749,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
749749
#[instrument(skip(self), level = "debug")]
750750
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
751751
let literal = self.monomorphize(constant.literal);
752-
let val = match literal {
753-
mir::ConstantKind::Val(val, _) => val,
754-
mir::ConstantKind::Ty(ct) => match ct.kind() {
755-
ty::ConstKind::Value(val) => self.tcx.valtree_to_const_val((ct.ty(), val)),
756-
ty::ConstKind::Unevaluated(ct) => {
757-
debug!(?ct);
758-
let param_env = ty::ParamEnv::reveal_all();
759-
match self.tcx.const_eval_resolve(param_env, ct.expand(), None) {
760-
// The `monomorphize` call should have evaluated that constant already.
761-
Ok(val) => val,
762-
Err(ErrorHandled::Reported(_)) => return,
763-
Err(ErrorHandled::TooGeneric) => span_bug!(
764-
self.body.source_info(location).span,
765-
"collection encountered polymorphic constant: {:?}",
766-
literal
767-
),
768-
}
769-
}
770-
_ => return,
771-
},
772-
mir::ConstantKind::Unevaluated(uv, _) => {
773-
let param_env = ty::ParamEnv::reveal_all();
774-
match self.tcx.const_eval_resolve(param_env, uv, None) {
775-
// The `monomorphize` call should have evaluated that constant already.
776-
Ok(val) => val,
777-
Err(ErrorHandled::Reported(_)) => return,
778-
Err(ErrorHandled::TooGeneric) => span_bug!(
779-
self.body.source_info(location).span,
780-
"collection encountered polymorphic constant: {:?}",
781-
literal
782-
),
783-
}
784-
}
752+
let param_env = ty::ParamEnv::reveal_all();
753+
let val = match literal.eval(self.tcx, param_env, None) {
754+
Ok(v) => v,
755+
Err(ErrorHandled::Reported(_)) => return,
756+
Err(ErrorHandled::TooGeneric) => span_bug!(
757+
self.body.source_info(location).span,
758+
"collection encountered polymorphic constant: {:?}",
759+
literal
760+
),
785761
};
786762
collect_const_value(self.tcx, val, self.output);
787763
MirVisitor::visit_ty(self, literal.ty(), TyContext::Location(location));

0 commit comments

Comments
 (0)