Skip to content

Commit 997ec63

Browse files
committed
simplify handling of valtrees for unsized types
1 parent b6e3bc2 commit 997ec63

File tree

3 files changed

+43
-82
lines changed

3 files changed

+43
-82
lines changed

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+28-71
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ use crate::interpret::{
77
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
88
MemoryKind, Place, Projectable, Scalar,
99
};
10+
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
1011
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
1112
use rustc_span::source_map::DUMMY_SP;
12-
use rustc_target::abi::{Align, VariantIdx};
13+
use rustc_target::abi::VariantIdx;
1314

1415
#[instrument(skip(ecx), level = "debug")]
1516
fn branches<'tcx>(
@@ -154,52 +155,37 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
154155
}
155156
}
156157

157-
#[instrument(skip(ecx), level = "debug")]
158-
fn create_mplace_from_layout<'tcx>(
159-
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
160-
ty: Ty<'tcx>,
161-
) -> MPlaceTy<'tcx> {
162-
let tcx = ecx.tcx;
163-
let param_env = ecx.param_env;
164-
let layout = tcx.layout_of(param_env.and(ty)).unwrap();
165-
debug!(?layout);
166-
167-
ecx.allocate(layout, MemoryKind::Stack).unwrap()
168-
}
169-
170-
// Walks custom DSTs and gets the type of the unsized field and the number of elements
171-
// in the unsized field.
172-
fn get_info_on_unsized_field<'tcx>(
173-
ty: Ty<'tcx>,
158+
/// Valtrees don't store the `MemPlaceMeta` that all dynamically sized values have in the interpreter.
159+
/// This function reconstructs it.
160+
fn reconstruct_place_meta<'tcx>(
161+
layout: TyAndLayout<'tcx>,
174162
valtree: ty::ValTree<'tcx>,
175163
tcx: TyCtxt<'tcx>,
176-
) -> (Ty<'tcx>, usize) {
164+
) -> MemPlaceMeta {
165+
if layout.is_sized() {
166+
return MemPlaceMeta::None;
167+
}
168+
177169
let mut last_valtree = valtree;
170+
// Traverse the type, and update `last_valtree` as we go.
178171
let tail = tcx.struct_tail_with_normalize(
179-
ty,
172+
layout.ty,
180173
|ty| ty,
181174
|| {
182175
let branches = last_valtree.unwrap_branch();
183-
last_valtree = branches[branches.len() - 1];
176+
last_valtree = *branches.last().unwrap();
184177
debug!(?branches, ?last_valtree);
185178
},
186179
);
187-
let unsized_inner_ty = match tail.kind() {
188-
ty::Slice(t) => *t,
189-
ty::Str => tail,
190-
_ => bug!("expected Slice or Str"),
191-
};
192-
193-
// Have to adjust type for ty::Str
194-
let unsized_inner_ty = match unsized_inner_ty.kind() {
195-
ty::Str => tcx.types.u8,
196-
_ => unsized_inner_ty,
180+
// Sanity-check that we got a tail we support.
181+
match tail.kind() {
182+
ty::Slice(..) | ty::Str => {}
183+
_ => bug!("unsized tail of a valtree must be Slice or Str"),
197184
};
198185

199-
// Get the number of elements in the unsized field
186+
// Get the number of elements in the unsized field.
200187
let num_elems = last_valtree.unwrap_branch().len();
201-
202-
(unsized_inner_ty, num_elems)
188+
MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx))
203189
}
204190

205191
#[instrument(skip(ecx), level = "debug", ret)]
@@ -208,41 +194,9 @@ fn create_pointee_place<'tcx>(
208194
ty: Ty<'tcx>,
209195
valtree: ty::ValTree<'tcx>,
210196
) -> MPlaceTy<'tcx> {
211-
let tcx = ecx.tcx.tcx;
212-
213-
if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) {
214-
// We need to create `Allocation`s for custom DSTs
215-
216-
let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx);
217-
let unsized_inner_ty = match unsized_inner_ty.kind() {
218-
ty::Str => tcx.types.u8,
219-
_ => unsized_inner_ty,
220-
};
221-
let unsized_inner_ty_size =
222-
tcx.layout_of(ty::ParamEnv::empty().and(unsized_inner_ty)).unwrap().layout.size();
223-
debug!(?unsized_inner_ty, ?unsized_inner_ty_size, ?num_elems);
224-
225-
// for custom DSTs only the last field/element is unsized, but we need to also allocate
226-
// space for the other fields/elements
227-
let layout = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap();
228-
let size_of_sized_part = layout.layout.size();
229-
230-
// Get the size of the memory behind the DST
231-
let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap();
232-
233-
let size = size_of_sized_part.checked_add(dst_size, &tcx).unwrap();
234-
let align = Align::from_bytes(size.bytes().next_power_of_two()).unwrap();
235-
let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
236-
debug!(?ptr);
237-
238-
MPlaceTy::from_aligned_ptr_with_meta(
239-
ptr.into(),
240-
layout,
241-
MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)),
242-
)
243-
} else {
244-
create_mplace_from_layout(ecx, ty)
245-
}
197+
let layout = ecx.layout_of(ty).unwrap();
198+
let meta = reconstruct_place_meta(layout, valtree, ecx.tcx.tcx);
199+
ecx.allocate_dyn(layout, MemoryKind::Stack, meta).unwrap()
246200
}
247201

248202
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
@@ -282,10 +236,13 @@ pub fn valtree_to_const_value<'tcx>(
282236
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
283237
let place = match ty.kind() {
284238
ty::Ref(_, inner_ty, _) => {
285-
// Need to create a place for the pointee to fill for Refs
239+
// Need to create a place for the pointee (the reference itself will be an immediate)
286240
create_pointee_place(&mut ecx, *inner_ty, valtree)
287241
}
288-
_ => create_mplace_from_layout(&mut ecx, ty),
242+
_ => {
243+
// Need to create a place for this valtree.
244+
create_pointee_place(&mut ecx, ty, valtree)
245+
}
289246
};
290247
debug!(?place);
291248

compiler/rustc_const_eval/src/interpret/place.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -934,14 +934,26 @@ where
934934
Ok(MPlaceTy { mplace, layout: place.layout, align: place.align })
935935
}
936936

937+
pub fn allocate_dyn(
938+
&mut self,
939+
layout: TyAndLayout<'tcx>,
940+
kind: MemoryKind<M::MemoryKind>,
941+
meta: MemPlaceMeta<M::Provenance>,
942+
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
943+
let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else {
944+
span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
945+
};
946+
let ptr = self.allocate_ptr(size, align, kind)?;
947+
Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), layout, meta))
948+
}
949+
937950
pub fn allocate(
938951
&mut self,
939952
layout: TyAndLayout<'tcx>,
940953
kind: MemoryKind<M::MemoryKind>,
941954
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
942955
assert!(layout.is_sized());
943-
let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?;
944-
Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout))
956+
self.allocate_dyn(layout, kind, MemPlaceMeta::None)
945957
}
946958

947959
/// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation.

compiler/rustc_const_eval/src/interpret/terminator.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -393,15 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
393393
));
394394
assert_eq!(dest_offset, None);
395395
// Allocate enough memory to hold `src`.
396-
let Some((size, align)) = self.size_and_align_of_mplace(&src)? else {
397-
span_bug!(
398-
self.cur_span(),
399-
"unsized fn arg with `extern` type tail should not be allowed"
400-
)
401-
};
402-
let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?;
403-
let dest_place =
404-
MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), callee_arg.layout, src.meta);
396+
let dest_place = self.allocate_dyn(src.layout, MemoryKind::Stack, src.meta)?;
405397
// Update the local to be that new place.
406398
*M::access_local_mut(self, dest_frame, dest_local)? = Operand::Indirect(*dest_place);
407399
}

0 commit comments

Comments
 (0)