@@ -19,6 +19,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
1919 StableHasherResult } ;
2020
2121pub use rustc_target:: abi:: * ;
22+ use rustc_target:: spec:: HasTargetSpec ;
23+ use rustc_target:: abi:: call:: {
24+ ArgAttribute , ArgAttributes , ArgType , Conv , FnType , IgnoreMode , PassMode
25+ } ;
26+
27+
2228
2329pub trait IntegerExt {
2430 fn to_ty < ' a , ' tcx > ( & self , tcx : TyCtxt < ' a , ' tcx , ' tcx > , signed : bool ) -> Ty < ' tcx > ;
@@ -2259,3 +2265,346 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx>
22592265 }
22602266 }
22612267}
2268+
2269+ pub trait FnTypeExt < ' tcx , C > {
2270+ fn of_instance ( cx : & C , instance : & ty:: Instance < ' tcx > ) -> Self
2271+ where
2272+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2273+ + HasDataLayout
2274+ + HasTargetSpec
2275+ + HasTyCtxt < ' tcx >
2276+ + HasParamEnv < ' tcx > ;
2277+ fn new ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2278+ where
2279+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2280+ + HasDataLayout
2281+ + HasTargetSpec
2282+ + HasTyCtxt < ' tcx >
2283+ + HasParamEnv < ' tcx > ;
2284+ fn new_vtable ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2285+ where
2286+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2287+ + HasDataLayout
2288+ + HasTargetSpec
2289+ + HasTyCtxt < ' tcx >
2290+ + HasParamEnv < ' tcx > ;
2291+ fn new_internal (
2292+ cx : & C ,
2293+ sig : ty:: FnSig < ' tcx > ,
2294+ extra_args : & [ Ty < ' tcx > ] ,
2295+ mk_arg_type : impl Fn ( Ty < ' tcx > , Option < usize > ) -> ArgType < ' tcx , Ty < ' tcx > > ,
2296+ ) -> Self
2297+ where
2298+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2299+ + HasDataLayout
2300+ + HasTargetSpec
2301+ + HasTyCtxt < ' tcx >
2302+ + HasParamEnv < ' tcx > ;
2303+ }
2304+
2305+
2306+ impl < ' tcx , C > FnTypeExt < ' tcx , C > for call:: FnType < ' tcx , Ty < ' tcx > > {
2307+ fn of_instance ( cx : & C , instance : & ty:: Instance < ' tcx > ) -> Self
2308+ where
2309+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2310+ + HasDataLayout
2311+ + HasTargetSpec
2312+ + HasTargetSpec
2313+ + HasTyCtxt < ' tcx >
2314+ + HasParamEnv < ' tcx > ,
2315+ {
2316+ let sig = instance. fn_sig ( cx. tcx ( ) ) ;
2317+ let sig = cx
2318+ . tcx ( )
2319+ . normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , & sig) ;
2320+ call:: FnType :: new ( cx, sig, & [ ] )
2321+ }
2322+
2323+ fn new ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2324+ where
2325+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2326+ + HasDataLayout
2327+ + HasTargetSpec
2328+ + HasTyCtxt < ' tcx >
2329+ + HasParamEnv < ' tcx > ,
2330+ {
2331+ call:: FnType :: new_internal ( cx, sig, extra_args, |ty, _| ArgType :: new ( cx. layout_of ( ty) ) )
2332+ }
2333+
2334+
2335+ fn new_vtable ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2336+ where
2337+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2338+ + HasDataLayout
2339+ + HasTargetSpec
2340+ + HasTyCtxt < ' tcx >
2341+ + HasParamEnv < ' tcx > ,
2342+ {
2343+ FnType :: new_internal ( cx, sig, extra_args, |ty, arg_idx| {
2344+ let mut layout = cx. layout_of ( ty) ;
2345+ // Don't pass the vtable, it's not an argument of the virtual fn.
2346+ // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
2347+ // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
2348+ if arg_idx == Some ( 0 ) {
2349+ let fat_pointer_ty = if layout. is_unsized ( ) {
2350+ // unsized `self` is passed as a pointer to `self`
2351+ // FIXME (mikeyhew) change this to use &own if it is ever added to the language
2352+ cx. tcx ( ) . mk_mut_ptr ( layout. ty )
2353+ } else {
2354+ match layout. abi {
2355+ Abi :: ScalarPair ( ..) => ( ) ,
2356+ _ => bug ! ( "receiver type has unsupported layout: {:?}" , layout) ,
2357+ }
2358+
2359+ // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
2360+ // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
2361+ // elsewhere in the compiler as a method on a `dyn Trait`.
2362+ // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
2363+ // get a built-in pointer type
2364+ let mut fat_pointer_layout = layout;
2365+ ' descend_newtypes: while !fat_pointer_layout. ty . is_unsafe_ptr ( )
2366+ && !fat_pointer_layout. ty . is_region_ptr ( )
2367+ {
2368+ ' iter_fields: for i in 0 ..fat_pointer_layout. fields . count ( ) {
2369+ let field_layout = fat_pointer_layout. field ( cx, i) ;
2370+
2371+ if !field_layout. is_zst ( ) {
2372+ fat_pointer_layout = field_layout;
2373+ continue ' descend_newtypes;
2374+ }
2375+ }
2376+
2377+ bug ! (
2378+ "receiver has no non-zero-sized fields {:?}" ,
2379+ fat_pointer_layout
2380+ ) ;
2381+ }
2382+
2383+ fat_pointer_layout. ty
2384+ } ;
2385+
2386+ // we now have a type like `*mut RcBox<dyn Trait>`
2387+ // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
2388+ // this is understood as a special case elsewhere in the compiler
2389+ let unit_pointer_ty = cx. tcx ( ) . mk_mut_ptr ( cx. tcx ( ) . mk_unit ( ) ) ;
2390+ layout = cx. layout_of ( unit_pointer_ty) ;
2391+ layout. ty = fat_pointer_ty;
2392+ }
2393+ ArgType :: new ( layout)
2394+ } )
2395+ }
2396+
2397+ fn new_internal (
2398+ cx : & C ,
2399+ sig : ty:: FnSig < ' tcx > ,
2400+ extra_args : & [ Ty < ' tcx > ] ,
2401+ mk_arg_type : impl Fn ( Ty < ' tcx > , Option < usize > ) -> ArgType < ' tcx , Ty < ' tcx > > ,
2402+ ) -> Self
2403+ where
2404+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2405+ + HasDataLayout
2406+ + HasTargetSpec
2407+ + HasTargetSpec
2408+ + HasTyCtxt < ' tcx >
2409+ + HasParamEnv < ' tcx > ,
2410+ {
2411+ debug ! ( "FnType::new_internal({:?}, {:?})" , sig, extra_args) ;
2412+
2413+ use rustc_target:: spec:: abi:: Abi :: * ;
2414+ let conv = match cx. tcx ( ) . sess . target . target . adjust_abi ( sig. abi ) {
2415+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv :: C ,
2416+
2417+ // It's the ABI's job to select this, not ours.
2418+ System => bug ! ( "system abi should be selected elsewhere" ) ,
2419+
2420+ Stdcall => Conv :: X86Stdcall ,
2421+ Fastcall => Conv :: X86Fastcall ,
2422+ Vectorcall => Conv :: X86VectorCall ,
2423+ Thiscall => Conv :: X86ThisCall ,
2424+ C => Conv :: C ,
2425+ Unadjusted => Conv :: C ,
2426+ Win64 => Conv :: X86_64Win64 ,
2427+ SysV64 => Conv :: X86_64SysV ,
2428+ Aapcs => Conv :: ArmAapcs ,
2429+ PtxKernel => Conv :: PtxKernel ,
2430+ Msp430Interrupt => Conv :: Msp430Intr ,
2431+ X86Interrupt => Conv :: X86Intr ,
2432+ AmdGpuKernel => Conv :: AmdGpuKernel ,
2433+
2434+ // These API constants ought to be more specific...
2435+ Cdecl => Conv :: C ,
2436+ } ;
2437+
2438+ let mut inputs = sig. inputs ( ) ;
2439+ let extra_args = if sig. abi == RustCall {
2440+ assert ! ( !sig. c_variadic && extra_args. is_empty( ) ) ;
2441+
2442+ match sig. inputs ( ) . last ( ) . unwrap ( ) . sty {
2443+ ty:: Tuple ( tupled_arguments) => {
2444+ inputs = & sig. inputs ( ) [ 0 ..sig. inputs ( ) . len ( ) - 1 ] ;
2445+ tupled_arguments. iter ( ) . map ( |k| k. expect_ty ( ) ) . collect ( )
2446+ }
2447+ _ => {
2448+ bug ! (
2449+ "argument to function with \" rust-call\" ABI \
2450+ is not a tuple"
2451+ ) ;
2452+ }
2453+ }
2454+ } else {
2455+ assert ! ( sig. c_variadic || extra_args. is_empty( ) ) ;
2456+ extra_args. to_vec ( )
2457+ } ;
2458+
2459+ let target = & cx. tcx ( ) . sess . target . target ;
2460+ let win_x64_gnu =
2461+ target. target_os == "windows" && target. arch == "x86_64" && target. target_env == "gnu" ;
2462+ let linux_s390x =
2463+ target. target_os == "linux" && target. arch == "s390x" && target. target_env == "gnu" ;
2464+ let linux_sparc64 =
2465+ target. target_os == "linux" && target. arch == "sparc64" && target. target_env == "gnu" ;
2466+ let rust_abi = match sig. abi {
2467+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true ,
2468+ _ => false ,
2469+ } ;
2470+
2471+ // Handle safe Rust thin and fat pointers.
2472+ let adjust_for_rust_scalar = |attrs : & mut ArgAttributes ,
2473+ scalar : & Scalar ,
2474+ layout : TyLayout < ' tcx > ,
2475+ offset : Size ,
2476+ is_return : bool | {
2477+ // Booleans are always an i1 that needs to be zero-extended.
2478+ if scalar. is_bool ( ) {
2479+ attrs. set ( ArgAttribute :: ZExt ) ;
2480+ return ;
2481+ }
2482+
2483+ // Only pointer types handled below.
2484+ if scalar. value != Pointer {
2485+ return ;
2486+ }
2487+
2488+ if scalar. valid_range . start ( ) < scalar. valid_range . end ( ) {
2489+ if * scalar. valid_range . start ( ) > 0 {
2490+ attrs. set ( ArgAttribute :: NonNull ) ;
2491+ }
2492+ }
2493+
2494+ if let Some ( pointee) = layout. pointee_info_at ( cx, offset) {
2495+ if let Some ( kind) = pointee. safe {
2496+ attrs. pointee_size = pointee. size ;
2497+ attrs. pointee_align = Some ( pointee. align ) ;
2498+
2499+ // `Box` pointer parameters never alias because ownership is transferred
2500+ // `&mut` pointer parameters never alias other parameters,
2501+ // or mutable global data
2502+ //
2503+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
2504+ // and can be marked as both `readonly` and `noalias`, as
2505+ // LLVM's definition of `noalias` is based solely on memory
2506+ // dependencies rather than pointer equality
2507+ let no_alias = match kind {
2508+ PointerKind :: Shared => false ,
2509+ PointerKind :: UniqueOwned => true ,
2510+ PointerKind :: Frozen | PointerKind :: UniqueBorrowed => !is_return,
2511+ } ;
2512+ if no_alias {
2513+ attrs. set ( ArgAttribute :: NoAlias ) ;
2514+ }
2515+
2516+ if kind == PointerKind :: Frozen && !is_return {
2517+ attrs. set ( ArgAttribute :: ReadOnly ) ;
2518+ }
2519+ }
2520+ }
2521+ } ;
2522+
2523+ // Store the index of the last argument. This is useful for working with
2524+ // C-compatible variadic arguments.
2525+ let last_arg_idx = if sig. inputs ( ) . is_empty ( ) {
2526+ None
2527+ } else {
2528+ Some ( sig. inputs ( ) . len ( ) - 1 )
2529+ } ;
2530+
2531+ let arg_of = |ty : Ty < ' tcx > , arg_idx : Option < usize > | {
2532+ let is_return = arg_idx. is_none ( ) ;
2533+ let mut arg = mk_arg_type ( ty, arg_idx) ;
2534+ if arg. layout . is_zst ( ) {
2535+ // For some forsaken reason, x86_64-pc-windows-gnu
2536+ // doesn't ignore zero-sized struct arguments.
2537+ // The same is true for s390x-unknown-linux-gnu
2538+ // and sparc64-unknown-linux-gnu.
2539+ if is_return || rust_abi || ( !win_x64_gnu && !linux_s390x && !linux_sparc64) {
2540+ arg. mode = PassMode :: Ignore ( IgnoreMode :: Zst ) ;
2541+ }
2542+ }
2543+
2544+ // If this is a C-variadic function, this is not the return value,
2545+ // and there is one or more fixed arguments; ensure that the `VaList`
2546+ // is ignored as an argument.
2547+ if sig. c_variadic {
2548+ match ( last_arg_idx, arg_idx) {
2549+ ( Some ( last_idx) , Some ( cur_idx) ) if last_idx == cur_idx => {
2550+ let va_list_did = match cx. tcx ( ) . lang_items ( ) . va_list ( ) {
2551+ Some ( did) => did,
2552+ None => bug ! ( "`va_list` lang item required for C-variadic functions" ) ,
2553+ } ;
2554+ match ty. sty {
2555+ ty:: Adt ( def, _) if def. did == va_list_did => {
2556+ // This is the "spoofed" `VaList`. Set the arguments mode
2557+ // so that it will be ignored.
2558+ arg. mode = PassMode :: Ignore ( IgnoreMode :: CVarArgs ) ;
2559+ }
2560+ _ => ( ) ,
2561+ }
2562+ }
2563+ _ => { }
2564+ }
2565+ }
2566+
2567+ // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
2568+ if !is_return && rust_abi {
2569+ if let Abi :: ScalarPair ( ref a, ref b) = arg. layout . abi {
2570+ let mut a_attrs = ArgAttributes :: new ( ) ;
2571+ let mut b_attrs = ArgAttributes :: new ( ) ;
2572+ adjust_for_rust_scalar ( & mut a_attrs, a, arg. layout , Size :: ZERO , false ) ;
2573+ adjust_for_rust_scalar (
2574+ & mut b_attrs,
2575+ b,
2576+ arg. layout ,
2577+ a. value . size ( cx) . align_to ( b. value . align ( cx) . abi ) ,
2578+ false ,
2579+ ) ;
2580+ arg. mode = PassMode :: Pair ( a_attrs, b_attrs) ;
2581+ return arg;
2582+ }
2583+ }
2584+
2585+ if let Abi :: Scalar ( ref scalar) = arg. layout . abi {
2586+ if let PassMode :: Direct ( ref mut attrs) = arg. mode {
2587+ adjust_for_rust_scalar ( attrs, scalar, arg. layout , Size :: ZERO , is_return) ;
2588+ }
2589+ }
2590+
2591+ arg
2592+ } ;
2593+
2594+ let fn_ty = FnType {
2595+ ret : arg_of ( sig. output ( ) , None ) ,
2596+ args : inputs
2597+ . iter ( )
2598+ . cloned ( )
2599+ . chain ( extra_args)
2600+ . enumerate ( )
2601+ . map ( |( i, ty) | arg_of ( ty, Some ( i) ) )
2602+ . collect ( ) ,
2603+ c_variadic : sig. c_variadic ,
2604+ conv,
2605+ } ;
2606+ // FIXME: uncomment this after figuring out wwhere should adjust_for_abi reside.
2607+ //fn_ty.adjust_for_abi(cx, sig.abi);
2608+ fn_ty
2609+ }
2610+ }
0 commit comments