2011-06-15 11:19:50 -07:00
|
|
|
|
2011-07-05 11:48:19 +02:00
|
|
|
import syntax::ast;
|
2011-08-21 21:44:41 -07:00
|
|
|
import syntax::ast_util;
|
2011-07-05 11:48:19 +02:00
|
|
|
import ast::ident;
|
|
|
|
import ast::fn_ident;
|
|
|
|
import ast::node_id;
|
|
|
|
import ast::def_id;
|
2011-08-31 18:45:37 +02:00
|
|
|
import mut::{expr_root, mut_field, inner_mut};
|
2011-07-05 11:48:19 +02:00
|
|
|
import syntax::codemap::span;
|
|
|
|
import syntax::visit;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
import visit::vt;
|
2011-08-15 16:38:23 -07:00
|
|
|
import std::vec;
|
2011-09-01 17:27:58 -07:00
|
|
|
import std::str;
|
2011-06-06 15:22:13 +02:00
|
|
|
import std::option;
|
|
|
|
import std::option::some;
|
|
|
|
import std::option::none;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
import std::option::is_none;
|
2011-06-06 15:22:13 +02:00
|
|
|
|
2011-06-15 12:17:37 +02:00
|
|
|
// This is not an alias-analyser (though it would merit from becoming one, or
|
2011-07-07 10:21:14 +02:00
|
|
|
// getting input from one, to be more precise). It is a pass that checks
|
2011-09-01 22:37:52 +02:00
|
|
|
// whether aliases are used in a safe way.
|
2011-07-07 10:21:14 +02:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
tag valid { valid; overwritten(span, ast::path); val_taken(span, ast::path); }
|
2011-06-15 12:17:37 +02:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type restrict =
|
2011-08-31 18:27:53 +02:00
|
|
|
@{root_var: option::t<node_id>,
|
2011-09-07 15:13:19 +02:00
|
|
|
node_id: node_id,
|
|
|
|
ty: ty::t,
|
2011-08-30 17:03:00 +02:00
|
|
|
local_id: uint,
|
2011-08-04 16:20:09 -07:00
|
|
|
bindings: [node_id],
|
2011-08-31 18:27:53 +02:00
|
|
|
unsafe_ty: option::t<ty::t>,
|
2011-08-04 16:20:09 -07:00
|
|
|
depends_on: [uint],
|
2011-09-07 15:13:19 +02:00
|
|
|
mutable ok: valid,
|
|
|
|
mutable given_up: bool};
|
2011-06-06 15:22:13 +02:00
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
type scope = @[restrict];
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
tag local_info { local(uint); }
|
2011-06-10 12:03:50 +02:00
|
|
|
|
2011-09-07 15:13:19 +02:00
|
|
|
type copy_map = std::map::hashmap<node_id, ()>;
|
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
type ctx =
|
|
|
|
{tcx: ty::ctxt,
|
|
|
|
local_map: std::map::hashmap<node_id, local_info>,
|
2011-09-07 15:13:19 +02:00
|
|
|
mutable next_local: uint,
|
|
|
|
copy_map: copy_map};
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> copy_map {
|
2011-07-27 14:48:34 +02:00
|
|
|
// Stores information about object fields and function
|
|
|
|
// arguments that's otherwise not easily available.
|
2011-09-02 15:34:58 -07:00
|
|
|
let cx =
|
|
|
|
@{tcx: tcx,
|
|
|
|
local_map: std::map::new_int_hash(),
|
2011-09-07 15:13:19 +02:00
|
|
|
mutable next_local: 0u,
|
|
|
|
copy_map: std::map::new_int_hash()};
|
2011-09-02 15:34:58 -07:00
|
|
|
let v =
|
|
|
|
@{visit_fn: visit_fn,
|
|
|
|
visit_expr: bind visit_expr(cx, _, _, _),
|
|
|
|
visit_decl: bind visit_decl(cx, _, _, _)
|
|
|
|
with *visit::default_visitor::<scope>()};
|
2011-08-19 15:16:48 -07:00
|
|
|
visit::visit_crate(*crate, @[], visit::mk_vt(v));
|
2011-07-04 21:59:50 +02:00
|
|
|
tcx.sess.abort_if_errors();
|
2011-09-07 15:13:19 +02:00
|
|
|
ret cx.copy_map;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn visit_fn(f: ast::_fn, _tp: [ast::ty_param], _sp: span, _name: fn_ident,
|
|
|
|
_id: ast::node_id, sc: scope, v: vt<scope>) {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
visit::visit_fn_decl(f.decl, sc, v);
|
2011-09-02 15:34:58 -07:00
|
|
|
let scope =
|
|
|
|
alt f.proto {
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
// Blocks need to obey any restrictions from the enclosing scope.
|
|
|
|
ast::proto_block. | ast::proto_closure. {
|
|
|
|
sc
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
// Non capturing functions start out fresh.
|
|
|
|
_ {
|
|
|
|
@[]
|
|
|
|
}
|
|
|
|
};
|
2011-08-04 19:31:47 -07:00
|
|
|
v.visit_block(f.body, scope, v);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let handled = true;
|
|
|
|
alt ex.node {
|
|
|
|
ast::expr_call(f, args) {
|
|
|
|
check_call(*cx, f, args, sc);
|
|
|
|
handled = false;
|
|
|
|
}
|
|
|
|
ast::expr_alt(input, arms) { check_alt(*cx, input, arms, sc, v); }
|
|
|
|
ast::expr_put(val) {
|
|
|
|
alt val {
|
|
|
|
some(ex) {
|
2011-08-31 18:45:37 +02:00
|
|
|
let root = expr_root(cx.tcx, ex, false);
|
2011-07-27 14:19:39 +02:00
|
|
|
if mut_field(root.ds) {
|
|
|
|
cx.tcx.sess.span_err(ex.span,
|
2011-09-02 15:34:58 -07:00
|
|
|
"result of put must be" +
|
|
|
|
" immutably rooted");
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
visit_expr(cx, ex, sc, v);
|
|
|
|
}
|
|
|
|
_ { }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::expr_for_each(decl, call, blk) {
|
|
|
|
check_for_each(*cx, decl, call, blk, sc, v);
|
|
|
|
}
|
|
|
|
ast::expr_for(decl, seq, blk) { check_for(*cx, decl, seq, blk, sc, v); }
|
|
|
|
ast::expr_path(pt) {
|
|
|
|
check_var(*cx, ex, pt, ex.id, false, sc);
|
|
|
|
handled = false;
|
|
|
|
}
|
|
|
|
ast::expr_swap(lhs, rhs) {
|
|
|
|
check_lval(cx, lhs, sc, v);
|
|
|
|
check_lval(cx, rhs, sc, v);
|
|
|
|
handled = false;
|
|
|
|
}
|
|
|
|
ast::expr_move(dest, src) {
|
|
|
|
check_assign(cx, dest, src, sc, v);
|
2011-08-31 18:45:37 +02:00
|
|
|
check_lval(cx, src, sc, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::expr_assign(dest, src) | ast::expr_assign_op(_, dest, src) {
|
|
|
|
check_assign(cx, dest, src, sc, v);
|
|
|
|
}
|
|
|
|
_ { handled = false; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
if !handled { visit::visit_expr(ex, sc, v); }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn register_locals(cx: ctx, pat: @ast::pat) {
|
2011-08-30 17:03:00 +02:00
|
|
|
for each pat in ast_util::pat_bindings(pat) {
|
|
|
|
cx.local_map.insert(pat.id, local(cx.next_local));
|
|
|
|
cx.next_local += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn visit_decl(cx: @ctx, d: @ast::decl, sc: scope, v: vt<scope>) {
|
2011-07-13 10:23:13 +02:00
|
|
|
visit::visit_decl(d, sc, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt d.node {
|
|
|
|
ast::decl_local(locs) {
|
2011-07-28 12:01:45 +02:00
|
|
|
for loc: @ast::local in locs {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt loc.node.init {
|
|
|
|
some(init) {
|
|
|
|
if init.op == ast::init_move {
|
2011-08-31 18:45:37 +02:00
|
|
|
check_lval(cx, init.expr, sc, v);
|
2011-07-13 10:23:13 +02:00
|
|
|
}
|
2011-07-22 17:19:06 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
none. { }
|
2011-07-13 10:23:13 +02:00
|
|
|
}
|
2011-08-30 17:03:00 +02:00
|
|
|
register_locals(*cx, loc.node.pat);
|
2011-07-13 10:23:13 +02:00
|
|
|
}
|
2011-07-22 17:19:06 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
_ { }
|
2011-07-13 10:23:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn cant_copy(cx: ctx, r: restrict) -> bool {
|
2011-09-07 15:13:19 +02:00
|
|
|
if r.given_up { ret false; }
|
|
|
|
// FIXME alt contexts copying not supported yet
|
|
|
|
if r.node_id == 0 { ret true; }
|
2011-09-12 11:27:30 +02:00
|
|
|
|
2011-09-07 15:13:19 +02:00
|
|
|
// FIXME warn when copy is expensive
|
|
|
|
if ty::type_allows_implicit_copy(cx.tcx, r.ty) {
|
|
|
|
r.given_up = true;
|
|
|
|
cx.copy_map.insert(r.node_id, ());
|
|
|
|
ret false;
|
2011-09-12 11:27:30 +02:00
|
|
|
} else { ret true; }
|
2011-09-07 15:13:19 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr], sc: scope) ->
|
|
|
|
[restrict] {
|
2011-08-31 18:45:37 +02:00
|
|
|
let fty = ty::type_autoderef(cx.tcx, ty::expr_ty(cx.tcx, f));
|
|
|
|
let arg_ts = ty::ty_fn_args(cx.tcx, fty);
|
2011-08-19 15:16:48 -07:00
|
|
|
let mut_roots: [{arg: uint, node: node_id}] = [];
|
2011-08-31 18:27:53 +02:00
|
|
|
let restricts = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
let i = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for arg_t: ty::arg in arg_ts {
|
2011-09-07 15:13:19 +02:00
|
|
|
let arg = args[i];
|
|
|
|
let root = expr_root(cx.tcx, arg, false);
|
2011-09-12 10:05:40 +02:00
|
|
|
if arg_t.mode == ast::by_mut_ref {
|
2011-09-07 15:13:19 +02:00
|
|
|
alt path_def(cx, arg) {
|
|
|
|
some(def) {
|
|
|
|
let dnum = ast_util::def_id_of_def(def).node;
|
|
|
|
mut_roots += [{arg: i, node: dnum}];
|
|
|
|
}
|
|
|
|
_ { }
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-09-07 15:13:19 +02:00
|
|
|
let root_var = path_def_id(cx, root.ex);
|
|
|
|
let unsafe_t =
|
|
|
|
alt inner_mut(root.ds) { some(t) { some(t) } _ { none } };
|
|
|
|
restricts +=
|
2011-09-12 11:27:30 +02:00
|
|
|
[
|
|
|
|
// FIXME kludge
|
|
|
|
@{root_var: root_var,
|
2011-09-07 15:13:19 +02:00
|
|
|
node_id: arg_t.mode == ast::by_mut_ref ? 0 : arg.id,
|
|
|
|
ty: arg_t.ty,
|
|
|
|
local_id: cx.next_local,
|
|
|
|
bindings: [arg.id],
|
|
|
|
unsafe_ty: unsafe_t,
|
|
|
|
depends_on: deps(sc, root_var),
|
|
|
|
mutable ok: valid,
|
2011-09-12 10:05:40 +02:00
|
|
|
mutable given_up: arg_t.mode == ast::by_move}];
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
i += 1u;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
let f_may_close =
|
|
|
|
alt f.node {
|
|
|
|
ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id), true) }
|
|
|
|
_ { true }
|
|
|
|
};
|
2011-08-31 18:27:53 +02:00
|
|
|
if f_may_close {
|
|
|
|
let i = 0u;
|
|
|
|
for r in restricts {
|
2011-09-07 15:13:19 +02:00
|
|
|
if !option::is_none(r.unsafe_ty) && cant_copy(cx, r) {
|
2011-08-28 00:24:28 -07:00
|
|
|
cx.tcx.sess.span_err(f.span,
|
2011-09-01 18:49:10 -07:00
|
|
|
#fmt["function may alias with argument \
|
2011-08-31 18:27:53 +02:00
|
|
|
%u, which is not immutably rooted",
|
2011-09-02 15:34:58 -07:00
|
|
|
i]);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-08-31 18:27:53 +02:00
|
|
|
i += 1u;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
let j = 0u;
|
2011-09-07 15:13:19 +02:00
|
|
|
for r in restricts {
|
|
|
|
alt r.unsafe_ty {
|
2011-08-31 18:27:53 +02:00
|
|
|
some(ty) {
|
|
|
|
let i = 0u;
|
|
|
|
for arg_t: ty::arg in arg_ts {
|
2011-09-12 10:05:40 +02:00
|
|
|
let mut_alias = arg_t.mode == ast::by_mut_ref;
|
2011-08-31 18:27:53 +02:00
|
|
|
if i != j &&
|
2011-09-12 11:27:30 +02:00
|
|
|
ty_can_unsafely_include(cx, ty, arg_t.ty, mut_alias) &&
|
|
|
|
cant_copy(cx, r) {
|
|
|
|
cx.tcx.sess.span_err(args[i].span,
|
|
|
|
#fmt["argument %u may alias with argument %u, \
|
|
|
|
which is not immutably rooted",
|
|
|
|
i, j]);
|
2011-08-31 18:27:53 +02:00
|
|
|
}
|
|
|
|
i += 1u;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-08-31 18:27:53 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-08-31 18:27:53 +02:00
|
|
|
j += 1u;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-06-10 16:38:13 +02:00
|
|
|
// Ensure we're not passing a root by mutable alias.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
for {node: node, arg: arg} in mut_roots {
|
2011-09-07 15:13:19 +02:00
|
|
|
let i = 0u;
|
|
|
|
for r in restricts {
|
|
|
|
if i != arg {
|
|
|
|
alt r.root_var {
|
|
|
|
some(root) {
|
|
|
|
if node == root && cant_copy(cx, r) {
|
2011-09-12 11:27:30 +02:00
|
|
|
cx.tcx.sess.span_err(args[arg].span,
|
|
|
|
"passing a mutable alias to a \
|
2011-09-07 15:13:19 +02:00
|
|
|
variable that roots another alias");
|
2011-08-31 18:27:53 +02:00
|
|
|
break;
|
|
|
|
}
|
2011-09-07 15:13:19 +02:00
|
|
|
}
|
|
|
|
none. { }
|
2011-07-14 17:26:10 -07:00
|
|
|
}
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
2011-09-07 15:13:19 +02:00
|
|
|
i += 1u;
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-31 18:27:53 +02:00
|
|
|
ret restricts;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
|
|
|
|
v: vt<scope>) {
|
2011-08-30 17:03:00 +02:00
|
|
|
v.visit_expr(input, sc, v);
|
2011-08-31 18:45:37 +02:00
|
|
|
let root = expr_root(cx.tcx, input, true);
|
2011-08-15 21:54:52 -07:00
|
|
|
for a: ast::arm in arms {
|
2011-08-30 17:03:00 +02:00
|
|
|
let dnums = ast_util::pat_binding_ids(a.pats[0]);
|
2011-07-27 14:19:39 +02:00
|
|
|
let new_sc = sc;
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::len(dnums) > 0u {
|
2011-08-31 18:27:53 +02:00
|
|
|
let root_var = path_def_id(cx, root.ex);
|
2011-09-02 15:34:58 -07:00
|
|
|
new_sc =
|
|
|
|
@(*sc +
|
2011-09-12 11:27:30 +02:00
|
|
|
[
|
|
|
|
// FIXME need to use separate restrict for each binding
|
|
|
|
@{root_var: root_var,
|
2011-09-07 15:13:19 +02:00
|
|
|
node_id: 0,
|
|
|
|
ty: ty::mk_int(cx.tcx),
|
2011-09-02 15:34:58 -07:00
|
|
|
local_id: cx.next_local,
|
|
|
|
bindings: dnums,
|
|
|
|
unsafe_ty: inner_mut(root.ds),
|
|
|
|
depends_on: deps(sc, root_var),
|
2011-09-07 15:13:19 +02:00
|
|
|
mutable ok: valid,
|
|
|
|
mutable given_up: false}]);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-08-30 17:03:00 +02:00
|
|
|
register_locals(cx, a.pats[0]);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
visit::visit_arm(a, new_sc, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_for_each(cx: ctx, local: @ast::local, call: @ast::expr,
|
|
|
|
blk: ast::blk, sc: scope, v: vt<scope>) {
|
2011-08-30 17:03:00 +02:00
|
|
|
v.visit_expr(call, sc, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt call.node {
|
|
|
|
ast::expr_call(f, args) {
|
2011-08-31 18:27:53 +02:00
|
|
|
let restricts = check_call(cx, f, args, sc);
|
2011-08-30 17:03:00 +02:00
|
|
|
register_locals(cx, local.node.pat);
|
2011-08-31 18:27:53 +02:00
|
|
|
visit::visit_block(blk, @(*sc + restricts), v);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
|
|
|
|
sc: scope, v: vt<scope>) {
|
2011-08-30 17:03:00 +02:00
|
|
|
v.visit_expr(seq, sc, v);
|
2011-08-31 18:45:37 +02:00
|
|
|
let root = expr_root(cx.tcx, seq, false);
|
2011-08-31 18:27:53 +02:00
|
|
|
let unsafe = inner_mut(root.ds);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-07-13 10:23:13 +02:00
|
|
|
// If this is a mutable vector, don't allow it to be touched.
|
2011-07-27 14:19:39 +02:00
|
|
|
let seq_t = ty::expr_ty(cx.tcx, seq);
|
2011-09-07 15:13:19 +02:00
|
|
|
let elt_t;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ty::struct(cx.tcx, seq_t) {
|
2011-09-07 15:13:19 +02:00
|
|
|
ty::ty_vec(mt) {
|
|
|
|
if mt.mut != ast::imm { unsafe = some(seq_t); }
|
|
|
|
elt_t = mt.ty;
|
|
|
|
}
|
2011-09-12 11:27:30 +02:00
|
|
|
ty::ty_str. { elt_t = ty::mk_mach(cx.tcx, ast::ty_u8); }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-08-31 18:27:53 +02:00
|
|
|
let root_var = path_def_id(cx, root.ex);
|
2011-08-19 15:16:48 -07:00
|
|
|
let new_sc =
|
2011-08-31 18:27:53 +02:00
|
|
|
@{root_var: root_var,
|
2011-09-12 11:27:30 +02:00
|
|
|
|
2011-09-07 15:13:19 +02:00
|
|
|
// FIXME reenable when trans knows how to copy for vars
|
|
|
|
node_id: 0, // blk.node.id,
|
|
|
|
ty: elt_t,
|
2011-08-30 17:03:00 +02:00
|
|
|
local_id: cx.next_local,
|
2011-08-31 18:27:53 +02:00
|
|
|
bindings: ast_util::pat_binding_ids(local.node.pat),
|
|
|
|
unsafe_ty: unsafe,
|
|
|
|
depends_on: deps(sc, root_var),
|
2011-09-07 15:13:19 +02:00
|
|
|
mutable ok: valid,
|
|
|
|
mutable given_up: false};
|
2011-08-30 17:03:00 +02:00
|
|
|
register_locals(cx, local.node.pat);
|
2011-08-19 15:16:48 -07:00
|
|
|
visit::visit_block(blk, @(*sc + [new_sc]), v);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_var(cx: ctx, ex: @ast::expr, p: ast::path, id: ast::node_id,
|
|
|
|
assign: bool, sc: scope) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let def = cx.tcx.def_map.get(id);
|
|
|
|
if !def_is_local(def, true) { ret; }
|
2011-08-21 21:44:41 -07:00
|
|
|
let my_defnum = ast_util::def_id_of_def(def).node;
|
2011-09-02 15:34:58 -07:00
|
|
|
let my_local_id =
|
|
|
|
alt cx.local_map.find(my_defnum) { some(local(id)) { id } _ { 0u } };
|
2011-07-27 14:19:39 +02:00
|
|
|
let var_t = ty::expr_ty(cx.tcx, ex);
|
2011-08-15 21:54:52 -07:00
|
|
|
for r: restrict in *sc {
|
2011-09-12 11:27:30 +02:00
|
|
|
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
// excludes variables introduced since the alias was made
|
2011-08-30 17:03:00 +02:00
|
|
|
if my_local_id < r.local_id {
|
2011-08-31 18:27:53 +02:00
|
|
|
alt r.unsafe_ty {
|
|
|
|
some(ty) {
|
|
|
|
if ty_can_unsafely_include(cx, ty, var_t, assign) {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
r.ok = val_taken(ex.span, p);
|
|
|
|
}
|
2011-08-31 18:27:53 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if vec::member(my_defnum, r.bindings) {
|
2011-06-09 14:19:13 +02:00
|
|
|
test_scope(cx, sc, r, p);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_lval(cx: @ctx, dest: @ast::expr, sc: scope, v: vt<scope>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt dest.node {
|
|
|
|
ast::expr_path(p) {
|
2011-08-31 18:45:37 +02:00
|
|
|
let def = cx.tcx.def_map.get(dest.id);
|
|
|
|
let dnum = ast_util::def_id_of_def(def).node;
|
2011-07-27 17:19:46 +02:00
|
|
|
for r: restrict in *sc {
|
2011-09-02 15:34:58 -07:00
|
|
|
if r.root_var == some(dnum) { r.ok = overwritten(dest.span, p); }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-08-31 18:45:37 +02:00
|
|
|
_ { visit_expr(cx, dest, sc, v); }
|
2011-07-07 10:21:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_assign(cx: @ctx, dest: @ast::expr, src: @ast::expr, sc: scope,
|
|
|
|
v: vt<scope>) {
|
2011-06-28 17:24:59 -07:00
|
|
|
visit_expr(cx, src, sc, v);
|
|
|
|
check_lval(cx, dest, sc, v);
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn test_scope(cx: ctx, sc: scope, r: restrict, p: ast::path) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let prob = r.ok;
|
2011-08-15 21:54:52 -07:00
|
|
|
for dep: uint in r.depends_on {
|
2011-07-27 14:19:39 +02:00
|
|
|
if prob != valid { break; }
|
2011-08-19 15:16:48 -07:00
|
|
|
prob = sc[dep].ok;
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
2011-09-07 15:13:19 +02:00
|
|
|
if prob != valid && cant_copy(cx, r) {
|
2011-09-12 11:27:30 +02:00
|
|
|
let msg =
|
|
|
|
alt prob {
|
|
|
|
overwritten(sp, wpt) {
|
|
|
|
{span: sp, msg: "overwriting " + ast_util::path_name(wpt)}
|
|
|
|
}
|
|
|
|
val_taken(sp, vpt) {
|
|
|
|
{span: sp,
|
|
|
|
msg: "taking the value of " + ast_util::path_name(vpt)}
|
|
|
|
}
|
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
cx.tcx.sess.span_err(msg.span,
|
2011-09-02 15:34:58 -07:00
|
|
|
msg.msg + " will invalidate alias " +
|
|
|
|
ast_util::path_name(p) +
|
|
|
|
", which is still used");
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn deps(sc: scope, root: option::t<node_id>) -> [uint] {
|
2011-08-19 15:16:48 -07:00
|
|
|
let result = [];
|
2011-08-31 18:27:53 +02:00
|
|
|
alt root {
|
|
|
|
some(dn) {
|
|
|
|
let i = 0u;
|
|
|
|
for r: restrict in *sc {
|
2011-08-19 15:16:48 -07:00
|
|
|
if vec::member(dn, r.bindings) { result += [i]; }
|
2011-08-31 18:27:53 +02:00
|
|
|
i += 1u;
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
2011-08-31 18:27:53 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { }
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn path_def(cx: ctx, ex: @ast::expr) -> option::t<ast::def> {
|
2011-07-27 17:19:46 +02:00
|
|
|
ret alt ex.node {
|
2011-08-19 15:16:48 -07:00
|
|
|
ast::expr_path(_) { some(cx.tcx.def_map.get(ex.id)) }
|
|
|
|
_ { none }
|
|
|
|
}
|
2011-07-27 17:19:46 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn path_def_id(cx: ctx, ex: @ast::expr) -> option::t<ast::node_id> {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ex.node {
|
|
|
|
ast::expr_path(_) {
|
2011-08-31 18:27:53 +02:00
|
|
|
ret some(ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)).node);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { ret none; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn ty_can_unsafely_include(cx: ctx, needle: ty::t, haystack: ty::t, mut: bool)
|
|
|
|
-> bool {
|
|
|
|
fn get_mut(cur: bool, mt: ty::mt) -> bool {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
ret cur || mt.mut != ast::imm;
|
|
|
|
}
|
2011-09-12 11:27:30 +02:00
|
|
|
fn helper(tcx: ty::ctxt, needle: ty::t, haystack: ty::t, mut: bool) ->
|
2011-07-27 14:19:39 +02:00
|
|
|
bool {
|
|
|
|
if needle == haystack { ret true; }
|
|
|
|
alt ty::struct(tcx, haystack) {
|
|
|
|
ty::ty_tag(_, ts) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for t: ty::t in ts {
|
2011-07-27 14:19:39 +02:00
|
|
|
if helper(tcx, needle, t, mut) { ret true; }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret false;
|
|
|
|
}
|
2011-08-18 11:46:52 -07:00
|
|
|
ty::ty_box(mt) | ty::ty_ptr(mt) {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret helper(tcx, needle, mt.ty, get_mut(mut, mt));
|
|
|
|
}
|
2011-08-10 17:23:46 -07:00
|
|
|
ty::ty_uniq(t) { ret helper(tcx, needle, t, false); }
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_rec(fields) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for f: ty::field in fields {
|
2011-07-27 14:19:39 +02:00
|
|
|
if helper(tcx, needle, f.mt.ty, get_mut(mut, f.mt)) {
|
|
|
|
ret true;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret false;
|
|
|
|
}
|
2011-08-15 12:08:05 +02:00
|
|
|
ty::ty_tup(ts) {
|
2011-08-19 15:16:48 -07:00
|
|
|
for t in ts { if helper(tcx, needle, t, mut) { ret true; } }
|
2011-08-15 11:40:26 +02:00
|
|
|
ret false;
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
// These may contain anything.
|
|
|
|
ty::ty_fn(_, _, _, _, _) {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
ty::ty_obj(_) { ret true; }
|
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
// A type param may include everything, but can only be
|
|
|
|
// treated as opaque downstream, and is thus safe unless we
|
|
|
|
// saw mutable fields, in which case the whole thing can be
|
|
|
|
// overwritten.
|
2011-08-19 15:16:48 -07:00
|
|
|
ty::ty_param(_, _) {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret mut;
|
|
|
|
}
|
|
|
|
_ { ret false; }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-21 15:32:31 -07:00
|
|
|
ret helper(cx.tcx, needle, haystack, mut);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn def_is_local(d: ast::def, objfields_count: bool) -> bool {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret alt d {
|
2011-09-02 15:34:58 -07:00
|
|
|
ast::def_local(_) | ast::def_arg(_, _) | ast::def_binding(_) |
|
|
|
|
ast::def_upvar(_, _, _) {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
ast::def_obj_field(_, _) { objfields_count }
|
|
|
|
_ { false }
|
|
|
|
};
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-15 21:01:28 +02:00
|
|
|
|
2011-06-06 15:22:13 +02:00
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
|
|
|
// End:
|