Skip to content

Commit 5f1d6c4

Browse files
committed
Auto merge of #65947 - eddyb:fn-abi, r=oli-obk,nagisa
rustc: split FnAbi's into definitions/direct calls ("of_instance") and indirect calls ("of_fn_ptr"). After this PR: * `InstanceDef::Virtual` is only used for "direct" virtual calls, and shims around those calls use `InstanceDef::ReifyShim` (i.e. for `<dyn Trait as Trait>::f as fn(_)`) * this could easily be done for intrinsics as well, to allow their reification, but I didn't do it * `FnAbi::of_instance` is **always** used for declaring/defining an `fn`, and for direct calls to an `fn` * this is great for e.g. #65881 (`#[track_caller]`), which can introduce the "caller location" argument into "codegen signatures" by only changing `FnAbi::of_instance`, after this PR * `FnAbi::of_fn_ptr` is used primarily for indirect calls, i.e. to `fn` pointers * *not* virtual calls (which use `FnAbi::of_instance` with `InstanceDef::Virtual`) * there's also a couple uses where the `rustc_codegen_llvm` needs to declare (i.e. FFI-import) an LLVM function that has no Rust declaration available at all * at least one of them could probably be a "weak lang item" instead As there are many steps, this PR is best reviewed commit by commit - some of which arguably should be in their own PRs, I may have gotten carried away a bit. cc @nagisa @rkruppe @oli-obk @anp
2 parents a7fc093 + c2f4c57 commit 5f1d6c4

34 files changed

+387
-426
lines changed

Diff for: src/librustc/mir/cache.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -279,18 +279,10 @@ impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyCache<'a, 'tcx> {
279279

280280

281281
impl Deref for ReadOnlyBodyCache<'a, 'tcx> {
282-
type Target = Body<'tcx>;
282+
type Target = &'a Body<'tcx>;
283283

284284
fn deref(&self) -> &Self::Target {
285-
self.body
286-
}
287-
}
288-
289-
impl Index<BasicBlock> for ReadOnlyBodyCache<'a, 'tcx> {
290-
type Output = BasicBlockData<'tcx>;
291-
292-
fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
293-
&self.body[index]
285+
&self.body
294286
}
295287
}
296288

Diff for: src/librustc/ty/instance.rs

+26-80
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
use crate::hir::CodegenFnAttrFlags;
2-
use crate::hir::Unsafety;
32
use crate::hir::def::Namespace;
43
use crate::hir::def_id::DefId;
5-
use crate::ty::{self, Ty, PolyFnSig, TypeFoldable, SubstsRef, TyCtxt};
4+
use crate::ty::{self, Ty, TypeFoldable, SubstsRef, TyCtxt};
65
use crate::ty::print::{FmtPrinter, Printer};
76
use crate::traits;
87
use crate::middle::lang_items::DropInPlaceFnLangItem;
98
use rustc_target::spec::abi::Abi;
109
use rustc_macros::HashStable;
1110

1211
use std::fmt;
13-
use std::iter;
1412

1513
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
1614
#[derive(HashStable, Lift)]
@@ -29,17 +27,26 @@ pub enum InstanceDef<'tcx> {
2927

3028
/// `fn()` pointer where the function itself cannot be turned into a pointer.
3129
///
32-
/// One example in the compiler today is functions annotated with `#[track_caller]`, which
33-
/// must have their implicit caller location argument populated for a call. Because this is a
34-
/// required part of the function's ABI but can't be tracked as a property of the function
35-
/// pointer, we create a single "caller location" at the site where the function is reified.
30+
/// One example is `<dyn Trait as Trait>::fn`, where the shim contains
31+
/// a virtual call, which codegen supports only via a direct call to the
32+
/// `<dyn Trait as Trait>::fn` instance (an `InstanceDef::Virtual`).
33+
///
34+
/// Another example is functions annotated with `#[track_caller]`, which
35+
/// must have their implicit caller location argument populated for a call.
36+
/// Because this is a required part of the function's ABI but can't be tracked
37+
/// as a property of the function pointer, we use a single "caller location"
38+
/// (the definition of the function itself).
3639
ReifyShim(DefId),
3740

3841
/// `<fn() as FnTrait>::call_*`
3942
/// `DefId` is `FnTrait::call_*`.
4043
FnPtrShim(DefId, Ty<'tcx>),
4144

42-
/// `<dyn Trait as Trait>::fn`
45+
/// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
46+
/// codegen'd as virtual calls.
47+
///
48+
/// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used
49+
/// (see `ReifyShim` above for more details on that).
4350
Virtual(DefId, usize),
4451

4552
/// `<[mut closure] as FnOnce>::call_once`
@@ -61,70 +68,6 @@ impl<'tcx> Instance<'tcx> {
6168
&ty,
6269
)
6370
}
64-
65-
fn fn_sig_noadjust(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
66-
let ty = self.ty(tcx);
67-
match ty.kind {
68-
ty::FnDef(..) |
69-
// Shims currently have type FnPtr. Not sure this should remain.
70-
ty::FnPtr(_) => ty.fn_sig(tcx),
71-
ty::Closure(def_id, substs) => {
72-
let sig = substs.as_closure().sig(def_id, tcx);
73-
74-
let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
75-
sig.map_bound(|sig| tcx.mk_fn_sig(
76-
iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
77-
sig.output(),
78-
sig.c_variadic,
79-
sig.unsafety,
80-
sig.abi
81-
))
82-
}
83-
ty::Generator(def_id, substs, _) => {
84-
let sig = substs.as_generator().poly_sig(def_id, tcx);
85-
86-
let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
87-
let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
88-
89-
let pin_did = tcx.lang_items().pin_type().unwrap();
90-
let pin_adt_ref = tcx.adt_def(pin_did);
91-
let pin_substs = tcx.intern_substs(&[env_ty.into()]);
92-
let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
93-
94-
sig.map_bound(|sig| {
95-
let state_did = tcx.lang_items().gen_state().unwrap();
96-
let state_adt_ref = tcx.adt_def(state_did);
97-
let state_substs = tcx.intern_substs(&[
98-
sig.yield_ty.into(),
99-
sig.return_ty.into(),
100-
]);
101-
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
102-
103-
tcx.mk_fn_sig(iter::once(env_ty),
104-
ret_ty,
105-
false,
106-
Unsafety::Normal,
107-
Abi::Rust
108-
)
109-
})
110-
}
111-
_ => bug!("unexpected type {:?} in Instance::fn_sig_noadjust", ty)
112-
}
113-
}
114-
115-
pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
116-
let mut fn_sig = self.fn_sig_noadjust(tcx);
117-
if let InstanceDef::VtableShim(..) = self.def {
118-
// Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
119-
fn_sig = fn_sig.map_bound(|mut fn_sig| {
120-
let mut inputs_and_output = fn_sig.inputs_and_output.to_vec();
121-
inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
122-
fn_sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
123-
fn_sig
124-
});
125-
}
126-
fn_sig
127-
}
12871
}
12972

13073
impl<'tcx> InstanceDef<'tcx> {
@@ -196,7 +139,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
196139
write!(f, " - intrinsic")
197140
}
198141
InstanceDef::Virtual(_, num) => {
199-
write!(f, " - shim(#{})", num)
142+
write!(f, " - virtual#{}", num)
200143
}
201144
InstanceDef::FnPtrShim(_, ty) => {
202145
write!(f, " - shim({:?})", ty)
@@ -311,20 +254,23 @@ impl<'tcx> Instance<'tcx> {
311254
substs: SubstsRef<'tcx>,
312255
) -> Option<Instance<'tcx>> {
313256
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
314-
Instance::resolve(tcx, param_env, def_id, substs).map(|resolved| {
257+
Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| {
315258
let has_track_caller = |def| tcx.codegen_fn_attrs(def).flags
316259
.contains(CodegenFnAttrFlags::TRACK_CALLER);
317260

318261
match resolved.def {
319262
InstanceDef::Item(def_id) if has_track_caller(def_id) => {
320263
debug!(" => fn pointer created for function with #[track_caller]");
321-
Instance {
322-
def: InstanceDef::ReifyShim(def_id),
323-
substs,
324-
}
325-
},
326-
_ => resolved,
264+
resolved.def = InstanceDef::ReifyShim(def_id);
265+
}
266+
InstanceDef::Virtual(def_id, _) => {
267+
debug!(" => fn pointer created for virtual call");
268+
resolved.def = InstanceDef::ReifyShim(def_id);
269+
}
270+
_ => {}
327271
}
272+
273+
resolved
328274
})
329275
}
330276

Diff for: src/librustc/ty/layout.rs

+96-18
Original file line numberDiff line numberDiff line change
@@ -2339,6 +2339,76 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
23392339
}
23402340
}
23412341

2342+
2343+
impl<'tcx> ty::Instance<'tcx> {
2344+
// NOTE(eddyb) this is private to avoid using it from outside of
2345+
// `FnAbi::of_instance` - any other uses are either too high-level
2346+
// for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
2347+
// or should go through `FnAbi` instead, to avoid losing any
2348+
// adjustments `FnAbi::of_instance` might be performing.
2349+
fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
2350+
let ty = self.ty(tcx);
2351+
match ty.kind {
2352+
ty::FnDef(..) |
2353+
// Shims currently have type FnPtr. Not sure this should remain.
2354+
ty::FnPtr(_) => {
2355+
let mut sig = ty.fn_sig(tcx);
2356+
if let ty::InstanceDef::VtableShim(..) = self.def {
2357+
// Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
2358+
sig = sig.map_bound(|mut sig| {
2359+
let mut inputs_and_output = sig.inputs_and_output.to_vec();
2360+
inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
2361+
sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
2362+
sig
2363+
});
2364+
}
2365+
sig
2366+
}
2367+
ty::Closure(def_id, substs) => {
2368+
let sig = substs.as_closure().sig(def_id, tcx);
2369+
2370+
let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
2371+
sig.map_bound(|sig| tcx.mk_fn_sig(
2372+
iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
2373+
sig.output(),
2374+
sig.c_variadic,
2375+
sig.unsafety,
2376+
sig.abi
2377+
))
2378+
}
2379+
ty::Generator(def_id, substs, _) => {
2380+
let sig = substs.as_generator().poly_sig(def_id, tcx);
2381+
2382+
let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
2383+
let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
2384+
2385+
let pin_did = tcx.lang_items().pin_type().unwrap();
2386+
let pin_adt_ref = tcx.adt_def(pin_did);
2387+
let pin_substs = tcx.intern_substs(&[env_ty.into()]);
2388+
let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
2389+
2390+
sig.map_bound(|sig| {
2391+
let state_did = tcx.lang_items().gen_state().unwrap();
2392+
let state_adt_ref = tcx.adt_def(state_did);
2393+
let state_substs = tcx.intern_substs(&[
2394+
sig.yield_ty.into(),
2395+
sig.return_ty.into(),
2396+
]);
2397+
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
2398+
2399+
tcx.mk_fn_sig(iter::once(env_ty),
2400+
ret_ty,
2401+
false,
2402+
hir::Unsafety::Normal,
2403+
rustc_target::spec::abi::Abi::Rust
2404+
)
2405+
})
2406+
}
2407+
_ => bug!("unexpected type {:?} in Instance::fn_sig", ty)
2408+
}
2409+
}
2410+
}
2411+
23422412
pub trait FnAbiExt<'tcx, C>
23432413
where
23442414
C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
@@ -2347,12 +2417,22 @@ where
23472417
+ HasTyCtxt<'tcx>
23482418
+ HasParamEnv<'tcx>,
23492419
{
2350-
fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self;
2351-
fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
2352-
fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
2420+
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
2421+
///
2422+
/// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance`
2423+
/// instead, where the instance is a `InstanceDef::Virtual`.
2424+
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
2425+
2426+
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
2427+
/// direct calls to an `fn`.
2428+
///
2429+
/// NB: that includes virtual calls, which are represented by "direct calls"
2430+
/// to a `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
2431+
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
2432+
23532433
fn new_internal(
23542434
cx: &C,
2355-
sig: ty::FnSig<'tcx>,
2435+
sig: ty::PolyFnSig<'tcx>,
23562436
extra_args: &[Ty<'tcx>],
23572437
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
23582438
) -> Self;
@@ -2367,25 +2447,19 @@ where
23672447
+ HasTyCtxt<'tcx>
23682448
+ HasParamEnv<'tcx>,
23692449
{
2370-
fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self {
2371-
let sig = instance.fn_sig(cx.tcx());
2372-
let sig = cx
2373-
.tcx()
2374-
.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
2375-
call::FnAbi::new(cx, sig, &[])
2376-
}
2377-
2378-
fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
2450+
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
23792451
call::FnAbi::new_internal(cx, sig, extra_args, |ty, _| ArgAbi::new(cx.layout_of(ty)))
23802452
}
23812453

2382-
fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
2383-
FnAbiExt::new_internal(cx, sig, extra_args, |ty, arg_idx| {
2454+
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
2455+
let sig = instance.fn_sig_for_fn_abi(cx.tcx());
2456+
2457+
call::FnAbi::new_internal(cx, sig, extra_args, |ty, arg_idx| {
23842458
let mut layout = cx.layout_of(ty);
23852459
// Don't pass the vtable, it's not an argument of the virtual fn.
23862460
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
23872461
// or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
2388-
if arg_idx == Some(0) {
2462+
if let (ty::InstanceDef::Virtual(..), Some(0)) = (&instance.def, arg_idx) {
23892463
let fat_pointer_ty = if layout.is_unsized() {
23902464
// unsized `self` is passed as a pointer to `self`
23912465
// FIXME (mikeyhew) change this to use &own if it is ever added to the language
@@ -2436,15 +2510,19 @@ where
24362510

24372511
fn new_internal(
24382512
cx: &C,
2439-
sig: ty::FnSig<'tcx>,
2513+
sig: ty::PolyFnSig<'tcx>,
24402514
extra_args: &[Ty<'tcx>],
24412515
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
24422516
) -> Self {
24432517
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
24442518

2519+
let sig = cx
2520+
.tcx()
2521+
.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
2522+
24452523
use rustc_target::spec::abi::Abi::*;
24462524
let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) {
2447-
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C,
2525+
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
24482526

24492527
// It's the ABI's job to select this, not ours.
24502528
System => bug!("system abi should be selected elsewhere"),

Diff for: src/librustc_codegen_llvm/abi.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
372372

373373
fn llvm_cconv(&self) -> llvm::CallConv {
374374
match self.conv {
375-
Conv::C => llvm::CCallConv,
375+
Conv::C | Conv::Rust => llvm::CCallConv,
376376
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
377377
Conv::ArmAapcs => llvm::ArmAapcsCallConv,
378378
Conv::Msp430Intr => llvm::Msp430Intr,
@@ -388,6 +388,11 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
388388
}
389389

390390
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
391+
// FIXME(eddyb) can this also be applied to callsites?
392+
if self.ret.layout.abi.is_uninhabited() {
393+
llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
394+
}
395+
391396
let mut i = 0;
392397
let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
393398
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);

0 commit comments

Comments
 (0)