implement new borrow ck (disabled by default)
This commit is contained in:
parent
5e7229b72c
commit
50a3dd40ae
@ -49,7 +49,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTSYNTAX): \
|
||||
$$(TCORELIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
|
||||
$$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3))
|
||||
@$$(call E, compile_and_link: $$@)
|
||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
|
||||
$$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@
|
||||
|
||||
endef
|
||||
|
||||
|
@ -4,7 +4,7 @@ import session::session;
|
||||
import syntax::parse;
|
||||
import syntax::{ast, codemap};
|
||||
import syntax::attr;
|
||||
import middle::{trans, resolve, freevars, kind, ty, typeck, fn_usage,
|
||||
import middle::{trans, resolve, freevars, kind, ty, typeck,
|
||||
last_use, lint};
|
||||
import syntax::print::{pp, pprust};
|
||||
import util::{ppaux, filesearch};
|
||||
@ -158,12 +158,13 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
|
||||
bind middle::block_use::check_crate(ty_cx, crate));
|
||||
time(time_passes, "loop checking",
|
||||
bind middle::check_loop::check_crate(ty_cx, crate));
|
||||
time(time_passes, "function usage",
|
||||
bind fn_usage::check_crate_fn_usage(ty_cx, crate));
|
||||
time(time_passes, "alt checking",
|
||||
bind middle::check_alt::check_crate(ty_cx, crate));
|
||||
time(time_passes, "typestate checking",
|
||||
bind middle::tstate::ck::check_crate(ty_cx, crate));
|
||||
let _root_map = time(
|
||||
time_passes, "borrow checking",
|
||||
bind middle::borrowck::check_crate(ty_cx, method_map, crate));
|
||||
let mutbl_map =
|
||||
time(time_passes, "mutability checking",
|
||||
bind middle::mutbl::check_crate(ty_cx, crate));
|
||||
@ -401,6 +402,14 @@ fn build_session_options(match: getopts::match,
|
||||
let target_opt = getopts::opt_maybe_str(match, "target");
|
||||
let mut no_asm_comments = getopts::opt_present(match, "no-asm-comments");
|
||||
let debug_rustc = getopts::opt_present(match, "debug-rustc");
|
||||
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 {}
|
||||
@ -455,7 +464,8 @@ fn build_session_options(match: getopts::match,
|
||||
parse_only: parse_only,
|
||||
no_trans: no_trans,
|
||||
no_asm_comments: no_asm_comments,
|
||||
debug_rustc: debug_rustc};
|
||||
debug_rustc: debug_rustc,
|
||||
borrowck: borrowck};
|
||||
ret sopts;
|
||||
}
|
||||
|
||||
@ -533,7 +543,8 @@ fn opts() -> [getopts::opt] {
|
||||
optmulti("cfg"), optflag("test"),
|
||||
optflag("lib"), optflag("bin"), optflag("static"), optflag("gc"),
|
||||
optflag("no-asm-comments"),
|
||||
optflag("debug-rustc")];
|
||||
optflag("debug-rustc"),
|
||||
optopt("borrowck")];
|
||||
}
|
||||
|
||||
type output_filenames = @{out_filename: str, obj_filename:str};
|
||||
|
@ -47,7 +47,8 @@ type options =
|
||||
parse_only: bool,
|
||||
no_trans: bool,
|
||||
no_asm_comments: bool,
|
||||
debug_rustc: bool};
|
||||
debug_rustc: bool,
|
||||
borrowck: uint}; // 0=off,1=warn,2=err
|
||||
|
||||
type crate_metadata = {name: str, data: [u8]};
|
||||
|
||||
@ -139,6 +140,7 @@ fn basic_options() -> @options {
|
||||
no_trans: false,
|
||||
no_asm_comments: false,
|
||||
debug_rustc: false,
|
||||
borrowck: 0u,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -844,9 +844,10 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
|
||||
}
|
||||
}
|
||||
|
||||
option::iter(tcx.borrowings.find(id)) {|_i|
|
||||
option::iter(tcx.borrowings.find(id)) {|s|
|
||||
ebml_w.tag(c::tag_table_borrowings) {||
|
||||
ebml_w.id(id);
|
||||
ebml_w.wr_tagged_i64(c::tag_table_val as uint, s as i64);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -919,8 +920,6 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
|
||||
dcx.maps.copy_map.insert(id, ());
|
||||
} else if tag == (c::tag_table_spill as uint) {
|
||||
dcx.maps.spill_map.insert(id, ());
|
||||
} else if tag == (c::tag_table_borrowings as uint) {
|
||||
dcx.tcx.borrowings.insert(id, ());
|
||||
} else {
|
||||
let val_doc = entry_doc[c::tag_table_val];
|
||||
let val_dsr = ebml::ebml_deserializer(val_doc);
|
||||
@ -952,7 +951,10 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
|
||||
val_dsr.read_method_origin(xcx));
|
||||
} else if tag == (c::tag_table_vtable_map as uint) {
|
||||
dcx.maps.vtable_map.insert(id,
|
||||
val_dsr.read_vtable_res(xcx));
|
||||
val_dsr.read_vtable_res(xcx));
|
||||
} else if tag == (c::tag_table_borrowings as uint) {
|
||||
let scope_id = ebml::doc_as_i64(val_doc) as int;
|
||||
dcx.tcx.borrowings.insert(id, scope_id);
|
||||
} else {
|
||||
xcx.dcx.tcx.sess.bug(
|
||||
#fmt["unknown tag found in side tables: %x", tag]);
|
||||
|
1334
src/rustc/middle/borrowck.rs
Normal file
1334
src/rustc/middle/borrowck.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,95 +0,0 @@
|
||||
import std::map::hashmap;
|
||||
import syntax::ast;
|
||||
import syntax::visit;
|
||||
import syntax::print::pprust::expr_to_str;
|
||||
import driver::session::session;
|
||||
|
||||
export check_crate_fn_usage;
|
||||
|
||||
type fn_usage_ctx = {
|
||||
tcx: ty::ctxt,
|
||||
unsafe_fn_legal: bool,
|
||||
generic_bare_fn_legal: bool
|
||||
};
|
||||
|
||||
fn fn_usage_expr(expr: @ast::expr,
|
||||
ctx: fn_usage_ctx,
|
||||
v: visit::vt<fn_usage_ctx>) {
|
||||
alt expr.node {
|
||||
ast::expr_path(path) {
|
||||
if !ctx.unsafe_fn_legal {
|
||||
alt ctx.tcx.def_map.find(expr.id) {
|
||||
some(ast::def_fn(_, ast::unsafe_fn)) {
|
||||
log(error, ("expr=", expr_to_str(expr)));
|
||||
ctx.tcx.sess.span_fatal(
|
||||
expr.span,
|
||||
"unsafe functions can only be called");
|
||||
}
|
||||
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
if !ctx.generic_bare_fn_legal
|
||||
&& ty::expr_has_ty_params(ctx.tcx, expr) {
|
||||
alt ty::get(ty::expr_ty(ctx.tcx, expr)).struct {
|
||||
ty::ty_fn({proto: ast::proto_bare, _}) {
|
||||
ctx.tcx.sess.span_fatal(
|
||||
expr.span,
|
||||
"generic bare functions can only be called or bound");
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast::expr_call(f, args, _) {
|
||||
let f_ctx = {unsafe_fn_legal: true,
|
||||
generic_bare_fn_legal: true with ctx};
|
||||
v.visit_expr(f, f_ctx, v);
|
||||
|
||||
let args_ctx = {unsafe_fn_legal: false,
|
||||
generic_bare_fn_legal: false with ctx};
|
||||
visit::visit_exprs(args, args_ctx, v);
|
||||
}
|
||||
|
||||
ast::expr_bind(f, args) {
|
||||
let f_ctx = {unsafe_fn_legal: false,
|
||||
generic_bare_fn_legal: true with ctx};
|
||||
v.visit_expr(f, f_ctx, v);
|
||||
|
||||
let args_ctx = {unsafe_fn_legal: false,
|
||||
generic_bare_fn_legal: false with ctx};
|
||||
for args.each {|arg|
|
||||
visit::visit_expr_opt(arg, args_ctx, v);
|
||||
}
|
||||
}
|
||||
|
||||
_ {
|
||||
let subctx = {unsafe_fn_legal: false,
|
||||
generic_bare_fn_legal: false with ctx};
|
||||
visit::visit_expr(expr, subctx, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_crate_fn_usage(tcx: ty::ctxt, crate: @ast::crate) {
|
||||
let visit =
|
||||
visit::mk_vt(
|
||||
@{visit_expr: fn_usage_expr
|
||||
with *visit::default_visitor()});
|
||||
let ctx = {
|
||||
tcx: tcx,
|
||||
unsafe_fn_legal: false,
|
||||
generic_bare_fn_legal: false
|
||||
};
|
||||
visit::visit_crate(*crate, ctx, visit);
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
@ -24,6 +24,15 @@ export resolve_deep_var;
|
||||
export compare_tys;
|
||||
export fixup_err, fixup_err_to_str;
|
||||
|
||||
// Extra information needed to perform an assignment that may borrow.
|
||||
// The `expr_id` is the is of the expression whose type is being
|
||||
// assigned, and `borrow_scope` is the region scope to use if the
|
||||
// value should be borrowed.
|
||||
type assignment = {
|
||||
expr_id: ast::node_id,
|
||||
borrow_scope: ast::node_id
|
||||
};
|
||||
|
||||
type bound<T:copy> = option<T>;
|
||||
|
||||
type bounds<T:copy> = {lb: bound<T>, ub: bound<T>};
|
||||
@ -84,12 +93,12 @@ fn mk_eqty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
|
||||
indent {|| cx.commit {|| cx.eq_tys(a, b) } }.to_ures()
|
||||
}
|
||||
|
||||
fn mk_assignty(cx: infer_ctxt, a_node_id: ast::node_id,
|
||||
a: ty::t, b: ty::t) -> ures {
|
||||
fn mk_assignty(cx: infer_ctxt, anmnt: assignment,
|
||||
a: ty::t, b: ty::t) -> ures {
|
||||
#debug["mk_assignty(%? / %s <: %s)",
|
||||
a_node_id, a.to_str(cx), b.to_str(cx)];
|
||||
anmnt, a.to_str(cx), b.to_str(cx)];
|
||||
indent {|| cx.commit {||
|
||||
cx.assign_tys(a_node_id, a, b)
|
||||
cx.assign_tys(anmnt, a, b)
|
||||
} }.to_ures()
|
||||
}
|
||||
|
||||
@ -765,8 +774,7 @@ impl methods for resolve_state {
|
||||
// this upper-bound might be stricter than what is truly needed.
|
||||
|
||||
impl assignment for infer_ctxt {
|
||||
fn assign_tys(a_node_id: ast::node_id,
|
||||
a: ty::t, b: ty::t) -> ures {
|
||||
fn assign_tys(anmnt: assignment, a: ty::t, b: ty::t) -> ures {
|
||||
|
||||
fn select(fst: option<ty::t>, snd: option<ty::t>) -> option<ty::t> {
|
||||
alt fst {
|
||||
@ -780,8 +788,8 @@ impl assignment for infer_ctxt {
|
||||
}
|
||||
}
|
||||
|
||||
#debug["assign_tys(a_node_id=%?, %s -> %s)",
|
||||
a_node_id, a.to_str(self), b.to_str(self)];
|
||||
#debug["assign_tys(anmnt=%?, %s -> %s)",
|
||||
anmnt, a.to_str(self), b.to_str(self)];
|
||||
let _r = indenter();
|
||||
|
||||
alt (ty::get(a).struct, ty::get(b).struct) {
|
||||
@ -794,34 +802,34 @@ impl assignment for infer_ctxt {
|
||||
let {root:_, bounds: b_bounds} = self.get(self.vb, b_id);
|
||||
let a_bnd = select(a_bounds.ub, a_bounds.lb);
|
||||
let b_bnd = select(b_bounds.lb, b_bounds.ub);
|
||||
self.assign_tys_or_sub(a_node_id, a, b, a_bnd, b_bnd)
|
||||
self.assign_tys_or_sub(anmnt, a, b, a_bnd, b_bnd)
|
||||
}
|
||||
|
||||
(ty::ty_var(a_id), _) {
|
||||
let {root:_, bounds:a_bounds} = self.get(self.vb, a_id);
|
||||
let a_bnd = select(a_bounds.ub, a_bounds.lb);
|
||||
self.assign_tys_or_sub(a_node_id, a, b, a_bnd, some(b))
|
||||
self.assign_tys_or_sub(anmnt, a, b, a_bnd, some(b))
|
||||
}
|
||||
|
||||
(_, ty::ty_var(b_id)) {
|
||||
let {root:_, bounds: b_bounds} = self.get(self.vb, b_id);
|
||||
let b_bnd = select(b_bounds.lb, b_bounds.ub);
|
||||
self.assign_tys_or_sub(a_node_id, a, b, some(a), b_bnd)
|
||||
self.assign_tys_or_sub(anmnt, a, b, some(a), b_bnd)
|
||||
}
|
||||
|
||||
(_, _) {
|
||||
self.assign_tys_or_sub(a_node_id, a, b, some(a), some(b))
|
||||
self.assign_tys_or_sub(anmnt, a, b, some(a), some(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assign_tys_or_sub(
|
||||
a_node_id: ast::node_id,
|
||||
anmnt: assignment,
|
||||
a: ty::t, b: ty::t,
|
||||
a_bnd: option<ty::t>, b_bnd: option<ty::t>) -> ures {
|
||||
|
||||
#debug["assign_tys_or_sub(a_node_id=%?, %s -> %s, %s -> %s)",
|
||||
a_node_id, a.to_str(self), b.to_str(self),
|
||||
#debug["assign_tys_or_sub(anmnt=%?, %s -> %s, %s -> %s)",
|
||||
anmnt, a.to_str(self), b.to_str(self),
|
||||
a_bnd.to_str(self), b_bnd.to_str(self)];
|
||||
let _r = indenter();
|
||||
|
||||
@ -837,34 +845,34 @@ impl assignment for infer_ctxt {
|
||||
alt (ty::get(a_bnd).struct, ty::get(b_bnd).struct) {
|
||||
(ty::ty_box(mt_a), ty::ty_rptr(r_b, mt_b)) {
|
||||
let nr_b = ty::mk_box(self.tcx, mt_b);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
self.crosspolinate(anmnt, a, nr_b, r_b)
|
||||
}
|
||||
(ty::ty_uniq(mt_a), ty::ty_rptr(r_b, mt_b)) {
|
||||
let nr_b = ty::mk_uniq(self.tcx, mt_b);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
self.crosspolinate(anmnt, a, nr_b, r_b)
|
||||
}
|
||||
(ty::ty_estr(vs_a),
|
||||
ty::ty_estr(ty::vstore_slice(r_b)))
|
||||
if is_borrowable(vs_a) {
|
||||
let nr_b = ty::mk_estr(self.tcx, vs_a);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
self.crosspolinate(anmnt, a, nr_b, r_b)
|
||||
}
|
||||
(ty::ty_str,
|
||||
ty::ty_estr(ty::vstore_slice(r_b))) {
|
||||
let nr_b = ty::mk_str(self.tcx);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
self.crosspolinate(anmnt, a, nr_b, r_b)
|
||||
}
|
||||
|
||||
(ty::ty_evec(mt_a, vs_a),
|
||||
ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
|
||||
if is_borrowable(vs_a) {
|
||||
let nr_b = ty::mk_evec(self.tcx, mt_b, vs_a);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
self.crosspolinate(anmnt, a, nr_b, r_b)
|
||||
}
|
||||
(ty::ty_vec(mt_a),
|
||||
ty::ty_evec(mt_b, ty::vstore_slice(r_b))) {
|
||||
let nr_b = ty::mk_vec(self.tcx, mt_b);
|
||||
self.crosspolinate(a_node_id, a, nr_b, r_b)
|
||||
self.crosspolinate(anmnt, a, nr_b, r_b)
|
||||
}
|
||||
_ {
|
||||
self.sub_tys(a, b)
|
||||
@ -877,25 +885,25 @@ impl assignment for infer_ctxt {
|
||||
}
|
||||
}
|
||||
|
||||
fn crosspolinate(a_node_id: ast::node_id,
|
||||
fn crosspolinate(anmnt: assignment,
|
||||
a: ty::t,
|
||||
nr_b: ty::t,
|
||||
r_b: ty::region) -> ures {
|
||||
|
||||
#debug["crosspolinate(a_node_id=%?, a=%s, nr_b=%s, r_b=%s)",
|
||||
a_node_id, a.to_str(self), nr_b.to_str(self),
|
||||
#debug["crosspolinate(anmnt=%?, a=%s, nr_b=%s, r_b=%s)",
|
||||
anmnt, a.to_str(self), nr_b.to_str(self),
|
||||
r_b.to_str(self)];
|
||||
|
||||
indent {||
|
||||
self.sub_tys(a, nr_b).then {||
|
||||
let a_scope_id = self.tcx.region_map.parents.get(a_node_id);
|
||||
let r_a = ty::re_scope(a_scope_id);
|
||||
#debug["a_scope_id=%?", a_scope_id];
|
||||
let r_a = ty::re_scope(anmnt.borrow_scope);
|
||||
#debug["anmnt=%?", anmnt];
|
||||
sub(self).contraregions(r_a, r_b).chain {|_r|
|
||||
// if successful, add an entry indicating that
|
||||
// borrowing occurred
|
||||
#debug["borrowing expression #%?", a_node_id];
|
||||
self.tcx.borrowings.insert(a_node_id, ());
|
||||
#debug["borrowing expression #%?", anmnt];
|
||||
self.tcx.borrowings.insert(anmnt.expr_id,
|
||||
anmnt.borrow_scope);
|
||||
uok()
|
||||
}
|
||||
}
|
||||
|
@ -136,6 +136,7 @@ import driver::session::session;
|
||||
import middle::ty;
|
||||
import syntax::{ast, visit};
|
||||
import syntax::codemap::span;
|
||||
import syntax::print::pprust;
|
||||
import util::common::new_def_hash;
|
||||
|
||||
import std::list;
|
||||
@ -151,10 +152,12 @@ type binding = {node_id: ast::node_id,
|
||||
br: ty::bound_region};
|
||||
|
||||
type region_map = {
|
||||
/* Mapping from a block/function expression to its parent. */
|
||||
// Mapping from a block/function expression to its parent.
|
||||
parents: hashmap<ast::node_id,ast::node_id>,
|
||||
|
||||
/* Mapping from a local variable to its containing block. */
|
||||
// Mapping from arguments and local variables to the block in
|
||||
// which they are declared. Arguments are considered to be declared
|
||||
// within the body of the function.
|
||||
local_blocks: hashmap<ast::node_id,ast::node_id>
|
||||
};
|
||||
|
||||
@ -163,7 +166,43 @@ type ctxt = {
|
||||
def_map: resolve::def_map,
|
||||
region_map: @region_map,
|
||||
|
||||
parent: parent
|
||||
// These two fields (parent and closure_parent) specify the parent
|
||||
// scope of the current expression. The parent scope is the
|
||||
// innermost block, call, or alt expression during the execution
|
||||
// of which the current expression will be evaluated. Generally
|
||||
// speaking, the innermost parent scope is also the closest
|
||||
// suitable ancestor in the AST tree.
|
||||
//
|
||||
// However, there are two subtle cases where the parent scope for
|
||||
// an expression is not strictly derived from the AST. The first
|
||||
// such exception concerns call arguments and the second concerns
|
||||
// closures (which, at least today, are always call arguments).
|
||||
// Consider:
|
||||
//
|
||||
// { // block a
|
||||
// foo( // call b
|
||||
// x,
|
||||
// y,
|
||||
// fn&() {
|
||||
// // fn body c
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// Here, the parent of the three argument expressions is
|
||||
// actually the block `a`, not the call `b`, because they will
|
||||
// be evaluated before the call conceptually takes place.
|
||||
// However, the body of the closure is parented by the call
|
||||
// `b` (it cannot be invoked except during that call, after
|
||||
// all).
|
||||
//
|
||||
// To capture these patterns, we use two fields. The first,
|
||||
// parent, is the parent scope of a normal expression. The
|
||||
// second, closure_parent, is the parent scope that a closure body
|
||||
// ought to use. These only differ in the case of calls, where
|
||||
// the closure parent is the call, but the parent is the container
|
||||
// of the call.
|
||||
parent: parent,
|
||||
closure_parent: parent
|
||||
};
|
||||
|
||||
// Returns true if `subscope` is equal to or is lexically nested inside
|
||||
@ -213,18 +252,20 @@ fn nearest_common_ancestor(region_map: @region_map, scope_a: ast::node_id,
|
||||
// where they diverge. If one vector is a suffix of the other,
|
||||
// then the corresponding scope is a superscope of the other.
|
||||
|
||||
if a_ancestors[a_index] != b_ancestors[b_index] {
|
||||
ret none;
|
||||
}
|
||||
|
||||
loop {
|
||||
if a_ancestors[a_index] != b_ancestors[b_index] {
|
||||
if a_index == a_ancestors.len() {
|
||||
ret none;
|
||||
} else {
|
||||
ret some(a_ancestors[a_index + 1u]);
|
||||
}
|
||||
}
|
||||
// Loop invariant: a_ancestors[a_index] == b_ancestors[b_index]
|
||||
// for all indices between a_index and the end of the array
|
||||
if a_index == 0u { ret some(scope_a); }
|
||||
if b_index == 0u { ret some(scope_b); }
|
||||
a_index -= 1u;
|
||||
b_index -= 1u;
|
||||
if a_ancestors[a_index] != b_ancestors[b_index] {
|
||||
ret some(a_ancestors[a_index + 1u]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,6 +284,7 @@ fn record_parent(cx: ctxt, child_id: ast::node_id) {
|
||||
alt cx.parent {
|
||||
none { /* no-op */ }
|
||||
some(parent_id) {
|
||||
#debug["parent of node %d is node %d", child_id, parent_id];
|
||||
cx.region_map.parents.insert(child_id, parent_id);
|
||||
}
|
||||
}
|
||||
@ -253,8 +295,8 @@ fn resolve_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
|
||||
record_parent(cx, blk.node.id);
|
||||
|
||||
// Descend.
|
||||
let new_cx: ctxt = {parent: some(blk.node.id)
|
||||
with cx};
|
||||
let new_cx: ctxt = {parent: some(blk.node.id),
|
||||
closure_parent: some(blk.node.id) with cx};
|
||||
visit::visit_block(blk, new_cx, visitor);
|
||||
}
|
||||
|
||||
@ -286,16 +328,16 @@ fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
|
||||
fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
|
||||
record_parent(cx, expr.id);
|
||||
alt expr.node {
|
||||
ast::expr_fn(*) | ast::expr_fn_block(*) {
|
||||
let new_cx = {parent: some(expr.id) with cx};
|
||||
visit::visit_expr(expr, new_cx, visitor);
|
||||
}
|
||||
ast::expr_call(_, _, _) {
|
||||
let new_cx = {parent: some(expr.id) with cx};
|
||||
ast::expr_call(*) {
|
||||
#debug["node %d: %s", expr.id, pprust::expr_to_str(expr)];
|
||||
let new_cx = {closure_parent: some(expr.id) with cx};
|
||||
visit::visit_expr(expr, new_cx, visitor);
|
||||
}
|
||||
ast::expr_alt(subexpr, _, _) {
|
||||
let new_cx = {parent: some(expr.id) with cx};
|
||||
#debug["node %d: %s", expr.id, pprust::expr_to_str(expr)];
|
||||
let new_cx = {parent: some(expr.id),
|
||||
closure_parent: some(expr.id)
|
||||
with cx};
|
||||
visit::visit_expr(expr, new_cx, visitor);
|
||||
}
|
||||
_ {
|
||||
@ -312,20 +354,53 @@ fn resolve_local(local: @ast::local, cx: ctxt, visitor: visit::vt<ctxt>) {
|
||||
|
||||
fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
|
||||
// Items create a new outer block scope as far as we're concerned.
|
||||
let new_cx: ctxt = {parent: some(item.id) with cx};
|
||||
let new_cx: ctxt = {closure_parent: some(item.id),
|
||||
parent: some(item.id) with cx};
|
||||
visit::visit_item(item, new_cx, visitor);
|
||||
}
|
||||
|
||||
fn resolve_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
|
||||
sp: span, id: ast::node_id, cx: ctxt,
|
||||
visitor: visit::vt<ctxt>) {
|
||||
|
||||
let fn_cx = alt fk {
|
||||
visit::fk_item_fn(*) | visit::fk_method(*) | visit::fk_res(*) |
|
||||
visit::fk_ctor(*) {
|
||||
// Top-level functions are a root scope.
|
||||
{parent: some(id), closure_parent: some(id) with cx}
|
||||
}
|
||||
|
||||
visit::fk_anon(*) | visit::fk_fn_block(*) {
|
||||
// Closures use the closure_parent.
|
||||
{parent: cx.closure_parent with cx}
|
||||
}
|
||||
};
|
||||
|
||||
#debug["visiting fn with body %d. cx.parent: %? \
|
||||
cx.closure_parent: %? fn_cx.parent: %?",
|
||||
body.node.id, cx.parent,
|
||||
cx.closure_parent, fn_cx.parent];
|
||||
|
||||
for decl.inputs.each { |input|
|
||||
cx.region_map.local_blocks.insert(
|
||||
input.id, body.node.id);
|
||||
}
|
||||
|
||||
visit::visit_fn(fk, decl, body, sp, id, fn_cx, visitor);
|
||||
}
|
||||
|
||||
fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
|
||||
-> @region_map {
|
||||
let cx: ctxt = {sess: sess,
|
||||
def_map: def_map,
|
||||
region_map: @{parents: map::int_hash(),
|
||||
local_blocks: map::int_hash()},
|
||||
parent: none};
|
||||
parent: none,
|
||||
closure_parent: none};
|
||||
let visitor = visit::mk_vt(@{
|
||||
visit_block: resolve_block,
|
||||
visit_item: resolve_item,
|
||||
visit_fn: resolve_fn,
|
||||
visit_arm: resolve_arm,
|
||||
visit_pat: resolve_pat,
|
||||
visit_expr: resolve_expr,
|
||||
|
@ -18,7 +18,7 @@ fn count_insn(cx: block, category: str) {
|
||||
if (cx.ccx().sess.opts.count_llvm_insns) {
|
||||
|
||||
let h = cx.ccx().stats.llvm_insns;
|
||||
let mut v = cx.ccx().stats.llvm_insn_ctxt;
|
||||
let v = cx.ccx().stats.llvm_insn_ctxt;
|
||||
|
||||
// Build version of path with cycles removed.
|
||||
|
||||
|
@ -29,6 +29,8 @@ export constr;
|
||||
export constr_general;
|
||||
export constr_table;
|
||||
export ctxt;
|
||||
export deref, deref_sty;
|
||||
export index, index_sty;
|
||||
export def_has_ty_params;
|
||||
export expr_has_ty_params;
|
||||
export expr_ty;
|
||||
@ -126,7 +128,7 @@ export type_is_unique;
|
||||
export type_is_c_like_enum;
|
||||
export type_structurally_contains;
|
||||
export type_structurally_contains_uniques;
|
||||
export type_autoderef;
|
||||
export type_autoderef, deref, deref_sty;
|
||||
export type_param;
|
||||
export type_needs_unwind_cleanup;
|
||||
export canon_mode;
|
||||
@ -228,7 +230,8 @@ type ctxt =
|
||||
iface_method_cache: hashmap<def_id, @[method]>,
|
||||
ty_param_bounds: hashmap<ast::node_id, param_bounds>,
|
||||
inferred_modes: hashmap<ast::node_id, ast::mode>,
|
||||
borrowings: hashmap<ast::node_id, ()>,
|
||||
// maps the id of borrowed expr to scope of borrowed ptr
|
||||
borrowings: hashmap<ast::node_id, ast::node_id>,
|
||||
normalized_cache: hashmap<t, t>};
|
||||
|
||||
enum tbox_flag {
|
||||
@ -572,6 +575,8 @@ fn mk_float(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f)) }
|
||||
|
||||
fn mk_uint(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u)) }
|
||||
|
||||
fn mk_u8(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u8)) }
|
||||
|
||||
fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) }
|
||||
|
||||
fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) }
|
||||
@ -1711,25 +1716,63 @@ fn vars_in_type(ty: t) -> [ty_vid] {
|
||||
rslt
|
||||
}
|
||||
|
||||
// Returns the type and mutability of *t.
|
||||
//
|
||||
// The parameter `expl` indicates if this is an *explicit* dereference. Some
|
||||
// types---notably unsafe ptrs---can only be dereferenced explicitly.
|
||||
fn deref(cx: ctxt, t: t, expl: bool) -> option<mt> {
|
||||
deref_sty(cx, get(t).struct, expl)
|
||||
}
|
||||
fn deref_sty(cx: ctxt, sty: sty, expl: bool) -> option<mt> {
|
||||
alt sty {
|
||||
ty_rptr(_, mt) | ty_box(mt) | ty_uniq(mt) {
|
||||
some(mt)
|
||||
}
|
||||
|
||||
ty_ptr(mt) if expl {
|
||||
some(mt)
|
||||
}
|
||||
|
||||
ty_res(_, inner, substs) {
|
||||
let inner = subst(cx, substs, inner);
|
||||
some({ty: inner, mutbl: ast::m_imm})
|
||||
}
|
||||
|
||||
ty_enum(did, substs) {
|
||||
let variants = enum_variants(cx, did);
|
||||
if vec::len(*variants) == 1u && vec::len(variants[0].args) == 1u {
|
||||
let v_t = subst(cx, substs, variants[0].args[0]);
|
||||
some({ty: v_t, mutbl: ast::m_imm})
|
||||
} else {
|
||||
none
|
||||
}
|
||||
}
|
||||
|
||||
_ { none }
|
||||
}
|
||||
}
|
||||
|
||||
fn type_autoderef(cx: ctxt, t: t) -> t {
|
||||
let mut t1 = t;
|
||||
let mut t = t;
|
||||
loop {
|
||||
alt get(t1).struct {
|
||||
ty_box(mt) | ty_uniq(mt) | ty::ty_rptr(_, mt) { t1 = mt.ty; }
|
||||
ty_res(_, inner, substs) {
|
||||
t1 = subst(cx, substs, inner);
|
||||
}
|
||||
ty_enum(did, substs) {
|
||||
let variants = enum_variants(cx, did);
|
||||
if vec::len(*variants) != 1u || vec::len(variants[0].args) != 1u {
|
||||
break;
|
||||
}
|
||||
t1 = subst(cx, substs, variants[0].args[0]);
|
||||
}
|
||||
_ { break; }
|
||||
alt deref(cx, t, false) {
|
||||
none { ret t; }
|
||||
some(mt) { t = mt.ty; }
|
||||
}
|
||||
}
|
||||
ret t1;
|
||||
}
|
||||
|
||||
// Returns the type and mutability of t[i]
|
||||
fn index(cx: ctxt, t: t) -> option<mt> {
|
||||
index_sty(cx, get(t).struct)
|
||||
}
|
||||
|
||||
fn index_sty(cx: ctxt, sty: sty) -> option<mt> {
|
||||
alt sty {
|
||||
ty_vec(mt) | ty_evec(mt, _) { some(mt) }
|
||||
ty_str | ty_estr(_) { some({ty: mk_u8(cx), mutbl: ast::m_imm}) }
|
||||
_ { none }
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_bound_region(br: bound_region) -> uint {
|
||||
|
@ -8,7 +8,7 @@ import metadata::csearch;
|
||||
import driver::session::session;
|
||||
import util::common::*;
|
||||
import syntax::codemap::span;
|
||||
import pat_util::*;
|
||||
import pat_util::{pat_is_variant, pat_id_map};
|
||||
import middle::ty;
|
||||
import middle::ty::{arg, field, node_type_table, mk_nil,
|
||||
ty_param_bounds_and_ty, lookup_public_fields};
|
||||
@ -216,9 +216,17 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
ast::def_fn(id, ast::unsafe_fn) {
|
||||
// Unsafe functions can only be touched in an unsafe context
|
||||
fcx.require_unsafe(sp, "access to unsafe function");
|
||||
ret ty::lookup_item_type(fcx.ccx.tcx, id);
|
||||
}
|
||||
|
||||
ast::def_fn(id, _) | ast::def_const(id) |
|
||||
ast::def_variant(_, id) | ast::def_class(id)
|
||||
{ ret ty::lookup_item_type(fcx.ccx.tcx, id); }
|
||||
ast::def_variant(_, id) | ast::def_class(id) {
|
||||
ret ty::lookup_item_type(fcx.ccx.tcx, id);
|
||||
}
|
||||
ast::def_binding(nid) {
|
||||
assert (fcx.locals.contains_key(nid));
|
||||
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
|
||||
@ -1340,6 +1348,29 @@ impl methods for @fn_ctxt {
|
||||
fn mk_eqty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
|
||||
infer::mk_eqty(self.infcx, sub, sup)
|
||||
}
|
||||
|
||||
fn require_impure(sp: span) {
|
||||
alt self.purity {
|
||||
ast::unsafe_fn { ret; }
|
||||
ast::impure_fn | ast::crust_fn { ret; }
|
||||
ast::pure_fn {
|
||||
self.ccx.tcx.sess.span_err(
|
||||
sp,
|
||||
"found impure expression in pure function decl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn require_unsafe(sp: span, op: str) {
|
||||
alt self.purity {
|
||||
ast::unsafe_fn {/*ok*/}
|
||||
_ {
|
||||
self.ccx.tcx.sess.span_err(
|
||||
sp,
|
||||
#fmt["%s requires unsafe function or block", op]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_ty_params(ccx: @crate_ctxt, atps: [ast::ty_param])
|
||||
@ -1715,13 +1746,14 @@ mod collect {
|
||||
}
|
||||
|
||||
|
||||
// FIXME This is almost a duplicate of ty::type_autoderef, with structure_of
|
||||
// instead of ty::struct.
|
||||
fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
|
||||
let mut t1 = t;
|
||||
let mut enum_dids = [];
|
||||
loop {
|
||||
alt structure_of(fcx, sp, t1) {
|
||||
let sty = structure_of(fcx, sp, t1);
|
||||
|
||||
// Some extra checks to detect weird cycles and so forth:
|
||||
alt sty {
|
||||
ty::ty_box(inner) | ty::ty_uniq(inner) | ty::ty_rptr(_, inner) {
|
||||
alt ty::get(t1).struct {
|
||||
ty::ty_var(v1) {
|
||||
@ -1730,10 +1762,6 @@ fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
t1 = inner.ty;
|
||||
}
|
||||
ty::ty_res(_, inner, substs) {
|
||||
t1 = ty::subst(fcx.ccx.tcx, substs, inner);
|
||||
}
|
||||
ty::ty_enum(did, substs) {
|
||||
// Watch out for a type like `enum t = @t`. Such a type would
|
||||
@ -1745,14 +1773,14 @@ fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
|
||||
ret t1;
|
||||
}
|
||||
vec::push(enum_dids, did);
|
||||
|
||||
let variants = ty::enum_variants(fcx.ccx.tcx, did);
|
||||
if vec::len(*variants) != 1u || vec::len(variants[0].args) != 1u {
|
||||
ret t1;
|
||||
}
|
||||
t1 = ty::subst(fcx.ccx.tcx, substs, variants[0].args[0]);
|
||||
}
|
||||
_ { ret t1; }
|
||||
_ { /*ok*/ }
|
||||
}
|
||||
|
||||
// Otherwise, deref if type is derefable:
|
||||
alt ty::deref_sty(fcx.ccx.tcx, sty, false) {
|
||||
none { ret t1; }
|
||||
some(mt) { t1 = mt.ty; }
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1812,9 +1840,11 @@ mod demand {
|
||||
}
|
||||
|
||||
// Checks that the type `actual` can be assigned to `expected`.
|
||||
fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) {
|
||||
fn assign(fcx: @fn_ctxt, sp: span, borrow_scope: ast::node_id,
|
||||
expected: ty::t, expr: @ast::expr) {
|
||||
let expr_ty = fcx.expr_ty(expr);
|
||||
alt infer::mk_assignty(fcx.infcx, expr.id, expr_ty, expected) {
|
||||
let anmnt = {expr_id: expr.id, borrow_scope: borrow_scope};
|
||||
alt infer::mk_assignty(fcx.infcx, anmnt, expr_ty, expected) {
|
||||
result::ok(()) { /* ok */ }
|
||||
result::err(err) {
|
||||
fcx.report_mismatched_types(sp, expected, expr_ty, err);
|
||||
@ -2093,7 +2123,7 @@ fn valid_range_bounds(ccx: @crate_ctxt, from: @ast::expr, to: @ast::expr)
|
||||
|
||||
type pat_ctxt = {
|
||||
fcx: @fn_ctxt,
|
||||
map: pat_util::pat_id_map,
|
||||
map: pat_id_map,
|
||||
alt_region: ty::region,
|
||||
block_region: ty::region,
|
||||
/* Equal to either alt_region or block_region. */
|
||||
@ -2265,12 +2295,11 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
|
||||
}
|
||||
fcx.write_ty(pat.id, b_ty);
|
||||
}
|
||||
ast::pat_ident(name, sub)
|
||||
if !pat_util::pat_is_variant(tcx.def_map, pat) {
|
||||
ast::pat_ident(name, sub) if !pat_is_variant(tcx.def_map, pat) {
|
||||
let vid = lookup_local(pcx.fcx, pat.span, pat.id);
|
||||
let mut typ = ty::mk_var(tcx, vid);
|
||||
demand::suptype(pcx.fcx, pat.span, expected, typ);
|
||||
let canon_id = pcx.map.get(path_to_ident(name));
|
||||
let canon_id = pcx.map.get(pat_util::path_to_ident(name));
|
||||
if canon_id != pat.id {
|
||||
let tv_id = lookup_local(pcx.fcx, pat.span, canon_id);
|
||||
let ct = ty::mk_var(tcx, tv_id);
|
||||
@ -2383,27 +2412,6 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
|
||||
}
|
||||
}
|
||||
|
||||
fn require_unsafe(sess: session, f_purity: ast::purity, sp: span) {
|
||||
alt f_purity {
|
||||
ast::unsafe_fn { ret; }
|
||||
_ {
|
||||
sess.span_err(
|
||||
sp,
|
||||
"unsafe operation requires unsafe function or block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn require_impure(sess: session, f_purity: ast::purity, sp: span) {
|
||||
alt f_purity {
|
||||
ast::unsafe_fn { ret; }
|
||||
ast::impure_fn | ast::crust_fn { ret; }
|
||||
ast::pure_fn {
|
||||
sess.span_err(sp, "found impure expression in pure function decl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity,
|
||||
callee: @ast::expr, sp: span) {
|
||||
if caller_purity == ast::unsafe_fn { ret; }
|
||||
@ -2866,9 +2874,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
// A generic function to factor out common logic from call and bind
|
||||
// expressions.
|
||||
fn check_call_or_bind(
|
||||
fcx: @fn_ctxt, sp: span, fty: ty::t,
|
||||
fcx: @fn_ctxt, sp: span, call_expr_id: ast::node_id, fty: ty::t,
|
||||
args: [option<@ast::expr>]) -> {fty: ty::t, bot: bool} {
|
||||
|
||||
let mut bot = false;
|
||||
|
||||
let fty = universally_quantify_before_call(fcx, sp, fty);
|
||||
#debug["check_call_or_bind: after universal quant., fty=%s",
|
||||
fcx.ty_to_str(fty)];
|
||||
@ -2916,10 +2926,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
// functions. This is so that we have more information about the types
|
||||
// of arguments when we typecheck the functions. This isn't really the
|
||||
// right way to do this.
|
||||
let check_args = fn@(check_blocks: bool) -> bool {
|
||||
let mut i = 0u;
|
||||
let mut bot = false;
|
||||
for args.each {|a_opt|
|
||||
for [false, true].each { |check_blocks|
|
||||
for args.eachi {|i, a_opt|
|
||||
alt a_opt {
|
||||
some(a) {
|
||||
let is_block = alt a.node {
|
||||
@ -2930,18 +2938,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
let arg_ty = arg_tys[i];
|
||||
bot |= check_expr_with_unifier(
|
||||
fcx, a, some(arg_ty)) {||
|
||||
demand::assign(fcx, a.span, arg_ty, a);
|
||||
demand::assign(fcx, a.span, call_expr_id,
|
||||
arg_ty, a);
|
||||
};
|
||||
}
|
||||
}
|
||||
none { }
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret bot;
|
||||
};
|
||||
|
||||
let bot = check_args(false) | check_args(true);
|
||||
}
|
||||
|
||||
{fty: fty, bot: bot}
|
||||
}
|
||||
@ -2965,7 +2970,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
// Call the generic checker.
|
||||
let fty = {
|
||||
let args_opt = args.map { |arg| some(arg) };
|
||||
let r = check_call_or_bind(fcx, sp, fn_ty, args_opt);
|
||||
let r = check_call_or_bind(fcx, sp, call_expr_id,
|
||||
fn_ty, args_opt);
|
||||
bot |= r.bot;
|
||||
r.fty
|
||||
};
|
||||
@ -3046,7 +3052,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
some(origin) {
|
||||
let {fty: method_ty, bot: bot} = {
|
||||
let method_ty = fcx.node_ty(callee_id);
|
||||
check_call_or_bind(fcx, op_ex.span, method_ty, args)
|
||||
check_call_or_bind(fcx, op_ex.span, op_ex.id,
|
||||
method_ty, args)
|
||||
};
|
||||
fcx.ccx.method_map.insert(op_ex.id, origin);
|
||||
some((ty::ty_fn_ret(method_ty), bot))
|
||||
@ -3257,7 +3264,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
bot |= check_binop(fcx, expr, op, lhs, rhs);
|
||||
}
|
||||
ast::expr_assign_op(op, lhs, rhs) {
|
||||
require_impure(tcx.sess, fcx.purity, expr.span);
|
||||
fcx.require_impure(expr.span);
|
||||
bot |= check_binop(fcx, expr, op, lhs, rhs);
|
||||
let lhs_t = fcx.expr_ty(lhs);
|
||||
let result_t = fcx.expr_ty(expr);
|
||||
@ -3291,30 +3298,37 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
oper_t = ty::mk_uniq(tcx, {ty: oper_t, mutbl: mutbl});
|
||||
}
|
||||
ast::deref {
|
||||
alt structure_of(fcx, expr.span, oper_t) {
|
||||
ty::ty_box(inner) { oper_t = inner.ty; }
|
||||
ty::ty_uniq(inner) { oper_t = inner.ty; }
|
||||
ty::ty_res(_, inner, _) { oper_t = inner; }
|
||||
ty::ty_enum(id, substs) {
|
||||
let variants = ty::enum_variants(tcx, id);
|
||||
if vec::len(*variants) != 1u ||
|
||||
vec::len(variants[0].args) != 1u {
|
||||
tcx.sess.span_fatal(expr.span,
|
||||
"can only dereference enums " +
|
||||
"with a single variant which has a "
|
||||
+ "single argument");
|
||||
let sty = structure_of(fcx, expr.span, oper_t);
|
||||
|
||||
// deref'ing an unsafe pointer requires that we be in an unsafe
|
||||
// context
|
||||
alt sty {
|
||||
ty::ty_ptr(*) {
|
||||
fcx.require_unsafe(
|
||||
expr.span,
|
||||
"dereference of unsafe pointer");
|
||||
}
|
||||
_ { /*ok*/ }
|
||||
}
|
||||
|
||||
alt ty::deref_sty(tcx, sty, true) {
|
||||
some(mt) { oper_t = mt.ty }
|
||||
none {
|
||||
alt sty {
|
||||
ty::ty_enum(*) {
|
||||
tcx.sess.span_fatal(
|
||||
expr.span,
|
||||
"can only dereference enums \
|
||||
with a single variant which has a \
|
||||
single argument");
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_fatal(
|
||||
expr.span,
|
||||
#fmt["type %s cannot be dereferenced",
|
||||
fcx.ty_to_str(oper_t)]);
|
||||
}
|
||||
}
|
||||
oper_t = ty::subst(tcx, substs, variants[0].args[0]);
|
||||
}
|
||||
ty::ty_ptr(inner) {
|
||||
oper_t = inner.ty;
|
||||
require_unsafe(tcx.sess, fcx.purity, expr.span);
|
||||
}
|
||||
ty::ty_rptr(_, inner) { oper_t = inner.ty; }
|
||||
_ {
|
||||
tcx.sess.span_err(expr.span,
|
||||
#fmt("Type %s cannot be dereferenced",
|
||||
ty_to_str(tcx, oper_t)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3410,21 +3424,20 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
fcx.write_ty(id, fcx.expr_ty(a));
|
||||
}
|
||||
ast::expr_move(lhs, rhs) {
|
||||
require_impure(tcx.sess, fcx.purity, expr.span);
|
||||
fcx.require_impure(expr.span);
|
||||
bot = check_assignment(fcx, expr.span, lhs, rhs, id);
|
||||
}
|
||||
ast::expr_assign(lhs, rhs) {
|
||||
require_impure(tcx.sess, fcx.purity, expr.span);
|
||||
fcx.require_impure(expr.span);
|
||||
bot = check_assignment(fcx, expr.span, lhs, rhs, id);
|
||||
}
|
||||
ast::expr_swap(lhs, rhs) {
|
||||
require_impure(tcx.sess, fcx.purity, expr.span);
|
||||
fcx.require_impure(expr.span);
|
||||
bot = check_assignment(fcx, expr.span, lhs, rhs, id);
|
||||
}
|
||||
ast::expr_if(cond, thn, elsopt) {
|
||||
bot =
|
||||
check_expr_with(fcx, cond, ty::mk_bool(tcx)) |
|
||||
check_then_else(fcx, thn, elsopt, id, expr.span);
|
||||
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) |
|
||||
check_then_else(fcx, thn, elsopt, id, expr.span);
|
||||
}
|
||||
ast::expr_while(cond, body) {
|
||||
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx));
|
||||
@ -3451,7 +3464,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
for arms.each {|arm|
|
||||
let pcx = {
|
||||
fcx: fcx,
|
||||
map: pat_util::pat_id_map(tcx.def_map, arm.pats[0]),
|
||||
map: pat_id_map(tcx.def_map, arm.pats[0]),
|
||||
alt_region: ty::re_scope(expr.id),
|
||||
block_region: ty::re_scope(arm.body.node.id),
|
||||
pat_region: ty::re_scope(expr.id)
|
||||
@ -3545,7 +3558,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
|
||||
let {fty, bot: ccob_bot} = {
|
||||
let fn_ty = fcx.expr_ty(f);
|
||||
check_call_or_bind(fcx, expr.span, fn_ty, args)
|
||||
check_call_or_bind(fcx, expr.span, expr.id, fn_ty, args)
|
||||
};
|
||||
bot |= ccob_bot;
|
||||
|
||||
@ -3792,19 +3805,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
let base_t = do_autoderef(fcx, expr.span, raw_base_t);
|
||||
bot |= check_expr(fcx, idx, none);
|
||||
let idx_t = fcx.expr_ty(idx);
|
||||
alt structure_of(fcx, expr.span, base_t) {
|
||||
ty::ty_evec(mt, _) |
|
||||
ty::ty_vec(mt) {
|
||||
alt ty::index_sty(tcx, structure_of(fcx, expr.span, base_t)) {
|
||||
some(mt) {
|
||||
require_integral(fcx, idx.span, idx_t);
|
||||
fcx.write_ty(id, mt.ty);
|
||||
}
|
||||
ty::ty_estr(_) |
|
||||
ty::ty_str {
|
||||
require_integral(fcx, idx.span, idx_t);
|
||||
let typ = ty::mk_mach_uint(tcx, ast::ty_u8);
|
||||
fcx.write_ty(id, typ);
|
||||
}
|
||||
_ {
|
||||
none {
|
||||
let resolved = structurally_resolved_type(fcx, expr.span,
|
||||
raw_base_t);
|
||||
alt lookup_op_method(fcx, expr, resolved, "[]",
|
||||
@ -3919,7 +3925,7 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {
|
||||
fcx.ccx.tcx.region_map.local_blocks.get(local.node.id));
|
||||
let pcx = {
|
||||
fcx: fcx,
|
||||
map: pat_util::pat_id_map(fcx.ccx.tcx.def_map, local.node.pat),
|
||||
map: pat_id_map(fcx.ccx.tcx.def_map, local.node.pat),
|
||||
alt_region: region,
|
||||
block_region: region,
|
||||
pat_region: region
|
||||
|
@ -39,12 +39,12 @@ mod middle {
|
||||
mod ast_map;
|
||||
mod resolve;
|
||||
mod typeck;
|
||||
mod fn_usage;
|
||||
mod check_loop;
|
||||
mod check_alt;
|
||||
mod check_const;
|
||||
mod lint;
|
||||
mod mutbl;
|
||||
mod borrowck;
|
||||
mod alias;
|
||||
mod last_use;
|
||||
mod block_use;
|
||||
|
17
src/test/compile-fail/borrowck-hold-box.rs
Normal file
17
src/test/compile-fail/borrowck-hold-box.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn borrow(v: &int, f: fn(x: &int)) {
|
||||
f(v);
|
||||
}
|
||||
|
||||
fn box_imm() {
|
||||
let mut v = ~3;
|
||||
borrow(v) { |w| //! NOTE loan of mutable local variable granted here
|
||||
v = ~4; //! ERROR cannot assign to mutable local variable due to outstanding loan
|
||||
assert *v == 3;
|
||||
assert *w == 4;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
26
src/test/compile-fail/borrowck-lend-args.rs
Normal file
26
src/test/compile-fail/borrowck-lend-args.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn borrow(_v: &int) {}
|
||||
|
||||
fn borrow_from_arg_imm_ref(&&v: ~int) {
|
||||
borrow(v); // ERROR unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn borrow_from_arg_mut_ref(&v: ~int) {
|
||||
borrow(v); //! ERROR unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn borrow_from_arg_move(-v: ~int) {
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn borrow_from_arg_copy(+v: ~int) {
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn borrow_from_arg_val(++v: ~int) {
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
96
src/test/compile-fail/borrowck-lend-flow.rs
Normal file
96
src/test/compile-fail/borrowck-lend-flow.rs
Normal file
@ -0,0 +1,96 @@
|
||||
// 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
|
||||
// either genuine or would require more advanced changes. The latter
|
||||
// cases are noted.
|
||||
|
||||
fn borrow(_v: &int) {}
|
||||
|
||||
fn inc(v: &mut ~int) {
|
||||
*v = ~(**v + 1);
|
||||
}
|
||||
|
||||
fn post_aliased_const() {
|
||||
let mut v = ~3;
|
||||
borrow(v);
|
||||
let _w = &const v;
|
||||
}
|
||||
|
||||
fn post_aliased_mut() {
|
||||
// SPURIOUS--flow
|
||||
let mut v = ~3;
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
let _w = &mut v; //! NOTE prior loan as mutable granted here
|
||||
}
|
||||
|
||||
fn post_aliased_scope(cond: bool) {
|
||||
// NDM--scope of &
|
||||
let mut v = ~3;
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
if cond { inc(&mut v); } //! NOTE prior loan as mutable granted here
|
||||
}
|
||||
|
||||
fn loop_aliased_mut() {
|
||||
let mut v = ~3, w = ~4;
|
||||
let mut _x = &mut w;
|
||||
loop {
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
_x = &mut v; //! NOTE prior loan as mutable granted here
|
||||
}
|
||||
}
|
||||
|
||||
fn while_aliased_mut(cond: bool) {
|
||||
let mut v = ~3, w = ~4;
|
||||
let mut _x = &mut w;
|
||||
while cond {
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
_x = &mut v; //! NOTE prior loan as mutable granted here
|
||||
}
|
||||
}
|
||||
|
||||
fn while_aliased_mut_cond(cond: bool, cond2: bool) {
|
||||
let mut v = ~3, w = ~4;
|
||||
let mut _x = &mut w;
|
||||
while cond {
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
if cond2 {
|
||||
_x = &mut v; //! NOTE prior loan as mutable granted here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn do_while_aliased_mut(cond: bool) {
|
||||
let mut v = ~3, w = ~4;
|
||||
let mut _x = &mut w;
|
||||
do {
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
_x = &mut v; //! NOTE prior loan as mutable granted here
|
||||
} while cond;
|
||||
}
|
||||
|
||||
fn loop_in_block() {
|
||||
let mut v = ~3, w = ~4;
|
||||
let mut _x = &mut w;
|
||||
uint::range(0u, 10u) {|_i|
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
_x = &mut v; //! NOTE prior loan as mutable granted here
|
||||
}
|
||||
}
|
||||
|
||||
fn at_most_once_block() {
|
||||
fn at_most_once(f: fn()) { f() }
|
||||
|
||||
// Here, the borrow check has no way of knowing that the block is
|
||||
// executed at most once.
|
||||
|
||||
let mut v = ~3, w = ~4;
|
||||
let mut _x = &mut w;
|
||||
at_most_once {||
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
_x = &mut v; //! NOTE prior loan as mutable granted here
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
21
src/test/compile-fail/borrowck-pat-enum-in-box.rs
Normal file
21
src/test/compile-fail/borrowck-pat-enum-in-box.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn match_imm_box(v: &const @option<int>) -> int {
|
||||
alt *v {
|
||||
@some(i) {i}
|
||||
@none {0}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_const_box(v: &const @const option<int>) -> int {
|
||||
alt *v {
|
||||
@some(i) {
|
||||
//!^ ERROR enum variant in aliasable, mutable location
|
||||
i
|
||||
}
|
||||
@none {0}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
45
src/test/compile-fail/borrowck-pat-enum.rs
Normal file
45
src/test/compile-fail/borrowck-pat-enum.rs
Normal file
@ -0,0 +1,45 @@
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn match_ref(&&v: option<int>) -> int {
|
||||
alt v {
|
||||
some(i) {
|
||||
//^ ERROR enum variant in aliasable, mutable location
|
||||
i
|
||||
}
|
||||
none {0}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_ref_unused(&&v: option<int>) {
|
||||
alt v {
|
||||
some(_) {}
|
||||
none {}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_const_reg(v: &const option<int>) -> int {
|
||||
alt *v {
|
||||
some(i) {
|
||||
//!^ ERROR enum variant in aliasable, mutable location
|
||||
i
|
||||
}
|
||||
none {0}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_const_reg_unused(v: &const option<int>) {
|
||||
alt *v {
|
||||
some(_) {}
|
||||
none {}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_imm_reg(v: &option<int>) -> int {
|
||||
alt *v {
|
||||
some(i) {i}
|
||||
none {0}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
14
src/test/compile-fail/borrowck-pat-reassign-binding.rs
Normal file
14
src/test/compile-fail/borrowck-pat-reassign-binding.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// compile-flags:--borrowck=err
|
||||
// xfail-pretty -- comments are infaithfully preserved
|
||||
|
||||
fn main() {
|
||||
let mut x: option<int> = none;
|
||||
alt x { //! NOTE loan of mutable local variable granted here
|
||||
none {}
|
||||
some(i) {
|
||||
// Not ok: i is an outstanding ptr into x.
|
||||
x = some(i+1);
|
||||
//!^ ERROR cannot assign to mutable local variable due to outstanding loan
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// compile-flags:--borrowck=err
|
||||
// xfail-pretty -- comments are infaithfully preserved
|
||||
|
||||
fn main() {
|
||||
let mut x = none;
|
||||
alt x { //! NOTE loan of mutable local variable granted here
|
||||
none {
|
||||
// It is ok to reassign x here, because there is in
|
||||
// fact no outstanding loan of x!
|
||||
x = some(0);
|
||||
}
|
||||
some(i) {
|
||||
x = some(1); //! ERROR cannot assign to mutable local variable due to outstanding loan
|
||||
}
|
||||
}
|
||||
}
|
55
src/test/compile-fail/borrowck-uniq-via-box.rs
Normal file
55
src/test/compile-fail/borrowck-uniq-via-box.rs
Normal file
@ -0,0 +1,55 @@
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn borrow(_v: &int) {}
|
||||
|
||||
fn box_mut(v: @mut ~int) {
|
||||
borrow(*v); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
|
||||
}
|
||||
|
||||
fn box_rec_mut(v: @{mut f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_mut_rec(v: @mut {f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_mut_recs(v: @mut {f: {g: {h: ~int}}}) {
|
||||
borrow(v.f.g.h); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_imm(v: @~int) {
|
||||
borrow(*v); // OK
|
||||
}
|
||||
|
||||
fn box_imm_rec(v: @{f: ~int}) {
|
||||
borrow(v.f); // OK
|
||||
}
|
||||
|
||||
fn box_imm_recs(v: @{f: {g: {h: ~int}}}) {
|
||||
borrow(v.f.g.h); // OK
|
||||
}
|
||||
|
||||
fn box_const(v: @const ~int) {
|
||||
borrow(*v); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_rec_const(v: @{const f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_recs_const(v: @{f: {g: {const h: ~int}}}) {
|
||||
borrow(v.f.g.h); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_const_rec(v: @const {f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_const_recs(v: @const {f: {g: {h: ~int}}}) {
|
||||
borrow(v.f.g.h); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
52
src/test/compile-fail/borrowck-uniq-via-lend.rs
Normal file
52
src/test/compile-fail/borrowck-uniq-via-lend.rs
Normal file
@ -0,0 +1,52 @@
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn borrow(_v: &int) {}
|
||||
|
||||
fn local() {
|
||||
let mut v = ~3;
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn local_rec() {
|
||||
let mut v = {f: ~3};
|
||||
borrow(v.f);
|
||||
}
|
||||
|
||||
fn local_recs() {
|
||||
let mut v = {f: {g: {h: ~3}}};
|
||||
borrow(v.f.g.h);
|
||||
}
|
||||
|
||||
fn aliased_imm() { // NDM: Spurious
|
||||
let mut v = ~3;
|
||||
let _w = &v; //! ERROR illegal borrow: mutability mismatch, required immutable but found mutable
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn aliased_const() {
|
||||
let mut v = ~3;
|
||||
let _w = &const v;
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn aliased_mut() {
|
||||
let mut v = ~3;
|
||||
let _w = &mut v; //! NOTE prior loan as mutable granted here
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
}
|
||||
|
||||
fn aliased_other() {
|
||||
let mut v = ~3, w = ~4;
|
||||
let _x = &mut w;
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn aliased_other_reassign() {
|
||||
let mut v = ~3, w = ~4;
|
||||
let mut _x = &mut w;
|
||||
_x = &mut v; //! NOTE prior loan as mutable granted here
|
||||
borrow(v); //! ERROR loan of mutable local variable as immutable conflicts with prior loan
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
54
src/test/compile-fail/borrowck-uniq-via-ref.rs
Normal file
54
src/test/compile-fail/borrowck-uniq-via-ref.rs
Normal file
@ -0,0 +1,54 @@
|
||||
// compile-flags:--borrowck=err
|
||||
fn borrow(_v: &int) {}
|
||||
|
||||
fn box_mut(v: &mut ~int) {
|
||||
borrow(*v); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
|
||||
}
|
||||
|
||||
fn box_rec_mut(v: &{mut f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_mut_rec(v: &mut {f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_mut_recs(v: &mut {f: {g: {h: ~int}}}) {
|
||||
borrow(v.f.g.h); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_imm(v: &~int) {
|
||||
borrow(*v); // OK
|
||||
}
|
||||
|
||||
fn box_imm_rec(v: &{f: ~int}) {
|
||||
borrow(v.f); // OK
|
||||
}
|
||||
|
||||
fn box_imm_recs(v: &{f: {g: {h: ~int}}}) {
|
||||
borrow(v.f.g.h); // OK
|
||||
}
|
||||
|
||||
fn box_const(v: &const ~int) {
|
||||
borrow(*v); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_rec_const(v: &{const f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_recs_const(v: &{f: {g: {const h: ~int}}}) {
|
||||
borrow(v.f.g.h); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_const_rec(v: &const {f: ~int}) {
|
||||
borrow(v.f); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn box_const_recs(v: &const {f: {g: {h: ~int}}}) {
|
||||
borrow(v.f.g.h); //! ERROR illegal borrow: unique value in aliasable, mutable location
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
// error-pattern: generic bare functions can only be called or bound
|
||||
// Issue #1038
|
||||
|
||||
fn main() {
|
||||
fn foo<T>() { }
|
||||
|
||||
// This wants to build a closure over type int,
|
||||
// but there's no way to do that while still being a bare function
|
||||
let f: fn() = foo::<int>;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
// error-pattern: generic bare functions can only be called or bound
|
||||
// Issue #1038
|
||||
|
||||
fn main() {
|
||||
fn foo<T>(i: T) { }
|
||||
|
||||
// This wants to build a closure over type int,
|
||||
// but there's no way to do that while still being a bare function
|
||||
f(foo);
|
||||
}
|
||||
|
||||
fn f(i: fn(&&int)) {
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
// -*- rust -*-
|
||||
// error-pattern: unsafe functions can only be called
|
||||
|
||||
#[abi = "cdecl"]
|
||||
native mod test {
|
||||
@ -8,6 +7,7 @@ native mod test {
|
||||
|
||||
fn main() {
|
||||
let x = test::free;
|
||||
//!^ ERROR access to unsafe function requires unsafe function or block
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,10 +2,10 @@
|
||||
// This generates a ton of error msgs at the moment.
|
||||
fn broken() -> int {
|
||||
let mut x = 3;
|
||||
let mut y = [&x]; //! ERROR reference is not valid
|
||||
let mut y = [&mut x]; //! ERROR reference is not valid
|
||||
while x < 10 {
|
||||
let z = x;
|
||||
y += [&z];
|
||||
let mut z = x;
|
||||
y += [&mut z];
|
||||
x += 1;
|
||||
}
|
||||
vec::foldl(0, y) {|v, p| v + *p }
|
||||
|
@ -1,11 +1,9 @@
|
||||
// -*- rust -*-
|
||||
// error-pattern: unsafe operation requires unsafe function or block
|
||||
|
||||
fn f(p: *u8) {
|
||||
*p = 0u8;
|
||||
*p = 0u8; //! ERROR dereference of unsafe pointer requires unsafe function or block
|
||||
ret;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f();
|
||||
}
|
||||
|
22
src/test/compile-fail/unsafe-fn-autoderef.rs
Normal file
22
src/test/compile-fail/unsafe-fn-autoderef.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// -*- rust -*-
|
||||
|
||||
type rec = {f: int};
|
||||
fn f(p: *rec) -> int {
|
||||
|
||||
// Test that * ptrs do not autoderef. There is a deeper reason for
|
||||
// prohibiting this, beyond making unsafe things annoying (which doesn't
|
||||
// actually seem desirable to me). The deeper reason is that if you
|
||||
// have a type like:
|
||||
//
|
||||
// enum foo = *foo;
|
||||
//
|
||||
// you end up with an infinite auto-deref chain, which is
|
||||
// currently impossible (in all other cases, infinite auto-derefs
|
||||
// are prohibited by various checks, such as that the enum is
|
||||
// instantiable and so forth).
|
||||
|
||||
ret p.f; //! ERROR attempted access of field f on type *rec
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
// -*- rust -*-
|
||||
// error-pattern: unsafe operation requires unsafe function or block
|
||||
|
||||
fn f(p: *u8) -> u8 {
|
||||
ret *p;
|
||||
ret *p; //! ERROR dereference of unsafe pointer requires unsafe function or block
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f();
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
// -*- rust -*-
|
||||
// error-pattern: unsafe functions can only be called
|
||||
|
||||
unsafe fn f() { ret; }
|
||||
|
||||
fn main() {
|
||||
let x = f;
|
||||
let x = f; //! ERROR access to unsafe function requires unsafe function or block
|
||||
x();
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
// -*- rust -*-
|
||||
// error-pattern: unsafe functions can only be called
|
||||
|
||||
unsafe fn f(x: int, y: int) -> int { ret x + y; }
|
||||
|
||||
fn main() {
|
||||
let x = bind f(3, _);
|
||||
//!^ ERROR access to unsafe function requires unsafe function or block
|
||||
let y = x(4);
|
||||
}
|
||||
|
13
src/test/run-pass/borrowck-pat-reassign-no-binding.rs
Normal file
13
src/test/run-pass/borrowck-pat-reassign-no-binding.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn main() {
|
||||
let mut x = none;
|
||||
alt x {
|
||||
none {
|
||||
// It is ok to reassign x here, because there is in
|
||||
// fact no outstanding loan of x!
|
||||
x = some(0);
|
||||
}
|
||||
some(_) { }
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user