// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Manages the dataflow bits required for borrowck. //! //! FIXME: this might be better as a "generic" fixed-point combinator, //! but is not as ugly as it is right now. use rustc::mir::{BasicBlock, Location}; use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use dataflow::{EverInitializedLvals, MovingOutStatements}; use dataflow::{ActiveBorrows, FlowAtLocation, FlowsAtLocation}; use dataflow::move_paths::HasMoveData; use std::fmt; // (forced to be `pub` due to its use as an associated type below.) pub(crate) struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> { pub borrows: FlowAtLocation>, pub inits: FlowAtLocation>, pub uninits: FlowAtLocation>, pub move_outs: FlowAtLocation>, pub ever_inits: FlowAtLocation>, } impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> { pub fn new( borrows: FlowAtLocation>, inits: FlowAtLocation>, uninits: FlowAtLocation>, move_outs: FlowAtLocation>, ever_inits: FlowAtLocation>, ) -> Self { Flows { borrows, inits, uninits, move_outs, ever_inits, } } } macro_rules! each_flow { ($this:ident, $meth:ident($arg:ident)) => { FlowAtLocation::$meth(&mut $this.borrows, $arg); FlowAtLocation::$meth(&mut $this.inits, $arg); FlowAtLocation::$meth(&mut $this.uninits, $arg); FlowAtLocation::$meth(&mut $this.move_outs, $arg); FlowAtLocation::$meth(&mut $this.ever_inits, $arg); } } impl<'b, 'gcx, 'tcx> FlowsAtLocation for Flows<'b, 'gcx, 'tcx> { fn reset_to_entry_of(&mut self, bb: BasicBlock) { each_flow!(self, reset_to_entry_of(bb)); } fn reconstruct_statement_effect(&mut self, location: Location) { each_flow!(self, reconstruct_statement_effect(location)); } fn reconstruct_terminator_effect(&mut self, location: Location) { each_flow!(self, reconstruct_terminator_effect(location)); } fn apply_local_effect(&mut self, location: Location) { each_flow!(self, apply_local_effect(location)); } } impl<'b, 'gcx, 'tcx> fmt::Display for Flows<'b, 'gcx, 'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut s = String::new(); s.push_str("borrows in effect: ["); let mut saw_one = false; self.borrows.each_state_bit(|borrow| { if saw_one { s.push_str(", "); }; saw_one = true; let borrow_data = &self.borrows.operator().borrows()[borrow.borrow_index()]; s.push_str(&format!("{}", borrow_data)); }); s.push_str("] "); s.push_str("borrows generated: ["); let mut saw_one = false; self.borrows.each_gen_bit(|borrow| { if saw_one { s.push_str(", "); }; saw_one = true; let borrow_data = &self.borrows.operator().borrows()[borrow.borrow_index()]; s.push_str(&format!("{}", borrow_data)); }); s.push_str("] "); s.push_str("inits: ["); let mut saw_one = false; self.inits.each_state_bit(|mpi_init| { if saw_one { s.push_str(", "); }; saw_one = true; let move_path = &self.inits.operator().move_data().move_paths[mpi_init]; s.push_str(&format!("{}", move_path)); }); s.push_str("] "); s.push_str("uninits: ["); let mut saw_one = false; self.uninits.each_state_bit(|mpi_uninit| { if saw_one { s.push_str(", "); }; saw_one = true; let move_path = &self.uninits.operator().move_data().move_paths[mpi_uninit]; s.push_str(&format!("{}", move_path)); }); s.push_str("] "); s.push_str("move_out: ["); let mut saw_one = false; self.move_outs.each_state_bit(|mpi_move_out| { if saw_one { s.push_str(", "); }; saw_one = true; let move_out = &self.move_outs.operator().move_data().moves[mpi_move_out]; s.push_str(&format!("{:?}", move_out)); }); s.push_str("] "); s.push_str("ever_init: ["); let mut saw_one = false; self.ever_inits.each_state_bit(|mpi_ever_init| { if saw_one { s.push_str(", "); }; saw_one = true; let ever_init = &self.ever_inits.operator().move_data().inits[mpi_ever_init]; s.push_str(&format!("{:?}", ever_init)); }); s.push_str("]"); fmt::Display::fmt(&s, fmt) } }