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::patch::MirPatch;
13
14pub(super) fn build_async_destructor_ctor_shim<'tcx>(
15 tcx: TyCtxt<'tcx>,
16 def_id: DefId,
17 ty: Ty<'tcx>,
18) -> Body<'tcx> {
19 {
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:19",
"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(19u32),
::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);
20 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());
21 let generic_body = tcx.optimized_mir(def_id);
22 let args = tcx.mk_args(&[ty.into()]);
23 let mut body = EarlyBinder::bind(generic_body.clone()).instantiate(tcx, args).skip_norm_wip();
24
25 pm::run_passes(
28 tcx,
29 &mut body,
30 &[
31 &simplify::SimplifyCfg::MakeShim,
32 &abort_unwinding_calls::AbortUnwindingCalls,
33 &add_call_guards::CriticalCallEdges,
34 ],
35 None,
36 pm::Optimizations::Allowed,
37 );
38 body
39}
40
41pub(super) fn build_async_drop_shim<'tcx>(
43 tcx: TyCtxt<'tcx>,
44 def_id: DefId,
45 ty: Ty<'tcx>,
46) -> Body<'tcx> {
47 {
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:47",
"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(47u32),
::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_drop_shim(def_id={0:?}, ty={1:?})",
def_id, ty) as &dyn Value))])
});
} else { ; }
};debug!("build_async_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
48 let ty::Coroutine(_, parent_args) = ty.kind() else {
49 ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
50 };
51 let typing_env = ty::TypingEnv::fully_monomorphized();
52
53 let drop_ty = parent_args.first().unwrap().expect_ty();
54 let drop_ptr_ty = Ty::new_mut_ptr(tcx, drop_ty);
55
56 if !tcx.is_coroutine(def_id) {
::core::panicking::panic("assertion failed: tcx.is_coroutine(def_id)")
};assert!(tcx.is_coroutine(def_id));
57 let coroutine_kind = tcx.coroutine_kind(def_id).unwrap();
58
59 if !#[allow(non_exhaustive_omitted_patterns)] match coroutine_kind {
CoroutineKind::Desugared(CoroutineDesugaring::Async,
CoroutineSource::Fn) => true,
_ => false,
} {
::core::panicking::panic("assertion failed: matches!(coroutine_kind,\n CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn))")
};assert!(matches!(
60 coroutine_kind,
61 CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)
62 ));
63
64 let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env);
65 let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env);
66
67 let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
68 let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty());
69
70 let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig_safe_rust_abi([ty, resume_ty], tcx.types.unit));
71 let sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
72
73 if !!drop_ty.is_coroutine() {
::core::panicking::panic("assertion failed: !drop_ty.is_coroutine()")
};assert!(!drop_ty.is_coroutine());
74 let span = tcx.def_span(def_id);
75 let source_info = SourceInfo::outermost(span);
76
77 let coroutine_layout = Place::from(Local::new(1 + 0));
79 let coroutine_layout_dropee =
80 tcx.mk_place_field(coroutine_layout, FieldIdx::new(0), drop_ptr_ty);
81
82 let return_block = BasicBlock::new(1);
83 let mut blocks = IndexVec::with_capacity(2);
84 let block = |blocks: &mut IndexVec<_, _>, kind| {
85 blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
86 };
87 block(
88 &mut blocks,
89 if needs_sync_drop {
90 TerminatorKind::Drop {
91 place: tcx.mk_place_deref(coroutine_layout_dropee),
92 target: return_block,
93 unwind: UnwindAction::Continue,
94 replace: false,
95 drop: None,
96 async_fut: None,
97 }
98 } else {
99 TerminatorKind::Goto { target: return_block }
100 },
101 );
102 block(&mut blocks, TerminatorKind::Return);
103
104 let source = MirSource::from_instance(ty::InstanceKind::AsyncDropGlue(def_id, ty));
105 let mut body =
106 new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
107
108 body.coroutine = Some(Box::new(CoroutineInfo::initial(
109 coroutine_kind,
110 parent_args.as_coroutine().yield_ty(),
111 parent_args.as_coroutine().resume_ty(),
112 )));
113 body.phase = MirPhase::Runtime(RuntimePhase::Initial);
114 if !needs_async_drop || drop_ty.references_error() {
115 return body;
119 }
120
121 let mut dropee_ptr = Place::from(body.local_decls.push(LocalDecl::new(drop_ptr_ty, span)));
122 let st_kind = StatementKind::Assign(Box::new((
123 dropee_ptr,
124 Rvalue::Use(Operand::Move(coroutine_layout_dropee)),
125 )));
126 body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind));
127 dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span);
128
129 let dropline = body.basic_blocks.last_index();
130
131 let patch = {
132 let mut elaborator = DropShimElaborator {
133 body: &body,
134 patch: MirPatch::new(&body),
135 tcx,
136 typing_env,
137 produce_async_drops: true,
138 };
139 let dropee = tcx.mk_place_deref(dropee_ptr);
140 let resume_block = elaborator.patch.resume_block();
141 elaborate_drop(
142 &mut elaborator,
143 source_info,
144 dropee,
145 (),
146 return_block,
147 Unwind::To(resume_block),
148 START_BLOCK,
149 dropline,
150 );
151 elaborator.patch
152 };
153 patch.apply(&mut body);
154
155 body
156}
157
158pub(super) fn build_future_drop_poll_shim<'tcx>(
167 tcx: TyCtxt<'tcx>,
168 def_id: DefId,
169 proxy_ty: Ty<'tcx>,
170 impl_ty: Ty<'tcx>,
171) -> Body<'tcx> {
172 let instance = ty::InstanceKind::FutureDropPollShim(def_id, proxy_ty, impl_ty);
173 let ty::Coroutine(coroutine_def_id, _) = impl_ty.kind() else {
174 ::rustc_middle::util::bug::bug_fmt(format_args!("build_future_drop_poll_shim not for coroutine impl type: ({0:?})",
instance));bug!("build_future_drop_poll_shim not for coroutine impl type: ({:?})", instance);
175 };
176
177 let span = tcx.def_span(def_id);
178
179 if tcx.is_async_drop_in_place_coroutine(*coroutine_def_id) {
180 build_adrop_for_adrop_shim(tcx, proxy_ty, impl_ty, span, instance)
181 } else {
182 build_adrop_for_coroutine_shim(tcx, proxy_ty, impl_ty, span, instance)
183 }
184}
185
186fn build_adrop_for_coroutine_shim<'tcx>(
191 tcx: TyCtxt<'tcx>,
192 proxy_ty: Ty<'tcx>,
193 impl_ty: Ty<'tcx>,
194 span: Span,
195 instance: ty::InstanceKind<'tcx>,
196) -> Body<'tcx> {
197 let ty::Coroutine(coroutine_def_id, impl_args) = impl_ty.kind() else {
198 ::rustc_middle::util::bug::bug_fmt(format_args!("build_adrop_for_coroutine_shim not for coroutine impl type: ({0:?})",
instance));bug!("build_adrop_for_coroutine_shim not for coroutine impl type: ({:?})", instance);
199 };
200 let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
201 let pin_proxy_layout_local = Local::new(1);
203 let source_info = SourceInfo::outermost(span);
204 let body = tcx.optimized_mir(*coroutine_def_id).future_drop_poll().unwrap();
209 let mut body: Body<'tcx> =
210 EarlyBinder::bind(body.clone()).instantiate(tcx, impl_args).skip_norm_wip();
211 body.source.instance = instance;
212 body.phase = MirPhase::Runtime(RuntimePhase::Initial);
213 body.var_debug_info.clear();
214 let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
215 let args = tcx.mk_args(&[proxy_ref.into()]);
216 let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args);
217
218 let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
219
220 let proxy_ref_local = body.local_decls.push(LocalDecl::new(proxy_ref, span));
221 let cor_ref_local = body.local_decls.push(LocalDecl::new(cor_ref, span));
222
223 FixProxyFutureDropVisitor { tcx, replace_to: cor_ref_local }.visit_body(&mut body);
224 body.local_decls[pin_proxy_layout_local] = LocalDecl::new(pin_proxy_ref, span);
226
227 {
228 let mut idx: usize = 0;
229 let proxy_ref_place = Place::from(pin_proxy_layout_local)
231 .project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
232 body.basic_blocks_mut()[START_BLOCK].statements.insert(
233 idx,
234 Statement::new(
235 source_info,
236 StatementKind::Assign(Box::new((
237 Place::from(proxy_ref_local),
238 Rvalue::Use(Operand::Copy(proxy_ref_place)),
239 ))),
240 ),
241 );
242 idx += 1;
243 let mut cor_ptr_local = proxy_ref_local;
244 proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
245 if ty != proxy_ty {
246 let ty_ptr = Ty::new_mut_ptr(tcx, ty);
247 let impl_ptr_place = Place::from(cor_ptr_local).project_deeper(
248 &[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)],
249 tcx,
250 );
251 cor_ptr_local = body.local_decls.push(LocalDecl::new(ty_ptr, span));
252 body.basic_blocks_mut()[START_BLOCK].statements.insert(
254 idx,
255 Statement::new(
256 source_info,
257 StatementKind::Assign(Box::new((
258 Place::from(cor_ptr_local),
259 Rvalue::Use(Operand::Copy(impl_ptr_place)),
260 ))),
261 ),
262 );
263 idx += 1;
264 }
265 });
266
267 let reborrow = Rvalue::Ref(
269 tcx.lifetimes.re_erased,
270 BorrowKind::Mut { kind: MutBorrowKind::Default },
271 tcx.mk_place_deref(Place::from(cor_ptr_local)),
272 );
273 body.basic_blocks_mut()[START_BLOCK].statements.insert(
274 idx,
275 Statement::new(
276 source_info,
277 StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))),
278 ),
279 );
280 }
281 body
282}
283
284fn build_adrop_for_adrop_shim<'tcx>(
287 tcx: TyCtxt<'tcx>,
288 proxy_ty: Ty<'tcx>,
289 impl_ty: Ty<'tcx>,
290 span: Span,
291 instance: ty::InstanceKind<'tcx>,
292) -> Body<'tcx> {
293 let source_info = SourceInfo::outermost(span);
294 let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
295 let pin_proxy_layout_local = Local::new(1);
297 let proxy_ref_place = Place::from(pin_proxy_layout_local)
298 .project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
299 let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
300
301 let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span));
303 let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
304 let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
306 let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()]));
307 let sig = tcx.mk_fn_sig_safe_rust_abi([env_ty, Ty::new_task_context(tcx)], ret_ty);
309 let mut locals = local_decls_for_sig(&sig, span);
313 let mut blocks = IndexVec::with_capacity(3);
314
315 let proxy_ref_local = locals.push(LocalDecl::new(proxy_ref, span));
316
317 let call_bb = BasicBlock::new(1);
318 let return_bb = BasicBlock::new(2);
319
320 let mut statements = Vec::new();
321
322 statements.push(Statement::new(
323 source_info,
324 StatementKind::Assign(Box::new((
325 Place::from(proxy_ref_local),
326 Rvalue::Use(Operand::Copy(proxy_ref_place)),
327 ))),
328 ));
329
330 let mut cor_ptr_local = proxy_ref_local;
331 proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
332 if ty != proxy_ty {
333 let ty_ptr = Ty::new_mut_ptr(tcx, ty);
334 let impl_ptr_place = Place::from(cor_ptr_local)
335 .project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx);
336 cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span));
337 statements.push(Statement::new(
339 source_info,
340 StatementKind::Assign(Box::new((
341 Place::from(cor_ptr_local),
342 Rvalue::Use(Operand::Copy(impl_ptr_place)),
343 ))),
344 ));
345 }
346 });
347
348 let reborrow = Rvalue::Ref(
350 tcx.lifetimes.re_erased,
351 BorrowKind::Mut { kind: MutBorrowKind::Default },
352 tcx.mk_place_deref(Place::from(cor_ptr_local)),
353 );
354 let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span)));
355 statements.push(Statement::new(
356 source_info,
357 StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
358 ));
359
360 let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()]));
362 let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span)));
363
364 let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span);
365 blocks.push(BasicBlockData::new_stmts(
367 statements,
368 Some(Terminator {
369 source_info,
370 kind: TerminatorKind::Call {
371 func: Operand::function_handle(tcx, pin_fn, [cor_ref.into()], span),
372 args: [dummy_spanned(Operand::Move(cor_ref_place))].into(),
373 destination: cor_pin_place,
374 target: Some(call_bb),
375 unwind: UnwindAction::Continue,
376 call_source: CallSource::Misc,
377 fn_span: span,
378 },
379 }),
380 false,
381 ));
382 let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span);
385 let resume_ctx = Place::from(Local::new(2));
386 blocks.push(BasicBlockData::new(
387 Some(Terminator {
388 source_info,
389 kind: TerminatorKind::Call {
390 func: Operand::function_handle(tcx, poll_fn, [impl_ty.into()], span),
391 args: [
392 dummy_spanned(Operand::Move(cor_pin_place)),
393 dummy_spanned(Operand::Move(resume_ctx)),
394 ]
395 .into(),
396 destination: Place::return_place(),
397 target: Some(return_bb),
398 unwind: UnwindAction::Continue,
399 call_source: CallSource::Misc,
400 fn_span: span,
401 },
402 }),
403 false,
404 ));
405 blocks.push(BasicBlockData::new(
406 Some(Terminator { source_info, kind: TerminatorKind::Return }),
407 false,
408 ));
409
410 let source = MirSource::from_instance(instance);
411 let mut body = new_body(source, blocks, locals, sig.inputs().len(), span);
412 body.phase = MirPhase::Runtime(RuntimePhase::Initial);
413 return body;
414}