Skip to content

Commit

Permalink
rustc and rustc::borrowck: pass fragment info down into trans.
Browse files Browse the repository at this point in the history
  • Loading branch information
pnkfelix committed Jul 28, 2015
1 parent a0f3f2a commit d3d552b
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 4 deletions.
39 changes: 39 additions & 0 deletions src/librustc/middle/ty.rs
Expand Up @@ -957,6 +957,44 @@ pub struct ctxt<'tcx> {
/// Maps a cast expression to its kind. This is keyed on the
/// *from* expression of the cast, not the cast itself.
pub cast_kinds: RefCell<NodeMap<cast::CastKind>>,

/// Maps Fn items to a collection of fragment infos.
///
/// The main goal is to identify data (each of which may be moved
/// or assigned) whose subparts are not moved nor assigned
/// (i.e. their state is *unfragmented*) and corresponding ast
/// nodes where the path to that data is moved or assigned.
///
/// In the long term, unfragmented values will have their
/// destructor entirely driven by a single stack-local drop-flag,
/// and their parents, the collections of the unfragmented values
/// (or more simply, "fragmented values"), are mapped to the
/// corresponding collections of stack-local drop-flags.
///
/// (However, in the short term that is not the case; e.g. some
/// unfragmented paths still need to be zeroed, namely when they
/// reference parent data from an outer scope that was not
/// entirely moved, and therefore that needs to be zeroed so that
/// we do not get double-drop when we hit the end of the parent
/// scope.)
///
/// Also: currently the table solely holds keys for node-ids of
/// unfragmented values (see `FragmentInfo` enum definition), but
/// longer-term we will need to also store mappings from
/// fragmented data to the set of unfragmented pieces that
/// constitute it.
pub fragment_infos: RefCell<DefIdMap<Vec<FragmentInfo>>>,
}

/// Describes the fragment-state associated with a NodeId.
///
/// Currently only unfragmented paths have entries in the table,
/// but longer-term this enum is expected to expand to also
/// include data for fragmented paths.
#[derive(Copy, Clone, Debug)]
pub enum FragmentInfo {
Moved { var: NodeId, move_expr: NodeId },
Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId },
}

impl<'tcx> ctxt<'tcx> {
Expand Down Expand Up @@ -3498,6 +3536,7 @@ impl<'tcx> ctxt<'tcx> {
const_qualif_map: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap()),
}, f)
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_borrowck/borrowck/check_loans.rs
Expand Up @@ -86,7 +86,7 @@ fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Rc<LoanPath<'
struct CheckLoanCtxt<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
move_data: move_data::FlowedMoveData<'a, 'tcx>,
move_data: &'a move_data::FlowedMoveData<'a, 'tcx>,
all_loans: &'a [Loan<'tcx>],
param_env: &'a ty::ParameterEnvironment<'a, 'tcx>,
}
Expand Down Expand Up @@ -191,7 +191,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {

pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
dfcx_loans: &LoanDataFlow<'b, 'tcx>,
move_data: move_data::FlowedMoveData<'c, 'tcx>,
move_data: &move_data::FlowedMoveData<'c, 'tcx>,
all_loans: &[Loan<'tcx>],
fn_id: ast::NodeId,
decl: &ast::FnDecl,
Expand Down
88 changes: 87 additions & 1 deletion src/librustc_borrowck/borrowck/fragments.rs
Expand Up @@ -15,7 +15,7 @@
use self::Fragment::*;

use borrowck::InteriorKind::{InteriorField, InteriorElement};
use borrowck::LoanPath;
use borrowck::{self, LoanPath};
use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend};
use borrowck::LoanPathElem::{LpDeref, LpInterior};
use borrowck::move_data::InvalidMovePathIndex;
Expand Down Expand Up @@ -59,6 +59,84 @@ impl Fragment {
}
}

pub fn build_unfragmented_map(this: &mut borrowck::BorrowckCtxt,
move_data: &MoveData,
id: ast::NodeId) {
let fr = &move_data.fragments.borrow();

// For now, don't care about other kinds of fragments; the precise
// classfication of all paths for non-zeroing *drop* needs them,
// but the loose approximation used by non-zeroing moves does not.
let moved_leaf_paths = fr.moved_leaf_paths();
let assigned_leaf_paths = fr.assigned_leaf_paths();

let mut fragment_infos = Vec::with_capacity(moved_leaf_paths.len());

let find_var_id = |move_path_index: MovePathIndex| -> Option<ast::NodeId> {
let lp = move_data.path_loan_path(move_path_index);
match lp.kind {
LpVar(var_id) => Some(var_id),
LpUpvar(ty::UpvarId { var_id, closure_expr_id }) => {
// The `var_id` is unique *relative to* the current function.
// (Check that we are indeed talking about the same function.)
assert_eq!(id, closure_expr_id);
Some(var_id)
}
LpDowncast(..) | LpExtend(..) => {
// This simple implementation of non-zeroing move does
// not attempt to deal with tracking substructure
// accurately in the general case.
None
}
}
};

let moves = move_data.moves.borrow();
for &move_path_index in moved_leaf_paths {
let var_id = match find_var_id(move_path_index) {
None => continue,
Some(var_id) => var_id,
};

move_data.each_applicable_move(move_path_index, |move_index| {
let info = ty::FragmentInfo::Moved {
var: var_id,
move_expr: moves[move_index.get()].id,
};
debug!("fragment_infos push({:?} \
due to move_path_index: {} move_index: {}",
info, move_path_index.get(), move_index.get());
fragment_infos.push(info);
true
});
}

for &move_path_index in assigned_leaf_paths {
let var_id = match find_var_id(move_path_index) {
None => continue,
Some(var_id) => var_id,
};

let var_assigns = move_data.var_assignments.borrow();
for var_assign in var_assigns.iter()
.filter(|&assign| assign.path == move_path_index)
{
let info = ty::FragmentInfo::Assigned {
var: var_id,
assign_expr: var_assign.id,
assignee_id: var_assign.assignee_id,
};
debug!("fragment_infos push({:?} due to var_assignment", info);
fragment_infos.push(info);
}
}

let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut();
let fn_did = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
let prev = fraginfo_map.insert(fn_did, fragment_infos);
assert!(prev.is_none());
}

pub struct FragmentSets {
/// During move_data construction, `moved_leaf_paths` tracks paths
/// that have been used directly by being moved out of. When
Expand Down Expand Up @@ -103,6 +181,14 @@ impl FragmentSets {
}
}

pub fn moved_leaf_paths(&self) -> &[MovePathIndex] {
&self.moved_leaf_paths
}

pub fn assigned_leaf_paths(&self) -> &[MovePathIndex] {
&self.assigned_leaf_paths
}

pub fn add_move(&mut self, path_index: MovePathIndex) {
self.moved_leaf_paths.push(path_index);
}
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_borrowck/borrowck/mod.rs
Expand Up @@ -169,12 +169,16 @@ fn borrowck_fn(this: &mut BorrowckCtxt,

check_loans::check_loans(this,
&loan_dfcx,
flowed_moves,
&flowed_moves,
&all_loans[..],
id,
decl,
body);

move_data::fragments::build_unfragmented_map(this,
&flowed_moves.move_data,
id);

visit::walk_fn(this, fk, decl, body, sp);
}

Expand Down
4 changes: 4 additions & 0 deletions src/librustc_borrowck/borrowck/move_data.rs
Expand Up @@ -159,6 +159,9 @@ pub struct Assignment {

/// span of node where assignment occurs
pub span: Span,

/// id for l-value expression on lhs of assignment
pub assignee_id: ast::NodeId,
}

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -412,6 +415,7 @@ impl<'tcx> MoveData<'tcx> {
path: path_index,
id: assign_id,
span: span,
assignee_id: assignee_id,
};

if self.is_var_path(path_index) {
Expand Down

0 comments on commit d3d552b

Please sign in to comment.