提交 013fc924 编写于 作者: N Niko Matsakis

remove alias analysis and replace with borrowck

This reverts commit 7ef825bb.
上级 1351117a
......@@ -1382,83 +1382,7 @@ gets access to them.
## Safe references
There is one catch with this approach: sometimes the compiler can
*not* statically guarantee that the argument value at the caller side
will survive to the end of the call. Another argument might indirectly
refer to it and be used to overwrite it, or a closure might assign a
new value to it.
Fortunately, Rust tasks are single-threaded worlds, which share no
data with other tasks, and most data is immutable. This allows most
argument-passing situations to be proved safe without further
difficulty.
Take the following program:
~~~~
# fn get_really_big_record() -> int { 1 }
# fn myfunc(a: int) {}
fn main() {
let x = get_really_big_record();
myfunc(x);
}
~~~~
Here we know for sure that no one else has access to the `x` variable
in `main`, so we're good. But the call could also look like this:
~~~~
# fn myfunc(a: int, b: fn()) {}
# fn get_another_record() -> int { 1 }
# let mut x = 1;
myfunc(x, {|| x = get_another_record(); });
~~~~
Now, if `myfunc` first calls its second argument and then accesses its
first argument, it will see a different value from the one that was
passed to it.
In such a case, the compiler will insert an implicit copy of `x`,
*except* if `x` contains something mutable, in which case a copy would
result in code that behaves differently. If copying `x` might be
expensive (for example, if it holds a vector), the compiler will emit
a warning.
There are even more tricky cases, in which the Rust compiler is forced
to pessimistically assume a value will get mutated, even though it is
not sure.
~~~~
fn for_each(v: [mut @int], iter: fn(@int)) {
for v.each {|elt| iter(elt); }
}
~~~~
For all this function knows, calling `iter` (which is a closure that
might have access to the vector that's passed as `v`) could cause the
elements in the vector to be mutated, with the effect that it can not
guarantee that the boxes will live for the duration of the call. So it
has to copy them. In this case, this will happen implicitly (bumping a
reference count is considered cheap enough to not warn about it).
## The copy operator
If the `for_each` function given above were to take a vector of
`{mut a: int}` instead of `@int`, it would not be able to
implicitly copy, since if the `iter` function changes a copy of a
mutable record, the changes won't be visible in the record itself. If
we *do* want to allow copies there, we have to explicitly allow it
with the `copy` operator:
~~~~
type mutrec = {mut x: int};
fn for_each(v: [mut mutrec], iter: fn(mutrec)) {
for v.each {|elt| iter(copy elt); }
}
~~~~
Adding a `copy` operator is also the way to muffle warnings about
implicit copies.
*This system has recently changed. An explanantion is forthcoming.*
## Other uses of safe references
......
......@@ -204,9 +204,6 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
let (root_map, mutbl_map) = time(
time_passes, "borrow checking",
bind middle::borrowck::check_crate(ty_cx, method_map, crate));
let (copy_map, _ref_map) =
time(time_passes, "alias checking",
bind middle::alias::check_crate(ty_cx, crate));
time(time_passes, "kind checking",
bind kind::check_crate(ty_cx, method_map, last_use_map, crate));
time(time_passes, "lint checking",
......@@ -216,7 +213,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
let outputs = option::get(outputs);
let maps = {mutbl_map: mutbl_map, root_map: root_map,
copy_map: copy_map, last_use_map: last_use_map,
last_use_map: last_use_map,
impl_map: impl_map, method_map: method_map,
vtable_map: vtable_map};
......@@ -448,14 +445,6 @@ fn build_session_options(match: getopts::match,
let sysroot_opt = getopts::opt_maybe_str(match, "sysroot");
let target_opt = getopts::opt_maybe_str(match, "target");
let save_temps = getopts::opt_present(match, "save-temps");
let borrowck = alt getopts::opt_maybe_str(match, "borrowck") {
none { 0u }
some("warn") { 1u }
some("err") { 2u }
some(_) {
early_error(demitter, "borrowck may be warn or err")
}
};
alt output_type {
// unless we're emitting huamn-readable assembly, omit comments.
link::output_type_llvm_assembly | link::output_type_assembly {}
......@@ -504,8 +493,7 @@ fn build_session_options(match: getopts::match,
test: test,
parse_only: parse_only,
no_trans: no_trans,
debugging_opts: debugging_opts,
borrowck: borrowck};
debugging_opts: debugging_opts};
ret sopts;
}
......@@ -582,8 +570,7 @@ fn opts() -> [getopts::opt] {
optmulti("Z"),
optmulti("cfg"), optflag("test"),
optflag("lib"), optflag("bin"), optflag("static"), optflag("gc"),
optopt("borrowck")];
optflag("lib"), optflag("bin"), optflag("static"), optflag("gc")];
}
type output_filenames = @{out_filename: str, obj_filename:str};
......
......@@ -66,9 +66,6 @@ fn debugging_opts_map() -> [(str, str, uint)] {
no_trans: bool,
debugging_opts: uint,
// temporary hack: 0=off,1=warn,2=err --> if 2, alias is disabled
borrowck: uint,
};
type crate_metadata = {name: str, data: [u8]};
......@@ -181,8 +178,7 @@ fn basic_options() -> @options {
test: false,
parse_only: false,
no_trans: false,
debugging_opts: 0u,
borrowck: 0u,
debugging_opts: 0u
}
}
......
......@@ -116,7 +116,6 @@ enum astencode_tag { // Reserves 0x50 -- 0x6f
tag_table_param_bounds,
tag_table_inferred_modes,
tag_table_mutbl,
tag_table_copy,
tag_table_last_use,
tag_table_spill,
tag_table_method_map,
......
此差异已折叠。
......@@ -52,7 +52,6 @@
type maps = {
mutbl_map: middle::borrowck::mutbl_map,
root_map: middle::borrowck::root_map,
copy_map: middle::alias::copy_map,
last_use_map: middle::liveness::last_use_map,
impl_map: middle::resolve::impl_map,
method_map: middle::typeck::method_map,
......@@ -831,12 +830,6 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
}
}
option::iter(maps.copy_map.find(id)) {|_m|
ebml_w.tag(c::tag_table_copy) {||
ebml_w.id(id);
}
}
option::iter(maps.last_use_map.find(id)) {|m|
ebml_w.tag(c::tag_table_last_use) {||
ebml_w.id(id);
......@@ -943,8 +936,6 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
if tag == (c::tag_table_mutbl as uint) {
dcx.maps.mutbl_map.insert(id, ());
} else if tag == (c::tag_table_copy as uint) {
dcx.maps.copy_map.insert(id, ());
} else {
let val_doc = entry_doc[c::tag_table_val];
let val_dsr = ebml::ebml_deserializer(val_doc);
......
......@@ -171,28 +171,12 @@
fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
crate: @ast::crate) -> (root_map, mutbl_map) {
// big hack to keep this off except when I want it on
let msg_level = if tcx.sess.opts.borrowck != 0u {
tcx.sess.opts.borrowck
} else {
os::getenv("RUST_BORROWCK").map_default(0u) { |v|
option::get(uint::from_str(v))
}
};
let bccx = @{tcx: tcx,
method_map: method_map,
msg_level: msg_level,
root_map: root_map(),
mutbl_map: int_hash()};
let req_maps = if msg_level > 0u {
gather_loans::gather_loans(bccx, crate)
} else {
{req_loan_map: int_hash(),
pure_map: int_hash()}
};
let req_maps = gather_loans::gather_loans(bccx, crate);
check_loans::check_loans(bccx, req_maps, crate);
ret (bccx.root_map, bccx.mutbl_map);
}
......@@ -202,7 +186,6 @@ fn check_crate(tcx: ty::ctxt,
type borrowck_ctxt = @{tcx: ty::ctxt,
method_map: typeck::method_map,
msg_level: uint,
root_map: root_map,
mutbl_map: mutbl_map};
......@@ -363,11 +346,7 @@ fn report(err: bckerr) {
}
fn span_err(s: span, m: str) {
if self.msg_level == 1u {
self.tcx.sess.span_warn(s, m);
} else {
self.tcx.sess.span_err(s, m);
}
self.tcx.sess.span_err(s, m);
}
fn span_note(s: span, m: str) {
......
......@@ -614,25 +614,7 @@ fn make_phi_bindings(bcx: block, map: [exit_node],
bcx.fcx.lllocals.insert(node_id, local_mem(local));
} else { success = false; }
};
if success {
// Copy references that the alias analysis considered unsafe
for ids.each_value {|node_id|
if bcx.ccx().maps.copy_map.contains_key(node_id) {
let local = alt bcx.fcx.lllocals.find(node_id) {
some(local_mem(x)) { x }
_ { bcx.tcx().sess.bug("someone \
forgot to document an invariant in \
make_phi_bindings"); }
};
let e_ty = node_id_type(bcx, node_id);
let alloc = alloc_ty(bcx, e_ty);
bcx = copy_val(bcx, INIT, alloc,
load_if_immediate(bcx, local, e_ty), e_ty);
add_clean(bcx, alloc, e_ty);
bcx.fcx.lllocals.insert(node_id, local_mem(alloc));
}
};
} else {
if !success {
Unreachable(bcx);
}
ret success;
......@@ -719,7 +701,7 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
alt pat.node {
ast::pat_ident(_,inner) {
if pat_is_variant(bcx.tcx().def_map, pat) { ret bcx; }
if make_copy || ccx.maps.copy_map.contains_key(pat.id) {
if make_copy {
let ty = node_id_type(bcx, pat.id);
let llty = type_of::type_of(ccx, ty);
let alloc = alloca(bcx, llty);
......
......@@ -2891,22 +2891,11 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
// to have type lldestty (the callee's expected type).
val = llvm::LLVMGetUndef(lldestty);
} else if arg_mode == ast::by_ref || arg_mode == ast::by_val {
let mut copied = false;
let imm = ty::type_is_immediate(arg.ty);
#debug[" arg.ty=%s, imm=%b, arg_mode=%?, lv.kind=%?",
ty_to_str(bcx.tcx(), arg.ty), imm, arg_mode, lv.kind];
if arg_mode == ast::by_ref && lv.kind != owned && imm {
val = do_spill_noroot(bcx, val);
copied = true;
}
if ccx.maps.copy_map.contains_key(e.id) && lv.kind != temporary {
if !copied {
let alloc = alloc_ty(bcx, arg.ty);
bcx = copy_val(bcx, INIT, alloc,
load_if_immediate(bcx, val, arg.ty), arg.ty);
val = alloc;
} else { bcx = take_ty(bcx, val, arg.ty); }
add_clean(bcx, val, arg.ty);
}
if arg_mode == ast::by_val && (lv.kind == owned || !imm) {
val = Load(bcx, val);
......
......@@ -78,7 +78,6 @@ mod middle {
mod loan;
mod preserve;
}
mod alias;
mod liveness;
mod block_use;
mod kind;
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
type point = { x: int, y: int };
fn a() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
type point = { x: int, y: int };
fn a() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn borrow(_v: &int) {}
fn borrow_from_arg_imm_ref(&&v: ~int) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// Note: the borrowck analysis is currently flow-insensitive.
// Therefore, some of these errors are marked as spurious and could be
// corrected by a simple change to the analysis. The others are
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn borrow(v: &int, f: fn(x: &int)) {
f(v);
}
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn take(-_v: ~int) {
}
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn borrow(v: &int, f: fn(x: &int)) {
f(v);
}
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
type point = { x: int, y: int };
impl foo for point {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
type point = { x: int, y: int };
impl foo for point {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// Here we check that it is allowed to lend out an element of a
// (locally rooted) mutable, unique vector, and that we then prevent
// modifications to the contents.
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn want_slice(v: [int]/&) -> int {
let mut sum = 0;
for vec::each(v) { |i| sum += i; }
......
enum cycle {
node({mut a: ~cycle}),
empty
}
fn main() {
let x = ~node({mut a: ~empty});
// Create a cycle!
alt check *x { //! NOTE loan of immutable local variable granted here
node(y) {
y.a <- x; //! ERROR moving out of immutable local variable prohibited due to outstanding loan
}
};
}
\ No newline at end of file
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn match_imm_box(v: &const @option<int>) -> int {
alt *v {
@some(i) {i}
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn match_ref(&&v: option<int>) -> int {
alt v {
some(i) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// xfail-pretty -- comments are infaithfully preserved
fn main() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// xfail-pretty -- comments are infaithfully preserved
fn main() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
pure fn pure_borrow(_x: &int, _y: ()) {}
fn test1(x: @mut ~int) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn impure(_i: int) {}
// check that unchecked alone does not override borrowck:
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn borrow(_v: &int) {}
fn box_mut(v: @mut ~int) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn borrow(_v: &int) {}
fn local() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn borrow(_v: &int) {}
fn box_mut(v: &mut ~int) {
......
......@@ -8,8 +8,6 @@ fn f<T>(&o: option<T>) {
fn main() {
f::<int>(option::none);
//!^ ERROR taking mut reference to static item
// Additional errors reported by borrowck:
//^^ ERROR illegal borrow unless pure: creating mutable alias to aliasable, immutable memory
//^^^ NOTE impure due to access to impure function
//!^^ ERROR illegal borrow unless pure: creating mutable alias to aliasable, immutable memory
//!^^^ NOTE impure due to access to impure function
}
\ No newline at end of file
// error-pattern:invalidate reference x
fn whoknows(x: @mut {mut x: int}) { x.x = 10; }
fn main() {
let box = @mut {mut x: 1};
alt *box { x { whoknows(box); log(error, x); } }
}
// error-pattern:may alias with argument
fn foo(x: {mut x: int}, f: fn@()) { log(debug, x); }
fn whoknows(x: @mut {mut x: int}) { *x = {mut x: 10}; }
fn main() {
let box = @mut {mut x: 1};
foo(*box, bind whoknows(box));
}
// error-pattern:invalidate reference i
enum foo { left({mut x: int}), right(bool) }
fn main() {
let mut x = left({mut x: 10});
alt x { left(i) { x = right(false); copy x; log(debug, i); } _ { } }
}
// error-pattern:mut reference to a variable that roots another reference
fn f(a: {mut x: int}, &b: {mut x: int}) -> int {
b.x += 1;
ret a.x + b.x;
}
fn main() { let i = {mut x: 4}; log(debug, f(i, i)); }
fn main() {
let x = ~{mut a: ~10, b: ~20};
alt x {
~{a, b} { assert *a == 10; (*x).a = ~30; assert *a == 10; }
~{a, b} { assert *a == 10; (*x).a = ~30; assert *a == 30; }
}
}
fn main() {
let x = @{mut a: @10, b: @20};
alt x {
@{a, b} { assert *a == 10; (*x).a = @30; assert *a == 10; }
@{a, b} { assert *a == 10; (*x).a = @30; assert *a == 30; }
}
}
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn want_slice(v: [int]/&) -> int {
let mut sum = 0;
for vec::each(v) { |i| sum += i; }
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn main() {
let mut x = none;
alt x {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn main() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn main() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn borrow(x: &int, f: fn(x: &int)) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn main() {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn borrow(x: &int, f: fn(x: &int)) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn switcher(x: option<@int>) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn borrow(x: &int, f: fn(x: &int)) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn testfn(cond: bool) {
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
// exec-env:RUST_POISON_ON_FREE=1
fn borrow(x: &int, f: fn(x: &int)) {
......
......@@ -145,7 +145,7 @@ fn main() {
intrinsic::visit_ty::<i16>(vv);
intrinsic::visit_ty::<[int]>(vv);
for v.types.each {|s|
for (copy v.types).each {|s|
io::println(#fmt("type: %s", s));
}
assert v.types == ["bool", "int", "i8", "i16",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册