From 00bf46175f8b07cdf5671818a15c232b62f68749 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 6 Oct 2011 15:29:54 -0700 Subject: [PATCH 01/12] expand purity to include unsafe --- src/comp/middle/alias.rs | 40 ++++++++++++++++++--------------- src/comp/middle/typeck.rs | 1 + src/comp/syntax/ast.rs | 1 + src/comp/syntax/parse/parser.rs | 5 +++++ 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 27021c2a20824..3314fb890a2ce 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -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, - 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}; } @@ -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 @@ -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); } @@ -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); } } @@ -689,9 +693,9 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t, pat: @ast::pat) fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) -> {ex: @ast::expr, mut: option::t} { 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 { @@ -703,10 +707,10 @@ 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}; } _ {} } @@ -714,7 +718,7 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) _ {} } } - ret {ex: base_root.ex, mut: unsafe}; + ret {ex: base_root.ex, mut: unsafe_ty}; } fn unsafe_set(from: option::t) -> [unsafe_ty] { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 695000f7cf93f..ee25c59a7892e 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1525,6 +1525,7 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat, 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"); diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index a5c6e3ebd5c54..36791c10cb278 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -390,6 +390,7 @@ type fn_decl = tag purity { pure_fn; // declared with "pure fn" + unsafe_fn; // declared with "unsafe fn" impure_fn; // declared with "fn" } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index c359cc843cc19..5a4c5d78772ad 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -165,6 +165,7 @@ fn bad_expr_word_table() -> hashmap { words.insert("fn", ()); words.insert("lambda", ()); words.insert("pure", ()); + words.insert("unsafe", ()); words.insert("iter", ()); words.insert("block", ()); words.insert("import", ()); @@ -2153,6 +2154,10 @@ fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> { let proto = parse_fn_proto(p); ret some(parse_item_fn_or_iter(p, ast::pure_fn, proto, attrs, ast::il_normal)); + } else if eat_word(p, "unsafe") { + expect_word(p, "fn"); + ret some(parse_item_fn_or_iter(p, ast::unsafe_fn, ast::proto_fn, + attrs, ast::il_normal)); } else if eat_word(p, "iter") { ret some(parse_item_fn_or_iter(p, ast::impure_fn, ast::proto_iter, attrs, ast::il_normal)); From 60ce53c9db01ef2e0237f5e4587424e932f148a7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 6 Oct 2011 16:42:27 -0700 Subject: [PATCH 02/12] Extend the unchecked block stuff to allow unsafe blocks as well. --- src/comp/front/test.rs | 5 ++-- src/comp/metadata/decoder.rs | 1 + src/comp/metadata/encoder.rs | 1 + src/comp/middle/trans.rs | 4 +-- src/comp/middle/typeck.rs | 31 +++++++++++++++++++++--- src/comp/syntax/ast.rs | 9 ++++--- src/comp/syntax/ast_util.rs | 6 ++--- src/comp/syntax/parse/parser.rs | 33 ++++++++++++++++--------- src/comp/syntax/print/pprust.rs | 10 +++++--- src/lib/io.rs | 4 +-- src/lib/sys.rs | 43 +++++++++++++++++++++++++++++---- src/lib/uint.rs | 2 +- 12 files changed, 114 insertions(+), 35 deletions(-) diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 6f7270f4396f8..fcef6e551f122 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -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()); + checked_block([], option::some(test_descs), cx.next_node_id()); let body = nospan(body_); let fn_ = {decl: decl, proto: proto, body: body}; @@ -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()); + checked_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}; diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index ca3b4f4e2c5e6..d62a9572ecc46 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -175,6 +175,7 @@ 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) } diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs index 7850b4139a1aa..b67114d3d9a3d 100644 --- a/src/comp/metadata/encoder.rs +++ b/src/comp/metadata/encoder.rs @@ -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); diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 0e3e95e5f9f8f..a1fa888e74db2 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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 diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ee25c59a7892e..411a8ed213f9a 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1523,6 +1523,15 @@ 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) { + 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; } @@ -1536,7 +1545,22 @@ 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. { + alt ccx.tcx.def_map.find(callee.id) { + some(ast::def_fn(_, ast::unsafe_fn.)) { + ccx.tcx.sess.span_fatal + (sp, "safe function calls function marked unsafe"); + } + //some(ast::def_native_fn(_)) { + // 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; } @@ -2066,8 +2090,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // 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 } + ast::unchecked_blk. { @{purity: ast::impure_fn with *fcx} } + ast::unsafe_blk. { @{purity: ast::unsafe_fn with *fcx} } + ast::checked_blk. { fcx } }; bot = check_block(fcx_for_block, b); let typ = diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 36791c10cb278..6b72a4b67c375 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -78,7 +78,8 @@ tag meta_item_ { type blk = spanned; type blk_ = - {stmts: [@stmt], expr: option::t<@expr>, id: node_id, rules: check_mode}; + {stmts: [@stmt], expr: option::t<@expr>, id: node_id, + rules: blk_check_mode}; type pat = {id: node_id, node: pat_, span: span}; @@ -173,7 +174,9 @@ type field_ = {mut: mutability, ident: ident, expr: @expr}; type field = spanned; -tag check_mode { checked; unchecked; } +tag blk_check_mode { checked_blk; unchecked_blk; unsafe_blk; } + +tag expr_check_mode { claimed_expr; checked_expr; } type expr = {id: node_id, node: expr_, span: span}; @@ -222,7 +225,7 @@ tag expr_ { expr_assert(@expr); /* preds that typestate is aware of */ - expr_check(check_mode, @expr); + expr_check(expr_check_mode, @expr); /* FIXME Would be nice if expr_check desugared to expr_if_check. */ diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index d70b63dac6759..5d2a143a946a8 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -185,13 +185,13 @@ fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret std::box::ptr_eq(a, b); } fn hash_ty(&&t: @ty) -> uint { ret t.span.lo << 16u + t.span.hi; } fn block_from_expr(e: @expr) -> blk { - let blk_ = checked_blk([], option::some::<@expr>(e), e.id); + let blk_ = checked_block([], option::some::<@expr>(e), e.id); ret {node: blk_, span: e.span}; } -fn checked_blk(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) -> +fn checked_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) -> blk_ { - ret {stmts: stmts1, expr: expr1, id: id1, rules: checked}; + ret {stmts: stmts1, expr: expr1, id: id1, rules: checked_blk}; } fn obj_field_from_anon_obj_field(f: anon_obj_field) -> obj_field { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 5a4c5d78772ad..25344a8b2cffe 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -828,7 +828,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { p.peek() == token::OROR { ret parse_fn_block_expr(p); } else { - let blk = parse_block_tail(p, lo, ast::checked); + let blk = parse_block_tail(p, lo, ast::checked_blk); ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); } } else if eat_word(p, "if") { @@ -853,9 +853,9 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { } else if eat_word(p, "lambda") { ret parse_fn_expr(p, ast::proto_closure); } else if eat_word(p, "unchecked") { - expect(p, token::LBRACE); - let blk = parse_block_tail(p, lo, ast::unchecked); - ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); + ret parse_block_expr(p, lo, ast::unchecked_blk); + } else if eat_word(p, "unsafe") { + ret parse_block_expr(p, lo, ast::unsafe_blk); } else if p.peek() == token::LBRACKET { p.bump(); let mut = parse_mutability(p); @@ -872,7 +872,8 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_embed_type(ty)); } else if p.peek() == token::POUND_LBRACE { p.bump(); - let blk = ast::mac_embed_block(parse_block_tail(p, lo, ast::checked)); + let blk = ast::mac_embed_block( + parse_block_tail(p, lo, ast::checked_blk)); ret mk_mac_expr(p, lo, p.get_hi_pos(), blk); } else if p.peek() == token::ELLIPSIS { p.bump(); @@ -948,7 +949,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { let e = parse_expr(p); hi = e.span.hi; - ex = ast::expr_check(ast::checked, e); + ex = ast::expr_check(ast::checked_expr, e); } else if eat_word(p, "claim") { /* Same rules as check, except that if check-claims is enabled (a command-line flag), then the parser turns @@ -956,7 +957,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { let e = parse_expr(p); hi = e.span.hi; - ex = ast::expr_check(ast::unchecked, e); + ex = ast::expr_check(ast::claimed_expr, e); } else if eat_word(p, "ret") { if can_begin_expr(p.peek()) { let e = parse_expr(p); @@ -1014,6 +1015,14 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { ret mk_expr(p, lo, hi, ex); } +fn parse_block_expr(p: parser, + lo: uint, + blk_mode: ast::blk_check_mode) -> @ast::expr { + expect(p, token::LBRACE); + let blk = parse_block_tail(p, lo, blk_mode); + ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); +} + fn parse_syntax_ext(p: parser) -> @ast::expr { let lo = p.get_lo_pos(); expect(p, token::POUND); @@ -1311,7 +1320,7 @@ fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr { fn parse_fn_block_expr(p: parser) -> @ast::expr { let lo = p.get_last_lo_pos(); let decl = parse_fn_block_decl(p); - let body = parse_block_tail(p, lo, ast::checked); + let body = parse_block_tail(p, lo, ast::checked_blk); let _fn = {decl: decl, proto: ast::proto_block, body: body}; ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn)); } @@ -1675,10 +1684,12 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool { fn parse_block(p: parser) -> ast::blk { let lo = p.get_lo_pos(); if eat_word(p, "unchecked") { - be parse_block_tail(p, lo, ast::unchecked); + be parse_block_tail(p, lo, ast::unchecked_blk); + } else if eat_word(p, "unsafe") { + be parse_block_tail(p, lo, ast::unsafe_blk); } else { expect(p, token::LBRACE); - be parse_block_tail(p, lo, ast::checked); + be parse_block_tail(p, lo, ast::checked_blk); } } @@ -1695,7 +1706,7 @@ fn parse_block_no_value(p: parser) -> ast::blk { // I guess that also means "already parsed the 'impure'" if // necessary, and this should take a qualifier. // some blocks start with "#{"... -fn parse_block_tail(p: parser, lo: uint, s: ast::check_mode) -> ast::blk { +fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk { let stmts: [@ast::stmt] = []; let expr: option::t<@ast::expr> = none; while p.peek() != token::RBRACE { diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index f1b8dc69d1296..10b5db1e12900 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -572,7 +572,11 @@ tag embed_type { block_macro; block_block_fn; block_normal; } fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type, indented: uint) { - alt blk.node.rules { ast::unchecked. { word(s.s, "unchecked"); } _ { } } + alt blk.node.rules { + ast::unchecked_blk. { word(s.s, "unchecked"); } + ast::unsafe_blk. { word(s.s, "unsafe"); } + ast::checked_blk. { } + } maybe_print_comment(s, blk.span.lo); let ann_node = node_block(s, blk); @@ -934,8 +938,8 @@ fn print_expr(s: ps, &&expr: @ast::expr) { } ast::expr_check(m, expr) { alt m { - ast::unchecked. { word_nbsp(s, "claim"); } - ast::checked. { word_nbsp(s, "check"); } + ast::claimed_expr. { word_nbsp(s, "claim"); } + ast::checked_expr. { word_nbsp(s, "check"); } } popen(s); print_expr(s, expr); diff --git a/src/lib/io.rs b/src/lib/io.rs index d8f7f36b24f6e..c2ee7ff53ca5c 100644 --- a/src/lib/io.rs +++ b/src/lib/io.rs @@ -263,7 +263,7 @@ obj fd_buf_writer(fd: int, res: option::t<@fd_res>) { let nout = os::libc::write(fd, vbuf, len); if nout < 0 { log_err "error dumping buffer"; - log_err sys::rustrt::last_os_error(); + log_err sys::last_os_error(); fail; } count += nout as uint; @@ -299,7 +299,7 @@ fn file_buf_writer(path: str, flags: [fileflag]) -> buf_writer { }); if fd < 0 { log_err "error opening file for writing"; - log_err sys::rustrt::last_os_error(); + log_err sys::last_os_error(); fail; } ret fd_buf_writer(fd, option::some(@fd_res(fd))); diff --git a/src/lib/sys.rs b/src/lib/sys.rs index 7bec897ab02c3..c366e7c4ce52c 100644 --- a/src/lib/sys.rs +++ b/src/lib/sys.rs @@ -1,11 +1,8 @@ -import rustrt::size_of; - -export rustrt; -export size_of; +//export rustrt; +//export size_of; native "rust" mod rustrt { - // Explicitly re-export native stuff we want to be made // available outside this crate. Otherwise it's // visible-in-crate, but not re-exported. @@ -17,6 +14,42 @@ native "rust" mod rustrt { fn unsupervise(); } +fn last_os_error() -> str { + //unsafe { + ret rustrt::last_os_error(); + //} +} + +fn size_of() -> uint { + //unsafe { + ret rustrt::size_of::(); + //} +} + +fn align_of() -> uint { + //unsafe { + ret rustrt::align_of::(); + //} +} + +fn refcount(t: @T) -> uint { + //unsafe { + ret rustrt::refcount::(t); + //} +} + +fn do_gc() -> () { + //unsafe { + ret rustrt::do_gc(); + //} +} + +fn unsupervise() -> () { + //unsafe { + ret rustrt::unsupervise(); + //} +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/lib/uint.rs b/src/lib/uint.rs index d992ade5a7273..12a512e1de829 100644 --- a/src/lib/uint.rs +++ b/src/lib/uint.rs @@ -32,7 +32,7 @@ iter range(lo: uint, hi: uint) -> uint { } fn next_power_of_two(n: uint) -> uint { - let halfbits: uint = sys::rustrt::size_of::() * 4u; + let halfbits: uint = sys::size_of::() * 4u; let tmp: uint = n - 1u; let shift: uint = 1u; while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; } From a2582b21bb3fb89bb99d285e9315c10f74eeda61 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 6 Oct 2011 21:33:04 -0700 Subject: [PATCH 03/12] Add unsafe blocks, unsafe functions, and two rudimentary tests related to them --- src/comp/middle/typeck.rs | 10 ++++++---- src/comp/syntax/parse/parser.rs | 3 ++- src/lib/vec.rs | 4 +++- src/test/compile-fail/unsafe-fn-called-from-safe.rs | 8 ++++++++ src/test/run-pass/unsafe-fn-called-from-unsafe-blk.rs | 11 +++++++++++ 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/unsafe-fn-called-from-safe.rs create mode 100644 src/test/run-pass/unsafe-fn-called-from-unsafe-blk.rs diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 411a8ed213f9a..838b1f674fbf5 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1552,10 +1552,12 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, ccx.tcx.sess.span_fatal (sp, "safe function calls function marked unsafe"); } - //some(ast::def_native_fn(_)) { - // ccx.tcx.sess.span_fatal - // (sp, "native functions can only be invoked from unsafe code"); - //} + /* Temporarily disable until unsafe blocks parse! + some(ast::def_native_fn(_)) { + ccx.tcx.sess.span_fatal + (sp, "native functions can only be invoked from unsafe code"); + } + */ _ { } } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 25344a8b2cffe..75b72acba3f0e 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -2165,7 +2165,8 @@ fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> { let proto = parse_fn_proto(p); ret some(parse_item_fn_or_iter(p, ast::pure_fn, proto, attrs, ast::il_normal)); - } else if eat_word(p, "unsafe") { + } else if is_word(p, "unsafe") && p.look_ahead(1u) != token::LBRACE { + p.bump(); expect_word(p, "fn"); ret some(parse_item_fn_or_iter(p, ast::unsafe_fn, ast::proto_fn, attrs, ast::il_normal)); diff --git a/src/lib/vec.rs b/src/lib/vec.rs index bf21e056f6c84..b2d19d9ed54e2 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -15,7 +15,9 @@ native "rust" mod rustrt { /// Reserves space for `n` elements in the given vector. fn reserve<@T>(&v: [mutable? T], n: uint) { - rustrt::vec_reserve_shared(v, n); + //unsafe { + rustrt::vec_reserve_shared(v, n); + //} } pure fn len(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } } diff --git a/src/test/compile-fail/unsafe-fn-called-from-safe.rs b/src/test/compile-fail/unsafe-fn-called-from-safe.rs new file mode 100644 index 0000000000000..62fcfa689d97f --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-called-from-safe.rs @@ -0,0 +1,8 @@ +// -*- rust -*- +// error-pattern: safe function calls function marked unsafe + +unsafe fn f() { ret; } + +fn main() { + f(); +} diff --git a/src/test/run-pass/unsafe-fn-called-from-unsafe-blk.rs b/src/test/run-pass/unsafe-fn-called-from-unsafe-blk.rs new file mode 100644 index 0000000000000..39cdd19a794a2 --- /dev/null +++ b/src/test/run-pass/unsafe-fn-called-from-unsafe-blk.rs @@ -0,0 +1,11 @@ +// -*- rust -*- +// +// See also: compile-fail/unsafe-fn-called-from-safe.rs + +unsafe fn f() { ret; } + +fn main() { + unsafe { + f(); + } +} From a0efd30873b573b7b12979dfddc53e0f1fea2e12 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 6 Oct 2011 21:36:04 -0700 Subject: [PATCH 04/12] it is also legal to call unsafe functions from other unsafe functions --- src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs diff --git a/src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs b/src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs new file mode 100644 index 0000000000000..e19bee45cfc10 --- /dev/null +++ b/src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs @@ -0,0 +1,10 @@ +// -*- rust -*- +// +// See also: compile-fail/unsafe-fn-called-from-safe.rs + +unsafe fn f() { ret; } + +unsafe fn g() { + f(); +} + From 91a039c2121d7abf94a317362d5b357383d7c5f9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 09:01:24 -0700 Subject: [PATCH 05/12] fix test to include a main() function --- src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs b/src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs index e19bee45cfc10..445fdff80aadd 100644 --- a/src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs +++ b/src/test/run-pass/unsafe-fn-called-from-unsafe-fn.rs @@ -8,3 +8,6 @@ unsafe fn g() { f(); } +fn main() { + ret; +} From 6ec4b8bdb3d57c62d3c32d03bc0bee5188971ed4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 11:04:22 -0700 Subject: [PATCH 06/12] add 'u' to decoder (kinda' important) --- src/comp/metadata/decoder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index d62a9572ecc46..c4a7d7fef99bb 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -251,6 +251,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 } From f829894b9076e4fc0097566c9bd5a087a6d9ecc7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 11:04:54 -0700 Subject: [PATCH 07/12] add 'u' to one other place it was missing --- src/comp/metadata/decoder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index c4a7d7fef99bb..ee0b7f6c758a3 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -280,6 +280,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"; } From 4450a827ea33e984d02d3269cc3bc05eba4c4357 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 15:51:55 -0700 Subject: [PATCH 08/12] make treatment of unchecked/unsafe blocks more uniform; also repair various errors in the parser related to such blocks. rename checked_blk to default_blk to reflect the fact that it inherits its purity from the surrounding context. --- src/comp/front/test.rs | 4 ++-- src/comp/middle/typeck.rs | 15 +++++++-------- src/comp/syntax/ast.rs | 2 +- src/comp/syntax/ast_util.rs | 6 +++--- src/comp/syntax/parse/parser.rs | 10 ++++++---- src/comp/syntax/print/pprust.rs | 2 +- .../run-pass/unsafe-fn-called-from-unsafe-blk | Bin 0 -> 9936 bytes .../run-pass/unsafe-fn-called-from-unsafe-blk.rs | 9 ++++++++- 8 files changed, 28 insertions(+), 20 deletions(-) create mode 100755 src/test/run-pass/unsafe-fn-called-from-unsafe-blk diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index fcef6e551f122..70985f108060d 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -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_block([], 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}; @@ -303,7 +303,7 @@ fn mk_main(cx: test_ctxt) -> @ast::item { let test_main_call_expr = mk_test_main_call(cx); let body_: ast::blk_ = - checked_block([], option::some(test_main_call_expr), + default_block([], option::some(test_main_call_expr), cx.next_node_id()); let body = {node: body_, span: dummy_sp()}; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 838b1f674fbf5..ec7c2537874e7 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -2090,13 +2090,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_blk. { @{purity: ast::impure_fn with *fcx} } - ast::unsafe_blk. { @{purity: ast::unsafe_fn with *fcx} } - ast::checked_blk. { 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) } @@ -2553,7 +2547,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 { diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 6b72a4b67c375..d9b5365db5fdb 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -174,7 +174,7 @@ type field_ = {mut: mutability, ident: ident, expr: @expr}; type field = spanned; -tag blk_check_mode { checked_blk; unchecked_blk; unsafe_blk; } +tag blk_check_mode { default_blk; unchecked_blk; unsafe_blk; } tag expr_check_mode { claimed_expr; checked_expr; } diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index 5d2a143a946a8..32c381d909015 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -185,13 +185,13 @@ fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret std::box::ptr_eq(a, b); } fn hash_ty(&&t: @ty) -> uint { ret t.span.lo << 16u + t.span.hi; } fn block_from_expr(e: @expr) -> blk { - let blk_ = checked_block([], option::some::<@expr>(e), e.id); + let blk_ = default_block([], option::some::<@expr>(e), e.id); ret {node: blk_, span: e.span}; } -fn checked_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) -> +fn default_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) -> blk_ { - ret {stmts: stmts1, expr: expr1, id: id1, rules: checked_blk}; + ret {stmts: stmts1, expr: expr1, id: id1, rules: default_blk}; } fn obj_field_from_anon_obj_field(f: anon_obj_field) -> obj_field { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 75b72acba3f0e..ab573691720db 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -828,7 +828,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { p.peek() == token::OROR { ret parse_fn_block_expr(p); } else { - let blk = parse_block_tail(p, lo, ast::checked_blk); + let blk = parse_block_tail(p, lo, ast::default_blk); ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); } } else if eat_word(p, "if") { @@ -873,7 +873,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { } else if p.peek() == token::POUND_LBRACE { p.bump(); let blk = ast::mac_embed_block( - parse_block_tail(p, lo, ast::checked_blk)); + parse_block_tail(p, lo, ast::default_blk)); ret mk_mac_expr(p, lo, p.get_hi_pos(), blk); } else if p.peek() == token::ELLIPSIS { p.bump(); @@ -1320,7 +1320,7 @@ fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr { fn parse_fn_block_expr(p: parser) -> @ast::expr { let lo = p.get_last_lo_pos(); let decl = parse_fn_block_decl(p); - let body = parse_block_tail(p, lo, ast::checked_blk); + let body = parse_block_tail(p, lo, ast::default_blk); let _fn = {decl: decl, proto: ast::proto_block, body: body}; ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn)); } @@ -1684,12 +1684,14 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool { fn parse_block(p: parser) -> ast::blk { let lo = p.get_lo_pos(); if eat_word(p, "unchecked") { + expect(p, token::LBRACE); be parse_block_tail(p, lo, ast::unchecked_blk); } else if eat_word(p, "unsafe") { + expect(p, token::LBRACE); be parse_block_tail(p, lo, ast::unsafe_blk); } else { expect(p, token::LBRACE); - be parse_block_tail(p, lo, ast::checked_blk); + be parse_block_tail(p, lo, ast::default_blk); } } diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 10b5db1e12900..b806df75128d8 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -575,7 +575,7 @@ fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type, alt blk.node.rules { ast::unchecked_blk. { word(s.s, "unchecked"); } ast::unsafe_blk. { word(s.s, "unsafe"); } - ast::checked_blk. { } + ast::default_blk. { } } maybe_print_comment(s, blk.span.lo); diff --git a/src/test/run-pass/unsafe-fn-called-from-unsafe-blk b/src/test/run-pass/unsafe-fn-called-from-unsafe-blk new file mode 100755 index 0000000000000000000000000000000000000000..a57f8f90ca9eb2a486976b28935c5f795bf5d161 GIT binary patch literal 9936 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 Date: Mon, 10 Oct 2011 10:17:14 -0700 Subject: [PATCH 09/12] enable unsafe checking but only with a flag --check-unsafe --- src/comp/driver/rustc.rs | 7 +++++-- src/comp/driver/session.rs | 3 ++- src/comp/middle/typeck.rs | 29 ++++++++++++++++++----------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 4dc58c04fe5af..be09a59074156 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -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 (temporary option) "); } @@ -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 { @@ -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; } @@ -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]) { diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 1f3f9baab8a90..6ba2148e8a4c8 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -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]}; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ec7c2537874e7..26dcb5074da0c 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1524,11 +1524,13 @@ 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) { - alt f_purity { - ast::unsafe_fn. { ret; } - _ { - sess.span_fatal(sp, "Found unsafe expression in safe function decl"); - } + if sess.get_opts().check_unsafe { + alt f_purity { + ast::unsafe_fn. { ret; } + _ { + sess.span_fatal(sp, "Found unsafe expression in safe function decl"); + } + } } } @@ -1547,17 +1549,22 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, alt caller_purity { 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.)) { - ccx.tcx.sess.span_fatal - (sp, "safe function calls function marked unsafe"); + if sess.get_opts().check_unsafe { + ccx.tcx.sess.span_fatal( + sp, + "safe function calls function marked unsafe"); + } } - /* Temporarily disable until unsafe blocks parse! some(ast::def_native_fn(_)) { - ccx.tcx.sess.span_fatal - (sp, "native functions can only be invoked from unsafe code"); + if sess.get_opts().check_unsafe { + ccx.tcx.sess.span_fatal( + sp, + "native functions can only be invoked from unsafe code"); + } } - */ _ { } } From 234263d6a8d1a372c26bed7a5e1c9843128734c0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 16:24:22 -0700 Subject: [PATCH 10/12] correct lines over 78 chars --- src/comp/driver/rustc.rs | 2 +- src/comp/middle/typeck.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index be09a59074156..76819b9960544 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -264,7 +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 (temporary option) + --check-unsafe disallow unsafe actions in non-unsafe functions "); } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 26dcb5074da0c..cd21c022f4cfc 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1528,7 +1528,9 @@ fn require_unsafe(sess: session::session, f_purity: ast::purity, sp: span) { alt f_purity { ast::unsafe_fn. { ret; } _ { - sess.span_fatal(sp, "Found unsafe expression in safe function decl"); + sess.span_fatal( + sp, + "Found unsafe expression in safe function decl"); } } } From 7a12d5493050f4e556258862de804887b20dc4b8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 17:05:19 -0700 Subject: [PATCH 11/12] skip test, remove whitespace --- src/comp/middle/typeck.rs | 2 +- src/test/compile-fail/unsafe-fn-called-from-safe.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index cd21c022f4cfc..8eebe3f9949fe 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1529,7 +1529,7 @@ fn require_unsafe(sess: session::session, f_purity: ast::purity, sp: span) { ast::unsafe_fn. { ret; } _ { sess.span_fatal( - sp, + sp, "Found unsafe expression in safe function decl"); } } diff --git a/src/test/compile-fail/unsafe-fn-called-from-safe.rs b/src/test/compile-fail/unsafe-fn-called-from-safe.rs index 62fcfa689d97f..b294ad16344fd 100644 --- a/src/test/compile-fail/unsafe-fn-called-from-safe.rs +++ b/src/test/compile-fail/unsafe-fn-called-from-safe.rs @@ -1,5 +1,6 @@ // -*- rust -*- // error-pattern: safe function calls function marked unsafe +// xfail-test unsafe fn f() { ret; } From 9886fc0bcff4eee6b26e70f97e53c8e557bf01d3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 14:52:38 -0700 Subject: [PATCH 12/12] make native functions markable as unsafe and incorporate that into the type check --- src/comp/metadata/decoder.rs | 4 +++- src/comp/metadata/encoder.rs | 10 ++++++++-- src/comp/middle/resolve.rs | 8 +++++--- src/comp/middle/trans.rs | 2 +- src/comp/middle/ty.rs | 2 +- src/comp/middle/typeck.rs | 5 +++-- src/comp/syntax/ast.rs | 2 +- src/comp/syntax/ast_util.rs | 2 +- src/comp/syntax/parse/parser.rs | 11 +++++++---- 9 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index ee0b7f6c758a3..4a103d357558a 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -178,7 +178,9 @@ fn lookup_def(cnum: ast::crate_num, data: @[u8], did_: ast::def_id) -> '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) } diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs index b67114d3d9a3d..3617005a400ab 100644 --- a/src/comp/metadata/encoder.rs +++ b/src/comp/metadata/encoder.rs @@ -350,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); diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index f2995f58b6c6a..b9d520b66c539 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -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)); } } } @@ -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 } }; } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a1fa888e74db2..5529b1bf309d6 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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); } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 428278b413241..3a4d852f2adec 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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; } } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 8eebe3f9949fe..f848cf638f8b8 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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) { @@ -1560,7 +1560,7 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, "safe function calls function marked unsafe"); } } - some(ast::def_native_fn(_)) { + some(ast::def_native_fn(_, ast::unsafe_fn.)) { if sess.get_opts().check_unsafe { ccx.tcx.sess.span_fatal( sp, @@ -1893,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); diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index d9b5365db5fdb..a837dbdac2476 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -41,7 +41,7 @@ tag def { def_binding(def_id); def_use(def_id); def_native_ty(def_id); - def_native_fn(def_id); + def_native_fn(def_id, purity); def_upvar(def_id, @def, /* writable */bool); } diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index 32c381d909015..db9cdc2f1a13e 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -37,7 +37,7 @@ fn def_id_of_def(d: def) -> def_id { def_binding(id) { ret id; } def_use(id) { ret id; } def_native_ty(id) { ret id; } - def_native_fn(id) { ret id; } + def_native_fn(id, _) { ret id; } def_upvar(id, _, _) { ret id; } } } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index ab573691720db..7a1e61f27ba07 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -1972,11 +1972,11 @@ fn parse_item_native_type(p: parser, attrs: [ast::attribute]) -> span: ast_util::mk_sp(t.lo, hi)}; } -fn parse_item_native_fn(p: parser, attrs: [ast::attribute]) -> - @ast::native_item { +fn parse_item_native_fn(p: parser, attrs: [ast::attribute], + purity: ast::purity) -> @ast::native_item { let lo = p.get_last_lo_pos(); let t = parse_fn_header(p); - let decl = parse_fn_decl(p, ast::impure_fn, ast::il_normal); + let decl = parse_fn_decl(p, purity, ast::il_normal); let link_name = none; if p.peek() == token::EQ { p.bump(); link_name = some(parse_str(p)); } let hi = p.get_hi_pos(); @@ -1993,7 +1993,10 @@ fn parse_native_item(p: parser, attrs: [ast::attribute]) -> if eat_word(p, "type") { ret parse_item_native_type(p, attrs); } else if eat_word(p, "fn") { - ret parse_item_native_fn(p, attrs); + ret parse_item_native_fn(p, attrs, ast::impure_fn); + } else if eat_word(p, "unsafe") { + expect_word(p, "fn"); + ret parse_item_native_fn(p, attrs, ast::unsafe_fn); } else { unexpected(p, p.peek()); } }