From d1b2d29528b7794b41e66fc2136e395a02f8529b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:59:35 +0200 Subject: Merging upstream version 1.73.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_const_eval/src/const_eval/error.rs | 9 +- .../src/const_eval/eval_queries.rs | 18 +- .../rustc_const_eval/src/const_eval/fn_queries.rs | 15 +- .../rustc_const_eval/src/const_eval/machine.rs | 71 ++++---- compiler/rustc_const_eval/src/const_eval/mod.rs | 10 +- .../rustc_const_eval/src/const_eval/valtrees.rs | 202 ++++++--------------- 6 files changed, 119 insertions(+), 206 deletions(-) (limited to 'compiler/rustc_const_eval/src/const_eval') diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 7890d878d..d39a7e8a1 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -138,7 +138,10 @@ where err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { ErrorHandled::TooGeneric } - err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(error_reported), + err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar), + err_inval!(Layout(LayoutError::ReferencesError(guar))) => { + ErrorHandled::Reported(guar.into()) + } err_inval!(Layout(layout_error @ LayoutError::SizeOverflow(_))) => { // We must *always* hard error on these, even if the caller wants just a lint. // The `message` makes little sense here, this is a more serious error than the @@ -150,8 +153,8 @@ where tcx.sess.create_err(Spanned { span, node: layout_error.into_diagnostic() }); err.code(rustc_errors::error_code!(E0080)); let Some((mut err, handler)) = err.into_diagnostic() else { - panic!("did not emit diag"); - }; + panic!("did not emit diag"); + }; for frame in frames { err.eager_subdiagnostic(handler, frame); } 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 417ab78fd..4c7e91944 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -45,20 +45,20 @@ fn eval_body_using_ecx<'mir, 'tcx>( "Unexpected DefKind: {:?}", ecx.tcx.def_kind(cid.instance.def_id()) ); - let layout = ecx.layout_of(body.bound_return_ty().subst(tcx, cid.instance.substs))?; + let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?; assert!(layout.is_sized()); let ret = ecx.allocate(layout, MemoryKind::Stack)?; trace!( "eval_body_using_ecx: pushing stack frame for global: {}{}", with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())), - cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p)) + cid.promoted.map_or_else(String::new, |p| format!("::promoted[{p:?}]")) ); ecx.push_stack_frame( cid.instance, body, - &ret.into(), + &ret.clone().into(), StackPopCleanup::Root { cleanup: false }, )?; @@ -228,7 +228,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - assert!(key.param_env.is_const()); // see comment in eval_to_allocation_raw_provider for what we're doing here if key.param_env.reveal() == Reveal::All { let mut key = key; @@ -245,10 +244,10 @@ pub fn eval_to_const_value_raw_provider<'tcx>( // Catch such calls and evaluate them instead of trying to load a constant's MIR. if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { let ty = key.value.instance.ty(tcx, key.param_env); - let ty::FnDef(_, substs) = ty.kind() else { + let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { + return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).map_err(|error| { let span = tcx.def_span(def_id); super::report( @@ -269,7 +268,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - assert!(key.param_env.is_const()); // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was @@ -328,10 +326,10 @@ pub fn eval_to_allocation_raw_provider<'tcx>( ("static", String::new()) } else { // If the current item has generics, we'd like to enrich the message with the - // instance and its substs: to show the actual compile-time values, in addition to + // instance and its args: to show the actual compile-time values, in addition to // the expression, leading to the const eval error. let instance = &key.value.instance; - if !instance.substs.is_empty() { + if !instance.args.is_empty() { let instance = with_no_trimmed_paths!(instance.to_string()); ("const_with_path", instance) } else { @@ -356,7 +354,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // Since evaluation had no errors, validate the resulting constant. // This is a separate `try` block to provide more targeted error reporting. let validation: Result<_, InterpErrorInfo<'_>> = try { - let mut ref_tracking = RefTracking::new(mplace); + let mut ref_tracking = RefTracking::new(mplace.clone()); let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { let mode = match tcx.static_mutability(cid.instance.def_id()) { diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index fa8253d5e..4ee4ebbb9 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -28,16 +28,19 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { && tcx.constness(parent_id) == hir::Constness::Const } -/// Checks whether an item is considered to be `const`. If it is a constructor, it is const. If -/// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic, -/// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return -/// `Constness::NotConst`. +/// Checks whether an item is considered to be `const`. If it is a constructor, anonymous const, +/// const block, const item or associated const, it is const. If it is a trait impl/function, +/// return if it has a `const` modifier. If it is an intrinsic, report whether said intrinsic +/// has a `rustc_const_{un,}stable` attribute. Otherwise, return `Constness::NotConst`. fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { let node = tcx.hir().get_by_def_id(def_id); match node { - hir::Node::Ctor(_) => hir::Constness::Const, - hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, + hir::Node::Ctor(_) + | hir::Node::AnonConst(_) + | hir::Node::ConstBlock(_) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const, + hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx.generics_of(def_id).host_effect_index.map_or(hir::Constness::NotConst, |_| hir::Constness::Const), hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index f9f645af4..b740b79d1 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::errors::{LongRunning, LongRunningWarn}; use crate::interpret::{ - self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx, + self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, Scalar, }; use crate::{errors, fluent_generated as fluent}; @@ -201,7 +201,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { fn hook_special_const_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], + args: &[FnArg<'tcx>], dest: &PlaceTy<'tcx>, ret: Option, ) -> InterpResult<'tcx, Option>> { @@ -210,12 +210,13 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { if Some(def_id) == self.tcx.lang_items().panic_display() || Some(def_id) == self.tcx.lang_items().begin_panic_fn() { + let args = self.copy_fn_args(args)?; // &str or &&str assert!(args.len() == 1); - let mut msg_place = self.deref_operand(&args[0])?; + let mut msg_place = self.deref_pointer(&args[0])?; while msg_place.layout.ty.is_ref() { - msg_place = self.deref_operand(&msg_place.into())?; + msg_place = self.deref_pointer(&msg_place)?; } let msg = Symbol::intern(self.read_str(&msg_place)?); @@ -229,15 +230,16 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { *self.tcx, ty::ParamEnv::reveal_all(), const_def_id, - instance.substs, + instance.args, ) .unwrap() .unwrap(); return Ok(Some(new_instance)); } else if Some(def_id) == self.tcx.lang_items().align_offset_fn() { + let args = self.copy_fn_args(args)?; // For align_offset, we replace the function call if the pointer has no address. - match self.align_offset(instance, args, dest, ret)? { + match self.align_offset(instance, &args, dest, ret)? { ControlFlow::Continue(()) => return Ok(Some(instance)), ControlFlow::Break(()) => return Ok(None), } @@ -293,7 +295,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { self.eval_fn_call( FnVal::Instance(instance), (CallAbi::Rust, fn_abi), - &[addr, align], + &[FnArg::Copy(addr), FnArg::Copy(align)], /* with_caller_location = */ false, dest, ret, @@ -425,52 +427,41 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, + orig_instance: ty::Instance<'tcx>, _abi: CallAbi, - args: &[OpTy<'tcx>], + args: &[FnArg<'tcx>], dest: &PlaceTy<'tcx>, ret: Option, _unwind: mir::UnwindAction, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - debug!("find_mir_or_eval_fn: {:?}", instance); + debug!("find_mir_or_eval_fn: {:?}", orig_instance); + + // Replace some functions. + let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else { + // Call has already been handled. + return Ok(None); + }; // Only check non-glue functions if let ty::InstanceDef::Item(def) = instance.def { // Execution might have wandered off into other crates, so we cannot do a stability- - // sensitive check here. But we can at least rule out functions that are not const - // at all. - if !ecx.tcx.is_const_fn_raw(def) { - // allow calling functions inside a trait marked with #[const_trait]. - if !ecx.tcx.is_const_default_method(def) { - // We certainly do *not* want to actually call the fn - // though, so be sure we return here. - throw_unsup_format!("calling non-const function `{}`", instance) - } - } - - let Some(new_instance) = ecx.hook_special_const_fn(instance, args, dest, ret)? else { - return Ok(None); - }; - - if new_instance != instance { - // We call another const fn instead. - // However, we return the *original* instance to make backtraces work out - // (and we hope this does not confuse the FnAbi checks too much). - return Ok(Self::find_mir_or_eval_fn( - ecx, - new_instance, - _abi, - args, - dest, - ret, - _unwind, - )? - .map(|(body, _instance)| (body, instance))); + // sensitive check here. But we can at least rule out functions that are not const at + // all. That said, we have to allow calling functions inside a trait marked with + // #[const_trait]. These *are* const-checked! + // FIXME: why does `is_const_fn_raw` not classify them as const? + if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def)) + || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) + { + // We certainly do *not* want to actually call the fn + // though, so be sure we return here. + throw_unsup_format!("calling non-const function `{}`", instance) } } // This is a const fn. Call it. - Ok(Some((ecx.load_mir(instance.def, None)?, instance))) + // In case of replacement, we return the *original* instance to make backtraces work out + // (and we hope this does not confuse the FnAbi checks too much). + Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) } fn call_intrinsic( diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index a3064b53d..854104622 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -85,7 +85,7 @@ pub(crate) fn eval_to_valtree<'tcx>( } #[instrument(skip(tcx), level = "debug")] -pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>( +pub fn try_destructure_mir_constant_for_diagnostics<'tcx>( tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>, @@ -101,17 +101,17 @@ pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>( return None; } ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).ok()?.1; - let down = ecx.operand_downcast(&op, variant).ok()?; + let variant = ecx.read_discriminant(&op).ok()?; + let down = ecx.project_downcast(&op, variant).ok()?; (def.variants()[variant].fields.len(), Some(variant), down) } - ty::Tuple(substs) => (substs.len(), None, op), + ty::Tuple(args) => (args.len(), None, op), _ => bug!("cannot destructure mir constant {:?}", val), }; let fields_iter = (0..field_count) .map(|i| { - let field_op = ecx.operand_field(&down, i).ok()?; + let field_op = ecx.project_field(&down, i).ok()?; let val = op_to_const(&ecx, &field_op); Some((val, field_op.layout.ty)) }) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index e574df276..b15a65d67 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -2,14 +2,15 @@ use super::eval_queries::{mk_eval_cx, op_to_const}; use super::machine::CompileTimeEvalContext; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::const_eval::CanAccessStatics; +use crate::interpret::MPlaceTy; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, - MemoryKind, PlaceTy, Scalar, + MemoryKind, Place, Projectable, Scalar, }; -use crate::interpret::{MPlaceTy, Value}; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_span::source_map::DUMMY_SP; -use rustc_target::abi::{Align, FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::VariantIdx; #[instrument(skip(ecx), level = "debug")] fn branches<'tcx>( @@ -20,15 +21,15 @@ fn branches<'tcx>( num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { let place = match variant { - Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), - None => *place, + Some(variant) => ecx.project_downcast(place, variant).unwrap(), + None => place.clone(), }; let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32())))); debug!(?place, ?variant); let mut fields = Vec::with_capacity(n); for i in 0..n { - let field = ecx.mplace_field(&place, i).unwrap(); + let field = ecx.project_field(&place, i).unwrap(); let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; fields.push(Some(valtree)); } @@ -55,13 +56,11 @@ fn slice_branches<'tcx>( place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { - let n = place - .len(&ecx.tcx.tcx) - .unwrap_or_else(|_| panic!("expected to use len of place {:?}", place)); + let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {place:?}")); let mut elems = Vec::with_capacity(n as usize); for i in 0..n { - let place_elem = ecx.mplace_index(place, i).unwrap(); + let place_elem = ecx.project_index(place, i).unwrap(); let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?; elems.push(valtree); } @@ -88,7 +87,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( Ok(ty::ValTree::zst()) } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let Ok(val) = ecx.read_immediate(&place.into()) else { + let Ok(val) = ecx.read_immediate(place) else { return Err(ValTreeCreationError::Other); }; let val = val.to_scalar(); @@ -104,7 +103,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType), ty::Ref(_, _, _) => { - let Ok(derefd_place)= ecx.deref_operand(&place.into()) else { + let Ok(derefd_place)= ecx.deref_pointer(place) else { return Err(ValTreeCreationError::Other); }; debug!(?derefd_place); @@ -132,7 +131,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( bug!("uninhabited types should have errored and never gotten converted to valtree") } - let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else { + let Ok(variant) = ecx.read_discriminant(place) else { return Err(ValTreeCreationError::Other); }; branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) @@ -156,52 +155,37 @@ pub(crate) fn const_to_valtree_inner<'tcx>( } } -#[instrument(skip(ecx), level = "debug")] -fn create_mplace_from_layout<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, - ty: Ty<'tcx>, -) -> MPlaceTy<'tcx> { - let tcx = ecx.tcx; - let param_env = ecx.param_env; - let layout = tcx.layout_of(param_env.and(ty)).unwrap(); - debug!(?layout); - - ecx.allocate(layout, MemoryKind::Stack).unwrap() -} - -// Walks custom DSTs and gets the type of the unsized field and the number of elements -// in the unsized field. -fn get_info_on_unsized_field<'tcx>( - ty: Ty<'tcx>, +/// Valtrees don't store the `MemPlaceMeta` that all dynamically sized values have in the interpreter. +/// This function reconstructs it. +fn reconstruct_place_meta<'tcx>( + layout: TyAndLayout<'tcx>, valtree: ty::ValTree<'tcx>, tcx: TyCtxt<'tcx>, -) -> (Ty<'tcx>, usize) { +) -> MemPlaceMeta { + if layout.is_sized() { + return MemPlaceMeta::None; + } + let mut last_valtree = valtree; + // Traverse the type, and update `last_valtree` as we go. let tail = tcx.struct_tail_with_normalize( - ty, + layout.ty, |ty| ty, || { let branches = last_valtree.unwrap_branch(); - last_valtree = branches[branches.len() - 1]; + last_valtree = *branches.last().unwrap(); debug!(?branches, ?last_valtree); }, ); - let unsized_inner_ty = match tail.kind() { - ty::Slice(t) => *t, - ty::Str => tail, - _ => bug!("expected Slice or Str"), - }; - - // Have to adjust type for ty::Str - let unsized_inner_ty = match unsized_inner_ty.kind() { - ty::Str => tcx.types.u8, - _ => unsized_inner_ty, + // Sanity-check that we got a tail we support. + match tail.kind() { + ty::Slice(..) | ty::Str => {} + _ => bug!("unsized tail of a valtree must be Slice or Str"), }; - // Get the number of elements in the unsized field + // Get the number of elements in the unsized field. let num_elems = last_valtree.unwrap_branch().len(); - - (unsized_inner_ty, num_elems) + MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)) } #[instrument(skip(ecx), level = "debug", ret)] @@ -210,41 +194,9 @@ fn create_pointee_place<'tcx>( ty: Ty<'tcx>, valtree: ty::ValTree<'tcx>, ) -> MPlaceTy<'tcx> { - let tcx = ecx.tcx.tcx; - - 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.types.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 size = size_of_sized_part.checked_add(dst_size, &tcx).unwrap(); - let align = Align::from_bytes(size.bytes().next_power_of_two()).unwrap(); - let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap(); - debug!(?ptr); - - MPlaceTy::from_aligned_ptr_with_meta( - ptr.into(), - layout, - MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)), - ) - } else { - create_mplace_from_layout(ecx, ty) - } + let layout = ecx.layout_of(ty).unwrap(); + let meta = reconstruct_place_meta(layout, valtree, ecx.tcx.tcx); + ecx.allocate_dyn(layout, MemoryKind::Stack, meta).unwrap() } /// Converts a `ValTree` to a `ConstValue`, which is needed after mir @@ -282,17 +234,20 @@ pub fn valtree_to_const_value<'tcx>( ), }, ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => { - let mut place = match ty.kind() { + let place = match ty.kind() { ty::Ref(_, inner_ty, _) => { - // Need to create a place for the pointee to fill for Refs + // Need to create a place for the pointee (the reference itself will be an immediate) create_pointee_place(&mut ecx, *inner_ty, valtree) } - _ => create_mplace_from_layout(&mut ecx, ty), + _ => { + // Need to create a place for this valtree. + create_pointee_place(&mut ecx, ty, valtree) + } }; debug!(?place); - valtree_into_mplace(&mut ecx, &mut place, valtree); - dump_place(&ecx, place.into()); + valtree_into_mplace(&mut ecx, &place, valtree); + dump_place(&ecx, &place); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap(); match ty.kind() { @@ -331,7 +286,7 @@ pub fn valtree_to_const_value<'tcx>( #[instrument(skip(ecx), level = "debug")] fn valtree_into_mplace<'tcx>( ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, - place: &mut MPlaceTy<'tcx>, + place: &MPlaceTy<'tcx>, valtree: ty::ValTree<'tcx>, ) { // This will match on valtree and write the value(s) corresponding to the ValTree @@ -347,14 +302,14 @@ fn valtree_into_mplace<'tcx>( ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { let scalar_int = valtree.unwrap_leaf(); debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place); - ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap(); + ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap(); } ty::Ref(_, inner_ty, _) => { - let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree); + let pointee_place = create_pointee_place(ecx, *inner_ty, valtree); debug!(?pointee_place); - valtree_into_mplace(ecx, &mut pointee_place, valtree); - dump_place(ecx, pointee_place.into()); + valtree_into_mplace(ecx, &pointee_place, valtree); + dump_place(ecx, &pointee_place); intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap(); let imm = match inner_ty.kind() { @@ -371,7 +326,7 @@ fn valtree_into_mplace<'tcx>( }; debug!(?imm); - ecx.write_immediate(imm, &place.into()).unwrap(); + ecx.write_immediate(imm, place).unwrap(); } ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => { let branches = valtree.unwrap_branch(); @@ -386,12 +341,12 @@ fn valtree_into_mplace<'tcx>( debug!(?variant); ( - place.project_downcast(ecx, variant_idx).unwrap(), + ecx.project_downcast(place, variant_idx).unwrap(), &branches[1..], Some(variant_idx), ) } - _ => (*place, branches, None), + _ => (place.clone(), branches, None), }; debug!(?place_adjusted, ?branches); @@ -400,70 +355,33 @@ fn valtree_into_mplace<'tcx>( for (i, inner_valtree) in branches.iter().enumerate() { debug!(?i, ?inner_valtree); - 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) => { - let i = FieldIdx::from_usize(i); - def.variant(FIRST_VARIANT).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_with_meta( - offset, - MemPlaceMeta::Meta(Scalar::from_target_usize( - num_elems as u64, - &tcx, - )), - inner_layout, - &tcx, - ) - .unwrap() + let place_inner = match ty.kind() { + ty::Str | ty::Slice(_) | ty::Array(..) => { + ecx.project_index(place, i as u64).unwrap() } - _ => ecx.mplace_field(&place_adjusted, i).unwrap(), + _ => ecx.project_field(&place_adjusted, i).unwrap(), }; debug!(?place_inner); - valtree_into_mplace(ecx, &mut place_inner, *inner_valtree); - dump_place(&ecx, place_inner.into()); + valtree_into_mplace(ecx, &place_inner, *inner_valtree); + dump_place(&ecx, &place_inner); } debug!("dump of place_adjusted:"); - dump_place(ecx, place_adjusted.into()); + dump_place(ecx, &place_adjusted); if let Some(variant_idx) = variant_idx { // don't forget filling the place with the discriminant of the enum - ecx.write_discriminant(variant_idx, &place.into()).unwrap(); + ecx.write_discriminant(variant_idx, place).unwrap(); } debug!("dump of place after writing discriminant:"); - dump_place(ecx, place.into()); + dump_place(ecx, place); } _ => bug!("shouldn't have created a ValTree for {:?}", ty), } } -fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: PlaceTy<'tcx>) { - trace!("{:?}", ecx.dump_place(*place)); +fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) { + trace!("{:?}", ecx.dump_place(Place::Ptr(**place))); } -- cgit v1.2.3