Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsafe pre snapshot #1033

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/comp/driver/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ options:
--test build test harness
--gc garbage collect shared data (experimental/temporary)
--stack-growth perform stack checks (experimental)
--check-unsafe disallow unsafe actions in non-unsafe functions

");
}
Expand Down Expand Up @@ -322,6 +323,7 @@ fn build_session_options(match: getopts::match)

let parse_only = opt_present(match, "parse-only");
let no_trans = opt_present(match, "no-trans");
let check_unsafe = opt_present(match, "check-unsafe");

let output_type =
if parse_only || no_trans {
Expand Down Expand Up @@ -393,7 +395,8 @@ fn build_session_options(match: getopts::match)
parse_only: parse_only,
no_trans: no_trans,
do_gc: do_gc,
stack_growth: stack_growth};
stack_growth: stack_growth,
check_unsafe: check_unsafe};
ret sopts;
}

Expand Down Expand Up @@ -432,7 +435,7 @@ fn opts() -> [getopts::opt] {
optflag("no-typestate"), optflag("noverify"),
optmulti("cfg"), optflag("test"),
optflag("lib"), optflag("static"), optflag("gc"),
optflag("stack-growth")];
optflag("stack-growth"), optflag("check-unsafe")];
}

fn main(args: [str]) {
Expand Down
3 changes: 2 additions & 1 deletion src/comp/driver/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ type options =
parse_only: bool,
no_trans: bool,
do_gc: bool,
stack_growth: bool};
stack_growth: bool,
check_unsafe: bool};

type crate_metadata = {name: str, data: [u8]};

Expand Down
5 changes: 3 additions & 2 deletions src/comp/front/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ fn mk_tests(cx: test_ctxt) -> @ast::item {
let test_descs = mk_test_desc_vec(cx);

let body_: ast::blk_ =
checked_blk([], option::some(test_descs), cx.next_node_id());
default_block([], option::some(test_descs), cx.next_node_id());
let body = nospan(body_);

let fn_ = {decl: decl, proto: proto, body: body};
Expand Down Expand Up @@ -303,7 +303,8 @@ fn mk_main(cx: test_ctxt) -> @ast::item {
let test_main_call_expr = mk_test_main_call(cx);

let body_: ast::blk_ =
checked_blk([], option::some(test_main_call_expr), cx.next_node_id());
default_block([], option::some(test_main_call_expr),
cx.next_node_id());
let body = {node: body_, span: dummy_sp()};

let fn_ = {decl: decl, proto: proto, body: body};
Expand Down
7 changes: 6 additions & 1 deletion src/comp/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,12 @@ fn lookup_def(cnum: ast::crate_num, data: @[u8], did_: ast::def_id) ->
let def =
alt fam_ch as char {
'c' { ast::def_const(did) }
'u' { ast::def_fn(did, ast::unsafe_fn) }
'f' { ast::def_fn(did, ast::impure_fn) }
'p' { ast::def_fn(did, ast::pure_fn) }
'F' { ast::def_native_fn(did) }
'U' { ast::def_native_fn(did, ast::unsafe_fn) }
'F' { ast::def_native_fn(did, ast::impure_fn) }
'P' { ast::def_native_fn(did, ast::pure_fn) }
'y' { ast::def_ty(did) }
'T' { ast::def_native_ty(did) }
't' { ast::def_ty(did) }
Expand Down Expand Up @@ -250,6 +253,7 @@ fn family_has_type_params(fam_ch: u8) -> bool {
ret alt fam_ch as char {
'c' { false }
'f' { true }
'u' { true }
'p' { true }
'F' { true }
'y' { true }
Expand Down Expand Up @@ -278,6 +282,7 @@ fn item_family_to_str(fam: u8) -> str {
alt fam as char {
'c' { ret "const"; }
'f' { ret "fn"; }
'u' { ret "unsafe fn"; }
'p' { ret "pure fn"; }
'F' { ret "native fn"; }
'y' { ret "type"; }
Expand Down
11 changes: 9 additions & 2 deletions src/comp/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w,
alt fd.decl.purity {
unsafe_fn. { 'u' }
pure_fn. { 'p' }
impure_fn. { 'f' }
} as u8);
Expand Down Expand Up @@ -349,9 +350,15 @@ fn encode_info_for_native_item(ecx: @encode_ctxt, ebml_w: ebml::writer,
encode_type(ecx, ebml_w,
ty::mk_native(ecx.ccx.tcx, local_def(nitem.id)));
}
native_item_fn(_, _, tps) {
native_item_fn(_, fn_decl, tps) {
let letter =
alt fn_decl.purity {
unsafe_fn. { 'U' }
pure_fn. { 'P' } // this is currently impossible, but hey.
impure_fn. { 'F' }
} as u8;
encode_def_id(ebml_w, local_def(nitem.id));
encode_family(ebml_w, 'F' as u8);
encode_family(ebml_w, letter);
encode_type_param_kinds(ebml_w, tps);
encode_type(ecx, ebml_w, node_id_to_monotype(ecx.ccx.tcx, nitem.id));
encode_symbol(ecx, ebml_w, nitem.id);
Expand Down
40 changes: 22 additions & 18 deletions src/comp/middle/alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ tag ret_info { by_ref(bool, node_id); other; }
type scope = {bs: [binding], ret_info: ret_info};

fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option::t<node_id>,
unsafe: [unsafe_ty]) -> binding {
unsafe_tys: [unsafe_ty]) -> binding {
ret @{node_id: id, span: span, root_var: root_var,
local_id: local_id_of_node(cx, id),
unsafe_tys: unsafe, mutable ok: valid,
unsafe_tys: unsafe_tys, mutable ok: valid,
mutable copied: not_copied};
}

Expand Down Expand Up @@ -284,12 +284,12 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
}
let j = 0u;
for b in bindings {
for unsafe in b.unsafe_tys {
for unsafe_ty in b.unsafe_tys {
let i = 0u;
for arg_t: ty::arg in arg_ts {
let mut_alias = arg_t.mode == ast::by_mut_ref;
if i != j &&
ty_can_unsafely_include(cx, unsafe, arg_t.ty,
ty_can_unsafely_include(cx, unsafe_ty, arg_t.ty,
mut_alias) &&
cant_copy(cx, b) {
cx.tcx.sess.span_err
Expand Down Expand Up @@ -397,24 +397,28 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
let new_bs = sc.bs;
let root_var = path_def_id(cx, root.ex);
let pat_id_map = ast_util::pat_id_map(a.pats[0]);
type info = {id: node_id, mutable unsafe: [unsafe_ty], span: span};
type info = {
id: node_id,
mutable unsafe_tys: [unsafe_ty],
span: span};
let binding_info: [info] = [];
for pat in a.pats {
for proot in pattern_roots(cx.tcx, root.mut, pat) {
let canon_id = pat_id_map.get(proot.name);
alt vec::find({|x| x.id == canon_id}, binding_info) {
some(s) { s.unsafe += unsafe_set(proot.mut); }
some(s) { s.unsafe_tys += unsafe_set(proot.mut); }
none. {
binding_info += [{id: canon_id,
mutable unsafe: unsafe_set(proot.mut),
span: proot.span}];
binding_info += [
{id: canon_id,
mutable unsafe_tys: unsafe_set(proot.mut),
span: proot.span}];
}
}
}
}
for info in binding_info {
new_bs += [mk_binding(cx, info.id, info.span, root_var,
copy info.unsafe)];
copy info.unsafe_tys)];
}
visit::visit_arm(a, {bs: new_bs with sc}, v);
}
Expand Down Expand Up @@ -470,8 +474,8 @@ fn check_var(cx: ctx, ex: @ast::expr, p: ast::path, id: ast::node_id,
for b in sc.bs {
// excludes variables introduced since the alias was made
if my_local_id < b.local_id {
for unsafe in b.unsafe_tys {
if ty_can_unsafely_include(cx, unsafe, var_t, assign) {
for unsafe_ty in b.unsafe_tys {
if ty_can_unsafely_include(cx, unsafe_ty, var_t, assign) {
b.ok = val_taken(ex.span, p);
}
}
Expand Down Expand Up @@ -689,9 +693,9 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat)
fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool)
-> {ex: @ast::expr, mut: option::t<unsafe_ty>} {
let base_root = mut::expr_root(cx.tcx, ex, autoderef);
let unsafe = none;
let unsafe_ty = none;
for d in *base_root.ds {
if d.mut { unsafe = some(contains(d.outer_t)); break; }
if d.mut { unsafe_ty = some(contains(d.outer_t)); break; }
}
if is_none(path_def_id(cx, base_root.ex)) {
alt base_root.ex.node {
Expand All @@ -703,18 +707,18 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool)
let arg_root = expr_root(cx, arg, false);
if mut {
let ret_ty = ty::expr_ty(cx.tcx, base_root.ex);
unsafe = some(mut_contains(ret_ty));
unsafe_ty = some(mut_contains(ret_ty));
}
if !is_none(arg_root.mut) { unsafe = arg_root.mut; }
ret {ex: arg_root.ex, mut: unsafe};
if !is_none(arg_root.mut) { unsafe_ty = arg_root.mut; }
ret {ex: arg_root.ex, mut: unsafe_ty};
}
_ {}
}
}
_ {}
}
}
ret {ex: base_root.ex, mut: unsafe};
ret {ex: base_root.ex, mut: unsafe_ty};
}

fn unsafe_set(from: option::t<unsafe_ty>) -> [unsafe_ty] {
Expand Down
8 changes: 5 additions & 3 deletions src/comp/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1059,9 +1059,11 @@ fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) ->
ret some(ast::def_native_ty(local_def(native_item.id)));
}
}
ast::native_item_fn(_, _, _) {
ast::native_item_fn(_, decl, _) {
if ns == ns_value {
ret some(ast::def_native_fn(local_def(native_item.id)));
ret some(ast::def_native_fn(
local_def(native_item.id),
decl.purity));
}
}
}
Expand Down Expand Up @@ -1163,7 +1165,7 @@ fn ns_for_def(d: def) -> namespace {
ast::def_binding(_) { ns_type }
ast::def_use(_) { ns_module }
ast::def_native_ty(_) { ns_type }
ast::def_native_fn(_) { ns_value }
ast::def_native_fn(_, _) { ns_value }
};
}

Expand Down
6 changes: 3 additions & 3 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3095,7 +3095,7 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
-> lval_maybe_callee {
let ccx = bcx_ccx(cx);
alt def {
ast::def_fn(did, _) | ast::def_native_fn(did) {
ast::def_fn(did, _) | ast::def_native_fn(did, _) {
let tyt = ty::lookup_item_type(ccx.tcx, did);
ret lval_static_fn(cx, tyt, did, id);
}
Expand Down Expand Up @@ -4379,11 +4379,11 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
assert dest == ignore;
ret trans_check_expr(bcx, a, "Assertion");
}
ast::expr_check(ast::checked., a) {
ast::expr_check(ast::checked_expr., a) {
assert dest == ignore;
ret trans_check_expr(bcx, a, "Predicate");
}
ast::expr_check(ast::unchecked., a) {
ast::expr_check(ast::claimed_expr., a) {
assert dest == ignore;
/* Claims are turned on and off by a global variable
that the RTS sets. This case generates code to
Expand Down
2 changes: 1 addition & 1 deletion src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2602,7 +2602,7 @@ fn def_has_ty_params(def: ast::def) -> bool {
ast::def_binding(_) { ret false; }
ast::def_use(_) { ret false; }
ast::def_native_ty(_) { ret false; }
ast::def_native_fn(_) { ret true; }
ast::def_native_fn(_, _) { ret true; }
}
}

Expand Down
55 changes: 46 additions & 9 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
ret {kinds: no_kinds, ty: typ};
}
ast::def_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_native_fn(id) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_native_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_const(id) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_variant(_, vid) { ret ty::lookup_item_type(fcx.ccx.tcx, vid); }
ast::def_binding(id) {
Expand Down Expand Up @@ -1523,8 +1523,22 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
}
}

fn require_unsafe(sess: session::session, f_purity: ast::purity, sp: span) {
if sess.get_opts().check_unsafe {
alt f_purity {
ast::unsafe_fn. { ret; }
_ {
sess.span_fatal(
sp,
"Found unsafe expression in safe function decl");
}
}
}
}

fn require_impure(sess: session::session, f_purity: ast::purity, sp: span) {
alt f_purity {
ast::unsafe_fn. { ret; }
ast::impure_fn. { ret; }
ast::pure_fn. {
sess.span_fatal(sp, "Found impure expression in pure function decl");
Expand All @@ -1535,7 +1549,29 @@ fn require_impure(sess: session::session, f_purity: ast::purity, sp: span) {
fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity,
callee: @ast::expr, sp: span) {
alt caller_purity {
ast::impure_fn. { ret; }
ast::unsafe_fn. { ret; }
ast::impure_fn. {
let sess = ccx.tcx.sess;
alt ccx.tcx.def_map.find(callee.id) {
some(ast::def_fn(_, ast::unsafe_fn.)) {
if sess.get_opts().check_unsafe {
ccx.tcx.sess.span_fatal(
sp,
"safe function calls function marked unsafe");
}
}
some(ast::def_native_fn(_, ast::unsafe_fn.)) {
if sess.get_opts().check_unsafe {
ccx.tcx.sess.span_fatal(
sp,
"native functions can only be invoked from unsafe code");
}
}
_ {
}
}
ret;
}
ast::pure_fn. {
alt ccx.tcx.def_map.find(callee.id) {
some(ast::def_fn(_, ast::pure_fn.)) { ret; }
Expand Down Expand Up @@ -1857,6 +1893,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
ast::expr_path(pth) {
let defn = lookup_def(fcx, pth.span, id);

let tpt = ty_param_kinds_and_ty_for_def(fcx, expr.span, defn);
if ty::def_has_ty_params(defn) {
let path_tpot = instantiate_path(fcx, pth, tpt, expr.span);
Expand Down Expand Up @@ -2063,12 +2100,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
ast::expr_block(b) {
// If this is an unchecked block, turn off purity-checking
let fcx_for_block =
alt b.node.rules {
ast::unchecked. { @{purity: ast::impure_fn with *fcx} }
_ { fcx }
};
bot = check_block(fcx_for_block, b);
bot = check_block(fcx, b);
let typ =
alt b.node.expr {
some(expr) { expr_ty(tcx, expr) }
Expand Down Expand Up @@ -2525,7 +2557,12 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool {
ret bot;
}

fn check_block(fcx: @fn_ctxt, blk: ast::blk) -> bool {
fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
let fcx = alt blk.node.rules {
ast::unchecked_blk. { @{purity: ast::impure_fn with *fcx0} }
ast::unsafe_blk. { @{purity: ast::unsafe_fn with *fcx0} }
ast::default_blk. { fcx0 }
};
let bot = false;
let warned = false;
for s: @ast::stmt in blk.node.stmts {
Expand Down
Loading