@@ -7,9 +7,10 @@ use crate::interpret::{
7
7
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
8
8
MemoryKind, Place, Projectable, Scalar,
9
9
};
10
+ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
10
11
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
11
12
use rustc_span::source_map::DUMMY_SP;
12
- use rustc_target::abi::{Align, FieldIdx, VariantIdx, FIRST_VARIANT} ;
13
+ use rustc_target::abi::VariantIdx;
13
14
14
15
#[instrument(skip(ecx), level = "debug")]
15
16
fn branches<'tcx>(
@@ -154,52 +155,37 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
154
155
}
155
156
}
156
157
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>,
174
162
valtree: ty::ValTree<'tcx>,
175
163
tcx: TyCtxt<'tcx>,
176
- ) -> (Ty<'tcx>, usize) {
164
+ ) -> MemPlaceMeta {
165
+ if layout.is_sized() {
166
+ return MemPlaceMeta::None;
167
+ }
168
+
177
169
let mut last_valtree = valtree;
170
+ // Traverse the type, and update `last_valtree` as we go.
178
171
let tail = tcx.struct_tail_with_normalize(
179
- ty,
172
+ layout. ty,
180
173
|ty| ty,
181
174
|| {
182
175
let branches = last_valtree.unwrap_branch();
183
- last_valtree = branches[branches.len() - 1] ;
176
+ last_valtree = * branches.last().unwrap() ;
184
177
debug!(?branches, ?last_valtree);
185
178
},
186
179
);
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"),
197
184
};
198
185
199
- // Get the number of elements in the unsized field
186
+ // Get the number of elements in the unsized field.
200
187
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))
203
189
}
204
190
205
191
#[instrument(skip(ecx), level = "debug", ret)]
@@ -208,41 +194,9 @@ fn create_pointee_place<'tcx>(
208
194
ty: Ty<'tcx>,
209
195
valtree: ty::ValTree<'tcx>,
210
196
) -> 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()
246
200
}
247
201
248
202
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
@@ -282,10 +236,13 @@ pub fn valtree_to_const_value<'tcx>(
282
236
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
283
237
let place = match ty.kind() {
284
238
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)
286
240
create_pointee_place(&mut ecx, *inner_ty, valtree)
287
241
}
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
+ }
289
246
};
290
247
debug!(?place);
291
248
@@ -399,45 +356,8 @@ fn valtree_into_mplace<'tcx>(
399
356
debug!(?i, ?inner_valtree);
400
357
401
358
let place_inner = match ty.kind() {
402
- ty::Str | ty::Slice(_) => ecx.project_index(place, i as u64).unwrap(),
403
- _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
404
- && i == branches.len() - 1 =>
405
- {
406
- // Note: For custom DSTs we need to manually process the last unsized field.
407
- // We created a `Pointer` for the `Allocation` of the complete sized version of
408
- // the Adt in `create_pointee_place` and now we fill that `Allocation` with the
409
- // values in the ValTree. For the unsized field we have to additionally add the meta
410
- // data.
411
-
412
- let (unsized_inner_ty, num_elems) =
413
- get_info_on_unsized_field(ty, valtree, tcx);
414
- debug!(?unsized_inner_ty);
415
-
416
- let inner_ty = match ty.kind() {
417
- ty::Adt(def, args) => {
418
- let i = FieldIdx::from_usize(i);
419
- def.variant(FIRST_VARIANT).fields[i].ty(tcx, args)
420
- }
421
- ty::Tuple(inner_tys) => inner_tys[i],
422
- _ => bug!("unexpected unsized type {:?}", ty),
423
- };
424
-
425
- let inner_layout =
426
- tcx.layout_of(ty::ParamEnv::empty().and(inner_ty)).unwrap();
427
- debug!(?inner_layout);
428
-
429
- let offset = place_adjusted.layout.fields.offset(i);
430
- place
431
- .offset_with_meta(
432
- offset,
433
- MemPlaceMeta::Meta(Scalar::from_target_usize(
434
- num_elems as u64,
435
- &tcx,
436
- )),
437
- inner_layout,
438
- &tcx,
439
- )
440
- .unwrap()
359
+ ty::Str | ty::Slice(_) | ty::Array(..) => {
360
+ ecx.project_index(place, i as u64).unwrap()
441
361
}
442
362
_ => ecx.project_field(&place_adjusted, i).unwrap(),
443
363
};
0 commit comments