Skip to content

Commit b45015f

Browse files
committed
Prereq1 for async drop - added drop & async_fut Option fields in Drop terminator
1 parent 9afe713 commit b45015f

File tree

23 files changed

+218
-42
lines changed

23 files changed

+218
-42
lines changed

compiler/rustc_borrowck/src/lib.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,14 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
690690
TerminatorKind::SwitchInt { discr, targets: _ } => {
691691
self.consume_operand(loc, (discr, span), flow_state);
692692
}
693-
TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
693+
TerminatorKind::Drop {
694+
place,
695+
target: _,
696+
unwind: _,
697+
replace,
698+
drop: _,
699+
async_fut: _,
700+
} => {
694701
debug!(
695702
"visit_terminator_drop \
696703
loc: {:?} term: {:?} place: {:?} span: {:?}",

compiler/rustc_borrowck/src/polonius/loan_invalidations.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
103103
TerminatorKind::SwitchInt { discr, targets: _ } => {
104104
self.consume_operand(location, discr);
105105
}
106-
TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => {
106+
TerminatorKind::Drop {
107+
place: drop_place,
108+
target: _,
109+
unwind: _,
110+
replace,
111+
drop: _,
112+
async_fut: _,
113+
} => {
107114
let write_kind =
108115
if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
109116
self.access_place(

compiler/rustc_borrowck/src/type_check/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1700,8 +1700,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
17001700
}
17011701
}
17021702
TerminatorKind::Unreachable => {}
1703-
TerminatorKind::Drop { target, unwind, .. }
1704-
| TerminatorKind::Assert { target, unwind, .. } => {
1703+
TerminatorKind::Drop { target, unwind, drop, .. } => {
1704+
self.assert_iscleanup(body, block_data, target, is_cleanup);
1705+
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
1706+
if let Some(drop) = drop {
1707+
self.assert_iscleanup(body, block_data, drop, is_cleanup);
1708+
}
1709+
}
1710+
TerminatorKind::Assert { target, unwind, .. } => {
17051711
self.assert_iscleanup(body, block_data, target, is_cleanup);
17061712
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
17071713
}

compiler/rustc_codegen_cranelift/src/base.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
549549
| TerminatorKind::CoroutineDrop => {
550550
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
551551
}
552-
TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
552+
TerminatorKind::Drop { place, target, unwind: _, replace: _, drop, async_fut } => {
553+
assert!(
554+
async_fut.is_none() && drop.is_none(),
555+
"Async Drop must be expanded or reset to sync before codegen"
556+
);
553557
let drop_place = codegen_place(fx, *place);
554558
crate::abi::codegen_drop(fx, source_info, drop_place, *target);
555559
}

compiler/rustc_codegen_ssa/src/mir/block.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1347,16 +1347,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13471347
MergingSucc::False
13481348
}
13491349

1350-
mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => self
1351-
.codegen_drop_terminator(
1350+
mir::TerminatorKind::Drop { place, target, unwind, replace: _, drop, async_fut } => {
1351+
assert!(
1352+
async_fut.is_none() && drop.is_none(),
1353+
"Async Drop must be expanded or reset to sync before codegen"
1354+
);
1355+
self.codegen_drop_terminator(
13521356
helper,
13531357
bx,
13541358
&terminator.source_info,
13551359
place,
13561360
target,
13571361
unwind,
13581362
mergeable_succ(),
1359-
),
1363+
)
1364+
}
13601365

13611366
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self
13621367
.codegen_assert_terminator(

compiler/rustc_const_eval/src/interpret/step.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
528528
}
529529
}
530530

531-
Drop { place, target, unwind, replace: _ } => {
531+
Drop { place, target, unwind, replace: _, drop, async_fut } => {
532+
assert!(
533+
async_fut.is_none() && drop.is_none(),
534+
"Async Drop must be expanded or reset to sync in runtime MIR"
535+
);
532536
let place = self.eval_place(place)?;
533537
let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
534538
if let ty::InstanceKind::DropGlue(_, None) = instance.def {

compiler/rustc_middle/src/mir/pretty.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,13 @@ impl<'tcx> TerminatorKind<'tcx> {
10151015
Call { target: None, unwind: _, .. } => vec![],
10161016
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
10171017
Yield { drop: None, .. } => vec!["resume".into()],
1018-
Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
1018+
Drop { unwind: UnwindAction::Cleanup(_), drop: Some(_), .. } => {
1019+
vec!["return".into(), "unwind".into(), "drop".into()]
1020+
}
1021+
Drop { unwind: UnwindAction::Cleanup(_), drop: None, .. } => {
1022+
vec!["return".into(), "unwind".into()]
1023+
}
1024+
Drop { unwind: _, drop: Some(_), .. } => vec!["return".into(), "drop".into()],
10191025
Drop { unwind: _, .. } => vec!["return".into()],
10201026
Assert { unwind: UnwindAction::Cleanup(_), .. } => {
10211027
vec!["success".into(), "unwind".into()]

compiler/rustc_middle/src/mir/syntax.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ pub enum MirPhase {
7373
/// is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be misaligned
7474
/// for this reason implicitly moves `P` to a temporary before dropping. Runtime MIR has no such
7575
/// rules, and dropping a misaligned place is simply UB.
76+
/// - Async drops: after drop elaboration some drops may become async (`drop`, `async_fut` fields).
77+
/// StateTransform pass will expand those async drops or reset to sync.
7678
/// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In runtime
7779
/// MIR, this is UB.
7880
/// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way
@@ -704,7 +706,34 @@ pub enum TerminatorKind<'tcx> {
704706
/// The `replace` flag indicates whether this terminator was created as part of an assignment.
705707
/// This should only be used for diagnostic purposes, and does not have any operational
706708
/// meaning.
707-
Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool },
709+
///
710+
/// Async drop processing:
711+
/// In compiler/rustc_mir_build/src/build/scope.rs we detect possible async drop:
712+
/// drop of object with `needs_async_drop`.
713+
/// Async drop later, in StateTransform pass, may be expanded into additional yield-point
714+
/// for poll-loop of async drop future.
715+
/// So we need prepared 'drop' target block in the similar way as for `Yield` terminator
716+
/// (see `drops.build_mir::<CoroutineDrop>` in scopes.rs).
717+
/// In compiler/rustc_mir_transform/src/elaborate_drops.rs for object implementing `AsyncDrop` trait
718+
/// we need to prepare async drop feature - resolve `AsyncDrop::drop` and codegen call.
719+
/// `async_fut` is set to the corresponding local.
720+
/// For coroutine drop we don't need this logic because coroutine drop works with the same
721+
/// layout object as coroutine itself. So `async_fut` will be `None` for coroutine drop.
722+
/// Both `drop` and `async_fut` fields are only used in compiler/rustc_mir_transform/src/coroutine.rs,
723+
/// StateTransform pass. In `expand_async_drops` async drops are expanded
724+
/// into one or two yield points with poll ready/pending switch.
725+
/// When a coroutine has any internal async drop, the coroutine drop function will be async
726+
/// (generated by `create_coroutine_drop_shim_async`, not `create_coroutine_drop_shim`).
727+
Drop {
728+
place: Place<'tcx>,
729+
target: BasicBlock,
730+
unwind: UnwindAction,
731+
replace: bool,
732+
/// Cleanup to be done if the coroutine is dropped at this suspend point (for async drop).
733+
drop: Option<BasicBlock>,
734+
/// Prepared async future local (for async drop)
735+
async_fut: Option<Local>,
736+
},
708737

709738
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
710739
/// the referred to function. The operand types must match the argument types of the function.

compiler/rustc_middle/src/mir/terminator.rs

+66-18
Original file line numberDiff line numberDiff line change
@@ -418,77 +418,123 @@ mod helper {
418418
pub fn successors(&self) -> Successors<'_> {
419419
use self::TerminatorKind::*;
420420
match *self {
421+
// 3-successors for async drop: target, unwind, dropline (parent coroutine drop)
422+
Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: Some(d), .. } => {
423+
slice::from_ref(t)
424+
.into_iter()
425+
.copied()
426+
.chain(Some(u).into_iter().chain(Some(d)))
427+
}
428+
// 2-successors
421429
Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
422430
| Yield { resume: ref t, drop: Some(u), .. }
423-
| Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
431+
| Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: None, .. }
432+
| Drop { target: ref t, unwind: _, drop: Some(u), .. }
424433
| Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
425434
| FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
426-
slice::from_ref(t).into_iter().copied().chain(Some(u))
435+
slice::from_ref(t).into_iter().copied().chain(Some(u).into_iter().chain(None))
427436
}
437+
// single successor
428438
Goto { target: ref t }
429439
| Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
430440
| Call { target: Some(ref t), unwind: _, .. }
431441
| Yield { resume: ref t, drop: None, .. }
432442
| Drop { target: ref t, unwind: _, .. }
433443
| Assert { target: ref t, unwind: _, .. }
434444
| FalseUnwind { real_target: ref t, unwind: _ } => {
435-
slice::from_ref(t).into_iter().copied().chain(None)
445+
slice::from_ref(t).into_iter().copied().chain(None.into_iter().chain(None))
436446
}
447+
// No successors
437448
UnwindResume
438449
| UnwindTerminate(_)
439450
| CoroutineDrop
440451
| Return
441452
| Unreachable
442453
| TailCall { .. }
443-
| Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
454+
| Call { target: None, unwind: _, .. } => {
455+
(&[]).into_iter().copied().chain(None.into_iter().chain(None))
456+
}
457+
// Multiple successors
444458
InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
445-
targets.iter().copied().chain(Some(u))
459+
targets.iter().copied().chain(Some(u).into_iter().chain(None))
460+
}
461+
InlineAsm { ref targets, unwind: _, .. } => {
462+
targets.iter().copied().chain(None.into_iter().chain(None))
446463
}
447-
InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
448-
SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
449-
FalseEdge { ref real_target, imaginary_target } => {
450-
slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
464+
SwitchInt { ref targets, .. } => {
465+
targets.targets.iter().copied().chain(None.into_iter().chain(None))
451466
}
467+
// FalseEdge
468+
FalseEdge { ref real_target, imaginary_target } => slice::from_ref(real_target)
469+
.into_iter()
470+
.copied()
471+
.chain(Some(imaginary_target).into_iter().chain(None)),
452472
}
453473
}
454474

455475
#[inline]
456476
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
457477
use self::TerminatorKind::*;
458478
match *self {
479+
// 3-successors for async drop: target, unwind, dropline (parent coroutine drop)
480+
Drop {
481+
target: ref mut t,
482+
unwind: UnwindAction::Cleanup(ref mut u),
483+
drop: Some(ref mut d),
484+
..
485+
} => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(Some(d))),
486+
// 2-successors
459487
Call {
460488
target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), ..
461489
}
462490
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
463-
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
491+
| Drop {
492+
target: ref mut t,
493+
unwind: UnwindAction::Cleanup(ref mut u),
494+
drop: None,
495+
..
496+
}
497+
| Drop { target: ref mut t, unwind: _, drop: Some(ref mut u), .. }
464498
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
465499
| FalseUnwind {
466500
real_target: ref mut t,
467501
unwind: UnwindAction::Cleanup(ref mut u),
468-
} => slice::from_mut(t).into_iter().chain(Some(u)),
502+
} => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(None)),
503+
// single successor
469504
Goto { target: ref mut t }
470505
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
471506
| Call { target: Some(ref mut t), unwind: _, .. }
472507
| Yield { resume: ref mut t, drop: None, .. }
473508
| Drop { target: ref mut t, unwind: _, .. }
474509
| Assert { target: ref mut t, unwind: _, .. }
475510
| FalseUnwind { real_target: ref mut t, unwind: _ } => {
476-
slice::from_mut(t).into_iter().chain(None)
511+
slice::from_mut(t).into_iter().chain(None.into_iter().chain(None))
477512
}
513+
// No successors
478514
UnwindResume
479515
| UnwindTerminate(_)
480516
| CoroutineDrop
481517
| Return
482518
| Unreachable
483519
| TailCall { .. }
484-
| Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
520+
| Call { target: None, unwind: _, .. } => {
521+
(&mut []).into_iter().chain(None.into_iter().chain(None))
522+
}
523+
// Multiple successors
485524
InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
486-
targets.iter_mut().chain(Some(u))
525+
targets.iter_mut().chain(Some(u).into_iter().chain(None))
526+
}
527+
InlineAsm { ref mut targets, unwind: _, .. } => {
528+
targets.iter_mut().chain(None.into_iter().chain(None))
529+
}
530+
SwitchInt { ref mut targets, .. } => {
531+
targets.targets.iter_mut().chain(None.into_iter().chain(None))
487532
}
488-
InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
489-
SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
533+
// FalseEdge
490534
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
491-
slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
535+
slice::from_mut(real_target)
536+
.into_iter()
537+
.chain(Some(imaginary_target).into_iter().chain(None))
492538
}
493539
}
494540
}
@@ -619,8 +665,10 @@ impl<'tcx> TerminatorKind<'tcx> {
619665

620666
Goto { target } => TerminatorEdges::Single(target),
621667

668+
// FIXME: Maybe we need also TerminatorEdges::Trio for async drop
669+
// (target + unwind + dropline)
622670
Assert { target, unwind, expected: _, msg: _, cond: _ }
623-
| Drop { target, unwind, place: _, replace: _ }
671+
| Drop { target, unwind, place: _, replace: _, drop: _, async_fut: _ }
624672
| FalseUnwind { real_target: target, unwind } => match unwind {
625673
UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
626674
UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {

compiler/rustc_middle/src/mir/visit.rs

+2
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,8 @@ macro_rules! make_mir_visitor {
511511
target: _,
512512
unwind: _,
513513
replace: _,
514+
drop: _,
515+
async_fut: _,
514516
} => {
515517
self.visit_place(
516518
place,

compiler/rustc_mir_build/src/build/custom/parse/instruction.rs

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
7070
target: self.parse_return_to(args[1])?,
7171
unwind: self.parse_unwind_action(args[2])?,
7272
replace: false,
73+
drop: None,
74+
async_fut: None,
7375
})
7476
},
7577
@call(mir_call, args) => {

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+2
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
729729
target: success,
730730
unwind: UnwindAction::Continue,
731731
replace: false,
732+
drop: None,
733+
async_fut: None,
732734
},
733735
);
734736
this.diverge_from(block);

compiler/rustc_mir_build/src/build/scope.rs

+8
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ impl DropTree {
401401
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
402402
place: drop_node.data.local.into(),
403403
replace: false,
404+
drop: None,
405+
async_fut: None,
404406
};
405407
cfg.terminate(block, drop_node.data.source_info, terminator);
406408
}
@@ -814,6 +816,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
814816
target: next,
815817
unwind: UnwindAction::Continue,
816818
replace: false,
819+
drop: None,
820+
async_fut: None,
817821
},
818822
);
819823
block = next;
@@ -1291,6 +1295,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12911295
target: assign,
12921296
unwind: UnwindAction::Cleanup(assign_unwind),
12931297
replace: true,
1298+
drop: None,
1299+
async_fut: None,
12941300
},
12951301
);
12961302
self.diverge_from(block);
@@ -1405,6 +1411,8 @@ fn build_scope_drops<'tcx>(
14051411
target: next,
14061412
unwind: UnwindAction::Continue,
14071413
replace: false,
1414+
drop: None,
1415+
async_fut: None,
14081416
},
14091417
);
14101418
block = next;

0 commit comments

Comments
 (0)