From 00bf46175f8b07cdf5671818a15c232b62f68749 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 6 Oct 2011 15:29:54 -0700 Subject: [PATCH 01/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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/49] 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 zcmeHNZEO_B8J@j8hiiJkK@MsNDGNO+RDnN;Ax=xHGx$3ErOY>@AiDx+?RIu z%!i8P^nkEksIIEoMxshBH9w;Mp+ESMs%=DMq@*9JT(weL300N?(N%UU)1rV{8uxi; z_k7FwoTUHq;|AWDcix%znRnj#*tr@1?%#iZe+6Sq2Khj1K!XsRpV%Tv;JZPb5A=LF zb}V+}tH@MCsLCu&NpBcnoDar^2R-GaQ`JLC?Y4jdZWYc=?Ud0ES`e>D-uGSdZ~KFrG%)>%i~^a&t9sUd)|L=Mp@fOXeZ0$G8KGmm$AX zhf&q1lyfb`le(JK9BDm9`P1+P2Bf@d`M%J2g<%-yy*-0H4vvTw#MQaw&MWc<%`Xa^ z7xerX+UDb`ZZy^pQ$^@LG_OeJ2F`PsQ_j>XnEDbM!ir-;7#LpP(R`}ekx@SgBLWOe zPZp`eApK8*C@h^55BnmjIO{12jOFJPt48&(-n|_hnddd`jhBpL#KfclM~hgNMEn>pe&dlR^gw_A`aCX$%7S(5ttV zu?ea|095^am}A0d`%_QA$yPaCF|ZQIudThpVAkq-H{rXv(t zR4=Gzih89Nu`!v|`k40tq_Vk|aJv-GxA*1a~ zs5*8gDuW(j9CtC=hYU?O+H+aeG}IT;M*BFj>3mL0v=d1C{|POyyQ|n@T=H=>^WjE) z7CJNrmoRU{9s|A^njZMLc;M^Ix?Q?8Uz!WqBYtaBWlbGQ_`F7_@v)h$0Gq- zE=~E*UoYN6CRlj^o1W#5RIVbuTP_b-w`YALQ?n0NZ=Rq&AzzwnwPQgm_F%T9bfa}- z%9^qJA6N(cmFb0rg;_QmuwwVEp}Vub*%=!guttFO5%kN;=|Az1enWc#7Hn|Zb*!>u z574yTf0w#z58by0BZ0~r)WS^J6VRWd19mKI_lNAEpv~~_puh7y3kv_dcgOC(Z%L&a z{u3ipHT#d+u~xf3Y!8L(V$eR~Uww62`n9!Q)FJ;o`?aH`xg8bq*09~*Y7d3&V#q!l zv_}H=xc>{f-zv^qXXmVuiWR$M_0O1HcI?*Wi=Rg)FP9UD-`ELN`)tM98zJM#^0#^; zL6Ta-ojvHQ?+`nK3vr*Ty^5|g|{#|s95O(j(y=IjulX+<|8hgLU5Na z{J^b;BPAJpVye8bjm}mJ+qR2%hlo2w+$G{}5${EuVhDfx5~9?4;^@1V+DaV#YDjew zrx3S~II5BwB#ypYsVs3AAmUpUYLJc<<%KIhWb($xAYBQfuQgLZ8;GIsVdYM(T1?+{ z)x_tvU@B%_iK~XGjH{WVW+?fjl1L|$8lCtRBYj3QSUN}NeXrXNfcC_ex>{ctHGJ%^OAf;b9wyGOk!Fa`iw22F!k z&`3eTxde@bd`yb^n19m8WWPTEiQlI&narRNb`mC?Il`oG1f)=~#eWfnbdDgi%l}ze z5a+6%Re^K9eJlO0oYbT<1ARhk#g!OTLRDSTBd;f*`!rI29y7B}pSpN%nR06TWzee) z+NQE=RF1MPq^u4X-DklEn77`tXD+n7yPO|Fs7C#{2pu|yvi++< zByX7r2D|pJQZ9IgnWW-yGORFm9P~UW0rG|e$kXrLji3mq4b%UdS@$|r&t!!xj zb8EL$HcUL?D;zBN4&!eCqV(Y8Jc5tn-4~DGhxKrIZIl-ac=X6{dO_iM8#nSfHIp_^ zvk8A0-P0p$qMQ#oZ^cJ6qlm}eGSjz1s+~%k#P0x~)$r&yE{ZyUS;*@q*R}XKm3KiP z(DCS_3yp3_49(<5K|Pt{Cw090z#dfHTeByrrZW&RA7?>FG0s{z+a-|Lq%W(cbL>0v zq2V5Vj7`c~Zal5y+3}jp{Mi(2)8a)_!+XCTzM4^epB6iseGbnS6OZ!7Ryoc%-|XIEj?pB2b%QZz%+EtJBw(NGlsJCw2% z>gb>=EpaWms>QiyqPJ1v>Aq<*@pKWWFh*}|t8hIT1>Z(ID$;$_7s0Pyjazo`F_%9M zzMpsr_3_?G_r1gqfG@dx8T>0QKMnpD!~-XxF!nZhSqh1JvzsKx^(Wnty+=H7W>DXU zRN&*H?lG4yfZs+uaGpo~Hdj6gc^C2M*ERI(86lq#mwYE&zJP~c!{rCSf7|6l(EYK? zE0F(O@Gt~6yb0d<&)Dxh{GUAhjKhm7!C4P~&%-~8Qe;J)PkHzbhewg~){W-Hy(GH8 z=-!>iM*$&3iM9}jA%z`nn3kU&@SeBc&E_Z;d^{$QSjvwkRlwKi^o)IvYhc zpP)(4xLDnBHyy_xN*p`X*?1L-qQ(nR6g6IpRJ8n>=guFQh^>P22D^%5ZG%P1-G0y> z<>8%0>k2#zomY1+^qMrpPUT(7j- Date: Mon, 10 Oct 2011 10:17:14 -0700 Subject: [PATCH 09/49] 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/49] 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/49] 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/49] 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()); } } From 26c2a6e89d556f1b396861094a93c1827341ce14 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 10:59:19 -0700 Subject: [PATCH 13/49] Add unsafe tags to usage of LLVM funcs --- src/comp/middle/trans_common.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index a2287c4c0fca9..9e0f99685a5d7 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -428,11 +428,13 @@ fn val_str(tn: type_names, v: ValueRef) -> str { ret ty_str(tn, val_ty(v)); } // Returns the nth element of the given LLVM structure type. fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef { - let elt_count = llvm::LLVMCountStructElementTypes(llstructty); - assert (n < elt_count); - let elt_tys = std::vec::init_elt(T_nil(), elt_count); - llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); - ret llvm::LLVMGetElementType(elt_tys[n]); + unsafe { + let elt_count = llvm::LLVMCountStructElementTypes(llstructty); + assert (n < elt_count); + let elt_tys = std::vec::init_elt(T_nil(), elt_count); + llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); + ret llvm::LLVMGetElementType(elt_tys[n]); + } } fn find_scope_cx(cx: @block_ctxt) -> @block_ctxt { From 9eff1a0991ff41dfcef687b92562cdc27be4d0b6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 12:05:38 -0700 Subject: [PATCH 14/49] add unsafe tags into various points in the translation chains and so forth --- src/comp/back/link.rs | 10 +++-- src/comp/lib/llvm.rs | 12 +++-- src/comp/metadata/creader.rs | 34 ++++++++------- src/comp/middle/trans_build.rs | 77 +++++++++++++++++++++------------ src/comp/middle/trans_common.rs | 65 ++++++++++++++++++---------- src/test/stdtest/str.rs | 4 +- src/test/stdtest/vec.rs | 2 +- 7 files changed, 128 insertions(+), 76 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 52024d6f5b728..01f44cd2edbfa 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -35,10 +35,12 @@ tag output_type { } fn llvm_err(sess: session::session, msg: str) { - let buf = llvm::LLVMRustGetLastError(); - if buf == std::ptr::null() { - sess.fatal(msg); - } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } + unsafe { + let buf = llvm::LLVMRustGetLastError(); + if buf == std::ptr::null() { + sess.fatal(msg); + } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } + } } fn link_intrinsics(sess: session::session, llmod: ModuleRef) { diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index c47f75135d7c1..2cf85bcd218c6 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -961,7 +961,9 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); let n_args: uint = llvm::LLVMCountParamTypes(ty); let args: [TypeRef] = vec::init_elt::(0 as TypeRef, n_args); - llvm::LLVMGetParamTypes(ty, vec::to_ptr(args)); + unsafe { + llvm::LLVMGetParamTypes(ty, vec::to_ptr(args)); + } s += tys_str(names, outer, args); s += ") -> "; s += type_to_str_inner(names, outer, out_ty); @@ -971,7 +973,9 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> let s: str = "{"; let n_elts: uint = llvm::LLVMCountStructElementTypes(ty); let elts: [TypeRef] = vec::init_elt::(0 as TypeRef, n_elts); - llvm::LLVMGetStructElementTypes(ty, vec::to_ptr(elts)); + unsafe { + llvm::LLVMGetStructElementTypes(ty, vec::to_ptr(elts)); + } s += tys_str(names, outer, elts); s += "}"; ret s; @@ -1011,7 +1015,9 @@ fn float_width(llt: TypeRef) -> uint { fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] { let args = vec::init_elt(0 as TypeRef, llvm::LLVMCountParamTypes(fn_ty)); - llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); + unsafe { + llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); + } ret args; } diff --git a/src/comp/metadata/creader.rs b/src/comp/metadata/creader.rs index 90da54f36b314..1dd51a8b680ab 100644 --- a/src/comp/metadata/creader.rs +++ b/src/comp/metadata/creader.rs @@ -170,24 +170,26 @@ fn find_library_crate_aux(nn: {prefix: str, suffix: str}, crate_name: str, } fn get_metadata_section(filename: str) -> option::t<@[u8]> { - let mb = str::as_buf(filename, {|buf| - llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) - }); - if mb as int == 0 { ret option::none::<@[u8]>; } - let of = mk_object_file(mb); - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let name_buf = llvm::LLVMGetSectionName(si.llsi); - let name = str::str_from_cstr(name_buf); - if str::eq(name, x86::get_meta_sect_name()) { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi); - let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); - ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); + unsafe { + let mb = str::as_buf(filename, {|buf| + llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) + }); + if mb as int == 0 { ret option::none::<@[u8]>; } + let of = mk_object_file(mb); + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let name_buf = llvm::LLVMGetSectionName(si.llsi); + let name = str::str_from_cstr(name_buf); + if str::eq(name, x86::get_meta_sect_name()) { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi); + let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); + ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); + } + llvm::LLVMMoveToNextSection(si.llsi); } - llvm::LLVMMoveToNextSection(si.llsi); + ret option::none::<@[u8]>; } - ret option::none::<@[u8]>; } fn load_library_crate(sess: session::session, span: span, ident: ast::ident, diff --git a/src/comp/middle/trans_build.rs b/src/comp/middle/trans_build.rs index 384cbb49ff959..7cf9a9c27b3f2 100644 --- a/src/comp/middle/trans_build.rs +++ b/src/comp/middle/trans_build.rs @@ -37,8 +37,10 @@ fn AggregateRet(cx: @block_ctxt, RetVals: [ValueRef]) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals), - vec::len(RetVals)); + unsafe { + llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals), + vec::len(RetVals)); + } } fn Br(cx: @block_ctxt, Dest: BasicBlockRef) { @@ -88,8 +90,10 @@ fn Invoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), Then, Catch, noname()); + unsafe { + llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), Then, Catch, noname()); + } } fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], @@ -97,9 +101,11 @@ fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), Then, Catch, noname()); - llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + unsafe { + let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), Then, Catch, noname()); + llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + } } fn Unreachable(cx: @block_ctxt) { @@ -311,15 +317,19 @@ fn Store(cx: @block_ctxt, Val: ValueRef, Ptr: ValueRef) { fn GEP(cx: @block_ctxt, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices), - vec::len(Indices), noname()); + unsafe { + ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices), + vec::len(Indices), noname()); + } } fn InBoundsGEP(cx: @block_ctxt, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, vec::to_ptr(Indices), - vec::len(Indices), noname()); + unsafe { + ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, vec::to_ptr(Indices), + vec::len(Indices), noname()); + } } fn StructGEP(cx: @block_ctxt, Pointer: ValueRef, Idx: uint) -> ValueRef { @@ -460,9 +470,11 @@ fn Phi(cx: @block_ctxt, Ty: TypeRef, vals: [ValueRef], bbs: [BasicBlockRef]) if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } assert (vec::len::(vals) == vec::len::(bbs)); let phi = EmptyPhi(cx, Ty); - llvm::LLVMAddIncoming(phi, vec::to_ptr(vals), vec::to_ptr(bbs), - vec::len(vals)); - ret phi; + unsafe { + llvm::LLVMAddIncoming(phi, vec::to_ptr(vals), vec::to_ptr(bbs), + vec::len(vals)); + ret phi; + } } fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) { @@ -480,26 +492,32 @@ fn _UndefReturn(Fn: ValueRef) -> ValueRef { } fn Call(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { - if cx.unreachable { ret _UndefReturn(Fn); } - ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), noname()); + unsafe { + if cx.unreachable { ret _UndefReturn(Fn); } + ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), noname()); + } } fn FastCall(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { - if cx.unreachable { ret _UndefReturn(Fn); } - let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), noname()); - llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); - ret v; + unsafe { + if cx.unreachable { ret _UndefReturn(Fn); } + let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), noname()); + llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + ret v; + } } fn CallWithConv(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], Conv: uint) -> ValueRef { - if cx.unreachable { ret _UndefReturn(Fn); } - let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), noname()); - llvm::LLVMSetInstructionCallConv(v, Conv); - ret v; + unsafe { + if cx.unreachable { ret _UndefReturn(Fn); } + let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), noname()); + llvm::LLVMSetInstructionCallConv(v, Conv); + ret v; + } } fn Select(cx: @block_ctxt, If: ValueRef, Then: ValueRef, Else: ValueRef) -> @@ -568,7 +586,10 @@ fn Trap(cx: @block_ctxt) { }); assert (T as int != 0); let Args: [ValueRef] = []; - llvm::LLVMBuildCall(b, T, vec::to_ptr(Args), vec::len(Args), noname()); + unsafe { + llvm::LLVMBuildCall(b, T, vec::to_ptr(Args), + vec::len(Args), noname()); + } } fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef, diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 9e0f99685a5d7..945530d87d2af 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -518,8 +518,10 @@ fn T_size_t() -> TypeRef { } fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef { - ret llvm::LLVMFunctionType(output, to_ptr(inputs), - std::vec::len::(inputs), False); + unsafe { + ret llvm::LLVMFunctionType(output, to_ptr(inputs), + std::vec::len::(inputs), False); + } } fn T_fn_pair(cx: crate_ctxt, tfn: TypeRef) -> TypeRef { @@ -529,7 +531,9 @@ fn T_fn_pair(cx: crate_ctxt, tfn: TypeRef) -> TypeRef { fn T_ptr(t: TypeRef) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); } fn T_struct(elts: [TypeRef]) -> TypeRef { - ret llvm::LLVMStructType(to_ptr(elts), std::vec::len(elts), False); + unsafe { + ret llvm::LLVMStructType(to_ptr(elts), std::vec::len(elts), False); + } } fn T_named_struct(name: str) -> TypeRef { @@ -538,7 +542,9 @@ fn T_named_struct(name: str) -> TypeRef { } fn set_struct_body(t: TypeRef, elts: [TypeRef]) { - llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); + unsafe { + llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); + } } fn T_empty_struct() -> TypeRef { ret T_struct([]); } @@ -578,12 +584,15 @@ fn T_task() -> TypeRef { fn T_tydesc_field(cx: crate_ctxt, field: int) -> TypeRef { // Bit of a kludge: pick the fn typeref out of the tydesc.. - let tydesc_elts: [TypeRef] = - std::vec::init_elt::(T_nil(), abi::n_tydesc_fields as uint); - llvm::LLVMGetStructElementTypes(cx.tydesc_type, - to_ptr::(tydesc_elts)); - let t = llvm::LLVMGetElementType(tydesc_elts[field]); - ret t; + unsafe { + let tydesc_elts: [TypeRef] = + std::vec::init_elt::(T_nil(), + abi::n_tydesc_fields as uint); + llvm::LLVMGetStructElementTypes(cx.tydesc_type, + to_ptr::(tydesc_elts)); + let t = llvm::LLVMGetElementType(tydesc_elts[field]); + ret t; + } } fn T_glue_fn(cx: crate_ctxt) -> TypeRef { @@ -790,30 +799,42 @@ fn C_postr(s: str) -> ValueRef { } fn C_zero_byte_arr(size: uint) -> ValueRef { - let i = 0u; - let elts: [ValueRef] = []; - while i < size { elts += [C_u8(0u)]; i += 1u; } - ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), - std::vec::len(elts)); + unsafe { + let i = 0u; + let elts: [ValueRef] = []; + while i < size { elts += [C_u8(0u)]; i += 1u; } + ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), + std::vec::len(elts)); + } } fn C_struct(elts: [ValueRef]) -> ValueRef { - ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), - False); + unsafe { + ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), + False); + } } fn C_named_struct(T: TypeRef, elts: [ValueRef]) -> ValueRef { - ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), - std::vec::len(elts)); + unsafe { + ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), + std::vec::len(elts)); + } } fn C_array(ty: TypeRef, elts: [ValueRef]) -> ValueRef { - ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), std::vec::len(elts)); + unsafe { + ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), + std::vec::len(elts)); + } } fn C_bytes(bytes: [u8]) -> ValueRef { - ret llvm::LLVMConstString(unsafe::reinterpret_cast(vec::to_ptr(bytes)), - vec::len(bytes), False); + unsafe { + ret llvm::LLVMConstString( + unsafe::reinterpret_cast(vec::to_ptr(bytes)), + vec::len(bytes), False); + } } fn C_shape(ccx: @crate_ctxt, bytes: [u8]) -> ValueRef { diff --git a/src/test/stdtest/str.rs b/src/test/stdtest/str.rs index f1839a0aa91df..8cce515ec3e7d 100644 --- a/src/test/stdtest/str.rs +++ b/src/test/stdtest/str.rs @@ -256,7 +256,7 @@ fn unsafe_from_bytes() { } #[test] -fn str_from_cstr() { +unsafe fn str_from_cstr() { let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; let b = vec::to_ptr(a); let c = str::str_from_cstr(b); @@ -278,7 +278,7 @@ fn as_buf_small() { } #[test] -fn as_buf2() { +unsafe fn as_buf2() { let s = "hello"; let sb = str::as_buf(s, {|b| b }); let s_cstr = str::str_from_cstr(sb); diff --git a/src/test/stdtest/vec.rs b/src/test/stdtest/vec.rs index 5e5de913914ae..313db7b71f107 100644 --- a/src/test/stdtest/vec.rs +++ b/src/test/stdtest/vec.rs @@ -21,7 +21,7 @@ fn square_if_odd(&&n: uint) -> option::t { fn add(&&x: uint, &&y: uint) -> uint { ret x + y; } #[test] -fn test_unsafe_ptrs() { +unsafe fn test_unsafe_ptrs() { // Test on-stack copy-from-buf. let a = [1, 2, 3]; let ptr = vec::to_ptr(a); From 816548ba8dc76ac3015ef8af7e74271f9cd6ea23 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 11:59:20 -0700 Subject: [PATCH 15/49] continue to annotate trans functions as unsafe where neccessary --- src/comp/middle/trans_objects.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs index aabe09b3d0586..af5f4266b9eb3 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -569,7 +569,7 @@ fn create_backwarding_vtbl(cx: @local_ctxt, sp: span, inner_obj_ty: ty::t, // finish_vtbl: Given a vector of vtable entries, create the table in // read-only memory and return a pointer to it. fn finish_vtbl(cx: @local_ctxt, llmethods: [ValueRef], name: str) -> - ValueRef { + ValueRef unsafe { let vtbl = C_struct(llmethods); let vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + [name]); let gvar = @@ -619,7 +619,7 @@ fn begin_fn(cx: @local_ctxt, sp: span, m: @ty::method, // returns the value returned from that call. fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, ty_params: [ast::ty_param], outer_obj_ty: ty::t, - _additional_field_tys: [ty::t]) -> ValueRef { + _additional_field_tys: [ty::t]) -> ValueRef unsafe { let llbackwarding_fn = begin_fn(cx, sp, m, ty_params, "backwarding_fn"); let fcx = new_fn_ctxt(cx, sp, llbackwarding_fn); @@ -724,7 +724,7 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, fn process_fwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, ty_params: [ast::ty_param], inner_obj_ty: ty::t, backwarding_vtbl: ValueRef, - additional_field_tys: [ty::t]) -> ValueRef { + additional_field_tys: [ty::t]) -> ValueRef unsafe { // Create a new function context and block context for the function, // holding onto a pointer to the first block. From d961094397372006b91987c0181c8109d2c9120d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 12:21:37 -0700 Subject: [PATCH 16/49] continue to annotate trans functions as unsafe where neccessary --- src/comp/middle/gc.rs | 6 ++++-- src/comp/middle/shape.rs | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/comp/middle/gc.rs b/src/comp/middle/gc.rs index be5376bc2b6bf..7de07b55e3b17 100644 --- a/src/comp/middle/gc.rs +++ b/src/comp/middle/gc.rs @@ -16,7 +16,8 @@ type ctxt = @{mutable next_tydesc_num: uint}; fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; } -fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef { +fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) + -> ValueRef unsafe { let llglobal = str::as_buf(name, {|buf| @@ -27,7 +28,8 @@ fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef { ret llglobal; } -fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt { +fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> + @block_ctxt unsafe { let bcx = cx; if !type_is_gc_relevant(bcx_tcx(cx), ty) || ty::type_has_dynamic_size(bcx_tcx(cx), ty) { diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index 7c54bde66b32f..17c72d6b6c21b 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -72,7 +72,7 @@ fn eq_res_info(a: res_info, b: res_info) -> bool { } fn mk_global(ccx: @crate_ctxt, name: str, llval: ValueRef, internal: bool) -> - ValueRef { + ValueRef unsafe { let llglobal = str::as_buf(name, {|buf| @@ -245,7 +245,7 @@ fn s_float(_tcx: ty_ctxt) -> u8 { ret shape_f64; // TODO: x86-64 } -fn mk_ctxt(llmod: ModuleRef) -> ctxt { +fn mk_ctxt(llmod: ModuleRef) -> ctxt unsafe { let llshapetablesty = trans_common::T_named_struct("shapes"); let llshapetables = str::as_buf("shapes", @@ -580,7 +580,7 @@ fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef { ret mk_global(ccx, "resource_shapes", C_struct(dtors), true); } -fn gen_shape_tables(ccx: @crate_ctxt) { +fn gen_shape_tables(ccx: @crate_ctxt) unsafe { let lltagstable = gen_tag_shapes(ccx); let llresourcestable = gen_resource_shapes(ccx); trans_common::set_struct_body(ccx.shape_cx.llshapetablesty, From 37a8c1b115d13dedf0adbd0755ef59fdf04ea681 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 15:16:55 -0700 Subject: [PATCH 17/49] continue to annotate functions as unsafe where neccessary --- src/comp/back/link.rs | 5 +++-- src/comp/lib/llvm.rs | 26 ++++++++++++-------------- src/compiletest/procsrv.rs | 2 +- src/test/stdtest/ptr.rs | 2 +- src/test/stdtest/run.rs | 8 ++++---- src/test/stdtest/sys.rs | 2 +- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 01f44cd2edbfa..fbf1f4b78813d 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -43,7 +43,7 @@ fn llvm_err(sess: session::session, msg: str) { } } -fn link_intrinsics(sess: session::session, llmod: ModuleRef) { +fn link_intrinsics(sess: session::session, llmod: ModuleRef) unsafe { let path = alt filesearch::search( sess.filesearch(), bind filesearch::pick_file("intrinsics.bc", _)) { @@ -90,7 +90,8 @@ mod write { } else { stem = str::substr(output_path, 0u, dot_pos as uint); } ret stem + "." + extension; } - fn run_passes(sess: session::session, llmod: ModuleRef, output: str) { + fn run_passes(sess: session::session, llmod: ModuleRef, output: str) + unsafe { let opts = sess.get_opts(); if opts.time_llvm_passes { llvm::LLVMRustEnableTimePasses(); } link_intrinsics(sess, llmod); diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 2cf85bcd218c6..8a6464cc1cfdc 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -925,7 +925,7 @@ fn type_to_str(names: type_names, ty: TypeRef) -> str { } fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> - str { + str unsafe { if names.type_has_name(ty) { ret names.get_name(ty); } @@ -1003,7 +1003,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> } } -fn float_width(llt: TypeRef) -> uint { +fn float_width(llt: TypeRef) -> uint unsafe { ret alt llvm::LLVMGetTypeKind(llt) { 1 { 32u } 2 { 64u } @@ -1013,24 +1013,22 @@ fn float_width(llt: TypeRef) -> uint { }; } -fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] { +fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] unsafe { let args = vec::init_elt(0 as TypeRef, llvm::LLVMCountParamTypes(fn_ty)); - unsafe { - llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); - } + llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); ret args; } /* Memory-managed interface to target data. */ -resource target_data_res(TD: TargetDataRef) { +resource target_data_res(TD: TargetDataRef) unsafe { llvm::LLVMDisposeTargetData(TD); } type target_data = {lltd: TargetDataRef, dtor: @target_data_res}; -fn mk_target_data(string_rep: str) -> target_data { +fn mk_target_data(string_rep: str) -> target_data unsafe { let lltd = str::as_buf(string_rep, {|buf| llvm::LLVMCreateTargetData(buf) }); ret {lltd: lltd, dtor: @target_data_res(lltd)}; @@ -1038,39 +1036,39 @@ fn mk_target_data(string_rep: str) -> target_data { /* Memory-managed interface to pass managers. */ -resource pass_manager_res(PM: PassManagerRef) { +resource pass_manager_res(PM: PassManagerRef) unsafe { llvm::LLVMDisposePassManager(PM); } type pass_manager = {llpm: PassManagerRef, dtor: @pass_manager_res}; -fn mk_pass_manager() -> pass_manager { +fn mk_pass_manager() -> pass_manager unsafe { let llpm = llvm::LLVMCreatePassManager(); ret {llpm: llpm, dtor: @pass_manager_res(llpm)}; } /* Memory-managed interface to object files. */ -resource object_file_res(ObjectFile: ObjectFileRef) { +resource object_file_res(ObjectFile: ObjectFileRef) unsafe { llvm::LLVMDisposeObjectFile(ObjectFile); } type object_file = {llof: ObjectFileRef, dtor: @object_file_res}; -fn mk_object_file(llmb: MemoryBufferRef) -> object_file { +fn mk_object_file(llmb: MemoryBufferRef) -> object_file unsafe { let llof = llvm::LLVMCreateObjectFile(llmb); ret {llof: llof, dtor: @object_file_res(llof)}; } /* Memory-managed interface to section iterators. */ -resource section_iter_res(SI: SectionIteratorRef) { +resource section_iter_res(SI: SectionIteratorRef) unsafe { llvm::LLVMDisposeSectionIterator(SI); } type section_iter = {llsi: SectionIteratorRef, dtor: @section_iter_res}; -fn mk_section_iter(llof: ObjectFileRef) -> section_iter { +fn mk_section_iter(llof: ObjectFileRef) -> section_iter unsafe { let llsi = llvm::LLVMGetSections(llof); ret {llsi: llsi, dtor: @section_iter_res(llsi)}; } diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 1563e3112ca1e..6a74d044bfb1d 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -70,7 +70,7 @@ fn run(handle: handle, lib_path: str, prog: str, args: [str], ret {status: status, out: output, err: errput}; } -fn writeclose(fd: int, s: option::t) { +fn writeclose(fd: int, s: option::t) unsafe { if option::is_some(s) { let writer = io::new_writer(io::fd_buf_writer(fd, option::none)); writer.write_str(option::get(s)); diff --git a/src/test/stdtest/ptr.rs b/src/test/stdtest/ptr.rs index ef0ffa54a04b9..ac829f90e5ff7 100644 --- a/src/test/stdtest/ptr.rs +++ b/src/test/stdtest/ptr.rs @@ -5,7 +5,7 @@ import std::unsafe; type pair = {mutable fst: int, mutable snd: int}; #[test] -fn test() { +fn test() unsafe { let p = {mutable fst: 10, mutable snd: 20}; let pptr: *mutable pair = ptr::addr_of(p); let iptr: *mutable int = unsafe::reinterpret_cast(pptr); diff --git a/src/test/stdtest/run.rs b/src/test/stdtest/run.rs index e5c36d37041b4..15bcf4e532007 100644 --- a/src/test/stdtest/run.rs +++ b/src/test/stdtest/run.rs @@ -23,7 +23,7 @@ fn test_leaks() { fn test_leaks() { } #[test] -fn test_pipes() { +fn test_pipes() unsafe { let pipe_in = os::pipe(); let pipe_out = os::pipe(); let pipe_err = os::pipe(); @@ -45,14 +45,14 @@ fn test_pipes() { log actual; assert (expected == actual); - fn writeclose(fd: int, s: str) { + fn writeclose(fd: int, s: str) unsafe { let writer = io::new_writer(io::fd_buf_writer(fd, option::none)); writer.write_str(s); os::libc::close(fd); } - fn readclose(fd: int) -> str { + fn readclose(fd: int) -> str unsafe { // Copied from run::program_output let file = os::fd_FILE(fd); let reader = io::new_reader(io::FILE_buf_reader(file, option::none)); @@ -67,7 +67,7 @@ fn test_pipes() { } #[test] -fn waitpid() { +fn waitpid() unsafe { let pid = run::spawn_process("false", [], 0, 0, 0); let status = run::waitpid(pid); assert status == 1; diff --git a/src/test/stdtest/sys.rs b/src/test/stdtest/sys.rs index 56cafe9217a0e..547adba7bf56e 100644 --- a/src/test/stdtest/sys.rs +++ b/src/test/stdtest/sys.rs @@ -1,4 +1,4 @@ import std::sys; #[test] -fn last_os_error() { log sys::rustrt::last_os_error(); } +fn last_os_error() unsafe { log sys::rustrt::last_os_error(); } From e4bd3ccaacc75055c19030d0cfe6175013414c49 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 15:19:34 -0700 Subject: [PATCH 18/49] all tests pass --- src/compiletest/procsrv.rs | 4 ++-- src/test/run-pass/interior-vec.rs | 2 +- src/test/run-pass/issue-506.rs | 2 +- src/test/run-pass/unify-return-ty.rs | 2 +- src/test/run-pass/unique-copy-box.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 6a74d044bfb1d..467b98d8b640a 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -79,7 +79,7 @@ fn writeclose(fd: int, s: option::t) unsafe { os::libc::close(fd); } -fn readclose(fd: int) -> str { +fn readclose(fd: int) -> str unsafe { // Copied from run::program_output let file = os::fd_FILE(fd); let reader = io::new_reader(io::FILE_buf_reader(file, option::none)); @@ -92,7 +92,7 @@ fn readclose(fd: int) -> str { ret buf; } -fn worker(p: port) { +fn worker(p: port) unsafe { // FIXME (787): If we declare this inside of the while loop and then // break out of it before it's ever initialized (i.e. we don't run diff --git a/src/test/run-pass/interior-vec.rs b/src/test/run-pass/interior-vec.rs index 0c0a3c17179b4..b28367790464c 100644 --- a/src/test/run-pass/interior-vec.rs +++ b/src/test/run-pass/interior-vec.rs @@ -4,7 +4,7 @@ native "rust-intrinsic" mod rusti { fn vec_len(&&v: [T]) -> uint; } -fn main() { +fn main() unsafe { let v: [int] = []; assert (vec_len(v) == 0u); // zero-length let x = [1, 2]; diff --git a/src/test/run-pass/issue-506.rs b/src/test/run-pass/issue-506.rs index 8285b5e1f3b4a..2ed94852bf97b 100644 --- a/src/test/run-pass/issue-506.rs +++ b/src/test/run-pass/issue-506.rs @@ -9,6 +9,6 @@ native "rust" mod rustrt { fn task_yield(); } -fn yield_wrap() { rustrt::task_yield(); } +fn yield_wrap() unsafe { rustrt::task_yield(); } fn main() { let f = yield_wrap; task::spawn(f); } diff --git a/src/test/run-pass/unify-return-ty.rs b/src/test/run-pass/unify-return-ty.rs index b8f9a39f50bd9..2a22499e8c72c 100644 --- a/src/test/run-pass/unify-return-ty.rs +++ b/src/test/run-pass/unify-return-ty.rs @@ -4,6 +4,6 @@ use std; import std::unsafe; -fn null<@T>() -> *T { unsafe::reinterpret_cast(0) } +fn null<@T>() -> *T unsafe { unsafe::reinterpret_cast(0) } fn main() { null::(); } diff --git a/src/test/run-pass/unique-copy-box.rs b/src/test/run-pass/unique-copy-box.rs index d7a5e3fe8500b..6a54407b45837 100644 --- a/src/test/run-pass/unique-copy-box.rs +++ b/src/test/run-pass/unique-copy-box.rs @@ -1,7 +1,7 @@ use std; import std::sys::rustrt::refcount; -fn main() { +fn main() unsafe { let i = ~@1; let j = ~@2; let rc1 = refcount(*i); From 01490a4e7df9ba68aafb9615bfef712a7979c382 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 15:21:50 -0700 Subject: [PATCH 19/49] all tests pass --- src/test/bench/shootout-nbody.rs | 4 ++-- src/test/compile-fail/native-type-mismatch.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 92da06f186a82..61122d8e6b48f 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -70,7 +70,7 @@ mod NBodySystem { while i < 5 { move(bodies[i], dt); i += 1; } } - fn advance_one(bi: Body::props, bj: Body::props, dt: float) { + fn advance_one(bi: Body::props, bj: Body::props, dt: float) unsafe { let dx: float = bi.x - bj.x; let dy: float = bi.y - bj.y; let dz: float = bi.z - bj.z; @@ -95,7 +95,7 @@ mod NBodySystem { b.z += dt * b.vz; } - fn energy(bodies: [Body::props]) -> float { + fn energy(bodies: [Body::props]) -> float unsafe { let dx: float; let dy: float; let dz: float; diff --git a/src/test/compile-fail/native-type-mismatch.rs b/src/test/compile-fail/native-type-mismatch.rs index d2c28ae47f18b..fb0847925325c 100644 --- a/src/test/compile-fail/native-type-mismatch.rs +++ b/src/test/compile-fail/native-type-mismatch.rs @@ -1,7 +1,7 @@ // error-pattern:expected *Mb but found native use std; -fn main() { +fn main() unsafe { let f: std::os::libc::FILE = std::io::rustrt::rust_get_stdin(); std::os::libc::fopen(f, f); } From 074657266217508a68b46dc79ab2be83c3ccf0cd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:31:23 -0700 Subject: [PATCH 20/49] add pass to check that unsafe fns cannot be used as values --- src/comp/driver/rustc.rs | 4 +- src/comp/middle/unsafeck.rs | 72 +++++++++++++++++++ src/comp/rustc.rc | 1 + .../compile-fail/unsafe-fn-used-as-value.rs | 9 +++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/comp/middle/unsafeck.rs create mode 100644 src/test/compile-fail/unsafe-fn-used-as-value.rs diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 76819b9960544..84409978bda36 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -5,7 +5,7 @@ import metadata::{creader, cstore}; import syntax::parse::{parser, token}; import syntax::{ast, codemap}; import front::attr; -import middle::{trans, resolve, freevars, kind, ty, typeck}; +import middle::{trans, resolve, freevars, kind, ty, typeck, unsafeck}; import middle::tstate::ck; import syntax::print::{pp, pprust}; import util::{ppaux, common, filesearch}; @@ -129,6 +129,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, bind freevars::annotate_freevars(def_map, crate)); let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars); time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate)); + time(time_passes, "unsafechecking", + bind unsafeck::unsafeck_crate(ty_cx, crate)); time(time_passes, "alt checking", bind middle::check_alt::check_crate(ty_cx, crate)); if sess.get_opts().run_typestate { diff --git a/src/comp/middle/unsafeck.rs b/src/comp/middle/unsafeck.rs new file mode 100644 index 0000000000000..251258f11a8b0 --- /dev/null +++ b/src/comp/middle/unsafeck.rs @@ -0,0 +1,72 @@ +import syntax::ast; +import syntax::visit; +import std::option::some; +import syntax::print::pprust::{expr_to_str, path_to_str}; + +export unsafeck_crate; + +type unsafe_ctx = { + tcx: ty::ctxt, + unsafe_fn_legal: bool +}; + +fn unsafeck_view_item(_vi: @ast::view_item, + _ctx: unsafe_ctx, + _v: visit::vt) { + // Ignore paths that appear in use, import, etc +} + +fn unsafeck_expr(expr: @ast::expr, + ctx: unsafe_ctx, + v: visit::vt) { + 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.)) | + some(ast::def_native_fn(_, ast::unsafe_fn.)) { + log_err ("expr=", expr_to_str(expr)); + ctx.tcx.sess.span_fatal( + expr.span, + "unsafe functions can only be called"); + } + + _ {} + } + } + } + + ast::expr_call(f, args) { + let f_ctx = {unsafe_fn_legal: true with ctx}; + visit::visit_expr(f, f_ctx, v); + + let args_ctx = {unsafe_fn_legal: false with ctx}; + visit::visit_exprs(args, args_ctx, v); + } + + _ { + let subctx = {unsafe_fn_legal: false with ctx}; + visit::visit_expr(expr, subctx, v); + } + } +} + +fn unsafeck_crate(tcx: ty::ctxt, crate: @ast::crate) { + let visit = + visit::mk_vt( + @{visit_expr: unsafeck_expr, + visit_view_item: unsafeck_view_item + with *visit::default_visitor()}); + let ctx = {tcx: tcx, unsafe_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 +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 9b1dff7576998..2f861155e1cab 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -25,6 +25,7 @@ mod middle { mod ast_map; mod resolve; mod typeck; + mod unsafeck; mod check_alt; mod mut; mod alias; diff --git a/src/test/compile-fail/unsafe-fn-used-as-value.rs b/src/test/compile-fail/unsafe-fn-used-as-value.rs new file mode 100644 index 0000000000000..e2fa46b0374f8 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-used-as-value.rs @@ -0,0 +1,9 @@ +// -*- rust -*- +// error-pattern: unsafe functions can only be called + +unsafe fn f() { ret; } + +fn main() { + let x = f; + x(); +} From 7dbf2e9057caafc2fd65ffb9201b453a4e1a1a2f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:36:29 -0700 Subject: [PATCH 21/49] improve the span used in test generation --- src/comp/front/test.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 70985f108060d..3e9e7916b334a 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -6,13 +6,14 @@ import syntax::ast_util::*; //import syntax::ast_util::dummy_sp; import syntax::fold; import syntax::print::pprust; +import syntax::codemap::span; import front::attr; export modify_for_testing; type node_id_gen = fn() -> ast::node_id; -type test = {path: [ast::ident], ignore: bool}; +type test = {span: span, path: [ast::ident], ignore: bool}; type test_ctxt = @{next_node_id: node_id_gen, @@ -90,7 +91,7 @@ fn fold_item(cx: test_ctxt, &&i: @ast::item, fld: fold::ast_fold) -> if is_test_fn(i) { log "this is a test function"; - let test = {path: cx.path, ignore: is_ignored(i)}; + let test = {span: i.span, path: cx.path, ignore: is_ignored(i)}; cx.testfns += [test]; log #fmt["have %u test functions", vec::len(cx.testfns)]; } @@ -237,6 +238,7 @@ fn mk_test_desc_vec(cx: test_ctxt) -> @ast::expr { } fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { + let span = test.span; let path = test.path; log #fmt["encoding %s", ast_util::path_name_i(path)]; @@ -246,7 +248,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let name_expr: ast::expr = {id: cx.next_node_id(), node: ast::expr_lit(@name_lit), - span: dummy_sp()}; + span: span}; let name_field: ast::field = nospan({mut: ast::imm, ident: "name", expr: @name_expr}); @@ -256,7 +258,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let fn_expr: ast::expr = {id: cx.next_node_id(), node: ast::expr_path(fn_path), - span: dummy_sp()}; + span: span}; let fn_field: ast::field = nospan({mut: ast::imm, ident: "fn", expr: @fn_expr}); @@ -266,7 +268,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let ignore_expr: ast::expr = {id: cx.next_node_id(), node: ast::expr_lit(@ignore_lit), - span: dummy_sp()}; + span: span}; let ignore_field: ast::field = nospan({mut: ast::imm, ident: "ignore", expr: @ignore_expr}); @@ -274,7 +276,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let desc_rec_: ast::expr_ = ast::expr_rec([name_field, fn_field, ignore_field], option::none); let desc_rec: ast::expr = - {id: cx.next_node_id(), node: desc_rec_, span: dummy_sp()}; + {id: cx.next_node_id(), node: desc_rec_, span: span}; ret @desc_rec; } From f273250fa82af262e314d185529c929738dbc2b0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:50:54 -0700 Subject: [PATCH 22/49] make a good error msg if you try to use an unsafe fn for a test --- src/comp/driver/rustc.rs | 2 +- src/comp/front/test.rs | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 84409978bda36..46f8da829a631 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -110,7 +110,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, if sess.get_opts().test { crate = time(time_passes, "building test harness", - bind front::test::modify_for_testing(crate)); + bind front::test::modify_for_testing(sess, crate)); } crate = time(time_passes, "expansion", diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 3e9e7916b334a..ce1c0f02088c7 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -7,6 +7,7 @@ import syntax::ast_util::*; import syntax::fold; import syntax::print::pprust; import syntax::codemap::span; +import driver::session; import front::attr; export modify_for_testing; @@ -16,13 +17,15 @@ type node_id_gen = fn() -> ast::node_id; type test = {span: span, path: [ast::ident], ignore: bool}; type test_ctxt = - @{next_node_id: node_id_gen, + @{sess: session::session, + next_node_id: node_id_gen, mutable path: [ast::ident], mutable testfns: [test]}; // Traverse the crate, collecting all the test functions, eliding any // existing main functions, and synthesizing a main test harness -fn modify_for_testing(crate: @ast::crate) -> @ast::crate { +fn modify_for_testing(sess: session::session, + crate: @ast::crate) -> @ast::crate { // FIXME: This hackasaurus assumes that 200000 is a safe number to start // generating node_ids at (which is totally not the case). pauls is going @@ -37,7 +40,8 @@ fn modify_for_testing(crate: @ast::crate) -> @ast::crate { }(next_node_id); let cx: test_ctxt = - @{next_node_id: next_node_id_fn, + @{sess: sess, + next_node_id: next_node_id_fn, mutable path: [], mutable testfns: []}; @@ -90,10 +94,19 @@ fn fold_item(cx: test_ctxt, &&i: @ast::item, fld: fold::ast_fold) -> log #fmt["current path: %s", ast_util::path_name_i(cx.path)]; if is_test_fn(i) { - log "this is a test function"; - let test = {span: i.span, path: cx.path, ignore: is_ignored(i)}; - cx.testfns += [test]; - log #fmt["have %u test functions", vec::len(cx.testfns)]; + alt i.node { + ast::item_fn(f, _) when f.decl.purity == ast::unsafe_fn { + cx.sess.span_fatal( + i.span, + "unsafe functions cannot be used for tests"); + } + _ { + log "this is a test function"; + let test = {span: i.span, path: cx.path, ignore: is_ignored(i)}; + cx.testfns += [test]; + log #fmt["have %u test functions", vec::len(cx.testfns)]; + } + } } let res = fold::noop_fold_item(i, fld); From 76e25c0abc9c54b79f093e78e7ed8132edd54f53 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:53:10 -0700 Subject: [PATCH 23/49] convert a few tests from unsafe fns to fns with unsafe bodies --- src/test/stdtest/str.rs | 4 ++-- src/test/stdtest/vec.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/stdtest/str.rs b/src/test/stdtest/str.rs index 8cce515ec3e7d..aa3a61f3dd515 100644 --- a/src/test/stdtest/str.rs +++ b/src/test/stdtest/str.rs @@ -256,7 +256,7 @@ fn unsafe_from_bytes() { } #[test] -unsafe fn str_from_cstr() { +fn str_from_cstr() unsafe { let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; let b = vec::to_ptr(a); let c = str::str_from_cstr(b); @@ -278,7 +278,7 @@ fn as_buf_small() { } #[test] -unsafe fn as_buf2() { +fn as_buf2() unsafe { let s = "hello"; let sb = str::as_buf(s, {|b| b }); let s_cstr = str::str_from_cstr(sb); diff --git a/src/test/stdtest/vec.rs b/src/test/stdtest/vec.rs index 313db7b71f107..3d8614f2d2448 100644 --- a/src/test/stdtest/vec.rs +++ b/src/test/stdtest/vec.rs @@ -21,7 +21,7 @@ fn square_if_odd(&&n: uint) -> option::t { fn add(&&x: uint, &&y: uint) -> uint { ret x + y; } #[test] -unsafe fn test_unsafe_ptrs() { +fn test_unsafe_ptrs() unsafe { // Test on-stack copy-from-buf. let a = [1, 2, 3]; let ptr = vec::to_ptr(a); From 6ebbe7281976c8e6df19255c1bc30eaaa7b827b2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 18:01:54 -0700 Subject: [PATCH 24/49] add some new tests --- src/test/compile-fail/native-unsafe-fn-called.rs | 11 +++++++++++ src/test/compile-fail/native-unsafe-fn.rs | 12 ++++++++++++ src/test/compile-fail/unsafe-fn-called-from-safe.rs | 1 - 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/native-unsafe-fn-called.rs create mode 100644 src/test/compile-fail/native-unsafe-fn.rs diff --git a/src/test/compile-fail/native-unsafe-fn-called.rs b/src/test/compile-fail/native-unsafe-fn-called.rs new file mode 100644 index 0000000000000..3104884130b19 --- /dev/null +++ b/src/test/compile-fail/native-unsafe-fn-called.rs @@ -0,0 +1,11 @@ +// -*- rust -*- +// error-pattern: safe function calls function marked unsafe + +native "cdecl" mod test { + unsafe fn free(); +} + +fn main() { + test::free(); +} + diff --git a/src/test/compile-fail/native-unsafe-fn.rs b/src/test/compile-fail/native-unsafe-fn.rs new file mode 100644 index 0000000000000..2a2ce4b3246e0 --- /dev/null +++ b/src/test/compile-fail/native-unsafe-fn.rs @@ -0,0 +1,12 @@ +// -*- rust -*- +// error-pattern: unsafe functions can only be called + +native "cdecl" mod test { + unsafe fn free(); +} + +fn main() { + let x = test::free; +} + + 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 b294ad16344fd..62fcfa689d97f 100644 --- a/src/test/compile-fail/unsafe-fn-called-from-safe.rs +++ b/src/test/compile-fail/unsafe-fn-called-from-safe.rs @@ -1,6 +1,5 @@ // -*- rust -*- // error-pattern: safe function calls function marked unsafe -// xfail-test unsafe fn f() { ret; } From 140a4671a1c4dcc84fa4a66d1530d0c8f7f054e8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 18:02:51 -0700 Subject: [PATCH 25/49] fix error msg --- src/comp/middle/typeck.rs | 10 ++-------- src/test/compile-fail/native-unsafe-fn-called.rs | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index f848cf638f8b8..2f115b8e836ea 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1553,18 +1553,12 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, 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_fn(_, ast::unsafe_fn.)) | 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"); + "safe function calls function marked unsafe"); } } _ { diff --git a/src/test/compile-fail/native-unsafe-fn-called.rs b/src/test/compile-fail/native-unsafe-fn-called.rs index 3104884130b19..6e9d7ac18fccc 100644 --- a/src/test/compile-fail/native-unsafe-fn-called.rs +++ b/src/test/compile-fail/native-unsafe-fn-called.rs @@ -1,6 +1,5 @@ // -*- rust -*- // error-pattern: safe function calls function marked unsafe - native "cdecl" mod test { unsafe fn free(); } From 3866463befc2b48e6d2f499ae8197823b34961e2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 21:08:01 -0700 Subject: [PATCH 26/49] prohibit ptr deref unless in unsafe code --- src/comp/middle/typeck.rs | 22 ++++++++++++++++++-- src/test/compile-fail/unsafe-fn-deref-ptr.rs | 11 ++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/unsafe-fn-deref-ptr.rs diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 2f115b8e836ea..e18e5c2c63ea9 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -193,7 +193,7 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { } -// Returns the one-level-deep structure of the given type. +// Returns the one-level-deep structure of the given type.f fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty { ret ty::struct(fcx.ccx.tcx, structurally_resolved_type(fcx, sp, typ)); } @@ -1530,7 +1530,7 @@ fn require_unsafe(sess: session::session, f_purity: ast::purity, sp: span) { _ { sess.span_fatal( sp, - "Found unsafe expression in safe function decl"); + "unsafe operation requires unsafe function or block"); } } } @@ -1591,6 +1591,23 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { ret check_expr_with_unifier(fcx, expr, demand::simple, expected); } +fn check_for_unsafe_assignments(fcx: @fn_ctxt, lhs: @ast::expr) { + alt lhs.node { + ast::expr_unary(ast::deref., ptr) { + let ty = expr_ty(fcx.ccx.tcx, ptr); + let sty = structure_of(fcx, ptr.span, ty); + alt sty { + ty::ty_ptr(_) { + require_unsafe(fcx.ccx.tcx.sess, fcx.purity, lhs.span); + } + _ {} + } + } + _ { + } + } +} + fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, expected: ty::t) -> bool { //log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr); @@ -1702,6 +1719,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, rhs: @ast::expr, id: ast::node_id) -> bool { let t = next_ty_var(fcx); let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t); + check_for_unsafe_assignments(fcx, lhs); write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx)); ret bot; } diff --git a/src/test/compile-fail/unsafe-fn-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-deref-ptr.rs new file mode 100644 index 0000000000000..cf5dac3ff89f4 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-deref-ptr.rs @@ -0,0 +1,11 @@ +// -*- rust -*- +// error-pattern: unsafe operation requires unsafe function or block + +fn f(p: *u8) { + *p = 0u8; + ret; +} + +fn main() { + f(); +} From 991314c32ea66deca56e0e8c848ef3b1a276119d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 21:21:52 -0700 Subject: [PATCH 27/49] make compiler emit more than 1 error in the case of unsafe --- src/comp/middle/typeck.rs | 31 +++++--------------- src/test/compile-fail/unsafe-fn-deref-ptr.rs | 5 ++-- src/test/stdtest/str.rs | 4 +-- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index e18e5c2c63ea9..aed017eeef56e 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1528,7 +1528,7 @@ fn require_unsafe(sess: session::session, f_purity: ast::purity, sp: span) { alt f_purity { ast::unsafe_fn. { ret; } _ { - sess.span_fatal( + sess.span_err( sp, "unsafe operation requires unsafe function or block"); } @@ -1541,7 +1541,7 @@ fn require_impure(sess: session::session, f_purity: ast::purity, sp: span) { ast::unsafe_fn. { ret; } ast::impure_fn. { ret; } ast::pure_fn. { - sess.span_fatal(sp, "Found impure expression in pure function decl"); + sess.span_err(sp, "Found impure expression in pure function decl"); } } } @@ -1556,7 +1556,7 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, some(ast::def_fn(_, ast::unsafe_fn.)) | some(ast::def_native_fn(_, ast::unsafe_fn.)) { if sess.get_opts().check_unsafe { - ccx.tcx.sess.span_fatal( + ccx.tcx.sess.span_err( sp, "safe function calls function marked unsafe"); } @@ -1570,7 +1570,7 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, alt ccx.tcx.def_map.find(callee.id) { some(ast::def_fn(_, ast::pure_fn.)) { ret; } _ { - ccx.tcx.sess.span_fatal + ccx.tcx.sess.span_err (sp, "pure function calls function not known to be pure"); } } @@ -1591,23 +1591,6 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { ret check_expr_with_unifier(fcx, expr, demand::simple, expected); } -fn check_for_unsafe_assignments(fcx: @fn_ctxt, lhs: @ast::expr) { - alt lhs.node { - ast::expr_unary(ast::deref., ptr) { - let ty = expr_ty(fcx.ccx.tcx, ptr); - let sty = structure_of(fcx, ptr.span, ty); - alt sty { - ty::ty_ptr(_) { - require_unsafe(fcx.ccx.tcx.sess, fcx.purity, lhs.span); - } - _ {} - } - } - _ { - } - } -} - fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, expected: ty::t) -> bool { //log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr); @@ -1719,7 +1702,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, rhs: @ast::expr, id: ast::node_id) -> bool { let t = next_ty_var(fcx); let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t); - check_for_unsafe_assignments(fcx, lhs); write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx)); ret bot; } @@ -1872,7 +1854,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, oper_t = ty::substitute_type_params(tcx, tps, variants[0].args[0]); } - ty::ty_ptr(inner) { oper_t = inner.ty; } + ty::ty_ptr(inner) { + oper_t = inner.ty; + require_unsafe(fcx.ccx.tcx.sess, fcx.purity, expr.span); + } _ { tcx.sess.span_fatal(expr.span, "dereferencing non-" + diff --git a/src/test/compile-fail/unsafe-fn-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-deref-ptr.rs index cf5dac3ff89f4..238acc8729c2b 100644 --- a/src/test/compile-fail/unsafe-fn-deref-ptr.rs +++ b/src/test/compile-fail/unsafe-fn-deref-ptr.rs @@ -1,9 +1,8 @@ // -*- rust -*- // error-pattern: unsafe operation requires unsafe function or block -fn f(p: *u8) { - *p = 0u8; - ret; +fn f(p: *u8) -> u8 { + ret *p; } fn main() { diff --git a/src/test/stdtest/str.rs b/src/test/stdtest/str.rs index aa3a61f3dd515..470c8daee5e57 100644 --- a/src/test/stdtest/str.rs +++ b/src/test/stdtest/str.rs @@ -264,14 +264,14 @@ fn str_from_cstr() unsafe { } #[test] -fn as_buf() { +fn as_buf() unsafe { let a = "Abcdefg"; let b = str::as_buf(a, {|buf| assert (*buf == 65u8); 100 }); assert (b == 100); } #[test] -fn as_buf_small() { +fn as_buf_small() unsafe { let a = "A"; let b = str::as_buf(a, {|buf| assert (*buf == 65u8); 100 }); assert (b == 100); From b70e41cb331c80dd8d966bcfb5c384023eaa5311 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 21:22:08 -0700 Subject: [PATCH 28/49] new test --- src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs diff --git a/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs new file mode 100644 index 0000000000000..cf5dac3ff89f4 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs @@ -0,0 +1,11 @@ +// -*- rust -*- +// error-pattern: unsafe operation requires unsafe function or block + +fn f(p: *u8) { + *p = 0u8; + ret; +} + +fn main() { + f(); +} From 8029ce8bba0c93c7084c6766141d52961c7a25e4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 22:08:36 -0700 Subject: [PATCH 29/49] remove unsafe tags --- src/comp/lib/llvm.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 8a6464cc1cfdc..c028c028e6b26 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -925,7 +925,7 @@ fn type_to_str(names: type_names, ty: TypeRef) -> str { } fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> - str unsafe { + str { if names.type_has_name(ty) { ret names.get_name(ty); } @@ -956,7 +956,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> 7 { ret "i" + std::int::str(llvm::LLVMGetIntTypeWidth(ty) as int); } - 8 { + 8 unsafe { let s = "fn("; let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); let n_args: uint = llvm::LLVMCountParamTypes(ty); @@ -969,7 +969,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> s += type_to_str_inner(names, outer, out_ty); ret s; } - 9 { + 9 unsafe { let s: str = "{"; let n_elts: uint = llvm::LLVMCountStructElementTypes(ty); let elts: [TypeRef] = vec::init_elt::(0 as TypeRef, n_elts); @@ -1003,7 +1003,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> } } -fn float_width(llt: TypeRef) -> uint unsafe { +fn float_width(llt: TypeRef) -> uint { ret alt llvm::LLVMGetTypeKind(llt) { 1 { 32u } 2 { 64u } @@ -1022,13 +1022,13 @@ fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] unsafe { /* Memory-managed interface to target data. */ -resource target_data_res(TD: TargetDataRef) unsafe { +resource target_data_res(TD: TargetDataRef) { llvm::LLVMDisposeTargetData(TD); } type target_data = {lltd: TargetDataRef, dtor: @target_data_res}; -fn mk_target_data(string_rep: str) -> target_data unsafe { +fn mk_target_data(string_rep: str) -> target_data { let lltd = str::as_buf(string_rep, {|buf| llvm::LLVMCreateTargetData(buf) }); ret {lltd: lltd, dtor: @target_data_res(lltd)}; @@ -1036,39 +1036,39 @@ fn mk_target_data(string_rep: str) -> target_data unsafe { /* Memory-managed interface to pass managers. */ -resource pass_manager_res(PM: PassManagerRef) unsafe { +resource pass_manager_res(PM: PassManagerRef) { llvm::LLVMDisposePassManager(PM); } type pass_manager = {llpm: PassManagerRef, dtor: @pass_manager_res}; -fn mk_pass_manager() -> pass_manager unsafe { +fn mk_pass_manager() -> pass_manager { let llpm = llvm::LLVMCreatePassManager(); ret {llpm: llpm, dtor: @pass_manager_res(llpm)}; } /* Memory-managed interface to object files. */ -resource object_file_res(ObjectFile: ObjectFileRef) unsafe { +resource object_file_res(ObjectFile: ObjectFileRef) { llvm::LLVMDisposeObjectFile(ObjectFile); } type object_file = {llof: ObjectFileRef, dtor: @object_file_res}; -fn mk_object_file(llmb: MemoryBufferRef) -> object_file unsafe { +fn mk_object_file(llmb: MemoryBufferRef) -> object_file { let llof = llvm::LLVMCreateObjectFile(llmb); ret {llof: llof, dtor: @object_file_res(llof)}; } /* Memory-managed interface to section iterators. */ -resource section_iter_res(SI: SectionIteratorRef) unsafe { +resource section_iter_res(SI: SectionIteratorRef) { llvm::LLVMDisposeSectionIterator(SI); } type section_iter = {llsi: SectionIteratorRef, dtor: @section_iter_res}; -fn mk_section_iter(llof: ObjectFileRef) -> section_iter unsafe { +fn mk_section_iter(llof: ObjectFileRef) -> section_iter { let llsi = llvm::LLVMGetSections(llof); ret {llsi: llsi, dtor: @section_iter_res(llsi)}; } From f5f9e2d50325f24714d371f230e2e10f3c6ddc5d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Oct 2011 13:31:41 -0700 Subject: [PATCH 30/49] reimplement some of the unsafe stuff which got lost: - blocks inherit unsafety - remove the --check-unsafe flag - add unsafe annotations where needed to get things to compile --- src/comp/back/link.rs | 17 ++-- src/comp/driver/rustc.rs | 4 +- src/comp/driver/session.rs | 3 +- src/comp/lib/llvm.rs | 4 +- src/comp/metadata/creader.rs | 36 ++++---- src/comp/metadata/decoder.rs | 4 + src/comp/middle/gc.rs | 6 +- src/comp/middle/shape.rs | 6 +- src/comp/middle/trans_build.rs | 6 +- src/comp/middle/trans_common.rs | 86 ++++++++----------- src/comp/middle/trans_objects.rs | 4 +- src/comp/middle/typeck.rs | 36 ++++---- src/compiletest/procsrv.rs | 6 +- src/lib/aio.rs | 4 +- src/lib/dbg.rs | 6 +- src/lib/generic_os.rs | 2 +- src/lib/io.rs | 6 +- src/lib/run_program.rs | 2 +- src/lib/str.rs | 8 +- src/lib/sys.rs | 24 ++---- src/lib/task.rs | 2 +- src/lib/vec.rs | 12 ++- .../compile-fail/unsafe-fn-used-in-bind.rs | 9 ++ 23 files changed, 137 insertions(+), 156 deletions(-) create mode 100644 src/test/compile-fail/unsafe-fn-used-in-bind.rs diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index fbf1f4b78813d..4a7e238ae55d1 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -34,16 +34,14 @@ tag output_type { output_type_exe; } -fn llvm_err(sess: session::session, msg: str) { - unsafe { - let buf = llvm::LLVMRustGetLastError(); - if buf == std::ptr::null() { - sess.fatal(msg); - } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } - } +fn llvm_err(sess: session::session, msg: str) unsafe { + let buf = llvm::LLVMRustGetLastError(); + if buf == std::ptr::null() { + sess.fatal(msg); + } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } } -fn link_intrinsics(sess: session::session, llmod: ModuleRef) unsafe { +fn link_intrinsics(sess: session::session, llmod: ModuleRef) { let path = alt filesearch::search( sess.filesearch(), bind filesearch::pick_file("intrinsics.bc", _)) { @@ -90,8 +88,7 @@ mod write { } else { stem = str::substr(output_path, 0u, dot_pos as uint); } ret stem + "." + extension; } - fn run_passes(sess: session::session, llmod: ModuleRef, output: str) - unsafe { + fn run_passes(sess: session::session, llmod: ModuleRef, output: str) { let opts = sess.get_opts(); if opts.time_llvm_passes { llvm::LLVMRustEnableTimePasses(); } link_intrinsics(sess, llmod); diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 46f8da829a631..43d138c9e1acc 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -325,7 +325,6 @@ 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 { @@ -397,8 +396,7 @@ fn build_session_options(match: getopts::match) parse_only: parse_only, no_trans: no_trans, do_gc: do_gc, - stack_growth: stack_growth, - check_unsafe: check_unsafe}; + stack_growth: stack_growth}; ret sopts; } diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 6ba2148e8a4c8..1f3f9baab8a90 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -41,8 +41,7 @@ type options = parse_only: bool, no_trans: bool, do_gc: bool, - stack_growth: bool, - check_unsafe: bool}; + stack_growth: bool}; type crate_metadata = {name: str, data: [u8]}; diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index c028c028e6b26..9562e05bed575 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -956,7 +956,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> 7 { ret "i" + std::int::str(llvm::LLVMGetIntTypeWidth(ty) as int); } - 8 unsafe { + 8 { let s = "fn("; let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); let n_args: uint = llvm::LLVMCountParamTypes(ty); @@ -969,7 +969,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> s += type_to_str_inner(names, outer, out_ty); ret s; } - 9 unsafe { + 9 { let s: str = "{"; let n_elts: uint = llvm::LLVMCountStructElementTypes(ty); let elts: [TypeRef] = vec::init_elt::(0 as TypeRef, n_elts); diff --git a/src/comp/metadata/creader.rs b/src/comp/metadata/creader.rs index 1dd51a8b680ab..fe352290d2c81 100644 --- a/src/comp/metadata/creader.rs +++ b/src/comp/metadata/creader.rs @@ -169,27 +169,25 @@ fn find_library_crate_aux(nn: {prefix: str, suffix: str}, crate_name: str, }); } -fn get_metadata_section(filename: str) -> option::t<@[u8]> { - unsafe { - let mb = str::as_buf(filename, {|buf| - llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) - }); - if mb as int == 0 { ret option::none::<@[u8]>; } - let of = mk_object_file(mb); - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let name_buf = llvm::LLVMGetSectionName(si.llsi); - let name = str::str_from_cstr(name_buf); - if str::eq(name, x86::get_meta_sect_name()) { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi); - let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); - ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); - } - llvm::LLVMMoveToNextSection(si.llsi); +fn get_metadata_section(filename: str) -> option::t<@[u8]> unsafe { + let mb = str::as_buf(filename, {|buf| + llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) + }); + if mb as int == 0 { ret option::none::<@[u8]>; } + let of = mk_object_file(mb); + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let name_buf = llvm::LLVMGetSectionName(si.llsi); + let name = str::str_from_cstr(name_buf); + if str::eq(name, x86::get_meta_sect_name()) { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi); + let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); + ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); } - ret option::none::<@[u8]>; + llvm::LLVMMoveToNextSection(si.llsi); } + ret option::none::<@[u8]>; } fn load_library_crate(sess: session::session, span: span, ident: ast::ident, diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index 4a103d357558a..8d3f8f5d82440 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -256,6 +256,8 @@ fn family_has_type_params(fam_ch: u8) -> bool { 'u' { true } 'p' { true } 'F' { true } + 'U' { true } + 'P' { true } 'y' { true } 't' { true } 'T' { false } @@ -285,6 +287,8 @@ fn item_family_to_str(fam: u8) -> str { 'u' { ret "unsafe fn"; } 'p' { ret "pure fn"; } 'F' { ret "native fn"; } + 'U' { ret "unsafe native fn"; } + 'P' { ret "pure native fn"; } 'y' { ret "type"; } 'T' { ret "native type"; } 't' { ret "type"; } diff --git a/src/comp/middle/gc.rs b/src/comp/middle/gc.rs index 7de07b55e3b17..be5376bc2b6bf 100644 --- a/src/comp/middle/gc.rs +++ b/src/comp/middle/gc.rs @@ -16,8 +16,7 @@ type ctxt = @{mutable next_tydesc_num: uint}; fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; } -fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) - -> ValueRef unsafe { +fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef { let llglobal = str::as_buf(name, {|buf| @@ -28,8 +27,7 @@ fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) ret llglobal; } -fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> - @block_ctxt unsafe { +fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt { let bcx = cx; if !type_is_gc_relevant(bcx_tcx(cx), ty) || ty::type_has_dynamic_size(bcx_tcx(cx), ty) { diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index 17c72d6b6c21b..7c54bde66b32f 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -72,7 +72,7 @@ fn eq_res_info(a: res_info, b: res_info) -> bool { } fn mk_global(ccx: @crate_ctxt, name: str, llval: ValueRef, internal: bool) -> - ValueRef unsafe { + ValueRef { let llglobal = str::as_buf(name, {|buf| @@ -245,7 +245,7 @@ fn s_float(_tcx: ty_ctxt) -> u8 { ret shape_f64; // TODO: x86-64 } -fn mk_ctxt(llmod: ModuleRef) -> ctxt unsafe { +fn mk_ctxt(llmod: ModuleRef) -> ctxt { let llshapetablesty = trans_common::T_named_struct("shapes"); let llshapetables = str::as_buf("shapes", @@ -580,7 +580,7 @@ fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef { ret mk_global(ccx, "resource_shapes", C_struct(dtors), true); } -fn gen_shape_tables(ccx: @crate_ctxt) unsafe { +fn gen_shape_tables(ccx: @crate_ctxt) { let lltagstable = gen_tag_shapes(ccx); let llresourcestable = gen_resource_shapes(ccx); trans_common::set_struct_body(ccx.shape_cx.llshapetablesty, diff --git a/src/comp/middle/trans_build.rs b/src/comp/middle/trans_build.rs index 7cf9a9c27b3f2..d0b0523af9372 100644 --- a/src/comp/middle/trans_build.rs +++ b/src/comp/middle/trans_build.rs @@ -492,16 +492,16 @@ fn _UndefReturn(Fn: ValueRef) -> ValueRef { } fn Call(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { + if cx.unreachable { ret _UndefReturn(Fn); } unsafe { - if cx.unreachable { ret _UndefReturn(Fn); } ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); } } fn FastCall(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { + if cx.unreachable { ret _UndefReturn(Fn); } unsafe { - if cx.unreachable { ret _UndefReturn(Fn); } let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); @@ -511,8 +511,8 @@ fn FastCall(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { fn CallWithConv(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], Conv: uint) -> ValueRef { + if cx.unreachable { ret _UndefReturn(Fn); } unsafe { - if cx.unreachable { ret _UndefReturn(Fn); } let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); llvm::LLVMSetInstructionCallConv(v, Conv); diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 945530d87d2af..6ed895aa6559b 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -427,14 +427,12 @@ fn val_ty(v: ValueRef) -> TypeRef { ret llvm::LLVMTypeOf(v); } fn val_str(tn: type_names, v: ValueRef) -> str { ret ty_str(tn, val_ty(v)); } // Returns the nth element of the given LLVM structure type. -fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef { - unsafe { - let elt_count = llvm::LLVMCountStructElementTypes(llstructty); - assert (n < elt_count); - let elt_tys = std::vec::init_elt(T_nil(), elt_count); - llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); - ret llvm::LLVMGetElementType(elt_tys[n]); - } +fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef unsafe { + let elt_count = llvm::LLVMCountStructElementTypes(llstructty); + assert (n < elt_count); + let elt_tys = std::vec::init_elt(T_nil(), elt_count); + llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); + ret llvm::LLVMGetElementType(elt_tys[n]); } fn find_scope_cx(cx: @block_ctxt) -> @block_ctxt { @@ -541,10 +539,8 @@ fn T_named_struct(name: str) -> TypeRef { ret str::as_buf(name, {|buf| llvm::LLVMStructCreateNamed(c, buf) }); } -fn set_struct_body(t: TypeRef, elts: [TypeRef]) { - unsafe { - llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); - } +fn set_struct_body(t: TypeRef, elts: [TypeRef]) unsafe { + llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); } fn T_empty_struct() -> TypeRef { ret T_struct([]); } @@ -581,18 +577,16 @@ fn T_task() -> TypeRef { ret t; } -fn T_tydesc_field(cx: crate_ctxt, field: int) -> TypeRef { +fn T_tydesc_field(cx: crate_ctxt, field: int) -> TypeRef unsafe { // Bit of a kludge: pick the fn typeref out of the tydesc.. - unsafe { - let tydesc_elts: [TypeRef] = - std::vec::init_elt::(T_nil(), - abi::n_tydesc_fields as uint); - llvm::LLVMGetStructElementTypes(cx.tydesc_type, - to_ptr::(tydesc_elts)); - let t = llvm::LLVMGetElementType(tydesc_elts[field]); - ret t; - } + let tydesc_elts: [TypeRef] = + std::vec::init_elt::(T_nil(), + abi::n_tydesc_fields as uint); + llvm::LLVMGetStructElementTypes(cx.tydesc_type, + to_ptr::(tydesc_elts)); + let t = llvm::LLVMGetElementType(tydesc_elts[field]); + ret t; } fn T_glue_fn(cx: crate_ctxt) -> TypeRef { @@ -798,43 +792,33 @@ fn C_postr(s: str) -> ValueRef { }); } -fn C_zero_byte_arr(size: uint) -> ValueRef { - unsafe { - let i = 0u; - let elts: [ValueRef] = []; - while i < size { elts += [C_u8(0u)]; i += 1u; } - ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), - std::vec::len(elts)); - } +fn C_zero_byte_arr(size: uint) -> ValueRef unsafe { + let i = 0u; + let elts: [ValueRef] = []; + while i < size { elts += [C_u8(0u)]; i += 1u; } + ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), + std::vec::len(elts)); } -fn C_struct(elts: [ValueRef]) -> ValueRef { - unsafe { - ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), - False); - } +fn C_struct(elts: [ValueRef]) -> ValueRef unsafe { + ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), + False); } -fn C_named_struct(T: TypeRef, elts: [ValueRef]) -> ValueRef { - unsafe { - ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), - std::vec::len(elts)); - } +fn C_named_struct(T: TypeRef, elts: [ValueRef]) -> ValueRef unsafe { + ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), + std::vec::len(elts)); } -fn C_array(ty: TypeRef, elts: [ValueRef]) -> ValueRef { - unsafe { - ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), - std::vec::len(elts)); - } +fn C_array(ty: TypeRef, elts: [ValueRef]) -> ValueRef unsafe { + ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), + std::vec::len(elts)); } -fn C_bytes(bytes: [u8]) -> ValueRef { - unsafe { - ret llvm::LLVMConstString( - unsafe::reinterpret_cast(vec::to_ptr(bytes)), - vec::len(bytes), False); - } +fn C_bytes(bytes: [u8]) -> ValueRef unsafe { + ret llvm::LLVMConstString( + unsafe::reinterpret_cast(vec::to_ptr(bytes)), + vec::len(bytes), False); } fn C_shape(ccx: @crate_ctxt, bytes: [u8]) -> ValueRef { diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs index af5f4266b9eb3..a2a63d88306fe 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -569,7 +569,7 @@ fn create_backwarding_vtbl(cx: @local_ctxt, sp: span, inner_obj_ty: ty::t, // finish_vtbl: Given a vector of vtable entries, create the table in // read-only memory and return a pointer to it. fn finish_vtbl(cx: @local_ctxt, llmethods: [ValueRef], name: str) -> - ValueRef unsafe { + ValueRef { let vtbl = C_struct(llmethods); let vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + [name]); let gvar = @@ -619,7 +619,7 @@ fn begin_fn(cx: @local_ctxt, sp: span, m: @ty::method, // returns the value returned from that call. fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, ty_params: [ast::ty_param], outer_obj_ty: ty::t, - _additional_field_tys: [ty::t]) -> ValueRef unsafe { + _additional_field_tys: [ty::t]) -> ValueRef { let llbackwarding_fn = begin_fn(cx, sp, m, ty_params, "backwarding_fn"); let fcx = new_fn_ctxt(cx, sp, llbackwarding_fn); diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index aed017eeef56e..4b0f4f7b1c101 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1524,15 +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) { - if sess.get_opts().check_unsafe { - alt f_purity { - ast::unsafe_fn. { ret; } - _ { - sess.span_err( - sp, - "unsafe operation requires unsafe function or block"); - } - } + alt f_purity { + ast::unsafe_fn. { ret; } + _ { + sess.span_err( + sp, + "unsafe operation requires unsafe function or block"); + } } } @@ -1551,15 +1549,12 @@ 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.)) | some(ast::def_native_fn(_, ast::unsafe_fn.)) { - if sess.get_opts().check_unsafe { - ccx.tcx.sess.span_err( - sp, - "safe function calls function marked unsafe"); - } + ccx.tcx.sess.span_err( + sp, + "safe function calls function marked unsafe"); } _ { } @@ -2727,13 +2722,22 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, old_fcx: option::t<@fn_ctxt>) { + let decl = f.decl; let body = f.body; + + // If old_fcx is some(...), this is a block fn { |x| ... }. + // In that case, the purity is inherited from the context. + let purity = alt old_fcx { + none. { decl.purity } + some(f) { assert decl.purity == ast::impure_fn; f.purity } + }; + let gather_result = gather_locals(ccx, f, id, old_fcx); let fixups: [ast::node_id] = []; let fcx: @fn_ctxt = @{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)), - purity: decl.purity, + purity: purity, proto: f.proto, var_bindings: gather_result.var_bindings, locals: gather_result.locals, diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 467b98d8b640a..1563e3112ca1e 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -70,7 +70,7 @@ fn run(handle: handle, lib_path: str, prog: str, args: [str], ret {status: status, out: output, err: errput}; } -fn writeclose(fd: int, s: option::t) unsafe { +fn writeclose(fd: int, s: option::t) { if option::is_some(s) { let writer = io::new_writer(io::fd_buf_writer(fd, option::none)); writer.write_str(option::get(s)); @@ -79,7 +79,7 @@ fn writeclose(fd: int, s: option::t) unsafe { os::libc::close(fd); } -fn readclose(fd: int) -> str unsafe { +fn readclose(fd: int) -> str { // Copied from run::program_output let file = os::fd_FILE(fd); let reader = io::new_reader(io::FILE_buf_reader(file, option::none)); @@ -92,7 +92,7 @@ fn readclose(fd: int) -> str unsafe { ret buf; } -fn worker(p: port) unsafe { +fn worker(p: port) { // FIXME (787): If we declare this inside of the while loop and then // break out of it before it's ever initialized (i.e. we don't run diff --git a/src/lib/aio.rs b/src/lib/aio.rs index 5d7430a82ecfe..42f744ff865e8 100644 --- a/src/lib/aio.rs +++ b/src/lib/aio.rs @@ -41,7 +41,7 @@ tag request { type ctx = chan; -fn ip_to_sbuf(ip: net::ip_addr) -> *u8 { +fn ip_to_sbuf(ip: net::ip_addr) -> *u8 unsafe { // FIXME: This is broken. We're creating a vector, getting a pointer // to its buffer, then dropping the vector. On top of that, the vector @@ -131,7 +131,7 @@ fn request_task(c: chan) { serve(ip, portnum, events, server) { task::spawn(bind server_task(ip, portnum, events, server)); } - write(socket, v, status) { + write(socket, v, status) unsafe { rustrt::aio_writedata(socket, vec::unsafe::to_ptr::(v), vec::len::(v), status); } diff --git a/src/lib/dbg.rs b/src/lib/dbg.rs index 6371eec349bf6..af568ee8f0cf1 100644 --- a/src/lib/dbg.rs +++ b/src/lib/dbg.rs @@ -42,9 +42,11 @@ fn debug_obj(x: T, nmethods: uint, nbytes: uint) { fn debug_fn(x: T) { rustrt::debug_fn::(x); } -fn ptr_cast(x: @T) -> @U { ret rustrt::debug_ptrcast::(x); } +unsafe fn ptr_cast(x: @T) -> @U { + ret rustrt::debug_ptrcast::(x); +} -fn refcount(a: @T) -> uint { +fn refcount(a: @T) -> uint unsafe { let p: *uint = unsafe::reinterpret_cast(a); ret *p; } diff --git a/src/lib/generic_os.rs b/src/lib/generic_os.rs index e179aa1f92c28..d1e39a2ea9f8f 100644 --- a/src/lib/generic_os.rs +++ b/src/lib/generic_os.rs @@ -3,7 +3,7 @@ import str::sbuf; #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] -fn getenv(n: str) -> option::t { +fn getenv(n: str) -> option::t unsafe { let s = str::as_buf(n, {|buf| os::libc::getenv(buf) }); ret if unsafe::reinterpret_cast(s) == 0 { option::none:: diff --git a/src/lib/io.rs b/src/lib/io.rs index c2ee7ff53ca5c..327e565588963 100644 --- a/src/lib/io.rs +++ b/src/lib/io.rs @@ -57,7 +57,7 @@ fn convert_whence(whence: seek_style) -> int { resource FILE_res(f: os::libc::FILE) { os::libc::fclose(f); } obj FILE_buf_reader(f: os::libc::FILE, res: option::t<@FILE_res>) { - fn read(len: uint) -> [u8] { + fn read(len: uint) -> [u8] unsafe { let buf = []; vec::reserve::(buf, len); let read = @@ -239,7 +239,7 @@ type buf_writer = }; obj FILE_writer(f: os::libc::FILE, res: option::t<@FILE_res>) { - fn write(v: [u8]) { + fn write(v: [u8]) unsafe { let len = vec::len::(v); let vbuf = vec::unsafe::to_ptr::(v); let nout = os::libc::fwrite(vbuf, len, 1u, f); @@ -254,7 +254,7 @@ obj FILE_writer(f: os::libc::FILE, res: option::t<@FILE_res>) { resource fd_res(fd: int) { os::libc::close(fd); } obj fd_buf_writer(fd: int, res: option::t<@fd_res>) { - fn write(v: [u8]) { + fn write(v: [u8]) unsafe { let len = vec::len::(v); let count = 0u; let vbuf; diff --git a/src/lib/run_program.rs b/src/lib/run_program.rs index 31bccf320374c..cb36179587fa5 100644 --- a/src/lib/run_program.rs +++ b/src/lib/run_program.rs @@ -21,7 +21,7 @@ fn arg_vec(prog: str, args: [@str]) -> [sbuf] { } fn spawn_process(prog: str, args: [str], in_fd: int, out_fd: int, err_fd: int) - -> int { + -> int unsafe { // Note: we have to hold on to these vector references while we hold a // pointer to their buffers let prog = prog; diff --git a/src/lib/str.rs b/src/lib/str.rs index a3c8a5486920d..7a5660244223e 100644 --- a/src/lib/str.rs +++ b/src/lib/str.rs @@ -426,16 +426,18 @@ type sbuf = *u8; // NB: This is intentionally unexported because it's easy to misuse (there's // no guarantee that the string is rooted). Instead, use as_buf below. -fn buf(s: str) -> sbuf { +unsafe fn buf(s: str) -> sbuf { let saddr = ptr::addr_of(s); let vaddr: *[u8] = unsafe::reinterpret_cast(saddr); let buf = vec::to_ptr(*vaddr); ret buf; } -fn as_buf(s: str, f: block(sbuf) -> T) -> T { let buf = buf(s); f(buf) } +fn as_buf(s: str, f: block(sbuf) -> T) -> T unsafe { + let buf = buf(s); f(buf) +} -fn str_from_cstr(cstr: sbuf) -> str { +unsafe fn str_from_cstr(cstr: sbuf) -> str { let res = ""; let start = cstr; let curr = start; diff --git a/src/lib/sys.rs b/src/lib/sys.rs index c366e7c4ce52c..40209f9e54eb2 100644 --- a/src/lib/sys.rs +++ b/src/lib/sys.rs @@ -15,39 +15,27 @@ native "rust" mod rustrt { } fn last_os_error() -> str { - //unsafe { - ret rustrt::last_os_error(); - //} + ret rustrt::last_os_error(); } fn size_of() -> uint { - //unsafe { - ret rustrt::size_of::(); - //} + ret rustrt::size_of::(); } fn align_of() -> uint { - //unsafe { - ret rustrt::align_of::(); - //} + ret rustrt::align_of::(); } fn refcount(t: @T) -> uint { - //unsafe { - ret rustrt::refcount::(t); - //} + ret rustrt::refcount::(t); } fn do_gc() -> () { - //unsafe { - ret rustrt::do_gc(); - //} + ret rustrt::do_gc(); } fn unsupervise() -> () { - //unsafe { - ret rustrt::unsupervise(); - //} + ret rustrt::unsupervise(); } // Local Variables: diff --git a/src/lib/task.rs b/src/lib/task.rs index 7a95ea49aafd9..de1a749fee35e 100644 --- a/src/lib/task.rs +++ b/src/lib/task.rs @@ -108,7 +108,7 @@ fn spawn_joinable(-thunk: fn()) -> joinable_task { // FIXME: make this a fn~ once those are supported. fn spawn_inner(-thunk: fn(), notify: option>) -> - task_id { + task_id unsafe { let id = rustrt::new_task(); let raw_thunk: {code: u32, env: u32} = cast(thunk); diff --git a/src/lib/vec.rs b/src/lib/vec.rs index b2d19d9ed54e2..04e35e9e979b2 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -15,9 +15,7 @@ native "rust" mod rustrt { /// Reserves space for `n` elements in the given vector. fn reserve<@T>(&v: [mutable? T], n: uint) { - //unsafe { - rustrt::vec_reserve_shared(v, n); - //} + rustrt::vec_reserve_shared(v, n); } pure fn len(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } } @@ -353,22 +351,22 @@ iter iter2<@T>(v: [T]) -> (uint, T) { mod unsafe { type vec_repr = {mutable fill: uint, mutable alloc: uint, data: u8}; - fn from_buf<@T>(ptr: *T, elts: uint) -> [T] { + unsafe fn from_buf<@T>(ptr: *T, elts: uint) -> [T] { ret rustrt::vec_from_buf_shared(ptr, elts); } - fn set_len<@T>(&v: [T], new_len: uint) { + unsafe fn set_len<@T>(&v: [T], new_len: uint) { let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); (**repr).fill = new_len * sys::size_of::(); } - fn to_ptr<@T>(v: [T]) -> *T { + unsafe fn to_ptr<@T>(v: [T]) -> *T { let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); ret ::unsafe::reinterpret_cast(addr_of((**repr).data)); } } -fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); } +unsafe fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); } // Local Variables: // mode: rust; diff --git a/src/test/compile-fail/unsafe-fn-used-in-bind.rs b/src/test/compile-fail/unsafe-fn-used-in-bind.rs new file mode 100644 index 0000000000000..2622afe2e39f0 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-used-in-bind.rs @@ -0,0 +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, _); + let y = x(4); +} From 7f92f884ffe6cb1a94d5e1e093bbd6bc51c5bd5e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 15:51:55 -0700 Subject: [PATCH 31/49] 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. --- .../run-pass/unsafe-fn-called-from-unsafe-blk | Bin 0 -> 9936 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 src/test/run-pass/unsafe-fn-called-from-unsafe-blk 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 zcmeHNZEO_B8J@j8hiiJkK@MsNDGNO+RDnN;Ax=xHGx$3ErOY>@AiDx+?RIu z%!i8P^nkEksIIEoMxshBH9w;Mp+ESMs%=DMq@*9JT(weL300N?(N%UU)1rV{8uxi; z_k7FwoTUHq;|AWDcix%znRnj#*tr@1?%#iZe+6Sq2Khj1K!XsRpV%Tv;JZPb5A=LF zb}V+}tH@MCsLCu&NpBcnoDar^2R-GaQ`JLC?Y4jdZWYc=?Ud0ES`e>D-uGSdZ~KFrG%)>%i~^a&t9sUd)|L=Mp@fOXeZ0$G8KGmm$AX zhf&q1lyfb`le(JK9BDm9`P1+P2Bf@d`M%J2g<%-yy*-0H4vvTw#MQaw&MWc<%`Xa^ z7xerX+UDb`ZZy^pQ$^@LG_OeJ2F`PsQ_j>XnEDbM!ir-;7#LpP(R`}ekx@SgBLWOe zPZp`eApK8*C@h^55BnmjIO{12jOFJPt48&(-n|_hnddd`jhBpL#KfclM~hgNMEn>pe&dlR^gw_A`aCX$%7S(5ttV zu?ea|095^am}A0d`%_QA$yPaCF|ZQIudThpVAkq-H{rXv(t zR4=Gzih89Nu`!v|`k40tq_Vk|aJv-GxA*1a~ zs5*8gDuW(j9CtC=hYU?O+H+aeG}IT;M*BFj>3mL0v=d1C{|POyyQ|n@T=H=>^WjE) z7CJNrmoRU{9s|A^njZMLc;M^Ix?Q?8Uz!WqBYtaBWlbGQ_`F7_@v)h$0Gq- zE=~E*UoYN6CRlj^o1W#5RIVbuTP_b-w`YALQ?n0NZ=Rq&AzzwnwPQgm_F%T9bfa}- z%9^qJA6N(cmFb0rg;_QmuwwVEp}Vub*%=!guttFO5%kN;=|Az1enWc#7Hn|Zb*!>u z574yTf0w#z58by0BZ0~r)WS^J6VRWd19mKI_lNAEpv~~_puh7y3kv_dcgOC(Z%L&a z{u3ipHT#d+u~xf3Y!8L(V$eR~Uww62`n9!Q)FJ;o`?aH`xg8bq*09~*Y7d3&V#q!l zv_}H=xc>{f-zv^qXXmVuiWR$M_0O1HcI?*Wi=Rg)FP9UD-`ELN`)tM98zJM#^0#^; zL6Ta-ojvHQ?+`nK3vr*Ty^5|g|{#|s95O(j(y=IjulX+<|8hgLU5Na z{J^b;BPAJpVye8bjm}mJ+qR2%hlo2w+$G{}5${EuVhDfx5~9?4;^@1V+DaV#YDjew zrx3S~II5BwB#ypYsVs3AAmUpUYLJc<<%KIhWb($xAYBQfuQgLZ8;GIsVdYM(T1?+{ z)x_tvU@B%_iK~XGjH{WVW+?fjl1L|$8lCtRBYj3QSUN}NeXrXNfcC_ex>{ctHGJ%^OAf;b9wyGOk!Fa`iw22F!k z&`3eTxde@bd`yb^n19m8WWPTEiQlI&narRNb`mC?Il`oG1f)=~#eWfnbdDgi%l}ze z5a+6%Re^K9eJlO0oYbT<1ARhk#g!OTLRDSTBd;f*`!rI29y7B}pSpN%nR06TWzee) z+NQE=RF1MPq^u4X-DklEn77`tXD+n7yPO|Fs7C#{2pu|yvi++< zByX7r2D|pJQZ9IgnWW-yGORFm9P~UW0rG|e$kXrLji3mq4b%UdS@$|r&t!!xj zb8EL$HcUL?D;zBN4&!eCqV(Y8Jc5tn-4~DGhxKrIZIl-ac=X6{dO_iM8#nSfHIp_^ zvk8A0-P0p$qMQ#oZ^cJ6qlm}eGSjz1s+~%k#P0x~)$r&yE{ZyUS;*@q*R}XKm3KiP z(DCS_3yp3_49(<5K|Pt{Cw090z#dfHTeByrrZW&RA7?>FG0s{z+a-|Lq%W(cbL>0v zq2V5Vj7`c~Zal5y+3}jp{Mi(2)8a)_!+XCTzM4^epB6iseGbnS6OZ!7Ryoc%-|XIEj?pB2b%QZz%+EtJBw(NGlsJCw2% z>gb>=EpaWms>QiyqPJ1v>Aq<*@pKWWFh*}|t8hIT1>Z(ID$;$_7s0Pyjazo`F_%9M zzMpsr_3_?G_r1gqfG@dx8T>0QKMnpD!~-XxF!nZhSqh1JvzsKx^(Wnty+=H7W>DXU zRN&*H?lG4yfZs+uaGpo~Hdj6gc^C2M*ERI(86lq#mwYE&zJP~c!{rCSf7|6l(EYK? zE0F(O@Gt~6yb0d<&)Dxh{GUAhjKhm7!C4P~&%-~8Qe;J)PkHzbhewg~){W-Hy(GH8 z=-!>iM*$&3iM9}jA%z`nn3kU&@SeBc&E_Z;d^{$QSjvwkRlwKi^o)IvYhc zpP)(4xLDnBHyy_xN*p`X*?1L-qQ(nR6g6IpRJ8n>=guFQh^>P22D^%5ZG%P1-G0y> z<>8%0>k2#zomY1+^qMrpPUT(7j- Date: Fri, 7 Oct 2011 10:59:19 -0700 Subject: [PATCH 32/49] Add unsafe tags to usage of LLVM funcs --- src/comp/middle/trans_common.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index a2287c4c0fca9..9e0f99685a5d7 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -428,11 +428,13 @@ fn val_str(tn: type_names, v: ValueRef) -> str { ret ty_str(tn, val_ty(v)); } // Returns the nth element of the given LLVM structure type. fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef { - let elt_count = llvm::LLVMCountStructElementTypes(llstructty); - assert (n < elt_count); - let elt_tys = std::vec::init_elt(T_nil(), elt_count); - llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); - ret llvm::LLVMGetElementType(elt_tys[n]); + unsafe { + let elt_count = llvm::LLVMCountStructElementTypes(llstructty); + assert (n < elt_count); + let elt_tys = std::vec::init_elt(T_nil(), elt_count); + llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); + ret llvm::LLVMGetElementType(elt_tys[n]); + } } fn find_scope_cx(cx: @block_ctxt) -> @block_ctxt { From 1e206cd00f1a936c4321932ca950d7183bc4a807 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Oct 2011 12:05:38 -0700 Subject: [PATCH 33/49] add unsafe tags into various points in the translation chains and so forth --- src/comp/back/link.rs | 10 +++-- src/comp/lib/llvm.rs | 12 +++-- src/comp/metadata/creader.rs | 34 ++++++++------- src/comp/middle/trans_build.rs | 77 +++++++++++++++++++++------------ src/comp/middle/trans_common.rs | 65 ++++++++++++++++++---------- src/test/stdtest/str.rs | 4 +- src/test/stdtest/vec.rs | 2 +- 7 files changed, 128 insertions(+), 76 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 52024d6f5b728..01f44cd2edbfa 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -35,10 +35,12 @@ tag output_type { } fn llvm_err(sess: session::session, msg: str) { - let buf = llvm::LLVMRustGetLastError(); - if buf == std::ptr::null() { - sess.fatal(msg); - } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } + unsafe { + let buf = llvm::LLVMRustGetLastError(); + if buf == std::ptr::null() { + sess.fatal(msg); + } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } + } } fn link_intrinsics(sess: session::session, llmod: ModuleRef) { diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index c47f75135d7c1..2cf85bcd218c6 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -961,7 +961,9 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); let n_args: uint = llvm::LLVMCountParamTypes(ty); let args: [TypeRef] = vec::init_elt::(0 as TypeRef, n_args); - llvm::LLVMGetParamTypes(ty, vec::to_ptr(args)); + unsafe { + llvm::LLVMGetParamTypes(ty, vec::to_ptr(args)); + } s += tys_str(names, outer, args); s += ") -> "; s += type_to_str_inner(names, outer, out_ty); @@ -971,7 +973,9 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> let s: str = "{"; let n_elts: uint = llvm::LLVMCountStructElementTypes(ty); let elts: [TypeRef] = vec::init_elt::(0 as TypeRef, n_elts); - llvm::LLVMGetStructElementTypes(ty, vec::to_ptr(elts)); + unsafe { + llvm::LLVMGetStructElementTypes(ty, vec::to_ptr(elts)); + } s += tys_str(names, outer, elts); s += "}"; ret s; @@ -1011,7 +1015,9 @@ fn float_width(llt: TypeRef) -> uint { fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] { let args = vec::init_elt(0 as TypeRef, llvm::LLVMCountParamTypes(fn_ty)); - llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); + unsafe { + llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); + } ret args; } diff --git a/src/comp/metadata/creader.rs b/src/comp/metadata/creader.rs index 90da54f36b314..1dd51a8b680ab 100644 --- a/src/comp/metadata/creader.rs +++ b/src/comp/metadata/creader.rs @@ -170,24 +170,26 @@ fn find_library_crate_aux(nn: {prefix: str, suffix: str}, crate_name: str, } fn get_metadata_section(filename: str) -> option::t<@[u8]> { - let mb = str::as_buf(filename, {|buf| - llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) - }); - if mb as int == 0 { ret option::none::<@[u8]>; } - let of = mk_object_file(mb); - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let name_buf = llvm::LLVMGetSectionName(si.llsi); - let name = str::str_from_cstr(name_buf); - if str::eq(name, x86::get_meta_sect_name()) { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi); - let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); - ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); + unsafe { + let mb = str::as_buf(filename, {|buf| + llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) + }); + if mb as int == 0 { ret option::none::<@[u8]>; } + let of = mk_object_file(mb); + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let name_buf = llvm::LLVMGetSectionName(si.llsi); + let name = str::str_from_cstr(name_buf); + if str::eq(name, x86::get_meta_sect_name()) { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi); + let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); + ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); + } + llvm::LLVMMoveToNextSection(si.llsi); } - llvm::LLVMMoveToNextSection(si.llsi); + ret option::none::<@[u8]>; } - ret option::none::<@[u8]>; } fn load_library_crate(sess: session::session, span: span, ident: ast::ident, diff --git a/src/comp/middle/trans_build.rs b/src/comp/middle/trans_build.rs index 384cbb49ff959..7cf9a9c27b3f2 100644 --- a/src/comp/middle/trans_build.rs +++ b/src/comp/middle/trans_build.rs @@ -37,8 +37,10 @@ fn AggregateRet(cx: @block_ctxt, RetVals: [ValueRef]) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals), - vec::len(RetVals)); + unsafe { + llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals), + vec::len(RetVals)); + } } fn Br(cx: @block_ctxt, Dest: BasicBlockRef) { @@ -88,8 +90,10 @@ fn Invoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), Then, Catch, noname()); + unsafe { + llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), Then, Catch, noname()); + } } fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], @@ -97,9 +101,11 @@ fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), Then, Catch, noname()); - llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + unsafe { + let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), Then, Catch, noname()); + llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + } } fn Unreachable(cx: @block_ctxt) { @@ -311,15 +317,19 @@ fn Store(cx: @block_ctxt, Val: ValueRef, Ptr: ValueRef) { fn GEP(cx: @block_ctxt, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices), - vec::len(Indices), noname()); + unsafe { + ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices), + vec::len(Indices), noname()); + } } fn InBoundsGEP(cx: @block_ctxt, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, vec::to_ptr(Indices), - vec::len(Indices), noname()); + unsafe { + ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, vec::to_ptr(Indices), + vec::len(Indices), noname()); + } } fn StructGEP(cx: @block_ctxt, Pointer: ValueRef, Idx: uint) -> ValueRef { @@ -460,9 +470,11 @@ fn Phi(cx: @block_ctxt, Ty: TypeRef, vals: [ValueRef], bbs: [BasicBlockRef]) if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } assert (vec::len::(vals) == vec::len::(bbs)); let phi = EmptyPhi(cx, Ty); - llvm::LLVMAddIncoming(phi, vec::to_ptr(vals), vec::to_ptr(bbs), - vec::len(vals)); - ret phi; + unsafe { + llvm::LLVMAddIncoming(phi, vec::to_ptr(vals), vec::to_ptr(bbs), + vec::len(vals)); + ret phi; + } } fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) { @@ -480,26 +492,32 @@ fn _UndefReturn(Fn: ValueRef) -> ValueRef { } fn Call(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { - if cx.unreachable { ret _UndefReturn(Fn); } - ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), noname()); + unsafe { + if cx.unreachable { ret _UndefReturn(Fn); } + ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), noname()); + } } fn FastCall(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { - if cx.unreachable { ret _UndefReturn(Fn); } - let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), noname()); - llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); - ret v; + unsafe { + if cx.unreachable { ret _UndefReturn(Fn); } + let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), noname()); + llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + ret v; + } } fn CallWithConv(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], Conv: uint) -> ValueRef { - if cx.unreachable { ret _UndefReturn(Fn); } - let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), noname()); - llvm::LLVMSetInstructionCallConv(v, Conv); - ret v; + unsafe { + if cx.unreachable { ret _UndefReturn(Fn); } + let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), noname()); + llvm::LLVMSetInstructionCallConv(v, Conv); + ret v; + } } fn Select(cx: @block_ctxt, If: ValueRef, Then: ValueRef, Else: ValueRef) -> @@ -568,7 +586,10 @@ fn Trap(cx: @block_ctxt) { }); assert (T as int != 0); let Args: [ValueRef] = []; - llvm::LLVMBuildCall(b, T, vec::to_ptr(Args), vec::len(Args), noname()); + unsafe { + llvm::LLVMBuildCall(b, T, vec::to_ptr(Args), + vec::len(Args), noname()); + } } fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef, diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 9e0f99685a5d7..945530d87d2af 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -518,8 +518,10 @@ fn T_size_t() -> TypeRef { } fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef { - ret llvm::LLVMFunctionType(output, to_ptr(inputs), - std::vec::len::(inputs), False); + unsafe { + ret llvm::LLVMFunctionType(output, to_ptr(inputs), + std::vec::len::(inputs), False); + } } fn T_fn_pair(cx: crate_ctxt, tfn: TypeRef) -> TypeRef { @@ -529,7 +531,9 @@ fn T_fn_pair(cx: crate_ctxt, tfn: TypeRef) -> TypeRef { fn T_ptr(t: TypeRef) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); } fn T_struct(elts: [TypeRef]) -> TypeRef { - ret llvm::LLVMStructType(to_ptr(elts), std::vec::len(elts), False); + unsafe { + ret llvm::LLVMStructType(to_ptr(elts), std::vec::len(elts), False); + } } fn T_named_struct(name: str) -> TypeRef { @@ -538,7 +542,9 @@ fn T_named_struct(name: str) -> TypeRef { } fn set_struct_body(t: TypeRef, elts: [TypeRef]) { - llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); + unsafe { + llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); + } } fn T_empty_struct() -> TypeRef { ret T_struct([]); } @@ -578,12 +584,15 @@ fn T_task() -> TypeRef { fn T_tydesc_field(cx: crate_ctxt, field: int) -> TypeRef { // Bit of a kludge: pick the fn typeref out of the tydesc.. - let tydesc_elts: [TypeRef] = - std::vec::init_elt::(T_nil(), abi::n_tydesc_fields as uint); - llvm::LLVMGetStructElementTypes(cx.tydesc_type, - to_ptr::(tydesc_elts)); - let t = llvm::LLVMGetElementType(tydesc_elts[field]); - ret t; + unsafe { + let tydesc_elts: [TypeRef] = + std::vec::init_elt::(T_nil(), + abi::n_tydesc_fields as uint); + llvm::LLVMGetStructElementTypes(cx.tydesc_type, + to_ptr::(tydesc_elts)); + let t = llvm::LLVMGetElementType(tydesc_elts[field]); + ret t; + } } fn T_glue_fn(cx: crate_ctxt) -> TypeRef { @@ -790,30 +799,42 @@ fn C_postr(s: str) -> ValueRef { } fn C_zero_byte_arr(size: uint) -> ValueRef { - let i = 0u; - let elts: [ValueRef] = []; - while i < size { elts += [C_u8(0u)]; i += 1u; } - ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), - std::vec::len(elts)); + unsafe { + let i = 0u; + let elts: [ValueRef] = []; + while i < size { elts += [C_u8(0u)]; i += 1u; } + ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), + std::vec::len(elts)); + } } fn C_struct(elts: [ValueRef]) -> ValueRef { - ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), - False); + unsafe { + ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), + False); + } } fn C_named_struct(T: TypeRef, elts: [ValueRef]) -> ValueRef { - ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), - std::vec::len(elts)); + unsafe { + ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), + std::vec::len(elts)); + } } fn C_array(ty: TypeRef, elts: [ValueRef]) -> ValueRef { - ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), std::vec::len(elts)); + unsafe { + ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), + std::vec::len(elts)); + } } fn C_bytes(bytes: [u8]) -> ValueRef { - ret llvm::LLVMConstString(unsafe::reinterpret_cast(vec::to_ptr(bytes)), - vec::len(bytes), False); + unsafe { + ret llvm::LLVMConstString( + unsafe::reinterpret_cast(vec::to_ptr(bytes)), + vec::len(bytes), False); + } } fn C_shape(ccx: @crate_ctxt, bytes: [u8]) -> ValueRef { diff --git a/src/test/stdtest/str.rs b/src/test/stdtest/str.rs index f1839a0aa91df..8cce515ec3e7d 100644 --- a/src/test/stdtest/str.rs +++ b/src/test/stdtest/str.rs @@ -256,7 +256,7 @@ fn unsafe_from_bytes() { } #[test] -fn str_from_cstr() { +unsafe fn str_from_cstr() { let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; let b = vec::to_ptr(a); let c = str::str_from_cstr(b); @@ -278,7 +278,7 @@ fn as_buf_small() { } #[test] -fn as_buf2() { +unsafe fn as_buf2() { let s = "hello"; let sb = str::as_buf(s, {|b| b }); let s_cstr = str::str_from_cstr(sb); diff --git a/src/test/stdtest/vec.rs b/src/test/stdtest/vec.rs index 5e5de913914ae..313db7b71f107 100644 --- a/src/test/stdtest/vec.rs +++ b/src/test/stdtest/vec.rs @@ -21,7 +21,7 @@ fn square_if_odd(&&n: uint) -> option::t { fn add(&&x: uint, &&y: uint) -> uint { ret x + y; } #[test] -fn test_unsafe_ptrs() { +unsafe fn test_unsafe_ptrs() { // Test on-stack copy-from-buf. let a = [1, 2, 3]; let ptr = vec::to_ptr(a); From 5f288f2c94cc45c64e6c77739f5f51d1eb79e6c4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 11:59:20 -0700 Subject: [PATCH 34/49] continue to annotate trans functions as unsafe where neccessary --- src/comp/middle/trans_objects.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs index aabe09b3d0586..af5f4266b9eb3 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -569,7 +569,7 @@ fn create_backwarding_vtbl(cx: @local_ctxt, sp: span, inner_obj_ty: ty::t, // finish_vtbl: Given a vector of vtable entries, create the table in // read-only memory and return a pointer to it. fn finish_vtbl(cx: @local_ctxt, llmethods: [ValueRef], name: str) -> - ValueRef { + ValueRef unsafe { let vtbl = C_struct(llmethods); let vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + [name]); let gvar = @@ -619,7 +619,7 @@ fn begin_fn(cx: @local_ctxt, sp: span, m: @ty::method, // returns the value returned from that call. fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, ty_params: [ast::ty_param], outer_obj_ty: ty::t, - _additional_field_tys: [ty::t]) -> ValueRef { + _additional_field_tys: [ty::t]) -> ValueRef unsafe { let llbackwarding_fn = begin_fn(cx, sp, m, ty_params, "backwarding_fn"); let fcx = new_fn_ctxt(cx, sp, llbackwarding_fn); @@ -724,7 +724,7 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, fn process_fwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, ty_params: [ast::ty_param], inner_obj_ty: ty::t, backwarding_vtbl: ValueRef, - additional_field_tys: [ty::t]) -> ValueRef { + additional_field_tys: [ty::t]) -> ValueRef unsafe { // Create a new function context and block context for the function, // holding onto a pointer to the first block. From 7a0d10ff0ddbf259b272b5eefe87c3b5804d8dc1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 12:21:37 -0700 Subject: [PATCH 35/49] continue to annotate trans functions as unsafe where neccessary --- src/comp/middle/gc.rs | 6 ++++-- src/comp/middle/shape.rs | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/comp/middle/gc.rs b/src/comp/middle/gc.rs index be5376bc2b6bf..7de07b55e3b17 100644 --- a/src/comp/middle/gc.rs +++ b/src/comp/middle/gc.rs @@ -16,7 +16,8 @@ type ctxt = @{mutable next_tydesc_num: uint}; fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; } -fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef { +fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) + -> ValueRef unsafe { let llglobal = str::as_buf(name, {|buf| @@ -27,7 +28,8 @@ fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef { ret llglobal; } -fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt { +fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> + @block_ctxt unsafe { let bcx = cx; if !type_is_gc_relevant(bcx_tcx(cx), ty) || ty::type_has_dynamic_size(bcx_tcx(cx), ty) { diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index 7c54bde66b32f..17c72d6b6c21b 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -72,7 +72,7 @@ fn eq_res_info(a: res_info, b: res_info) -> bool { } fn mk_global(ccx: @crate_ctxt, name: str, llval: ValueRef, internal: bool) -> - ValueRef { + ValueRef unsafe { let llglobal = str::as_buf(name, {|buf| @@ -245,7 +245,7 @@ fn s_float(_tcx: ty_ctxt) -> u8 { ret shape_f64; // TODO: x86-64 } -fn mk_ctxt(llmod: ModuleRef) -> ctxt { +fn mk_ctxt(llmod: ModuleRef) -> ctxt unsafe { let llshapetablesty = trans_common::T_named_struct("shapes"); let llshapetables = str::as_buf("shapes", @@ -580,7 +580,7 @@ fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef { ret mk_global(ccx, "resource_shapes", C_struct(dtors), true); } -fn gen_shape_tables(ccx: @crate_ctxt) { +fn gen_shape_tables(ccx: @crate_ctxt) unsafe { let lltagstable = gen_tag_shapes(ccx); let llresourcestable = gen_resource_shapes(ccx); trans_common::set_struct_body(ccx.shape_cx.llshapetablesty, From cab76a5462901857dd2260aad087d60964534d20 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 15:16:55 -0700 Subject: [PATCH 36/49] continue to annotate functions as unsafe where neccessary --- src/comp/back/link.rs | 5 +++-- src/comp/lib/llvm.rs | 26 ++++++++++++-------------- src/compiletest/procsrv.rs | 2 +- src/test/stdtest/ptr.rs | 2 +- src/test/stdtest/run.rs | 8 ++++---- src/test/stdtest/sys.rs | 2 +- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 01f44cd2edbfa..fbf1f4b78813d 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -43,7 +43,7 @@ fn llvm_err(sess: session::session, msg: str) { } } -fn link_intrinsics(sess: session::session, llmod: ModuleRef) { +fn link_intrinsics(sess: session::session, llmod: ModuleRef) unsafe { let path = alt filesearch::search( sess.filesearch(), bind filesearch::pick_file("intrinsics.bc", _)) { @@ -90,7 +90,8 @@ mod write { } else { stem = str::substr(output_path, 0u, dot_pos as uint); } ret stem + "." + extension; } - fn run_passes(sess: session::session, llmod: ModuleRef, output: str) { + fn run_passes(sess: session::session, llmod: ModuleRef, output: str) + unsafe { let opts = sess.get_opts(); if opts.time_llvm_passes { llvm::LLVMRustEnableTimePasses(); } link_intrinsics(sess, llmod); diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 2cf85bcd218c6..8a6464cc1cfdc 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -925,7 +925,7 @@ fn type_to_str(names: type_names, ty: TypeRef) -> str { } fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> - str { + str unsafe { if names.type_has_name(ty) { ret names.get_name(ty); } @@ -1003,7 +1003,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> } } -fn float_width(llt: TypeRef) -> uint { +fn float_width(llt: TypeRef) -> uint unsafe { ret alt llvm::LLVMGetTypeKind(llt) { 1 { 32u } 2 { 64u } @@ -1013,24 +1013,22 @@ fn float_width(llt: TypeRef) -> uint { }; } -fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] { +fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] unsafe { let args = vec::init_elt(0 as TypeRef, llvm::LLVMCountParamTypes(fn_ty)); - unsafe { - llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); - } + llvm::LLVMGetParamTypes(fn_ty, vec::to_ptr(args)); ret args; } /* Memory-managed interface to target data. */ -resource target_data_res(TD: TargetDataRef) { +resource target_data_res(TD: TargetDataRef) unsafe { llvm::LLVMDisposeTargetData(TD); } type target_data = {lltd: TargetDataRef, dtor: @target_data_res}; -fn mk_target_data(string_rep: str) -> target_data { +fn mk_target_data(string_rep: str) -> target_data unsafe { let lltd = str::as_buf(string_rep, {|buf| llvm::LLVMCreateTargetData(buf) }); ret {lltd: lltd, dtor: @target_data_res(lltd)}; @@ -1038,39 +1036,39 @@ fn mk_target_data(string_rep: str) -> target_data { /* Memory-managed interface to pass managers. */ -resource pass_manager_res(PM: PassManagerRef) { +resource pass_manager_res(PM: PassManagerRef) unsafe { llvm::LLVMDisposePassManager(PM); } type pass_manager = {llpm: PassManagerRef, dtor: @pass_manager_res}; -fn mk_pass_manager() -> pass_manager { +fn mk_pass_manager() -> pass_manager unsafe { let llpm = llvm::LLVMCreatePassManager(); ret {llpm: llpm, dtor: @pass_manager_res(llpm)}; } /* Memory-managed interface to object files. */ -resource object_file_res(ObjectFile: ObjectFileRef) { +resource object_file_res(ObjectFile: ObjectFileRef) unsafe { llvm::LLVMDisposeObjectFile(ObjectFile); } type object_file = {llof: ObjectFileRef, dtor: @object_file_res}; -fn mk_object_file(llmb: MemoryBufferRef) -> object_file { +fn mk_object_file(llmb: MemoryBufferRef) -> object_file unsafe { let llof = llvm::LLVMCreateObjectFile(llmb); ret {llof: llof, dtor: @object_file_res(llof)}; } /* Memory-managed interface to section iterators. */ -resource section_iter_res(SI: SectionIteratorRef) { +resource section_iter_res(SI: SectionIteratorRef) unsafe { llvm::LLVMDisposeSectionIterator(SI); } type section_iter = {llsi: SectionIteratorRef, dtor: @section_iter_res}; -fn mk_section_iter(llof: ObjectFileRef) -> section_iter { +fn mk_section_iter(llof: ObjectFileRef) -> section_iter unsafe { let llsi = llvm::LLVMGetSections(llof); ret {llsi: llsi, dtor: @section_iter_res(llsi)}; } diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 1563e3112ca1e..6a74d044bfb1d 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -70,7 +70,7 @@ fn run(handle: handle, lib_path: str, prog: str, args: [str], ret {status: status, out: output, err: errput}; } -fn writeclose(fd: int, s: option::t) { +fn writeclose(fd: int, s: option::t) unsafe { if option::is_some(s) { let writer = io::new_writer(io::fd_buf_writer(fd, option::none)); writer.write_str(option::get(s)); diff --git a/src/test/stdtest/ptr.rs b/src/test/stdtest/ptr.rs index ef0ffa54a04b9..ac829f90e5ff7 100644 --- a/src/test/stdtest/ptr.rs +++ b/src/test/stdtest/ptr.rs @@ -5,7 +5,7 @@ import std::unsafe; type pair = {mutable fst: int, mutable snd: int}; #[test] -fn test() { +fn test() unsafe { let p = {mutable fst: 10, mutable snd: 20}; let pptr: *mutable pair = ptr::addr_of(p); let iptr: *mutable int = unsafe::reinterpret_cast(pptr); diff --git a/src/test/stdtest/run.rs b/src/test/stdtest/run.rs index e5c36d37041b4..15bcf4e532007 100644 --- a/src/test/stdtest/run.rs +++ b/src/test/stdtest/run.rs @@ -23,7 +23,7 @@ fn test_leaks() { fn test_leaks() { } #[test] -fn test_pipes() { +fn test_pipes() unsafe { let pipe_in = os::pipe(); let pipe_out = os::pipe(); let pipe_err = os::pipe(); @@ -45,14 +45,14 @@ fn test_pipes() { log actual; assert (expected == actual); - fn writeclose(fd: int, s: str) { + fn writeclose(fd: int, s: str) unsafe { let writer = io::new_writer(io::fd_buf_writer(fd, option::none)); writer.write_str(s); os::libc::close(fd); } - fn readclose(fd: int) -> str { + fn readclose(fd: int) -> str unsafe { // Copied from run::program_output let file = os::fd_FILE(fd); let reader = io::new_reader(io::FILE_buf_reader(file, option::none)); @@ -67,7 +67,7 @@ fn test_pipes() { } #[test] -fn waitpid() { +fn waitpid() unsafe { let pid = run::spawn_process("false", [], 0, 0, 0); let status = run::waitpid(pid); assert status == 1; diff --git a/src/test/stdtest/sys.rs b/src/test/stdtest/sys.rs index 56cafe9217a0e..547adba7bf56e 100644 --- a/src/test/stdtest/sys.rs +++ b/src/test/stdtest/sys.rs @@ -1,4 +1,4 @@ import std::sys; #[test] -fn last_os_error() { log sys::rustrt::last_os_error(); } +fn last_os_error() unsafe { log sys::rustrt::last_os_error(); } From 777dd6a57b82d0f1ae0bfb60b99dcfac213f9de1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 15:19:34 -0700 Subject: [PATCH 37/49] all tests pass --- src/compiletest/procsrv.rs | 4 ++-- src/test/run-pass/interior-vec.rs | 2 +- src/test/run-pass/issue-506.rs | 2 +- src/test/run-pass/unify-return-ty.rs | 2 +- src/test/run-pass/unique-copy-box.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 6a74d044bfb1d..467b98d8b640a 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -79,7 +79,7 @@ fn writeclose(fd: int, s: option::t) unsafe { os::libc::close(fd); } -fn readclose(fd: int) -> str { +fn readclose(fd: int) -> str unsafe { // Copied from run::program_output let file = os::fd_FILE(fd); let reader = io::new_reader(io::FILE_buf_reader(file, option::none)); @@ -92,7 +92,7 @@ fn readclose(fd: int) -> str { ret buf; } -fn worker(p: port) { +fn worker(p: port) unsafe { // FIXME (787): If we declare this inside of the while loop and then // break out of it before it's ever initialized (i.e. we don't run diff --git a/src/test/run-pass/interior-vec.rs b/src/test/run-pass/interior-vec.rs index 0c0a3c17179b4..b28367790464c 100644 --- a/src/test/run-pass/interior-vec.rs +++ b/src/test/run-pass/interior-vec.rs @@ -4,7 +4,7 @@ native "rust-intrinsic" mod rusti { fn vec_len(&&v: [T]) -> uint; } -fn main() { +fn main() unsafe { let v: [int] = []; assert (vec_len(v) == 0u); // zero-length let x = [1, 2]; diff --git a/src/test/run-pass/issue-506.rs b/src/test/run-pass/issue-506.rs index 8285b5e1f3b4a..2ed94852bf97b 100644 --- a/src/test/run-pass/issue-506.rs +++ b/src/test/run-pass/issue-506.rs @@ -9,6 +9,6 @@ native "rust" mod rustrt { fn task_yield(); } -fn yield_wrap() { rustrt::task_yield(); } +fn yield_wrap() unsafe { rustrt::task_yield(); } fn main() { let f = yield_wrap; task::spawn(f); } diff --git a/src/test/run-pass/unify-return-ty.rs b/src/test/run-pass/unify-return-ty.rs index b8f9a39f50bd9..2a22499e8c72c 100644 --- a/src/test/run-pass/unify-return-ty.rs +++ b/src/test/run-pass/unify-return-ty.rs @@ -4,6 +4,6 @@ use std; import std::unsafe; -fn null<@T>() -> *T { unsafe::reinterpret_cast(0) } +fn null<@T>() -> *T unsafe { unsafe::reinterpret_cast(0) } fn main() { null::(); } diff --git a/src/test/run-pass/unique-copy-box.rs b/src/test/run-pass/unique-copy-box.rs index d7a5e3fe8500b..6a54407b45837 100644 --- a/src/test/run-pass/unique-copy-box.rs +++ b/src/test/run-pass/unique-copy-box.rs @@ -1,7 +1,7 @@ use std; import std::sys::rustrt::refcount; -fn main() { +fn main() unsafe { let i = ~@1; let j = ~@2; let rc1 = refcount(*i); From a6cd35e7c702a88169c69d54882a982815801221 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 10 Oct 2011 15:21:50 -0700 Subject: [PATCH 38/49] all tests pass --- src/test/bench/shootout-nbody.rs | 4 ++-- src/test/compile-fail/native-type-mismatch.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 92da06f186a82..61122d8e6b48f 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -70,7 +70,7 @@ mod NBodySystem { while i < 5 { move(bodies[i], dt); i += 1; } } - fn advance_one(bi: Body::props, bj: Body::props, dt: float) { + fn advance_one(bi: Body::props, bj: Body::props, dt: float) unsafe { let dx: float = bi.x - bj.x; let dy: float = bi.y - bj.y; let dz: float = bi.z - bj.z; @@ -95,7 +95,7 @@ mod NBodySystem { b.z += dt * b.vz; } - fn energy(bodies: [Body::props]) -> float { + fn energy(bodies: [Body::props]) -> float unsafe { let dx: float; let dy: float; let dz: float; diff --git a/src/test/compile-fail/native-type-mismatch.rs b/src/test/compile-fail/native-type-mismatch.rs index d2c28ae47f18b..fb0847925325c 100644 --- a/src/test/compile-fail/native-type-mismatch.rs +++ b/src/test/compile-fail/native-type-mismatch.rs @@ -1,7 +1,7 @@ // error-pattern:expected *Mb but found native use std; -fn main() { +fn main() unsafe { let f: std::os::libc::FILE = std::io::rustrt::rust_get_stdin(); std::os::libc::fopen(f, f); } From c5d671c45e06f9a45da9935fb6e7f61f277ca11d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:31:23 -0700 Subject: [PATCH 39/49] add pass to check that unsafe fns cannot be used as values --- src/comp/driver/rustc.rs | 4 +- src/comp/middle/unsafeck.rs | 72 +++++++++++++++++++ src/comp/rustc.rc | 1 + .../compile-fail/unsafe-fn-used-as-value.rs | 9 +++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/comp/middle/unsafeck.rs create mode 100644 src/test/compile-fail/unsafe-fn-used-as-value.rs diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 76819b9960544..84409978bda36 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -5,7 +5,7 @@ import metadata::{creader, cstore}; import syntax::parse::{parser, token}; import syntax::{ast, codemap}; import front::attr; -import middle::{trans, resolve, freevars, kind, ty, typeck}; +import middle::{trans, resolve, freevars, kind, ty, typeck, unsafeck}; import middle::tstate::ck; import syntax::print::{pp, pprust}; import util::{ppaux, common, filesearch}; @@ -129,6 +129,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, bind freevars::annotate_freevars(def_map, crate)); let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars); time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate)); + time(time_passes, "unsafechecking", + bind unsafeck::unsafeck_crate(ty_cx, crate)); time(time_passes, "alt checking", bind middle::check_alt::check_crate(ty_cx, crate)); if sess.get_opts().run_typestate { diff --git a/src/comp/middle/unsafeck.rs b/src/comp/middle/unsafeck.rs new file mode 100644 index 0000000000000..251258f11a8b0 --- /dev/null +++ b/src/comp/middle/unsafeck.rs @@ -0,0 +1,72 @@ +import syntax::ast; +import syntax::visit; +import std::option::some; +import syntax::print::pprust::{expr_to_str, path_to_str}; + +export unsafeck_crate; + +type unsafe_ctx = { + tcx: ty::ctxt, + unsafe_fn_legal: bool +}; + +fn unsafeck_view_item(_vi: @ast::view_item, + _ctx: unsafe_ctx, + _v: visit::vt) { + // Ignore paths that appear in use, import, etc +} + +fn unsafeck_expr(expr: @ast::expr, + ctx: unsafe_ctx, + v: visit::vt) { + 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.)) | + some(ast::def_native_fn(_, ast::unsafe_fn.)) { + log_err ("expr=", expr_to_str(expr)); + ctx.tcx.sess.span_fatal( + expr.span, + "unsafe functions can only be called"); + } + + _ {} + } + } + } + + ast::expr_call(f, args) { + let f_ctx = {unsafe_fn_legal: true with ctx}; + visit::visit_expr(f, f_ctx, v); + + let args_ctx = {unsafe_fn_legal: false with ctx}; + visit::visit_exprs(args, args_ctx, v); + } + + _ { + let subctx = {unsafe_fn_legal: false with ctx}; + visit::visit_expr(expr, subctx, v); + } + } +} + +fn unsafeck_crate(tcx: ty::ctxt, crate: @ast::crate) { + let visit = + visit::mk_vt( + @{visit_expr: unsafeck_expr, + visit_view_item: unsafeck_view_item + with *visit::default_visitor()}); + let ctx = {tcx: tcx, unsafe_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 +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 9b1dff7576998..2f861155e1cab 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -25,6 +25,7 @@ mod middle { mod ast_map; mod resolve; mod typeck; + mod unsafeck; mod check_alt; mod mut; mod alias; diff --git a/src/test/compile-fail/unsafe-fn-used-as-value.rs b/src/test/compile-fail/unsafe-fn-used-as-value.rs new file mode 100644 index 0000000000000..e2fa46b0374f8 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-used-as-value.rs @@ -0,0 +1,9 @@ +// -*- rust -*- +// error-pattern: unsafe functions can only be called + +unsafe fn f() { ret; } + +fn main() { + let x = f; + x(); +} From 4ad03ccae0c1f446e62332f3b8d630deadcb116c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:36:29 -0700 Subject: [PATCH 40/49] improve the span used in test generation --- src/comp/front/test.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 70985f108060d..3e9e7916b334a 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -6,13 +6,14 @@ import syntax::ast_util::*; //import syntax::ast_util::dummy_sp; import syntax::fold; import syntax::print::pprust; +import syntax::codemap::span; import front::attr; export modify_for_testing; type node_id_gen = fn() -> ast::node_id; -type test = {path: [ast::ident], ignore: bool}; +type test = {span: span, path: [ast::ident], ignore: bool}; type test_ctxt = @{next_node_id: node_id_gen, @@ -90,7 +91,7 @@ fn fold_item(cx: test_ctxt, &&i: @ast::item, fld: fold::ast_fold) -> if is_test_fn(i) { log "this is a test function"; - let test = {path: cx.path, ignore: is_ignored(i)}; + let test = {span: i.span, path: cx.path, ignore: is_ignored(i)}; cx.testfns += [test]; log #fmt["have %u test functions", vec::len(cx.testfns)]; } @@ -237,6 +238,7 @@ fn mk_test_desc_vec(cx: test_ctxt) -> @ast::expr { } fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { + let span = test.span; let path = test.path; log #fmt["encoding %s", ast_util::path_name_i(path)]; @@ -246,7 +248,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let name_expr: ast::expr = {id: cx.next_node_id(), node: ast::expr_lit(@name_lit), - span: dummy_sp()}; + span: span}; let name_field: ast::field = nospan({mut: ast::imm, ident: "name", expr: @name_expr}); @@ -256,7 +258,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let fn_expr: ast::expr = {id: cx.next_node_id(), node: ast::expr_path(fn_path), - span: dummy_sp()}; + span: span}; let fn_field: ast::field = nospan({mut: ast::imm, ident: "fn", expr: @fn_expr}); @@ -266,7 +268,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let ignore_expr: ast::expr = {id: cx.next_node_id(), node: ast::expr_lit(@ignore_lit), - span: dummy_sp()}; + span: span}; let ignore_field: ast::field = nospan({mut: ast::imm, ident: "ignore", expr: @ignore_expr}); @@ -274,7 +276,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { let desc_rec_: ast::expr_ = ast::expr_rec([name_field, fn_field, ignore_field], option::none); let desc_rec: ast::expr = - {id: cx.next_node_id(), node: desc_rec_, span: dummy_sp()}; + {id: cx.next_node_id(), node: desc_rec_, span: span}; ret @desc_rec; } From 2771e9456b020249569cfbf899da922edaa37fdf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:50:54 -0700 Subject: [PATCH 41/49] make a good error msg if you try to use an unsafe fn for a test --- src/comp/driver/rustc.rs | 2 +- src/comp/front/test.rs | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 84409978bda36..46f8da829a631 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -110,7 +110,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, if sess.get_opts().test { crate = time(time_passes, "building test harness", - bind front::test::modify_for_testing(crate)); + bind front::test::modify_for_testing(sess, crate)); } crate = time(time_passes, "expansion", diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 3e9e7916b334a..ce1c0f02088c7 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -7,6 +7,7 @@ import syntax::ast_util::*; import syntax::fold; import syntax::print::pprust; import syntax::codemap::span; +import driver::session; import front::attr; export modify_for_testing; @@ -16,13 +17,15 @@ type node_id_gen = fn() -> ast::node_id; type test = {span: span, path: [ast::ident], ignore: bool}; type test_ctxt = - @{next_node_id: node_id_gen, + @{sess: session::session, + next_node_id: node_id_gen, mutable path: [ast::ident], mutable testfns: [test]}; // Traverse the crate, collecting all the test functions, eliding any // existing main functions, and synthesizing a main test harness -fn modify_for_testing(crate: @ast::crate) -> @ast::crate { +fn modify_for_testing(sess: session::session, + crate: @ast::crate) -> @ast::crate { // FIXME: This hackasaurus assumes that 200000 is a safe number to start // generating node_ids at (which is totally not the case). pauls is going @@ -37,7 +40,8 @@ fn modify_for_testing(crate: @ast::crate) -> @ast::crate { }(next_node_id); let cx: test_ctxt = - @{next_node_id: next_node_id_fn, + @{sess: sess, + next_node_id: next_node_id_fn, mutable path: [], mutable testfns: []}; @@ -90,10 +94,19 @@ fn fold_item(cx: test_ctxt, &&i: @ast::item, fld: fold::ast_fold) -> log #fmt["current path: %s", ast_util::path_name_i(cx.path)]; if is_test_fn(i) { - log "this is a test function"; - let test = {span: i.span, path: cx.path, ignore: is_ignored(i)}; - cx.testfns += [test]; - log #fmt["have %u test functions", vec::len(cx.testfns)]; + alt i.node { + ast::item_fn(f, _) when f.decl.purity == ast::unsafe_fn { + cx.sess.span_fatal( + i.span, + "unsafe functions cannot be used for tests"); + } + _ { + log "this is a test function"; + let test = {span: i.span, path: cx.path, ignore: is_ignored(i)}; + cx.testfns += [test]; + log #fmt["have %u test functions", vec::len(cx.testfns)]; + } + } } let res = fold::noop_fold_item(i, fld); From 8000ac30a00faa5f00f321cb0d84110ae14ad12e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 17:53:10 -0700 Subject: [PATCH 42/49] convert a few tests from unsafe fns to fns with unsafe bodies --- src/test/stdtest/str.rs | 4 ++-- src/test/stdtest/vec.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/stdtest/str.rs b/src/test/stdtest/str.rs index 8cce515ec3e7d..aa3a61f3dd515 100644 --- a/src/test/stdtest/str.rs +++ b/src/test/stdtest/str.rs @@ -256,7 +256,7 @@ fn unsafe_from_bytes() { } #[test] -unsafe fn str_from_cstr() { +fn str_from_cstr() unsafe { let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; let b = vec::to_ptr(a); let c = str::str_from_cstr(b); @@ -278,7 +278,7 @@ fn as_buf_small() { } #[test] -unsafe fn as_buf2() { +fn as_buf2() unsafe { let s = "hello"; let sb = str::as_buf(s, {|b| b }); let s_cstr = str::str_from_cstr(sb); diff --git a/src/test/stdtest/vec.rs b/src/test/stdtest/vec.rs index 313db7b71f107..3d8614f2d2448 100644 --- a/src/test/stdtest/vec.rs +++ b/src/test/stdtest/vec.rs @@ -21,7 +21,7 @@ fn square_if_odd(&&n: uint) -> option::t { fn add(&&x: uint, &&y: uint) -> uint { ret x + y; } #[test] -unsafe fn test_unsafe_ptrs() { +fn test_unsafe_ptrs() unsafe { // Test on-stack copy-from-buf. let a = [1, 2, 3]; let ptr = vec::to_ptr(a); From 98ee7ff8a973bb4d01babebc41dac916b3beab72 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 18:01:54 -0700 Subject: [PATCH 43/49] add some new tests --- src/test/compile-fail/native-unsafe-fn-called.rs | 11 +++++++++++ src/test/compile-fail/native-unsafe-fn.rs | 12 ++++++++++++ src/test/compile-fail/unsafe-fn-called-from-safe.rs | 1 - 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/native-unsafe-fn-called.rs create mode 100644 src/test/compile-fail/native-unsafe-fn.rs diff --git a/src/test/compile-fail/native-unsafe-fn-called.rs b/src/test/compile-fail/native-unsafe-fn-called.rs new file mode 100644 index 0000000000000..3104884130b19 --- /dev/null +++ b/src/test/compile-fail/native-unsafe-fn-called.rs @@ -0,0 +1,11 @@ +// -*- rust -*- +// error-pattern: safe function calls function marked unsafe + +native "cdecl" mod test { + unsafe fn free(); +} + +fn main() { + test::free(); +} + diff --git a/src/test/compile-fail/native-unsafe-fn.rs b/src/test/compile-fail/native-unsafe-fn.rs new file mode 100644 index 0000000000000..2a2ce4b3246e0 --- /dev/null +++ b/src/test/compile-fail/native-unsafe-fn.rs @@ -0,0 +1,12 @@ +// -*- rust -*- +// error-pattern: unsafe functions can only be called + +native "cdecl" mod test { + unsafe fn free(); +} + +fn main() { + let x = test::free; +} + + 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 b294ad16344fd..62fcfa689d97f 100644 --- a/src/test/compile-fail/unsafe-fn-called-from-safe.rs +++ b/src/test/compile-fail/unsafe-fn-called-from-safe.rs @@ -1,6 +1,5 @@ // -*- rust -*- // error-pattern: safe function calls function marked unsafe -// xfail-test unsafe fn f() { ret; } From d3ecc46f70a9649f57a77ca97f7f1dd7bd7ab6b2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 18:02:51 -0700 Subject: [PATCH 44/49] fix error msg --- src/comp/middle/typeck.rs | 10 ++-------- src/test/compile-fail/native-unsafe-fn-called.rs | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index f848cf638f8b8..2f115b8e836ea 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1553,18 +1553,12 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, 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_fn(_, ast::unsafe_fn.)) | 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"); + "safe function calls function marked unsafe"); } } _ { diff --git a/src/test/compile-fail/native-unsafe-fn-called.rs b/src/test/compile-fail/native-unsafe-fn-called.rs index 3104884130b19..6e9d7ac18fccc 100644 --- a/src/test/compile-fail/native-unsafe-fn-called.rs +++ b/src/test/compile-fail/native-unsafe-fn-called.rs @@ -1,6 +1,5 @@ // -*- rust -*- // error-pattern: safe function calls function marked unsafe - native "cdecl" mod test { unsafe fn free(); } From 63eee8f3e137cf3a372039171ed0a9953811c7f1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 21:08:01 -0700 Subject: [PATCH 45/49] prohibit ptr deref unless in unsafe code --- src/comp/middle/typeck.rs | 22 ++++++++++++++++++-- src/test/compile-fail/unsafe-fn-deref-ptr.rs | 11 ++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/unsafe-fn-deref-ptr.rs diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 2f115b8e836ea..e18e5c2c63ea9 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -193,7 +193,7 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { } -// Returns the one-level-deep structure of the given type. +// Returns the one-level-deep structure of the given type.f fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty { ret ty::struct(fcx.ccx.tcx, structurally_resolved_type(fcx, sp, typ)); } @@ -1530,7 +1530,7 @@ fn require_unsafe(sess: session::session, f_purity: ast::purity, sp: span) { _ { sess.span_fatal( sp, - "Found unsafe expression in safe function decl"); + "unsafe operation requires unsafe function or block"); } } } @@ -1591,6 +1591,23 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { ret check_expr_with_unifier(fcx, expr, demand::simple, expected); } +fn check_for_unsafe_assignments(fcx: @fn_ctxt, lhs: @ast::expr) { + alt lhs.node { + ast::expr_unary(ast::deref., ptr) { + let ty = expr_ty(fcx.ccx.tcx, ptr); + let sty = structure_of(fcx, ptr.span, ty); + alt sty { + ty::ty_ptr(_) { + require_unsafe(fcx.ccx.tcx.sess, fcx.purity, lhs.span); + } + _ {} + } + } + _ { + } + } +} + fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, expected: ty::t) -> bool { //log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr); @@ -1702,6 +1719,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, rhs: @ast::expr, id: ast::node_id) -> bool { let t = next_ty_var(fcx); let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t); + check_for_unsafe_assignments(fcx, lhs); write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx)); ret bot; } diff --git a/src/test/compile-fail/unsafe-fn-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-deref-ptr.rs new file mode 100644 index 0000000000000..cf5dac3ff89f4 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-deref-ptr.rs @@ -0,0 +1,11 @@ +// -*- rust -*- +// error-pattern: unsafe operation requires unsafe function or block + +fn f(p: *u8) { + *p = 0u8; + ret; +} + +fn main() { + f(); +} From fece625045005e1f451f19be41c8d43909f64fbd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 21:21:52 -0700 Subject: [PATCH 46/49] make compiler emit more than 1 error in the case of unsafe --- src/comp/middle/typeck.rs | 31 +++++--------------- src/test/compile-fail/unsafe-fn-deref-ptr.rs | 5 ++-- src/test/stdtest/str.rs | 4 +-- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index e18e5c2c63ea9..aed017eeef56e 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1528,7 +1528,7 @@ fn require_unsafe(sess: session::session, f_purity: ast::purity, sp: span) { alt f_purity { ast::unsafe_fn. { ret; } _ { - sess.span_fatal( + sess.span_err( sp, "unsafe operation requires unsafe function or block"); } @@ -1541,7 +1541,7 @@ fn require_impure(sess: session::session, f_purity: ast::purity, sp: span) { ast::unsafe_fn. { ret; } ast::impure_fn. { ret; } ast::pure_fn. { - sess.span_fatal(sp, "Found impure expression in pure function decl"); + sess.span_err(sp, "Found impure expression in pure function decl"); } } } @@ -1556,7 +1556,7 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, some(ast::def_fn(_, ast::unsafe_fn.)) | some(ast::def_native_fn(_, ast::unsafe_fn.)) { if sess.get_opts().check_unsafe { - ccx.tcx.sess.span_fatal( + ccx.tcx.sess.span_err( sp, "safe function calls function marked unsafe"); } @@ -1570,7 +1570,7 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, alt ccx.tcx.def_map.find(callee.id) { some(ast::def_fn(_, ast::pure_fn.)) { ret; } _ { - ccx.tcx.sess.span_fatal + ccx.tcx.sess.span_err (sp, "pure function calls function not known to be pure"); } } @@ -1591,23 +1591,6 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { ret check_expr_with_unifier(fcx, expr, demand::simple, expected); } -fn check_for_unsafe_assignments(fcx: @fn_ctxt, lhs: @ast::expr) { - alt lhs.node { - ast::expr_unary(ast::deref., ptr) { - let ty = expr_ty(fcx.ccx.tcx, ptr); - let sty = structure_of(fcx, ptr.span, ty); - alt sty { - ty::ty_ptr(_) { - require_unsafe(fcx.ccx.tcx.sess, fcx.purity, lhs.span); - } - _ {} - } - } - _ { - } - } -} - fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, expected: ty::t) -> bool { //log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr); @@ -1719,7 +1702,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, rhs: @ast::expr, id: ast::node_id) -> bool { let t = next_ty_var(fcx); let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t); - check_for_unsafe_assignments(fcx, lhs); write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx)); ret bot; } @@ -1872,7 +1854,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, oper_t = ty::substitute_type_params(tcx, tps, variants[0].args[0]); } - ty::ty_ptr(inner) { oper_t = inner.ty; } + ty::ty_ptr(inner) { + oper_t = inner.ty; + require_unsafe(fcx.ccx.tcx.sess, fcx.purity, expr.span); + } _ { tcx.sess.span_fatal(expr.span, "dereferencing non-" + diff --git a/src/test/compile-fail/unsafe-fn-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-deref-ptr.rs index cf5dac3ff89f4..238acc8729c2b 100644 --- a/src/test/compile-fail/unsafe-fn-deref-ptr.rs +++ b/src/test/compile-fail/unsafe-fn-deref-ptr.rs @@ -1,9 +1,8 @@ // -*- rust -*- // error-pattern: unsafe operation requires unsafe function or block -fn f(p: *u8) { - *p = 0u8; - ret; +fn f(p: *u8) -> u8 { + ret *p; } fn main() { diff --git a/src/test/stdtest/str.rs b/src/test/stdtest/str.rs index aa3a61f3dd515..470c8daee5e57 100644 --- a/src/test/stdtest/str.rs +++ b/src/test/stdtest/str.rs @@ -264,14 +264,14 @@ fn str_from_cstr() unsafe { } #[test] -fn as_buf() { +fn as_buf() unsafe { let a = "Abcdefg"; let b = str::as_buf(a, {|buf| assert (*buf == 65u8); 100 }); assert (b == 100); } #[test] -fn as_buf_small() { +fn as_buf_small() unsafe { let a = "A"; let b = str::as_buf(a, {|buf| assert (*buf == 65u8); 100 }); assert (b == 100); From 70c69f7bea45ad3f5fe1deaa3375d68d89e3c58c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 21:22:08 -0700 Subject: [PATCH 47/49] new test --- src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs diff --git a/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs new file mode 100644 index 0000000000000..cf5dac3ff89f4 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs @@ -0,0 +1,11 @@ +// -*- rust -*- +// error-pattern: unsafe operation requires unsafe function or block + +fn f(p: *u8) { + *p = 0u8; + ret; +} + +fn main() { + f(); +} From 417391695e9a9ba352d0c81b971eadf95aae252c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Oct 2011 22:08:36 -0700 Subject: [PATCH 48/49] remove unsafe tags --- src/comp/lib/llvm.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 8a6464cc1cfdc..c028c028e6b26 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -925,7 +925,7 @@ fn type_to_str(names: type_names, ty: TypeRef) -> str { } fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> - str unsafe { + str { if names.type_has_name(ty) { ret names.get_name(ty); } @@ -956,7 +956,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> 7 { ret "i" + std::int::str(llvm::LLVMGetIntTypeWidth(ty) as int); } - 8 { + 8 unsafe { let s = "fn("; let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); let n_args: uint = llvm::LLVMCountParamTypes(ty); @@ -969,7 +969,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> s += type_to_str_inner(names, outer, out_ty); ret s; } - 9 { + 9 unsafe { let s: str = "{"; let n_elts: uint = llvm::LLVMCountStructElementTypes(ty); let elts: [TypeRef] = vec::init_elt::(0 as TypeRef, n_elts); @@ -1003,7 +1003,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> } } -fn float_width(llt: TypeRef) -> uint unsafe { +fn float_width(llt: TypeRef) -> uint { ret alt llvm::LLVMGetTypeKind(llt) { 1 { 32u } 2 { 64u } @@ -1022,13 +1022,13 @@ fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] unsafe { /* Memory-managed interface to target data. */ -resource target_data_res(TD: TargetDataRef) unsafe { +resource target_data_res(TD: TargetDataRef) { llvm::LLVMDisposeTargetData(TD); } type target_data = {lltd: TargetDataRef, dtor: @target_data_res}; -fn mk_target_data(string_rep: str) -> target_data unsafe { +fn mk_target_data(string_rep: str) -> target_data { let lltd = str::as_buf(string_rep, {|buf| llvm::LLVMCreateTargetData(buf) }); ret {lltd: lltd, dtor: @target_data_res(lltd)}; @@ -1036,39 +1036,39 @@ fn mk_target_data(string_rep: str) -> target_data unsafe { /* Memory-managed interface to pass managers. */ -resource pass_manager_res(PM: PassManagerRef) unsafe { +resource pass_manager_res(PM: PassManagerRef) { llvm::LLVMDisposePassManager(PM); } type pass_manager = {llpm: PassManagerRef, dtor: @pass_manager_res}; -fn mk_pass_manager() -> pass_manager unsafe { +fn mk_pass_manager() -> pass_manager { let llpm = llvm::LLVMCreatePassManager(); ret {llpm: llpm, dtor: @pass_manager_res(llpm)}; } /* Memory-managed interface to object files. */ -resource object_file_res(ObjectFile: ObjectFileRef) unsafe { +resource object_file_res(ObjectFile: ObjectFileRef) { llvm::LLVMDisposeObjectFile(ObjectFile); } type object_file = {llof: ObjectFileRef, dtor: @object_file_res}; -fn mk_object_file(llmb: MemoryBufferRef) -> object_file unsafe { +fn mk_object_file(llmb: MemoryBufferRef) -> object_file { let llof = llvm::LLVMCreateObjectFile(llmb); ret {llof: llof, dtor: @object_file_res(llof)}; } /* Memory-managed interface to section iterators. */ -resource section_iter_res(SI: SectionIteratorRef) unsafe { +resource section_iter_res(SI: SectionIteratorRef) { llvm::LLVMDisposeSectionIterator(SI); } type section_iter = {llsi: SectionIteratorRef, dtor: @section_iter_res}; -fn mk_section_iter(llof: ObjectFileRef) -> section_iter unsafe { +fn mk_section_iter(llof: ObjectFileRef) -> section_iter { let llsi = llvm::LLVMGetSections(llof); ret {llsi: llsi, dtor: @section_iter_res(llsi)}; } From f80456239213f81bca9e42248552923360baf026 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Oct 2011 13:31:41 -0700 Subject: [PATCH 49/49] reimplement some of the unsafe stuff which got lost: - blocks inherit unsafety - remove the --check-unsafe flag - add unsafe annotations where needed to get things to compile --- src/comp/back/link.rs | 17 ++-- src/comp/driver/rustc.rs | 4 +- src/comp/driver/session.rs | 3 +- src/comp/lib/llvm.rs | 4 +- src/comp/metadata/creader.rs | 36 ++++---- src/comp/metadata/decoder.rs | 4 + src/comp/middle/gc.rs | 6 +- src/comp/middle/shape.rs | 6 +- src/comp/middle/trans_build.rs | 6 +- src/comp/middle/trans_common.rs | 86 ++++++++----------- src/comp/middle/trans_objects.rs | 4 +- src/comp/middle/typeck.rs | 36 ++++---- src/compiletest/procsrv.rs | 6 +- src/lib/aio.rs | 4 +- src/lib/dbg.rs | 6 +- src/lib/generic_os.rs | 2 +- src/lib/io.rs | 6 +- src/lib/run_program.rs | 2 +- src/lib/str.rs | 8 +- src/lib/sys.rs | 24 ++---- src/lib/task.rs | 2 +- src/lib/vec.rs | 12 ++- .../compile-fail/unsafe-fn-used-in-bind.rs | 9 ++ 23 files changed, 137 insertions(+), 156 deletions(-) create mode 100644 src/test/compile-fail/unsafe-fn-used-in-bind.rs diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index fbf1f4b78813d..4a7e238ae55d1 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -34,16 +34,14 @@ tag output_type { output_type_exe; } -fn llvm_err(sess: session::session, msg: str) { - unsafe { - let buf = llvm::LLVMRustGetLastError(); - if buf == std::ptr::null() { - sess.fatal(msg); - } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } - } +fn llvm_err(sess: session::session, msg: str) unsafe { + let buf = llvm::LLVMRustGetLastError(); + if buf == std::ptr::null() { + sess.fatal(msg); + } else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); } } -fn link_intrinsics(sess: session::session, llmod: ModuleRef) unsafe { +fn link_intrinsics(sess: session::session, llmod: ModuleRef) { let path = alt filesearch::search( sess.filesearch(), bind filesearch::pick_file("intrinsics.bc", _)) { @@ -90,8 +88,7 @@ mod write { } else { stem = str::substr(output_path, 0u, dot_pos as uint); } ret stem + "." + extension; } - fn run_passes(sess: session::session, llmod: ModuleRef, output: str) - unsafe { + fn run_passes(sess: session::session, llmod: ModuleRef, output: str) { let opts = sess.get_opts(); if opts.time_llvm_passes { llvm::LLVMRustEnableTimePasses(); } link_intrinsics(sess, llmod); diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 46f8da829a631..43d138c9e1acc 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -325,7 +325,6 @@ 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 { @@ -397,8 +396,7 @@ fn build_session_options(match: getopts::match) parse_only: parse_only, no_trans: no_trans, do_gc: do_gc, - stack_growth: stack_growth, - check_unsafe: check_unsafe}; + stack_growth: stack_growth}; ret sopts; } diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 6ba2148e8a4c8..1f3f9baab8a90 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -41,8 +41,7 @@ type options = parse_only: bool, no_trans: bool, do_gc: bool, - stack_growth: bool, - check_unsafe: bool}; + stack_growth: bool}; type crate_metadata = {name: str, data: [u8]}; diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index c028c028e6b26..9562e05bed575 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -956,7 +956,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> 7 { ret "i" + std::int::str(llvm::LLVMGetIntTypeWidth(ty) as int); } - 8 unsafe { + 8 { let s = "fn("; let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); let n_args: uint = llvm::LLVMCountParamTypes(ty); @@ -969,7 +969,7 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> s += type_to_str_inner(names, outer, out_ty); ret s; } - 9 unsafe { + 9 { let s: str = "{"; let n_elts: uint = llvm::LLVMCountStructElementTypes(ty); let elts: [TypeRef] = vec::init_elt::(0 as TypeRef, n_elts); diff --git a/src/comp/metadata/creader.rs b/src/comp/metadata/creader.rs index 1dd51a8b680ab..fe352290d2c81 100644 --- a/src/comp/metadata/creader.rs +++ b/src/comp/metadata/creader.rs @@ -169,27 +169,25 @@ fn find_library_crate_aux(nn: {prefix: str, suffix: str}, crate_name: str, }); } -fn get_metadata_section(filename: str) -> option::t<@[u8]> { - unsafe { - let mb = str::as_buf(filename, {|buf| - llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) - }); - if mb as int == 0 { ret option::none::<@[u8]>; } - let of = mk_object_file(mb); - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let name_buf = llvm::LLVMGetSectionName(si.llsi); - let name = str::str_from_cstr(name_buf); - if str::eq(name, x86::get_meta_sect_name()) { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi); - let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); - ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); - } - llvm::LLVMMoveToNextSection(si.llsi); +fn get_metadata_section(filename: str) -> option::t<@[u8]> unsafe { + let mb = str::as_buf(filename, {|buf| + llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) + }); + if mb as int == 0 { ret option::none::<@[u8]>; } + let of = mk_object_file(mb); + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let name_buf = llvm::LLVMGetSectionName(si.llsi); + let name = str::str_from_cstr(name_buf); + if str::eq(name, x86::get_meta_sect_name()) { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi); + let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf); + ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); } - ret option::none::<@[u8]>; + llvm::LLVMMoveToNextSection(si.llsi); } + ret option::none::<@[u8]>; } fn load_library_crate(sess: session::session, span: span, ident: ast::ident, diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index 4a103d357558a..8d3f8f5d82440 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -256,6 +256,8 @@ fn family_has_type_params(fam_ch: u8) -> bool { 'u' { true } 'p' { true } 'F' { true } + 'U' { true } + 'P' { true } 'y' { true } 't' { true } 'T' { false } @@ -285,6 +287,8 @@ fn item_family_to_str(fam: u8) -> str { 'u' { ret "unsafe fn"; } 'p' { ret "pure fn"; } 'F' { ret "native fn"; } + 'U' { ret "unsafe native fn"; } + 'P' { ret "pure native fn"; } 'y' { ret "type"; } 'T' { ret "native type"; } 't' { ret "type"; } diff --git a/src/comp/middle/gc.rs b/src/comp/middle/gc.rs index 7de07b55e3b17..be5376bc2b6bf 100644 --- a/src/comp/middle/gc.rs +++ b/src/comp/middle/gc.rs @@ -16,8 +16,7 @@ type ctxt = @{mutable next_tydesc_num: uint}; fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; } -fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) - -> ValueRef unsafe { +fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef { let llglobal = str::as_buf(name, {|buf| @@ -28,8 +27,7 @@ fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) ret llglobal; } -fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> - @block_ctxt unsafe { +fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt { let bcx = cx; if !type_is_gc_relevant(bcx_tcx(cx), ty) || ty::type_has_dynamic_size(bcx_tcx(cx), ty) { diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index 17c72d6b6c21b..7c54bde66b32f 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -72,7 +72,7 @@ fn eq_res_info(a: res_info, b: res_info) -> bool { } fn mk_global(ccx: @crate_ctxt, name: str, llval: ValueRef, internal: bool) -> - ValueRef unsafe { + ValueRef { let llglobal = str::as_buf(name, {|buf| @@ -245,7 +245,7 @@ fn s_float(_tcx: ty_ctxt) -> u8 { ret shape_f64; // TODO: x86-64 } -fn mk_ctxt(llmod: ModuleRef) -> ctxt unsafe { +fn mk_ctxt(llmod: ModuleRef) -> ctxt { let llshapetablesty = trans_common::T_named_struct("shapes"); let llshapetables = str::as_buf("shapes", @@ -580,7 +580,7 @@ fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef { ret mk_global(ccx, "resource_shapes", C_struct(dtors), true); } -fn gen_shape_tables(ccx: @crate_ctxt) unsafe { +fn gen_shape_tables(ccx: @crate_ctxt) { let lltagstable = gen_tag_shapes(ccx); let llresourcestable = gen_resource_shapes(ccx); trans_common::set_struct_body(ccx.shape_cx.llshapetablesty, diff --git a/src/comp/middle/trans_build.rs b/src/comp/middle/trans_build.rs index 7cf9a9c27b3f2..d0b0523af9372 100644 --- a/src/comp/middle/trans_build.rs +++ b/src/comp/middle/trans_build.rs @@ -492,16 +492,16 @@ fn _UndefReturn(Fn: ValueRef) -> ValueRef { } fn Call(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { + if cx.unreachable { ret _UndefReturn(Fn); } unsafe { - if cx.unreachable { ret _UndefReturn(Fn); } ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); } } fn FastCall(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { + if cx.unreachable { ret _UndefReturn(Fn); } unsafe { - if cx.unreachable { ret _UndefReturn(Fn); } let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); @@ -511,8 +511,8 @@ fn FastCall(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { fn CallWithConv(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], Conv: uint) -> ValueRef { + if cx.unreachable { ret _UndefReturn(Fn); } unsafe { - if cx.unreachable { ret _UndefReturn(Fn); } let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); llvm::LLVMSetInstructionCallConv(v, Conv); diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 945530d87d2af..6ed895aa6559b 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -427,14 +427,12 @@ fn val_ty(v: ValueRef) -> TypeRef { ret llvm::LLVMTypeOf(v); } fn val_str(tn: type_names, v: ValueRef) -> str { ret ty_str(tn, val_ty(v)); } // Returns the nth element of the given LLVM structure type. -fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef { - unsafe { - let elt_count = llvm::LLVMCountStructElementTypes(llstructty); - assert (n < elt_count); - let elt_tys = std::vec::init_elt(T_nil(), elt_count); - llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); - ret llvm::LLVMGetElementType(elt_tys[n]); - } +fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef unsafe { + let elt_count = llvm::LLVMCountStructElementTypes(llstructty); + assert (n < elt_count); + let elt_tys = std::vec::init_elt(T_nil(), elt_count); + llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); + ret llvm::LLVMGetElementType(elt_tys[n]); } fn find_scope_cx(cx: @block_ctxt) -> @block_ctxt { @@ -541,10 +539,8 @@ fn T_named_struct(name: str) -> TypeRef { ret str::as_buf(name, {|buf| llvm::LLVMStructCreateNamed(c, buf) }); } -fn set_struct_body(t: TypeRef, elts: [TypeRef]) { - unsafe { - llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); - } +fn set_struct_body(t: TypeRef, elts: [TypeRef]) unsafe { + llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); } fn T_empty_struct() -> TypeRef { ret T_struct([]); } @@ -581,18 +577,16 @@ fn T_task() -> TypeRef { ret t; } -fn T_tydesc_field(cx: crate_ctxt, field: int) -> TypeRef { +fn T_tydesc_field(cx: crate_ctxt, field: int) -> TypeRef unsafe { // Bit of a kludge: pick the fn typeref out of the tydesc.. - unsafe { - let tydesc_elts: [TypeRef] = - std::vec::init_elt::(T_nil(), - abi::n_tydesc_fields as uint); - llvm::LLVMGetStructElementTypes(cx.tydesc_type, - to_ptr::(tydesc_elts)); - let t = llvm::LLVMGetElementType(tydesc_elts[field]); - ret t; - } + let tydesc_elts: [TypeRef] = + std::vec::init_elt::(T_nil(), + abi::n_tydesc_fields as uint); + llvm::LLVMGetStructElementTypes(cx.tydesc_type, + to_ptr::(tydesc_elts)); + let t = llvm::LLVMGetElementType(tydesc_elts[field]); + ret t; } fn T_glue_fn(cx: crate_ctxt) -> TypeRef { @@ -798,43 +792,33 @@ fn C_postr(s: str) -> ValueRef { }); } -fn C_zero_byte_arr(size: uint) -> ValueRef { - unsafe { - let i = 0u; - let elts: [ValueRef] = []; - while i < size { elts += [C_u8(0u)]; i += 1u; } - ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), - std::vec::len(elts)); - } +fn C_zero_byte_arr(size: uint) -> ValueRef unsafe { + let i = 0u; + let elts: [ValueRef] = []; + while i < size { elts += [C_u8(0u)]; i += 1u; } + ret llvm::LLVMConstArray(T_i8(), std::vec::to_ptr(elts), + std::vec::len(elts)); } -fn C_struct(elts: [ValueRef]) -> ValueRef { - unsafe { - ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), - False); - } +fn C_struct(elts: [ValueRef]) -> ValueRef unsafe { + ret llvm::LLVMConstStruct(std::vec::to_ptr(elts), std::vec::len(elts), + False); } -fn C_named_struct(T: TypeRef, elts: [ValueRef]) -> ValueRef { - unsafe { - ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), - std::vec::len(elts)); - } +fn C_named_struct(T: TypeRef, elts: [ValueRef]) -> ValueRef unsafe { + ret llvm::LLVMConstNamedStruct(T, std::vec::to_ptr(elts), + std::vec::len(elts)); } -fn C_array(ty: TypeRef, elts: [ValueRef]) -> ValueRef { - unsafe { - ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), - std::vec::len(elts)); - } +fn C_array(ty: TypeRef, elts: [ValueRef]) -> ValueRef unsafe { + ret llvm::LLVMConstArray(ty, std::vec::to_ptr(elts), + std::vec::len(elts)); } -fn C_bytes(bytes: [u8]) -> ValueRef { - unsafe { - ret llvm::LLVMConstString( - unsafe::reinterpret_cast(vec::to_ptr(bytes)), - vec::len(bytes), False); - } +fn C_bytes(bytes: [u8]) -> ValueRef unsafe { + ret llvm::LLVMConstString( + unsafe::reinterpret_cast(vec::to_ptr(bytes)), + vec::len(bytes), False); } fn C_shape(ccx: @crate_ctxt, bytes: [u8]) -> ValueRef { diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs index af5f4266b9eb3..a2a63d88306fe 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -569,7 +569,7 @@ fn create_backwarding_vtbl(cx: @local_ctxt, sp: span, inner_obj_ty: ty::t, // finish_vtbl: Given a vector of vtable entries, create the table in // read-only memory and return a pointer to it. fn finish_vtbl(cx: @local_ctxt, llmethods: [ValueRef], name: str) -> - ValueRef unsafe { + ValueRef { let vtbl = C_struct(llmethods); let vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + [name]); let gvar = @@ -619,7 +619,7 @@ fn begin_fn(cx: @local_ctxt, sp: span, m: @ty::method, // returns the value returned from that call. fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method, ty_params: [ast::ty_param], outer_obj_ty: ty::t, - _additional_field_tys: [ty::t]) -> ValueRef unsafe { + _additional_field_tys: [ty::t]) -> ValueRef { let llbackwarding_fn = begin_fn(cx, sp, m, ty_params, "backwarding_fn"); let fcx = new_fn_ctxt(cx, sp, llbackwarding_fn); diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index aed017eeef56e..4b0f4f7b1c101 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1524,15 +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) { - if sess.get_opts().check_unsafe { - alt f_purity { - ast::unsafe_fn. { ret; } - _ { - sess.span_err( - sp, - "unsafe operation requires unsafe function or block"); - } - } + alt f_purity { + ast::unsafe_fn. { ret; } + _ { + sess.span_err( + sp, + "unsafe operation requires unsafe function or block"); + } } } @@ -1551,15 +1549,12 @@ 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.)) | some(ast::def_native_fn(_, ast::unsafe_fn.)) { - if sess.get_opts().check_unsafe { - ccx.tcx.sess.span_err( - sp, - "safe function calls function marked unsafe"); - } + ccx.tcx.sess.span_err( + sp, + "safe function calls function marked unsafe"); } _ { } @@ -2727,13 +2722,22 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, old_fcx: option::t<@fn_ctxt>) { + let decl = f.decl; let body = f.body; + + // If old_fcx is some(...), this is a block fn { |x| ... }. + // In that case, the purity is inherited from the context. + let purity = alt old_fcx { + none. { decl.purity } + some(f) { assert decl.purity == ast::impure_fn; f.purity } + }; + let gather_result = gather_locals(ccx, f, id, old_fcx); let fixups: [ast::node_id] = []; let fcx: @fn_ctxt = @{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)), - purity: decl.purity, + purity: purity, proto: f.proto, var_bindings: gather_result.var_bindings, locals: gather_result.locals, diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 467b98d8b640a..1563e3112ca1e 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -70,7 +70,7 @@ fn run(handle: handle, lib_path: str, prog: str, args: [str], ret {status: status, out: output, err: errput}; } -fn writeclose(fd: int, s: option::t) unsafe { +fn writeclose(fd: int, s: option::t) { if option::is_some(s) { let writer = io::new_writer(io::fd_buf_writer(fd, option::none)); writer.write_str(option::get(s)); @@ -79,7 +79,7 @@ fn writeclose(fd: int, s: option::t) unsafe { os::libc::close(fd); } -fn readclose(fd: int) -> str unsafe { +fn readclose(fd: int) -> str { // Copied from run::program_output let file = os::fd_FILE(fd); let reader = io::new_reader(io::FILE_buf_reader(file, option::none)); @@ -92,7 +92,7 @@ fn readclose(fd: int) -> str unsafe { ret buf; } -fn worker(p: port) unsafe { +fn worker(p: port) { // FIXME (787): If we declare this inside of the while loop and then // break out of it before it's ever initialized (i.e. we don't run diff --git a/src/lib/aio.rs b/src/lib/aio.rs index 5d7430a82ecfe..42f744ff865e8 100644 --- a/src/lib/aio.rs +++ b/src/lib/aio.rs @@ -41,7 +41,7 @@ tag request { type ctx = chan; -fn ip_to_sbuf(ip: net::ip_addr) -> *u8 { +fn ip_to_sbuf(ip: net::ip_addr) -> *u8 unsafe { // FIXME: This is broken. We're creating a vector, getting a pointer // to its buffer, then dropping the vector. On top of that, the vector @@ -131,7 +131,7 @@ fn request_task(c: chan) { serve(ip, portnum, events, server) { task::spawn(bind server_task(ip, portnum, events, server)); } - write(socket, v, status) { + write(socket, v, status) unsafe { rustrt::aio_writedata(socket, vec::unsafe::to_ptr::(v), vec::len::(v), status); } diff --git a/src/lib/dbg.rs b/src/lib/dbg.rs index 6371eec349bf6..af568ee8f0cf1 100644 --- a/src/lib/dbg.rs +++ b/src/lib/dbg.rs @@ -42,9 +42,11 @@ fn debug_obj(x: T, nmethods: uint, nbytes: uint) { fn debug_fn(x: T) { rustrt::debug_fn::(x); } -fn ptr_cast(x: @T) -> @U { ret rustrt::debug_ptrcast::(x); } +unsafe fn ptr_cast(x: @T) -> @U { + ret rustrt::debug_ptrcast::(x); +} -fn refcount(a: @T) -> uint { +fn refcount(a: @T) -> uint unsafe { let p: *uint = unsafe::reinterpret_cast(a); ret *p; } diff --git a/src/lib/generic_os.rs b/src/lib/generic_os.rs index e179aa1f92c28..d1e39a2ea9f8f 100644 --- a/src/lib/generic_os.rs +++ b/src/lib/generic_os.rs @@ -3,7 +3,7 @@ import str::sbuf; #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] -fn getenv(n: str) -> option::t { +fn getenv(n: str) -> option::t unsafe { let s = str::as_buf(n, {|buf| os::libc::getenv(buf) }); ret if unsafe::reinterpret_cast(s) == 0 { option::none:: diff --git a/src/lib/io.rs b/src/lib/io.rs index c2ee7ff53ca5c..327e565588963 100644 --- a/src/lib/io.rs +++ b/src/lib/io.rs @@ -57,7 +57,7 @@ fn convert_whence(whence: seek_style) -> int { resource FILE_res(f: os::libc::FILE) { os::libc::fclose(f); } obj FILE_buf_reader(f: os::libc::FILE, res: option::t<@FILE_res>) { - fn read(len: uint) -> [u8] { + fn read(len: uint) -> [u8] unsafe { let buf = []; vec::reserve::(buf, len); let read = @@ -239,7 +239,7 @@ type buf_writer = }; obj FILE_writer(f: os::libc::FILE, res: option::t<@FILE_res>) { - fn write(v: [u8]) { + fn write(v: [u8]) unsafe { let len = vec::len::(v); let vbuf = vec::unsafe::to_ptr::(v); let nout = os::libc::fwrite(vbuf, len, 1u, f); @@ -254,7 +254,7 @@ obj FILE_writer(f: os::libc::FILE, res: option::t<@FILE_res>) { resource fd_res(fd: int) { os::libc::close(fd); } obj fd_buf_writer(fd: int, res: option::t<@fd_res>) { - fn write(v: [u8]) { + fn write(v: [u8]) unsafe { let len = vec::len::(v); let count = 0u; let vbuf; diff --git a/src/lib/run_program.rs b/src/lib/run_program.rs index 31bccf320374c..cb36179587fa5 100644 --- a/src/lib/run_program.rs +++ b/src/lib/run_program.rs @@ -21,7 +21,7 @@ fn arg_vec(prog: str, args: [@str]) -> [sbuf] { } fn spawn_process(prog: str, args: [str], in_fd: int, out_fd: int, err_fd: int) - -> int { + -> int unsafe { // Note: we have to hold on to these vector references while we hold a // pointer to their buffers let prog = prog; diff --git a/src/lib/str.rs b/src/lib/str.rs index a3c8a5486920d..7a5660244223e 100644 --- a/src/lib/str.rs +++ b/src/lib/str.rs @@ -426,16 +426,18 @@ type sbuf = *u8; // NB: This is intentionally unexported because it's easy to misuse (there's // no guarantee that the string is rooted). Instead, use as_buf below. -fn buf(s: str) -> sbuf { +unsafe fn buf(s: str) -> sbuf { let saddr = ptr::addr_of(s); let vaddr: *[u8] = unsafe::reinterpret_cast(saddr); let buf = vec::to_ptr(*vaddr); ret buf; } -fn as_buf(s: str, f: block(sbuf) -> T) -> T { let buf = buf(s); f(buf) } +fn as_buf(s: str, f: block(sbuf) -> T) -> T unsafe { + let buf = buf(s); f(buf) +} -fn str_from_cstr(cstr: sbuf) -> str { +unsafe fn str_from_cstr(cstr: sbuf) -> str { let res = ""; let start = cstr; let curr = start; diff --git a/src/lib/sys.rs b/src/lib/sys.rs index c366e7c4ce52c..40209f9e54eb2 100644 --- a/src/lib/sys.rs +++ b/src/lib/sys.rs @@ -15,39 +15,27 @@ native "rust" mod rustrt { } fn last_os_error() -> str { - //unsafe { - ret rustrt::last_os_error(); - //} + ret rustrt::last_os_error(); } fn size_of() -> uint { - //unsafe { - ret rustrt::size_of::(); - //} + ret rustrt::size_of::(); } fn align_of() -> uint { - //unsafe { - ret rustrt::align_of::(); - //} + ret rustrt::align_of::(); } fn refcount(t: @T) -> uint { - //unsafe { - ret rustrt::refcount::(t); - //} + ret rustrt::refcount::(t); } fn do_gc() -> () { - //unsafe { - ret rustrt::do_gc(); - //} + ret rustrt::do_gc(); } fn unsupervise() -> () { - //unsafe { - ret rustrt::unsupervise(); - //} + ret rustrt::unsupervise(); } // Local Variables: diff --git a/src/lib/task.rs b/src/lib/task.rs index 7a95ea49aafd9..de1a749fee35e 100644 --- a/src/lib/task.rs +++ b/src/lib/task.rs @@ -108,7 +108,7 @@ fn spawn_joinable(-thunk: fn()) -> joinable_task { // FIXME: make this a fn~ once those are supported. fn spawn_inner(-thunk: fn(), notify: option>) -> - task_id { + task_id unsafe { let id = rustrt::new_task(); let raw_thunk: {code: u32, env: u32} = cast(thunk); diff --git a/src/lib/vec.rs b/src/lib/vec.rs index b2d19d9ed54e2..04e35e9e979b2 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -15,9 +15,7 @@ native "rust" mod rustrt { /// Reserves space for `n` elements in the given vector. fn reserve<@T>(&v: [mutable? T], n: uint) { - //unsafe { - rustrt::vec_reserve_shared(v, n); - //} + rustrt::vec_reserve_shared(v, n); } pure fn len(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } } @@ -353,22 +351,22 @@ iter iter2<@T>(v: [T]) -> (uint, T) { mod unsafe { type vec_repr = {mutable fill: uint, mutable alloc: uint, data: u8}; - fn from_buf<@T>(ptr: *T, elts: uint) -> [T] { + unsafe fn from_buf<@T>(ptr: *T, elts: uint) -> [T] { ret rustrt::vec_from_buf_shared(ptr, elts); } - fn set_len<@T>(&v: [T], new_len: uint) { + unsafe fn set_len<@T>(&v: [T], new_len: uint) { let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); (**repr).fill = new_len * sys::size_of::(); } - fn to_ptr<@T>(v: [T]) -> *T { + unsafe fn to_ptr<@T>(v: [T]) -> *T { let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); ret ::unsafe::reinterpret_cast(addr_of((**repr).data)); } } -fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); } +unsafe fn to_ptr<@T>(v: [T]) -> *T { ret unsafe::to_ptr(v); } // Local Variables: // mode: rust; diff --git a/src/test/compile-fail/unsafe-fn-used-in-bind.rs b/src/test/compile-fail/unsafe-fn-used-in-bind.rs new file mode 100644 index 0000000000000..2622afe2e39f0 --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-used-in-bind.rs @@ -0,0 +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, _); + let y = x(4); +}