From ef5f07256cfa4e1f43a18acb45e0d8108f8471a4 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 27 Apr 2022 11:11:54 +0200 Subject: [PATCH] combine all unsized types and add another recursive call to process nested unsized types correctly --- .../src/const_eval/eval_queries.rs | 9 +- .../src/const_eval/valtrees.rs | 165 ++++++++---------- compiler/rustc_middle/src/ty/util.rs | 2 +- 3 files changed, 79 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 6112c4ffbfa6d..38fecf7232ebc 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,4 +1,4 @@ -use super::{const_to_valtree, CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr}; +use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, @@ -219,13 +219,6 @@ fn turn_into_const_value<'tcx>( let const_val = op_to_const(&ecx, &mplace.into()); debug!(?const_val); - if cfg!(debug_assertions) { - if let Some(valtree) = const_to_valtree(tcx, key.param_env, constant) { - let const_val = tcx.valtree_to_const_val((constant.ty, valtree)); - debug!(?const_val); - } - } - const_val } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 389301300ea15..374179d0cc24d 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -194,55 +194,48 @@ fn create_pointee_place<'tcx>( ) -> MPlaceTy<'tcx> { let tcx = ecx.tcx.tcx; - match ty.kind() { - ty::Slice(_) | ty::Str => { - let slice_ty = match ty.kind() { - ty::Slice(slice_ty) => *slice_ty, - ty::Str => tcx.mk_ty(ty::Uint(ty::UintTy::U8)), - _ => bug!("expected ty::Slice | ty::Str"), - }; - - // Create a place for the underlying array - let len = valtree.unwrap_branch().len() as u64; - let arr_ty = tcx.mk_array(slice_ty, len as u64); - let place = create_mplace_from_layout(ecx, arr_ty); - debug!(?place); + if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) { + // We need to create `Allocation`s for custom DSTs + + let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx); + let unsized_inner_ty = match unsized_inner_ty.kind() { + ty::Str => tcx.mk_ty(ty::Uint(ty::UintTy::U8)), + _ => unsized_inner_ty, + }; + let unsized_inner_ty_size = + tcx.layout_of(ty::ParamEnv::empty().and(unsized_inner_ty)).unwrap().layout.size(); + debug!(?unsized_inner_ty, ?unsized_inner_ty_size, ?num_elems); + + // for custom DSTs only the last field/element is unsized, but we need to also allocate + // space for the other fields/elements + let layout = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap(); + let size_of_sized_part = layout.layout.size(); + + // Get the size of the memory behind the DST + let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap(); + + let ptr = ecx + .allocate_ptr( + size_of_sized_part.checked_add(dst_size, &tcx).unwrap(), + Align::from_bytes(1).unwrap(), + MemoryKind::Stack, + ) + .unwrap(); + debug!(?ptr); - place - } - ty::Adt(_, _) if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) => { - // We need to create `Allocation`s for custom DSTs - - let layout = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap(); - let sized_fields_size = layout.layout.size(); - let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx); - let unsized_inner_ty_size = - tcx.layout_of(ty::ParamEnv::empty().and(unsized_inner_ty)).unwrap().layout.size(); - debug!(?unsized_inner_ty, ?unsized_inner_ty_size, ?num_elems); - - // Get the size of the array behind the DST - let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap(); - - let ptr = ecx - .allocate_ptr( - sized_fields_size.checked_add(dst_size, &tcx).unwrap(), - Align::from_bytes(1).unwrap(), - MemoryKind::Stack, - ) - .unwrap(); - debug!(?ptr); - - let place = MPlaceTy::from_aligned_ptr(ptr.into(), layout); - debug!(?place); + let mut place = MPlaceTy::from_aligned_ptr(ptr.into(), layout); + place.meta = MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)); + debug!(?place); - place - } - _ => create_mplace_from_layout(ecx, ty), + place + } else { + create_mplace_from_layout(ecx, ty) } } /// Converts a `ValTree` to a `ConstValue`, which is needed after mir /// construction has finished. +// FIXME Merge `valtree_to_const_value` and `fill_place_recursively` into one function #[instrument(skip(tcx), level = "debug")] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, @@ -374,12 +367,9 @@ fn fill_place_recursively<'tcx>( ecx.write_immediate(imm, &(*place).into()).unwrap(); } - ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str => { + ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => { let branches = valtree.unwrap_branch(); - // Need to collect the length of the unsized field for meta info - let mut unsized_meta_info = None; - // Need to downcast place for enums let (place_adjusted, branches, variant_idx) = match ty.kind() { ty::Adt(def, _) if def.is_enum() => { @@ -399,48 +389,52 @@ fn fill_place_recursively<'tcx>( }; debug!(?place_adjusted, ?branches); - // Create the places for the fields and fill them recursively + // Create the places (by indexing into `place`) for the fields and fill + // them recursively for (i, inner_valtree) in branches.iter().enumerate() { debug!(?i, ?inner_valtree); - if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) && i == branches.len() - 1 { - // Note: For custom DSTs we need to manually process the last unsized field. - // We created a `Pointer` for the `Allocation` of the complete sized version of - // the Adt in `create_pointee_place` and now we fill that `Allocation` with the - // values in the ValTree. For the unsized field we have to additionally add the meta - // data. - - let offset = place.layout.fields.offset(i); - let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx); - unsized_meta_info = Some(num_elems); - - // We create an array type to allow the recursive call to fill the place - // corresponding to the array - let arr_ty = tcx.mk_array(unsized_inner_ty, num_elems as u64); - debug!(?arr_ty); - let arr_layout = tcx.layout_of(ty::ParamEnv::empty().and(arr_ty)).unwrap(); - let mut place_arr = - place.offset(offset, MemPlaceMeta::None, arr_layout, &tcx).unwrap(); - debug!(?place_arr); - - fill_place_recursively(ecx, &mut place_arr, *inner_valtree); - dump_place(&ecx, place_arr.into()); - - // Add the meta information for the unsized type - place_arr.meta = MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)); - - break; - } - - let mut place_inner = match *ty.kind() { - ty::Adt(_, _) | ty::Tuple(_) => ecx.mplace_field(&place_adjusted, i).unwrap(), - ty::Array(_, _) | ty::Str => { - ecx.mplace_index(&place_adjusted, i as u64).unwrap() + let mut place_inner = match ty.kind() { + ty::Str | ty::Slice(_) => ecx.mplace_index(&place, i as u64).unwrap(), + _ if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) + && i == branches.len() - 1 => + { + // Note: For custom DSTs we need to manually process the last unsized field. + // We created a `Pointer` for the `Allocation` of the complete sized version of + // the Adt in `create_pointee_place` and now we fill that `Allocation` with the + // values in the ValTree. For the unsized field we have to additionally add the meta + // data. + + let (unsized_inner_ty, num_elems) = + get_info_on_unsized_field(ty, valtree, tcx); + debug!(?unsized_inner_ty); + + let inner_ty = match ty.kind() { + ty::Adt(def, substs) => { + def.variant(VariantIdx::from_u32(0)).fields[i].ty(tcx, substs) + } + ty::Tuple(inner_tys) => inner_tys[i], + _ => bug!("unexpected unsized type {:?}", ty), + }; + + let inner_layout = + tcx.layout_of(ty::ParamEnv::empty().and(inner_ty)).unwrap(); + debug!(?inner_layout); + + let offset = place_adjusted.layout.fields.offset(i); + place + .offset( + offset, + MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)), + inner_layout, + &tcx, + ) + .unwrap() } - _ => bug!(), + _ => ecx.mplace_field(&place_adjusted, i).unwrap(), }; - debug!(?place_inner); + debug!(?place_inner); fill_place_recursively(ecx, &mut place_inner, *inner_valtree); dump_place(&ecx, place_inner.into()); } @@ -453,12 +447,7 @@ fn fill_place_recursively<'tcx>( ecx.write_discriminant(variant_idx, &(*place).into()).unwrap(); } - // add meta information for unsized type - if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) { - place.meta = - MemPlaceMeta::Meta(Scalar::from_u64(unsized_meta_info.unwrap() as u64)); - } - + debug!("dump of place after writing discriminant:"); dump_place(ecx, (*place).into()); } _ => bug!("shouldn't have created a ValTree for {:?}", ty), diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e7cc8b3427051..918fe49e8e3fc 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -220,7 +220,7 @@ impl<'tcx> TyCtxt<'tcx> { self, mut ty: Ty<'tcx>, mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, - // This is a hack that is currently used to allow us to walk a ValTree + // This is currently used to allow us to walk a ValTree // in lockstep with the type in order to get the ValTree branch that // corresponds to an unsized field. mut f: impl FnMut() -> (),