From f8f9f262c3d6533270127b1b9bf5e2628d51b2de Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Mon, 26 Aug 2024 16:45:15 +0300 Subject: [PATCH 1/4] Prereq1 for async drop - added drop & async_fut Option fields in Drop terminator --- compiler/rustc_borrowck/src/lib.rs | 9 +- .../src/polonius/legacy/loan_invalidations.rs | 9 +- compiler/rustc_borrowck/src/type_check/mod.rs | 10 ++- compiler/rustc_codegen_cranelift/src/base.rs | 6 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 11 ++- .../rustc_const_eval/src/interpret/step.rs | 6 +- compiler/rustc_middle/src/mir/pretty.rs | 8 +- compiler/rustc_middle/src/mir/syntax.rs | 31 ++++++- compiler/rustc_middle/src/mir/terminator.rs | 86 +++++++++++++++---- compiler/rustc_middle/src/mir/visit.rs | 9 +- .../src/builder/custom/parse/instruction.rs | 2 + .../src/builder/expr/as_rvalue.rs | 2 + compiler/rustc_mir_build/src/builder/scope.rs | 8 ++ .../src/impls/initialized.rs | 9 +- .../src/add_moves_for_packed_drops.rs | 6 +- compiler/rustc_mir_transform/src/coroutine.rs | 5 +- .../rustc_mir_transform/src/elaborate_drop.rs | 6 ++ .../src/elaborate_drops.rs | 4 +- compiler/rustc_mir_transform/src/inline.rs | 10 ++- .../src/lint_tail_expr_drop_order.rs | 2 + compiler/rustc_mir_transform/src/shim.rs | 6 ++ .../src/shim/async_destructor_ctor.rs | 2 + compiler/rustc_mir_transform/src/validate.rs | 5 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 19 ++-- 24 files changed, 227 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 240bd20053b15..eee440a6dfed8 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -659,7 +659,14 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< TerminatorKind::SwitchInt { discr, targets: _ } => { self.consume_operand(loc, (discr, span), state); } - TerminatorKind::Drop { place, target: _, unwind: _, replace } => { + TerminatorKind::Drop { + place, + target: _, + unwind: _, + replace, + drop: _, + async_fut: _, + } => { debug!( "visit_terminator_drop \ loc: {:?} term: {:?} place: {:?} span: {:?}", diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 0d1d8642bcacc..99dd0b2dd4664 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -101,7 +101,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { TerminatorKind::SwitchInt { discr, targets: _ } => { self.consume_operand(location, discr); } - TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => { + TerminatorKind::Drop { + place: drop_place, + target: _, + unwind: _, + replace, + drop: _, + async_fut: _, + } => { let write_kind = if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop }; self.access_place( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f6144a25938ce..b801cfea24a2b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2086,8 +2086,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } TerminatorKind::Unreachable => {} - TerminatorKind::Drop { target, unwind, .. } - | TerminatorKind::Assert { target, unwind, .. } => { + TerminatorKind::Drop { target, unwind, drop, .. } => { + self.assert_iscleanup(block_data, target, is_cleanup); + self.assert_iscleanup_unwind(block_data, unwind, is_cleanup); + if let Some(drop) = drop { + self.assert_iscleanup(block_data, drop, is_cleanup); + } + } + TerminatorKind::Assert { target, unwind, .. } => { self.assert_iscleanup(block_data, target, is_cleanup); self.assert_iscleanup_unwind(block_data, unwind, is_cleanup); } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index adaa754491e56..e9c7186b03c9f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -565,7 +565,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { | TerminatorKind::CoroutineDrop => { bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } - TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { + TerminatorKind::Drop { place, target, unwind: _, replace: _, drop, async_fut } => { + assert!( + async_fut.is_none() && drop.is_none(), + "Async Drop must be expanded or reset to sync before codegen" + ); let drop_place = codegen_place(fx, *place); crate::abi::codegen_drop(fx, source_info, drop_place, *target); } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d184ce3d61dea..135d5e44703fd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1386,8 +1386,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { MergingSucc::False } - mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => self - .codegen_drop_terminator( + mir::TerminatorKind::Drop { place, target, unwind, replace: _, drop, async_fut } => { + assert!( + async_fut.is_none() && drop.is_none(), + "Async Drop must be expanded or reset to sync before codegen" + ); + self.codegen_drop_terminator( helper, bx, &terminator.source_info, @@ -1395,7 +1399,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target, unwind, mergeable_succ(), - ), + ) + } mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self .codegen_assert_terminator( diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index ddf2d65914f6c..363ceee1970ee 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -539,7 +539,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Drop { place, target, unwind, replace: _ } => { + Drop { place, target, unwind, replace: _, drop, async_fut } => { + assert!( + async_fut.is_none() && drop.is_none(), + "Async Drop must be expanded or reset to sync in runtime MIR" + ); let place = self.eval_place(place)?; let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); if let ty::InstanceKind::DropGlue(_, None) = instance.def { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5a038b27337cf..b3a6794c9b666 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1050,7 +1050,13 @@ impl<'tcx> TerminatorKind<'tcx> { Call { target: None, unwind: _, .. } => vec![], Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], Yield { drop: None, .. } => vec!["resume".into()], - Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], + Drop { unwind: UnwindAction::Cleanup(_), drop: Some(_), .. } => { + vec!["return".into(), "unwind".into(), "drop".into()] + } + Drop { unwind: UnwindAction::Cleanup(_), drop: None, .. } => { + vec!["return".into(), "unwind".into()] + } + Drop { unwind: _, drop: Some(_), .. } => vec!["return".into(), "drop".into()], Drop { unwind: _, .. } => vec!["return".into()], Assert { unwind: UnwindAction::Cleanup(_), .. } => { vec!["success".into(), "unwind".into()] diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 707c8d04d557f..1513d43b82f54 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -77,6 +77,8 @@ pub enum MirPhase { /// exception is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be /// misaligned for this reason implicitly moves `P` to a temporary before dropping. Runtime /// MIR has no such rules, and dropping a misaligned place is simply UB. + /// - Async drops: after drop elaboration some drops may become async (`drop`, `async_fut` fields). + /// StateTransform pass will expand those async drops or reset to sync. /// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In /// runtime MIR, this is UB. /// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same @@ -766,7 +768,34 @@ pub enum TerminatorKind<'tcx> { /// The `replace` flag indicates whether this terminator was created as part of an assignment. /// This should only be used for diagnostic purposes, and does not have any operational /// meaning. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool }, + /// + /// Async drop processing: + /// In compiler/rustc_mir_build/src/build/scope.rs we detect possible async drop: + /// drop of object with `needs_async_drop`. + /// Async drop later, in StateTransform pass, may be expanded into additional yield-point + /// for poll-loop of async drop future. + /// So we need prepared 'drop' target block in the similar way as for `Yield` terminator + /// (see `drops.build_mir::` in scopes.rs). + /// In compiler/rustc_mir_transform/src/elaborate_drops.rs for object implementing `AsyncDrop` trait + /// we need to prepare async drop feature - resolve `AsyncDrop::drop` and codegen call. + /// `async_fut` is set to the corresponding local. + /// For coroutine drop we don't need this logic because coroutine drop works with the same + /// layout object as coroutine itself. So `async_fut` will be `None` for coroutine drop. + /// Both `drop` and `async_fut` fields are only used in compiler/rustc_mir_transform/src/coroutine.rs, + /// StateTransform pass. In `expand_async_drops` async drops are expanded + /// into one or two yield points with poll ready/pending switch. + /// When a coroutine has any internal async drop, the coroutine drop function will be async + /// (generated by `create_coroutine_drop_shim_async`, not `create_coroutine_drop_shim`). + Drop { + place: Place<'tcx>, + target: BasicBlock, + unwind: UnwindAction, + replace: bool, + /// Cleanup to be done if the coroutine is dropped at this suspend point (for async drop). + drop: Option, + /// Prepared async future local (for async drop) + async_fut: Option, + }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of /// the referred to function. The operand types must match the argument types of the function. diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index b2c51ad88645c..987b48ad6a65b 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -457,7 +457,7 @@ mod helper { #[cfg_attr(not(bootstrap), define_opaque(Successors))] pub fn successors_for_value(&self, value: u128) -> Successors<'_> { let target = self.target_for_value(value); - (&[]).into_iter().copied().chain(Some(target)) + (&[]).into_iter().copied().chain(Some(target).into_iter().chain(None)) } } @@ -467,13 +467,23 @@ mod helper { pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { + // 3-successors for async drop: target, unwind, dropline (parent coroutine drop) + Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: Some(d), .. } => { + slice::from_ref(t) + .into_iter() + .copied() + .chain(Some(u).into_iter().chain(Some(d))) + } + // 2-successors Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. } | Yield { resume: ref t, drop: Some(u), .. } - | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. } + | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: None, .. } + | Drop { target: ref t, unwind: _, drop: Some(u), .. } | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. } | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => { - slice::from_ref(t).into_iter().copied().chain(Some(u)) + slice::from_ref(t).into_iter().copied().chain(Some(u).into_iter().chain(None)) } + // single successor Goto { target: ref t } | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. } | Call { target: Some(ref t), unwind: _, .. } @@ -481,23 +491,33 @@ mod helper { | Drop { target: ref t, unwind: _, .. } | Assert { target: ref t, unwind: _, .. } | FalseUnwind { real_target: ref t, unwind: _ } => { - slice::from_ref(t).into_iter().copied().chain(None) + slice::from_ref(t).into_iter().copied().chain(None.into_iter().chain(None)) } + // No successors UnwindResume | UnwindTerminate(_) | CoroutineDrop | Return | Unreachable | TailCall { .. } - | Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None), + | Call { target: None, unwind: _, .. } => { + (&[]).into_iter().copied().chain(None.into_iter().chain(None)) + } + // Multiple successors InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => { - targets.iter().copied().chain(Some(u)) + targets.iter().copied().chain(Some(u).into_iter().chain(None)) + } + InlineAsm { ref targets, unwind: _, .. } => { + targets.iter().copied().chain(None.into_iter().chain(None)) } - InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None), - SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None), - FalseEdge { ref real_target, imaginary_target } => { - slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target)) + SwitchInt { ref targets, .. } => { + targets.targets.iter().copied().chain(None.into_iter().chain(None)) } + // FalseEdge + FalseEdge { ref real_target, imaginary_target } => slice::from_ref(real_target) + .into_iter() + .copied() + .chain(Some(imaginary_target).into_iter().chain(None)), } } @@ -506,16 +526,31 @@ mod helper { pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { use self::TerminatorKind::*; match *self { + // 3-successors for async drop: target, unwind, dropline (parent coroutine drop) + Drop { + target: ref mut t, + unwind: UnwindAction::Cleanup(ref mut u), + drop: Some(ref mut d), + .. + } => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(Some(d))), + // 2-successors Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. } | Yield { resume: ref mut t, drop: Some(ref mut u), .. } - | Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } + | Drop { + target: ref mut t, + unwind: UnwindAction::Cleanup(ref mut u), + drop: None, + .. + } + | Drop { target: ref mut t, unwind: _, drop: Some(ref mut u), .. } | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } | FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), - } => slice::from_mut(t).into_iter().chain(Some(u)), + } => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(None)), + // single successor Goto { target: ref mut t } | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. } | Call { target: Some(ref mut t), unwind: _, .. } @@ -523,22 +558,33 @@ mod helper { | Drop { target: ref mut t, unwind: _, .. } | Assert { target: ref mut t, unwind: _, .. } | FalseUnwind { real_target: ref mut t, unwind: _ } => { - slice::from_mut(t).into_iter().chain(None) + slice::from_mut(t).into_iter().chain(None.into_iter().chain(None)) } + // No successors UnwindResume | UnwindTerminate(_) | CoroutineDrop | Return | Unreachable | TailCall { .. } - | Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None), + | Call { target: None, unwind: _, .. } => { + (&mut []).into_iter().chain(None.into_iter().chain(None)) + } + // Multiple successors InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => { - targets.iter_mut().chain(Some(u)) + targets.iter_mut().chain(Some(u).into_iter().chain(None)) + } + InlineAsm { ref mut targets, unwind: _, .. } => { + targets.iter_mut().chain(None.into_iter().chain(None)) + } + SwitchInt { ref mut targets, .. } => { + targets.targets.iter_mut().chain(None.into_iter().chain(None)) } - InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None), - SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None), + // FalseEdge FalseEdge { ref mut real_target, ref mut imaginary_target } => { - slice::from_mut(real_target).into_iter().chain(Some(imaginary_target)) + slice::from_mut(real_target) + .into_iter() + .chain(Some(imaginary_target).into_iter().chain(None)) } } } @@ -671,8 +717,10 @@ impl<'tcx> TerminatorKind<'tcx> { Goto { target } => TerminatorEdges::Single(target), + // FIXME: Maybe we need also TerminatorEdges::Trio for async drop + // (target + unwind + dropline) Assert { target, unwind, expected: _, msg: _, cond: _ } - | Drop { target, unwind, place: _, replace: _ } + | Drop { target, unwind, place: _, replace: _, drop: _, async_fut: _ } | FalseUnwind { real_target: target, unwind } => match unwind { UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind), UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 3c83d962900ae..69b7aef320650 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -515,7 +515,14 @@ macro_rules! make_mir_visitor { self.visit_operand(discr, location); } - TerminatorKind::Drop { place, target: _, unwind: _, replace: _ } => { + TerminatorKind::Drop { + place, + target: _, + unwind: _, + replace: _, + drop: _, + async_fut: _, + } => { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Drop), diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 19669021eefb4..59e03fa79a050 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -69,6 +69,8 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { target: self.parse_return_to(args[1])?, unwind: self.parse_unwind_action(args[2])?, replace: false, + drop: None, + async_fut: None, }) }, @call(mir_call, args) => { diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index f9791776f71e5..5a97b08db28d6 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -762,6 +762,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target: success, unwind: UnwindAction::Continue, replace: false, + drop: None, + async_fut: None, }, ); this.diverge_from(block); diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index e42336a1dbbcc..79225c87d61fd 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -405,6 +405,8 @@ impl DropTree { unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup), place: drop_node.data.local.into(), replace: false, + drop: None, + async_fut: None, }; cfg.terminate(block, drop_node.data.source_info, terminator); } @@ -848,6 +850,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target: next, unwind: UnwindAction::Continue, replace: false, + drop: None, + async_fut: None, }, ); block = next; @@ -1371,6 +1375,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target: assign, unwind: UnwindAction::Cleanup(assign_unwind), replace: true, + drop: None, + async_fut: None, }, ); self.diverge_from(block); @@ -1510,6 +1516,8 @@ fn build_scope_drops<'tcx>( target: next, unwind: UnwindAction::Continue, replace: false, + drop: None, + async_fut: None, }, ); block = next; diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index f5ffc42d52ab0..18165b0b9bd08 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -376,7 +376,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { // the result of `is_unwind_dead`. let mut edges = terminator.edges(); if self.skip_unreachable_unwind - && let mir::TerminatorKind::Drop { target, unwind, place, replace: _ } = terminator.kind + && let mir::TerminatorKind::Drop { + target, + unwind, + place, + replace: _, + drop: _, + async_fut: _, + } = terminator.kind && matches!(unwind, mir::UnwindAction::Cleanup(_)) && self.is_unwind_dead(place, state) { diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index b33326cb873df..a414d120e68b5 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -83,7 +83,9 @@ fn add_move_for_packed_drop<'tcx>( is_cleanup: bool, ) { debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); - let TerminatorKind::Drop { ref place, target, unwind, replace } = terminator.kind else { + let TerminatorKind::Drop { ref place, target, unwind, replace, drop, async_fut } = + terminator.kind + else { unreachable!(); }; @@ -106,6 +108,8 @@ fn add_move_for_packed_drop<'tcx>( target: storage_dead_block, unwind, replace, + drop, + async_fut, }, ); } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 04d96f117072f..c41c4abec7117 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1077,7 +1077,8 @@ fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let (target, unwind, source_info) = match block_data.terminator() { Terminator { source_info, - kind: TerminatorKind::Drop { place, target, unwind, replace: _ }, + kind: + TerminatorKind::Drop { place, target, unwind, replace: _, drop: _, async_fut: _ }, } => { if let Some(local) = place.as_local() && local == SELF_ARG @@ -1365,6 +1366,8 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { target: return_block, unwind: UnwindAction::Continue, replace: false, + drop: None, + async_fut: None, }; let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 0d8cf524661c8..a824f82d7edce 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -229,6 +229,8 @@ where target: self.succ, unwind: self.unwind.into_action(), replace: false, + drop: None, + async_fut: None, }, ); } @@ -755,6 +757,8 @@ where target: loop_block, unwind: unwind.into_action(), replace: false, + drop: None, + async_fut: None, }, ); @@ -992,6 +996,8 @@ where target, unwind: unwind.into_action(), replace: false, + drop: None, + async_fut: None, }; self.new_block(unwind, block) } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 530c72ca549a6..8f11085082fd3 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -328,7 +328,9 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { // This function should mirror what `collect_drop_flags` does. for (bb, data) in self.body.basic_blocks.iter_enumerated() { let terminator = data.terminator(); - let TerminatorKind::Drop { place, target, unwind, replace } = terminator.kind else { + let TerminatorKind::Drop { place, target, unwind, replace, drop: _, async_fut: _ } = + terminator.kind + else { continue; }; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 0ab24e48d443c..e2526acc63d28 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -413,7 +413,15 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { let term = blk.terminator(); let caller_attrs = tcx.codegen_fn_attrs(self.caller_def_id()); - if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind { + if let TerminatorKind::Drop { + ref place, + target, + unwind, + replace: _, + drop: _, + async_fut: _, + } = term.kind + { work_list.push(target); // If the place doesn't actually need dropping, treat it like a regular goto. diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 29a9133abe93d..496335ee3c12f 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -134,6 +134,8 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { target: _, unwind: _, replace: _, + drop: _, + async_fut: _, } = &terminator.kind && place_has_common_prefix(dropped_place, self.place) { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c9771467e499c..70a7265980986 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -621,6 +621,8 @@ impl<'tcx> CloneShimBuilder<'tcx> { target: unwind, unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup), replace: false, + drop: None, + async_fut: None, }, /* is_cleanup */ true, ); @@ -886,6 +888,8 @@ fn build_call_shim<'tcx>( target: BasicBlock::new(2), unwind: UnwindAction::Continue, replace: false, + drop: None, + async_fut: None, }, false, ); @@ -903,6 +907,8 @@ fn build_call_shim<'tcx>( target: BasicBlock::new(4), unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup), replace: false, + drop: None, + async_fut: None, }, /* is_cleanup */ true, ); diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index 94b1b4b1855b5..e7ef8bf5489c2 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -424,6 +424,8 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { UnwindTerminateReason::InCleanup, ), replace: false, + drop: None, + async_fut: None, } } else { TerminatorKind::Goto { target: *top_cleanup_bb } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index e7930f0a1e3f6..4647839b95c2a 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -373,9 +373,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { ); } } - TerminatorKind::Drop { target, unwind, .. } => { + TerminatorKind::Drop { target, unwind, drop, .. } => { self.check_edge(location, *target, EdgeKind::Normal); self.check_unwind_edge(location, *unwind); + if let Some(drop) = drop { + self.check_edge(location, *drop, EdgeKind::Normal); + } } TerminatorKind::Call { func, args, .. } | TerminatorKind::TailCall { func, args, .. } => { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 61b769bce0831..500d1bd69947a 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -648,13 +648,18 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort, mir::TerminatorKind::Return => TerminatorKind::Return, mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable, - mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => { - TerminatorKind::Drop { - place: place.stable(tables), - target: target.as_usize(), - unwind: unwind.stable(tables), - } - } + mir::TerminatorKind::Drop { + place, + target, + unwind, + replace: _, + drop: _, + async_fut: _, + } => TerminatorKind::Drop { + place: place.stable(tables), + target: target.as_usize(), + unwind: unwind.stable(tables), + }, mir::TerminatorKind::Call { func, args, From 92d848f0900dcdcf00c7017d7d60e0957b11227e Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Mon, 26 Aug 2024 18:16:42 +0300 Subject: [PATCH 2/4] Prereq2 for async drop - ResumedAfterDrop panic messages --- .../src/const_eval/machine.rs | 1 + compiler/rustc_hir/src/lang_items.rs | 4 + compiler/rustc_middle/messages.ftl | 6 ++ compiler/rustc_middle/src/mir/syntax.rs | 1 + compiler/rustc_middle/src/mir/terminator.rs | 40 +++++++- compiler/rustc_middle/src/mir/visit.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 3 + .../rustc_smir/src/stable_mir/mir/body.rs | 17 ++++ .../rustc_smir/src/stable_mir/mir/pretty.rs | 4 +- .../rustc_smir/src/stable_mir/mir/visit.rs | 3 +- compiler/rustc_span/src/symbol.rs | 4 + library/core/src/panicking.rs | 94 ++++++++++--------- 12 files changed, 132 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 61a7ec13511c2..7c7daed525b2d 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -502,6 +502,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { RemainderByZero(op) => RemainderByZero(eval_to_int(op)?), ResumedAfterReturn(coroutine_kind) => ResumedAfterReturn(*coroutine_kind), ResumedAfterPanic(coroutine_kind) => ResumedAfterPanic(*coroutine_kind), + ResumedAfterDrop(coroutine_kind) => ResumedAfterDrop(*coroutine_kind), MisalignedPointerDereference { required, found } => MisalignedPointerDereference { required: eval_to_int(required)?, found: eval_to_int(found)?, diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 90fab01ba2d45..6665fdce6ec99 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -318,6 +318,10 @@ language_item_table! { PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None; PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None; PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None; + PanicCoroutineResumedDrop, sym::panic_const_coroutine_resumed_drop, panic_const_coroutine_resumed_drop, Target::Fn, GenericRequirement::None; + PanicAsyncFnResumedDrop, sym::panic_const_async_fn_resumed_drop, panic_const_async_fn_resumed_drop, Target::Fn, GenericRequirement::None; + PanicAsyncGenFnResumedDrop, sym::panic_const_async_gen_fn_resumed_drop, panic_const_async_gen_fn_resumed_drop, Target::Fn, GenericRequirement::None; + PanicGenFnNoneDrop, sym::panic_const_gen_fn_none_drop, panic_const_gen_fn_none_drop, Target::Fn, GenericRequirement::None; /// libstd panic entry point. Necessary for const eval to be able to catch it BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 0b3c0be1a4e1a..3d27e587b6cb4 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -1,7 +1,11 @@ +middle_assert_async_resume_after_drop = `async fn` resumed after async drop + middle_assert_async_resume_after_panic = `async fn` resumed after panicking middle_assert_async_resume_after_return = `async fn` resumed after completion +middle_assert_coroutine_resume_after_drop = coroutine resumed after async drop + middle_assert_coroutine_resume_after_panic = coroutine resumed after panicking middle_assert_coroutine_resume_after_return = coroutine resumed after completion @@ -9,6 +13,8 @@ middle_assert_coroutine_resume_after_return = coroutine resumed after completion middle_assert_divide_by_zero = attempt to divide `{$val}` by zero +middle_assert_gen_resume_after_drop = `gen` fn or block cannot be further iterated on after it async dropped + middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further iterated on after it panicked middle_assert_misaligned_ptr_deref = diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1513d43b82f54..71ba2917b9b6a 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1066,6 +1066,7 @@ pub enum AssertKind { RemainderByZero(O), ResumedAfterReturn(CoroutineKind), ResumedAfterPanic(CoroutineKind), + ResumedAfterDrop(CoroutineKind), MisalignedPointerDereference { required: O, found: O }, NullPointerDereference, } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 987b48ad6a65b..ca9438b1ed64e 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -208,6 +208,16 @@ impl AssertKind { LangItem::PanicGenFnNonePanic } NullPointerDereference => LangItem::PanicNullPointerDereference, + ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop, + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + LangItem::PanicAsyncFnResumedDrop + } + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { + LangItem::PanicAsyncGenFnResumedDrop + } + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { + LangItem::PanicGenFnNoneDrop + } BoundsCheck { .. } | MisalignedPointerDereference { .. } => { bug!("Unexpected AssertKind") @@ -298,6 +308,18 @@ impl AssertKind { ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { write!(f, "\"`gen fn` should just keep returning `None` after panicking\"") } + ResumedAfterDrop(CoroutineKind::Coroutine(_)) => { + write!(f, "\"coroutine resumed after async drop\"") + } + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + write!(f, "\"`async fn` resumed after async drop\"") + } + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { + write!(f, "\"`async gen fn` resumed after async drop\"") + } + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { + write!(f, "\"`gen fn` resumed after drop\"") + } } } @@ -345,6 +367,19 @@ impl AssertKind { middle_assert_coroutine_resume_after_panic } NullPointerDereference => middle_assert_null_ptr_deref, + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + middle_assert_async_resume_after_drop + } + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { + todo!() + } + ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { + middle_assert_gen_resume_after_drop + } + ResumedAfterDrop(CoroutineKind::Coroutine(_)) => { + middle_assert_coroutine_resume_after_drop + } + MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref, } } @@ -377,7 +412,10 @@ impl AssertKind { add!("left", format!("{left:#?}")); add!("right", format!("{right:#?}")); } - ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {} + ResumedAfterReturn(_) + | ResumedAfterPanic(_) + | NullPointerDereference + | ResumedAfterDrop(_) => {} MisalignedPointerDereference { required, found } => { add!("required", format!("{required:#?}")); add!("found", format!("{found:#?}")); diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 69b7aef320650..9ff1ccef2cbf2 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -635,7 +635,7 @@ macro_rules! make_mir_visitor { OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { self.visit_operand(op, location); } - ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => { + ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference | ResumedAfterDrop(_) => { // Nothing to visit } MisalignedPointerDereference { required, found } => { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 500d1bd69947a..42b3e59b73ab9 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -494,6 +494,9 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { AssertKind::ResumedAfterPanic(coroutine) => { stable_mir::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables)) } + AssertKind::ResumedAfterDrop(coroutine) => { + stable_mir::mir::AssertMessage::ResumedAfterDrop(coroutine.stable(tables)) + } AssertKind::MisalignedPointerDereference { required, found } => { stable_mir::mir::AssertMessage::MisalignedPointerDereference { required: required.stable(tables), diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index b23605454246e..660cd7db0800d 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -267,6 +267,7 @@ pub enum AssertMessage { RemainderByZero(Operand), ResumedAfterReturn(CoroutineKind), ResumedAfterPanic(CoroutineKind), + ResumedAfterDrop(CoroutineKind), MisalignedPointerDereference { required: Operand, found: Operand }, NullPointerDereference, } @@ -320,6 +321,22 @@ impl AssertMessage { _, )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"), + AssertMessage::ResumedAfterDrop(CoroutineKind::Coroutine(_)) => { + Ok("coroutine resumed after async drop") + } + AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + _, + )) => Ok("`async fn` resumed after async drop"), + AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + _, + )) => Ok("`async gen fn` resumed after async drop"), + AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + _, + )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after async drop"), + AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"), AssertMessage::MisalignedPointerDereference { .. } => { Ok("misaligned pointer dereference") diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs index 439ebe978e591..7b96add854ad0 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs @@ -312,7 +312,9 @@ fn pretty_assert_message(writer: &mut W, msg: &AssertMessage) -> io::R AssertMessage::NullPointerDereference => { write!(writer, "\"null pointer dereference occurred\"") } - AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { + AssertMessage::ResumedAfterReturn(_) + | AssertMessage::ResumedAfterPanic(_) + | AssertMessage::ResumedAfterDrop(_) => { write!(writer, "{}", msg.description().unwrap()) } } diff --git a/compiler/rustc_smir/src/stable_mir/mir/visit.rs b/compiler/rustc_smir/src/stable_mir/mir/visit.rs index 786693ea98d36..e21dc11eea9ca 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/visit.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/visit.rs @@ -372,7 +372,8 @@ macro_rules! make_mir_visitor { } AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) - | AssertMessage::NullPointerDereference => { + | AssertMessage::NullPointerDereference + | AssertMessage::ResumedAfterDrop(_) => { //nothing to visit } AssertMessage::MisalignedPointerDereference { required, found } => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 31847ae3b4658..7bd0989f5fa14 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1518,14 +1518,18 @@ symbols! { panic_cannot_unwind, panic_const_add_overflow, panic_const_async_fn_resumed, + panic_const_async_fn_resumed_drop, panic_const_async_fn_resumed_panic, panic_const_async_gen_fn_resumed, + panic_const_async_gen_fn_resumed_drop, panic_const_async_gen_fn_resumed_panic, panic_const_coroutine_resumed, + panic_const_coroutine_resumed_drop, panic_const_coroutine_resumed_panic, panic_const_div_by_zero, panic_const_div_overflow, panic_const_gen_fn_none, + panic_const_gen_fn_none_drop, panic_const_gen_fn_none_panic, panic_const_mul_overflow, panic_const_neg_overflow, diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 33ad59916e391..83a45436b3050 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -155,30 +155,26 @@ pub const fn panic(expr: &'static str) -> ! { // reducing binary size impact. macro_rules! panic_const { ($($lang:ident = $message:expr,)+) => { - pub mod panic_const { - use super::*; - - $( - /// This is a panic called with a message that's a result of a MIR-produced Assert. - // - // never inline unless panic_immediate_abort to avoid code - // bloat at the call sites as much as possible - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] - #[cfg_attr(feature = "panic_immediate_abort", inline)] - #[track_caller] - #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable - #[lang = stringify!($lang)] - pub const fn $lang() -> ! { - // Use Arguments::new_const instead of format_args!("{expr}") to potentially - // reduce size overhead. The format_args! macro uses str's Display trait to - // write expr, which calls Formatter::pad, which must accommodate string - // truncation and padding (even though none is used here). Using - // Arguments::new_const may allow the compiler to omit Formatter::pad from the - // output binary, saving up to a few kilobytes. - panic_fmt(fmt::Arguments::new_const(&[$message])); - } - )+ - } + $( + /// This is a panic called with a message that's a result of a MIR-produced Assert. + // + // never inline unless panic_immediate_abort to avoid code + // bloat at the call sites as much as possible + #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] + #[cfg_attr(feature = "panic_immediate_abort", inline)] + #[track_caller] + #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable + #[lang = stringify!($lang)] + pub const fn $lang() -> ! { + // Use Arguments::new_const instead of format_args!("{expr}") to potentially + // reduce size overhead. The format_args! macro uses str's Display trait to + // write expr, which calls Formatter::pad, which must accommodate string + // truncation and padding (even though none is used here). Using + // Arguments::new_const may allow the compiler to omit Formatter::pad from the + // output binary, saving up to a few kilobytes. + panic_fmt(fmt::Arguments::new_const(&[$message])); + } + )+ } } @@ -186,25 +182,37 @@ macro_rules! panic_const { // slightly different forms. It's not clear if there's a good way to deduplicate without adding // special cases to the compiler (e.g., a const generic function wouldn't have a single definition // shared across crates, which is exactly what we want here). -panic_const! { - panic_const_add_overflow = "attempt to add with overflow", - panic_const_sub_overflow = "attempt to subtract with overflow", - panic_const_mul_overflow = "attempt to multiply with overflow", - panic_const_div_overflow = "attempt to divide with overflow", - panic_const_rem_overflow = "attempt to calculate the remainder with overflow", - panic_const_neg_overflow = "attempt to negate with overflow", - panic_const_shr_overflow = "attempt to shift right with overflow", - panic_const_shl_overflow = "attempt to shift left with overflow", - panic_const_div_by_zero = "attempt to divide by zero", - panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero", - panic_const_coroutine_resumed = "coroutine resumed after completion", - panic_const_async_fn_resumed = "`async fn` resumed after completion", - panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion", - panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion", - panic_const_coroutine_resumed_panic = "coroutine resumed after panicking", - panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking", - panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking", - panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking", +pub mod panic_const { + use super::*; + panic_const! { + panic_const_add_overflow = "attempt to add with overflow", + panic_const_sub_overflow = "attempt to subtract with overflow", + panic_const_mul_overflow = "attempt to multiply with overflow", + panic_const_div_overflow = "attempt to divide with overflow", + panic_const_rem_overflow = "attempt to calculate the remainder with overflow", + panic_const_neg_overflow = "attempt to negate with overflow", + panic_const_shr_overflow = "attempt to shift right with overflow", + panic_const_shl_overflow = "attempt to shift left with overflow", + panic_const_div_by_zero = "attempt to divide by zero", + panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero", + panic_const_coroutine_resumed = "coroutine resumed after completion", + panic_const_async_fn_resumed = "`async fn` resumed after completion", + panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion", + panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion", + panic_const_coroutine_resumed_panic = "coroutine resumed after panicking", + panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking", + panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking", + panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking", + } + // Separated panic constants list for async drop feature + // (May be joined when the corresponding lang items will be in the bootstrap) + #[cfg(not(bootstrap))] + panic_const! { + panic_const_coroutine_resumed_drop = "coroutine resumed after async drop", + panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop", + panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop", + panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop", + } } /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller. From 900a39197e84576cc8e6d6102065e94416ab9644 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Mon, 26 Aug 2024 19:06:14 +0300 Subject: [PATCH 3/4] Prereq3 for async drop - LangItem registration for async_drop_in_place::{closure} --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_passes/src/lang_items.rs | 23 +++++++++++++++++++++++ compiler/rustc_passes/src/lib.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + 4 files changed, 26 insertions(+) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 6665fdce6ec99..d04456631eac6 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -192,6 +192,7 @@ language_item_table! { AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::Exact(0); AsyncDestruct, sym::async_destruct, async_destruct_trait, Target::Trait, GenericRequirement::Exact(0); AsyncDropInPlace, sym::async_drop_in_place, async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); + AsyncDropInPlacePoll, sym::async_drop_in_place_poll, async_drop_in_place_poll_fn, Target::Closure, GenericRequirement::Exact(1); SurfaceAsyncDropInPlace, sym::surface_async_drop_in_place, surface_async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); AsyncDropSurfaceDropInPlace, sym::async_drop_surface_drop_in_place, async_drop_surface_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); AsyncDropSlice, sym::async_drop_slice, async_drop_slice_fn, Target::Fn, GenericRequirement::Exact(1); diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 664bd4ad0a252..52ea0c0516b48 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -57,6 +57,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { &mut self, actual_target: Target, def_id: LocalDefId, + cor_def_id: Option, attrs: &'ast [ast::Attribute], item_span: Span, generics: Option<&'ast ast::Generics>, @@ -73,6 +74,18 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { generics, actual_target, ); + // We need to register LangItem::AsyncDropInPlacePoll + // for async_drop_in_place::{closure} + if cor_def_id.is_some() && lang_item == LangItem::AsyncDropInPlace { + self.collect_item_extended( + LangItem::AsyncDropInPlacePoll, + cor_def_id.unwrap(), + item_span, + attr_span, + generics, + actual_target, + ); + } } // Known lang item with attribute on incorrect target. Some(lang_item) => { @@ -288,10 +301,18 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { unreachable!("macros should have been expanded") } }; + let cor_def_id = if let ast::ItemKind::Fn(box ast::Fn { sig, .. }) = &i.kind + && let Some(kind) = sig.header.coroutine_kind + { + self.resolver.node_id_to_def_id.get(&kind.closure_id()).copied() + } else { + None + }; self.check_for_lang( target, self.resolver.node_id_to_def_id[&i.id], + cor_def_id, &i.attrs, i.span, i.opt_generics(), @@ -307,6 +328,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.check_for_lang( Target::Variant, self.resolver.node_id_to_def_id[&variant.id], + None, &variant.attrs, variant.span, None, @@ -349,6 +371,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.check_for_lang( target, self.resolver.node_id_to_def_id[&i.id], + None, &i.attrs, i.span, generics, diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 6f6115af96c87..9f3ebe639eeb7 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(box_patterns)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7bd0989f5fa14..51f660001fa2c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -508,6 +508,7 @@ symbols! { async_drop_either, async_drop_fuse, async_drop_in_place, + async_drop_in_place_poll, async_drop_noop, async_drop_slice, async_drop_surface_drop_in_place, From b1f3a6e6601cb495005996fa43a6fb97bd52a0df Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Tue, 27 Aug 2024 13:42:11 +0300 Subject: [PATCH 4/4] Prereq4 for async drop - needs_async_drop query fixes and some cleanup from previous async drop glue implementation --- .../rustc_codegen_cranelift/src/abi/mod.rs | 9 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 7 +- compiler/rustc_hir/src/lang_items.rs | 14 +- compiler/rustc_hir_typeck/src/callee.rs | 6 +- compiler/rustc_middle/src/query/mod.rs | 12 + compiler/rustc_middle/src/ty/context.rs | 1 - compiler/rustc_middle/src/ty/sty.rs | 126 +--- compiler/rustc_middle/src/ty/util.rs | 149 ++-- compiler/rustc_mir_transform/src/shim.rs | 6 +- .../src/shim/async_destructor_ctor.rs | 641 ------------------ .../src/solve/assembly/mod.rs | 8 - .../src/solve/effect_goals.rs | 7 - .../src/solve/normalizes_to/mod.rs | 60 -- .../src/solve/trait_goals.rs | 13 - compiler/rustc_span/src/symbol.rs | 11 - .../src/traits/project.rs | 42 -- .../src/traits/select/candidate_assembly.rs | 3 - compiler/rustc_ty_utils/src/common_traits.rs | 8 + compiler/rustc_ty_utils/src/instance.rs | 3 +- compiler/rustc_ty_utils/src/needs_drop.rs | 38 +- compiler/rustc_type_ir/src/inherent.rs | 1 - compiler/rustc_type_ir/src/lang_items.rs | 1 - library/core/src/future/async_drop.rs | 284 -------- library/core/src/future/mod.rs | 3 - library/core/src/ops/drop.rs | 7 - library/core/src/ops/mod.rs | 1 - src/tools/miri/tests/pass/async-drop.rs | 199 ------ tests/crashes/128695.rs | 11 - tests/ui/async-await/async-drop.rs | 222 ------ tests/ui/async-await/async-drop.run.stdout | 22 - .../async-await/async-drop/ex-ice-132103.rs} | 4 +- .../async-drop/ex-ice-132103.stderr | 9 + 32 files changed, 151 insertions(+), 1777 deletions(-) delete mode 100644 compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs delete mode 100644 library/core/src/future/async_drop.rs delete mode 100644 src/tools/miri/tests/pass/async-drop.rs delete mode 100644 tests/crashes/128695.rs delete mode 100644 tests/ui/async-await/async-drop.rs delete mode 100644 tests/ui/async-await/async-drop.run.stdout rename tests/{crashes/132103.rs => ui/async-await/async-drop/ex-ice-132103.rs} (73%) create mode 100644 tests/ui/async-await/async-drop/ex-ice-132103.stderr diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index ddd119e0c6108..5f631405a9a4a 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -441,7 +441,9 @@ pub(crate) fn codegen_terminator_call<'tcx>( Err(instance) => Some(instance), } } - InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => { + // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, + // it is `func returning noop future` + InstanceKind::DropGlue(_, None) => { // empty drop glue - a nop. let dest = target.expect("Non terminating drop_in_place_real???"); let ret_block = fx.get_block(dest); @@ -707,9 +709,8 @@ pub(crate) fn codegen_drop<'tcx>( let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty); - if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) = - drop_instance.def - { + // AsyncDropGlueCtorShim can't be here + if let ty::InstanceKind::DropGlue(_, None) = drop_instance.def { // we don't actually need to drop anything } else { match ty.kind() { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 135d5e44703fd..950f19a6f0f4e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -926,10 +926,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def = instance.map(|i| i.def); - if let Some( - ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None), - ) = def - { + // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, + // it is `func returning noop future` + if let Some(ty::InstanceKind::DropGlue(_, None)) = def { // Empty drop glue; a no-op. let target = target.unwrap(); return helper.funclet_br(self, bx, target, mergeable_succ); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index d04456631eac6..503b1df63236f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -188,20 +188,9 @@ language_item_table! { Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None; Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None; - - AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::Exact(0); - AsyncDestruct, sym::async_destruct, async_destruct_trait, Target::Trait, GenericRequirement::Exact(0); + AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::None; AsyncDropInPlace, sym::async_drop_in_place, async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); AsyncDropInPlacePoll, sym::async_drop_in_place_poll, async_drop_in_place_poll_fn, Target::Closure, GenericRequirement::Exact(1); - SurfaceAsyncDropInPlace, sym::surface_async_drop_in_place, surface_async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); - AsyncDropSurfaceDropInPlace, sym::async_drop_surface_drop_in_place, async_drop_surface_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); - AsyncDropSlice, sym::async_drop_slice, async_drop_slice_fn, Target::Fn, GenericRequirement::Exact(1); - AsyncDropChain, sym::async_drop_chain, async_drop_chain_fn, Target::Fn, GenericRequirement::Exact(2); - AsyncDropNoop, sym::async_drop_noop, async_drop_noop_fn, Target::Fn, GenericRequirement::Exact(0); - AsyncDropDeferredDropInPlace, sym::async_drop_deferred_drop_in_place, async_drop_deferred_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); - AsyncDropFuse, sym::async_drop_fuse, async_drop_fuse_fn, Target::Fn, GenericRequirement::Exact(1); - AsyncDropDefer, sym::async_drop_defer, async_drop_defer_fn, Target::Fn, GenericRequirement::Exact(1); - AsyncDropEither, sym::async_drop_either, async_drop_either_fn, Target::Fn, GenericRequirement::Exact(3); CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1); DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); @@ -335,7 +324,6 @@ language_item_table! { ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); - FallbackSurfaceDrop, sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; /// For all binary crates without `#![no_main]`, Rust will generate a "main" function. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 02fd7367e2f29..5f5e9e45612a7 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -34,11 +34,9 @@ pub(crate) fn check_legal_trait_for_method_call( receiver: Option, expr_span: Span, trait_id: DefId, - body_id: DefId, + _body_id: DefId, ) -> Result<(), ErrorGuaranteed> { - if tcx.is_lang_item(trait_id, LangItem::Drop) - && tcx.lang_items().fallback_surface_drop_fn() != Some(body_id) - { + if tcx.is_lang_item(trait_id, LangItem::Drop) { let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { errors::ExplicitDestructorCallSugg::Snippet { lo: expr_span.shrink_to_lo(), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0d5fba3cc69b4..f3d245f26ed70 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1575,6 +1575,10 @@ rustc_queries! { query is_unpin_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Unpin`", env.value } } + /// Query backing `Ty::is_async_drop`. + query is_async_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` is `AsyncDrop`", env.value } + } /// Query backing `Ty::needs_drop`. query needs_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` needs drop", env.value } @@ -1607,6 +1611,14 @@ rustc_queries! { cache_on_disk_if { true } } + /// A list of types where the ADT requires async drop if and only if any of + /// those types require async drop. If the ADT is known to always need async drop + /// then `Err(AlwaysRequiresDrop)` is returned. + query adt_async_drop_tys(def_id: DefId) -> Result<&'tcx ty::List>, AlwaysRequiresDrop> { + desc { |tcx| "computing when `{}` needs async drop", tcx.def_path_str(def_id) } + cache_on_disk_if { true } + } + /// A list of types where the ADT requires drop if and only if any of those types /// has significant drop. A type marked with the attribute `rustc_insignificant_dtor` /// is considered to not be significant. A drop is significant if it is implemented diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 162ca1f4af850..712b9e4861b61 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -694,7 +694,6 @@ macro_rules! bidirectional_lang_item_map { bidirectional_lang_item_map! { // tidy-alphabetical-start - AsyncDestruct, AsyncFn, AsyncFnKindHelper, AsyncFnKindUpvars, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 27ee363f1c142..c385cedeb35cf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -4,7 +4,6 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; -use std::iter; use std::ops::{ControlFlow, Range}; use hir::def::{CtorKind, DefKind}; @@ -18,7 +17,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_type_ir::TyKind::*; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate}; use tracing::instrument; -use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; +use ty::util::IntTypeExt; use super::GenericParamDefKind; use crate::infer::canonical::Canonical; @@ -1045,10 +1044,6 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { self.discriminant_ty(interner) } - fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> { - self.async_destructor_ty(interner) - } - fn has_unsafe_fields(self) -> bool { Ty::has_unsafe_fields(self) } @@ -1559,125 +1554,6 @@ impl<'tcx> Ty<'tcx> { } } - /// Returns the type of the async destructor of this type. - pub fn async_destructor_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.async_drop_glue_morphology(tcx) { - AsyncDropGlueMorphology::Noop => { - return Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop) - .instantiate_identity(); - } - AsyncDropGlueMorphology::DeferredDropInPlace => { - let drop_in_place = - Ty::async_destructor_combinator(tcx, LangItem::AsyncDropDeferredDropInPlace) - .instantiate(tcx, &[self.into()]); - return Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) - .instantiate(tcx, &[drop_in_place.into()]); - } - AsyncDropGlueMorphology::Custom => (), - } - - match *self.kind() { - ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { - let assoc_items = tcx - .associated_item_def_ids(tcx.require_lang_item(LangItem::AsyncDestruct, None)); - Ty::new_projection(tcx, assoc_items[0], [self]) - } - - ty::Array(elem_ty, _) | ty::Slice(elem_ty) => { - let dtor = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropSlice) - .instantiate(tcx, &[elem_ty.into()]); - Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) - .instantiate(tcx, &[dtor.into()]) - } - - ty::Adt(adt_def, args) if adt_def.is_enum() || adt_def.is_struct() => self - .adt_async_destructor_ty( - tcx, - adt_def.variants().iter().map(|v| v.fields.iter().map(|f| f.ty(tcx, args))), - ), - ty::Tuple(tys) => self.adt_async_destructor_ty(tcx, iter::once(tys)), - ty::Closure(_, args) => { - self.adt_async_destructor_ty(tcx, iter::once(args.as_closure().upvar_tys())) - } - ty::CoroutineClosure(_, args) => self - .adt_async_destructor_ty(tcx, iter::once(args.as_coroutine_closure().upvar_tys())), - - ty::Adt(adt_def, _) => { - assert!(adt_def.is_union()); - - let surface_drop = self.surface_async_dropper_ty(tcx).unwrap(); - - Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) - .instantiate(tcx, &[surface_drop.into()]) - } - - ty::Bound(..) - | ty::Foreign(_) - | ty::Placeholder(_) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`async_destructor_ty` applied to unexpected type: {self:?}") - } - - _ => bug!("`async_destructor_ty` is not yet implemented for type: {self:?}"), - } - } - - fn adt_async_destructor_ty(self, tcx: TyCtxt<'tcx>, variants: I) -> Ty<'tcx> - where - I: Iterator + ExactSizeIterator, - I::Item: IntoIterator>, - { - debug_assert_eq!(self.async_drop_glue_morphology(tcx), AsyncDropGlueMorphology::Custom); - - let defer = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropDefer); - let chain = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain); - - let noop = - Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop).instantiate_identity(); - let either = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropEither); - - let variants_dtor = variants - .into_iter() - .map(|variant| { - variant - .into_iter() - .map(|ty| defer.instantiate(tcx, &[ty.into()])) - .reduce(|acc, next| chain.instantiate(tcx, &[acc.into(), next.into()])) - .unwrap_or(noop) - }) - .reduce(|other, matched| { - either.instantiate(tcx, &[other.into(), matched.into(), self.into()]) - }) - .unwrap(); - - let dtor = if let Some(dropper_ty) = self.surface_async_dropper_ty(tcx) { - Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain) - .instantiate(tcx, &[dropper_ty.into(), variants_dtor.into()]) - } else { - variants_dtor - }; - - Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) - .instantiate(tcx, &[dtor.into()]) - } - - fn surface_async_dropper_ty(self, tcx: TyCtxt<'tcx>) -> Option> { - let adt_def = self.ty_adt_def()?; - let dropper = adt_def - .async_destructor(tcx) - .map(|_| LangItem::SurfaceAsyncDropInPlace) - .or_else(|| adt_def.destructor(tcx).map(|_| LangItem::AsyncDropSurfaceDropInPlace))?; - Some(Ty::async_destructor_combinator(tcx, dropper).instantiate(tcx, &[self.into()])) - } - - fn async_destructor_combinator( - tcx: TyCtxt<'tcx>, - lang_item: LangItem, - ) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { - tcx.fn_sig(tcx.require_lang_item(lang_item, None)) - .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap()) - } - /// Returns the type of metadata for (potentially wide) pointers to this type, /// or the struct tail if the metadata type cannot be determined. pub fn ptr_metadata_ty_or_tail( diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e4863896fc8b3..16290efe4f3f7 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -468,25 +468,6 @@ impl<'tcx> TyCtxt<'tcx> { Some(ty::AsyncDestructor { impl_did: dtor_candidate? }) } - /// Returns async drop glue morphology for a definition. To get async drop - /// glue morphology for a type see [`Ty::async_drop_glue_morphology`]. - // - // FIXME: consider making this a query - pub fn async_drop_glue_morphology(self, did: DefId) -> AsyncDropGlueMorphology { - let ty: Ty<'tcx> = self.type_of(did).instantiate_identity(); - - // Async drop glue morphology is an internal detail, so - // using `TypingMode::PostAnalysis` probably should be fine. - let typing_env = ty::TypingEnv::fully_monomorphized(); - if ty.needs_async_drop(self, typing_env) { - AsyncDropGlueMorphology::Custom - } else if ty.needs_drop(self, typing_env) { - AsyncDropGlueMorphology::DeferredDropInPlace - } else { - AsyncDropGlueMorphology::Noop - } - } - /// Returns the set of types that are required to be alive in /// order to run the destructor of `def` (see RFCs 769 and /// 1238). @@ -1114,18 +1095,6 @@ impl<'tcx> TypeFolder> for WeakAliasTypeExpander<'tcx> { } } -/// Indicates the form of `AsyncDestruct::Destructor`. Used to simplify async -/// drop glue for types not using async drop. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum AsyncDropGlueMorphology { - /// Async destructor simply does nothing - Noop, - /// Async destructor simply runs `drop_in_place` - DeferredDropInPlace, - /// Async destructor has custom logic - Custom, -} - impl<'tcx> Ty<'tcx> { /// Returns the `Size` for primitive types (bool, uint, int, char, float). pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size { @@ -1295,16 +1264,17 @@ impl<'tcx> Ty<'tcx> { } } - /// Get morphology of the async drop glue, needed for types which do not - /// use async drop. To get async drop glue morphology for a definition see - /// [`TyCtxt::async_drop_glue_morphology`]. Used for `AsyncDestruct::Destructor` - /// type construction. - // - // FIXME: implement optimization to not instantiate a certain morphology of - // async drop glue too soon to allow per type optimizations, see array case - // for more info. Perhaps then remove this method and use `needs_(async_)drop` - // instead. - pub fn async_drop_glue_morphology(self, tcx: TyCtxt<'tcx>) -> AsyncDropGlueMorphology { + /// Checks whether values of this type `T` implement the `AsyncDrop` trait. + pub fn is_async_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + !self.is_trivially_not_async_drop() + && tcx.is_async_drop_raw(typing_env.as_query_input(self)) + } + + /// Fast path helper for testing if a type is `AsyncDrop`. + /// + /// Returning true means the type is known to be `!AsyncDrop`. Returning + /// `false` means nothing -- could be `AsyncDrop`, might not be. + fn is_trivially_not_async_drop(self) -> bool { match self.kind() { ty::Int(_) | ty::Uint(_) @@ -1316,46 +1286,26 @@ impl<'tcx> Ty<'tcx> { | ty::Ref(..) | ty::RawPtr(..) | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => AsyncDropGlueMorphology::Noop, - + | ty::Error(_) + | ty::FnPtr(..) => true, // FIXME(unsafe_binders): ty::UnsafeBinder(_) => todo!(), - - ty::Tuple(tys) if tys.is_empty() => AsyncDropGlueMorphology::Noop, - ty::Adt(adt_def, _) if adt_def.is_manually_drop() => AsyncDropGlueMorphology::Noop, - - // Foreign types can never have destructors. - ty::Foreign(_) => AsyncDropGlueMorphology::Noop, - - // FIXME: implement dynamic types async drops - ty::Error(_) | ty::Dynamic(..) => AsyncDropGlueMorphology::DeferredDropInPlace, - - ty::Tuple(_) | ty::Array(_, _) | ty::Slice(_) => { - // Assume worst-case scenario, because we can instantiate async - // destructors in different orders: - // - // 1. Instantiate [T; N] with T = String and N = 0 - // 2. Instantiate <[String; 0] as AsyncDestruct>::Destructor - // - // And viceversa, thus we cannot rely on String not using async - // drop or array having zero (0) elements - AsyncDropGlueMorphology::Custom - } - ty::Pat(ty, _) => ty.async_drop_glue_morphology(tcx), - - ty::Adt(adt_def, _) => tcx.async_drop_glue_morphology(adt_def.did()), - - ty::Closure(did, _) - | ty::CoroutineClosure(did, _) - | ty::Coroutine(did, _) - | ty::CoroutineWitness(did, _) => tcx.async_drop_glue_morphology(*did), - - ty::Alias(..) | ty::Param(_) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(_) => { - // No specifics, but would usually mean forwarding async drop glue - AsyncDropGlueMorphology::Custom + ty::Tuple(fields) => fields.iter().all(Self::is_trivially_not_async_drop), + ty::Pat(elem_ty, _) | ty::Slice(elem_ty) | ty::Array(elem_ty, _) => { + elem_ty.is_trivially_not_async_drop() } + ty::Adt(..) + | ty::Bound(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Dynamic(..) + | ty::Foreign(_) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Infer(_) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(_) => false, } } @@ -1401,9 +1351,6 @@ impl<'tcx> Ty<'tcx> { /// (Note that this implies that if `ty` has an async destructor attached, /// then `needs_async_drop` will definitely return `true` for `ty`.) /// - /// When constructing `AsyncDestruct::Destructor` type, use - /// [`Ty::async_drop_glue_morphology`] instead. - // // FIXME(zetanumbers): Note that this method is used to check eligible types // in unions. #[inline] @@ -1638,6 +1585,46 @@ pub fn needs_drop_components_with_async<'tcx>( } } +pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { + match *ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Str + | ty::RawPtr(_, _) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Never + | ty::Foreign(_) => true, + + ty::Alias(..) + | ty::Dynamic(..) + | ty::Error(_) + | ty::Bound(..) + | ty::Param(_) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::UnsafeBinder(_) => false, + + // Not trivial because they have components, and instead of looking inside, + // we'll just perform trait selection. + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Adt(..) => false, + + ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => is_trivially_const_drop(ty), + + ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)), + } +} + /// Does the equivalent of /// ```ignore (illustrative) /// let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 70a7265980986..e02283d15c91a 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -23,8 +23,6 @@ use crate::{ instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify, }; -mod async_destructor_ctor; - pub(super) fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } @@ -129,8 +127,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< 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), - ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) => { - async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty) + ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, _ty) => { + bug!("AsyncDropGlueCtorShim in re-working ({:?})", instance) } ty::InstanceKind::Virtual(..) => { bug!("InstanceKind::Virtual ({:?}) is for direct calls only", instance) diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs deleted file mode 100644 index e7ef8bf5489c2..0000000000000 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ /dev/null @@ -1,641 +0,0 @@ -use std::iter; - -use itertools::Itertools; -use rustc_abi::{FieldIdx, VariantIdx}; -use rustc_const_eval::interpret; -use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; -use rustc_index::{Idx, IndexVec}; -use rustc_middle::mir::*; -use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::util::{AsyncDropGlueMorphology, Discr}; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::{bug, span_bug}; -use rustc_span::source_map::respan; -use rustc_span::{Span, Symbol}; -use rustc_target::spec::PanicStrategy; -use tracing::debug; - -use super::{local_decls_for_sig, new_body}; - -pub(super) fn build_async_destructor_ctor_shim<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - ty: Option>, -) -> Body<'tcx> { - debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); - - AsyncDestructorCtorShimBuilder::new(tcx, def_id, ty).build() -} - -/// Builder for async_drop_in_place shim. Functions as a stack machine -/// to build up an expression using combinators. Stack contains pairs -/// of locals and types. Combinator is a not yet instantiated pair of a -/// function and a type, is considered to be an operator which consumes -/// operands from the stack by instantiating its function and its type -/// with operand types and moving locals into the function call. Top -/// pair is considered to be the last operand. -// FIXME: add mir-opt tests -struct AsyncDestructorCtorShimBuilder<'tcx> { - tcx: TyCtxt<'tcx>, - def_id: DefId, - self_ty: Option>, - span: Span, - source_info: SourceInfo, - typing_env: ty::TypingEnv<'tcx>, - - stack: Vec>, - last_bb: BasicBlock, - top_cleanup_bb: Option, - - locals: IndexVec>, - bbs: IndexVec>, -} - -#[derive(Clone, Copy)] -enum SurfaceDropKind { - Async, - Sync, -} - -impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { - const SELF_PTR: Local = Local::from_u32(1); - const INPUT_COUNT: usize = 1; - const MAX_STACK_LEN: usize = 2; - - fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Option>) -> Self { - let args = if let Some(ty) = self_ty { - tcx.mk_args(&[ty.into()]) - } else { - ty::GenericArgs::identity_for_item(tcx, def_id) - }; - let sig = tcx.fn_sig(def_id).instantiate(tcx, args); - let sig = tcx.instantiate_bound_regions_with_erased(sig); - let span = tcx.def_span(def_id); - - let source_info = SourceInfo::outermost(span); - - debug_assert_eq!(sig.inputs().len(), Self::INPUT_COUNT); - let locals = local_decls_for_sig(&sig, span); - - // Usual case: noop() + unwind resume + return - let mut bbs = IndexVec::with_capacity(3); - let typing_env = ty::TypingEnv::post_analysis(tcx, def_id); - AsyncDestructorCtorShimBuilder { - tcx, - def_id, - self_ty, - span, - source_info, - typing_env, - - stack: Vec::with_capacity(Self::MAX_STACK_LEN), - last_bb: bbs.push(BasicBlockData::new(None, false)), - top_cleanup_bb: match tcx.sess.panic_strategy() { - PanicStrategy::Unwind => { - // Don't drop input arg because it's just a pointer - Some(bbs.push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::UnwindResume, - }), - is_cleanup: true, - })) - } - PanicStrategy::Abort => None, - }, - - locals, - bbs, - } - } - - fn build(self) -> Body<'tcx> { - let (tcx, Some(self_ty)) = (self.tcx, self.self_ty) else { - return self.build_zst_output(); - }; - match self_ty.async_drop_glue_morphology(tcx) { - AsyncDropGlueMorphology::Noop => span_bug!( - self.span, - "async drop glue shim generator encountered type with noop async drop glue morphology" - ), - AsyncDropGlueMorphology::DeferredDropInPlace => { - return self.build_deferred_drop_in_place(); - } - AsyncDropGlueMorphology::Custom => (), - } - - let surface_drop_kind = || { - let adt_def = self_ty.ty_adt_def()?; - if adt_def.async_destructor(tcx).is_some() { - Some(SurfaceDropKind::Async) - } else if adt_def.destructor(tcx).is_some() { - Some(SurfaceDropKind::Sync) - } else { - None - } - }; - - match self_ty.kind() { - ty::Array(elem_ty, _) => self.build_slice(true, *elem_ty), - ty::Slice(elem_ty) => self.build_slice(false, *elem_ty), - - ty::Tuple(elem_tys) => self.build_chain(None, elem_tys.iter()), - ty::Adt(adt_def, args) if adt_def.is_struct() => { - let field_tys = adt_def.non_enum_variant().fields.iter().map(|f| f.ty(tcx, args)); - self.build_chain(surface_drop_kind(), field_tys) - } - ty::Closure(_, args) => self.build_chain(None, args.as_closure().upvar_tys().iter()), - ty::CoroutineClosure(_, args) => { - self.build_chain(None, args.as_coroutine_closure().upvar_tys().iter()) - } - - ty::Adt(adt_def, args) if adt_def.is_enum() => { - self.build_enum(*adt_def, *args, surface_drop_kind()) - } - - ty::Adt(adt_def, _) => { - assert!(adt_def.is_union()); - match surface_drop_kind().unwrap() { - SurfaceDropKind::Async => self.build_fused_async_surface(), - SurfaceDropKind::Sync => self.build_fused_sync_surface(), - } - } - - ty::Bound(..) - | ty::Foreign(_) - | ty::Placeholder(_) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) | ty::TyVar(_)) - | ty::Param(_) - | ty::Alias(..) => { - bug!("Building async destructor for unexpected type: {self_ty:?}") - } - - _ => { - bug!( - "Building async destructor constructor shim is not yet implemented for type: {self_ty:?}" - ) - } - } - } - - fn build_enum( - mut self, - adt_def: ty::AdtDef<'tcx>, - args: ty::GenericArgsRef<'tcx>, - surface_drop: Option, - ) -> Body<'tcx> { - let tcx = self.tcx; - - let surface = match surface_drop { - None => None, - Some(kind) => { - self.put_self(); - Some(match kind { - SurfaceDropKind::Async => self.combine_async_surface(), - SurfaceDropKind::Sync => self.combine_sync_surface(), - }) - } - }; - - let mut other = None; - for (variant_idx, discr) in adt_def.discriminants(tcx) { - let variant = adt_def.variant(variant_idx); - - let mut chain = None; - for (field_idx, field) in variant.fields.iter_enumerated() { - let field_ty = field.ty(tcx, args); - self.put_variant_field(variant.name, variant_idx, field_idx, field_ty); - let defer = self.combine_defer(field_ty); - chain = Some(match chain { - None => defer, - Some(chain) => self.combine_chain(chain, defer), - }) - } - let variant_dtor = chain.unwrap_or_else(|| self.put_noop()); - - other = Some(match other { - None => variant_dtor, - Some(other) => { - self.put_self(); - self.put_discr(discr); - self.combine_either(other, variant_dtor) - } - }); - } - let variants_dtor = other.unwrap_or_else(|| self.put_noop()); - - let dtor = match surface { - None => variants_dtor, - Some(surface) => self.combine_chain(surface, variants_dtor), - }; - self.combine_fuse(dtor); - self.return_() - } - - fn build_chain(mut self, surface_drop: Option, elem_tys: I) -> Body<'tcx> - where - I: Iterator> + ExactSizeIterator, - { - let surface = match surface_drop { - None => None, - Some(kind) => { - self.put_self(); - Some(match kind { - SurfaceDropKind::Async => self.combine_async_surface(), - SurfaceDropKind::Sync => self.combine_sync_surface(), - }) - } - }; - - let mut chain = None; - for (field_idx, field_ty) in elem_tys.enumerate().map(|(i, ty)| (FieldIdx::new(i), ty)) { - self.put_field(field_idx, field_ty); - let defer = self.combine_defer(field_ty); - chain = Some(match chain { - None => defer, - Some(chain) => self.combine_chain(chain, defer), - }) - } - let chain = chain.unwrap_or_else(|| self.put_noop()); - - let dtor = match surface { - None => chain, - Some(surface) => self.combine_chain(surface, chain), - }; - self.combine_fuse(dtor); - self.return_() - } - - fn build_zst_output(mut self) -> Body<'tcx> { - self.put_zst_output(); - self.return_() - } - - fn build_deferred_drop_in_place(mut self) -> Body<'tcx> { - self.put_self(); - let deferred = self.combine_deferred_drop_in_place(); - self.combine_fuse(deferred); - self.return_() - } - - fn build_fused_async_surface(mut self) -> Body<'tcx> { - self.put_self(); - let surface = self.combine_async_surface(); - self.combine_fuse(surface); - self.return_() - } - - fn build_fused_sync_surface(mut self) -> Body<'tcx> { - self.put_self(); - let surface = self.combine_sync_surface(); - self.combine_fuse(surface); - self.return_() - } - - fn build_slice(mut self, is_array: bool, elem_ty: Ty<'tcx>) -> Body<'tcx> { - if is_array { - self.put_array_as_slice(elem_ty) - } else { - self.put_self() - } - let dtor = self.combine_slice(elem_ty); - self.combine_fuse(dtor); - self.return_() - } - - fn put_zst_output(&mut self) { - let return_ty = self.locals[RETURN_PLACE].ty; - self.put_operand(Operand::Constant(Box::new(ConstOperand { - span: self.span, - user_ty: None, - const_: Const::zero_sized(return_ty), - }))); - } - - /// Puts `to_drop: *mut Self` on top of the stack. - fn put_self(&mut self) { - self.put_operand(Operand::Copy(Self::SELF_PTR.into())) - } - - /// Given that `Self is [ElemTy; N]` puts `to_drop: *mut [ElemTy]` - /// on top of the stack. - fn put_array_as_slice(&mut self, elem_ty: Ty<'tcx>) { - let slice_ptr_ty = Ty::new_mut_ptr(self.tcx, Ty::new_slice(self.tcx, elem_ty)); - self.put_temp_rvalue(Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize, CoercionSource::Implicit), - Operand::Copy(Self::SELF_PTR.into()), - slice_ptr_ty, - )) - } - - /// If given Self is a struct puts `to_drop: *mut FieldTy` on top - /// of the stack. - fn put_field(&mut self, field: FieldIdx, field_ty: Ty<'tcx>) { - let place = Place { - local: Self::SELF_PTR, - projection: self - .tcx - .mk_place_elems(&[PlaceElem::Deref, PlaceElem::Field(field, field_ty)]), - }; - self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place)) - } - - /// If given Self is an enum puts `to_drop: *mut FieldTy` on top of - /// the stack. - fn put_variant_field( - &mut self, - variant_sym: Symbol, - variant: VariantIdx, - field: FieldIdx, - field_ty: Ty<'tcx>, - ) { - let place = Place { - local: Self::SELF_PTR, - projection: self.tcx.mk_place_elems(&[ - PlaceElem::Deref, - PlaceElem::Downcast(Some(variant_sym), variant), - PlaceElem::Field(field, field_ty), - ]), - }; - self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place)) - } - - /// If given Self is an enum puts `to_drop: *mut FieldTy` on top of - /// the stack. - fn put_discr(&mut self, discr: Discr<'tcx>) { - let (size, _) = discr.ty.int_size_and_signed(self.tcx); - self.put_operand(Operand::const_from_scalar( - self.tcx, - discr.ty, - interpret::Scalar::from_uint(discr.val, size), - self.span, - )); - } - - /// Puts `x: RvalueType` on top of the stack. - fn put_temp_rvalue(&mut self, rvalue: Rvalue<'tcx>) { - let last_bb = &mut self.bbs[self.last_bb]; - debug_assert!(last_bb.terminator.is_none()); - let source_info = self.source_info; - - let local_ty = rvalue.ty(&self.locals, self.tcx); - // We need to create a new local to be able to "consume" it with - // a combinator - let local = self.locals.push(LocalDecl::with_source_info(local_ty, source_info)); - last_bb.statements.extend_from_slice(&[ - Statement { source_info, kind: StatementKind::StorageLive(local) }, - Statement { - source_info, - kind: StatementKind::Assign(Box::new((local.into(), rvalue))), - }, - ]); - - self.put_operand(Operand::Move(local.into())); - } - - /// Puts operand on top of the stack. - fn put_operand(&mut self, operand: Operand<'tcx>) { - if let Some(top_cleanup_bb) = &mut self.top_cleanup_bb { - let source_info = self.source_info; - match &operand { - Operand::Copy(_) | Operand::Constant(_) => { - *top_cleanup_bb = self.bbs.push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target: *top_cleanup_bb }, - }), - is_cleanup: true, - }); - } - Operand::Move(place) => { - let local = place.as_local().unwrap(); - *top_cleanup_bb = self.bbs.push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { - source_info, - kind: if self.locals[local].ty.needs_drop(self.tcx, self.typing_env) { - TerminatorKind::Drop { - place: local.into(), - target: *top_cleanup_bb, - unwind: UnwindAction::Terminate( - UnwindTerminateReason::InCleanup, - ), - replace: false, - drop: None, - async_fut: None, - } - } else { - TerminatorKind::Goto { target: *top_cleanup_bb } - }, - }), - is_cleanup: true, - }); - } - }; - } - self.stack.push(operand); - } - - /// Puts `noop: async_drop::Noop` on top of the stack - fn put_noop(&mut self) -> Ty<'tcx> { - self.apply_combinator(0, LangItem::AsyncDropNoop, &[]) - } - - fn combine_async_surface(&mut self) -> Ty<'tcx> { - self.apply_combinator(1, LangItem::SurfaceAsyncDropInPlace, &[self.self_ty.unwrap().into()]) - } - - fn combine_sync_surface(&mut self) -> Ty<'tcx> { - self.apply_combinator( - 1, - LangItem::AsyncDropSurfaceDropInPlace, - &[self.self_ty.unwrap().into()], - ) - } - - fn combine_deferred_drop_in_place(&mut self) -> Ty<'tcx> { - self.apply_combinator( - 1, - LangItem::AsyncDropDeferredDropInPlace, - &[self.self_ty.unwrap().into()], - ) - } - - fn combine_fuse(&mut self, inner_future_ty: Ty<'tcx>) -> Ty<'tcx> { - self.apply_combinator(1, LangItem::AsyncDropFuse, &[inner_future_ty.into()]) - } - - fn combine_slice(&mut self, elem_ty: Ty<'tcx>) -> Ty<'tcx> { - self.apply_combinator(1, LangItem::AsyncDropSlice, &[elem_ty.into()]) - } - - fn combine_defer(&mut self, to_drop_ty: Ty<'tcx>) -> Ty<'tcx> { - self.apply_combinator(1, LangItem::AsyncDropDefer, &[to_drop_ty.into()]) - } - - fn combine_chain(&mut self, first: Ty<'tcx>, second: Ty<'tcx>) -> Ty<'tcx> { - self.apply_combinator(2, LangItem::AsyncDropChain, &[first.into(), second.into()]) - } - - fn combine_either(&mut self, other: Ty<'tcx>, matched: Ty<'tcx>) -> Ty<'tcx> { - self.apply_combinator( - 4, - LangItem::AsyncDropEither, - &[other.into(), matched.into(), self.self_ty.unwrap().into()], - ) - } - - fn return_(mut self) -> Body<'tcx> { - let last_bb = &mut self.bbs[self.last_bb]; - debug_assert!(last_bb.terminator.is_none()); - let source_info = self.source_info; - - let (1, Some(output)) = (self.stack.len(), self.stack.pop()) else { - span_bug!( - self.span, - "async destructor ctor shim builder finished with invalid number of stack items: expected 1 found {}", - self.stack.len(), - ) - }; - #[cfg(debug_assertions)] - if let Some(ty) = self.self_ty { - debug_assert_eq!( - output.ty(&self.locals, self.tcx), - ty.async_destructor_ty(self.tcx), - "output async destructor types did not match for type: {ty:?}", - ); - } - - let dead_storage = match &output { - Operand::Move(place) => Some(Statement { - source_info, - kind: StatementKind::StorageDead(place.as_local().unwrap()), - }), - _ => None, - }; - - last_bb.statements.extend( - iter::once(Statement { - source_info, - kind: StatementKind::Assign(Box::new((RETURN_PLACE.into(), Rvalue::Use(output)))), - }) - .chain(dead_storage), - ); - - last_bb.terminator = Some(Terminator { source_info, kind: TerminatorKind::Return }); - - let source = MirSource::from_instance(ty::InstanceKind::AsyncDropGlueCtorShim( - self.def_id, - self.self_ty, - )); - new_body(source, self.bbs, self.locals, Self::INPUT_COUNT, self.span) - } - - fn apply_combinator( - &mut self, - arity: usize, - function: LangItem, - args: &[ty::GenericArg<'tcx>], - ) -> Ty<'tcx> { - let function = self.tcx.require_lang_item(function, Some(self.span)); - let operands_split = self - .stack - .len() - .checked_sub(arity) - .expect("async destructor ctor shim combinator tried to consume too many items"); - let operands = &self.stack[operands_split..]; - - let func_ty = Ty::new_fn_def(self.tcx, function, args.iter().copied()); - let func_sig = func_ty.fn_sig(self.tcx).no_bound_vars().unwrap(); - #[cfg(debug_assertions)] - operands.iter().zip(func_sig.inputs()).for_each(|(operand, expected_ty)| { - let operand_ty = operand.ty(&self.locals, self.tcx); - if operand_ty == *expected_ty { - return; - } - - // If projection of Discriminant then compare with `Ty::discriminant_ty` - if let ty::Alias(ty::Projection, ty::AliasTy { args, def_id, .. }) = expected_ty.kind() - && self.tcx.is_lang_item(*def_id, LangItem::Discriminant) - && args.first().unwrap().as_type().unwrap().discriminant_ty(self.tcx) == operand_ty - { - return; - } - - span_bug!( - self.span, - "Operand type and combinator argument type are not equal. - operand_ty: {:?} - argument_ty: {:?} -", - operand_ty, - expected_ty - ); - }); - - let target = self.bbs.push(BasicBlockData { - statements: operands - .iter() - .rev() - .filter_map(|o| { - if let Operand::Move(Place { local, projection }) = o { - assert!(projection.is_empty()); - Some(Statement { - source_info: self.source_info, - kind: StatementKind::StorageDead(*local), - }) - } else { - None - } - }) - .collect(), - terminator: None, - is_cleanup: false, - }); - - let dest_ty = func_sig.output(); - let dest = - self.locals.push(LocalDecl::with_source_info(dest_ty, self.source_info).immutable()); - - let unwind = if let Some(top_cleanup_bb) = &mut self.top_cleanup_bb { - for _ in 0..arity { - *top_cleanup_bb = - self.bbs[*top_cleanup_bb].terminator().successors().exactly_one().ok().unwrap(); - } - UnwindAction::Cleanup(*top_cleanup_bb) - } else { - UnwindAction::Unreachable - }; - - let last_bb = &mut self.bbs[self.last_bb]; - debug_assert!(last_bb.terminator.is_none()); - last_bb.statements.push(Statement { - source_info: self.source_info, - kind: StatementKind::StorageLive(dest), - }); - last_bb.terminator = Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Call { - func: Operand::Constant(Box::new(ConstOperand { - span: self.span, - user_ty: None, - const_: Const::Val(ConstValue::ZeroSized, func_ty), - })), - destination: dest.into(), - target: Some(target), - unwind, - call_source: CallSource::Misc, - fn_span: self.span, - args: self.stack.drain(operands_split..).map(|o| respan(self.span, o)).collect(), - }, - }); - - self.put_operand(Operand::Move(dest.into())); - self.last_bb = target; - - dest_ty - } -} diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 384a304c4a9d6..972ee47085504 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -251,11 +251,6 @@ where goal: Goal, ) -> Result, NoSolution>; - fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution>; - fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -454,9 +449,6 @@ where Some(TraitSolverLangItem::DiscriminantKind) => { G::consider_builtin_discriminant_kind_candidate(self, goal) } - Some(TraitSolverLangItem::AsyncDestruct) => { - G::consider_builtin_async_destruct_candidate(self, goal) - } Some(TraitSolverLangItem::Destruct) => { G::consider_builtin_destruct_candidate(self, goal) } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0b61c368d8e8d..5ad6e1dd27539 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -336,13 +336,6 @@ where unreachable!("DiscriminantKind is not const") } - fn consider_builtin_async_destruct_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, - ) -> Result, NoSolution> { - unreachable!("AsyncDestruct is not const") - } - fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index de6d21da0f592..89e4162910814 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -846,66 +846,6 @@ where }) } - fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - let self_ty = goal.predicate.self_ty(); - let async_destructor_ty = match self_ty.kind() { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Array(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) - | ty::Never - | ty::Adt(_, _) - | ty::Str - | ty::Slice(_) - | ty::Tuple(_) - | ty::Error(_) => self_ty.async_destructor_ty(ecx.cx()), - - ty::UnsafeBinder(_) => { - // FIXME(unsafe_binders): Instantiate the binder with placeholders I guess. - todo!() - } - - // Given an alias, parameter, or placeholder we add an impl candidate normalizing to a rigid - // alias. In case there's a where-bound further constraining this alias it is preferred over - // this impl candidate anyways. It's still a bit scuffed. - ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { - return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { - ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }); - } - - ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Foreign(..) - | ty::Bound(..) => panic!( - "unexpected self ty `{:?}` when normalizing `::AsyncDestructor`", - goal.predicate.self_ty() - ), - - ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => panic!( - "`consider_builtin_async_destruct_candidate` is not yet implemented for type: {self_ty:?}" - ), - }; - - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { - ecx.eq(goal.param_env, goal.predicate.term, async_destructor_ty.into()) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - } - fn consider_builtin_destruct_candidate( _ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index d42c9980f4633..fbb0d025c5d2f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -571,19 +571,6 @@ where .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } - fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - if goal.predicate.polarity != ty::PredicatePolarity::Positive { - return Err(NoSolution); - } - - // `AsyncDestruct` is automatically implemented for every type. - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) - .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) - } - fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 51f660001fa2c..515b41c31a95e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -500,18 +500,9 @@ symbols! { async_call_mut, async_call_once, async_closure, - async_destruct, async_drop, - async_drop_chain, - async_drop_defer, - async_drop_deferred_drop_in_place, - async_drop_either, - async_drop_fuse, async_drop_in_place, async_drop_in_place_poll, - async_drop_noop, - async_drop_slice, - async_drop_surface_drop_in_place, async_fn, async_fn_in_dyn_trait, async_fn_in_trait, @@ -981,7 +972,6 @@ symbols! { fadd_fast, fake_variadic, fallback, - fallback_surface_drop, fdiv_algebraic, fdiv_fast, feature, @@ -2056,7 +2046,6 @@ symbols! { suggestion, super_let, supertrait_item_shadowing, - surface_async_drop_in_place, sym, sync, synthetic, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 349569d750e08..c7f17b512cafc 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1051,43 +1051,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Infer(..) | ty::Error(_) => false, } - } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncDestruct) { - match self_ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(..) - | ty::Str - | ty::Array(..) - | ty::Slice(_) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::UnsafeBinder(_) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Pat(..) - | ty::Never - | ty::Tuple(..) - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, - - // type parameters, opaques, and unnormalized projections don't have - // a known async destructor and may need to be normalized further or rely - // on param env for async destructor projections - ty::Param(_) - | ty::Foreign(_) - | ty::Alias(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(_) - | ty::Error(_) => false, - } } else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) { let tail = selcx.tcx().struct_tail_raw( self_ty, @@ -1541,11 +1504,6 @@ fn confirm_builtin_candidate<'cx, 'tcx>( assert_eq!(discriminant_def_id, item_def_id); (self_ty.discriminant_ty(tcx).into(), PredicateObligations::new()) - } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { - let destructor_def_id = tcx.associated_item_def_ids(trait_def_id)[0]; - assert_eq!(destructor_def_id, item_def_id); - - (self_ty.async_destructor_ty(tcx).into(), PredicateObligations::new()) } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, item_def_id); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index cf6d2bc151fb0..e4f1c3b62b068 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -79,9 +79,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if tcx.is_lang_item(def_id, LangItem::DiscriminantKind) { // `DiscriminantKind` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if tcx.is_lang_item(def_id, LangItem::AsyncDestruct) { - // `AsyncDestruct` is automatically implemented for every type. - candidates.vec.push(BuiltinCandidate { has_nested: false }); } else if tcx.is_lang_item(def_id, LangItem::PointeeTrait) { // `Pointee` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 20646cf9a826c..bb2c4172b0877 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -29,6 +29,13 @@ fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, T is_item_raw(tcx, query, LangItem::Unpin) } +fn is_async_drop_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, +) -> bool { + is_item_raw(tcx, query, LangItem::AsyncDrop) +} + fn is_item_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, @@ -46,6 +53,7 @@ pub(crate) fn provide(providers: &mut Providers) { is_sized_raw, is_freeze_raw, is_unpin_raw, + is_async_drop_raw, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 66c18bed5e71a..6678493123ec4 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -5,7 +5,6 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError}; -use rustc_middle::ty::util::AsyncDropGlueMorphology; use rustc_middle::ty::{ self, ClosureKind, GenericArgsRef, Instance, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, }; @@ -62,7 +61,7 @@ fn resolve_instance_raw<'tcx>( } else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) { let ty = args.type_at(0); - if ty.async_drop_glue_morphology(tcx) != AsyncDropGlueMorphology::Noop { + if ty.needs_async_drop(tcx, typing_env) { match *ty.kind() { ty::Closure(..) | ty::CoroutineClosure(..) diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 52955ec59a4a0..c3b04c20f4b67 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -42,11 +42,11 @@ fn needs_async_drop_raw<'tcx>( let adt_has_async_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.async_destructor(tcx).map(|_| DtorType::Significant); let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_async_dtor, false, false) - .filter(filter_array_elements(tcx, query.typing_env)) + .filter(filter_array_elements_async(tcx, query.typing_env)) .next() .is_some(); - debug!("needs_drop_raw({:?}) = {:?}", query, res); + debug!("needs_async_drop_raw({:?}) = {:?}", query, res); res } @@ -66,6 +66,18 @@ fn filter_array_elements<'tcx>( Err(AlwaysRequiresDrop) => true, } } +fn filter_array_elements_async<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, +) -> impl Fn(&Result, AlwaysRequiresDrop>) -> bool { + move |ty| match ty { + Ok(ty) => match *ty.kind() { + ty::Array(elem, _) => tcx.needs_async_drop_raw(typing_env.as_query_input(elem)), + _ => true, + }, + Err(AlwaysRequiresDrop) => true, + } +} fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, @@ -414,6 +426,27 @@ fn adt_drop_tys<'tcx>( .collect::, _>>() .map(|components| tcx.mk_type_list(&components)) } + +fn adt_async_drop_tys<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> Result<&'tcx ty::List>, AlwaysRequiresDrop> { + // This is for the "adt_async_drop_tys" query, that considers all `AsyncDrop` impls. + let adt_has_dtor = + |adt_def: ty::AdtDef<'tcx>| adt_def.async_destructor(tcx).map(|_| DtorType::Significant); + // `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_args)` + drop_tys_helper( + tcx, + tcx.type_of(def_id).instantiate_identity(), + ty::TypingEnv::non_body_analysis(tcx, def_id), + adt_has_dtor, + false, + false, + ) + .collect::, _>>() + .map(|components| tcx.mk_type_list(&components)) +} + // If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed // a `tcx.make_ty(def, identity_args)` and as such it is legal to instantiate the generic parameters // of the ADT into the outputted `ty`s. @@ -458,6 +491,7 @@ pub(crate) fn provide(providers: &mut Providers) { needs_async_drop_raw, has_significant_drop_raw, adt_drop_tys, + adt_async_drop_tys, adt_significant_drop_tys, list_significant_drop_tys, ..*providers diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 59c2d3c2fc8d9..77d7e33870390 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -151,7 +151,6 @@ pub trait Ty>: fn discriminant_ty(self, interner: I) -> I::Ty; - fn async_destructor_ty(self, interner: I) -> I::Ty; fn is_known_rigid(self) -> bool { self.kind().is_known_rigid() } diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 65f7cdf8f922b..699dd82fb22c9 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -2,7 +2,6 @@ /// representation of `LangItem`s used in the underlying compiler implementation. pub enum TraitSolverLangItem { // tidy-alphabetical-start - AsyncDestruct, AsyncFn, AsyncFnKindHelper, AsyncFnKindUpvars, diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs deleted file mode 100644 index f1778a4d782af..0000000000000 --- a/library/core/src/future/async_drop.rs +++ /dev/null @@ -1,284 +0,0 @@ -#![unstable(feature = "async_drop", issue = "126482")] - -use crate::fmt; -use crate::future::{Future, IntoFuture}; -use crate::intrinsics::discriminant_value; -use crate::marker::{DiscriminantKind, PhantomPinned}; -use crate::mem::MaybeUninit; -use crate::pin::Pin; -use crate::task::{Context, Poll, ready}; - -/// Asynchronously drops a value by running `AsyncDrop::async_drop` -/// on a value and its fields recursively. -#[unstable(feature = "async_drop", issue = "126482")] -pub fn async_drop(value: T) -> AsyncDropOwning { - AsyncDropOwning { value: MaybeUninit::new(value), dtor: None, _pinned: PhantomPinned } -} - -/// A future returned by the [`async_drop`]. -#[unstable(feature = "async_drop", issue = "126482")] -pub struct AsyncDropOwning { - value: MaybeUninit, - dtor: Option>, - _pinned: PhantomPinned, -} - -#[unstable(feature = "async_drop", issue = "126482")] -impl fmt::Debug for AsyncDropOwning { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AsyncDropOwning").finish_non_exhaustive() - } -} - -#[unstable(feature = "async_drop", issue = "126482")] -impl Future for AsyncDropOwning { - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // SAFETY: Self is pinned thus it is ok to store references to self - unsafe { - let this = self.get_unchecked_mut(); - let dtor = Pin::new_unchecked( - this.dtor.get_or_insert_with(|| async_drop_in_place(this.value.as_mut_ptr())), - ); - // AsyncDestuctors are idempotent so Self gets idempotency as well - dtor.poll(cx) - } - } -} - -#[lang = "async_drop_in_place"] -#[allow(unconditional_recursion)] -// FIXME: Consider if `#[rustc_diagnostic_item = "ptr_drop_in_place"]` is needed? -unsafe fn async_drop_in_place_raw( - to_drop: *mut T, -) -> ::AsyncDestructor { - // Code here does not matter - this is replaced by the - // real async drop glue constructor by the compiler. - - // SAFETY: see comment above - unsafe { async_drop_in_place_raw(to_drop) } -} - -/// Creates the asynchronous destructor of the pointed-to value. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `to_drop` must be [valid](crate::ptr#safety) for both reads and writes. -/// -/// * `to_drop` must be properly aligned, even if `T` has size 0. -/// -/// * `to_drop` must be nonnull, even if `T` has size 0. -/// -/// * The value `to_drop` points to must be valid for async dropping, -/// which may mean it must uphold additional invariants. These -/// invariants depend on the type of the value being dropped. For -/// instance, when dropping a Box, the box's pointer to the heap must -/// be valid. -/// -/// * While `async_drop_in_place` is executing or the returned async -/// destructor is alive, the only way to access parts of `to_drop` -/// is through the `self: Pin<&mut Self>` references supplied to -/// the `AsyncDrop::async_drop` methods that `async_drop_in_place` -/// or `AsyncDropInPlace::poll` invokes. This usually means the -/// returned future stores the `to_drop` pointer and user is required -/// to guarantee that dropped value doesn't move. -/// -#[unstable(feature = "async_drop", issue = "126482")] -pub unsafe fn async_drop_in_place(to_drop: *mut T) -> AsyncDropInPlace { - // SAFETY: `async_drop_in_place_raw` has the same safety requirements - unsafe { AsyncDropInPlace(async_drop_in_place_raw(to_drop)) } -} - -/// A future returned by the [`async_drop_in_place`]. -#[unstable(feature = "async_drop", issue = "126482")] -pub struct AsyncDropInPlace(::AsyncDestructor); - -#[unstable(feature = "async_drop", issue = "126482")] -impl fmt::Debug for AsyncDropInPlace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AsyncDropInPlace").finish_non_exhaustive() - } -} - -#[unstable(feature = "async_drop", issue = "126482")] -impl Future for AsyncDropInPlace { - type Output = (); - - #[inline(always)] - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // SAFETY: This code simply forwards poll call to the inner future - unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }.poll(cx) - } -} - -// FIXME(zetanumbers): Add same restrictions on AsyncDrop impls as -// with Drop impls -/// Custom code within the asynchronous destructor. -#[unstable(feature = "async_drop", issue = "126482")] -#[lang = "async_drop"] -pub trait AsyncDrop { - /// A future returned by the [`AsyncDrop::async_drop`] to be part - /// of the async destructor. - #[unstable(feature = "async_drop", issue = "126482")] - type Dropper<'a>: Future - where - Self: 'a; - - /// Constructs the asynchronous destructor for this type. - #[unstable(feature = "async_drop", issue = "126482")] - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_>; -} - -#[lang = "async_destruct"] -#[rustc_deny_explicit_impl] -#[rustc_do_not_implement_via_object] -trait AsyncDestruct { - type AsyncDestructor: Future; -} - -/// Basically calls `AsyncDrop::async_drop` with pointer. Used to simplify -/// generation of the code for `async_drop_in_place_raw` -#[lang = "surface_async_drop_in_place"] -async unsafe fn surface_async_drop_in_place(ptr: *mut T) { - // SAFETY: We call this from async drop `async_drop_in_place_raw` - // which has the same safety requirements - unsafe { ::async_drop(Pin::new_unchecked(&mut *ptr)).await } -} - -/// Basically calls `Drop::drop` with pointer. Used to simplify generation -/// of the code for `async_drop_in_place_raw` -#[allow(drop_bounds)] -#[lang = "async_drop_surface_drop_in_place"] -async unsafe fn surface_drop_in_place(ptr: *mut T) { - // SAFETY: We call this from async drop `async_drop_in_place_raw` - // which has the same safety requirements - unsafe { crate::ops::fallback_surface_drop(&mut *ptr) } -} - -/// Wraps a future to continue outputting `Poll::Ready(())` once after -/// wrapped future completes by returning `Poll::Ready(())` on poll. This -/// is useful for constructing async destructors to guarantee this -/// "fuse" property -// -// FIXME: Consider optimizing combinators to not have to use fuse in majority -// of cases, perhaps by adding `#[(rustc_)idempotent(_future)]` attribute for -// async functions and blocks with the unit return type. However current layout -// optimizations currently encode `None` case into the async block's discriminant. -struct Fuse { - inner: Option, -} - -#[lang = "async_drop_fuse"] -fn fuse(inner: T) -> Fuse { - Fuse { inner: Some(inner) } -} - -impl Future for Fuse -where - T: Future, -{ - type Output = (); - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // SAFETY: pin projection into `self.inner` - unsafe { - let this = self.get_unchecked_mut(); - if let Some(inner) = &mut this.inner { - ready!(Pin::new_unchecked(inner).poll(cx)); - this.inner = None; - } - } - Poll::Ready(()) - } -} - -/// Async destructor for arrays and slices. -#[lang = "async_drop_slice"] -async unsafe fn slice(s: *mut [T]) { - let len = s.len(); - let ptr = s.as_mut_ptr(); - for i in 0..len { - // SAFETY: we iterate over elements of `s` slice - unsafe { async_drop_in_place_raw(ptr.add(i)).await } - } -} - -/// Constructs a chain of two futures, which awaits them sequentially as -/// a future. -#[lang = "async_drop_chain"] -async fn chain(first: F, last: G) -where - F: IntoFuture, - G: IntoFuture, -{ - first.await; - last.await; -} - -/// Basically a lazy version of `async_drop_in_place`. Returns a future -/// that would call `AsyncDrop::async_drop` on a first poll. -/// -/// # Safety -/// -/// Same as `async_drop_in_place` except is lazy to avoid creating -/// multiple mutable references. -#[lang = "async_drop_defer"] -async unsafe fn defer(to_drop: *mut T) { - // SAFETY: same safety requirements as `async_drop_in_place` - unsafe { async_drop_in_place(to_drop) }.await -} - -/// If `T`'s discriminant is equal to the stored one then awaits `M` -/// otherwise awaits the `O`. -/// -/// # Safety -/// -/// Users should carefully manage the returned future, since it would -/// try creating an immutable reference from `this` and get pointee's -/// discriminant. -// FIXME(zetanumbers): Send and Sync impls -#[lang = "async_drop_either"] -async unsafe fn either, M: IntoFuture, T>( - other: O, - matched: M, - this: *mut T, - discr: ::Discriminant, -) { - // SAFETY: Guaranteed by the safety section of this funtion's documentation - if unsafe { discriminant_value(&*this) } == discr { - drop(other); - matched.await - } else { - drop(matched); - other.await - } -} - -#[lang = "async_drop_deferred_drop_in_place"] -async unsafe fn deferred_drop_in_place(to_drop: *mut T) { - // SAFETY: same safety requirements as with drop_in_place (implied by - // function's name) - unsafe { crate::ptr::drop_in_place(to_drop) } -} - -/// Used for noop async destructors. We don't use [`core::future::Ready`] -/// because it panics after its second poll, which could be potentially -/// bad if that would happen during the cleanup. -#[derive(Clone, Copy)] -struct Noop; - -#[lang = "async_drop_noop"] -fn noop() -> Noop { - Noop -} - -impl Future for Noop { - type Output = (); - - fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { - Poll::Ready(()) - } -} diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 65c0171c88d5b..518c9bbf6223c 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -12,7 +12,6 @@ use crate::ptr::NonNull; use crate::task::Context; -mod async_drop; mod future; mod into_future; mod join; @@ -20,8 +19,6 @@ mod pending; mod poll_fn; mod ready; -#[unstable(feature = "async_drop", issue = "126482")] -pub use async_drop::{AsyncDrop, AsyncDropInPlace, async_drop, async_drop_in_place}; #[stable(feature = "into_future", since = "1.64.0")] pub use into_future::IntoFuture; #[stable(feature = "future_readiness_fns", since = "1.48.0")] diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index e024b7fb4d301..5d040804a8d1c 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -240,10 +240,3 @@ pub trait Drop { #[stable(feature = "rust1", since = "1.0.0")] fn drop(&mut self); } - -/// Fallback function to call surface level `Drop::drop` function -#[allow(drop_bounds)] -#[lang = "fallback_surface_drop"] -pub(crate) fn fallback_surface_drop(x: &mut T) { - ::drop(x) -} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 627a875d9f724..1658f0e5a3692 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -176,7 +176,6 @@ pub use self::deref::Receiver; pub use self::deref::{Deref, DerefMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::drop::Drop; -pub(crate) use self::drop::fallback_surface_drop; #[stable(feature = "rust1", since = "1.0.0")] pub use self::function::{Fn, FnMut, FnOnce}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/tools/miri/tests/pass/async-drop.rs b/src/tools/miri/tests/pass/async-drop.rs deleted file mode 100644 index 6d556b77795d9..0000000000000 --- a/src/tools/miri/tests/pass/async-drop.rs +++ /dev/null @@ -1,199 +0,0 @@ -//@revisions: stack tree -//@compile-flags: -Zmiri-strict-provenance -//@[tree]compile-flags: -Zmiri-tree-borrows - -// WARNING: If you would ever want to modify this test, -// please consider modifying rustc's async drop test at -// `tests/ui/async-await/async-drop.rs`. - -#![feature(async_drop, impl_trait_in_assoc_type)] -#![allow(incomplete_features, dead_code)] - -// FIXME(zetanumbers): consider AsyncDestruct::async_drop cleanup tests -use core::future::{AsyncDrop, Future, async_drop_in_place}; -use core::hint::black_box; -use core::mem::{self, ManuallyDrop}; -use core::pin::{Pin, pin}; -use core::task::{Context, Poll, Waker}; - -async fn test_async_drop(x: T) { - let mut x = mem::MaybeUninit::new(x); - let dtor = pin!(unsafe { async_drop_in_place(x.as_mut_ptr()) }); - test_idempotency(dtor).await; -} - -fn test_idempotency(mut x: Pin<&mut T>) -> impl Future + '_ -where - T: Future, -{ - core::future::poll_fn(move |cx| { - assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); - assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); - Poll::Ready(()) - }) -} - -fn main() { - let waker = Waker::noop(); - let mut cx = Context::from_waker(&waker); - - let i = 13; - let fut = pin!(async { - test_async_drop(Int(0)).await; - test_async_drop(AsyncInt(0)).await; - test_async_drop([AsyncInt(1), AsyncInt(2)]).await; - test_async_drop((AsyncInt(3), AsyncInt(4))).await; - test_async_drop(5).await; - let j = 42; - test_async_drop(&i).await; - test_async_drop(&j).await; - test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }).await; - test_async_drop(ManuallyDrop::new(AsyncInt(9))).await; - - let foo = AsyncInt(10); - test_async_drop(AsyncReference { foo: &foo }).await; - - let foo = AsyncInt(11); - test_async_drop(|| { - black_box(foo); - let foo = AsyncInt(10); - foo - }) - .await; - - test_async_drop(AsyncEnum::A(AsyncInt(12))).await; - test_async_drop(AsyncEnum::B(SyncInt(13))).await; - - test_async_drop(SyncInt(14)).await; - test_async_drop(SyncThenAsync { i: 15, a: AsyncInt(16), b: SyncInt(17), c: AsyncInt(18) }) - .await; - - let async_drop_fut = pin!(core::future::async_drop(AsyncInt(19))); - test_idempotency(async_drop_fut).await; - - let foo = AsyncInt(20); - test_async_drop(async || { - black_box(foo); - let foo = AsyncInt(19); - // Await point there, but this is async closure so it's fine - black_box(core::future::ready(())).await; - foo - }) - .await; - - test_async_drop(AsyncUnion { signed: 21 }).await; - }); - let res = fut.poll(&mut cx); - assert_eq!(res, Poll::Ready(())); -} - -struct AsyncInt(i32); - -impl AsyncDrop for AsyncInt { - type Dropper<'a> = impl Future; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncInt::Dropper::poll: {}", self.0); - } - } -} - -struct SyncInt(i32); - -impl Drop for SyncInt { - fn drop(&mut self) { - println!("SyncInt::drop: {}", self.0); - } -} - -struct SyncThenAsync { - i: i32, - a: AsyncInt, - b: SyncInt, - c: AsyncInt, -} - -impl Drop for SyncThenAsync { - fn drop(&mut self) { - println!("SyncThenAsync::drop: {}", self.i); - } -} - -struct AsyncReference<'a> { - foo: &'a AsyncInt, -} - -impl AsyncDrop for AsyncReference<'_> { - type Dropper<'a> - = impl Future - where - Self: 'a; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncReference::Dropper::poll: {}", self.foo.0); - } - } -} - -struct Int(i32); - -struct AsyncStruct { - i: i32, - a: AsyncInt, - b: AsyncInt, -} - -impl AsyncDrop for AsyncStruct { - type Dropper<'a> = impl Future; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncStruct::Dropper::poll: {}", self.i); - } - } -} - -enum AsyncEnum { - A(AsyncInt), - B(SyncInt), -} - -impl AsyncDrop for AsyncEnum { - type Dropper<'a> = impl Future; - - fn async_drop(mut self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - let new_self = match &*self { - AsyncEnum::A(foo) => { - println!("AsyncEnum(A)::Dropper::poll: {}", foo.0); - AsyncEnum::B(SyncInt(foo.0)) - } - AsyncEnum::B(foo) => { - println!("AsyncEnum(B)::Dropper::poll: {}", foo.0); - AsyncEnum::A(AsyncInt(foo.0)) - } - }; - mem::forget(mem::replace(&mut *self, new_self)); - } - } -} - -// FIXME(zetanumbers): Disallow types with `AsyncDrop` in unions -union AsyncUnion { - signed: i32, - unsigned: u32, -} - -impl AsyncDrop for AsyncUnion { - type Dropper<'a> = impl Future; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncUnion::Dropper::poll: {}, {}", unsafe { self.signed }, unsafe { - self.unsigned - }); - } - } -} diff --git a/tests/crashes/128695.rs b/tests/crashes/128695.rs deleted file mode 100644 index 661f427dc0e99..0000000000000 --- a/tests/crashes/128695.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#128695 -//@ edition: 2021 - -use core::pin::{pin, Pin}; - -fn main() { - let fut = pin!(async { - let async_drop_fut = pin!(core::future::async_drop(async {})); - (async_drop_fut).await; - }); -} diff --git a/tests/ui/async-await/async-drop.rs b/tests/ui/async-await/async-drop.rs deleted file mode 100644 index b1af81423cea5..0000000000000 --- a/tests/ui/async-await/async-drop.rs +++ /dev/null @@ -1,222 +0,0 @@ -//@ run-pass -//@ check-run-results - -// WARNING: If you would ever want to modify this test, -// please consider modifying miri's async drop test at -// `src/tools/miri/tests/pass/async-drop.rs`. - -#![feature(async_drop, impl_trait_in_assoc_type)] -#![allow(incomplete_features, dead_code)] - -//@ edition: 2021 - -// FIXME(zetanumbers): consider AsyncDestruct::async_drop cleanup tests -use core::future::{async_drop_in_place, AsyncDrop, Future}; -use core::hint::black_box; -use core::mem::{self, ManuallyDrop}; -use core::pin::{pin, Pin}; -use core::task::{Context, Poll, Waker}; - -async fn test_async_drop(x: T, _size: usize) { - let mut x = mem::MaybeUninit::new(x); - let dtor = pin!(unsafe { async_drop_in_place(x.as_mut_ptr()) }); - - // FIXME(zetanumbers): This check fully depends on the layout of - // the coroutine state, since async destructor combinators are just - // async functions. - #[cfg(target_pointer_width = "64")] - assert_eq!( - mem::size_of_val(&*dtor), - _size, - "sizes did not match for async destructor of type {}", - core::any::type_name::(), - ); - - test_idempotency(dtor).await; -} - -fn test_idempotency(mut x: Pin<&mut T>) -> impl Future + '_ -where - T: Future, -{ - core::future::poll_fn(move |cx| { - assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); - assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); - Poll::Ready(()) - }) -} - -fn main() { - let waker = Waker::noop(); - let mut cx = Context::from_waker(&waker); - - let i = 13; - let fut = pin!(async { - test_async_drop(Int(0), 0).await; - // FIXME(#63818): niches in coroutines are disabled. - // Some of these sizes should be smaller, as indicated in comments. - test_async_drop(AsyncInt(0), /*104*/ 112).await; - test_async_drop([AsyncInt(1), AsyncInt(2)], /*152*/ 168).await; - test_async_drop((AsyncInt(3), AsyncInt(4)), /*488*/ 528).await; - test_async_drop(5, 0).await; - let j = 42; - test_async_drop(&i, 0).await; - test_async_drop(&j, 0).await; - test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, /*1688*/ 1792).await; - test_async_drop(ManuallyDrop::new(AsyncInt(9)), 0).await; - - let foo = AsyncInt(10); - test_async_drop(AsyncReference { foo: &foo }, /*104*/ 112).await; - - let foo = AsyncInt(11); - test_async_drop( - || { - black_box(foo); - let foo = AsyncInt(10); - foo - }, - /*120*/ 136, - ) - .await; - - test_async_drop(AsyncEnum::A(AsyncInt(12)), /*680*/ 736).await; - test_async_drop(AsyncEnum::B(SyncInt(13)), /*680*/ 736).await; - - test_async_drop(SyncInt(14), /*16*/ 24).await; - test_async_drop( - SyncThenAsync { i: 15, a: AsyncInt(16), b: SyncInt(17), c: AsyncInt(18) }, - /*3064*/ 3296, - ) - .await; - - let async_drop_fut = pin!(core::future::async_drop(AsyncInt(19))); - test_idempotency(async_drop_fut).await; - - let foo = AsyncInt(20); - test_async_drop( - async || { - black_box(foo); - let foo = AsyncInt(19); - // Await point there, but this is async closure so it's fine - black_box(core::future::ready(())).await; - foo - }, - /*120*/ 136, - ) - .await; - - test_async_drop(AsyncUnion { signed: 21 }, /*32*/ 40).await; - }); - let res = fut.poll(&mut cx); - assert_eq!(res, Poll::Ready(())); -} - -struct AsyncInt(i32); - -impl AsyncDrop for AsyncInt { - type Dropper<'a> = impl Future; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncInt::Dropper::poll: {}", self.0); - } - } -} - -struct SyncInt(i32); - -impl Drop for SyncInt { - fn drop(&mut self) { - println!("SyncInt::drop: {}", self.0); - } -} - -struct SyncThenAsync { - i: i32, - a: AsyncInt, - b: SyncInt, - c: AsyncInt, -} - -impl Drop for SyncThenAsync { - fn drop(&mut self) { - println!("SyncThenAsync::drop: {}", self.i); - } -} - -struct AsyncReference<'a> { - foo: &'a AsyncInt, -} - -impl AsyncDrop for AsyncReference<'_> { - type Dropper<'a> = impl Future where Self: 'a; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncReference::Dropper::poll: {}", self.foo.0); - } - } -} - -struct Int(i32); - -struct AsyncStruct { - i: i32, - a: AsyncInt, - b: AsyncInt, -} - -impl AsyncDrop for AsyncStruct { - type Dropper<'a> = impl Future; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncStruct::Dropper::poll: {}", self.i); - } - } -} - -enum AsyncEnum { - A(AsyncInt), - B(SyncInt), -} - -impl AsyncDrop for AsyncEnum { - type Dropper<'a> = impl Future; - - fn async_drop(mut self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - let new_self = match &*self { - AsyncEnum::A(foo) => { - println!("AsyncEnum(A)::Dropper::poll: {}", foo.0); - AsyncEnum::B(SyncInt(foo.0)) - } - AsyncEnum::B(foo) => { - println!("AsyncEnum(B)::Dropper::poll: {}", foo.0); - AsyncEnum::A(AsyncInt(foo.0)) - } - }; - mem::forget(mem::replace(&mut *self, new_self)); - } - } -} - -// FIXME(zetanumbers): Disallow types with `AsyncDrop` in unions -union AsyncUnion { - signed: i32, - unsigned: u32, -} - -impl AsyncDrop for AsyncUnion { - type Dropper<'a> = impl Future; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!( - "AsyncUnion::Dropper::poll: {}, {}", - unsafe { self.signed }, - unsafe { self.unsigned }, - ); - } - } -} diff --git a/tests/ui/async-await/async-drop.run.stdout b/tests/ui/async-await/async-drop.run.stdout deleted file mode 100644 index 9cae4331caf92..0000000000000 --- a/tests/ui/async-await/async-drop.run.stdout +++ /dev/null @@ -1,22 +0,0 @@ -AsyncInt::Dropper::poll: 0 -AsyncInt::Dropper::poll: 1 -AsyncInt::Dropper::poll: 2 -AsyncInt::Dropper::poll: 3 -AsyncInt::Dropper::poll: 4 -AsyncStruct::Dropper::poll: 6 -AsyncInt::Dropper::poll: 7 -AsyncInt::Dropper::poll: 8 -AsyncReference::Dropper::poll: 10 -AsyncInt::Dropper::poll: 11 -AsyncEnum(A)::Dropper::poll: 12 -SyncInt::drop: 12 -AsyncEnum(B)::Dropper::poll: 13 -AsyncInt::Dropper::poll: 13 -SyncInt::drop: 14 -SyncThenAsync::drop: 15 -AsyncInt::Dropper::poll: 16 -SyncInt::drop: 17 -AsyncInt::Dropper::poll: 18 -AsyncInt::Dropper::poll: 19 -AsyncInt::Dropper::poll: 20 -AsyncUnion::Dropper::poll: 21, 21 diff --git a/tests/crashes/132103.rs b/tests/ui/async-await/async-drop/ex-ice-132103.rs similarity index 73% rename from tests/crashes/132103.rs rename to tests/ui/async-await/async-drop/ex-ice-132103.rs index 5bf4792c44c9f..0163d0f97f612 100644 --- a/tests/crashes/132103.rs +++ b/tests/ui/async-await/async-drop/ex-ice-132103.rs @@ -1,6 +1,8 @@ -//@ known-bug: #132103 +//! This test used to ICE: rust-lang/rust#132103 +//! Fixed when re-work async drop to templated coroutine scheme. //@compile-flags: -Zvalidate-mir --edition=2018 -Zinline-mir=yes use core::future::{async_drop_in_place, Future}; +//~^ ERROR unresolved import `core::future::async_drop_in_place` [E0432] use core::mem::{self}; use core::pin::pin; use core::task::{Context, Waker}; diff --git a/tests/ui/async-await/async-drop/ex-ice-132103.stderr b/tests/ui/async-await/async-drop/ex-ice-132103.stderr new file mode 100644 index 0000000000000..1febe56c1669b --- /dev/null +++ b/tests/ui/async-await/async-drop/ex-ice-132103.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `core::future::async_drop_in_place` + --> $DIR/ex-ice-132103.rs:4:20 + | +LL | use core::future::{async_drop_in_place, Future}; + | ^^^^^^^^^^^^^^^^^^^ no `async_drop_in_place` in `future` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`.