@@ -12,8 +12,8 @@ use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMo
12
12
use rustc_target:: spec:: abi:: Abi ;
13
13
14
14
use 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 ,
17
17
} ;
18
18
19
19
impl < ' 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> {
185
185
// No question
186
186
return true ;
187
187
}
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
+ }
188
194
if caller_abi. layout . size != callee_abi. layout . size
189
195
|| caller_abi. layout . align . abi != callee_abi. layout . align . abi
190
196
{
191
197
// This cannot go well...
192
- // FIXME: What about unsized types?
193
198
return false ;
194
199
}
195
200
// 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> {
287
292
caller_arg. layout. ty
288
293
)
289
294
}
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
+ }
290
320
// We allow some transmutes here.
291
321
// FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This
292
322
// is true for all `copy_op`, but there are a lot of special cases for argument passing
0 commit comments