diff options
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/eval_context.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/terminator.rs | 34 |
2 files changed, 35 insertions, 31 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 58674a1eec5..babc5790f9e 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -912,15 +912,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - /// Mark a storage as live, killing the previous content. - pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> { + pub fn storage_live_dyn( + &mut self, + local: mir::Local, + meta: MemPlaceMeta<M::Provenance>, + ) -> InterpResult<'tcx> { trace!("{:?} is now live", local); - if self.layout_of_local(self.frame(), local, None)?.is_unsized() { - throw_unsup!(UnsizedLocal); - } + let layout = self.layout_of_local(self.frame(), local, None)?; + let local_val = LocalValue::Live(if layout.is_sized() { + assert!(matches!(meta, MemPlaceMeta::None)); // we're dropping the metadata + // Just make this an efficient immediate. + Operand::Immediate(Immediate::Uninit) + } else { + // Need to allocate some memory. + let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?; + Operand::Indirect(*dest_place) + }); - let local_val = LocalValue::Live(Operand::Immediate(Immediate::Uninit)); // StorageLive expects the local to be dead, and marks it live. let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); if !matches!(old, LocalValue::Dead) { @@ -929,6 +938,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } + /// Mark a storage as live, killing the previous content. + pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> { + trace!("{:?} is now live", local); + + if self.layout_of_local(self.frame(), local, None)?.is_unsized() { + throw_unsup!(UnsizedLocal); + } + + self.storage_live_dyn(local, MemPlaceMeta::None) + } + pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> { assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); trace!("{:?} is now dead", local); diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index fd65758b064..279a06d3868 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::mem; use either::Either; use rustc_ast::ast::InlineAsmOptions; @@ -15,8 +14,8 @@ use rustc_target::abi::{self, FieldIdx}; use rustc_target::spec::abi::Abi; use super::{ - AllocId, FnVal, ImmTy, InterpCx, InterpResult, LocalValue, MPlaceTy, Machine, MemoryKind, OpTy, - Operand, PlaceTy, Provenance, Scalar, StackPopCleanup, + AllocId, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, + Provenance, Scalar, StackPopCleanup, }; use crate::fluent_generated as fluent; @@ -394,28 +393,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // did in-place of by-copy argument passing, except for pointer equality tests. let caller_arg_copy = self.copy_fn_arg(&caller_arg)?; if !already_live { - // Special handling for unsized parameters: they are harder to make live. - if caller_arg_copy.layout.is_unsized() { - // `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way. - assert_eq!(caller_arg_copy.layout.ty, callee_ty); - // We have to properly pre-allocate the memory for the callee. - // So let's tear down some abstractions. - // This all has to be in memory, there are no immediate unsized values. - let src = caller_arg_copy.assert_mem_place(); - // The destination cannot be one of these "spread args". - let dest_local = callee_arg.as_local().expect("unsized arguments cannot be spread"); - // Allocate enough memory to hold `src`. - let dest_place = self.allocate_dyn(src.layout, MemoryKind::Stack, src.meta)?; - // Update the local to be that new place. This is essentially a "dyn-sized StorageLive". - let old = mem::replace( - &mut self.frame_mut().locals[dest_local].value, - LocalValue::Live(Operand::Indirect(*dest_place)), - ); - assert!(matches!(old, LocalValue::Dead)); - } else { - // Just make the local live. - self.storage_live(callee_arg.as_local().unwrap())?; - } + let local = callee_arg.as_local().unwrap(); + let meta = caller_arg_copy.meta(); + // `check_argument_compat` ensures that if metadata is needed, both have the same type, + // so we know they will use the metadata the same way. + assert!(!meta.has_meta() || caller_arg_copy.layout.ty == callee_ty); + + self.storage_live_dyn(local, meta)?; } // Now we can finally actually evaluate the callee place. let callee_arg = self.eval_place(*callee_arg)?; |
