]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_transform/src/generator.rs
Sync core::simd up to rust-lang/portable-simd@2e081db92aa3ee0a4563bc28ce01bdad5b1b2efd
[rust.git] / compiler / rustc_mir_transform / src / generator.rs
1 //! This is the implementation of the pass which transforms generators into state machines.
2 //!
3 //! MIR generation for generators creates a function which has a self argument which
4 //! passes by value. This argument is effectively a generator type which only contains upvars and
5 //! is only used for this argument inside the MIR for the generator.
6 //! It is passed by value to enable upvars to be moved out of it. Drop elaboration runs on that
7 //! MIR before this pass and creates drop flags for MIR locals.
8 //! It will also drop the generator argument (which only consists of upvars) if any of the upvars
9 //! are moved out of. This pass elaborates the drops of upvars / generator argument in the case
10 //! that none of the upvars were moved out of. This is because we cannot have any drops of this
11 //! generator in the MIR, since it is used to create the drop glue for the generator. We'd get
12 //! infinite recursion otherwise.
13 //!
14 //! This pass creates the implementation for the Generator::resume function and the drop shim
15 //! for the generator based on the MIR input. It converts the generator argument from Self to
16 //! &mut Self adding derefs in the MIR as needed. It computes the final layout of the generator
17 //! struct which looks like this:
18 //!     First upvars are stored
19 //!     It is followed by the generator state field.
20 //!     Then finally the MIR locals which are live across a suspension point are stored.
21 //!     ```ignore (illustrative)
22 //!     struct Generator {
23 //!         upvars...,
24 //!         state: u32,
25 //!         mir_locals...,
26 //!     }
27 //!     ```
28 //! This pass computes the meaning of the state field and the MIR locals which are live
29 //! across a suspension point. There are however three hardcoded generator states:
30 //!     0 - Generator have not been resumed yet
31 //!     1 - Generator has returned / is completed
32 //!     2 - Generator has been poisoned
33 //!
34 //! It also rewrites `return x` and `yield y` as setting a new generator state and returning
35 //! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
36 //! MIR locals which are live across a suspension point are moved to the generator struct
37 //! with references to them being updated with references to the generator struct.
38 //!
39 //! The pass creates two functions which have a switch on the generator state giving
40 //! the action to take.
41 //!
42 //! One of them is the implementation of Generator::resume.
43 //! For generators with state 0 (unresumed) it starts the execution of the generator.
44 //! For generators with state 1 (returned) and state 2 (poisoned) it panics.
45 //! Otherwise it continues the execution from the last suspension point.
46 //!
47 //! The other function is the drop glue for the generator.
48 //! For generators with state 0 (unresumed) it drops the upvars of the generator.
49 //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
50 //! Otherwise it drops all the values in scope at the last suspension point.
51
52 use crate::deref_separator::deref_finder;
53 use crate::simplify;
54 use crate::util::expand_aggregate;
55 use crate::MirPass;
56 use rustc_data_structures::fx::FxHashMap;
57 use rustc_hir as hir;
58 use rustc_hir::lang_items::LangItem;
59 use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet};
60 use rustc_index::vec::{Idx, IndexVec};
61 use rustc_middle::mir::dump_mir;
62 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
63 use rustc_middle::mir::*;
64 use rustc_middle::ty::subst::{Subst, SubstsRef};
65 use rustc_middle::ty::GeneratorSubsts;
66 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
67 use rustc_mir_dataflow::impls::{
68     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
69 };
70 use rustc_mir_dataflow::storage::always_storage_live_locals;
71 use rustc_mir_dataflow::{self, Analysis};
72 use rustc_target::abi::VariantIdx;
73 use rustc_target::spec::PanicStrategy;
74 use std::{iter, ops};
75
76 pub struct StateTransform;
77
78 struct RenameLocalVisitor<'tcx> {
79     from: Local,
80     to: Local,
81     tcx: TyCtxt<'tcx>,
82 }
83
84 impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
85     fn tcx(&self) -> TyCtxt<'tcx> {
86         self.tcx
87     }
88
89     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
90         if *local == self.from {
91             *local = self.to;
92         }
93     }
94
95     fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
96         match terminator.kind {
97             TerminatorKind::Return => {
98                 // Do not replace the implicit `_0` access here, as that's not possible. The
99                 // transform already handles `return` correctly.
100             }
101             _ => self.super_terminator(terminator, location),
102         }
103     }
104 }
105
106 struct DerefArgVisitor<'tcx> {
107     tcx: TyCtxt<'tcx>,
108 }
109
110 impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
111     fn tcx(&self) -> TyCtxt<'tcx> {
112         self.tcx
113     }
114
115     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
116         assert_ne!(*local, SELF_ARG);
117     }
118
119     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
120         if place.local == SELF_ARG {
121             replace_base(
122                 place,
123                 Place {
124                     local: SELF_ARG,
125                     projection: self.tcx().intern_place_elems(&[ProjectionElem::Deref]),
126                 },
127                 self.tcx,
128             );
129         } else {
130             self.visit_local(&mut place.local, context, location);
131
132             for elem in place.projection.iter() {
133                 if let PlaceElem::Index(local) = elem {
134                     assert_ne!(local, SELF_ARG);
135                 }
136             }
137         }
138     }
139 }
140
141 struct PinArgVisitor<'tcx> {
142     ref_gen_ty: Ty<'tcx>,
143     tcx: TyCtxt<'tcx>,
144 }
145
146 impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
147     fn tcx(&self) -> TyCtxt<'tcx> {
148         self.tcx
149     }
150
151     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
152         assert_ne!(*local, SELF_ARG);
153     }
154
155     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
156         if place.local == SELF_ARG {
157             replace_base(
158                 place,
159                 Place {
160                     local: SELF_ARG,
161                     projection: self.tcx().intern_place_elems(&[ProjectionElem::Field(
162                         Field::new(0),
163                         self.ref_gen_ty,
164                     )]),
165                 },
166                 self.tcx,
167             );
168         } else {
169             self.visit_local(&mut place.local, context, location);
170
171             for elem in place.projection.iter() {
172                 if let PlaceElem::Index(local) = elem {
173                     assert_ne!(local, SELF_ARG);
174                 }
175             }
176         }
177     }
178 }
179
180 fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) {
181     place.local = new_base.local;
182
183     let mut new_projection = new_base.projection.to_vec();
184     new_projection.append(&mut place.projection.to_vec());
185
186     place.projection = tcx.intern_place_elems(&new_projection);
187 }
188
189 const SELF_ARG: Local = Local::from_u32(1);
190
191 /// Generator has not been resumed yet.
192 const UNRESUMED: usize = GeneratorSubsts::UNRESUMED;
193 /// Generator has returned / is completed.
194 const RETURNED: usize = GeneratorSubsts::RETURNED;
195 /// Generator has panicked and is poisoned.
196 const POISONED: usize = GeneratorSubsts::POISONED;
197
198 /// Number of variants to reserve in generator state. Corresponds to
199 /// `UNRESUMED` (beginning of a generator) and `RETURNED`/`POISONED`
200 /// (end of a generator) states.
201 const RESERVED_VARIANTS: usize = 3;
202
203 /// A `yield` point in the generator.
204 struct SuspensionPoint<'tcx> {
205     /// State discriminant used when suspending or resuming at this point.
206     state: usize,
207     /// The block to jump to after resumption.
208     resume: BasicBlock,
209     /// Where to move the resume argument after resumption.
210     resume_arg: Place<'tcx>,
211     /// Which block to jump to if the generator is dropped in this state.
212     drop: Option<BasicBlock>,
213     /// Set of locals that have live storage while at this suspension point.
214     storage_liveness: GrowableBitSet<Local>,
215 }
216
217 struct TransformVisitor<'tcx> {
218     tcx: TyCtxt<'tcx>,
219     state_adt_ref: AdtDef<'tcx>,
220     state_substs: SubstsRef<'tcx>,
221
222     // The type of the discriminant in the generator struct
223     discr_ty: Ty<'tcx>,
224
225     // Mapping from Local to (type of local, generator struct index)
226     // FIXME(eddyb) This should use `IndexVec<Local, Option<_>>`.
227     remap: FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
228
229     // A map from a suspension point in a block to the locals which have live storage at that point
230     storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
231
232     // A list of suspension points, generated during the transform
233     suspension_points: Vec<SuspensionPoint<'tcx>>,
234
235     // The set of locals that have no `StorageLive`/`StorageDead` annotations.
236     always_live_locals: BitSet<Local>,
237
238     // The original RETURN_PLACE local
239     new_ret_local: Local,
240 }
241
242 impl<'tcx> TransformVisitor<'tcx> {
243     // Make a GeneratorState variant assignment. `core::ops::GeneratorState` only has single
244     // element tuple variants, so we can just write to the downcasted first field and then set the
245     // discriminant to the appropriate variant.
246     fn make_state(
247         &self,
248         idx: VariantIdx,
249         val: Operand<'tcx>,
250         source_info: SourceInfo,
251     ) -> impl Iterator<Item = Statement<'tcx>> {
252         let kind = AggregateKind::Adt(self.state_adt_ref.did(), idx, self.state_substs, None, None);
253         assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 1);
254         let ty = self
255             .tcx
256             .bound_type_of(self.state_adt_ref.variant(idx).fields[0].did)
257             .subst(self.tcx, self.state_substs);
258         expand_aggregate(
259             Place::return_place(),
260             std::iter::once((val, ty)),
261             kind,
262             source_info,
263             self.tcx,
264         )
265     }
266
267     // Create a Place referencing a generator struct field
268     fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
269         let self_place = Place::from(SELF_ARG);
270         let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index);
271         let mut projection = base.projection.to_vec();
272         projection.push(ProjectionElem::Field(Field::new(idx), ty));
273
274         Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) }
275     }
276
277     // Create a statement which changes the discriminant
278     fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> {
279         let self_place = Place::from(SELF_ARG);
280         Statement {
281             source_info,
282             kind: StatementKind::SetDiscriminant {
283                 place: Box::new(self_place),
284                 variant_index: state_disc,
285             },
286         }
287     }
288
289     // Create a statement which reads the discriminant into a temporary
290     fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) {
291         let temp_decl = LocalDecl::new(self.discr_ty, body.span).internal();
292         let local_decls_len = body.local_decls.push(temp_decl);
293         let temp = Place::from(local_decls_len);
294
295         let self_place = Place::from(SELF_ARG);
296         let assign = Statement {
297             source_info: SourceInfo::outermost(body.span),
298             kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))),
299         };
300         (assign, temp)
301     }
302 }
303
304 impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
305     fn tcx(&self) -> TyCtxt<'tcx> {
306         self.tcx
307     }
308
309     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
310         assert_eq!(self.remap.get(local), None);
311     }
312
313     fn visit_place(
314         &mut self,
315         place: &mut Place<'tcx>,
316         _context: PlaceContext,
317         _location: Location,
318     ) {
319         // Replace an Local in the remap with a generator struct access
320         if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) {
321             replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
322         }
323     }
324
325     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
326         // Remove StorageLive and StorageDead statements for remapped locals
327         data.retain_statements(|s| match s.kind {
328             StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
329                 !self.remap.contains_key(&l)
330             }
331             _ => true,
332         });
333
334         let ret_val = match data.terminator().kind {
335             TerminatorKind::Return => Some((
336                 VariantIdx::new(1),
337                 None,
338                 Operand::Move(Place::from(self.new_ret_local)),
339                 None,
340             )),
341             TerminatorKind::Yield { ref value, resume, resume_arg, drop } => {
342                 Some((VariantIdx::new(0), Some((resume, resume_arg)), value.clone(), drop))
343             }
344             _ => None,
345         };
346
347         if let Some((state_idx, resume, v, drop)) = ret_val {
348             let source_info = data.terminator().source_info;
349             // We must assign the value first in case it gets declared dead below
350             data.statements.extend(self.make_state(state_idx, v, source_info));
351             let state = if let Some((resume, mut resume_arg)) = resume {
352                 // Yield
353                 let state = RESERVED_VARIANTS + self.suspension_points.len();
354
355                 // The resume arg target location might itself be remapped if its base local is
356                 // live across a yield.
357                 let resume_arg =
358                     if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) {
359                         replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx);
360                         resume_arg
361                     } else {
362                         resume_arg
363                     };
364
365                 self.suspension_points.push(SuspensionPoint {
366                     state,
367                     resume,
368                     resume_arg,
369                     drop,
370                     storage_liveness: self.storage_liveness[block].clone().unwrap().into(),
371                 });
372
373                 VariantIdx::new(state)
374             } else {
375                 // Return
376                 VariantIdx::new(RETURNED) // state for returned
377             };
378             data.statements.push(self.set_discr(state, source_info));
379             data.terminator_mut().kind = TerminatorKind::Return;
380         }
381
382         self.super_basic_block_data(block, data);
383     }
384 }
385
386 fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
387     let gen_ty = body.local_decls.raw[1].ty;
388
389     let ref_gen_ty =
390         tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut });
391
392     // Replace the by value generator argument
393     body.local_decls.raw[1].ty = ref_gen_ty;
394
395     // Add a deref to accesses of the generator state
396     DerefArgVisitor { tcx }.visit_body(body);
397 }
398
399 fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
400     let ref_gen_ty = body.local_decls.raw[1].ty;
401
402     let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span));
403     let pin_adt_ref = tcx.adt_def(pin_did);
404     let substs = tcx.intern_substs(&[ref_gen_ty.into()]);
405     let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs);
406
407     // Replace the by ref generator argument
408     body.local_decls.raw[1].ty = pin_ref_gen_ty;
409
410     // Add the Pin field access to accesses of the generator state
411     PinArgVisitor { ref_gen_ty, tcx }.visit_body(body);
412 }
413
414 /// Allocates a new local and replaces all references of `local` with it. Returns the new local.
415 ///
416 /// `local` will be changed to a new local decl with type `ty`.
417 ///
418 /// Note that the new local will be uninitialized. It is the caller's responsibility to assign some
419 /// valid value to it before its first use.
420 fn replace_local<'tcx>(
421     local: Local,
422     ty: Ty<'tcx>,
423     body: &mut Body<'tcx>,
424     tcx: TyCtxt<'tcx>,
425 ) -> Local {
426     let new_decl = LocalDecl::new(ty, body.span);
427     let new_local = body.local_decls.push(new_decl);
428     body.local_decls.swap(local, new_local);
429
430     RenameLocalVisitor { from: local, to: new_local, tcx }.visit_body(body);
431
432     new_local
433 }
434
435 struct LivenessInfo {
436     /// Which locals are live across any suspension point.
437     saved_locals: GeneratorSavedLocals,
438
439     /// The set of saved locals live at each suspension point.
440     live_locals_at_suspension_points: Vec<BitSet<GeneratorSavedLocal>>,
441
442     /// Parallel vec to the above with SourceInfo for each yield terminator.
443     source_info_at_suspension_points: Vec<SourceInfo>,
444
445     /// For every saved local, the set of other saved locals that are
446     /// storage-live at the same time as this local. We cannot overlap locals in
447     /// the layout which have conflicting storage.
448     storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
449
450     /// For every suspending block, the locals which are storage-live across
451     /// that suspension point.
452     storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
453 }
454
455 fn locals_live_across_suspend_points<'tcx>(
456     tcx: TyCtxt<'tcx>,
457     body: &Body<'tcx>,
458     always_live_locals: &BitSet<Local>,
459     movable: bool,
460 ) -> LivenessInfo {
461     let body_ref: &Body<'_> = &body;
462
463     // Calculate when MIR locals have live storage. This gives us an upper bound of their
464     // lifetimes.
465     let mut storage_live = MaybeStorageLive::new(always_live_locals.clone())
466         .into_engine(tcx, body_ref)
467         .iterate_to_fixpoint()
468         .into_results_cursor(body_ref);
469
470     // Calculate the MIR locals which have been previously
471     // borrowed (even if they are still active).
472     let borrowed_locals_results =
473         MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
474
475     let mut borrowed_locals_cursor =
476         rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
477
478     // Calculate the MIR locals that we actually need to keep storage around
479     // for.
480     let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
481         .into_engine(tcx, body_ref)
482         .iterate_to_fixpoint();
483     let mut requires_storage_cursor =
484         rustc_mir_dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
485
486     // Calculate the liveness of MIR locals ignoring borrows.
487     let mut liveness = MaybeLiveLocals
488         .into_engine(tcx, body_ref)
489         .pass_name("generator")
490         .iterate_to_fixpoint()
491         .into_results_cursor(body_ref);
492
493     let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks());
494     let mut live_locals_at_suspension_points = Vec::new();
495     let mut source_info_at_suspension_points = Vec::new();
496     let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
497
498     for (block, data) in body.basic_blocks().iter_enumerated() {
499         if let TerminatorKind::Yield { .. } = data.terminator().kind {
500             let loc = Location { block, statement_index: data.statements.len() };
501
502             liveness.seek_to_block_end(block);
503             let mut live_locals: BitSet<_> = BitSet::new_empty(body.local_decls.len());
504             live_locals.union(liveness.get());
505
506             if !movable {
507                 // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
508                 // This is correct for movable generators since borrows cannot live across
509                 // suspension points. However for immovable generators we need to account for
510                 // borrows, so we conservatively assume that all borrowed locals are live until
511                 // we find a StorageDead statement referencing the locals.
512                 // To do this we just union our `liveness` result with `borrowed_locals`, which
513                 // contains all the locals which has been borrowed before this suspension point.
514                 // If a borrow is converted to a raw reference, we must also assume that it lives
515                 // forever. Note that the final liveness is still bounded by the storage liveness
516                 // of the local, which happens using the `intersect` operation below.
517                 borrowed_locals_cursor.seek_before_primary_effect(loc);
518                 live_locals.union(borrowed_locals_cursor.get());
519             }
520
521             // Store the storage liveness for later use so we can restore the state
522             // after a suspension point
523             storage_live.seek_before_primary_effect(loc);
524             storage_liveness_map[block] = Some(storage_live.get().clone());
525
526             // Locals live are live at this point only if they are used across
527             // suspension points (the `liveness` variable)
528             // and their storage is required (the `storage_required` variable)
529             requires_storage_cursor.seek_before_primary_effect(loc);
530             live_locals.intersect(requires_storage_cursor.get());
531
532             // The generator argument is ignored.
533             live_locals.remove(SELF_ARG);
534
535             debug!("loc = {:?}, live_locals = {:?}", loc, live_locals);
536
537             // Add the locals live at this suspension point to the set of locals which live across
538             // any suspension points
539             live_locals_at_any_suspension_point.union(&live_locals);
540
541             live_locals_at_suspension_points.push(live_locals);
542             source_info_at_suspension_points.push(data.terminator().source_info);
543         }
544     }
545
546     debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point);
547     let saved_locals = GeneratorSavedLocals(live_locals_at_any_suspension_point);
548
549     // Renumber our liveness_map bitsets to include only the locals we are
550     // saving.
551     let live_locals_at_suspension_points = live_locals_at_suspension_points
552         .iter()
553         .map(|live_here| saved_locals.renumber_bitset(&live_here))
554         .collect();
555
556     let storage_conflicts = compute_storage_conflicts(
557         body_ref,
558         &saved_locals,
559         always_live_locals.clone(),
560         requires_storage_results,
561     );
562
563     LivenessInfo {
564         saved_locals,
565         live_locals_at_suspension_points,
566         source_info_at_suspension_points,
567         storage_conflicts,
568         storage_liveness: storage_liveness_map,
569     }
570 }
571
572 /// The set of `Local`s that must be saved across yield points.
573 ///
574 /// `GeneratorSavedLocal` is indexed in terms of the elements in this set;
575 /// i.e. `GeneratorSavedLocal::new(1)` corresponds to the second local
576 /// included in this set.
577 struct GeneratorSavedLocals(BitSet<Local>);
578
579 impl GeneratorSavedLocals {
580     /// Returns an iterator over each `GeneratorSavedLocal` along with the `Local` it corresponds
581     /// to.
582     fn iter_enumerated(&self) -> impl '_ + Iterator<Item = (GeneratorSavedLocal, Local)> {
583         self.iter().enumerate().map(|(i, l)| (GeneratorSavedLocal::from(i), l))
584     }
585
586     /// Transforms a `BitSet<Local>` that contains only locals saved across yield points to the
587     /// equivalent `BitSet<GeneratorSavedLocal>`.
588     fn renumber_bitset(&self, input: &BitSet<Local>) -> BitSet<GeneratorSavedLocal> {
589         assert!(self.superset(&input), "{:?} not a superset of {:?}", self.0, input);
590         let mut out = BitSet::new_empty(self.count());
591         for (saved_local, local) in self.iter_enumerated() {
592             if input.contains(local) {
593                 out.insert(saved_local);
594             }
595         }
596         out
597     }
598
599     fn get(&self, local: Local) -> Option<GeneratorSavedLocal> {
600         if !self.contains(local) {
601             return None;
602         }
603
604         let idx = self.iter().take_while(|&l| l < local).count();
605         Some(GeneratorSavedLocal::new(idx))
606     }
607 }
608
609 impl ops::Deref for GeneratorSavedLocals {
610     type Target = BitSet<Local>;
611
612     fn deref(&self) -> &Self::Target {
613         &self.0
614     }
615 }
616
617 /// For every saved local, looks for which locals are StorageLive at the same
618 /// time. Generates a bitset for every local of all the other locals that may be
619 /// StorageLive simultaneously with that local. This is used in the layout
620 /// computation; see `GeneratorLayout` for more.
621 fn compute_storage_conflicts<'mir, 'tcx>(
622     body: &'mir Body<'tcx>,
623     saved_locals: &GeneratorSavedLocals,
624     always_live_locals: BitSet<Local>,
625     requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
626 ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
627     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
628
629     debug!("compute_storage_conflicts({:?})", body.span);
630     debug!("always_live = {:?}", always_live_locals);
631
632     // Locals that are always live or ones that need to be stored across
633     // suspension points are not eligible for overlap.
634     let mut ineligible_locals = always_live_locals;
635     ineligible_locals.intersect(&**saved_locals);
636
637     // Compute the storage conflicts for all eligible locals.
638     let mut visitor = StorageConflictVisitor {
639         body,
640         saved_locals: &saved_locals,
641         local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
642     };
643
644     requires_storage.visit_reachable_with(body, &mut visitor);
645
646     let local_conflicts = visitor.local_conflicts;
647
648     // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal).
649     //
650     // NOTE: Today we store a full conflict bitset for every local. Technically
651     // this is twice as many bits as we need, since the relation is symmetric.
652     // However, in practice these bitsets are not usually large. The layout code
653     // also needs to keep track of how many conflicts each local has, so it's
654     // simpler to keep it this way for now.
655     let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count());
656     for (saved_local_a, local_a) in saved_locals.iter_enumerated() {
657         if ineligible_locals.contains(local_a) {
658             // Conflicts with everything.
659             storage_conflicts.insert_all_into_row(saved_local_a);
660         } else {
661             // Keep overlap information only for stored locals.
662             for (saved_local_b, local_b) in saved_locals.iter_enumerated() {
663                 if local_conflicts.contains(local_a, local_b) {
664                     storage_conflicts.insert(saved_local_a, saved_local_b);
665                 }
666             }
667         }
668     }
669     storage_conflicts
670 }
671
672 struct StorageConflictVisitor<'mir, 'tcx, 's> {
673     body: &'mir Body<'tcx>,
674     saved_locals: &'s GeneratorSavedLocals,
675     // FIXME(tmandry): Consider using sparse bitsets here once we have good
676     // benchmarks for generators.
677     local_conflicts: BitMatrix<Local, Local>,
678 }
679
680 impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
681     for StorageConflictVisitor<'mir, 'tcx, '_>
682 {
683     type FlowState = BitSet<Local>;
684
685     fn visit_statement_before_primary_effect(
686         &mut self,
687         state: &Self::FlowState,
688         _statement: &'mir Statement<'tcx>,
689         loc: Location,
690     ) {
691         self.apply_state(state, loc);
692     }
693
694     fn visit_terminator_before_primary_effect(
695         &mut self,
696         state: &Self::FlowState,
697         _terminator: &'mir Terminator<'tcx>,
698         loc: Location,
699     ) {
700         self.apply_state(state, loc);
701     }
702 }
703
704 impl StorageConflictVisitor<'_, '_, '_> {
705     fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
706         // Ignore unreachable blocks.
707         if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable {
708             return;
709         }
710
711         let mut eligible_storage_live = flow_state.clone();
712         eligible_storage_live.intersect(&**self.saved_locals);
713
714         for local in eligible_storage_live.iter() {
715             self.local_conflicts.union_row_with(&eligible_storage_live, local);
716         }
717
718         if eligible_storage_live.count() > 1 {
719             trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live);
720         }
721     }
722 }
723
724 /// Validates the typeck view of the generator against the actual set of types saved between
725 /// yield points.
726 fn sanitize_witness<'tcx>(
727     tcx: TyCtxt<'tcx>,
728     body: &Body<'tcx>,
729     witness: Ty<'tcx>,
730     upvars: Vec<Ty<'tcx>>,
731     saved_locals: &GeneratorSavedLocals,
732 ) {
733     let did = body.source.def_id();
734     let param_env = tcx.param_env(did);
735
736     let allowed_upvars = tcx.normalize_erasing_regions(param_env, upvars);
737     let allowed = match witness.kind() {
738         &ty::GeneratorWitness(interior_tys) => {
739             tcx.normalize_erasing_late_bound_regions(param_env, interior_tys)
740         }
741         _ => {
742             tcx.sess.delay_span_bug(
743                 body.span,
744                 &format!("unexpected generator witness type {:?}", witness.kind()),
745             );
746             return;
747         }
748     };
749
750     for (local, decl) in body.local_decls.iter_enumerated() {
751         // Ignore locals which are internal or not saved between yields.
752         if !saved_locals.contains(local) || decl.internal {
753             continue;
754         }
755         let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty);
756
757         // Sanity check that typeck knows about the type of locals which are
758         // live across a suspension point
759         if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) {
760             span_bug!(
761                 body.span,
762                 "Broken MIR: generator contains type {} in MIR, \
763                        but typeck only knows about {} and {:?}",
764                 decl_ty,
765                 allowed,
766                 allowed_upvars
767             );
768         }
769     }
770 }
771
772 fn compute_layout<'tcx>(
773     liveness: LivenessInfo,
774     body: &mut Body<'tcx>,
775 ) -> (
776     FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
777     GeneratorLayout<'tcx>,
778     IndexVec<BasicBlock, Option<BitSet<Local>>>,
779 ) {
780     let LivenessInfo {
781         saved_locals,
782         live_locals_at_suspension_points,
783         source_info_at_suspension_points,
784         storage_conflicts,
785         storage_liveness,
786     } = liveness;
787
788     // Gather live local types and their indices.
789     let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
790     let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
791     for (saved_local, local) in saved_locals.iter_enumerated() {
792         locals.push(local);
793         tys.push(body.local_decls[local].ty);
794         debug!("generator saved local {:?} => {:?}", saved_local, local);
795     }
796
797     // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
798     // In debuginfo, these will correspond to the beginning (UNRESUMED) or end
799     // (RETURNED, POISONED) of the function.
800     let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span;
801     let mut variant_source_info: IndexVec<VariantIdx, SourceInfo> = [
802         SourceInfo::outermost(body_span.shrink_to_lo()),
803         SourceInfo::outermost(body_span.shrink_to_hi()),
804         SourceInfo::outermost(body_span.shrink_to_hi()),
805     ]
806     .iter()
807     .copied()
808     .collect();
809
810     // Build the generator variant field list.
811     // Create a map from local indices to generator struct indices.
812     let mut variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>> =
813         iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect();
814     let mut remap = FxHashMap::default();
815     for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() {
816         let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx);
817         let mut fields = IndexVec::new();
818         for (idx, saved_local) in live_locals.iter().enumerate() {
819             fields.push(saved_local);
820             // Note that if a field is included in multiple variants, we will
821             // just use the first one here. That's fine; fields do not move
822             // around inside generators, so it doesn't matter which variant
823             // index we access them by.
824             remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx));
825         }
826         variant_fields.push(fields);
827         variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]);
828     }
829     debug!("generator variant_fields = {:?}", variant_fields);
830     debug!("generator storage_conflicts = {:#?}", storage_conflicts);
831
832     let layout =
833         GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts };
834
835     (remap, layout, storage_liveness)
836 }
837
838 /// Replaces the entry point of `body` with a block that switches on the generator discriminant and
839 /// dispatches to blocks according to `cases`.
840 ///
841 /// After this function, the former entry point of the function will be bb1.
842 fn insert_switch<'tcx>(
843     body: &mut Body<'tcx>,
844     cases: Vec<(usize, BasicBlock)>,
845     transform: &TransformVisitor<'tcx>,
846     default: TerminatorKind<'tcx>,
847 ) {
848     let default_block = insert_term_block(body, default);
849     let (assign, discr) = transform.get_discr(body);
850     let switch_targets =
851         SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
852     let switch = TerminatorKind::SwitchInt {
853         discr: Operand::Move(discr),
854         switch_ty: transform.discr_ty,
855         targets: switch_targets,
856     };
857
858     let source_info = SourceInfo::outermost(body.span);
859     body.basic_blocks_mut().raw.insert(
860         0,
861         BasicBlockData {
862             statements: vec![assign],
863             terminator: Some(Terminator { source_info, kind: switch }),
864             is_cleanup: false,
865         },
866     );
867
868     let blocks = body.basic_blocks_mut().iter_mut();
869
870     for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) {
871         *target = BasicBlock::new(target.index() + 1);
872     }
873 }
874
875 fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
876     use crate::shim::DropShimElaborator;
877     use rustc_middle::mir::patch::MirPatch;
878     use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, Unwind};
879
880     // Note that `elaborate_drops` only drops the upvars of a generator, and
881     // this is ok because `open_drop` can only be reached within that own
882     // generator's resume function.
883
884     let def_id = body.source.def_id();
885     let param_env = tcx.param_env(def_id);
886
887     let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env };
888
889     for (block, block_data) in body.basic_blocks().iter_enumerated() {
890         let (target, unwind, source_info) = match block_data.terminator() {
891             Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
892                 if let Some(local) = place.as_local() {
893                     if local == SELF_ARG {
894                         (target, unwind, source_info)
895                     } else {
896                         continue;
897                     }
898                 } else {
899                     continue;
900                 }
901             }
902             _ => continue,
903         };
904         let unwind = if block_data.is_cleanup {
905             Unwind::InCleanup
906         } else {
907             Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block()))
908         };
909         elaborate_drop(
910             &mut elaborator,
911             *source_info,
912             Place::from(SELF_ARG),
913             (),
914             *target,
915             unwind,
916             block,
917         );
918     }
919     elaborator.patch.apply(body);
920 }
921
922 fn create_generator_drop_shim<'tcx>(
923     tcx: TyCtxt<'tcx>,
924     transform: &TransformVisitor<'tcx>,
925     gen_ty: Ty<'tcx>,
926     body: &mut Body<'tcx>,
927     drop_clean: BasicBlock,
928 ) -> Body<'tcx> {
929     let mut body = body.clone();
930     body.arg_count = 1; // make sure the resume argument is not included here
931
932     let source_info = SourceInfo::outermost(body.span);
933
934     let mut cases = create_cases(&mut body, transform, Operation::Drop);
935
936     cases.insert(0, (UNRESUMED, drop_clean));
937
938     // The returned state and the poisoned state fall through to the default
939     // case which is just to return
940
941     insert_switch(&mut body, cases, &transform, TerminatorKind::Return);
942
943     for block in body.basic_blocks_mut() {
944         let kind = &mut block.terminator_mut().kind;
945         if let TerminatorKind::GeneratorDrop = *kind {
946             *kind = TerminatorKind::Return;
947         }
948     }
949
950     // Replace the return variable
951     body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.mk_unit(), source_info);
952
953     make_generator_state_argument_indirect(tcx, &mut body);
954
955     // Change the generator argument from &mut to *mut
956     body.local_decls[SELF_ARG] = LocalDecl::with_source_info(
957         tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
958         source_info,
959     );
960     if tcx.sess.opts.unstable_opts.mir_emit_retag {
961         // Alias tracking must know we changed the type
962         body.basic_blocks_mut()[START_BLOCK].statements.insert(
963             0,
964             Statement {
965                 source_info,
966                 kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))),
967             },
968         )
969     }
970
971     // Make sure we remove dead blocks to remove
972     // unrelated code from the resume part of the function
973     simplify::remove_dead_blocks(tcx, &mut body);
974
975     dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
976
977     body
978 }
979
980 fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock {
981     let source_info = SourceInfo::outermost(body.span);
982     body.basic_blocks_mut().push(BasicBlockData {
983         statements: Vec::new(),
984         terminator: Some(Terminator { source_info, kind }),
985         is_cleanup: false,
986     })
987 }
988
989 fn insert_panic_block<'tcx>(
990     tcx: TyCtxt<'tcx>,
991     body: &mut Body<'tcx>,
992     message: AssertMessage<'tcx>,
993 ) -> BasicBlock {
994     let assert_block = BasicBlock::new(body.basic_blocks().len());
995     let term = TerminatorKind::Assert {
996         cond: Operand::Constant(Box::new(Constant {
997             span: body.span,
998             user_ty: None,
999             literal: ConstantKind::from_bool(tcx, false),
1000         })),
1001         expected: true,
1002         msg: message,
1003         target: assert_block,
1004         cleanup: None,
1005     };
1006
1007     let source_info = SourceInfo::outermost(body.span);
1008     body.basic_blocks_mut().push(BasicBlockData {
1009         statements: Vec::new(),
1010         terminator: Some(Terminator { source_info, kind: term }),
1011         is_cleanup: false,
1012     });
1013
1014     assert_block
1015 }
1016
1017 fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
1018     // Returning from a function with an uninhabited return type is undefined behavior.
1019     if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) {
1020         return false;
1021     }
1022
1023     // If there's a return terminator the function may return.
1024     for block in body.basic_blocks() {
1025         if let TerminatorKind::Return = block.terminator().kind {
1026             return true;
1027         }
1028     }
1029
1030     // Otherwise the function can't return.
1031     false
1032 }
1033
1034 fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
1035     // Nothing can unwind when landing pads are off.
1036     if tcx.sess.panic_strategy() == PanicStrategy::Abort {
1037         return false;
1038     }
1039
1040     // Unwinds can only start at certain terminators.
1041     for block in body.basic_blocks() {
1042         match block.terminator().kind {
1043             // These never unwind.
1044             TerminatorKind::Goto { .. }
1045             | TerminatorKind::SwitchInt { .. }
1046             | TerminatorKind::Abort
1047             | TerminatorKind::Return
1048             | TerminatorKind::Unreachable
1049             | TerminatorKind::GeneratorDrop
1050             | TerminatorKind::FalseEdge { .. }
1051             | TerminatorKind::FalseUnwind { .. } => {}
1052
1053             // Resume will *continue* unwinding, but if there's no other unwinding terminator it
1054             // will never be reached.
1055             TerminatorKind::Resume => {}
1056
1057             TerminatorKind::Yield { .. } => {
1058                 unreachable!("`can_unwind` called before generator transform")
1059             }
1060
1061             // These may unwind.
1062             TerminatorKind::Drop { .. }
1063             | TerminatorKind::DropAndReplace { .. }
1064             | TerminatorKind::Call { .. }
1065             | TerminatorKind::InlineAsm { .. }
1066             | TerminatorKind::Assert { .. } => return true,
1067         }
1068     }
1069
1070     // If we didn't find an unwinding terminator, the function cannot unwind.
1071     false
1072 }
1073
1074 fn create_generator_resume_function<'tcx>(
1075     tcx: TyCtxt<'tcx>,
1076     transform: TransformVisitor<'tcx>,
1077     body: &mut Body<'tcx>,
1078     can_return: bool,
1079 ) {
1080     let can_unwind = can_unwind(tcx, body);
1081
1082     // Poison the generator when it unwinds
1083     if can_unwind {
1084         let source_info = SourceInfo::outermost(body.span);
1085         let poison_block = body.basic_blocks_mut().push(BasicBlockData {
1086             statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)],
1087             terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }),
1088             is_cleanup: true,
1089         });
1090
1091         for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() {
1092             let source_info = block.terminator().source_info;
1093
1094             if let TerminatorKind::Resume = block.terminator().kind {
1095                 // An existing `Resume` terminator is redirected to jump to our dedicated
1096                 // "poisoning block" above.
1097                 if idx != poison_block {
1098                     *block.terminator_mut() = Terminator {
1099                         source_info,
1100                         kind: TerminatorKind::Goto { target: poison_block },
1101                     };
1102                 }
1103             } else if !block.is_cleanup {
1104                 // Any terminators that *can* unwind but don't have an unwind target set are also
1105                 // pointed at our poisoning block (unless they're part of the cleanup path).
1106                 if let Some(unwind @ None) = block.terminator_mut().unwind_mut() {
1107                     *unwind = Some(poison_block);
1108                 }
1109             }
1110         }
1111     }
1112
1113     let mut cases = create_cases(body, &transform, Operation::Resume);
1114
1115     use rustc_middle::mir::AssertKind::{ResumedAfterPanic, ResumedAfterReturn};
1116
1117     // Jump to the entry point on the unresumed
1118     cases.insert(0, (UNRESUMED, BasicBlock::new(0)));
1119
1120     // Panic when resumed on the returned or poisoned state
1121     let generator_kind = body.generator_kind().unwrap();
1122
1123     if can_unwind {
1124         cases.insert(
1125             1,
1126             (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))),
1127         );
1128     }
1129
1130     if can_return {
1131         cases.insert(
1132             1,
1133             (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind))),
1134         );
1135     }
1136
1137     insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
1138
1139     make_generator_state_argument_indirect(tcx, body);
1140     make_generator_state_argument_pinned(tcx, body);
1141
1142     // Make sure we remove dead blocks to remove
1143     // unrelated code from the drop part of the function
1144     simplify::remove_dead_blocks(tcx, body);
1145
1146     dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
1147 }
1148
1149 fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
1150     let return_block = insert_term_block(body, TerminatorKind::Return);
1151
1152     let term =
1153         TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None };
1154     let source_info = SourceInfo::outermost(body.span);
1155
1156     // Create a block to destroy an unresumed generators. This can only destroy upvars.
1157     body.basic_blocks_mut().push(BasicBlockData {
1158         statements: Vec::new(),
1159         terminator: Some(Terminator { source_info, kind: term }),
1160         is_cleanup: false,
1161     })
1162 }
1163
1164 /// An operation that can be performed on a generator.
1165 #[derive(PartialEq, Copy, Clone)]
1166 enum Operation {
1167     Resume,
1168     Drop,
1169 }
1170
1171 impl Operation {
1172     fn target_block(self, point: &SuspensionPoint<'_>) -> Option<BasicBlock> {
1173         match self {
1174             Operation::Resume => Some(point.resume),
1175             Operation::Drop => point.drop,
1176         }
1177     }
1178 }
1179
1180 fn create_cases<'tcx>(
1181     body: &mut Body<'tcx>,
1182     transform: &TransformVisitor<'tcx>,
1183     operation: Operation,
1184 ) -> Vec<(usize, BasicBlock)> {
1185     let tcx = transform.tcx;
1186
1187     let source_info = SourceInfo::outermost(body.span);
1188
1189     transform
1190         .suspension_points
1191         .iter()
1192         .filter_map(|point| {
1193             // Find the target for this suspension point, if applicable
1194             operation.target_block(point).map(|target| {
1195                 let mut statements = Vec::new();
1196
1197                 // Create StorageLive instructions for locals with live storage
1198                 for i in 0..(body.local_decls.len()) {
1199                     if i == 2 {
1200                         // The resume argument is live on function entry. Don't insert a
1201                         // `StorageLive`, or the following `Assign` will read from uninitialized
1202                         // memory.
1203                         continue;
1204                     }
1205
1206                     let l = Local::new(i);
1207                     let needs_storage_live = point.storage_liveness.contains(l)
1208                         && !transform.remap.contains_key(&l)
1209                         && !transform.always_live_locals.contains(l);
1210                     if needs_storage_live {
1211                         statements
1212                             .push(Statement { source_info, kind: StatementKind::StorageLive(l) });
1213                     }
1214                 }
1215
1216                 if operation == Operation::Resume {
1217                     // Move the resume argument to the destination place of the `Yield` terminator
1218                     let resume_arg = Local::new(2); // 0 = return, 1 = self
1219
1220                     // handle `box yield` properly
1221                     let box_place = if let [projection @ .., ProjectionElem::Deref] =
1222                         &**point.resume_arg.projection
1223                     {
1224                         let box_place =
1225                             Place::from(point.resume_arg.local).project_deeper(projection, tcx);
1226
1227                         let box_ty = box_place.ty(&body.local_decls, tcx).ty;
1228
1229                         if box_ty.is_box() { Some((box_place, box_ty)) } else { None }
1230                     } else {
1231                         None
1232                     };
1233
1234                     if let Some((box_place, box_ty)) = box_place {
1235                         let unique_did = box_ty
1236                             .ty_adt_def()
1237                             .expect("expected Box to be an Adt")
1238                             .non_enum_variant()
1239                             .fields[0]
1240                             .did;
1241
1242                         let Some(nonnull_def) = tcx.type_of(unique_did).ty_adt_def() else {
1243                             span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique")
1244                         };
1245
1246                         let nonnull_did = nonnull_def.non_enum_variant().fields[0].did;
1247
1248                         let (unique_ty, nonnull_ty, ptr_ty) =
1249                             crate::elaborate_box_derefs::build_ptr_tys(
1250                                 tcx,
1251                                 box_ty.boxed_ty(),
1252                                 unique_did,
1253                                 nonnull_did,
1254                             );
1255
1256                         let ptr_local = body.local_decls.push(LocalDecl::new(ptr_ty, body.span));
1257
1258                         statements.push(Statement {
1259                             source_info,
1260                             kind: StatementKind::StorageLive(ptr_local),
1261                         });
1262
1263                         statements.push(Statement {
1264                             source_info,
1265                             kind: StatementKind::Assign(Box::new((
1266                                 Place::from(ptr_local),
1267                                 Rvalue::Use(Operand::Copy(box_place.project_deeper(
1268                                     &crate::elaborate_box_derefs::build_projection(
1269                                         unique_ty, nonnull_ty, ptr_ty,
1270                                     ),
1271                                     tcx,
1272                                 ))),
1273                             ))),
1274                         });
1275
1276                         statements.push(Statement {
1277                             source_info,
1278                             kind: StatementKind::Assign(Box::new((
1279                                 Place::from(ptr_local)
1280                                     .project_deeper(&[ProjectionElem::Deref], tcx),
1281                                 Rvalue::Use(Operand::Move(resume_arg.into())),
1282                             ))),
1283                         });
1284
1285                         statements.push(Statement {
1286                             source_info,
1287                             kind: StatementKind::StorageDead(ptr_local),
1288                         });
1289                     } else {
1290                         statements.push(Statement {
1291                             source_info,
1292                             kind: StatementKind::Assign(Box::new((
1293                                 point.resume_arg,
1294                                 Rvalue::Use(Operand::Move(resume_arg.into())),
1295                             ))),
1296                         });
1297                     }
1298                 }
1299
1300                 // Then jump to the real target
1301                 let block = body.basic_blocks_mut().push(BasicBlockData {
1302                     statements,
1303                     terminator: Some(Terminator {
1304                         source_info,
1305                         kind: TerminatorKind::Goto { target },
1306                     }),
1307                     is_cleanup: false,
1308                 });
1309
1310                 (point.state, block)
1311             })
1312         })
1313         .collect()
1314 }
1315
1316 impl<'tcx> MirPass<'tcx> for StateTransform {
1317     fn phase_change(&self) -> Option<MirPhase> {
1318         Some(MirPhase::GeneratorsLowered)
1319     }
1320
1321     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
1322         let Some(yield_ty) = body.yield_ty() else {
1323             // This only applies to generators
1324             return;
1325         };
1326
1327         assert!(body.generator_drop().is_none());
1328
1329         // The first argument is the generator type passed by value
1330         let gen_ty = body.local_decls.raw[1].ty;
1331
1332         // Get the interior types and substs which typeck computed
1333         let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() {
1334             ty::Generator(_, substs, movability) => {
1335                 let substs = substs.as_generator();
1336                 (
1337                     substs.upvar_tys().collect(),
1338                     substs.witness(),
1339                     substs.discr_ty(tcx),
1340                     movability == hir::Movability::Movable,
1341                 )
1342             }
1343             _ => {
1344                 tcx.sess
1345                     .delay_span_bug(body.span, &format!("unexpected generator type {}", gen_ty));
1346                 return;
1347             }
1348         };
1349
1350         // Compute GeneratorState<yield_ty, return_ty>
1351         let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
1352         let state_adt_ref = tcx.adt_def(state_did);
1353         let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]);
1354         let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
1355
1356         // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
1357         // RETURN_PLACE then is a fresh unused local with type ret_ty.
1358         let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx);
1359
1360         // We also replace the resume argument and insert an `Assign`.
1361         // This is needed because the resume argument `_2` might be live across a `yield`, in which
1362         // case there is no `Assign` to it that the transform can turn into a store to the generator
1363         // state. After the yield the slot in the generator state would then be uninitialized.
1364         let resume_local = Local::new(2);
1365         let new_resume_local =
1366             replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
1367
1368         // When first entering the generator, move the resume argument into its new local.
1369         let source_info = SourceInfo::outermost(body.span);
1370         let stmts = &mut body.basic_blocks_mut()[BasicBlock::new(0)].statements;
1371         stmts.insert(
1372             0,
1373             Statement {
1374                 source_info,
1375                 kind: StatementKind::Assign(Box::new((
1376                     new_resume_local.into(),
1377                     Rvalue::Use(Operand::Move(resume_local.into())),
1378                 ))),
1379             },
1380         );
1381
1382         let always_live_locals = always_storage_live_locals(&body);
1383
1384         let liveness_info =
1385             locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
1386
1387         sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals);
1388
1389         if tcx.sess.opts.unstable_opts.validate_mir {
1390             let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
1391                 assigned_local: None,
1392                 saved_locals: &liveness_info.saved_locals,
1393                 storage_conflicts: &liveness_info.storage_conflicts,
1394             };
1395
1396             vis.visit_body(body);
1397         }
1398
1399         // Extract locals which are live across suspension point into `layout`
1400         // `remap` gives a mapping from local indices onto generator struct indices
1401         // `storage_liveness` tells us which locals have live storage at suspension points
1402         let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
1403
1404         let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
1405
1406         // Run the transformation which converts Places from Local to generator struct
1407         // accesses for locals in `remap`.
1408         // It also rewrites `return x` and `yield y` as writing a new generator state and returning
1409         // GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
1410         let mut transform = TransformVisitor {
1411             tcx,
1412             state_adt_ref,
1413             state_substs,
1414             remap,
1415             storage_liveness,
1416             always_live_locals,
1417             suspension_points: Vec::new(),
1418             new_ret_local,
1419             discr_ty,
1420         };
1421         transform.visit_body(body);
1422
1423         // Update our MIR struct to reflect the changes we've made
1424         body.arg_count = 2; // self, resume arg
1425         body.spread_arg = None;
1426
1427         body.generator.as_mut().unwrap().yield_ty = None;
1428         body.generator.as_mut().unwrap().generator_layout = Some(layout);
1429
1430         // Insert `drop(generator_struct)` which is used to drop upvars for generators in
1431         // the unresumed state.
1432         // This is expanded to a drop ladder in `elaborate_generator_drops`.
1433         let drop_clean = insert_clean_drop(body);
1434
1435         dump_mir(tcx, None, "generator_pre-elab", &0, body, |_, _| Ok(()));
1436
1437         // Expand `drop(generator_struct)` to a drop ladder which destroys upvars.
1438         // If any upvars are moved out of, drop elaboration will handle upvar destruction.
1439         // However we need to also elaborate the code generated by `insert_clean_drop`.
1440         elaborate_generator_drops(tcx, body);
1441
1442         dump_mir(tcx, None, "generator_post-transform", &0, body, |_, _| Ok(()));
1443
1444         // Create a copy of our MIR and use it to create the drop shim for the generator
1445         let drop_shim = create_generator_drop_shim(tcx, &transform, gen_ty, body, drop_clean);
1446
1447         body.generator.as_mut().unwrap().generator_drop = Some(drop_shim);
1448
1449         // Create the Generator::resume function
1450         create_generator_resume_function(tcx, transform, body, can_return);
1451
1452         // Run derefer to fix Derefs that are not in the first place
1453         deref_finder(tcx, body);
1454     }
1455 }
1456
1457 /// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
1458 /// in the generator state machine but whose storage is not marked as conflicting
1459 ///
1460 /// Validation needs to happen immediately *before* `TransformVisitor` is invoked, not after.
1461 ///
1462 /// This condition would arise when the assignment is the last use of `_5` but the initial
1463 /// definition of `_4` if we weren't extra careful to mark all locals used inside a statement as
1464 /// conflicting. Non-conflicting generator saved locals may be stored at the same location within
1465 /// the generator state machine, which would result in ill-formed MIR: the left-hand and right-hand
1466 /// sides of an assignment may not alias. This caused a miscompilation in [#73137].
1467 ///
1468 /// [#73137]: https://github.com/rust-lang/rust/issues/73137
1469 struct EnsureGeneratorFieldAssignmentsNeverAlias<'a> {
1470     saved_locals: &'a GeneratorSavedLocals,
1471     storage_conflicts: &'a BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
1472     assigned_local: Option<GeneratorSavedLocal>,
1473 }
1474
1475 impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
1476     fn saved_local_for_direct_place(&self, place: Place<'_>) -> Option<GeneratorSavedLocal> {
1477         if place.is_indirect() {
1478             return None;
1479         }
1480
1481         self.saved_locals.get(place.local)
1482     }
1483
1484     fn check_assigned_place(&mut self, place: Place<'_>, f: impl FnOnce(&mut Self)) {
1485         if let Some(assigned_local) = self.saved_local_for_direct_place(place) {
1486             assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse");
1487
1488             self.assigned_local = Some(assigned_local);
1489             f(self);
1490             self.assigned_local = None;
1491         }
1492     }
1493 }
1494
1495 impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
1496     fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
1497         let Some(lhs) = self.assigned_local else {
1498             // This visitor only invokes `visit_place` for the right-hand side of an assignment
1499             // and only after setting `self.assigned_local`. However, the default impl of
1500             // `Visitor::super_body` may call `visit_place` with a `NonUseContext` for places
1501             // with debuginfo. Ignore them here.
1502             assert!(!context.is_use());
1503             return;
1504         };
1505
1506         let Some(rhs) = self.saved_local_for_direct_place(*place) else { return };
1507
1508         if !self.storage_conflicts.contains(lhs, rhs) {
1509             bug!(
1510                 "Assignment between generator saved locals whose storage is not \
1511                     marked as conflicting: {:?}: {:?} = {:?}",
1512                 location,
1513                 lhs,
1514                 rhs,
1515             );
1516         }
1517     }
1518
1519     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
1520         match &statement.kind {
1521             StatementKind::Assign(box (lhs, rhs)) => {
1522                 self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
1523             }
1524
1525             StatementKind::FakeRead(..)
1526             | StatementKind::SetDiscriminant { .. }
1527             | StatementKind::Deinit(..)
1528             | StatementKind::StorageLive(_)
1529             | StatementKind::StorageDead(_)
1530             | StatementKind::Retag(..)
1531             | StatementKind::AscribeUserType(..)
1532             | StatementKind::Coverage(..)
1533             | StatementKind::CopyNonOverlapping(..)
1534             | StatementKind::Nop => {}
1535         }
1536     }
1537
1538     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
1539         // Checking for aliasing in terminators is probably overkill, but until we have actual
1540         // semantics, we should be conservative here.
1541         match &terminator.kind {
1542             TerminatorKind::Call {
1543                 func,
1544                 args,
1545                 destination,
1546                 target: Some(_),
1547                 cleanup: _,
1548                 from_hir_call: _,
1549                 fn_span: _,
1550             } => {
1551                 self.check_assigned_place(*destination, |this| {
1552                     this.visit_operand(func, location);
1553                     for arg in args {
1554                         this.visit_operand(arg, location);
1555                     }
1556                 });
1557             }
1558
1559             TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
1560                 self.check_assigned_place(*resume_arg, |this| this.visit_operand(value, location));
1561             }
1562
1563             // FIXME: Does `asm!` have any aliasing requirements?
1564             TerminatorKind::InlineAsm { .. } => {}
1565
1566             TerminatorKind::Call { .. }
1567             | TerminatorKind::Goto { .. }
1568             | TerminatorKind::SwitchInt { .. }
1569             | TerminatorKind::Resume
1570             | TerminatorKind::Abort
1571             | TerminatorKind::Return
1572             | TerminatorKind::Unreachable
1573             | TerminatorKind::Drop { .. }
1574             | TerminatorKind::DropAndReplace { .. }
1575             | TerminatorKind::Assert { .. }
1576             | TerminatorKind::GeneratorDrop
1577             | TerminatorKind::FalseEdge { .. }
1578             | TerminatorKind::FalseUnwind { .. } => {}
1579         }
1580     }
1581 }