2024-06-29 17:25:44 -04:00
|
|
|
use std::assert_matches::assert_matches;
|
2017-02-07 22:46:21 +01:00
|
|
|
use std::{fmt, iter};
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2024-11-02 19:33:00 -07:00
|
|
|
use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx};
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_hir as hir;
|
|
|
|
|
use rustc_hir::def_id::DefId;
|
2020-08-18 11:47:27 +01:00
|
|
|
use rustc_hir::lang_items::LangItem;
|
2024-06-29 17:25:44 -04:00
|
|
|
use rustc_index::{Idx, IndexVec};
|
2024-08-26 16:45:15 +03:00
|
|
|
use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::mir::*;
|
2023-05-15 06:24:45 +02:00
|
|
|
use rustc_middle::query::Providers;
|
2024-05-31 14:13:46 -04:00
|
|
|
use rustc_middle::ty::{
|
|
|
|
|
self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt,
|
|
|
|
|
};
|
2024-05-08 19:46:29 +10:00
|
|
|
use rustc_middle::{bug, span_bug};
|
2024-08-26 16:45:15 +03:00
|
|
|
use rustc_span::source_map::{Spanned, dummy_spanned};
|
2024-01-12 08:21:42 +01:00
|
|
|
use rustc_span::{DUMMY_SP, Span};
|
2024-08-28 15:03:14 +10:00
|
|
|
use tracing::{debug, instrument};
|
2017-02-07 22:46:21 +01:00
|
|
|
|
2025-02-14 15:30:51 +11:00
|
|
|
use crate::elaborate_drop::{DropElaborator, DropFlagMode, DropStyle, Unwind, elaborate_drop};
|
2025-02-14 15:56:06 +11:00
|
|
|
use crate::patch::MirPatch;
|
2021-01-01 01:53:25 +01:00
|
|
|
use crate::{
|
2024-12-10 12:06:24 +00:00
|
|
|
abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, inline,
|
2024-08-26 16:45:15 +03:00
|
|
|
instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads,
|
|
|
|
|
run_optimization_passes, simplify,
|
2021-01-01 01:53:25 +01:00
|
|
|
};
|
2017-03-09 20:36:01 +02:00
|
|
|
|
2024-02-13 12:31:41 +03:00
|
|
|
mod async_destructor_ctor;
|
|
|
|
|
|
2024-08-28 09:39:59 +10:00
|
|
|
pub(super) fn provide(providers: &mut Providers) {
|
2017-02-08 18:31:03 +01:00
|
|
|
providers.mir_shims = make_shim;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-07 13:51:08 +03:00
|
|
|
// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> accesses
|
2024-08-26 16:45:15 +03:00
|
|
|
struct FixProxyFutureDropVisitor<'tcx> {
|
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
replace_to: Local,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'tcx> MutVisitor<'tcx> for FixProxyFutureDropVisitor<'tcx> {
|
|
|
|
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
|
|
|
|
self.tcx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_place(
|
|
|
|
|
&mut self,
|
|
|
|
|
place: &mut Place<'tcx>,
|
|
|
|
|
_context: PlaceContext,
|
|
|
|
|
_location: Location,
|
|
|
|
|
) {
|
|
|
|
|
if place.local == Local::from_u32(1) {
|
|
|
|
|
if place.projection.len() == 1 {
|
|
|
|
|
assert!(matches!(
|
|
|
|
|
place.projection.first(),
|
|
|
|
|
Some(ProjectionElem::Field(FieldIdx::ZERO, _))
|
|
|
|
|
));
|
|
|
|
|
*place = Place::from(self.replace_to);
|
|
|
|
|
} else if place.projection.len() == 2 {
|
|
|
|
|
assert!(matches!(place.projection[0], ProjectionElem::Field(FieldIdx::ZERO, _)));
|
|
|
|
|
assert!(matches!(place.projection[1], ProjectionElem::Deref));
|
|
|
|
|
*place =
|
|
|
|
|
Place::from(self.replace_to).project_deeper(&[ProjectionElem::Deref], self.tcx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-16 21:35:16 -04:00
|
|
|
fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<'tcx> {
|
2017-03-06 12:58:51 +02:00
|
|
|
debug!("make_shim({:?})", instance);
|
2017-03-08 18:33:21 +02:00
|
|
|
|
2017-03-09 20:36:01 +02:00
|
|
|
let mut result = match instance {
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::Item(..) => bug!("item {:?} passed to make_shim", instance),
|
|
|
|
|
ty::InstanceKind::VTableShim(def_id) => {
|
2023-06-19 09:06:32 +02:00
|
|
|
let adjustment = Adjustment::Deref { source: DerefSource::MutPtr };
|
|
|
|
|
build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))
|
2020-06-14 23:01:32 +02:00
|
|
|
}
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::FnPtrShim(def_id, ty) => {
|
2025-08-12 17:57:02 -05:00
|
|
|
let trait_ = tcx.parent(def_id);
|
2024-02-26 22:53:45 +00:00
|
|
|
// Supports `Fn` or `async Fn` traits.
|
|
|
|
|
let adjustment = match tcx
|
|
|
|
|
.fn_trait_kind_from_def_id(trait_)
|
|
|
|
|
.or_else(|| tcx.async_fn_trait_kind_from_def_id(trait_))
|
|
|
|
|
{
|
2017-03-08 18:33:21 +02:00
|
|
|
Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
|
2023-06-19 09:06:32 +02:00
|
|
|
Some(ty::ClosureKind::Fn) => Adjustment::Deref { source: DerefSource::ImmRef },
|
|
|
|
|
Some(ty::ClosureKind::FnMut) => Adjustment::Deref { source: DerefSource::MutRef },
|
2017-03-08 18:33:21 +02:00
|
|
|
None => bug!("fn pointer {:?} is not an fn", ty),
|
|
|
|
|
};
|
2020-08-09 20:08:45 +01:00
|
|
|
|
|
|
|
|
build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty))
|
2017-03-08 18:33:21 +02:00
|
|
|
}
|
2019-10-09 21:02:54 -07:00
|
|
|
// We are generating a call back to our def-id, which the
|
2019-10-29 20:56:21 +02:00
|
|
|
// codegen backend knows to turn to an actual call, be it
|
|
|
|
|
// a virtual call, or a direct call to a function for which
|
|
|
|
|
// indirect calls must be codegen'd differently than direct ones
|
|
|
|
|
// (such as `#[track_caller]`).
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::ReifyShim(def_id, _) => {
|
2020-08-09 20:08:45 +01:00
|
|
|
build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
|
2017-03-06 12:58:51 +02:00
|
|
|
}
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => {
|
2025-06-04 06:26:56 +00:00
|
|
|
let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP);
|
2019-09-25 15:36:14 -04:00
|
|
|
let call_mut = tcx
|
2017-03-08 23:19:09 +02:00
|
|
|
.associated_items(fn_mut)
|
2020-02-17 13:09:01 -08:00
|
|
|
.in_definition_order()
|
2025-04-11 06:28:59 +10:00
|
|
|
.find(|it| it.is_fn())
|
2017-03-08 23:19:09 +02:00
|
|
|
.unwrap()
|
|
|
|
|
.def_id;
|
|
|
|
|
|
2020-08-09 20:08:45 +01:00
|
|
|
build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
2021-12-05 16:21:23 -08:00
|
|
|
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::ConstructCoroutineInClosureShim {
|
2024-02-28 20:25:25 +00:00
|
|
|
coroutine_closure_def_id,
|
|
|
|
|
receiver_by_ref,
|
|
|
|
|
} => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref),
|
2024-01-25 00:30:55 +00:00
|
|
|
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::DropGlue(def_id, ty) => {
|
2023-10-19 21:46:28 +00:00
|
|
|
// FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end
|
2021-12-05 16:21:23 -08:00
|
|
|
// of this function. Is this intentional?
|
2024-08-01 13:05:17 -04:00
|
|
|
if let Some(&ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) {
|
|
|
|
|
let coroutine_body = tcx.optimized_mir(coroutine_def_id);
|
2024-01-29 17:41:51 +00:00
|
|
|
|
|
|
|
|
let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind()
|
|
|
|
|
else {
|
|
|
|
|
bug!()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// If this is a regular coroutine, grab its drop shim. If this is a coroutine
|
|
|
|
|
// that comes from a coroutine-closure, and the kind ty differs from the "maximum"
|
|
|
|
|
// kind that it supports, then grab the appropriate drop shim. This ensures that
|
|
|
|
|
// the future returned by `<[coroutine-closure] as AsyncFnOnce>::call_once` will
|
|
|
|
|
// drop the coroutine-closure's upvars.
|
|
|
|
|
let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() {
|
|
|
|
|
coroutine_body.coroutine_drop().unwrap()
|
|
|
|
|
} else {
|
2024-02-13 15:29:50 +00:00
|
|
|
assert_eq!(
|
|
|
|
|
args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
|
|
|
|
|
ty::ClosureKind::FnOnce
|
|
|
|
|
);
|
2024-08-01 13:05:17 -04:00
|
|
|
tcx.optimized_mir(tcx.coroutine_by_move_body_def_id(coroutine_def_id))
|
|
|
|
|
.coroutine_drop()
|
|
|
|
|
.unwrap()
|
2024-01-29 17:41:51 +00:00
|
|
|
};
|
|
|
|
|
|
2023-06-28 15:29:16 +01:00
|
|
|
let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args);
|
2021-12-05 16:21:23 -08:00
|
|
|
debug!("make_shim({:?}) = {:?}", instance, body);
|
2023-06-28 15:29:16 +01:00
|
|
|
|
|
|
|
|
pm::run_passes(
|
|
|
|
|
tcx,
|
|
|
|
|
&mut body,
|
2023-11-28 00:00:00 +00:00
|
|
|
&[
|
2024-03-15 21:06:40 +01:00
|
|
|
&mentioned_items::MentionedItems,
|
2023-11-28 00:00:00 +00:00
|
|
|
&abort_unwinding_calls::AbortUnwindingCalls,
|
|
|
|
|
&add_call_guards::CriticalCallEdges,
|
|
|
|
|
],
|
2023-06-28 15:29:16 +01:00
|
|
|
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
|
2024-12-09 19:34:51 +00:00
|
|
|
pm::Optimizations::Allowed,
|
2023-06-28 15:29:16 +01:00
|
|
|
);
|
|
|
|
|
|
2021-12-05 16:21:23 -08:00
|
|
|
return body;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
build_drop_shim(tcx, def_id, ty)
|
|
|
|
|
}
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance),
|
|
|
|
|
ty::InstanceKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
|
|
|
|
|
ty::InstanceKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
|
2024-08-26 16:45:15 +03:00
|
|
|
ty::InstanceKind::FutureDropPollShim(def_id, proxy_ty, impl_ty) => {
|
|
|
|
|
let mut body =
|
|
|
|
|
async_destructor_ctor::build_future_drop_poll_shim(tcx, def_id, proxy_ty, impl_ty);
|
|
|
|
|
|
|
|
|
|
pm::run_passes(
|
|
|
|
|
tcx,
|
|
|
|
|
&mut body,
|
|
|
|
|
&[
|
|
|
|
|
&mentioned_items::MentionedItems,
|
|
|
|
|
&abort_unwinding_calls::AbortUnwindingCalls,
|
|
|
|
|
&add_call_guards::CriticalCallEdges,
|
|
|
|
|
],
|
|
|
|
|
Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
|
|
|
|
|
pm::Optimizations::Allowed,
|
|
|
|
|
);
|
|
|
|
|
run_optimization_passes(tcx, &mut body);
|
|
|
|
|
debug!("make_shim({:?}) = {:?}", instance, body);
|
|
|
|
|
return body;
|
|
|
|
|
}
|
|
|
|
|
ty::InstanceKind::AsyncDropGlue(def_id, ty) => {
|
|
|
|
|
let mut body = async_destructor_ctor::build_async_drop_shim(tcx, def_id, ty);
|
|
|
|
|
|
|
|
|
|
// Main pass required here is StateTransform to convert sync drop ladder
|
|
|
|
|
// into coroutine.
|
|
|
|
|
// Others are minimal passes as for sync drop glue shim
|
|
|
|
|
pm::run_passes(
|
|
|
|
|
tcx,
|
|
|
|
|
&mut body,
|
|
|
|
|
&[
|
|
|
|
|
&mentioned_items::MentionedItems,
|
|
|
|
|
&abort_unwinding_calls::AbortUnwindingCalls,
|
|
|
|
|
&add_call_guards::CriticalCallEdges,
|
|
|
|
|
&simplify::SimplifyCfg::MakeShim,
|
|
|
|
|
&crate::coroutine::StateTransform,
|
|
|
|
|
],
|
|
|
|
|
Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
|
|
|
|
|
pm::Optimizations::Allowed,
|
|
|
|
|
);
|
|
|
|
|
run_optimization_passes(tcx, &mut body);
|
|
|
|
|
debug!("make_shim({:?}) = {:?}", instance, body);
|
|
|
|
|
return body;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) => {
|
2024-08-26 16:45:15 +03:00
|
|
|
let body = async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty);
|
|
|
|
|
debug!("make_shim({:?}) = {:?}", instance, body);
|
|
|
|
|
return body;
|
2024-02-13 12:31:41 +03:00
|
|
|
}
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::Virtual(..) => {
|
|
|
|
|
bug!("InstanceKind::Virtual ({:?}) is for direct calls only", instance)
|
2019-10-29 20:56:21 +02:00
|
|
|
}
|
2024-06-16 21:35:16 -04:00
|
|
|
ty::InstanceKind::Intrinsic(_) => {
|
2017-03-08 23:19:09 +02:00
|
|
|
bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
|
|
|
|
|
}
|
2017-03-06 12:58:51 +02:00
|
|
|
};
|
2019-11-06 00:04:53 -05:00
|
|
|
debug!("make_shim({:?}) = untransformed {:?}", instance, result);
|
2018-11-22 17:17:45 +01:00
|
|
|
|
2023-08-19 18:47:08 +00:00
|
|
|
// We don't validate MIR here because the shims may generate code that's
|
2024-11-20 11:59:52 +01:00
|
|
|
// only valid in a `PostAnalysis` param-env. However, since we do initial
|
2023-08-19 18:47:08 +00:00
|
|
|
// validation with the MirBuilt phase, which uses a user-facing param-env.
|
|
|
|
|
// This causes validation errors when TAITs are involved.
|
|
|
|
|
pm::run_passes_no_validate(
|
2019-08-15 06:39:31 -04:00
|
|
|
tcx,
|
|
|
|
|
&mut result,
|
2021-12-02 14:20:03 -08:00
|
|
|
&[
|
2024-03-15 21:06:40 +01:00
|
|
|
&mentioned_items::MentionedItems,
|
2018-11-22 17:17:45 +01:00
|
|
|
&add_moves_for_packed_drops::AddMovesForPackedDrops,
|
2022-07-09 18:04:38 -07:00
|
|
|
&deref_separator::Derefer,
|
2018-11-22 17:17:45 +01:00
|
|
|
&remove_noop_landing_pads::RemoveNoopLandingPads,
|
2023-04-17 20:17:01 -06:00
|
|
|
&simplify::SimplifyCfg::MakeShim,
|
2024-07-27 14:36:17 +08:00
|
|
|
&instsimplify::InstSimplify::BeforeInline,
|
2024-12-10 12:06:24 +00:00
|
|
|
// Perform inlining of `#[rustc_force_inline]`-annotated callees.
|
|
|
|
|
&inline::ForceInline,
|
2021-06-08 11:23:58 -07:00
|
|
|
&abort_unwinding_calls::AbortUnwindingCalls,
|
2023-11-19 00:00:00 +00:00
|
|
|
&add_call_guards::CriticalCallEdges,
|
2021-12-02 14:20:03 -08:00
|
|
|
],
|
2022-09-26 18:43:35 -07:00
|
|
|
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
|
2018-11-22 17:17:45 +01:00
|
|
|
);
|
|
|
|
|
|
2019-11-06 00:04:53 -05:00
|
|
|
debug!("make_shim({:?}) = {:?}", instance, result);
|
2017-03-06 12:58:51 +02:00
|
|
|
|
2020-03-27 20:26:20 +01:00
|
|
|
result
|
2017-02-08 18:31:03 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-19 09:06:32 +02:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
|
|
|
enum DerefSource {
|
|
|
|
|
/// `fn shim(&self) { inner(*self )}`.
|
|
|
|
|
ImmRef,
|
|
|
|
|
/// `fn shim(&mut self) { inner(*self )}`.
|
|
|
|
|
MutRef,
|
|
|
|
|
/// `fn shim(*mut self) { inner(*self )}`.
|
|
|
|
|
MutPtr,
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-08 18:33:21 +02:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
|
|
|
enum Adjustment {
|
2020-06-14 23:44:08 +02:00
|
|
|
/// Pass the receiver as-is.
|
2017-03-08 18:33:21 +02:00
|
|
|
Identity,
|
2020-06-14 23:44:08 +02:00
|
|
|
|
2023-06-19 09:06:32 +02:00
|
|
|
/// We get passed a reference or a raw pointer to `self` and call the target with `*self`.
|
2020-06-14 23:44:08 +02:00
|
|
|
///
|
|
|
|
|
/// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
|
2022-07-19 19:57:44 -04:00
|
|
|
/// (for `VTableShim`, which effectively is passed `&own Self`).
|
2023-06-19 09:06:32 +02:00
|
|
|
Deref { source: DerefSource },
|
2020-06-14 23:44:08 +02:00
|
|
|
|
|
|
|
|
/// We get passed `self: Self` and call the target with `&mut self`.
|
|
|
|
|
///
|
|
|
|
|
/// In this case we need to ensure that the `Self` is dropped after the call, as the callee
|
|
|
|
|
/// won't do it for us.
|
2017-03-08 23:19:09 +02:00
|
|
|
RefMut,
|
2017-03-08 18:33:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
2020-06-14 23:46:06 +02:00
|
|
|
enum CallKind<'tcx> {
|
2020-06-14 23:44:08 +02:00
|
|
|
/// Call the `FnPtr` that was passed as the receiver.
|
2020-06-14 23:46:06 +02:00
|
|
|
Indirect(Ty<'tcx>),
|
2020-06-14 23:44:08 +02:00
|
|
|
|
|
|
|
|
/// Call a known `FnDef`.
|
2017-03-08 18:33:21 +02:00
|
|
|
Direct(DefId),
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-11 23:52:51 +03:00
|
|
|
fn local_decls_for_sig<'tcx>(
|
|
|
|
|
sig: &ty::FnSig<'tcx>,
|
|
|
|
|
span: Span,
|
2017-02-07 22:46:21 +01:00
|
|
|
) -> IndexVec<Local, LocalDecl<'tcx>> {
|
2020-05-06 10:17:38 +10:00
|
|
|
iter::once(LocalDecl::new(sig.output(), span))
|
Overhaul `TyS` and `Ty`.
Specifically, change `Ty` from this:
```
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
```
to this
```
pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>);
```
There are two benefits to this.
- It's now a first class type, so we can define methods on it. This
means we can move a lot of methods away from `TyS`, leaving `TyS` as a
barely-used type, which is appropriate given that it's not meant to
be used directly.
- The uniqueness requirement is now explicit, via the `Interned` type.
E.g. the pointer-based `Eq` and `Hash` comes from `Interned`, rather
than via `TyS`, which wasn't obvious at all.
Much of this commit is boring churn. The interesting changes are in
these files:
- compiler/rustc_middle/src/arena.rs
- compiler/rustc_middle/src/mir/visit.rs
- compiler/rustc_middle/src/ty/context.rs
- compiler/rustc_middle/src/ty/mod.rs
Specifically:
- Most mentions of `TyS` are removed. It's very much a dumb struct now;
`Ty` has all the smarts.
- `TyS` now has `crate` visibility instead of `pub`.
- `TyS::make_for_test` is removed in favour of the static `BOOL_TY`,
which just works better with the new structure.
- The `Eq`/`Ord`/`Hash` impls are removed from `TyS`. `Interned`s impls
of `Eq`/`Hash` now suffice. `Ord` is now partly on `Interned`
(pointer-based, for the `Equal` case) and partly on `TyS`
(contents-based, for the other cases).
- There are many tedious sigil adjustments, i.e. adding or removing `*`
or `&`. They seem to be unavoidable.
2022-01-25 14:13:38 +11:00
|
|
|
.chain(sig.inputs().iter().map(|ity| LocalDecl::new(*ity, span).immutable()))
|
2017-03-08 18:33:21 +02:00
|
|
|
.collect()
|
2017-02-07 22:46:21 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-16 15:43:27 +07:00
|
|
|
fn dropee_emit_retag<'tcx>(
|
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
body: &mut Body<'tcx>,
|
2025-04-29 13:55:28 +00:00
|
|
|
mut dropee_ptr: Place<'tcx>,
|
2025-04-16 15:43:27 +07:00
|
|
|
span: Span,
|
|
|
|
|
) -> Place<'tcx> {
|
|
|
|
|
if tcx.sess.opts.unstable_opts.mir_emit_retag {
|
|
|
|
|
let source_info = SourceInfo::outermost(span);
|
|
|
|
|
// We want to treat the function argument as if it was passed by `&mut`. As such, we
|
|
|
|
|
// generate
|
|
|
|
|
// ```
|
|
|
|
|
// temp = &mut *arg;
|
|
|
|
|
// Retag(temp, FnEntry)
|
|
|
|
|
// ```
|
|
|
|
|
// It's important that we do this first, before anything that depends on `dropee_ptr`
|
|
|
|
|
// has been put into the body.
|
|
|
|
|
let reborrow = Rvalue::Ref(
|
|
|
|
|
tcx.lifetimes.re_erased,
|
|
|
|
|
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
|
|
|
|
tcx.mk_place_deref(dropee_ptr),
|
|
|
|
|
);
|
|
|
|
|
let ref_ty = reborrow.ty(body.local_decls(), tcx);
|
|
|
|
|
dropee_ptr = body.local_decls.push(LocalDecl::new(ref_ty, span)).into();
|
|
|
|
|
let new_statements = [
|
|
|
|
|
StatementKind::Assign(Box::new((dropee_ptr, reborrow))),
|
|
|
|
|
StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)),
|
|
|
|
|
];
|
|
|
|
|
for s in new_statements {
|
2025-06-08 15:30:18 +08:00
|
|
|
body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, s));
|
2025-04-16 15:43:27 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dropee_ptr
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-12 10:31:00 -07:00
|
|
|
fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) -> Body<'tcx> {
|
2017-03-14 01:08:21 +02:00
|
|
|
debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
|
|
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
assert!(!matches!(ty, Some(ty) if ty.is_coroutine()));
|
2016-12-26 14:34:03 +01:00
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
let args = if let Some(ty) = ty {
|
|
|
|
|
tcx.mk_args(&[ty.into()])
|
2017-03-14 01:08:21 +02:00
|
|
|
} else {
|
2023-07-11 22:35:29 +01:00
|
|
|
GenericArgs::identity_for_item(tcx, def_id)
|
2017-03-14 01:08:21 +02:00
|
|
|
};
|
2023-07-11 22:35:29 +01:00
|
|
|
let sig = tcx.fn_sig(def_id).instantiate(tcx, args);
|
2023-11-17 09:29:48 +00:00
|
|
|
let sig = tcx.instantiate_bound_regions_with_erased(sig);
|
2017-03-14 01:08:21 +02:00
|
|
|
let span = tcx.def_span(def_id);
|
|
|
|
|
|
2020-05-06 10:30:11 +10:00
|
|
|
let source_info = SourceInfo::outermost(span);
|
2017-03-14 01:08:21 +02:00
|
|
|
|
|
|
|
|
let return_block = BasicBlock::new(1);
|
2018-11-07 15:38:06 +01:00
|
|
|
let mut blocks = IndexVec::with_capacity(2);
|
2017-03-14 01:08:21 +02:00
|
|
|
let block = |blocks: &mut IndexVec<_, _>, kind| {
|
2025-06-16 22:31:25 +08:00
|
|
|
blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
|
2017-03-14 01:08:21 +02:00
|
|
|
};
|
|
|
|
|
block(&mut blocks, TerminatorKind::Goto { target: return_block });
|
|
|
|
|
block(&mut blocks, TerminatorKind::Return);
|
|
|
|
|
|
2024-06-16 21:35:16 -04:00
|
|
|
let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty));
|
2020-10-04 11:01:38 -07:00
|
|
|
let mut body =
|
2022-01-12 03:19:52 +00:00
|
|
|
new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
|
2019-10-25 10:01:08 -04:00
|
|
|
|
2022-12-06 01:18:24 -08:00
|
|
|
// The first argument (index 0), but add 1 for the return value.
|
2025-04-29 13:55:28 +00:00
|
|
|
let dropee_ptr = Place::from(Local::new(1 + 0));
|
|
|
|
|
let dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span);
|
2022-12-06 01:18:24 -08:00
|
|
|
|
|
|
|
|
if ty.is_some() {
|
2017-03-14 01:08:21 +02:00
|
|
|
let patch = {
|
2024-11-15 13:53:31 +01:00
|
|
|
let typing_env = ty::TypingEnv::post_analysis(tcx, def_id);
|
2024-08-26 16:45:15 +03:00
|
|
|
let mut elaborator = DropShimElaborator {
|
|
|
|
|
body: &body,
|
|
|
|
|
patch: MirPatch::new(&body),
|
|
|
|
|
tcx,
|
|
|
|
|
typing_env,
|
|
|
|
|
produce_async_drops: false,
|
|
|
|
|
};
|
2019-10-20 21:04:59 -04:00
|
|
|
let dropee = tcx.mk_place_deref(dropee_ptr);
|
2017-03-14 01:08:21 +02:00
|
|
|
let resume_block = elaborator.patch.resume_block();
|
2025-02-14 15:30:51 +11:00
|
|
|
elaborate_drop(
|
2017-03-14 01:08:21 +02:00
|
|
|
&mut elaborator,
|
|
|
|
|
source_info,
|
2020-03-30 20:25:43 -03:00
|
|
|
dropee,
|
2017-03-14 01:08:21 +02:00
|
|
|
(),
|
|
|
|
|
return_block,
|
2025-02-14 15:30:51 +11:00
|
|
|
Unwind::To(resume_block),
|
2017-03-14 01:08:21 +02:00
|
|
|
START_BLOCK,
|
2024-08-26 16:45:15 +03:00
|
|
|
None,
|
2017-03-14 01:08:21 +02:00
|
|
|
);
|
|
|
|
|
elaborator.patch
|
|
|
|
|
};
|
2019-11-06 12:00:46 -05:00
|
|
|
patch.apply(&mut body);
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 12:00:46 -05:00
|
|
|
body
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-26 10:46:49 +00:00
|
|
|
fn new_body<'tcx>(
|
2020-10-04 11:01:38 -07:00
|
|
|
source: MirSource<'tcx>,
|
2019-11-26 10:46:49 +00:00
|
|
|
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
|
|
|
|
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
|
|
|
|
arg_count: usize,
|
|
|
|
|
span: Span,
|
2019-11-26 01:31:27 +00:00
|
|
|
) -> Body<'tcx> {
|
2024-08-01 14:01:17 +02:00
|
|
|
let mut body = Body::new(
|
2020-10-04 11:01:38 -07:00
|
|
|
source,
|
2019-11-26 01:31:27 +00:00
|
|
|
basic_blocks,
|
2019-11-26 19:55:03 +02:00
|
|
|
IndexVec::from_elem_n(
|
2020-02-08 21:31:09 +02:00
|
|
|
SourceScopeData {
|
|
|
|
|
span,
|
|
|
|
|
parent_scope: None,
|
|
|
|
|
inlined: None,
|
2020-09-21 06:52:37 +03:00
|
|
|
inlined_parent_scope: None,
|
2020-02-08 21:31:09 +02:00
|
|
|
local_data: ClearCrossCrate::Clear,
|
|
|
|
|
},
|
2019-11-26 22:17:35 +02:00
|
|
|
1,
|
2019-11-26 19:55:03 +02:00
|
|
|
),
|
2019-11-26 01:31:27 +00:00
|
|
|
local_decls,
|
|
|
|
|
IndexVec::new(),
|
|
|
|
|
arg_count,
|
|
|
|
|
vec![],
|
|
|
|
|
span,
|
|
|
|
|
None,
|
2022-02-07 22:00:15 -08:00
|
|
|
// FIXME(compiler-errors): is this correct?
|
|
|
|
|
None,
|
2024-08-01 14:01:17 +02:00
|
|
|
);
|
|
|
|
|
// Shims do not directly mention any consts.
|
|
|
|
|
body.set_required_consts(Vec::new());
|
|
|
|
|
body
|
2019-11-26 01:31:27 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 09:39:59 +10:00
|
|
|
pub(super) struct DropShimElaborator<'a, 'tcx> {
|
2019-06-03 18:26:48 -04:00
|
|
|
pub body: &'a Body<'tcx>,
|
2016-12-26 14:34:03 +01:00
|
|
|
pub patch: MirPatch<'tcx>,
|
2019-06-14 00:48:52 +03:00
|
|
|
pub tcx: TyCtxt<'tcx>,
|
2024-11-15 13:53:31 +01:00
|
|
|
pub typing_env: ty::TypingEnv<'tcx>,
|
2024-08-26 16:45:15 +03:00
|
|
|
pub produce_async_drops: bool,
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-06 00:48:37 -08:00
|
|
|
impl fmt::Debug for DropShimElaborator<'_, '_> {
|
2025-07-18 14:00:00 -07:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
|
|
|
|
f.debug_struct("DropShimElaborator").finish_non_exhaustive()
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
|
|
|
|
|
type Path = ();
|
|
|
|
|
|
2025-02-15 22:39:56 -08:00
|
|
|
fn patch_ref(&self) -> &MirPatch<'tcx> {
|
|
|
|
|
&self.patch
|
|
|
|
|
}
|
2017-03-14 01:08:21 +02:00
|
|
|
fn patch(&mut self) -> &mut MirPatch<'tcx> {
|
|
|
|
|
&mut self.patch
|
|
|
|
|
}
|
2019-06-03 18:26:48 -04:00
|
|
|
fn body(&self) -> &'a Body<'tcx> {
|
|
|
|
|
self.body
|
|
|
|
|
}
|
2019-06-14 00:48:52 +03:00
|
|
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
2019-06-12 00:11:55 +03:00
|
|
|
self.tcx
|
|
|
|
|
}
|
2024-11-15 13:53:31 +01:00
|
|
|
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
|
|
|
|
|
self.typing_env
|
2017-05-15 17:57:30 -04:00
|
|
|
}
|
2017-03-14 01:08:21 +02:00
|
|
|
|
2024-08-26 16:45:15 +03:00
|
|
|
fn terminator_loc(&self, bb: BasicBlock) -> Location {
|
|
|
|
|
self.patch.terminator_loc(self.body, bb)
|
|
|
|
|
}
|
|
|
|
|
fn allow_async_drops(&self) -> bool {
|
|
|
|
|
self.produce_async_drops
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-14 01:08:21 +02:00
|
|
|
fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
|
2020-05-16 22:10:05 +02:00
|
|
|
match mode {
|
|
|
|
|
DropFlagMode::Shallow => {
|
|
|
|
|
// Drops for the contained fields are "shallow" and "static" - they will simply call
|
|
|
|
|
// the field's own drop glue.
|
|
|
|
|
DropStyle::Static
|
|
|
|
|
}
|
|
|
|
|
DropFlagMode::Deep => {
|
|
|
|
|
// The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
|
|
|
|
|
// dropping each field contained in the value.
|
|
|
|
|
DropStyle::Open
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {}
|
|
|
|
|
|
2023-03-28 12:32:57 -07:00
|
|
|
fn field_subpath(&self, _path: Self::Path, _field: FieldIdx) -> Option<Self::Path> {
|
2017-03-14 01:08:21 +02:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
|
|
|
|
|
None
|
|
|
|
|
}
|
2018-11-01 19:03:38 +01:00
|
|
|
fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option<Self::Path> {
|
2017-03-14 01:08:21 +02:00
|
|
|
Some(())
|
|
|
|
|
}
|
2020-08-23 14:54:58 +02:00
|
|
|
fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option<Self::Path> {
|
2017-11-28 15:48:23 +03:00
|
|
|
None
|
|
|
|
|
}
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-16 21:35:16 -04:00
|
|
|
fn build_thread_local_shim<'tcx>(
|
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
instance: ty::InstanceKind<'tcx>,
|
|
|
|
|
) -> Body<'tcx> {
|
2023-02-03 09:04:12 +01:00
|
|
|
let def_id = instance.def_id();
|
|
|
|
|
|
|
|
|
|
let span = tcx.def_span(def_id);
|
|
|
|
|
let source_info = SourceInfo::outermost(span);
|
|
|
|
|
|
2025-06-16 22:31:25 +08:00
|
|
|
let blocks = IndexVec::from_raw(vec![BasicBlockData::new_stmts(
|
|
|
|
|
vec![Statement::new(
|
2023-02-03 09:04:12 +01:00
|
|
|
source_info,
|
2025-06-08 15:30:18 +08:00
|
|
|
StatementKind::Assign(Box::new((
|
2023-02-03 09:04:12 +01:00
|
|
|
Place::return_place(),
|
|
|
|
|
Rvalue::ThreadLocalRef(def_id),
|
|
|
|
|
))),
|
2025-06-08 15:30:18 +08:00
|
|
|
)],
|
2025-06-16 22:31:25 +08:00
|
|
|
Some(Terminator { source_info, kind: TerminatorKind::Return }),
|
|
|
|
|
false,
|
|
|
|
|
)]);
|
2023-02-03 09:04:12 +01:00
|
|
|
|
|
|
|
|
new_body(
|
|
|
|
|
MirSource::from_instance(instance),
|
|
|
|
|
blocks,
|
|
|
|
|
IndexVec::from_raw(vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]),
|
|
|
|
|
0,
|
|
|
|
|
span,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
|
2020-04-12 10:31:00 -07:00
|
|
|
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
|
2017-08-04 14:44:12 +02:00
|
|
|
debug!("build_clone_shim(def_id={:?})", def_id);
|
|
|
|
|
|
2018-01-30 14:47:25 +05:30
|
|
|
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
|
2017-08-09 13:55:27 +02:00
|
|
|
|
2019-07-30 00:07:28 +02:00
|
|
|
let dest = Place::return_place();
|
2019-10-20 21:04:59 -04:00
|
|
|
let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
|
2018-01-30 17:36:19 +05:30
|
|
|
|
2020-08-03 00:49:11 +02:00
|
|
|
match self_ty.kind() {
|
2024-08-08 17:18:20 +10:00
|
|
|
ty::FnDef(..) | ty::FnPtr(..) => builder.copy_shim(),
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Closure(_, args) => builder.tuple_like_shim(dest, src, args.as_closure().upvar_tys()),
|
2024-07-25 14:02:33 -04:00
|
|
|
ty::CoroutineClosure(_, args) => {
|
|
|
|
|
builder.tuple_like_shim(dest, src, args.as_coroutine_closure().upvar_tys())
|
|
|
|
|
}
|
2019-08-07 09:01:53 +02:00
|
|
|
ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
|
2023-12-21 01:52:10 +00:00
|
|
|
ty::Coroutine(coroutine_def_id, args) => {
|
2023-12-26 22:43:11 +00:00
|
|
|
assert_eq!(tcx.coroutine_movability(*coroutine_def_id), hir::Movability::Movable);
|
2023-10-30 23:35:35 +00:00
|
|
|
builder.coroutine_shim(dest, src, *coroutine_def_id, args.as_coroutine())
|
2022-03-13 13:39:20 +08:00
|
|
|
}
|
2017-09-13 22:40:48 +02:00
|
|
|
_ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty),
|
2017-08-09 13:55:27 +02:00
|
|
|
};
|
2017-08-04 14:44:12 +02:00
|
|
|
|
2020-04-12 10:31:00 -07:00
|
|
|
builder.into_mir()
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
2017-08-08 17:13:12 +02:00
|
|
|
|
2019-06-11 22:03:44 +03:00
|
|
|
struct CloneShimBuilder<'tcx> {
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2017-08-09 13:55:27 +02:00
|
|
|
def_id: DefId,
|
|
|
|
|
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
|
|
|
|
blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
|
|
|
|
span: Span,
|
|
|
|
|
sig: ty::FnSig<'tcx>,
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-06 00:48:37 -08:00
|
|
|
impl<'tcx> CloneShimBuilder<'tcx> {
|
2019-06-14 00:48:52 +03:00
|
|
|
fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
|
2024-02-12 15:39:32 +09:00
|
|
|
// we must instantiate the self_ty because it's
|
2018-01-30 14:47:25 +05:30
|
|
|
// otherwise going to be TySelf and we can't index
|
|
|
|
|
// or access fields of a Place of type TySelf.
|
2023-07-11 22:35:29 +01:00
|
|
|
let sig = tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]);
|
2023-11-17 09:29:48 +00:00
|
|
|
let sig = tcx.instantiate_bound_regions_with_erased(sig);
|
2017-08-09 13:55:27 +02:00
|
|
|
let span = tcx.def_span(def_id);
|
|
|
|
|
|
|
|
|
|
CloneShimBuilder {
|
|
|
|
|
tcx,
|
|
|
|
|
def_id,
|
|
|
|
|
local_decls: local_decls_for_sig(&sig, span),
|
|
|
|
|
blocks: IndexVec::new(),
|
|
|
|
|
span,
|
|
|
|
|
sig,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-17 23:55:04 +02:00
|
|
|
fn into_mir(self) -> Body<'tcx> {
|
2024-06-16 21:35:16 -04:00
|
|
|
let source = MirSource::from_instance(ty::InstanceKind::CloneShim(
|
2020-10-04 11:01:38 -07:00
|
|
|
self.def_id,
|
|
|
|
|
self.sig.inputs_and_output[0],
|
|
|
|
|
));
|
2022-01-12 03:19:52 +00:00
|
|
|
new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn source_info(&self) -> SourceInfo {
|
2020-05-06 10:30:11 +10:00
|
|
|
SourceInfo::outermost(self.span)
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn block(
|
|
|
|
|
&mut self,
|
|
|
|
|
statements: Vec<Statement<'tcx>>,
|
|
|
|
|
kind: TerminatorKind<'tcx>,
|
|
|
|
|
is_cleanup: bool,
|
|
|
|
|
) -> BasicBlock {
|
|
|
|
|
let source_info = self.source_info();
|
2025-06-16 22:31:25 +08:00
|
|
|
self.blocks.push(BasicBlockData::new_stmts(
|
2017-08-08 17:13:12 +02:00
|
|
|
statements,
|
2025-06-16 22:31:25 +08:00
|
|
|
Some(Terminator { source_info, kind }),
|
2017-08-08 17:13:12 +02:00
|
|
|
is_cleanup,
|
2025-06-16 22:31:25 +08:00
|
|
|
))
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-30 17:36:19 +05:30
|
|
|
/// Gives the index of an upcoming BasicBlock, with an offset.
|
|
|
|
|
/// offset=0 will give you the index of the next BasicBlock,
|
|
|
|
|
/// offset=1 will give the index of the next-to-next block,
|
|
|
|
|
/// offset=-1 will give you the index of the last-created block
|
2022-03-13 13:39:20 +08:00
|
|
|
fn block_index_offset(&self, offset: usize) -> BasicBlock {
|
2018-01-30 17:36:19 +05:30
|
|
|
BasicBlock::new(self.blocks.len() + offset)
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-09 13:55:27 +02:00
|
|
|
fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
|
2025-06-08 15:30:18 +08:00
|
|
|
Statement::new(self.source_info(), kind)
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn copy_shim(&mut self) {
|
2019-10-20 21:04:59 -04:00
|
|
|
let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
|
2021-08-05 05:36:38 +02:00
|
|
|
let ret_statement = self.make_statement(StatementKind::Assign(Box::new((
|
2019-09-11 16:05:45 -03:00
|
|
|
Place::return_place(),
|
|
|
|
|
Rvalue::Use(Operand::Copy(rcvr)),
|
2021-08-05 05:36:38 +02:00
|
|
|
))));
|
2017-08-09 13:55:27 +02:00
|
|
|
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
|
|
|
|
}
|
2017-08-04 14:44:12 +02:00
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
|
2017-08-09 13:55:27 +02:00
|
|
|
let span = self.span;
|
2020-05-06 10:17:38 +10:00
|
|
|
let mut local = LocalDecl::new(ty, span);
|
2023-01-30 12:00:11 +00:00
|
|
|
if mutability.is_not() {
|
2020-05-06 10:17:38 +10:00
|
|
|
local = local.immutable();
|
|
|
|
|
}
|
|
|
|
|
Place::from(self.local_decls.push(local))
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn make_clone_call(
|
|
|
|
|
&mut self,
|
2018-01-30 17:24:56 +05:30
|
|
|
dest: Place<'tcx>,
|
|
|
|
|
src: Place<'tcx>,
|
2017-09-14 21:44:23 -04:00
|
|
|
ty: Ty<'tcx>,
|
2017-08-09 13:55:27 +02:00
|
|
|
next: BasicBlock,
|
2018-01-30 17:24:56 +05:30
|
|
|
cleanup: BasicBlock,
|
2018-01-30 10:38:54 +05:30
|
|
|
) {
|
2017-08-09 13:55:27 +02:00
|
|
|
let tcx = self.tcx;
|
|
|
|
|
|
2017-08-04 14:44:12 +02:00
|
|
|
// `func == Clone::clone(&ty) -> ty`
|
2023-07-05 20:13:26 +01:00
|
|
|
let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]);
|
2023-09-20 20:51:14 +02:00
|
|
|
let func = Operand::Constant(Box::new(ConstOperand {
|
2017-08-09 13:55:27 +02:00
|
|
|
span: self.span,
|
2018-08-09 06:18:00 -04:00
|
|
|
user_ty: None,
|
2023-09-20 20:51:14 +02:00
|
|
|
const_: Const::zero_sized(func_ty),
|
2021-08-05 05:36:38 +02:00
|
|
|
}));
|
2017-08-04 14:44:12 +02:00
|
|
|
|
2024-03-21 16:50:21 -04:00
|
|
|
let ref_loc =
|
|
|
|
|
self.make_place(Mutability::Not, Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty));
|
2017-08-04 14:44:12 +02:00
|
|
|
|
2018-01-30 17:24:56 +05:30
|
|
|
// `let ref_loc: &ty = &src;`
|
2021-08-05 05:36:38 +02:00
|
|
|
let statement = self.make_statement(StatementKind::Assign(Box::new((
|
2020-01-22 16:30:15 +01:00
|
|
|
ref_loc,
|
2019-09-11 16:05:45 -03:00
|
|
|
Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src),
|
2021-08-05 05:36:38 +02:00
|
|
|
))));
|
2017-08-04 14:44:12 +02:00
|
|
|
|
|
|
|
|
// `let loc = Clone::clone(ref_loc);`
|
2017-08-09 13:55:27 +02:00
|
|
|
self.block(
|
|
|
|
|
vec![statement],
|
|
|
|
|
TerminatorKind::Call {
|
2017-08-04 14:44:12 +02:00
|
|
|
func,
|
2024-06-21 02:20:18 -07:00
|
|
|
args: [Spanned { node: Operand::Move(ref_loc), span: DUMMY_SP }].into(),
|
2022-04-16 09:27:54 -04:00
|
|
|
destination: dest,
|
|
|
|
|
target: Some(next),
|
2022-10-08 23:47:59 +01:00
|
|
|
unwind: UnwindAction::Cleanup(cleanup),
|
2023-06-18 05:24:38 +00:00
|
|
|
call_source: CallSource::Normal,
|
2020-06-09 15:34:23 -04:00
|
|
|
fn_span: self.span,
|
2017-08-08 17:13:12 +02:00
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
);
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
2017-08-04 14:44:12 +02:00
|
|
|
|
2022-03-13 13:39:20 +08:00
|
|
|
fn clone_fields<I>(
|
|
|
|
|
&mut self,
|
|
|
|
|
dest: Place<'tcx>,
|
|
|
|
|
src: Place<'tcx>,
|
|
|
|
|
target: BasicBlock,
|
|
|
|
|
mut unwind: BasicBlock,
|
|
|
|
|
tys: I,
|
|
|
|
|
) -> BasicBlock
|
2019-04-26 14:26:49 +02:00
|
|
|
where
|
2022-02-07 16:06:31 +01:00
|
|
|
I: IntoIterator<Item = Ty<'tcx>>,
|
2019-04-26 14:26:49 +02:00
|
|
|
{
|
2022-04-10 14:04:44 +08:00
|
|
|
// For an iterator of length n, create 2*n + 1 blocks.
|
2022-02-07 16:06:31 +01:00
|
|
|
for (i, ity) in tys.into_iter().enumerate() {
|
2022-04-10 14:04:44 +08:00
|
|
|
// Each iteration creates two blocks, referred to here as block 2*i and block 2*i + 1.
|
|
|
|
|
//
|
|
|
|
|
// Block 2*i attempts to clone the field. If successful it branches to 2*i + 2 (the
|
|
|
|
|
// next clone block). If unsuccessful it branches to the previous unwind block, which
|
|
|
|
|
// is initially the `unwind` argument passed to this function.
|
|
|
|
|
//
|
|
|
|
|
// Block 2*i + 1 is the unwind block for this iteration. It drops the cloned value
|
|
|
|
|
// created by block 2*i. We store this block in `unwind` so that the next clone block
|
|
|
|
|
// will unwind to it if cloning fails.
|
|
|
|
|
|
2023-03-28 12:32:57 -07:00
|
|
|
let field = FieldIdx::new(i);
|
2020-04-16 00:00:22 +02:00
|
|
|
let src_field = self.tcx.mk_place_field(src, field, ity);
|
2018-01-30 17:36:19 +05:30
|
|
|
|
2020-04-16 00:00:22 +02:00
|
|
|
let dest_field = self.tcx.mk_place_field(dest, field, ity);
|
2017-08-09 13:55:27 +02:00
|
|
|
|
2022-03-13 13:39:20 +08:00
|
|
|
let next_unwind = self.block_index_offset(1);
|
2018-01-30 17:36:19 +05:30
|
|
|
let next_block = self.block_index_offset(2);
|
2022-03-13 13:39:20 +08:00
|
|
|
self.make_clone_call(dest_field, src_field, ity, next_block, unwind);
|
|
|
|
|
self.block(
|
|
|
|
|
vec![],
|
2022-10-08 23:47:59 +01:00
|
|
|
TerminatorKind::Drop {
|
|
|
|
|
place: dest_field,
|
|
|
|
|
target: unwind,
|
2023-08-21 09:57:10 +02:00
|
|
|
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
2023-05-25 17:30:23 +00:00
|
|
|
replace: false,
|
2024-08-26 16:45:15 +03:00
|
|
|
drop: None,
|
|
|
|
|
async_fut: None,
|
2022-10-08 23:47:59 +01:00
|
|
|
},
|
2023-08-21 09:57:10 +02:00
|
|
|
/* is_cleanup */ true,
|
2022-03-13 13:39:20 +08:00
|
|
|
);
|
|
|
|
|
unwind = next_unwind;
|
|
|
|
|
}
|
2022-04-10 14:04:44 +08:00
|
|
|
// If all clones succeed then we end up here.
|
2022-03-21 12:57:06 +08:00
|
|
|
self.block(vec![], TerminatorKind::Goto { target }, false);
|
2022-03-13 13:39:20 +08:00
|
|
|
unwind
|
|
|
|
|
}
|
2018-01-30 10:38:54 +05:30
|
|
|
|
2022-03-13 13:39:20 +08:00
|
|
|
fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
|
|
|
|
|
where
|
|
|
|
|
I: IntoIterator<Item = Ty<'tcx>>,
|
|
|
|
|
{
|
2022-03-21 12:57:06 +08:00
|
|
|
self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false);
|
2023-08-19 13:10:25 +02:00
|
|
|
let unwind = self.block(vec![], TerminatorKind::UnwindResume, true);
|
2022-03-13 13:39:20 +08:00
|
|
|
let target = self.block(vec![], TerminatorKind::Return, false);
|
2018-01-30 10:51:48 +05:30
|
|
|
|
2022-03-13 13:39:20 +08:00
|
|
|
let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, tys);
|
|
|
|
|
}
|
2017-08-04 14:44:12 +02:00
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
fn coroutine_shim(
|
2022-03-13 13:39:20 +08:00
|
|
|
&mut self,
|
|
|
|
|
dest: Place<'tcx>,
|
|
|
|
|
src: Place<'tcx>,
|
2023-10-30 23:35:35 +00:00
|
|
|
coroutine_def_id: DefId,
|
2024-05-31 14:13:46 -04:00
|
|
|
args: CoroutineArgs<TyCtxt<'tcx>>,
|
2022-03-13 13:39:20 +08:00
|
|
|
) {
|
2022-03-21 12:57:06 +08:00
|
|
|
self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false);
|
2023-08-19 13:10:25 +02:00
|
|
|
let unwind = self.block(vec![], TerminatorKind::UnwindResume, true);
|
2022-03-13 13:39:20 +08:00
|
|
|
// This will get overwritten with a switch once we know the target blocks
|
|
|
|
|
let switch = self.block(vec![], TerminatorKind::Unreachable, false);
|
2023-07-11 22:35:29 +01:00
|
|
|
let unwind = self.clone_fields(dest, src, switch, unwind, args.upvar_tys());
|
2022-03-13 13:39:20 +08:00
|
|
|
let target = self.block(vec![], TerminatorKind::Return, false);
|
|
|
|
|
let unreachable = self.block(vec![], TerminatorKind::Unreachable, false);
|
2023-10-30 23:35:35 +00:00
|
|
|
let mut cases = Vec::with_capacity(args.state_tys(coroutine_def_id, self.tcx).count());
|
|
|
|
|
for (index, state_tys) in args.state_tys(coroutine_def_id, self.tcx).enumerate() {
|
2022-03-13 13:39:20 +08:00
|
|
|
let variant_index = VariantIdx::new(index);
|
|
|
|
|
let dest = self.tcx.mk_place_downcast_unnamed(dest, variant_index);
|
|
|
|
|
let src = self.tcx.mk_place_downcast_unnamed(src, variant_index);
|
|
|
|
|
let clone_block = self.block_index_offset(1);
|
2022-04-10 14:05:31 +08:00
|
|
|
let start_block = self.block(
|
2022-03-13 13:39:20 +08:00
|
|
|
vec![self.make_statement(StatementKind::SetDiscriminant {
|
|
|
|
|
place: Box::new(Place::return_place()),
|
|
|
|
|
variant_index,
|
|
|
|
|
})],
|
|
|
|
|
TerminatorKind::Goto { target: clone_block },
|
|
|
|
|
false,
|
|
|
|
|
);
|
2022-04-10 14:05:31 +08:00
|
|
|
cases.push((index as u128, start_block));
|
2022-03-13 13:39:20 +08:00
|
|
|
let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, state_tys);
|
|
|
|
|
}
|
2023-07-11 22:35:29 +01:00
|
|
|
let discr_ty = args.discr_ty(self.tcx);
|
2022-03-13 13:39:20 +08:00
|
|
|
let temp = self.make_place(Mutability::Mut, discr_ty);
|
|
|
|
|
let rvalue = Rvalue::Discriminant(src);
|
|
|
|
|
let statement = self.make_statement(StatementKind::Assign(Box::new((temp, rvalue))));
|
|
|
|
|
match &mut self.blocks[switch] {
|
|
|
|
|
BasicBlockData { statements, terminator: Some(Terminator { kind, .. }), .. } => {
|
|
|
|
|
statements.push(statement);
|
|
|
|
|
*kind = TerminatorKind::SwitchInt {
|
|
|
|
|
discr: Operand::Move(temp),
|
|
|
|
|
targets: SwitchTargets::new(cases.into_iter(), unreachable),
|
|
|
|
|
};
|
2022-03-21 12:57:06 +08:00
|
|
|
}
|
2022-03-13 13:39:20 +08:00
|
|
|
BasicBlockData { terminator: None, .. } => unreachable!(),
|
|
|
|
|
}
|
2017-08-09 13:55:27 +02:00
|
|
|
}
|
2017-08-04 14:44:12 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-09 20:08:45 +01:00
|
|
|
/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`,
|
|
|
|
|
/// first adjusting its first argument according to `rcvr_adjustment`.
|
2022-10-20 09:39:09 +00:00
|
|
|
#[instrument(level = "debug", skip(tcx), ret)]
|
2019-06-12 00:11:55 +03:00
|
|
|
fn build_call_shim<'tcx>(
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2024-06-16 21:35:16 -04:00
|
|
|
instance: ty::InstanceKind<'tcx>,
|
2020-01-19 21:21:48 +02:00
|
|
|
rcvr_adjustment: Option<Adjustment>,
|
2020-06-14 23:46:06 +02:00
|
|
|
call_kind: CallKind<'tcx>,
|
2020-04-12 10:31:00 -07:00
|
|
|
) -> Body<'tcx> {
|
2020-08-09 20:08:45 +01:00
|
|
|
// `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used
|
2024-02-12 15:39:32 +09:00
|
|
|
// to instantiate into the signature of the shim. It is not necessary for users of this
|
2024-06-16 21:35:16 -04:00
|
|
|
// MIR body to perform further instantiations (see `InstanceKind::has_polymorphic_mir_body`).
|
|
|
|
|
let (sig_args, untuple_args) = if let ty::InstanceKind::FnPtrShim(_, ty) = instance {
|
2023-11-17 09:29:48 +00:00
|
|
|
let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx));
|
2020-08-09 20:08:45 +01:00
|
|
|
|
|
|
|
|
let untuple_args = sig.inputs();
|
|
|
|
|
|
|
|
|
|
// Create substitutions for the `Self` and `Args` generic parameters of the shim body.
|
2023-07-05 20:13:26 +01:00
|
|
|
let arg_tup = Ty::new_tup(tcx, untuple_args);
|
2020-08-09 20:08:45 +01:00
|
|
|
|
2022-12-13 10:44:35 +00:00
|
|
|
(Some([ty.into(), arg_tup.into()]), Some(untuple_args))
|
2020-08-09 20:08:45 +01:00
|
|
|
} else {
|
|
|
|
|
(None, None)
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-03 12:54:47 +02:00
|
|
|
let def_id = instance.def_id();
|
2024-11-16 20:18:13 +00:00
|
|
|
|
2023-01-18 16:52:47 -07:00
|
|
|
let sig = tcx.fn_sig(def_id);
|
2023-11-17 09:29:48 +00:00
|
|
|
let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig));
|
2019-12-03 12:54:47 +02:00
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
assert_eq!(sig_args.is_some(), !instance.has_polymorphic_mir_body());
|
|
|
|
|
let mut sig = if let Some(sig_args) = sig_args {
|
|
|
|
|
sig.instantiate(tcx, &sig_args)
|
2023-05-26 12:14:48 -06:00
|
|
|
} else {
|
2023-07-11 22:35:29 +01:00
|
|
|
sig.instantiate_identity()
|
2023-05-26 12:14:48 -06:00
|
|
|
};
|
2020-08-09 20:08:45 +01:00
|
|
|
|
2020-06-14 23:46:06 +02:00
|
|
|
if let CallKind::Indirect(fnty) = call_kind {
|
|
|
|
|
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
|
|
|
|
|
// can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
|
|
|
|
|
// the implemented `FnX` trait.
|
|
|
|
|
|
|
|
|
|
// Apply the opposite adjustment to the MIR input.
|
|
|
|
|
let mut inputs_and_output = sig.inputs_and_output.to_vec();
|
|
|
|
|
|
|
|
|
|
// Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
|
|
|
|
|
// fn arguments. `Self` may be passed via (im)mutable reference or by-value.
|
|
|
|
|
assert_eq!(inputs_and_output.len(), 3);
|
|
|
|
|
|
|
|
|
|
// `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
|
|
|
|
|
// `FnDef` and `FnPtr` callees, not the `Self` type param.
|
|
|
|
|
let self_arg = &mut inputs_and_output[0];
|
|
|
|
|
*self_arg = match rcvr_adjustment.unwrap() {
|
|
|
|
|
Adjustment::Identity => fnty,
|
2023-06-19 09:06:32 +02:00
|
|
|
Adjustment::Deref { source } => match source {
|
2023-07-05 20:13:26 +01:00
|
|
|
DerefSource::ImmRef => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fnty),
|
|
|
|
|
DerefSource::MutRef => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fnty),
|
|
|
|
|
DerefSource::MutPtr => Ty::new_mut_ptr(tcx, fnty),
|
2023-06-19 09:06:32 +02:00
|
|
|
},
|
|
|
|
|
Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {instance:?}"),
|
2020-06-14 23:46:06 +02:00
|
|
|
};
|
2023-02-17 14:33:08 +11:00
|
|
|
sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
|
2020-06-14 23:46:06 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-16 19:00:28 +00:00
|
|
|
// FIXME: Avoid having to adjust the signature both here and in
|
|
|
|
|
// `fn_sig_for_fn_abi`.
|
2024-06-16 21:35:16 -04:00
|
|
|
if let ty::InstanceKind::VTableShim(..) = instance {
|
2019-12-03 12:54:47 +02:00
|
|
|
// Modify fn(self, ...) to fn(self: *mut Self, ...)
|
|
|
|
|
let mut inputs_and_output = sig.inputs_and_output.to_vec();
|
|
|
|
|
let self_arg = &mut inputs_and_output[0];
|
|
|
|
|
debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param);
|
2023-07-05 20:13:26 +01:00
|
|
|
*self_arg = Ty::new_mut_ptr(tcx, *self_arg);
|
2023-02-17 14:33:08 +11:00
|
|
|
sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
|
2019-12-03 12:54:47 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-08 18:33:21 +02:00
|
|
|
let span = tcx.def_span(def_id);
|
2017-03-06 12:58:51 +02:00
|
|
|
|
2022-10-20 09:39:09 +00:00
|
|
|
debug!(?sig);
|
2017-03-06 12:58:51 +02:00
|
|
|
|
2017-04-11 23:52:51 +03:00
|
|
|
let mut local_decls = local_decls_for_sig(&sig, span);
|
2020-05-06 10:30:11 +10:00
|
|
|
let source_info = SourceInfo::outermost(span);
|
2017-03-06 12:58:51 +02:00
|
|
|
|
2025-03-18 16:17:18 +00:00
|
|
|
let destination = Place::return_place();
|
2024-11-16 20:18:13 +00:00
|
|
|
|
2020-01-19 21:21:48 +02:00
|
|
|
let rcvr_place = || {
|
|
|
|
|
assert!(rcvr_adjustment.is_some());
|
2024-11-16 20:18:13 +00:00
|
|
|
Place::from(Local::new(1))
|
2020-01-19 21:21:48 +02:00
|
|
|
};
|
2017-03-08 23:19:09 +02:00
|
|
|
let mut statements = vec![];
|
2017-03-06 12:58:51 +02:00
|
|
|
|
2020-01-19 21:21:48 +02:00
|
|
|
let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
|
|
|
|
|
Adjustment::Identity => Operand::Move(rcvr_place()),
|
2023-06-19 09:06:32 +02:00
|
|
|
Adjustment::Deref { source: _ } => Operand::Move(tcx.mk_place_deref(rcvr_place())),
|
2017-03-08 23:19:09 +02:00
|
|
|
Adjustment::RefMut => {
|
|
|
|
|
// let rcvr = &mut rcvr;
|
2020-05-06 10:17:38 +10:00
|
|
|
let ref_rcvr = local_decls.push(
|
|
|
|
|
LocalDecl::new(
|
2024-03-21 16:50:21 -04:00
|
|
|
Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, sig.inputs()[0]),
|
2020-05-06 10:17:38 +10:00
|
|
|
span,
|
|
|
|
|
)
|
|
|
|
|
.immutable(),
|
|
|
|
|
);
|
2023-05-31 06:25:27 +08:00
|
|
|
let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default };
|
2025-06-08 15:30:18 +08:00
|
|
|
statements.push(Statement::new(
|
2017-08-06 22:54:09 -07:00
|
|
|
source_info,
|
2025-06-08 15:30:18 +08:00
|
|
|
StatementKind::Assign(Box::new((
|
2019-09-11 16:05:45 -03:00
|
|
|
Place::from(ref_rcvr),
|
2020-01-19 21:21:48 +02:00
|
|
|
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
|
2021-08-05 05:36:38 +02:00
|
|
|
))),
|
2025-06-08 15:30:18 +08:00
|
|
|
));
|
2019-06-24 17:46:09 +02:00
|
|
|
Operand::Move(Place::from(ref_rcvr))
|
2017-03-08 23:19:09 +02:00
|
|
|
}
|
2020-01-19 21:21:48 +02:00
|
|
|
});
|
2017-03-08 18:33:21 +02:00
|
|
|
|
|
|
|
|
let (callee, mut args) = match call_kind {
|
2020-06-14 23:44:08 +02:00
|
|
|
// `FnPtr` call has no receiver. Args are untupled below.
|
2020-06-14 23:46:06 +02:00
|
|
|
CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
|
2020-06-14 23:44:08 +02:00
|
|
|
|
|
|
|
|
// `FnDef` call with optional receiver.
|
2017-08-04 11:25:13 +03:00
|
|
|
CallKind::Direct(def_id) => {
|
2023-07-11 22:35:29 +01:00
|
|
|
let ty = tcx.type_of(def_id).instantiate_identity();
|
2017-08-04 11:25:13 +03:00
|
|
|
(
|
2023-09-20 20:51:14 +02:00
|
|
|
Operand::Constant(Box::new(ConstOperand {
|
2017-08-06 22:54:09 -07:00
|
|
|
span,
|
2018-08-09 06:18:00 -04:00
|
|
|
user_ty: None,
|
2023-09-20 20:51:14 +02:00
|
|
|
const_: Const::zero_sized(ty),
|
2021-08-05 05:36:38 +02:00
|
|
|
})),
|
2020-01-19 21:21:48 +02:00
|
|
|
rcvr.into_iter().collect::<Vec<_>>(),
|
2017-08-04 11:25:13 +03:00
|
|
|
)
|
|
|
|
|
}
|
2017-03-08 18:33:21 +02:00
|
|
|
};
|
|
|
|
|
|
2020-01-19 21:21:48 +02:00
|
|
|
let mut arg_range = 0..sig.inputs().len();
|
|
|
|
|
|
|
|
|
|
// Take the `self` ("receiver") argument out of the range (it's adjusted above).
|
|
|
|
|
if rcvr_adjustment.is_some() {
|
|
|
|
|
arg_range.start += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Take the last argument, if we need to untuple it (handled below).
|
|
|
|
|
if untuple_args.is_some() {
|
|
|
|
|
arg_range.end -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pass all of the non-special arguments directly.
|
|
|
|
|
args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
|
|
|
|
|
|
|
|
|
|
// Untuple the last argument, if we have to.
|
2017-03-08 18:33:21 +02:00
|
|
|
if let Some(untuple_args) = untuple_args {
|
2020-01-19 21:21:48 +02:00
|
|
|
let tuple_arg = Local::new(1 + (sig.inputs().len() - 1));
|
2017-03-08 18:33:21 +02:00
|
|
|
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
|
2023-03-28 12:32:57 -07:00
|
|
|
Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), FieldIdx::new(i), *ity))
|
2017-03-08 18:33:21 +02:00
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-19 21:21:48 +02:00
|
|
|
let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
|
2018-11-07 15:38:06 +01:00
|
|
|
let mut blocks = IndexVec::with_capacity(n_blocks);
|
2017-03-08 23:19:09 +02:00
|
|
|
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
|
2025-06-16 22:31:25 +08:00
|
|
|
blocks.push(BasicBlockData::new_stmts(
|
2017-03-08 23:19:09 +02:00
|
|
|
statements,
|
2025-06-16 22:31:25 +08:00
|
|
|
Some(Terminator { source_info, kind }),
|
2017-03-08 23:19:09 +02:00
|
|
|
is_cleanup,
|
2025-06-16 22:31:25 +08:00
|
|
|
))
|
2017-03-08 23:19:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// BB #0
|
2024-06-21 02:20:18 -07:00
|
|
|
let args = args.into_iter().map(|a| Spanned { node: a, span: DUMMY_SP }).collect();
|
2017-03-08 23:19:09 +02:00
|
|
|
block(
|
|
|
|
|
&mut blocks,
|
|
|
|
|
statements,
|
|
|
|
|
TerminatorKind::Call {
|
|
|
|
|
func: callee,
|
2017-08-06 22:54:09 -07:00
|
|
|
args,
|
2024-11-16 20:18:13 +00:00
|
|
|
destination,
|
2022-04-16 09:27:54 -04:00
|
|
|
target: Some(BasicBlock::new(1)),
|
2022-10-08 23:47:59 +01:00
|
|
|
unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
|
|
|
|
UnwindAction::Cleanup(BasicBlock::new(3))
|
2017-03-08 23:19:09 +02:00
|
|
|
} else {
|
2022-10-08 23:47:59 +01:00
|
|
|
UnwindAction::Continue
|
2019-12-22 17:42:04 -05:00
|
|
|
},
|
2023-06-18 05:24:38 +00:00
|
|
|
call_source: CallSource::Misc,
|
2020-06-09 15:34:23 -04:00
|
|
|
fn_span: span,
|
2018-09-29 10:34:12 +01:00
|
|
|
},
|
2017-03-08 23:19:09 +02:00
|
|
|
false,
|
|
|
|
|
);
|
|
|
|
|
|
2020-01-19 21:21:48 +02:00
|
|
|
if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
2017-03-08 23:19:09 +02:00
|
|
|
// BB #1 - drop for Self
|
|
|
|
|
block(
|
|
|
|
|
&mut blocks,
|
|
|
|
|
vec![],
|
2022-10-08 23:47:59 +01:00
|
|
|
TerminatorKind::Drop {
|
|
|
|
|
place: rcvr_place(),
|
|
|
|
|
target: BasicBlock::new(2),
|
|
|
|
|
unwind: UnwindAction::Continue,
|
2023-05-25 17:30:23 +00:00
|
|
|
replace: false,
|
2024-08-26 16:45:15 +03:00
|
|
|
drop: None,
|
|
|
|
|
async_fut: None,
|
2022-10-08 23:47:59 +01:00
|
|
|
},
|
2017-03-08 23:19:09 +02:00
|
|
|
false,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// BB #1/#2 - return
|
2025-03-18 16:17:18 +00:00
|
|
|
let stmts = vec![];
|
2024-11-16 20:18:13 +00:00
|
|
|
block(&mut blocks, stmts, TerminatorKind::Return, false);
|
2020-01-19 21:21:48 +02:00
|
|
|
if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
2017-03-08 23:19:09 +02:00
|
|
|
// BB #3 - drop if closure panics
|
|
|
|
|
block(
|
|
|
|
|
&mut blocks,
|
|
|
|
|
vec![],
|
2022-10-08 23:47:59 +01:00
|
|
|
TerminatorKind::Drop {
|
|
|
|
|
place: rcvr_place(),
|
|
|
|
|
target: BasicBlock::new(4),
|
2023-08-21 09:57:10 +02:00
|
|
|
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
2023-05-25 17:30:23 +00:00
|
|
|
replace: false,
|
2024-08-26 16:45:15 +03:00
|
|
|
drop: None,
|
|
|
|
|
async_fut: None,
|
2022-10-08 23:47:59 +01:00
|
|
|
},
|
2023-08-21 09:57:10 +02:00
|
|
|
/* is_cleanup */ true,
|
2017-03-08 23:19:09 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// BB #4 - resume
|
2023-08-19 13:10:25 +02:00
|
|
|
block(&mut blocks, vec![], TerminatorKind::UnwindResume, true);
|
2017-03-08 23:19:09 +02:00
|
|
|
}
|
2017-03-06 12:58:51 +02:00
|
|
|
|
2022-01-12 03:19:52 +00:00
|
|
|
let mut body =
|
|
|
|
|
new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
|
2019-11-26 01:31:27 +00:00
|
|
|
|
2024-11-02 19:33:00 -07:00
|
|
|
if let ExternAbi::RustCall = sig.abi {
|
2019-06-03 18:26:48 -04:00
|
|
|
body.spread_arg = Some(Local::new(sig.inputs().len()));
|
2017-03-08 18:33:21 +02:00
|
|
|
}
|
2020-04-12 10:31:00 -07:00
|
|
|
|
|
|
|
|
body
|
2017-03-06 12:58:51 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 09:39:59 +10:00
|
|
|
pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
|
2019-05-26 09:55:50 +01:00
|
|
|
debug_assert!(tcx.is_constructor(ctor_id));
|
|
|
|
|
|
2024-11-15 13:53:31 +01:00
|
|
|
let typing_env = ty::TypingEnv::post_analysis(tcx, ctor_id);
|
2017-11-20 13:08:52 -05:00
|
|
|
|
2018-03-03 08:23:28 -05:00
|
|
|
// Normalize the sig.
|
2023-01-18 15:43:20 -07:00
|
|
|
let sig = tcx
|
2023-01-18 16:52:47 -07:00
|
|
|
.fn_sig(ctor_id)
|
2023-07-11 22:35:29 +01:00
|
|
|
.instantiate_identity()
|
2023-01-18 15:43:20 -07:00
|
|
|
.no_bound_vars()
|
|
|
|
|
.expect("LBR in ADT constructor signature");
|
2024-11-15 13:53:31 +01:00
|
|
|
let sig = tcx.normalize_erasing_regions(typing_env, sig);
|
2017-02-07 22:46:21 +01:00
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
let ty::Adt(adt_def, args) = sig.output().kind() else {
|
2022-02-19 00:48:49 +01:00
|
|
|
bug!("unexpected type for ADT ctor {:?}", sig.output());
|
2017-02-07 22:46:21 +01:00
|
|
|
};
|
|
|
|
|
|
2019-05-26 09:55:50 +01:00
|
|
|
debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
|
2017-02-07 22:46:21 +01:00
|
|
|
|
2022-03-29 23:50:01 +02:00
|
|
|
let span = tcx.def_span(ctor_id);
|
|
|
|
|
|
2017-04-11 23:52:51 +03:00
|
|
|
let local_decls = local_decls_for_sig(&sig, span);
|
2017-02-07 22:46:21 +01:00
|
|
|
|
2020-05-06 10:30:11 +10:00
|
|
|
let source_info = SourceInfo::outermost(span);
|
2017-02-07 22:46:21 +01:00
|
|
|
|
2023-03-25 18:43:03 -07:00
|
|
|
let variant_index =
|
|
|
|
|
if adt_def.is_enum() { adt_def.variant_index_with_ctor_id(ctor_id) } else { FIRST_VARIANT };
|
2017-02-07 22:46:21 +01:00
|
|
|
|
2019-05-26 09:55:50 +01:00
|
|
|
// Generate the following MIR:
|
|
|
|
|
//
|
|
|
|
|
// (return as Variant).field0 = arg0;
|
|
|
|
|
// (return as Variant).field1 = arg1;
|
|
|
|
|
//
|
|
|
|
|
// return;
|
|
|
|
|
debug!("build_ctor: variant_index={:?}", variant_index);
|
|
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
let kind = AggregateKind::Adt(adt_def.did(), variant_index, args, None, None);
|
2023-01-25 18:34:19 +00:00
|
|
|
let variant = adt_def.variant(variant_index);
|
2025-06-08 15:30:18 +08:00
|
|
|
let statement = Statement::new(
|
|
|
|
|
source_info,
|
|
|
|
|
StatementKind::Assign(Box::new((
|
2023-01-25 18:34:19 +00:00
|
|
|
Place::return_place(),
|
|
|
|
|
Rvalue::Aggregate(
|
|
|
|
|
Box::new(kind),
|
|
|
|
|
(0..variant.fields.len())
|
|
|
|
|
.map(|idx| Operand::Move(Place::from(Local::new(idx + 1))))
|
|
|
|
|
.collect(),
|
|
|
|
|
),
|
|
|
|
|
))),
|
2025-06-08 15:30:18 +08:00
|
|
|
);
|
2019-05-26 09:55:50 +01:00
|
|
|
|
2025-06-16 22:31:25 +08:00
|
|
|
let start_block = BasicBlockData::new_stmts(
|
|
|
|
|
vec![statement],
|
|
|
|
|
Some(Terminator { source_info, kind: TerminatorKind::Return }),
|
|
|
|
|
false,
|
|
|
|
|
);
|
2017-02-07 22:46:21 +01:00
|
|
|
|
2020-10-04 11:01:38 -07:00
|
|
|
let source = MirSource::item(ctor_id);
|
2024-08-01 14:01:17 +02:00
|
|
|
let mut body = new_body(
|
2020-10-04 11:01:38 -07:00
|
|
|
source,
|
|
|
|
|
IndexVec::from_elem_n(start_block, 1),
|
|
|
|
|
local_decls,
|
|
|
|
|
sig.inputs().len(),
|
|
|
|
|
span,
|
2019-05-26 09:55:50 +01:00
|
|
|
);
|
2024-08-01 14:01:17 +02:00
|
|
|
// A constructor doesn't mention any other items (and we don't run the usual optimization passes
|
|
|
|
|
// so this would otherwise not get filled).
|
|
|
|
|
body.set_mentioned_items(Vec::new());
|
2019-05-26 09:55:50 +01:00
|
|
|
|
2022-09-04 20:00:31 -07:00
|
|
|
crate::pass_manager::dump_mir_for_phase_change(tcx, &body);
|
2020-10-04 11:01:38 -07:00
|
|
|
|
2020-03-27 20:26:20 +01:00
|
|
|
body
|
2017-02-07 22:46:21 +01:00
|
|
|
}
|
2022-07-20 14:32:58 +02:00
|
|
|
|
|
|
|
|
/// ```ignore (pseudo-impl)
|
|
|
|
|
/// impl FnPtr for fn(u32) {
|
|
|
|
|
/// fn addr(self) -> usize {
|
|
|
|
|
/// self as usize
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
|
|
|
|
fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
|
2024-08-11 12:10:36 -04:00
|
|
|
assert_matches!(self_ty.kind(), ty::FnPtr(..), "expected fn ptr, found {self_ty}");
|
2022-07-20 14:32:58 +02:00
|
|
|
let span = tcx.def_span(def_id);
|
2023-07-11 22:35:29 +01:00
|
|
|
let Some(sig) = tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]).no_bound_vars() else {
|
2022-07-20 14:32:58 +02:00
|
|
|
span_bug!(span, "FnPtr::addr with bound vars for `{self_ty}`");
|
|
|
|
|
};
|
|
|
|
|
let locals = local_decls_for_sig(&sig, span);
|
|
|
|
|
|
|
|
|
|
let source_info = SourceInfo::outermost(span);
|
2024-08-28 08:24:10 +10:00
|
|
|
// FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful
|
|
|
|
|
// provenance.
|
2022-07-20 14:32:58 +02:00
|
|
|
let rvalue = Rvalue::Cast(
|
|
|
|
|
CastKind::FnPtrToPtr,
|
|
|
|
|
Operand::Move(Place::from(Local::new(1))),
|
2023-07-05 20:13:26 +01:00
|
|
|
Ty::new_imm_ptr(tcx, tcx.types.unit),
|
2022-07-20 14:32:58 +02:00
|
|
|
);
|
2025-06-08 15:30:18 +08:00
|
|
|
let stmt = Statement::new(
|
2022-07-20 14:32:58 +02:00
|
|
|
source_info,
|
2025-06-08 15:30:18 +08:00
|
|
|
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
|
|
|
|
|
);
|
2022-07-20 14:32:58 +02:00
|
|
|
let statements = vec![stmt];
|
2025-06-16 22:31:25 +08:00
|
|
|
let start_block = BasicBlockData::new_stmts(
|
2022-07-20 14:32:58 +02:00
|
|
|
statements,
|
2025-06-16 22:31:25 +08:00
|
|
|
Some(Terminator { source_info, kind: TerminatorKind::Return }),
|
|
|
|
|
false,
|
|
|
|
|
);
|
2024-06-16 21:35:16 -04:00
|
|
|
let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty));
|
2022-07-20 14:32:58 +02:00
|
|
|
new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
|
|
|
|
|
}
|
2024-01-25 00:30:55 +00:00
|
|
|
|
|
|
|
|
fn build_construct_coroutine_by_move_shim<'tcx>(
|
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
coroutine_closure_def_id: DefId,
|
2024-02-28 20:25:25 +00:00
|
|
|
receiver_by_ref: bool,
|
2024-01-25 00:30:55 +00:00
|
|
|
) -> Body<'tcx> {
|
2024-02-28 20:25:25 +00:00
|
|
|
let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
|
2024-06-29 17:25:44 -04:00
|
|
|
let mut self_local: Place<'tcx> = Local::from_usize(1).into();
|
2024-01-25 00:30:55 +00:00
|
|
|
let ty::CoroutineClosure(_, args) = *self_ty.kind() else {
|
|
|
|
|
bug!();
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-29 17:25:44 -04:00
|
|
|
// We use `&Self` here because we only need to emit an ABI-compatible shim body,
|
|
|
|
|
// rather than match the signature exactly (which might take `&mut self` instead).
|
2024-03-19 12:55:26 -04:00
|
|
|
//
|
2024-06-29 17:25:44 -04:00
|
|
|
// We adjust the `self_local` to be a deref since we want to copy fields out of
|
|
|
|
|
// a reference to the closure.
|
2024-02-28 20:25:25 +00:00
|
|
|
if receiver_by_ref {
|
2024-06-29 17:25:44 -04:00
|
|
|
self_local = tcx.mk_place_deref(self_local);
|
|
|
|
|
self_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, self_ty);
|
2024-02-28 20:25:25 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-25 00:30:55 +00:00
|
|
|
let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
|
|
|
|
|
tcx.mk_fn_sig(
|
|
|
|
|
[self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()),
|
|
|
|
|
sig.to_coroutine_given_kind_and_upvars(
|
|
|
|
|
tcx,
|
|
|
|
|
args.as_coroutine_closure().parent_args(),
|
|
|
|
|
tcx.coroutine_for_closure(coroutine_closure_def_id),
|
|
|
|
|
ty::ClosureKind::FnOnce,
|
|
|
|
|
tcx.lifetimes.re_erased,
|
|
|
|
|
args.as_coroutine_closure().tupled_upvars_ty(),
|
|
|
|
|
args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
|
|
|
|
|
),
|
|
|
|
|
sig.c_variadic,
|
2024-05-17 14:17:48 -03:00
|
|
|
sig.safety,
|
2024-01-25 00:30:55 +00:00
|
|
|
sig.abi,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
let sig = tcx.liberate_late_bound_regions(coroutine_closure_def_id, poly_sig);
|
|
|
|
|
let ty::Coroutine(coroutine_def_id, coroutine_args) = *sig.output().kind() else {
|
|
|
|
|
bug!();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let span = tcx.def_span(coroutine_closure_def_id);
|
|
|
|
|
let locals = local_decls_for_sig(&sig, span);
|
|
|
|
|
|
|
|
|
|
let mut fields = vec![];
|
2024-09-15 16:07:08 -04:00
|
|
|
|
|
|
|
|
// Move all of the closure args.
|
2024-01-25 00:30:55 +00:00
|
|
|
for idx in 1..sig.inputs().len() {
|
|
|
|
|
fields.push(Operand::Move(Local::from_usize(idx + 1).into()));
|
|
|
|
|
}
|
2024-09-15 16:07:08 -04:00
|
|
|
|
2024-01-25 00:30:55 +00:00
|
|
|
for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
|
2024-06-29 17:25:44 -04:00
|
|
|
if receiver_by_ref {
|
|
|
|
|
// The only situation where it's possible is when we capture immuatable references,
|
|
|
|
|
// since those don't need to be reborrowed with the closure's env lifetime. Since
|
|
|
|
|
// references are always `Copy`, just emit a copy.
|
2024-09-15 16:07:08 -04:00
|
|
|
if !matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) {
|
|
|
|
|
// This copy is only sound if it's a `&T`. This may be
|
|
|
|
|
// reachable e.g. when eagerly computing the `Fn` instance
|
|
|
|
|
// of an async closure that doesn't borrowck.
|
|
|
|
|
tcx.dcx().delayed_bug(format!(
|
|
|
|
|
"field should be captured by immutable ref if we have \
|
|
|
|
|
an `Fn` instance, but it was: {ty}"
|
|
|
|
|
));
|
|
|
|
|
}
|
2024-06-29 17:25:44 -04:00
|
|
|
fields.push(Operand::Copy(tcx.mk_place_field(
|
|
|
|
|
self_local,
|
|
|
|
|
FieldIdx::from_usize(idx),
|
|
|
|
|
ty,
|
|
|
|
|
)));
|
|
|
|
|
} else {
|
|
|
|
|
fields.push(Operand::Move(tcx.mk_place_field(
|
|
|
|
|
self_local,
|
|
|
|
|
FieldIdx::from_usize(idx),
|
|
|
|
|
ty,
|
|
|
|
|
)));
|
|
|
|
|
}
|
2024-01-25 00:30:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let source_info = SourceInfo::outermost(span);
|
|
|
|
|
let rvalue = Rvalue::Aggregate(
|
|
|
|
|
Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)),
|
|
|
|
|
IndexVec::from_raw(fields),
|
|
|
|
|
);
|
2025-06-08 15:30:18 +08:00
|
|
|
let stmt = Statement::new(
|
2024-01-25 00:30:55 +00:00
|
|
|
source_info,
|
2025-06-08 15:30:18 +08:00
|
|
|
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
|
|
|
|
|
);
|
2024-01-25 00:30:55 +00:00
|
|
|
let statements = vec![stmt];
|
2025-06-16 22:31:25 +08:00
|
|
|
let start_block = BasicBlockData::new_stmts(
|
2024-01-25 00:30:55 +00:00
|
|
|
statements,
|
2025-06-16 22:31:25 +08:00
|
|
|
Some(Terminator { source_info, kind: TerminatorKind::Return }),
|
|
|
|
|
false,
|
|
|
|
|
);
|
2024-01-25 00:30:55 +00:00
|
|
|
|
2024-06-16 21:35:16 -04:00
|
|
|
let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim {
|
2024-01-25 00:30:55 +00:00
|
|
|
coroutine_closure_def_id,
|
2024-02-28 20:25:25 +00:00
|
|
|
receiver_by_ref,
|
2024-01-25 00:30:55 +00:00
|
|
|
});
|
|
|
|
|
|
2024-01-29 17:41:51 +00:00
|
|
|
let body =
|
|
|
|
|
new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span);
|
Introduce `MirDumper` and `MirWriter`.
MIR dumping is a mess. There are lots of functions and entry points,
e.g. `dump_mir`, `dump_mir_with_options`, `dump_polonius_mir`,
`dump_mir_to_writer`. Also, it's crucial that `create_dump_file` is
never called without `dump_enabled` first being checked, but there is no
mechanism for ensuring this and it's hard to tell if it is satisfied on
all paths. (`dump_enabled` is checked twice on some paths, however!)
This commit introduces `MirWriter`, which controls the MIR writing, and
encapsulates the `extra_data` closure and `options`. Two existing
functions are now methods of this type. It sets reasonable defaults,
allowing the removal of many `|_, _| Ok(())` closures.
The commit also introduces `MirDumper`, which is layered on top of
`MirWriter`, and which manages the creation of the dump files,
encapsulating pass names, disambiguators, etc. Four existing functions
are now methods of this type.
- `MirDumper::new` will only succeed if dumps are enabled, and will
return `None` otherwise, which makes it impossible to dump when you
shouldn't.
- It also sets reasonable defaults for various things like
disambiguators, which means you no longer need to specify them in many
cases. When they do need to be specified, it's now done via setter
methods.
- It avoids some repetition. E.g. `dump_nll_mir` previously specifed the
pass name `"nll"` four times and the disambiguator `&0` three times;
now it specifies them just once, to put them in the `MirDumper`.
- For Polonius, the `extra_data` closure can now be specified earlier,
which avoids having to pass some arguments through some functions.
2025-08-15 14:38:17 +10:00
|
|
|
|
|
|
|
|
let pass_name =
|
|
|
|
|
if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" };
|
|
|
|
|
if let Some(dumper) = MirDumper::new(tcx, pass_name, &body) {
|
|
|
|
|
dumper.dump_mir(&body);
|
|
|
|
|
}
|
2024-01-29 17:41:51 +00:00
|
|
|
|
|
|
|
|
body
|
2024-01-25 00:30:55 +00:00
|
|
|
}
|