@@ -6,7 +6,7 @@ use std::sync::atomic::AtomicBool;
66use libffi:: low:: CodePtr ;
77use libffi:: middle:: Type as FfiType ;
88use rustc_abi:: { HasDataLayout , Size } ;
9- use rustc_middle:: ty:: layout:: HasTypingEnv ;
9+ use rustc_middle:: ty:: layout:: TyAndLayout ;
1010use rustc_middle:: ty:: { self , IntTy , Ty , UintTy } ;
1111use rustc_span:: Symbol ;
1212use serde:: { Deserialize , Serialize } ;
@@ -277,7 +277,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
277277
278278 // This should go first so that we emit unsupported before doing a bunch
279279 // of extra work for types that aren't supported yet.
280- let ty = this. ty_to_ffitype ( v. layout . ty ) ?;
280+ let ty = this. ty_to_ffitype ( v. layout ) ?;
281281
282282 // Helper to print a warning when a pointer is shared with the native code.
283283 let expose = |prov : Provenance | -> InterpResult < ' tcx > {
@@ -386,34 +386,44 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
386386 let this = self . eval_context_ref ( ) ;
387387 let mut fields = vec ! [ ] ;
388388 for field in & adt_def. non_enum_variant ( ) . fields {
389- fields. push ( this. ty_to_ffitype ( field. ty ( * this. tcx , args) ) ?) ;
389+ let layout = this. layout_of ( field. ty ( * this. tcx , args) ) ?;
390+ fields. push ( this. ty_to_ffitype ( layout) ?) ;
390391 }
391392
392393 interp_ok ( FfiType :: structure ( fields) )
393394 }
394395
395396 /// Gets the matching libffi type for a given Ty.
396- fn ty_to_ffitype ( & self , ty : Ty < ' tcx > ) -> InterpResult < ' tcx , FfiType > {
397- let this = self . eval_context_ref ( ) ;
398- interp_ok ( match ty. kind ( ) {
399- ty:: Int ( IntTy :: I8 ) => FfiType :: i8 ( ) ,
400- ty:: Int ( IntTy :: I16 ) => FfiType :: i16 ( ) ,
401- ty:: Int ( IntTy :: I32 ) => FfiType :: i32 ( ) ,
402- ty:: Int ( IntTy :: I64 ) => FfiType :: i64 ( ) ,
403- ty:: Int ( IntTy :: Isize ) => FfiType :: isize ( ) ,
404- ty:: Uint ( UintTy :: U8 ) => FfiType :: u8 ( ) ,
405- ty:: Uint ( UintTy :: U16 ) => FfiType :: u16 ( ) ,
406- ty:: Uint ( UintTy :: U32 ) => FfiType :: u32 ( ) ,
407- ty:: Uint ( UintTy :: U64 ) => FfiType :: u64 ( ) ,
408- ty:: Uint ( UintTy :: Usize ) => FfiType :: usize ( ) ,
409- ty:: RawPtr ( pointee_ty, _mut) => {
410- if !pointee_ty. is_sized ( * this. tcx , this. typing_env ( ) ) {
411- throw_unsup_format ! ( "passing a pointer to an unsized type over FFI: {}" , ty) ;
412- }
413- FfiType :: pointer ( )
414- }
415- ty:: Adt ( adt_def, args) => self . adt_to_ffitype ( ty, * adt_def, args) ?,
416- _ => throw_unsup_format ! ( "unsupported argument type for native call: {}" , ty) ,
397+ fn ty_to_ffitype ( & self , layout : TyAndLayout < ' tcx > ) -> InterpResult < ' tcx , FfiType > {
398+ use rustc_abi:: { AddressSpace , BackendRepr , Integer , Primitive } ;
399+
400+ // `BackendRepr::Scalar` is also a signal to pass this type as a scalar in the ABI. This
401+ // matches what codegen does. This does mean that we support some types whose ABI is not
402+ // stable, but that's fine -- we anyway can't check that the callee has the intended ABI.
403+ if let BackendRepr :: Scalar ( s) = layout. backend_repr {
404+ // Simple sanity-check: this cannot be `repr(C)`.
405+ assert ! ( !layout. ty. ty_adt_def( ) . is_some_and( |adt| adt. repr( ) . c( ) ) ) ;
406+ return interp_ok ( match s. primitive ( ) {
407+ Primitive :: Int ( Integer :: I8 , /* signed */ true ) => FfiType :: i8 ( ) ,
408+ Primitive :: Int ( Integer :: I16 , /* signed */ true ) => FfiType :: i16 ( ) ,
409+ Primitive :: Int ( Integer :: I32 , /* signed */ true ) => FfiType :: i32 ( ) ,
410+ Primitive :: Int ( Integer :: I64 , /* signed */ true ) => FfiType :: i64 ( ) ,
411+ Primitive :: Int ( Integer :: I8 , /* signed */ false ) => FfiType :: u8 ( ) ,
412+ Primitive :: Int ( Integer :: I16 , /* signed */ false ) => FfiType :: u16 ( ) ,
413+ Primitive :: Int ( Integer :: I32 , /* signed */ false ) => FfiType :: u32 ( ) ,
414+ Primitive :: Int ( Integer :: I64 , /* signed */ false ) => FfiType :: u64 ( ) ,
415+ Primitive :: Pointer ( AddressSpace :: ZERO ) => FfiType :: pointer ( ) ,
416+ _ =>
417+ throw_unsup_format ! (
418+ "unsupported scalar argument type for native call: {}" ,
419+ layout. ty
420+ ) ,
421+ } ) ;
422+ }
423+ interp_ok ( match layout. ty . kind ( ) {
424+ // Scalar types have already been handled above.
425+ ty:: Adt ( adt_def, args) => self . adt_to_ffitype ( layout. ty , * adt_def, args) ?,
426+ _ => throw_unsup_format ! ( "unsupported argument type for native call: {}" , layout. ty) ,
417427 } )
418428 }
419429}
0 commit comments