@@ -327,6 +327,74 @@ fn adjust_for_rust_scalar<'tcx>(
327327 }
328328}
329329
330+ /// Ensure that the ABI makes basic sense.
331+ fn fn_abi_sanity_check < ' tcx > ( cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > , fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ) {
332+ fn fn_arg_sanity_check < ' tcx > (
333+ cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
334+ fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
335+ arg : & ArgAbi < ' tcx , Ty < ' tcx > > ,
336+ ) {
337+ match & arg. mode {
338+ PassMode :: Ignore => { }
339+ PassMode :: Direct ( _) => {
340+ // Here the Rust type is used to determine the actual ABI, so we have to be very
341+ // careful. Scalar/ScalarPair is fine, since backends will generally use
342+ // `layout.abi` and ignore everything else. We should just reject `Aggregate`
343+ // entirely here, but some targets need to be fixed first.
344+ if matches ! ( arg. layout. abi, Abi :: Aggregate { .. } ) {
345+ assert ! (
346+ arg. layout. is_sized( ) ,
347+ "`PassMode::Direct` for unsized type in ABI: {:#?}" ,
348+ fn_abi
349+ ) ;
350+ // This really shouldn't happen, since `immediate_llvm_type` will use
351+ // `layout.fields` to turn this Rust type into an LLVM type. This means all
352+ // sorts of Rust type details leak into the ABI. However wasm sadly *does*
353+ // currently use this mode so we have to allow it -- but we absolutely
354+ // shouldn't let any more targets do that.
355+ // (Also see <https://github.com/rust-lang/rust/issues/115666>.)
356+ //
357+ // The unstable abi `PtxKernel` also uses Direct for now.
358+ // It needs to switch to something else before stabilization can happen.
359+ // (See issue: https://github.com/rust-lang/rust/issues/117271)
360+ assert ! (
361+ matches!( & * cx. tcx. sess. target. arch, "wasm32" | "wasm64" )
362+ || fn_abi. conv == Conv :: PtxKernel ,
363+ "`PassMode::Direct` for aggregates only allowed on wasm and `extern \" ptx-kernel\" ` fns\n Problematic type: {:#?}" ,
364+ arg. layout,
365+ ) ;
366+ }
367+ }
368+ PassMode :: Pair ( _, _) => {
369+ // Similar to `Direct`, we need to make sure that backends use `layout.abi` and
370+ // ignore the rest of the layout.
371+ assert ! (
372+ matches!( arg. layout. abi, Abi :: ScalarPair ( ..) ) ,
373+ "PassMode::Pair for type {}" ,
374+ arg. layout. ty
375+ ) ;
376+ }
377+ PassMode :: Cast { .. } => {
378+ // `Cast` means "transmute to `CastType`"; that only makes sense for sized types.
379+ assert ! ( arg. layout. is_sized( ) ) ;
380+ }
381+ PassMode :: Indirect { meta_attrs : None , .. } => {
382+ // No metadata, must be sized.
383+ assert ! ( arg. layout. is_sized( ) ) ;
384+ }
385+ PassMode :: Indirect { meta_attrs : Some ( _) , on_stack, .. } => {
386+ // With metadata. Must be unsized and not on the stack.
387+ assert ! ( arg. layout. is_unsized( ) && !on_stack) ;
388+ }
389+ }
390+ }
391+
392+ for arg in fn_abi. args . iter ( ) {
393+ fn_arg_sanity_check ( cx, fn_abi, arg) ;
394+ }
395+ fn_arg_sanity_check ( cx, fn_abi, & fn_abi. ret ) ;
396+ }
397+
330398// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
331399// arguments of this method, into a separate `struct`.
332400#[ tracing:: instrument( level = "debug" , skip( cx, caller_location, fn_def_id, force_thin_self_ptr) ) ]
@@ -453,6 +521,7 @@ fn fn_abi_new_uncached<'tcx>(
453521 } ;
454522 fn_abi_adjust_for_abi ( cx, & mut fn_abi, sig. abi , fn_def_id) ?;
455523 debug ! ( "fn_abi_new_uncached = {:?}" , fn_abi) ;
524+ fn_abi_sanity_check ( cx, & fn_abi) ;
456525 Ok ( cx. tcx . arena . alloc ( fn_abi) )
457526}
458527
0 commit comments