@@ -19,6 +19,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
19
19
StableHasherResult } ;
20
20
21
21
pub 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
+
22
28
23
29
pub trait IntegerExt {
24
30
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>
2259
2265
}
2260
2266
}
2261
2267
}
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