@@ -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 are anyway quite conservative in native-lib mode. 
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} 
@@ -454,6 +464,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
454464        // pointer was passed as argument). Uninitialised memory is left as-is, but any data 
455465        // exposed this way is garbage anyway. 
456466        this. visit_reachable_allocs ( this. exposed_allocs ( ) ,  |this,  alloc_id,  info| { 
467+             if  matches ! ( info. kind,  AllocKind :: Function )  { 
468+                 static  DEDUP :  AtomicBool  = AtomicBool :: new ( false ) ; 
469+                 if  !DEDUP . swap ( true ,  std:: sync:: atomic:: Ordering :: Relaxed )  { 
470+                     // Newly set, so first time we get here. 
471+                     this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallFnPtr ) ; 
472+                 } 
473+             } 
457474            // If there is no data behind this pointer, skip this. 
458475            if  !matches ! ( info. kind,  AllocKind :: LiveData )  { 
459476                return  interp_ok ( ( ) ) ; 
0 commit comments