@@ -327,6 +327,76 @@ 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+ // For an unsized type we'd only pass the sized prefix, so there is no universe
346+ // in which we ever want to allow this.
347+ assert ! (
348+ arg. layout. is_sized( ) ,
349+ "`PassMode::Direct` for unsized type in ABI: {:#?}" ,
350+ fn_abi
351+ ) ;
352+ // This really shouldn't happen even for sized aggregates, since
353+ // `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an
354+ // LLVM type. This means all sorts of Rust type details leak into the ABI.
355+ // However wasm sadly *does* currently use this mode so we have to allow it --
356+ // but we absolutely shouldn't let any more targets do that.
357+ // (Also see <https://github.com/rust-lang/rust/issues/115666>.)
358+ //
359+ // The unstable abi `PtxKernel` also uses Direct for now.
360+ // It needs to switch to something else before stabilization can happen.
361+ // (See issue: https://github.com/rust-lang/rust/issues/117271)
362+ assert ! (
363+ matches!( & * cx. tcx. sess. target. arch, "wasm32" | "wasm64" )
364+ || fn_abi. conv == Conv :: PtxKernel ,
365+ "`PassMode::Direct` for aggregates only allowed on wasm and `extern \" ptx-kernel\" ` fns\n Problematic type: {:#?}" ,
366+ arg. layout,
367+ ) ;
368+ }
369+ }
370+ PassMode :: Pair ( _, _) => {
371+ // Similar to `Direct`, we need to make sure that backends use `layout.abi` and
372+ // ignore the rest of the layout.
373+ assert ! (
374+ matches!( arg. layout. abi, Abi :: ScalarPair ( ..) ) ,
375+ "PassMode::Pair for type {}" ,
376+ arg. layout. ty
377+ ) ;
378+ }
379+ PassMode :: Cast { .. } => {
380+ // `Cast` means "transmute to `CastType`"; that only makes sense for sized types.
381+ assert ! ( arg. layout. is_sized( ) ) ;
382+ }
383+ PassMode :: Indirect { meta_attrs : None , .. } => {
384+ // No metadata, must be sized.
385+ assert ! ( arg. layout. is_sized( ) ) ;
386+ }
387+ PassMode :: Indirect { meta_attrs : Some ( _) , on_stack, .. } => {
388+ // With metadata. Must be unsized and not on the stack.
389+ assert ! ( arg. layout. is_unsized( ) && !on_stack) ;
390+ }
391+ }
392+ }
393+
394+ for arg in fn_abi. args . iter ( ) {
395+ fn_arg_sanity_check ( cx, fn_abi, arg) ;
396+ }
397+ fn_arg_sanity_check ( cx, fn_abi, & fn_abi. ret ) ;
398+ }
399+
330400// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
331401// arguments of this method, into a separate `struct`.
332402#[ tracing:: instrument( level = "debug" , skip( cx, caller_location, fn_def_id, force_thin_self_ptr) ) ]
@@ -453,6 +523,7 @@ fn fn_abi_new_uncached<'tcx>(
453523 } ;
454524 fn_abi_adjust_for_abi ( cx, & mut fn_abi, sig. abi , fn_def_id) ?;
455525 debug ! ( "fn_abi_new_uncached = {:?}" , fn_abi) ;
526+ fn_abi_sanity_check ( cx, & fn_abi) ;
456527 Ok ( cx. tcx . arena . alloc ( fn_abi) )
457528}
458529
0 commit comments