Skip to content

Commit bd9785c

Browse files
committed
Auto merge of #114071 - RalfJung:interpret-generic-read-write, r=oli-obk
interpret: make read/write methods generic Instead of always having to call `into()` to convert things to `PlaceTy`/`OpTy`, make the relevant methods generic. This also means that when we read from an `MPlaceTy`, we avoid creating an intermediate `PlaceTy`. This makes it feasible to remove the `Copy` from `MPlaceTy`. All the other `*Ty` interpreter types already had their `Copy` removed a while ago so this is only consistent. (And in fact we had one function that accidentally took `MPlaceTy` instead of `&MPlaceTy`.)
2 parents 52bdc37 + 571e8ce commit bd9785c

34 files changed

+403
-371
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
5858
ecx.push_stack_frame(
5959
cid.instance,
6060
body,
61-
&ret.into(),
61+
&ret.clone().into(),
6262
StackPopCleanup::Root { cleanup: false },
6363
)?;
6464

@@ -356,7 +356,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
356356
// Since evaluation had no errors, validate the resulting constant.
357357
// This is a separate `try` block to provide more targeted error reporting.
358358
let validation: Result<_, InterpErrorInfo<'_>> = try {
359-
let mut ref_tracking = RefTracking::new(mplace);
359+
let mut ref_tracking = RefTracking::new(mplace.clone());
360360
let mut inner = false;
361361
while let Some((mplace, path)) = ref_tracking.todo.pop() {
362362
let mode = match tcx.static_mutability(cid.instance.def_id()) {

compiler/rustc_const_eval/src/const_eval/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
216216

217217
let mut msg_place = self.deref_operand(&args[0])?;
218218
while msg_place.layout.ty.is_ref() {
219-
msg_place = self.deref_operand(&msg_place.into())?;
219+
msg_place = self.deref_operand(&msg_place)?;
220220
}
221221

222222
let msg = Symbol::intern(self.read_str(&msg_place)?);

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+23-23
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::const_eval::CanAccessStatics;
55
use crate::interpret::MPlaceTy;
66
use crate::interpret::{
77
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
8-
MemoryKind, PlaceTy, Projectable, Scalar,
8+
MemoryKind, Place, Projectable, Scalar,
99
};
1010
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
1111
use rustc_span::source_map::DUMMY_SP;
@@ -21,7 +21,7 @@ fn branches<'tcx>(
2121
) -> ValTreeCreationResult<'tcx> {
2222
let place = match variant {
2323
Some(variant) => ecx.project_downcast(place, variant).unwrap(),
24-
None => *place,
24+
None => place.clone(),
2525
};
2626
let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
2727
debug!(?place, ?variant);
@@ -86,7 +86,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
8686
Ok(ty::ValTree::zst())
8787
}
8888
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
89-
let Ok(val) = ecx.read_immediate(&place.into()) else {
89+
let Ok(val) = ecx.read_immediate(place) else {
9090
return Err(ValTreeCreationError::Other);
9191
};
9292
let val = val.to_scalar();
@@ -102,7 +102,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
102102
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
103103

104104
ty::Ref(_, _, _) => {
105-
let Ok(derefd_place)= ecx.deref_operand(&place.into()) else {
105+
let Ok(derefd_place)= ecx.deref_operand(place) else {
106106
return Err(ValTreeCreationError::Other);
107107
};
108108
debug!(?derefd_place);
@@ -130,7 +130,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
130130
bug!("uninhabited types should have errored and never gotten converted to valtree")
131131
}
132132

133-
let Ok(variant) = ecx.read_discriminant(&place.into()) else {
133+
let Ok(variant) = ecx.read_discriminant(place) else {
134134
return Err(ValTreeCreationError::Other);
135135
};
136136
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
@@ -280,7 +280,7 @@ pub fn valtree_to_const_value<'tcx>(
280280
),
281281
},
282282
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
283-
let mut place = match ty.kind() {
283+
let place = match ty.kind() {
284284
ty::Ref(_, inner_ty, _) => {
285285
// Need to create a place for the pointee to fill for Refs
286286
create_pointee_place(&mut ecx, *inner_ty, valtree)
@@ -289,8 +289,8 @@ pub fn valtree_to_const_value<'tcx>(
289289
};
290290
debug!(?place);
291291

292-
valtree_into_mplace(&mut ecx, &mut place, valtree);
293-
dump_place(&ecx, place.into());
292+
valtree_into_mplace(&mut ecx, &place, valtree);
293+
dump_place(&ecx, &place);
294294
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
295295

296296
match ty.kind() {
@@ -329,7 +329,7 @@ pub fn valtree_to_const_value<'tcx>(
329329
#[instrument(skip(ecx), level = "debug")]
330330
fn valtree_into_mplace<'tcx>(
331331
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
332-
place: &mut MPlaceTy<'tcx>,
332+
place: &MPlaceTy<'tcx>,
333333
valtree: ty::ValTree<'tcx>,
334334
) {
335335
// This will match on valtree and write the value(s) corresponding to the ValTree
@@ -345,14 +345,14 @@ fn valtree_into_mplace<'tcx>(
345345
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
346346
let scalar_int = valtree.unwrap_leaf();
347347
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
348-
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap();
348+
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap();
349349
}
350350
ty::Ref(_, inner_ty, _) => {
351-
let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
351+
let pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
352352
debug!(?pointee_place);
353353

354-
valtree_into_mplace(ecx, &mut pointee_place, valtree);
355-
dump_place(ecx, pointee_place.into());
354+
valtree_into_mplace(ecx, &pointee_place, valtree);
355+
dump_place(ecx, &pointee_place);
356356
intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
357357

358358
let imm = match inner_ty.kind() {
@@ -369,7 +369,7 @@ fn valtree_into_mplace<'tcx>(
369369
};
370370
debug!(?imm);
371371

372-
ecx.write_immediate(imm, &place.into()).unwrap();
372+
ecx.write_immediate(imm, place).unwrap();
373373
}
374374
ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
375375
let branches = valtree.unwrap_branch();
@@ -389,7 +389,7 @@ fn valtree_into_mplace<'tcx>(
389389
Some(variant_idx),
390390
)
391391
}
392-
_ => (*place, branches, None),
392+
_ => (place.clone(), branches, None),
393393
};
394394
debug!(?place_adjusted, ?branches);
395395

@@ -398,7 +398,7 @@ fn valtree_into_mplace<'tcx>(
398398
for (i, inner_valtree) in branches.iter().enumerate() {
399399
debug!(?i, ?inner_valtree);
400400

401-
let mut place_inner = match ty.kind() {
401+
let place_inner = match ty.kind() {
402402
ty::Str | ty::Slice(_) => ecx.project_index(place, i as u64).unwrap(),
403403
_ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
404404
&& i == branches.len() - 1 =>
@@ -443,25 +443,25 @@ fn valtree_into_mplace<'tcx>(
443443
};
444444

445445
debug!(?place_inner);
446-
valtree_into_mplace(ecx, &mut place_inner, *inner_valtree);
447-
dump_place(&ecx, place_inner.into());
446+
valtree_into_mplace(ecx, &place_inner, *inner_valtree);
447+
dump_place(&ecx, &place_inner);
448448
}
449449

450450
debug!("dump of place_adjusted:");
451-
dump_place(ecx, place_adjusted.into());
451+
dump_place(ecx, &place_adjusted);
452452

453453
if let Some(variant_idx) = variant_idx {
454454
// don't forget filling the place with the discriminant of the enum
455-
ecx.write_discriminant(variant_idx, &place.into()).unwrap();
455+
ecx.write_discriminant(variant_idx, place).unwrap();
456456
}
457457

458458
debug!("dump of place after writing discriminant:");
459-
dump_place(ecx, place.into());
459+
dump_place(ecx, place);
460460
}
461461
_ => bug!("shouldn't have created a ValTree for {:?}", ty),
462462
}
463463
}
464464

465-
fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: PlaceTy<'tcx>) {
466-
trace!("{:?}", ecx.dump_place(*place));
465+
fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) {
466+
trace!("{:?}", ecx.dump_place(Place::Ptr(**place)));
467467
}

compiler/rustc_const_eval/src/interpret/cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5656
}
5757

5858
CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
59-
let src = self.read_immediate(&src)?;
59+
let src = self.read_immediate(src)?;
6060
let res = self.ptr_to_ptr(&src, cast_ty)?;
6161
self.write_immediate(res, dest)?;
6262
}

compiler/rustc_const_eval/src/interpret/discriminant.rs

+22-22
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ use rustc_middle::{mir, ty};
55
use rustc_target::abi::{self, TagEncoding};
66
use rustc_target::abi::{VariantIdx, Variants};
77

8-
use super::{ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Scalar};
8+
use super::{ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable};
99

1010
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1111
/// Writes the discriminant of the given variant.
1212
#[instrument(skip(self), level = "trace")]
1313
pub fn write_discriminant(
1414
&mut self,
1515
variant_index: VariantIdx,
16-
dest: &PlaceTy<'tcx, M::Provenance>,
16+
dest: &impl Writeable<'tcx, M::Provenance>,
1717
) -> InterpResult<'tcx> {
1818
// Layout computation excludes uninhabited variants from consideration
1919
// therefore there's no way to represent those variants in the given layout.
2020
// Essentially, uninhabited variants do not have a tag that corresponds to their
2121
// discriminant, so we cannot do anything here.
2222
// When evaluating we will always error before even getting here, but ConstProp 'executes'
2323
// dead code, so we cannot ICE here.
24-
if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
24+
if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() {
2525
throw_ub!(UninhabitedEnumVariantWritten(variant_index))
2626
}
2727

28-
match dest.layout.variants {
28+
match dest.layout().variants {
2929
abi::Variants::Single { index } => {
3030
assert_eq!(index, variant_index);
3131
}
@@ -38,8 +38,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3838
// No need to validate that the discriminant here because the
3939
// `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
4040

41-
let discr_val =
42-
dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
41+
let discr_val = dest
42+
.layout()
43+
.ty
44+
.discriminant_for_variant(*self.tcx, variant_index)
45+
.unwrap()
46+
.val;
4347

4448
// raw discriminants for enums are isize or bigger during
4549
// their computation, but the in-memory tag is the smallest possible
@@ -92,32 +96,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9296
#[instrument(skip(self), level = "trace")]
9397
pub fn read_discriminant(
9498
&self,
95-
op: &OpTy<'tcx, M::Provenance>,
99+
op: &impl Readable<'tcx, M::Provenance>,
96100
) -> InterpResult<'tcx, VariantIdx> {
97-
trace!("read_discriminant_value {:#?}", op.layout);
101+
let ty = op.layout().ty;
102+
trace!("read_discriminant_value {:#?}", op.layout());
98103
// Get type and layout of the discriminant.
99-
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
104+
let discr_layout = self.layout_of(ty.discriminant_ty(*self.tcx))?;
100105
trace!("discriminant type: {:?}", discr_layout.ty);
101106

102107
// We use "discriminant" to refer to the value associated with a particular enum variant.
103108
// This is not to be confused with its "variant index", which is just determining its position in the
104109
// declared list of variants -- they can differ with explicitly assigned discriminants.
105110
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
106111
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
107-
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
112+
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants {
108113
Variants::Single { index } => {
109114
// Do some extra checks on enums.
110-
if op.layout.ty.is_enum() {
115+
if ty.is_enum() {
111116
// Hilariously, `Single` is used even for 0-variant enums.
112117
// (See https://github.com/rust-lang/rust/issues/89765).
113-
if matches!(op.layout.ty.kind(), ty::Adt(def, ..) if def.variants().is_empty())
114-
{
118+
if matches!(ty.kind(), ty::Adt(def, ..) if def.variants().is_empty()) {
115119
throw_ub!(UninhabitedEnumVariantRead(index))
116120
}
117121
// For consisteny with `write_discriminant`, and to make sure that
118122
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
119123
// for uninhabited variants.
120-
if op.layout.for_variant(self, index).abi.is_uninhabited() {
124+
if op.layout().for_variant(self, index).abi.is_uninhabited() {
121125
throw_ub!(UninhabitedEnumVariantRead(index))
122126
}
123127
}
@@ -163,7 +167,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
163167
self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
164168
let discr_bits = discr_val.assert_bits(discr_layout.size);
165169
// Convert discriminant to variant index, and catch invalid discriminants.
166-
let index = match *op.layout.ty.kind() {
170+
let index = match *ty.kind() {
167171
ty::Adt(adt, _) => {
168172
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
169173
}
@@ -217,12 +221,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
217221
.checked_add(variant_index_relative)
218222
.expect("overflow computing absolute variant idx"),
219223
);
220-
let variants = op
221-
.layout
222-
.ty
223-
.ty_adt_def()
224-
.expect("tagged layout for non adt")
225-
.variants();
224+
let variants =
225+
ty.ty_adt_def().expect("tagged layout for non adt").variants();
226226
assert!(variant_index < variants.next_index());
227227
variant_index
228228
} else {
@@ -237,7 +237,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
237237
}
238238
};
239239
// For consisteny with `write_discriminant`, and to make sure that `project_downcast` cannot fail due to strange layouts, we declare immediate UB for uninhabited variants.
240-
if op.layout.for_variant(self, index).abi.is_uninhabited() {
240+
if op.layout().for_variant(self, index).abi.is_uninhabited() {
241241
throw_ub!(UninhabitedEnumVariantRead(index))
242242
}
243243
Ok(index)

compiler/rustc_const_eval/src/interpret/intern.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
170170
let tcx = self.ecx.tcx;
171171
let ty = mplace.layout.ty;
172172
if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
173-
let value = self.ecx.read_immediate(&mplace.into())?;
173+
let value = self.ecx.read_immediate(mplace)?;
174174
let mplace = self.ecx.ref_to_mplace(&value)?;
175175
assert_eq!(mplace.layout.ty, referenced_ty);
176176
// Handle trait object vtables.
@@ -358,7 +358,7 @@ pub fn intern_const_alloc_recursive<
358358
Some(ret.layout.ty),
359359
);
360360

361-
ref_tracking.track((*ret, base_intern_mode), || ());
361+
ref_tracking.track((ret.clone(), base_intern_mode), || ());
362362

363363
while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
364364
let res = InternVisitor {
@@ -464,7 +464,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
464464
) -> InterpResult<'tcx, ()>,
465465
) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
466466
let dest = self.allocate(layout, MemoryKind::Stack)?;
467-
f(self, &dest.into())?;
467+
f(self, &dest.clone().into())?;
468468
let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
469469
alloc.mutability = Mutability::Not;
470470
Ok(self.tcx.mk_const_alloc(alloc))

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
226226
}
227227
sym::discriminant_value => {
228228
let place = self.deref_operand(&args[0])?;
229-
let variant = self.read_discriminant(&place.into())?;
229+
let variant = self.read_discriminant(&place)?;
230230
let discr = self.discriminant_for_variant(place.layout, variant)?;
231231
self.write_scalar(discr, dest)?;
232232
}
@@ -432,7 +432,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
432432
} else {
433433
self.project_index(&input, i)?.into()
434434
};
435-
self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?;
435+
self.copy_op(&value, &place, /*allow_transmute*/ false)?;
436436
}
437437
}
438438
sym::simd_extract => {
@@ -445,7 +445,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
445445
input_len
446446
);
447447
self.copy_op(
448-
&self.project_index(&input, index)?.into(),
448+
&self.project_index(&input, index)?,
449449
dest,
450450
/*allow_transmute*/ false,
451451
)?;
@@ -610,7 +610,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
610610
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
611611
nonoverlapping: bool,
612612
) -> InterpResult<'tcx> {
613-
let count = self.read_target_usize(&count)?;
613+
let count = self.read_target_usize(count)?;
614614
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
615615
let (size, align) = (layout.size, layout.align.abi);
616616
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
@@ -622,8 +622,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
622622
)
623623
})?;
624624

625-
let src = self.read_pointer(&src)?;
626-
let dst = self.read_pointer(&dst)?;
625+
let src = self.read_pointer(src)?;
626+
let dst = self.read_pointer(dst)?;
627627

628628
self.mem_copy(src, align, dst, align, size, nonoverlapping)
629629
}
@@ -636,9 +636,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
636636
) -> InterpResult<'tcx> {
637637
let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
638638

639-
let dst = self.read_pointer(&dst)?;
640-
let byte = self.read_scalar(&byte)?.to_u8()?;
641-
let count = self.read_target_usize(&count)?;
639+
let dst = self.read_pointer(dst)?;
640+
let byte = self.read_scalar(byte)?.to_u8()?;
641+
let count = self.read_target_usize(count)?;
642642

643643
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
644644
// but no actual allocation can be big enough for the difference to be noticeable.

0 commit comments

Comments
 (0)