diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 52024d6f5b728..4a7e238ae55d1 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -34,7 +34,7 @@ tag output_type { output_type_exe; } -fn llvm_err(sess: session::session, msg: str) { +fn llvm_err(sess: session::session, msg: str) unsafe { let buf = llvm::LLVMRustGetLastError(); if buf == std::ptr::null() { sess.fatal(msg); diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 76819b9960544..43d138c9e1acc 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}; @@ -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", @@ -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 { @@ -323,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 { @@ -395,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/front/test.rs b/src/comp/front/test.rs index 70985f108060d..ce1c0f02088c7 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -6,22 +6,26 @@ import syntax::ast_util::*; //import syntax::ast_util::dummy_sp; import syntax::fold; import syntax::print::pprust; +import syntax::codemap::span; +import driver::session; 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, + @{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 @@ -36,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: []}; @@ -89,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 = {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); @@ -237,6 +251,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 +261,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 +271,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 +281,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 +289,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; } diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index c47f75135d7c1..9562e05bed575 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; @@ -1009,7 +1013,7 @@ 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)); 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..fe352290d2c81 100644 --- a/src/comp/metadata/creader.rs +++ b/src/comp/metadata/creader.rs @@ -169,10 +169,10 @@ fn find_library_crate_aux(nn: {prefix: str, suffix: str}, crate_name: str, }); } -fn get_metadata_section(filename: str) -> option::t<@[u8]> { +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); 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/trans_build.rs b/src/comp/middle/trans_build.rs index 384cbb49ff959..d0b0523af9372 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) { @@ -481,25 +493,31 @@ 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 { + 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 { + 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 { + 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 a2287c4c0fca9..6ed895aa6559b 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -427,7 +427,7 @@ 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 { +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); @@ -516,8 +516,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 { @@ -527,7 +529,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 { @@ -535,7 +539,7 @@ 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]) { +fn set_struct_body(t: TypeRef, elts: [TypeRef]) unsafe { llvm::LLVMStructSetBody(t, to_ptr(elts), std::vec::len(elts), False); } @@ -573,11 +577,12 @@ 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.. let tydesc_elts: [TypeRef] = - std::vec::init_elt::(T_nil(), abi::n_tydesc_fields as uint); + 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]); @@ -787,7 +792,7 @@ fn C_postr(s: str) -> ValueRef { }); } -fn C_zero_byte_arr(size: uint) -> 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; } @@ -795,23 +800,25 @@ fn C_zero_byte_arr(size: uint) -> ValueRef { std::vec::len(elts)); } -fn C_struct(elts: [ValueRef]) -> ValueRef { +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 { +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 { - 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 { - 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 aabe09b3d0586..a2a63d88306fe 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -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. diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index f848cf638f8b8..4b0f4f7b1c101 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)); } @@ -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_fatal( - sp, - "Found unsafe expression in safe function decl"); - } - } + alt f_purity { + ast::unsafe_fn. { ret; } + _ { + sess.span_err( + sp, + "unsafe operation requires unsafe function or block"); + } } } @@ -1541,7 +1539,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"); } } } @@ -1551,21 +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.)) { - 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"); - } + ccx.tcx.sess.span_err( + sp, + "safe function calls function marked unsafe"); } _ { } @@ -1576,7 +1565,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"); } } @@ -1860,7 +1849,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-" + @@ -2730,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/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/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/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); } 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..6e9d7ac18fccc --- /dev/null +++ b/src/test/compile-fail/native-unsafe-fn-called.rs @@ -0,0 +1,10 @@ +// -*- 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-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(); +} 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; } 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..238acc8729c2b --- /dev/null +++ b/src/test/compile-fail/unsafe-fn-deref-ptr.rs @@ -0,0 +1,10 @@ +// -*- rust -*- +// error-pattern: unsafe operation requires unsafe function or block + +fn f(p: *u8) -> u8 { + ret *p; +} + +fn main() { + f(); +} 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(); +} 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); +} 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); 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 0000000000000..a57f8f90ca9eb Binary files /dev/null and b/src/test/run-pass/unsafe-fn-called-from-unsafe-blk differ 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/str.rs b/src/test/stdtest/str.rs index f1839a0aa91df..470c8daee5e57 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() { +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); @@ -264,21 +264,21 @@ fn str_from_cstr() { } #[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); } #[test] -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/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(); } diff --git a/src/test/stdtest/vec.rs b/src/test/stdtest/vec.rs index 5e5de913914ae..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] -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);