1use rustc_hir::def_id::DefId;
2use rustc_hir::lang_items::LangItem;
3use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource};
4use rustc_index::{Idx, IndexVec};
5use rustc_middle::mir::{
6 BasicBlock, BasicBlockData, Body, Local, LocalDecl, MirSource, Operand, Place, Rvalue,
7 SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
8};
9use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt};
10
11use super::*;
12use crate::deref_separator::deref_finder;
13use crate::patch::MirPatch;
14
15const SELF_ARG: Local = Local::arg(0);
16
17pub(super) fn build_async_destructor_ctor_shim<'tcx>(
18 tcx: TyCtxt<'tcx>,
19 def_id: DefId,
20 ty: Ty<'tcx>,
21) -> Body<'tcx> {
22 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs:22",
"rustc_mir_transform::shim::async_destructor_ctor",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs"),
::tracing_core::__macro_support::Option::Some(22u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim::async_destructor_ctor"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("build_async_destructor_ctor_shim(def_id={0:?}, ty={1:?})",
def_id, ty) as &dyn Value))])
});
} else { ; }
};debug!("build_async_destructor_ctor_shim(def_id={:?}, ty={:?})", def_id, ty);
23 if true {
{
match (&Some(def_id), &tcx.lang_items().async_drop_in_place_fn()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};
};debug_assert_eq!(Some(def_id), tcx.lang_items().async_drop_in_place_fn());
24 let generic_body = tcx.optimized_mir(def_id);
25 let args = tcx.mk_args(&[ty.into()]);
26 let mut body =
27 EarlyBinder::bind(tcx, generic_body.clone()).instantiate(tcx, args).skip_norm_wip();
28
29 pm::run_passes(
32 tcx,
33 &mut body,
34 &[
35 &simplify::SimplifyCfg::MakeShim,
36 &abort_unwinding_calls::AbortUnwindingCalls,
37 &add_call_guards::CriticalCallEdges,
38 ],
39 None,
40 pm::Optimizations::Allowed,
41 );
42 body
43}
44
45x;#[tracing::instrument(level = "trace", skip(tcx), ret)]
47pub(super) fn build_async_drop_shim<'tcx>(
48 tcx: TyCtxt<'tcx>,
49 def_id: DefId,
50 ty: Ty<'tcx>,
51) -> Body<'tcx> {
52 let ty::Coroutine(_, parent_args) = ty.kind() else {
53 bug!();
54 };
55 let typing_env = ty::TypingEnv::fully_monomorphized();
56
57 let drop_ty = parent_args.first().unwrap().expect_ty();
58 let drop_ptr_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, drop_ty);
59
60 assert!(tcx.is_coroutine(def_id));
61 let coroutine_kind = tcx.coroutine_kind(def_id).unwrap();
62
63 assert!(matches!(
64 coroutine_kind,
65 CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)
66 ));
67
68 let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env);
69 let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env);
70
71 let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
72 let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty());
73
74 let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig_safe_rust_abi([ty, resume_ty], tcx.types.unit));
75 let sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
76
77 assert!(!drop_ty.is_coroutine());
78 let span = tcx.def_span(def_id);
79 let source_info = SourceInfo::outermost(span);
80
81 let coroutine_layout = Place::from(SELF_ARG);
83 let coroutine_layout_dropee =
84 tcx.mk_place_field(coroutine_layout, FieldIdx::new(0), drop_ptr_ty);
85
86 let return_block = BasicBlock::new(1);
87 let mut blocks = IndexVec::with_capacity(2);
88 let block = |blocks: &mut IndexVec<_, _>, kind| {
89 blocks.push(BasicBlockData::new(
90 Some(Terminator { source_info, kind, attributes: ThinVec::new() }),
91 false,
92 ))
93 };
94 block(
95 &mut blocks,
96 if needs_sync_drop {
97 TerminatorKind::Drop {
98 place: tcx.mk_place_deref(coroutine_layout_dropee),
99 target: return_block,
100 unwind: UnwindAction::Continue,
101 replace: false,
102 drop: None,
103 }
104 } else {
105 TerminatorKind::Goto { target: return_block }
106 },
107 );
108 block(&mut blocks, TerminatorKind::Return);
109
110 let source = MirSource::from_shim(ty::ShimKind::AsyncDropGlue(def_id, ty));
111 let mut body =
112 new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
113
114 body.coroutine = Some(Box::new(CoroutineInfo::initial(
115 coroutine_kind,
116 parent_args.as_coroutine().yield_ty(),
117 parent_args.as_coroutine().resume_ty(),
118 )));
119 body.phase = MirPhase::Runtime(RuntimePhase::Initial);
120
121 if needs_async_drop && !drop_ty.references_error() {
125 let dropee_ptr = Place::from(body.local_decls.push(LocalDecl::new(drop_ptr_ty, span)));
126 let st_kind = StatementKind::Assign(Box::new((
127 dropee_ptr,
128 Rvalue::Use(Operand::Move(coroutine_layout_dropee), WithRetag::Yes),
129 )));
130 body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind));
131
132 let dropline = body.basic_blocks.last_index();
133
134 let patch = {
135 let mut elaborator = DropShimElaborator {
136 body: &body,
137 patch: MirPatch::new(&body),
138 tcx,
139 typing_env,
140 produce_async_drops: true,
141 };
142 let dropee = tcx.mk_place_deref(dropee_ptr);
143 let resume_block = elaborator.patch.resume_block();
144 elaborate_drop(
145 &mut elaborator,
146 source_info,
147 dropee,
148 (),
149 return_block,
150 Unwind::To(resume_block),
151 START_BLOCK,
152 dropline,
153 );
154 elaborator.patch
155 };
156 patch.apply(&mut body);
157 }
158
159 deref_finder(tcx, &mut body, false);
161
162 body
163}
164
165pub(super) fn build_future_drop_poll_shim<'tcx>(
174 tcx: TyCtxt<'tcx>,
175 def_id: DefId,
176 proxy_ty: Ty<'tcx>,
177 impl_ty: Ty<'tcx>,
178) -> Body<'tcx> {
179 let shim = ty::ShimKind::FutureDropPoll(def_id, proxy_ty, impl_ty);
180 let ty::Coroutine(coroutine_def_id, _) = impl_ty.kind() else {
181 ::rustc_middle::util::bug::bug_fmt(format_args!("build_future_drop_poll_shim not for coroutine impl type: ({0:?})",
shim));bug!("build_future_drop_poll_shim not for coroutine impl type: ({:?})", shim);
182 };
183
184 let span = tcx.def_span(def_id);
185
186 if tcx.is_async_drop_in_place_coroutine(*coroutine_def_id) {
187 build_adrop_for_adrop_shim(tcx, proxy_ty, impl_ty, span, shim)
188 } else {
189 build_adrop_for_coroutine_shim(tcx, proxy_ty, impl_ty, span, shim)
190 }
191}
192
193fn build_adrop_for_coroutine_shim<'tcx>(
198 tcx: TyCtxt<'tcx>,
199 proxy_ty: Ty<'tcx>,
200 impl_ty: Ty<'tcx>,
201 span: Span,
202 shim: ty::ShimKind<'tcx>,
203) -> Body<'tcx> {
204 let ty::Coroutine(coroutine_def_id, impl_args) = impl_ty.kind() else {
205 ::rustc_middle::util::bug::bug_fmt(format_args!("build_adrop_for_coroutine_shim not for coroutine impl type: ({0:?})",
shim));bug!("build_adrop_for_coroutine_shim not for coroutine impl type: ({:?})", shim);
206 };
207 let source_info = SourceInfo::outermost(span);
208 let body = tcx.optimized_mir(*coroutine_def_id).future_drop_poll().unwrap();
209 let mut body: Body<'tcx> =
210 EarlyBinder::bind(tcx, body.clone()).instantiate(tcx, impl_args).skip_norm_wip();
211 body.source.instance = ty::InstanceKind::Shim(shim);
212 body.phase = MirPhase::Runtime(RuntimePhase::Initial);
213 body.var_debug_info.clear();
214
215 let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
220
221 let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
222 let args = tcx.mk_args(&[proxy_ref.into()]);
223 let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args);
224
225 let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
226 let cor_ref_local = body.local_decls.push(LocalDecl::new(cor_ref, span));
227
228 FixProxyFutureDropVisitor { tcx, replace_to: cor_ref_local }.visit_body(&mut body);
229
230 body.local_decls[SELF_ARG] = LocalDecl::new(pin_proxy_ref, span);
232
233 let mut pin_proxy_to_cor_projection = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)]))vec![
235 PlaceElem::Field(FieldIdx::ZERO, proxy_ref),
237 ];
238
239 proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
241 if ty != proxy_ty {
242 let ty_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
243 pin_proxy_to_cor_projection.push(PlaceElem::Deref);
244 pin_proxy_to_cor_projection.push(PlaceElem::Field(FieldIdx::ZERO, ty_ref));
245 }
246 });
247
248 let projected_pin = Place::from(SELF_ARG).project_deeper(&pin_proxy_to_cor_projection, tcx);
250 body.basic_blocks_mut()[START_BLOCK].statements.insert(
251 0,
252 Statement::new(
253 source_info,
254 StatementKind::Assign(Box::new((
255 Place::from(cor_ref_local),
256 Rvalue::Use(Operand::Move(projected_pin), WithRetag::Yes),
257 ))),
258 ),
259 );
260
261 deref_finder(tcx, &mut body, false);
263
264 return body;
265
266 struct FixProxyFutureDropVisitor<'tcx> {
268 tcx: TyCtxt<'tcx>,
269 replace_to: Local,
270 }
271
272 impl<'tcx> MutVisitor<'tcx> for FixProxyFutureDropVisitor<'tcx> {
273 fn tcx(&self) -> TyCtxt<'tcx> {
274 self.tcx
275 }
276
277 fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, _: Location) {
278 if place.local == SELF_ARG
279 && let Some((first, rest)) = place.projection.split_first()
280 {
281 if !#[allow(non_exhaustive_omitted_patterns)] match first {
ProjectionElem::Field(FieldIdx::ZERO, _) => true,
_ => false,
} {
::core::panicking::panic("assertion failed: matches!(first, ProjectionElem::Field(FieldIdx::ZERO, _))")
};assert!(matches!(first, ProjectionElem::Field(FieldIdx::ZERO, _)));
282 *place = Place::from(self.replace_to).project_deeper(rest, self.tcx);
283 }
284 }
285 }
286}
287
288fn build_adrop_for_adrop_shim<'tcx>(
291 tcx: TyCtxt<'tcx>,
292 proxy_ty: Ty<'tcx>,
293 impl_ty: Ty<'tcx>,
294 span: Span,
295 shim: ty::ShimKind<'tcx>,
296) -> Body<'tcx> {
297 let source_info = SourceInfo::outermost(span);
298 let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
299 let proxy_ref_place =
301 Place::from(SELF_ARG).project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
302 let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
303
304 let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span));
306 let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
307 let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
309 let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()]));
310 let sig = tcx.mk_fn_sig_safe_rust_abi([env_ty, Ty::new_task_context(tcx)], ret_ty);
312 let mut locals = local_decls_for_sig(&sig, span);
316 let mut blocks = IndexVec::with_capacity(3);
317
318 let proxy_ref_local = locals.push(LocalDecl::new(proxy_ref, span));
319
320 let call_bb = BasicBlock::new(1);
321 let return_bb = BasicBlock::new(2);
322
323 let mut statements = Vec::new();
324
325 statements.push(Statement::new(
326 source_info,
327 StatementKind::Assign(Box::new((
328 Place::from(proxy_ref_local),
329 Rvalue::Use(Operand::Copy(proxy_ref_place), WithRetag::Yes),
330 ))),
331 ));
332
333 let mut cor_ptr_local = proxy_ref_local;
334 proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
335 if ty != proxy_ty {
336 let ty_ptr = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
337 let impl_ptr_place = Place::from(cor_ptr_local)
338 .project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx);
339 cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span));
340 statements.push(Statement::new(
342 source_info,
343 StatementKind::Assign(Box::new((
344 Place::from(cor_ptr_local),
345 Rvalue::Use(Operand::Copy(impl_ptr_place), WithRetag::Yes),
346 ))),
347 ));
348 }
349 });
350
351 let reborrow = Rvalue::Ref(
353 tcx.lifetimes.re_erased,
354 BorrowKind::Mut { kind: MutBorrowKind::Default },
355 tcx.mk_place_deref(Place::from(cor_ptr_local)),
356 );
357 let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span)));
358 statements.push(Statement::new(
359 source_info,
360 StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
361 ));
362
363 let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()]));
365 let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span)));
366
367 let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span);
368 blocks.push(BasicBlockData::new_stmts(
370 statements,
371 Some(Terminator {
372 source_info,
373 kind: TerminatorKind::Call {
374 func: Operand::function_handle(tcx, pin_fn, [cor_ref.into()], span),
375 args: [dummy_spanned(Operand::Move(cor_ref_place))].into(),
376 destination: cor_pin_place,
377 target: Some(call_bb),
378 unwind: UnwindAction::Continue,
379 call_source: CallSource::Misc,
380 fn_span: span,
381 },
382
383 attributes: ThinVec::new(),
384 }),
385 false,
386 ));
387 let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span);
390 let resume_ctx = Place::from(Local::new(2));
391 blocks.push(BasicBlockData::new(
392 Some(Terminator {
393 source_info,
394 kind: TerminatorKind::Call {
395 func: Operand::function_handle(tcx, poll_fn, [impl_ty.into()], span),
396 args: [
397 dummy_spanned(Operand::Move(cor_pin_place)),
398 dummy_spanned(Operand::Move(resume_ctx)),
399 ]
400 .into(),
401 destination: Place::return_place(),
402 target: Some(return_bb),
403 unwind: UnwindAction::Continue,
404 call_source: CallSource::Misc,
405 fn_span: span,
406 },
407
408 attributes: ThinVec::new(),
409 }),
410 false,
411 ));
412 blocks.push(BasicBlockData::new(
413 Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }),
414 false,
415 ));
416
417 let source = MirSource::from_shim(shim);
418 let mut body = new_body(source, blocks, locals, sig.inputs().len(), span);
419 body.phase = MirPhase::Runtime(RuntimePhase::Initial);
420 return body;
421}