Skip to content

Commit

Permalink
auto merge of #13724 : nikomatsakis/rust/expr-use-visitor, r=pnkfelix
Browse files Browse the repository at this point in the history
Pre-step towards issue #12624 and others: Introduce ExprUseVisitor, remove the
moves computation. ExprUseVisitor is a visitor that walks the AST for a
function and calls a delegate to inform it where borrows, copies, and moves
occur.

In this patch, I rewrite the gather_loans visitor to use ExprUseVisitor, but in
future patches, I think we could rewrite regionck, check_loans, and possibly
other passes to use it as well. This would refactor the repeated code between
those places that tries to determine where copies/moves/etc occur.

r? @alexcrichton
  • Loading branch information
bors committed May 1, 2014
2 parents 5c0abea + b9af043 commit 239557d
Show file tree
Hide file tree
Showing 29 changed files with 1,265 additions and 1,631 deletions.
4 changes: 2 additions & 2 deletions src/librustc/back/rpath.rs
Expand Up @@ -133,7 +133,7 @@ pub fn get_rpath_relative_to_output(os: abi::Os,
}

pub fn get_install_prefix_rpath(sysroot: &Path, target_triple: &str) -> ~str {
let install_prefix = env!("CFG_PREFIX");
let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");

let tlib = filesearch::relative_target_lib_path(sysroot, target_triple);
let mut path = Path::new(install_prefix);
Expand Down Expand Up @@ -171,7 +171,7 @@ mod test {
fn test_prefix_rpath() {
let sysroot = filesearch::get_or_default_sysroot();
let res = get_install_prefix_rpath(&sysroot, "triple");
let mut d = Path::new(env!("CFG_PREFIX"));
let mut d = Path::new((option_env!("CFG_PREFIX")).expect("CFG_PREFIX"));
d.push("lib");
d.push(filesearch::rustlibdir());
d.push("triple/lib");
Expand Down
23 changes: 6 additions & 17 deletions src/librustc/driver/driver.rs
Expand Up @@ -23,7 +23,7 @@ use metadata::{creader, filesearch};
use metadata::cstore::CStore;
use metadata::creader::Loader;
use metadata;
use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
use middle;
use util::common::time;
use util::ppaux;
Expand All @@ -35,7 +35,6 @@ use std::cell::{Cell, RefCell};
use std::io;
use std::io::fs;
use std::io::MemReader;
use std::mem::drop;
use std::os;
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
Expand Down Expand Up @@ -278,7 +277,6 @@ pub struct CrateAnalysis {
pub exported_items: middle::privacy::ExportedItems,
pub public_items: middle::privacy::PublicItems,
pub ty_cx: ty::ctxt,
pub maps: astencode::Maps,
pub reachable: NodeSet,
}

Expand Down Expand Up @@ -354,21 +352,14 @@ pub fn phase_3_run_analysis_passes(sess: Session,
time(time_passes, "effect checking", (), |_|
middle::effect::check_crate(&ty_cx, krate));

let middle::moves::MoveMaps {moves_map, capture_map} =
time(time_passes, "compute moves", (), |_|
middle::moves::compute_moves(&ty_cx, krate));

time(time_passes, "match checking", (), |_|
middle::check_match::check_crate(&ty_cx, &moves_map, krate));
middle::check_match::check_crate(&ty_cx, krate));

time(time_passes, "liveness checking", (), |_|
middle::liveness::check_crate(&ty_cx, &capture_map, krate));
middle::liveness::check_crate(&ty_cx, krate));

time(time_passes, "borrow checking", (), |_|
middle::borrowck::check_crate(&ty_cx, &moves_map,
&capture_map, krate));

drop(moves_map);
middle::borrowck::check_crate(&ty_cx, krate));

time(time_passes, "kind checking", (), |_|
kind::check_crate(&ty_cx, krate));
Expand All @@ -392,9 +383,6 @@ pub fn phase_3_run_analysis_passes(sess: Session,
ty_cx: ty_cx,
exported_items: exported_items,
public_items: public_items,
maps: astencode::Maps {
capture_map: RefCell::new(capture_map)
},
reachable: reachable_map
}
}
Expand Down Expand Up @@ -810,7 +798,8 @@ pub fn host_triple() -> &'static str {
// Instead of grabbing the host triple (for the current host), we grab (at
// compile time) the target triple that this rustc is built with and
// calling that (at runtime) the host triple.
env!("CFG_COMPILER_HOST_TRIPLE")
(option_env!("CFG_COMPILER_HOST_TRIPLE")).
expect("CFG_COMPILER_HOST_TRIPLE")
}

pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/lib.rs
Expand Up @@ -86,13 +86,13 @@ pub mod middle {
pub mod astencode;
pub mod lang_items;
pub mod privacy;
pub mod moves;
pub mod entry;
pub mod effect;
pub mod reachable;
pub mod graph;
pub mod cfg;
pub mod dead;
pub mod expr_use_visitor;
}

pub mod front {
Expand Down
69 changes: 4 additions & 65 deletions src/librustc/middle/astencode.rs
Expand Up @@ -24,8 +24,7 @@ use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter};
use metadata::tyencode;
use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
use middle::{ty, typeck, moves};
use middle;
use middle::{ty, typeck};
use util::ppaux::ty_to_str;

use syntax::{ast, ast_map, ast_util, codemap, fold};
Expand All @@ -36,7 +35,6 @@ use syntax;

use libc;
use std::cast;
use std::cell::RefCell;
use std::io::Seek;
use std::io::MemWriter;
use std::rc::Rc;
Expand All @@ -52,15 +50,9 @@ use writer = serialize::ebml::writer;
#[cfg(test)] use syntax::parse;
#[cfg(test)] use syntax::print::pprust;

// Auxiliary maps of things to be encoded
pub struct Maps {
pub capture_map: RefCell<middle::moves::CaptureMap>,
}

struct DecodeContext<'a> {
cdata: &'a cstore::crate_metadata,
tcx: &'a ty::ctxt,
maps: &'a Maps
}

struct ExtendedDecodeContext<'a> {
Expand All @@ -84,8 +76,7 @@ pub type Encoder<'a> = writer::Encoder<'a, MemWriter>;

pub fn encode_inlined_item(ecx: &e::EncodeContext,
ebml_w: &mut Encoder,
ii: e::InlinedItemRef,
maps: &Maps) {
ii: e::InlinedItemRef) {
let id = match ii {
e::IIItemRef(i) => i.id,
e::IIForeignRef(i) => i.id,
Expand All @@ -101,7 +92,7 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
ebml_w.start_tag(c::tag_ast as uint);
id_range.encode(ebml_w);
encode_ast(ebml_w, ii);
encode_side_tables_for_ii(ecx, maps, ebml_w, &ii);
encode_side_tables_for_ii(ecx, ebml_w, &ii);
ebml_w.end_tag();

debug!("< Encoded inlined fn: {} ({})",
Expand All @@ -111,14 +102,12 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,

pub fn decode_inlined_item(cdata: &cstore::crate_metadata,
tcx: &ty::ctxt,
maps: &Maps,
path: Vec<ast_map::PathElem>,
par_doc: ebml::Doc)
-> Result<ast::InlinedItem, Vec<ast_map::PathElem>> {
let dcx = &DecodeContext {
cdata: cdata,
tcx: tcx,
maps: maps
};
match par_doc.opt_child(c::tag_ast) {
None => Err(path),
Expand Down Expand Up @@ -551,32 +540,6 @@ impl tr for freevar_entry {
}
}

// ______________________________________________________________________
// Encoding and decoding of CaptureVar information

trait capture_var_helper {
fn read_capture_var(&mut self, xcx: &ExtendedDecodeContext)
-> moves::CaptureVar;
}

impl<'a> capture_var_helper for reader::Decoder<'a> {
fn read_capture_var(&mut self, xcx: &ExtendedDecodeContext)
-> moves::CaptureVar {
let cvar: moves::CaptureVar = Decodable::decode(self).unwrap();
cvar.tr(xcx)
}
}

impl tr for moves::CaptureVar {
fn tr(&self, xcx: &ExtendedDecodeContext) -> moves::CaptureVar {
moves::CaptureVar {
def: self.def.tr(xcx),
span: self.span.tr(xcx),
mode: self.mode
}
}
}

// ______________________________________________________________________
// Encoding and decoding of MethodCallee

Expand Down Expand Up @@ -935,7 +898,6 @@ impl<'a> write_tag_and_id for Encoder<'a> {
struct SideTableEncodingIdVisitor<'a,'b> {
ecx_ptr: *libc::c_void,
new_ebml_w: &'a mut Encoder<'b>,
maps: &'a Maps,
}

impl<'a,'b> ast_util::IdVisitingOperation for
Expand All @@ -953,12 +915,11 @@ impl<'a,'b> ast_util::IdVisitingOperation for
let ecx: &e::EncodeContext = unsafe {
cast::transmute(self.ecx_ptr)
};
encode_side_tables_for_id(ecx, self.maps, &mut new_ebml_w, id)
encode_side_tables_for_id(ecx, &mut new_ebml_w, id)
}
}

fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
maps: &Maps,
ebml_w: &mut Encoder,
ii: &ast::InlinedItem) {
ebml_w.start_tag(c::tag_table as uint);
Expand All @@ -974,13 +935,11 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
cast::transmute(ecx)
},
new_ebml_w: &mut new_ebml_w,
maps: maps,
});
ebml_w.end_tag();
}

fn encode_side_tables_for_id(ecx: &e::EncodeContext,
maps: &Maps,
ebml_w: &mut Encoder,
id: ast::NodeId) {
let tcx = ecx.tcx;
Expand Down Expand Up @@ -1096,17 +1055,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
})
})
}

for &cap_vars in maps.capture_map.borrow().find(&id).iter() {
ebml_w.tag(c::tag_table_capture_map, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
ebml_w.emit_from_vec(cap_vars.as_slice(), |ebml_w, cap_var| {
cap_var.encode(ebml_w)
});
})
})
}
}

trait doc_decoder_helpers {
Expand Down Expand Up @@ -1405,15 +1353,6 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx);
dcx.tcx.adjustments.borrow_mut().insert(id, adj);
}
c::tag_table_capture_map => {
let cvars =
val_dsr.read_to_vec(
|val_dsr| Ok(val_dsr.read_capture_var(xcx)))
.unwrap()
.move_iter()
.collect();
dcx.maps.capture_map.borrow_mut().insert(id, Rc::new(cvars));
}
_ => {
xcx.dcx.tcx.sess.bug(
format!("unknown tag found in side tables: {:x}", tag));
Expand Down
41 changes: 25 additions & 16 deletions src/librustc/middle/borrowck/check_loans.rs
Expand Up @@ -18,9 +18,10 @@
// 4. moves do not affect things loaned out in any way


use mc = middle::mem_categorization;
use middle::borrowck::*;
use middle::moves;
use euv = middle::expr_use_visitor;
use middle::freevars;
use mc = middle::mem_categorization;
use middle::ty;
use middle::typeck::MethodCall;
use syntax::ast;
Expand Down Expand Up @@ -288,7 +289,7 @@ impl<'a> CheckLoanCtxt<'a> {
}

match new_loan.cause {
ClosureCapture(span) => {
euv::ClosureCapture(span) => {
self.bccx.span_note(
span,
format!("borrow occurs due to use of `{}` in closure",
Expand Down Expand Up @@ -321,13 +322,17 @@ impl<'a> CheckLoanCtxt<'a> {
};

let borrow_summary = match old_loan.cause {
ClosureCapture(_) => {
euv::ClosureCapture(_) => {
format!("previous borrow of `{}` occurs here due to \
use in closure",
self.bccx.loan_path_to_str(&*old_loan.loan_path))
}

AddrOf | AutoRef | RefBinding | ClosureInvocation => {
euv::OverloadedOperator(..) |
euv::AddrOf(..) |
euv::AutoRef(..) |
euv::ClosureInvocation(..) |
euv::RefBinding(..) => {
format!("previous borrow of `{}` occurs here",
self.bccx.loan_path_to_str(&*old_loan.loan_path))
}
Expand Down Expand Up @@ -711,29 +716,33 @@ impl<'a> CheckLoanCtxt<'a> {
fn check_captured_variables(&self,
closure_id: ast::NodeId,
span: Span) {
for cap_var in self.bccx.capture_map.get(&closure_id).iter() {
let var_id = ast_util::def_id_of_def(cap_var.def).node;
self.check_if_path_is_moved(closure_id, span,
MovedInCapture, &Rc::new(LpVar(var_id)));
match cap_var.mode {
moves::CapRef | moves::CapCopy => {}
moves::CapMove => {
check_by_move_capture(self, closure_id, cap_var, &LpVar(var_id));
let freevar_mode = freevars::get_capture_mode(self.tcx(), closure_id);
freevars::with_freevars(self.tcx(), closure_id, |freevars| {
for freevar in freevars.iter() {
let var_id = ast_util::def_id_of_def(freevar.def).node;
let var_path = Rc::new(LpVar(var_id));
self.check_if_path_is_moved(closure_id, span,
MovedInCapture, &var_path);
match freevar_mode {
freevars::CaptureByRef => { }
freevars::CaptureByValue => {
check_by_move_capture(self, closure_id, freevar, &*var_path);
}
}
}
}
});
return;

fn check_by_move_capture(this: &CheckLoanCtxt,
closure_id: ast::NodeId,
cap_var: &moves::CaptureVar,
freevar: &freevars::freevar_entry,
move_path: &LoanPath) {
let move_err = this.analyze_move_out_from(closure_id, move_path);
match move_err {
MoveOk => {}
MoveWhileBorrowed(loan_path, loan_span) => {
this.bccx.span_err(
cap_var.span,
freevar.span,
format!("cannot move `{}` into closure \
because it is borrowed",
this.bccx.loan_path_to_str(move_path)));
Expand Down

0 comments on commit 239557d

Please sign in to comment.