@@ -365,10 +365,15 @@ fn adjust_for_rust_scalar<'tcx>(
365365}
366366
367367/// Ensure that the ABI makes basic sense.
368- fn fn_abi_sanity_check < ' tcx > ( cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > , fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ) {
368+ fn fn_abi_sanity_check < ' tcx > (
369+ cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
370+ fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
371+ spec_abi : SpecAbi ,
372+ ) {
369373 fn fn_arg_sanity_check < ' tcx > (
370374 cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
371375 fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
376+ spec_abi : SpecAbi ,
372377 arg : & ArgAbi < ' tcx , Ty < ' tcx > > ,
373378 ) {
374379 match & arg. mode {
@@ -398,8 +403,8 @@ fn fn_abi_sanity_check<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, fn_abi: &FnAbi<'
398403 // (See issue: https://github.com/rust-lang/rust/issues/117271)
399404 assert ! (
400405 matches!( & * cx. tcx. sess. target. arch, "wasm32" | "wasm64" )
401- || fn_abi . conv == Conv :: PtxKernel ,
402- "`PassMode::Direct` for aggregates only allowed on wasm and `extern \ " ptx-kernel\" ` fns \n Problematic type: {:#?}" ,
406+ || matches! ( spec_abi , SpecAbi :: PtxKernel | SpecAbi :: Unadjusted ) ,
407+ r# "`PassMode::Direct` for aggregates only allowed for "unadjusted" and "ptx-kernel" functions and on wasm \nProblematic type: {:#?}"# ,
403408 arg. layout,
404409 ) ;
405410 }
@@ -429,9 +434,9 @@ fn fn_abi_sanity_check<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, fn_abi: &FnAbi<'
429434 }
430435
431436 for arg in fn_abi. args . iter ( ) {
432- fn_arg_sanity_check ( cx, fn_abi, arg) ;
437+ fn_arg_sanity_check ( cx, fn_abi, spec_abi , arg) ;
433438 }
434- fn_arg_sanity_check ( cx, fn_abi, & fn_abi. ret ) ;
439+ fn_arg_sanity_check ( cx, fn_abi, spec_abi , & fn_abi. ret ) ;
435440}
436441
437442// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
@@ -560,7 +565,7 @@ fn fn_abi_new_uncached<'tcx>(
560565 } ;
561566 fn_abi_adjust_for_abi ( cx, & mut fn_abi, sig. abi , fn_def_id) ?;
562567 debug ! ( "fn_abi_new_uncached = {:?}" , fn_abi) ;
563- fn_abi_sanity_check ( cx, & fn_abi) ;
568+ fn_abi_sanity_check ( cx, & fn_abi, sig . abi ) ;
564569 Ok ( cx. tcx . arena . alloc ( fn_abi) )
565570}
566571
@@ -572,6 +577,24 @@ fn fn_abi_adjust_for_abi<'tcx>(
572577 fn_def_id : Option < DefId > ,
573578) -> Result < ( ) , & ' tcx FnAbiError < ' tcx > > {
574579 if abi == SpecAbi :: Unadjusted {
580+ // The "unadjusted" ABI passes aggregates in "direct" mode. That's fragile but needed for
581+ // some LLVM intrinsics.
582+ fn unadjust < ' tcx > ( arg : & mut ArgAbi < ' tcx , Ty < ' tcx > > ) {
583+ // This still uses `PassMode::Pair` for ScalarPair types. That's unlikely to be intended,
584+ // but who knows what breaks if we change this now.
585+ if matches ! ( arg. layout. abi, Abi :: Aggregate { .. } ) {
586+ assert ! (
587+ arg. layout. abi. is_sized( ) ,
588+ "'unadjusted' ABI does not support unsized arguments"
589+ ) ;
590+ }
591+ arg. make_direct_deprecated ( ) ;
592+ }
593+
594+ unadjust ( & mut fn_abi. ret ) ;
595+ for arg in fn_abi. args . iter_mut ( ) {
596+ unadjust ( arg) ;
597+ }
575598 return Ok ( ( ) ) ;
576599 }
577600
0 commit comments