about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan MacKenzie <ecstaticmorse@gmail.com>2020-01-20 15:14:24 -0800
committerDylan MacKenzie <ecstaticmorse@gmail.com>2020-02-10 13:03:08 -0800
commitce3f37b42ba25ab6fe2f401135be847a0351fbbe (patch)
tree42772fa33fb47325f0d20feb7d11d29499b2c608
parent702096da17254239d09e1095b060c083322b8ac2 (diff)
downloadrust-ce3f37b42ba25ab6fe2f401135be847a0351fbbe.tar.gz
rust-ce3f37b42ba25ab6fe2f401135be847a0351fbbe.zip
Use new dataflow interface for initialization/borrows analyses
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs88
-rw-r--r--src/librustc_mir/dataflow/impls/mod.rs215
2 files changed, 195 insertions, 108 deletions
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index f94ee67f2be..151ae28bae2 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -10,7 +10,8 @@ use crate::borrow_check::{
     places_conflict, BorrowData, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext,
     ToRegionVid,
 };
-use crate::dataflow::{BitDenotation, BottomValue, GenKillSet};
+use crate::dataflow::generic::{self, GenKill};
+use crate::dataflow::BottomValue;
 
 use std::rc::Rc;
 
@@ -172,7 +173,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     /// That means they went out of a nonlexical scope
     fn kill_loans_out_of_scope_at_location(
         &self,
-        trans: &mut GenKillSet<BorrowIndex>,
+        trans: &mut impl GenKill<BorrowIndex>,
         location: Location,
     ) {
         // NOTE: The state associated with a given `location`
@@ -187,16 +188,21 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         // region, then setting that gen-bit will override any
         // potential kill introduced here.
         if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
-            trans.kill_all(indices);
+            trans.kill_all(indices.iter().copied());
         }
     }
 
     /// Kill any borrows that conflict with `place`.
-    fn kill_borrows_on_place(&self, trans: &mut GenKillSet<BorrowIndex>, place: &Place<'tcx>) {
+    fn kill_borrows_on_place(&self, trans: &mut impl GenKill<BorrowIndex>, place: &Place<'tcx>) {
         debug!("kill_borrows_on_place: place={:?}", place);
 
-        let other_borrows_of_local =
-            self.borrow_set.local_map.get(&place.local).into_iter().flat_map(|bs| bs.into_iter());
+        let other_borrows_of_local = self
+            .borrow_set
+            .local_map
+            .get(&place.local)
+            .into_iter()
+            .flat_map(|bs| bs.into_iter())
+            .copied();
 
         // If the borrowed place is a local with no projections, all other borrows of this
         // local must conflict. This is purely an optimization so we don't have to call
@@ -212,7 +218,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         // pair of array indices are unequal, so that when `places_conflict` returns true, we
         // will be assured that two places being compared definitely denotes the same sets of
         // locations.
-        let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| {
+        let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| {
             places_conflict(
                 self.tcx,
                 self.body,
@@ -226,36 +232,41 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
+impl<'tcx> generic::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
     type Idx = BorrowIndex;
-    fn name() -> &'static str {
-        "borrows"
-    }
-    fn bits_per_block(&self) -> usize {
+
+    const NAME: &'static str = "borrows";
+
+    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
         self.borrow_set.borrows.len() * 2
     }
 
-    fn start_block_effect(&self, _entry_set: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
         // no borrows of code region_scopes have been taken prior to
         // function execution, so this method has no effect.
     }
 
-    fn before_statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
-        debug!("Borrows::before_statement_effect trans: {:?} location: {:?}", trans, location);
-        self.kill_loans_out_of_scope_at_location(trans, location);
+    fn pretty_print_idx(&self, w: &mut impl std::io::Write, idx: Self::Idx) -> std::io::Result<()> {
+        write!(w, "{:?}", self.location(idx))
     }
+}
 
-    fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
-        debug!("Borrows::statement_effect: trans={:?} location={:?}", trans, location);
-
-        let block = &self.body.basic_blocks().get(location.block).unwrap_or_else(|| {
-            panic!("could not find block at location {:?}", location);
-        });
-        let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| {
-            panic!("could not find statement at location {:?}");
-        });
+impl<'tcx> generic::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
+    fn before_statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        self.kill_loans_out_of_scope_at_location(trans, location);
+    }
 
-        debug!("Borrows::statement_effect: stmt={:?}", stmt);
+    fn statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        stmt: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
         match stmt.kind {
             mir::StatementKind::Assign(box (ref lhs, ref rhs)) => {
                 if let mir::Rvalue::Ref(_, _, ref place) = *rhs {
@@ -301,18 +312,29 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
         }
     }
 
-    fn before_terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
-        debug!("Borrows::before_terminator_effect: trans={:?} location={:?}", trans, location);
+    fn before_terminator_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
         self.kill_loans_out_of_scope_at_location(trans, location);
     }
 
-    fn terminator_effect(&self, _: &mut GenKillSet<Self::Idx>, _: Location) {}
+    fn terminator_effect(
+        &self,
+        _: &mut impl GenKill<Self::Idx>,
+        _: &mir::Terminator<'tcx>,
+        _: Location,
+    ) {
+    }
 
-    fn propagate_call_return(
+    fn call_return_effect(
         &self,
-        _in_out: &mut BitSet<BorrowIndex>,
-        _call_bb: mir::BasicBlock,
-        _dest_bb: mir::BasicBlock,
+        _trans: &mut impl GenKill<Self::Idx>,
+        _block: mir::BasicBlock,
+        _func: &mir::Operand<'tcx>,
+        _args: &[mir::Operand<'tcx>],
         _dest_place: &mir::Place<'tcx>,
     ) {
     }
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index 6b66406338d..5b2264c2a65 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -11,8 +11,9 @@ use super::MoveDataParamEnv;
 
 use crate::util::elaborate_drops::DropFlagState;
 
+use super::generic::{AnalysisDomain, GenKill, GenKillAnalysis};
 use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
-use super::{BitDenotation, BottomValue, GenKillSet};
+use super::{BottomValue, GenKillSet};
 
 use super::drop_flag_effects_for_function_entry;
 use super::drop_flag_effects_for_location;
@@ -216,6 +217,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
 /// }
 /// ```
 pub struct EverInitializedPlaces<'a, 'tcx> {
+    #[allow(dead_code)]
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
     mdpe: &'a MoveDataParamEnv<'tcx>,
@@ -235,7 +237,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> {
 
 impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
     fn update_bits(
-        trans: &mut GenKillSet<MovePathIndex>,
+        trans: &mut impl GenKill<MovePathIndex>,
         path: MovePathIndex,
         state: DropFlagState,
     ) {
@@ -248,7 +250,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
 
 impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
     fn update_bits(
-        trans: &mut GenKillSet<MovePathIndex>,
+        trans: &mut impl GenKill<MovePathIndex>,
         path: MovePathIndex,
         state: DropFlagState,
     ) {
@@ -261,7 +263,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
 
 impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
     fn update_bits(
-        trans: &mut GenKillSet<MovePathIndex>,
+        trans: &mut impl GenKill<MovePathIndex>,
         path: MovePathIndex,
         state: DropFlagState,
     ) {
@@ -272,39 +274,56 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
+impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
     type Idx = MovePathIndex;
-    fn name() -> &'static str {
-        "maybe_init"
-    }
-    fn bits_per_block(&self) -> usize {
+
+    const NAME: &'static str = "maybe_init";
+
+    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
         self.move_data().move_paths.len()
     }
 
-    fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) {
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
         drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
-            entry_set.insert(path);
+            state.insert(path);
         });
     }
 
-    fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
+    fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
+        write!(w, "{}", self.move_data().move_paths[mpi])
+    }
+}
+
+impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
+    fn statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
 
-    fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
+    fn terminator_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
 
-    fn propagate_call_return(
+    fn call_return_effect(
         &self,
-        in_out: &mut BitSet<MovePathIndex>,
-        _call_bb: mir::BasicBlock,
-        _dest_bb: mir::BasicBlock,
+        trans: &mut impl GenKill<Self::Idx>,
+        _block: mir::BasicBlock,
+        _func: &mir::Operand<'tcx>,
+        _args: &[mir::Operand<'tcx>],
         dest_place: &mir::Place<'tcx>,
     ) {
         // when a call returns successfully, that means we need to set
@@ -315,50 +334,67 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
             self.move_data(),
             self.move_data().rev_lookup.find(dest_place.as_ref()),
             |mpi| {
-                in_out.insert(mpi);
+                trans.gen(mpi);
             },
         );
     }
 }
 
-impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> {
+impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
     type Idx = MovePathIndex;
-    fn name() -> &'static str {
-        "maybe_uninit"
-    }
-    fn bits_per_block(&self) -> usize {
+
+    const NAME: &'static str = "maybe_uninit";
+
+    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
         self.move_data().move_paths.len()
     }
 
     // sets on_entry bits for Arg places
-    fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
         // set all bits to 1 (uninit) before gathering counterevidence
-        assert!(self.bits_per_block() == entry_set.domain_size());
-        entry_set.insert_all();
+        assert!(self.bits_per_block(body) == state.domain_size());
+        state.insert_all();
 
         drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
-            entry_set.remove(path);
+            state.remove(path);
         });
     }
 
-    fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
+    fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
+        write!(w, "{}", self.move_data().move_paths[mpi])
+    }
+}
+
+impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
+    fn statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
 
-    fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
+    fn terminator_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
 
-    fn propagate_call_return(
+    fn call_return_effect(
         &self,
-        in_out: &mut BitSet<MovePathIndex>,
-        _call_bb: mir::BasicBlock,
-        _dest_bb: mir::BasicBlock,
+        trans: &mut impl GenKill<Self::Idx>,
+        _block: mir::BasicBlock,
+        _func: &mir::Operand<'tcx>,
+        _args: &[mir::Operand<'tcx>],
         dest_place: &mir::Place<'tcx>,
     ) {
         // when a call returns successfully, that means we need to set
@@ -369,48 +405,65 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> {
             self.move_data(),
             self.move_data().rev_lookup.find(dest_place.as_ref()),
             |mpi| {
-                in_out.remove(mpi);
+                trans.kill(mpi);
             },
         );
     }
 }
 
-impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
+impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
     type Idx = MovePathIndex;
-    fn name() -> &'static str {
-        "definite_init"
-    }
-    fn bits_per_block(&self) -> usize {
+
+    const NAME: &'static str = "definite_init";
+
+    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
         self.move_data().move_paths.len()
     }
 
     // sets on_entry bits for Arg places
-    fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) {
-        entry_set.clear();
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+        state.clear();
 
         drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
-            entry_set.insert(path);
+            state.insert(path);
         });
     }
 
-    fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
+    fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
+        write!(w, "{}", self.move_data().move_paths[mpi])
+    }
+}
+
+impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
+    fn statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
 
-    fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
+    fn terminator_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
 
-    fn propagate_call_return(
+    fn call_return_effect(
         &self,
-        in_out: &mut BitSet<MovePathIndex>,
-        _call_bb: mir::BasicBlock,
-        _dest_bb: mir::BasicBlock,
+        trans: &mut impl GenKill<Self::Idx>,
+        _block: mir::BasicBlock,
+        _func: &mir::Operand<'tcx>,
+        _args: &[mir::Operand<'tcx>],
         dest_place: &mir::Place<'tcx>,
     ) {
         // when a call returns successfully, that means we need to set
@@ -421,30 +474,36 @@ impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
             self.move_data(),
             self.move_data().rev_lookup.find(dest_place.as_ref()),
             |mpi| {
-                in_out.insert(mpi);
+                trans.gen(mpi);
             },
         );
     }
 }
 
-impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
+impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
     type Idx = InitIndex;
-    fn name() -> &'static str {
-        "ever_init"
-    }
-    fn bits_per_block(&self) -> usize {
+
+    const NAME: &'static str = "ever_init";
+
+    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
         self.move_data().inits.len()
     }
 
-    fn start_block_effect(&self, entry_set: &mut BitSet<InitIndex>) {
-        for arg_init in 0..self.body.arg_count {
-            entry_set.insert(InitIndex::new(arg_init));
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+        for arg_init in 0..body.arg_count {
+            state.insert(InitIndex::new(arg_init));
         }
     }
+}
 
-    fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
-        let (_, body, move_data) = (self.tcx, self.body, self.move_data());
-        let stmt = &body[location.block].statements[location.statement_index];
+impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
+    fn statement_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        stmt: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        let move_data = self.move_data();
         let init_path_map = &move_data.init_path_map;
         let init_loc_map = &move_data.init_loc_map;
         let rev_lookup = &move_data.rev_lookup;
@@ -453,7 +512,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
             "statement {:?} at loc {:?} initializes move_indexes {:?}",
             stmt, location, &init_loc_map[location]
         );
-        trans.gen_all(&init_loc_map[location]);
+        trans.gen_all(init_loc_map[location].iter().copied());
 
         match stmt.kind {
             mir::StatementKind::StorageDead(local) => {
@@ -464,13 +523,18 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
                     "stmt {:?} at loc {:?} clears the ever initialized status of {:?}",
                     stmt, location, &init_path_map[move_path_index]
                 );
-                trans.kill_all(&init_path_map[move_path_index]);
+                trans.kill_all(init_path_map[move_path_index].iter().copied());
             }
             _ => {}
         }
     }
 
-    fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) {
+    fn terminator_effect(
+        &self,
+        trans: &mut impl GenKill<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
         let (body, move_data) = (self.body, self.move_data());
         let term = body[location.block].terminator();
         let init_loc_map = &move_data.init_loc_map;
@@ -479,28 +543,29 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> {
             term, location, &init_loc_map[location]
         );
         trans.gen_all(
-            init_loc_map[location].iter().filter(|init_index| {
-                move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly
-            }),
+            init_loc_map[location]
+                .iter()
+                .filter(|init_index| {
+                    move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly
+                })
+                .copied(),
         );
     }
 
-    fn propagate_call_return(
+    fn call_return_effect(
         &self,
-        in_out: &mut BitSet<InitIndex>,
-        call_bb: mir::BasicBlock,
-        _dest_bb: mir::BasicBlock,
+        trans: &mut impl GenKill<Self::Idx>,
+        block: mir::BasicBlock,
+        _func: &mir::Operand<'tcx>,
+        _args: &[mir::Operand<'tcx>],
         _dest_place: &mir::Place<'tcx>,
     ) {
         let move_data = self.move_data();
-        let bits_per_block = self.bits_per_block();
         let init_loc_map = &move_data.init_loc_map;
 
-        let call_loc =
-            Location { block: call_bb, statement_index: self.body[call_bb].statements.len() };
+        let call_loc = self.body.terminator_loc(block);
         for init_index in &init_loc_map[call_loc] {
-            assert!(init_index.index() < bits_per_block);
-            in_out.insert(*init_index);
+            trans.gen(*init_index);
         }
     }
 }