@@ -12,8 +12,8 @@ use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMo
1212use rustc_target:: spec:: abi:: Abi ;
1313
1414use super :: {
15- FnVal , ImmTy , InterpCx , InterpResult , MPlaceTy , Machine , OpTy , PlaceTy , Scalar ,
16- StackPopCleanup , StackPopUnwind ,
15+ FnVal , ImmTy , Immediate , InterpCx , InterpResult , MPlaceTy , Machine , MemoryKind , OpTy , Operand ,
16+ PlaceTy , Scalar , StackPopCleanup , StackPopUnwind ,
1717} ;
1818
1919impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
@@ -185,11 +185,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
185185 // No question
186186 return true ;
187187 }
188+ if caller_abi. layout . is_unsized ( ) || callee_abi. layout . is_unsized ( ) {
189+ // No, no, no. We require the types to *exactly* match for unsized arguments. If
190+ // these are somehow unsized "in a different way" (say, `dyn Trait` vs `[i32]`),
191+ // then who knows what happens.
192+ return false ;
193+ }
188194 if caller_abi. layout . size != callee_abi. layout . size
189195 || caller_abi. layout . align . abi != callee_abi. layout . align . abi
190196 {
191197 // This cannot go well...
192- // FIXME: What about unsized types?
193198 return false ;
194199 }
195200 // The rest *should* be okay, but we are extra conservative.
@@ -287,6 +292,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
287292 caller_arg. layout. ty
288293 )
289294 }
295+ // Special handling for unsized parameters.
296+ if caller_arg. layout . is_unsized ( ) {
297+ // `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way.
298+ assert_eq ! ( caller_arg. layout. ty, callee_arg. layout. ty) ;
299+ // We have to properly pre-allocate the memory for the callee.
300+ // So let's tear down some wrappers.
301+ // This all has to be in memory, there are no immediate unsized values.
302+ let src = caller_arg. assert_mem_place ( ) ;
303+ // The destination cannot be one of these "spread args".
304+ let ( dest_frame, dest_local) = callee_arg. assert_local ( ) ;
305+ // We are just initializing things, so there can't be anything here yet.
306+ assert ! ( matches!(
307+ * self . local_to_op( & self . stack( ) [ dest_frame] , dest_local, None ) ?,
308+ Operand :: Immediate ( Immediate :: Uninit )
309+ ) ) ;
310+ // Allocate enough memory to hold `src`.
311+ let Some ( ( size, align) ) = self . size_and_align_of_mplace ( & src) ? else {
312+ span_bug ! ( self . cur_span( ) , "unsized fn arg with `extern` type tail should not be allowed" )
313+ } ;
314+ let ptr = self . allocate_ptr ( size, align, MemoryKind :: Stack ) ?;
315+ let dest_place =
316+ MPlaceTy :: from_aligned_ptr_with_meta ( ptr. into ( ) , callee_arg. layout , src. meta ) ;
317+ // Update the local to be that new place.
318+ * M :: access_local_mut ( self , dest_frame, dest_local) ? = Operand :: Indirect ( * dest_place) ;
319+ }
290320 // We allow some transmutes here.
291321 // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This
292322 // is true for all `copy_op`, but there are a lot of special cases for argument passing
0 commit comments