Skip to content

Commit f87e91d

Browse files
committed
unify passing of sized and unsized function arguments :-)
1 parent 7cdeff2 commit f87e91d

File tree

2 files changed

+35
-31
lines changed

2 files changed

+35
-31
lines changed

compiler/rustc_const_eval/src/interpret/eval_context.rs

+26-6
Original file line numberDiff line numberDiff line change
@@ -912,15 +912,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
912912
Ok(())
913913
}
914914

915-
/// Mark a storage as live, killing the previous content.
916-
pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
915+
pub fn storage_live_dyn(
916+
&mut self,
917+
local: mir::Local,
918+
meta: MemPlaceMeta<M::Provenance>,
919+
) -> InterpResult<'tcx> {
917920
trace!("{:?} is now live", local);
918921

919-
if self.layout_of_local(self.frame(), local, None)?.is_unsized() {
920-
throw_unsup!(UnsizedLocal);
921-
}
922+
let layout = self.layout_of_local(self.frame(), local, None)?;
923+
let local_val = LocalValue::Live(if layout.is_sized() {
924+
assert!(matches!(meta, MemPlaceMeta::None)); // we're dropping the metadata
925+
// Just make this an efficient immediate.
926+
Operand::Immediate(Immediate::Uninit)
927+
} else {
928+
// Need to allocate some memory.
929+
let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
930+
Operand::Indirect(*dest_place)
931+
});
922932

923-
let local_val = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
924933
// StorageLive expects the local to be dead, and marks it live.
925934
let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
926935
if !matches!(old, LocalValue::Dead) {
@@ -929,6 +938,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
929938
Ok(())
930939
}
931940

941+
/// Mark a storage as live, killing the previous content.
942+
pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
943+
trace!("{:?} is now live", local);
944+
945+
if self.layout_of_local(self.frame(), local, None)?.is_unsized() {
946+
throw_unsup!(UnsizedLocal);
947+
}
948+
949+
self.storage_live_dyn(local, MemPlaceMeta::None)
950+
}
951+
932952
pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
933953
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
934954
trace!("{:?} is now dead", local);

compiler/rustc_const_eval/src/interpret/terminator.rs

+9-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::borrow::Cow;
2-
use std::mem;
32

43
use either::Either;
54
use rustc_ast::ast::InlineAsmOptions;
@@ -15,8 +14,8 @@ use rustc_target::abi::{self, FieldIdx};
1514
use rustc_target::spec::abi::Abi;
1615

1716
use super::{
18-
AllocId, FnVal, ImmTy, InterpCx, InterpResult, LocalValue, MPlaceTy, Machine, MemoryKind, OpTy,
19-
Operand, PlaceTy, Provenance, Scalar, StackPopCleanup,
17+
AllocId, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable,
18+
Provenance, Scalar, StackPopCleanup,
2019
};
2120
use crate::fluent_generated as fluent;
2221

@@ -394,28 +393,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
394393
// did in-place of by-copy argument passing, except for pointer equality tests.
395394
let caller_arg_copy = self.copy_fn_arg(&caller_arg)?;
396395
if !already_live {
397-
// Special handling for unsized parameters: they are harder to make live.
398-
if caller_arg_copy.layout.is_unsized() {
399-
// `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way.
400-
assert_eq!(caller_arg_copy.layout.ty, callee_ty);
401-
// We have to properly pre-allocate the memory for the callee.
402-
// So let's tear down some abstractions.
403-
// This all has to be in memory, there are no immediate unsized values.
404-
let src = caller_arg_copy.assert_mem_place();
405-
// The destination cannot be one of these "spread args".
406-
let dest_local = callee_arg.as_local().expect("unsized arguments cannot be spread");
407-
// Allocate enough memory to hold `src`.
408-
let dest_place = self.allocate_dyn(src.layout, MemoryKind::Stack, src.meta)?;
409-
// Update the local to be that new place. This is essentially a "dyn-sized StorageLive".
410-
let old = mem::replace(
411-
&mut self.frame_mut().locals[dest_local].value,
412-
LocalValue::Live(Operand::Indirect(*dest_place)),
413-
);
414-
assert!(matches!(old, LocalValue::Dead));
415-
} else {
416-
// Just make the local live.
417-
self.storage_live(callee_arg.as_local().unwrap())?;
418-
}
396+
let local = callee_arg.as_local().unwrap();
397+
let meta = caller_arg_copy.meta();
398+
// `check_argument_compat` ensures that if metadata is needed, both have the same type,
399+
// so we know they will use the metadata the same way.
400+
assert!(!meta.has_meta() || caller_arg_copy.layout.ty == callee_ty);
401+
402+
self.storage_live_dyn(local, meta)?;
419403
}
420404
// Now we can finally actually evaluate the callee place.
421405
let callee_arg = self.eval_place(*callee_arg)?;

0 commit comments

Comments
 (0)