Merge branch 'unwind'
Conflicts: src/comp/middle/trans.rs src/comp/middle/trans_build.rs src/lib/run_program.rs src/test/compiletest/runtest.rs
This commit is contained in:
commit
393deeb06f
49 changed files with 491 additions and 106 deletions
|
@ -114,7 +114,7 @@ ifdef CFG_UNIXY
|
||||||
endif
|
endif
|
||||||
ifdef CFG_VALGRIND
|
ifdef CFG_VALGRIND
|
||||||
CFG_VALGRIND += --leak-check=full \
|
CFG_VALGRIND += --leak-check=full \
|
||||||
--error-exitcode=1 \
|
--error-exitcode=100 \
|
||||||
--quiet --suppressions=$(CFG_SRC_DIR)src/etc/x86.supp
|
--quiet --suppressions=$(CFG_SRC_DIR)src/etc/x86.supp
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -37,7 +37,8 @@ type upcalls =
|
||||||
log_type: ValueRef,
|
log_type: ValueRef,
|
||||||
dynastack_mark: ValueRef,
|
dynastack_mark: ValueRef,
|
||||||
dynastack_alloc: ValueRef,
|
dynastack_alloc: ValueRef,
|
||||||
dynastack_free: ValueRef};
|
dynastack_free: ValueRef,
|
||||||
|
rust_personality: ValueRef};
|
||||||
|
|
||||||
fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
|
fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
|
||||||
taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
|
taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
|
||||||
|
@ -89,7 +90,9 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
|
||||||
dynastack_alloc:
|
dynastack_alloc:
|
||||||
d("dynastack_alloc_2", [T_size_t(), T_ptr(tydesc_type)],
|
d("dynastack_alloc_2", [T_size_t(), T_ptr(tydesc_type)],
|
||||||
T_ptr(T_i8())),
|
T_ptr(T_i8())),
|
||||||
dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void())};
|
dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void()),
|
||||||
|
rust_personality: dr("rust_personality", [], T_i32())
|
||||||
|
};
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
|
|
|
@ -572,6 +572,9 @@ native "cdecl" mod llvm = "rustllvm" {
|
||||||
fn LLVMBuildInvoke(B: BuilderRef, Fn: ValueRef, Args: *ValueRef,
|
fn LLVMBuildInvoke(B: BuilderRef, Fn: ValueRef, Args: *ValueRef,
|
||||||
NumArgs: uint, Then: BasicBlockRef,
|
NumArgs: uint, Then: BasicBlockRef,
|
||||||
Catch: BasicBlockRef, Name: sbuf) -> ValueRef;
|
Catch: BasicBlockRef, Name: sbuf) -> ValueRef;
|
||||||
|
fn LLVMBuildLandingPad(B: BuilderRef, Ty: TypeRef, PersFn: ValueRef,
|
||||||
|
NumClauses: uint, Name: sbuf) -> ValueRef;
|
||||||
|
fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef;
|
||||||
fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef;
|
fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef;
|
||||||
|
|
||||||
/* Add a case to the switch instruction */
|
/* Add a case to the switch instruction */
|
||||||
|
@ -580,6 +583,12 @@ native "cdecl" mod llvm = "rustllvm" {
|
||||||
/* Add a destination to the indirectbr instruction */
|
/* Add a destination to the indirectbr instruction */
|
||||||
fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef);
|
fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef);
|
||||||
|
|
||||||
|
/* Add a clause to the landing pad instruction */
|
||||||
|
fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef);
|
||||||
|
|
||||||
|
/* Set the cleanup on a landing pad instruction */
|
||||||
|
fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool);
|
||||||
|
|
||||||
/* Arithmetic */
|
/* Arithmetic */
|
||||||
fn LLVMBuildAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf)
|
fn LLVMBuildAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf)
|
||||||
-> ValueRef;
|
-> ValueRef;
|
||||||
|
|
|
@ -3715,7 +3715,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
||||||
for the call itself is unreachable. */
|
for the call itself is unreachable. */
|
||||||
let retval = C_nil();
|
let retval = C_nil();
|
||||||
if !is_terminated(bcx) {
|
if !is_terminated(bcx) {
|
||||||
FastCall(bcx, faddr, llargs);
|
bcx = invoke_fastcall(bcx, faddr, llargs).bcx;
|
||||||
alt lliterbody {
|
alt lliterbody {
|
||||||
none. {
|
none. {
|
||||||
if !ty::type_is_nil(bcx_tcx(cx), ret_ty) {
|
if !ty::type_is_nil(bcx_tcx(cx), ret_ty) {
|
||||||
|
@ -3748,6 +3748,67 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
||||||
ret rslt(bcx, retval);
|
ret rslt(bcx, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invoke(bcx: @block_ctxt, llfn: ValueRef,
|
||||||
|
llargs: [ValueRef]) -> result {
|
||||||
|
ret invoke_(bcx, llfn, llargs, Invoke);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invoke_fastcall(bcx: @block_ctxt, llfn: ValueRef,
|
||||||
|
llargs: [ValueRef]) -> result {
|
||||||
|
ret invoke_(bcx, llfn, llargs, FastInvoke);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invoke_(bcx: @block_ctxt, llfn: ValueRef,
|
||||||
|
llargs: [ValueRef],
|
||||||
|
invoker: fn(@block_ctxt, ValueRef, [ValueRef],
|
||||||
|
BasicBlockRef, BasicBlockRef) -> ValueRef) -> result {
|
||||||
|
// FIXME: May be worth turning this into a plain call when there are no
|
||||||
|
// cleanups to run
|
||||||
|
let normal_bcx = new_sub_block_ctxt(bcx, "normal return");
|
||||||
|
let unwind_bcx = new_sub_block_ctxt(bcx, "unwind");
|
||||||
|
let retval = invoker(bcx, llfn, llargs,
|
||||||
|
normal_bcx.llbb,
|
||||||
|
unwind_bcx.llbb);
|
||||||
|
trans_landing_pad(unwind_bcx);
|
||||||
|
ret rslt(normal_bcx, retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trans_landing_pad(bcx: @block_ctxt) {
|
||||||
|
// The landing pad return type (the type being propagated). Not sure what
|
||||||
|
// this represents but it's determined by the personality function and
|
||||||
|
// this is what the EH proposal example uses.
|
||||||
|
let llretty = T_struct([T_ptr(T_i8()), T_i32()]);
|
||||||
|
// The exception handling personality function. This is the C++
|
||||||
|
// personality function __gxx_personality_v0, wrapped in our naming
|
||||||
|
// convention.
|
||||||
|
let personality = bcx_ccx(bcx).upcalls.rust_personality;
|
||||||
|
// The only landing pad clause will be 'cleanup'
|
||||||
|
let clauses = 1u;
|
||||||
|
let llpad = LandingPad(bcx, llretty, personality, clauses);
|
||||||
|
// The landing pad result is used both for modifying the landing pad
|
||||||
|
// in the C API and as the exception value
|
||||||
|
let llretval = llpad;
|
||||||
|
// The landing pad block is a cleanup
|
||||||
|
SetCleanup(bcx, llpad);
|
||||||
|
|
||||||
|
// FIXME: This seems like a very naive and redundant way to generate the
|
||||||
|
// landing pads, as we're re-generating all in-scope cleanups for each
|
||||||
|
// function call. Probably good optimization opportunities here.
|
||||||
|
let bcx = bcx;
|
||||||
|
let scope_cx = bcx;
|
||||||
|
while true {
|
||||||
|
scope_cx = find_scope_cx(scope_cx);
|
||||||
|
bcx = trans_block_cleanups(bcx, scope_cx);
|
||||||
|
scope_cx = alt scope_cx.parent {
|
||||||
|
parent_some(b) { b }
|
||||||
|
parent_none. { break; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue unwinding
|
||||||
|
Resume(bcx, llretval);
|
||||||
|
}
|
||||||
|
|
||||||
fn trans_tup(cx: @block_ctxt, elts: [@ast::expr], id: ast::node_id) ->
|
fn trans_tup(cx: @block_ctxt, elts: [@ast::expr], id: ast::node_id) ->
|
||||||
result {
|
result {
|
||||||
let bcx = cx;
|
let bcx = cx;
|
||||||
|
@ -4211,7 +4272,7 @@ fn trans_fail_value(cx: @block_ctxt, sp_opt: option::t<span>,
|
||||||
let V_str = PointerCast(cx, V_fail_str, T_ptr(T_i8()));
|
let V_str = PointerCast(cx, V_fail_str, T_ptr(T_i8()));
|
||||||
V_filename = PointerCast(cx, V_filename, T_ptr(T_i8()));
|
V_filename = PointerCast(cx, V_filename, T_ptr(T_i8()));
|
||||||
let args = [cx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)];
|
let args = [cx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)];
|
||||||
Call(cx, bcx_ccx(cx).upcalls._fail, args);
|
let cx = invoke(cx, bcx_ccx(cx).upcalls._fail, args).bcx;
|
||||||
Unreachable(cx);
|
Unreachable(cx);
|
||||||
ret rslt(cx, C_nil());
|
ret rslt(cx, C_nil());
|
||||||
}
|
}
|
||||||
|
@ -4247,7 +4308,7 @@ fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
|
||||||
llargs += [r.val];
|
llargs += [r.val];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FastCall(bcx, llcallee, llargs);
|
bcx = invoke_fastcall(bcx, llcallee, llargs).bcx;
|
||||||
bcx = trans_block_cleanups(bcx, cx);
|
bcx = trans_block_cleanups(bcx, cx);
|
||||||
let next_cx = new_sub_block_ctxt(in_cx, "next");
|
let next_cx = new_sub_block_ctxt(in_cx, "next");
|
||||||
Br(bcx, next_cx.llbb);
|
Br(bcx, next_cx.llbb);
|
||||||
|
@ -4379,7 +4440,9 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> result {
|
||||||
// Make a note to drop this slot on the way out.
|
// Make a note to drop this slot on the way out.
|
||||||
add_clean(bcx, llptr, ty);
|
add_clean(bcx, llptr, ty);
|
||||||
|
|
||||||
if must_zero(local) { bcx = zero_alloca(bcx, llptr, ty).bcx; }
|
if must_zero(bcx_ccx(bcx), local) {
|
||||||
|
bcx = zero_alloca(bcx, llptr, ty).bcx;
|
||||||
|
}
|
||||||
|
|
||||||
alt local.node.init {
|
alt local.node.init {
|
||||||
some(init) {
|
some(init) {
|
||||||
|
@ -4405,35 +4468,38 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> result {
|
||||||
bcx.fcx.lllocals, false);
|
bcx.fcx.lllocals, false);
|
||||||
ret rslt(bcx, llptr);
|
ret rslt(bcx, llptr);
|
||||||
|
|
||||||
fn must_zero(local: @ast::local) -> bool {
|
fn must_zero(ccx: @crate_ctxt, local: @ast::local) -> bool {
|
||||||
alt local.node.init {
|
alt local.node.init {
|
||||||
some(init) { might_not_init(init.expr) }
|
some(init) { might_not_init(ccx, init.expr) }
|
||||||
none. { true }
|
none. { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn might_not_init(expr: @ast::expr) -> bool {
|
fn might_not_init(ccx: @crate_ctxt, expr: @ast::expr) -> bool {
|
||||||
type env = @mutable bool;
|
type env = {mutable mightnt: bool,
|
||||||
let e = @mutable false;
|
ccx: @crate_ctxt};
|
||||||
// FIXME: Probably also need to account for expressions that
|
let e = {mutable mightnt: false,
|
||||||
// fail but since we don't unwind yet, it doesn't seem to be a
|
ccx: ccx};
|
||||||
// problem
|
fn visit_expr(ex: @ast::expr, e: env, v: vt<env>) {
|
||||||
|
let might_not_init = alt ex.node {
|
||||||
|
ast::expr_ret(_) { true }
|
||||||
|
ast::expr_break. { true }
|
||||||
|
ast::expr_cont. { true }
|
||||||
|
ast::expr_call(_, _) { true }
|
||||||
|
_ {
|
||||||
|
let ex_ty = ty::expr_ty(e.ccx.tcx, ex);
|
||||||
|
ty::type_is_bot(e.ccx.tcx, ex_ty)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if might_not_init {
|
||||||
|
e.mightnt = true;
|
||||||
|
} else { visit::visit_expr(ex, e, v); }
|
||||||
|
}
|
||||||
let visitor =
|
let visitor =
|
||||||
visit::mk_vt(@{visit_expr:
|
visit::mk_vt(@{visit_expr: visit_expr
|
||||||
fn (ex: @ast::expr, e: env, v: vt<env>) {
|
with *visit::default_visitor()});
|
||||||
let might_not_init =
|
|
||||||
alt ex.node {
|
|
||||||
ast::expr_ret(_) { true }
|
|
||||||
ast::expr_break. { true }
|
|
||||||
ast::expr_cont. { true }
|
|
||||||
_ { false }
|
|
||||||
};
|
|
||||||
if might_not_init {
|
|
||||||
*e = true;
|
|
||||||
} else { visit::visit_expr(ex, e, v); }
|
|
||||||
} with *visit::default_visitor()});
|
|
||||||
visitor.visit_expr(expr, e, visitor);
|
visitor.visit_expr(expr, e, visitor);
|
||||||
ret *e;
|
ret e.mightnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,21 @@ fn Invoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef],
|
||||||
|
Then: BasicBlockRef, Catch: BasicBlockRef) -> ValueRef {
|
||||||
|
assert (!cx.terminated);
|
||||||
|
cx.terminated = true;
|
||||||
|
let v = str::as_buf("",
|
||||||
|
{|buf|
|
||||||
|
llvm::LLVMBuildInvoke(B(cx), Fn,
|
||||||
|
vec::to_ptr(Args),
|
||||||
|
vec::len(Args), Then,
|
||||||
|
Catch, buf)
|
||||||
|
});
|
||||||
|
llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv);
|
||||||
|
ret v;
|
||||||
|
}
|
||||||
|
|
||||||
fn Unreachable(cx: @block_ctxt) -> ValueRef {
|
fn Unreachable(cx: @block_ctxt) -> ValueRef {
|
||||||
assert (!cx.terminated);
|
assert (!cx.terminated);
|
||||||
cx.terminated = true;
|
cx.terminated = true;
|
||||||
|
@ -527,6 +542,29 @@ fn Trap(cx: @block_ctxt) -> ValueRef {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef,
|
||||||
|
NumClauses: uint) -> ValueRef {
|
||||||
|
assert (!cx.terminated);
|
||||||
|
ret str::as_buf("",
|
||||||
|
{|buf|
|
||||||
|
llvm::LLVMBuildLandingPad(B(cx),
|
||||||
|
Ty,
|
||||||
|
PersFn,
|
||||||
|
NumClauses,
|
||||||
|
buf)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SetCleanup(_cx: @block_ctxt, LandingPad: ValueRef) {
|
||||||
|
llvm::LLVMSetCleanup(LandingPad, lib::llvm::True);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Resume(cx: @block_ctxt, Exn: ValueRef) -> ValueRef {
|
||||||
|
assert (!cx.terminated);
|
||||||
|
cx.terminated = true;
|
||||||
|
ret llvm::LLVMBuildResume(B(cx), Exn);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
|
|
|
@ -27,7 +27,8 @@ for t in os.listdir(run_pass):
|
||||||
f = codecs.open(os.path.join(run_pass, t), "r", "utf8")
|
f = codecs.open(os.path.join(run_pass, t), "r", "utf8")
|
||||||
s = f.read()
|
s = f.read()
|
||||||
if not ("xfail-test" in s or
|
if not ("xfail-test" in s or
|
||||||
"xfail-fast" in s):
|
"xfail-fast" in s or
|
||||||
|
"xfail-win32" in s):
|
||||||
stage2_tests.append(t)
|
stage2_tests.append(t)
|
||||||
if "main(args: [str])" in s:
|
if "main(args: [str])" in s:
|
||||||
take_args[t] = True
|
take_args[t] = True
|
||||||
|
|
|
@ -6,6 +6,7 @@ export run_program;
|
||||||
export start_program;
|
export start_program;
|
||||||
export program_output;
|
export program_output;
|
||||||
export spawn_process;
|
export spawn_process;
|
||||||
|
export waitpid;
|
||||||
|
|
||||||
native "rust" mod rustrt {
|
native "rust" mod rustrt {
|
||||||
fn rust_run_program(argv: *sbuf, in_fd: int, out_fd: int, err_fd: int) ->
|
fn rust_run_program(argv: *sbuf, in_fd: int, out_fd: int, err_fd: int) ->
|
||||||
|
@ -33,7 +34,7 @@ fn spawn_process(prog: str, args: [str], in_fd: int, out_fd: int, err_fd: int)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_program(prog: str, args: [str]) -> int {
|
fn run_program(prog: str, args: [str]) -> int {
|
||||||
ret os::waitpid(spawn_process(prog, args, 0, 0, 0));
|
ret waitpid(spawn_process(prog, args, 0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
type program =
|
type program =
|
||||||
|
@ -87,7 +88,7 @@ fn start_program(prog: str, args: [str]) -> @program_res {
|
||||||
if finished { ret 0; }
|
if finished { ret 0; }
|
||||||
finished = true;
|
finished = true;
|
||||||
self.close_input();
|
self.close_input();
|
||||||
ret os::waitpid(pid);
|
ret waitpid(pid);
|
||||||
}
|
}
|
||||||
fn destroy() {
|
fn destroy() {
|
||||||
self.finish();
|
self.finish();
|
||||||
|
@ -117,6 +118,44 @@ fn program_output(prog: str, args: [str]) ->
|
||||||
out: read_all(pr.output()),
|
out: read_all(pr.output()),
|
||||||
err: read_all(pr.err())};
|
err: read_all(pr.err())};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns an exit status */
|
||||||
|
#[cfg(target_os = "win32")]
|
||||||
|
fn waitpid(pid: int) -> int {
|
||||||
|
os::waitpid(pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn waitpid(pid: int) -> int {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn WIFEXITED(status: int) -> bool {
|
||||||
|
(status & 0xff) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn WIFEXITED(status: int) -> bool {
|
||||||
|
(status & 0x7f) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn WEXITSTATUS(status: int) -> int {
|
||||||
|
(status >> 8) & 0xff
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn WEXITSTATUS(status: int) -> int {
|
||||||
|
status >> 8
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = os::waitpid(pid);
|
||||||
|
ret if WIFEXITED(status) {
|
||||||
|
WEXITSTATUS(status)
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
// fill-column: 78;
|
// fill-column: 78;
|
||||||
|
|
|
@ -26,7 +26,6 @@ export configure_test_task;
|
||||||
export joinable;
|
export joinable;
|
||||||
|
|
||||||
native "rust" mod rustrt {
|
native "rust" mod rustrt {
|
||||||
fn hack_allow_leaks();
|
|
||||||
fn sched_threads() -> uint;
|
fn sched_threads() -> uint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,12 +323,6 @@ fn configure_test_task() {
|
||||||
// If this task fails we don't want that failure to propagate to the
|
// If this task fails we don't want that failure to propagate to the
|
||||||
// test runner or else we couldn't keep running tests
|
// test runner or else we couldn't keep running tests
|
||||||
task::unsupervise();
|
task::unsupervise();
|
||||||
|
|
||||||
// FIXME (236): Hack supreme - unwinding doesn't work yet so if this
|
|
||||||
// task fails memory will not be freed correctly. This turns off the
|
|
||||||
// sanity checks in the runtime's memory region for the task, so that
|
|
||||||
// the test runner can continue.
|
|
||||||
rustrt::hack_allow_leaks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
|
|
|
@ -15,13 +15,13 @@ memory_region::alloc_header *memory_region::get_header(void *mem) {
|
||||||
memory_region::memory_region(rust_srv *srv, bool synchronized) :
|
memory_region::memory_region(rust_srv *srv, bool synchronized) :
|
||||||
_srv(srv), _parent(NULL), _live_allocations(0),
|
_srv(srv), _parent(NULL), _live_allocations(0),
|
||||||
_detailed_leaks(srv->env->detailed_leaks),
|
_detailed_leaks(srv->env->detailed_leaks),
|
||||||
_synchronized(synchronized), _hack_allow_leaks(false) {
|
_synchronized(synchronized) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region::memory_region(memory_region *parent) :
|
memory_region::memory_region(memory_region *parent) :
|
||||||
_srv(parent->_srv), _parent(parent), _live_allocations(0),
|
_srv(parent->_srv), _parent(parent), _live_allocations(0),
|
||||||
_detailed_leaks(parent->_detailed_leaks),
|
_detailed_leaks(parent->_detailed_leaks),
|
||||||
_synchronized(parent->_synchronized), _hack_allow_leaks(false) {
|
_synchronized(parent->_synchronized) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_region::add_alloc() {
|
void memory_region::add_alloc() {
|
||||||
|
@ -127,18 +127,13 @@ memory_region::~memory_region() {
|
||||||
assert(leak_count == _live_allocations);
|
assert(leak_count == _live_allocations);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!_hack_allow_leaks && _live_allocations > 0) {
|
if (_live_allocations > 0) {
|
||||||
_srv->fatal(msg, __FILE__, __LINE__,
|
_srv->fatal(msg, __FILE__, __LINE__,
|
||||||
"%d objects", _live_allocations);
|
"%d objects", _live_allocations);
|
||||||
}
|
}
|
||||||
if (_synchronized) { _lock.unlock(); }
|
if (_synchronized) { _lock.unlock(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
memory_region::hack_allow_leaks() {
|
|
||||||
_hack_allow_leaks = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
memory_region::release_alloc(void *mem) {
|
memory_region::release_alloc(void *mem) {
|
||||||
alloc_header *alloc = get_header(mem);
|
alloc_header *alloc = get_header(mem);
|
||||||
|
|
|
@ -32,7 +32,6 @@ private:
|
||||||
const bool _detailed_leaks;
|
const bool _detailed_leaks;
|
||||||
const bool _synchronized;
|
const bool _synchronized;
|
||||||
lock_and_signal _lock;
|
lock_and_signal _lock;
|
||||||
bool _hack_allow_leaks;
|
|
||||||
|
|
||||||
void add_alloc();
|
void add_alloc();
|
||||||
void dec_alloc();
|
void dec_alloc();
|
||||||
|
@ -46,10 +45,6 @@ public:
|
||||||
void *realloc(void *mem, size_t size);
|
void *realloc(void *mem, size_t size);
|
||||||
void free(void *mem);
|
void free(void *mem);
|
||||||
virtual ~memory_region();
|
virtual ~memory_region();
|
||||||
// FIXME (236: This is a temporary hack to allow failing tasks that leak
|
|
||||||
// to not kill the entire process, which the test runner needs. Please
|
|
||||||
// kill with prejudice once unwinding works.
|
|
||||||
void hack_allow_leaks();
|
|
||||||
|
|
||||||
void release_alloc(void *mem);
|
void release_alloc(void *mem);
|
||||||
void claim_alloc(void *mem);
|
void claim_alloc(void *mem);
|
||||||
|
|
|
@ -224,13 +224,6 @@ debug_opaque(rust_task *task, type_desc *t, uint8_t *front)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL void
|
|
||||||
hack_allow_leaks(rust_task *task)
|
|
||||||
{
|
|
||||||
LOG(task, stdlib, "hack_allow_leaks");
|
|
||||||
task->local_region.hack_allow_leaks();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct rust_box {
|
struct rust_box {
|
||||||
RUST_REFCOUNTED(rust_box)
|
RUST_REFCOUNTED(rust_box)
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,9 @@ static size_t const TIME_SLICE_IN_MS = 10;
|
||||||
|
|
||||||
static size_t const BUF_BYTES = 2048;
|
static size_t const BUF_BYTES = 2048;
|
||||||
|
|
||||||
|
// The error status to use when the process fails
|
||||||
|
#define PROC_FAIL_CODE 101;
|
||||||
|
|
||||||
// Every reference counted object should use this macro and initialize
|
// Every reference counted object should use this macro and initialize
|
||||||
// ref_count.
|
// ref_count.
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ rust_kernel::fail() {
|
||||||
// Runtime to terminate it in an unusual way" when trying to shutdown
|
// Runtime to terminate it in an unusual way" when trying to shutdown
|
||||||
// cleanly.
|
// cleanly.
|
||||||
#if defined(__WIN32__)
|
#if defined(__WIN32__)
|
||||||
exit(1);
|
exit(rval);
|
||||||
#endif
|
#endif
|
||||||
for(size_t i = 0; i < num_threads; ++i) {
|
for(size_t i = 0; i < num_threads; ++i) {
|
||||||
rust_scheduler *thread = threads[i];
|
rust_scheduler *thread = threads[i];
|
||||||
|
|
|
@ -71,7 +71,7 @@ rust_scheduler::fail() {
|
||||||
log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed",
|
log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed",
|
||||||
name, this);
|
name, this);
|
||||||
I(this, kernel->rval == 0);
|
I(this, kernel->rval == 0);
|
||||||
kernel->rval = 1;
|
kernel->rval = PROC_FAIL_CODE;
|
||||||
kernel->fail();
|
kernel->fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,18 +137,6 @@ struct rust_closure_env {
|
||||||
type_desc *td;
|
type_desc *td;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" CDECL
|
|
||||||
void task_exit(rust_closure_env *env, int rval, rust_task *task) {
|
|
||||||
LOG(task, task, "task exited with value %d", rval);
|
|
||||||
if(env) {
|
|
||||||
// free the environment.
|
|
||||||
I(task->sched, 1 == env->ref_count); // the ref count better be 1
|
|
||||||
//env->td->drop_glue(NULL, task, NULL, env->td->first_param, env);
|
|
||||||
//env->td->free_glue(NULL, task, NULL, env->td->first_param, env);
|
|
||||||
task->free(env);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" CDECL
|
extern "C" CDECL
|
||||||
void task_start_wrapper(spawn_args *a)
|
void task_start_wrapper(spawn_args *a)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "rust_gc.h"
|
#include "rust_gc.h"
|
||||||
#include "rust_internal.h"
|
#include "rust_internal.h"
|
||||||
#include "rust_upcall.h"
|
#include "rust_upcall.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unwind.h>
|
||||||
|
|
||||||
// Upcalls.
|
// Upcalls.
|
||||||
|
|
||||||
|
@ -190,6 +192,26 @@ upcall_dynastack_free(rust_task *task, void *ptr) {
|
||||||
return task->dynastack.free(ptr);
|
return task->dynastack.free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code
|
||||||
|
__gxx_personality_v0(int version,
|
||||||
|
_Unwind_Action actions,
|
||||||
|
uint64_t exception_class,
|
||||||
|
_Unwind_Exception *ue_header,
|
||||||
|
_Unwind_Context *context);
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code
|
||||||
|
upcall_rust_personality(int version,
|
||||||
|
_Unwind_Action actions,
|
||||||
|
uint64_t exception_class,
|
||||||
|
_Unwind_Exception *ue_header,
|
||||||
|
_Unwind_Context *context) {
|
||||||
|
return __gxx_personality_v0(version,
|
||||||
|
actions,
|
||||||
|
exception_class,
|
||||||
|
ue_header,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: C++
|
// mode: C++
|
||||||
|
|
|
@ -28,7 +28,6 @@ get_task_id
|
||||||
get_task_pointer
|
get_task_pointer
|
||||||
get_task_trampoline
|
get_task_trampoline
|
||||||
get_time
|
get_time
|
||||||
hack_allow_leaks
|
|
||||||
last_os_error
|
last_os_error
|
||||||
leak
|
leak
|
||||||
migrate_alloc
|
migrate_alloc
|
||||||
|
@ -78,5 +77,6 @@ upcall_vec_grow
|
||||||
upcall_vec_push
|
upcall_vec_push
|
||||||
upcall_log_type
|
upcall_log_type
|
||||||
upcall_malloc
|
upcall_malloc
|
||||||
|
upcall_rust_personality
|
||||||
upcall_shared_malloc
|
upcall_shared_malloc
|
||||||
upcall_shared_free
|
upcall_shared_free
|
||||||
|
|
|
@ -25,6 +25,7 @@ LLVMAddAttribute
|
||||||
LLVMAddBasicAliasAnalysisPass
|
LLVMAddBasicAliasAnalysisPass
|
||||||
LLVMAddCFGSimplificationPass
|
LLVMAddCFGSimplificationPass
|
||||||
LLVMAddCase
|
LLVMAddCase
|
||||||
|
LLVMAddClause
|
||||||
LLVMAddConstantMergePass
|
LLVMAddConstantMergePass
|
||||||
LLVMAddConstantPropagationPass
|
LLVMAddConstantPropagationPass
|
||||||
LLVMAddCorrelatedValuePropagationPass
|
LLVMAddCorrelatedValuePropagationPass
|
||||||
|
@ -122,6 +123,7 @@ LLVMBuildIntToPtr
|
||||||
LLVMBuildInvoke
|
LLVMBuildInvoke
|
||||||
LLVMBuildIsNotNull
|
LLVMBuildIsNotNull
|
||||||
LLVMBuildIsNull
|
LLVMBuildIsNull
|
||||||
|
LLVMBuildLandingPad
|
||||||
LLVMBuildLShr
|
LLVMBuildLShr
|
||||||
LLVMBuildLoad
|
LLVMBuildLoad
|
||||||
LLVMBuildMalloc
|
LLVMBuildMalloc
|
||||||
|
@ -141,6 +143,7 @@ LLVMBuildPhi
|
||||||
LLVMBuildPointerCast
|
LLVMBuildPointerCast
|
||||||
LLVMBuildPtrDiff
|
LLVMBuildPtrDiff
|
||||||
LLVMBuildPtrToInt
|
LLVMBuildPtrToInt
|
||||||
|
LLVMBuildResume
|
||||||
LLVMBuildRet
|
LLVMBuildRet
|
||||||
LLVMBuildRetVoid
|
LLVMBuildRetVoid
|
||||||
LLVMBuildSDiv
|
LLVMBuildSDiv
|
||||||
|
@ -548,6 +551,7 @@ LLVMRunPassManager
|
||||||
LLVMRunStaticConstructors
|
LLVMRunStaticConstructors
|
||||||
LLVMRunStaticDestructors
|
LLVMRunStaticDestructors
|
||||||
LLVMSetAlignment
|
LLVMSetAlignment
|
||||||
|
LLVMSetCleanup
|
||||||
LLVMSetCurrentDebugLocation
|
LLVMSetCurrentDebugLocation
|
||||||
LLVMSetDataLayout
|
LLVMSetDataLayout
|
||||||
LLVMSetFunctionCallConv
|
LLVMSetFunctionCallConv
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// xfail-test
|
||||||
// based on:
|
// based on:
|
||||||
// http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=java
|
// http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=java
|
||||||
|
|
||||||
|
|
|
@ -110,8 +110,9 @@ fn run_tests(config: config) {
|
||||||
let opts = test_opts(config);
|
let opts = test_opts(config);
|
||||||
let cx = {config: config, procsrv: procsrv::mk()};
|
let cx = {config: config, procsrv: procsrv::mk()};
|
||||||
let tests = make_tests(cx);
|
let tests = make_tests(cx);
|
||||||
test::run_tests_console_(opts, tests.tests, tests.to_task);
|
let res = test::run_tests_console_(opts, tests.tests, tests.to_task);
|
||||||
procsrv::close(cx.procsrv);
|
procsrv::close(cx.procsrv);
|
||||||
|
if !res { fail "Some tests failed"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_opts(config: config) -> test::test_opts {
|
fn test_opts(config: config) -> test::test_opts {
|
||||||
|
|
|
@ -16,10 +16,7 @@ type test_props = {
|
||||||
compile_flags: option::t<str>,
|
compile_flags: option::t<str>,
|
||||||
// If present, the name of a file that this test should match when
|
// If present, the name of a file that this test should match when
|
||||||
// pretty-printed
|
// pretty-printed
|
||||||
pp_exact: option::t<str>,
|
pp_exact: option::t<str>
|
||||||
// FIXME: no-valgrind is a temporary directive until all of run-fail
|
|
||||||
// is valgrind-clean
|
|
||||||
no_valgrind: bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load any test directives embedded in the file
|
// Load any test directives embedded in the file
|
||||||
|
@ -27,7 +24,6 @@ fn load_props(testfile: str) -> test_props {
|
||||||
let error_patterns = [];
|
let error_patterns = [];
|
||||||
let compile_flags = option::none;
|
let compile_flags = option::none;
|
||||||
let pp_exact = option::none;
|
let pp_exact = option::none;
|
||||||
let no_valgrind = false;
|
|
||||||
for each ln: str in iter_header(testfile) {
|
for each ln: str in iter_header(testfile) {
|
||||||
alt parse_error_pattern(ln) {
|
alt parse_error_pattern(ln) {
|
||||||
option::some(ep) { error_patterns += [ep]; }
|
option::some(ep) { error_patterns += [ep]; }
|
||||||
|
@ -41,16 +37,11 @@ fn load_props(testfile: str) -> test_props {
|
||||||
if option::is_none(pp_exact) {
|
if option::is_none(pp_exact) {
|
||||||
pp_exact = parse_pp_exact(ln, testfile);
|
pp_exact = parse_pp_exact(ln, testfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if no_valgrind == false {
|
|
||||||
no_valgrind = parse_name_directive(ln, "no-valgrind");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ret {
|
ret {
|
||||||
error_patterns: error_patterns,
|
error_patterns: error_patterns,
|
||||||
compile_flags: compile_flags,
|
compile_flags: compile_flags,
|
||||||
pp_exact: pp_exact,
|
pp_exact: pp_exact
|
||||||
no_valgrind: no_valgrind
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,11 +50,16 @@ fn is_test_ignored(config: config, testfile: str) -> bool {
|
||||||
for each ln: str in iter_header(testfile) {
|
for each ln: str in iter_header(testfile) {
|
||||||
// FIXME: Can't return or break from iterator
|
// FIXME: Can't return or break from iterator
|
||||||
found = found || parse_name_directive(ln, "xfail-test");
|
found = found || parse_name_directive(ln, "xfail-test");
|
||||||
|
found = found || parse_name_directive(ln, xfail_target());
|
||||||
if (config.mode == common::mode_pretty) {
|
if (config.mode == common::mode_pretty) {
|
||||||
found = found || parse_name_directive(ln, "xfail-pretty");
|
found = found || parse_name_directive(ln, "xfail-pretty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret found;
|
ret found;
|
||||||
|
|
||||||
|
fn xfail_target() -> str {
|
||||||
|
"xfail-" + std::os::target_os()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iter iter_header(testfile: str) -> str {
|
iter iter_header(testfile: str) -> str {
|
||||||
|
|
|
@ -66,7 +66,7 @@ fn run(handle: handle, lib_path: str, prog: str, args: [str],
|
||||||
writeclose(resp.infd, input);
|
writeclose(resp.infd, input);
|
||||||
let output = readclose(resp.outfd);
|
let output = readclose(resp.outfd);
|
||||||
let errput = readclose(resp.errfd);
|
let errput = readclose(resp.errfd);
|
||||||
let status = os::waitpid(resp.pid);
|
let status = run::waitpid(resp.pid);
|
||||||
ret {status: status, out: output, err: errput};
|
ret {status: status, out: output, err: errput};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,19 +51,21 @@ fn run_rfail_test(cx: cx, props: test_props, testfile: str) {
|
||||||
|
|
||||||
procres = exec_compiled_test(cx, props, testfile);
|
procres = exec_compiled_test(cx, props, testfile);
|
||||||
|
|
||||||
if procres.status == 0 {
|
// The value our Makefile configures valgrind to return on failure
|
||||||
fatal_procres("run-fail test didn't produce an error!", procres);
|
const valgrind_err: int = 100;
|
||||||
}
|
|
||||||
|
|
||||||
// This is the value valgrind returns on failure
|
|
||||||
// FIXME: Why is this value neither the value we pass to
|
|
||||||
// valgrind as --error-exitcode (1), nor the value we see as the
|
|
||||||
// exit code on the command-line (137)?
|
|
||||||
const valgrind_err: int = 9;
|
|
||||||
if procres.status == valgrind_err {
|
if procres.status == valgrind_err {
|
||||||
fatal_procres("run-fail test isn't valgrind-clean!", procres);
|
fatal_procres("run-fail test isn't valgrind-clean!", procres);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The value the rust runtime returns on failure
|
||||||
|
const rust_err: int = 101;
|
||||||
|
if procres.status != rust_err {
|
||||||
|
fatal_procres(
|
||||||
|
#fmt("run-fail test produced the wrong error code: %d",
|
||||||
|
procres.status),
|
||||||
|
procres);
|
||||||
|
}
|
||||||
|
|
||||||
check_error_patterns(props, testfile, procres);
|
check_error_patterns(props, testfile, procres);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,10 +253,9 @@ fn make_exe_name(config: config, testfile: str) -> str {
|
||||||
output_base_name(config, testfile) + os::exec_suffix()
|
output_base_name(config, testfile) + os::exec_suffix()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_run_args(config: config, props: test_props, testfile: str) ->
|
fn make_run_args(config: config, _props: test_props, testfile: str) ->
|
||||||
procargs {
|
procargs {
|
||||||
let toolargs =
|
let toolargs = {
|
||||||
if !props.no_valgrind {
|
|
||||||
// If we've got another tool to run under (valgrind),
|
// If we've got another tool to run under (valgrind),
|
||||||
// then split apart its command
|
// then split apart its command
|
||||||
let runtool =
|
let runtool =
|
||||||
|
@ -263,7 +264,7 @@ fn make_run_args(config: config, props: test_props, testfile: str) ->
|
||||||
option::none. { option::none }
|
option::none. { option::none }
|
||||||
};
|
};
|
||||||
split_maybe_args(runtool)
|
split_maybe_args(runtool)
|
||||||
} else { [] };
|
};
|
||||||
|
|
||||||
let args = toolargs + [make_exe_name(config, testfile)];
|
let args = toolargs + [make_exe_name(config, testfile)];
|
||||||
ret {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};
|
ret {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
// error-pattern:wooooo
|
// error-pattern:wooooo
|
||||||
// no-valgrind
|
|
||||||
fn main() { let a = 1; if 1 == 1 { a = 2; } fail "woooo" + "o"; }
|
fn main() { let a = 1; if 1 == 1 { a = 2; } fail "woooo" + "o"; }
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// error-pattern:meh
|
// error-pattern:meh
|
||||||
// no-valgrind
|
|
||||||
use std;
|
use std;
|
||||||
|
|
||||||
fn main() { let str_var: str = "meh"; fail #fmt["%s", str_var]; }
|
fn main() { let str_var: str = "meh"; fail #fmt["%s", str_var]; }
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// -*- rust -*-
|
// -*- rust -*-
|
||||||
|
|
||||||
// error-pattern:1 == 2
|
// error-pattern:1 == 2
|
||||||
// no-valgrind
|
// xfail-test
|
||||||
|
|
||||||
use std;
|
use std;
|
||||||
import std::task;
|
import std::task;
|
||||||
import std::comm::port;
|
import std::comm::port;
|
||||||
|
|
6
src/test/run-fail/unwind-assert.rs
Normal file
6
src/test/run-fail/unwind-assert.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = @0;
|
||||||
|
assert false;
|
||||||
|
}
|
10
src/test/run-fail/unwind-box.rs
Normal file
10
src/test/run-fail/unwind-box.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn failfn() {
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
@0;
|
||||||
|
failfn();
|
||||||
|
}
|
8
src/test/run-fail/unwind-check.rs
Normal file
8
src/test/run-fail/unwind-check.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
pure fn p(a: @int) -> bool { false }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = @0;
|
||||||
|
check p(a);
|
||||||
|
}
|
10
src/test/run-fail/unwind-closure.rs
Normal file
10
src/test/run-fail/unwind-closure.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn f(a: @int) {
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let g = bind f(@0);
|
||||||
|
g();
|
||||||
|
}
|
6
src/test/run-fail/unwind-fail.rs
Normal file
6
src/test/run-fail/unwind-fail.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
@0;
|
||||||
|
fail;
|
||||||
|
}
|
7
src/test/run-fail/unwind-initializer-indirect.rs
Normal file
7
src/test/run-fail/unwind-initializer-indirect.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn f() -> @int { fail; }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a: @int = f();
|
||||||
|
}
|
7
src/test/run-fail/unwind-initializer.rs
Normal file
7
src/test/run-fail/unwind-initializer.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a: @int = {
|
||||||
|
fail;
|
||||||
|
};
|
||||||
|
}
|
12
src/test/run-fail/unwind-iter.rs
Normal file
12
src/test/run-fail/unwind-iter.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
iter x() -> int {
|
||||||
|
fail;
|
||||||
|
put 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = @0;
|
||||||
|
for each x in x() {
|
||||||
|
}
|
||||||
|
}
|
12
src/test/run-fail/unwind-iter2.rs
Normal file
12
src/test/run-fail/unwind-iter2.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
iter x() -> int {
|
||||||
|
let a = @0;
|
||||||
|
put 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
for each x in x() {
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
}
|
16
src/test/run-fail/unwind-lambda.rs
Normal file
16
src/test/run-fail/unwind-lambda.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cheese = "roquefort";
|
||||||
|
let carrots = @"crunchy";
|
||||||
|
|
||||||
|
fn (tasties: @str, macerate: block(str)) {
|
||||||
|
macerate(*tasties);
|
||||||
|
} (carrots, { |food|
|
||||||
|
let mush = food + cheese;
|
||||||
|
lambda() {
|
||||||
|
let chew = mush + cheese;
|
||||||
|
fail "so yummy"
|
||||||
|
} ();
|
||||||
|
});
|
||||||
|
}
|
28
src/test/run-fail/unwind-misc-1.rs
Normal file
28
src/test/run-fail/unwind-misc-1.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
use std;
|
||||||
|
import std::map;
|
||||||
|
import std::uint;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let count = @mutable 0u;
|
||||||
|
let hash = bind fn (_s: [@str], count: @mutable uint) -> uint {
|
||||||
|
*count += 1u;
|
||||||
|
if *count == 10u {
|
||||||
|
fail;
|
||||||
|
} else {
|
||||||
|
ret *count;
|
||||||
|
}
|
||||||
|
} (_, count);
|
||||||
|
|
||||||
|
fn eq(s: [@str], t: [@str]) -> bool {
|
||||||
|
ret s == t;
|
||||||
|
}
|
||||||
|
|
||||||
|
let map = map::mk_hashmap(hash, eq);
|
||||||
|
let arr = [];
|
||||||
|
for each i in uint::range(0u, 10u) {
|
||||||
|
arr += [@"key stuff"];
|
||||||
|
map.insert(arr, arr + [@"value stuff"]);
|
||||||
|
}
|
||||||
|
}
|
11
src/test/run-fail/unwind-nested.rs
Normal file
11
src/test/run-fail/unwind-nested.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = @0;
|
||||||
|
{
|
||||||
|
let b = @0;
|
||||||
|
{
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/test/run-fail/unwind-resource-fail.rs
Normal file
12
src/test/run-fail/unwind-resource-fail.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
// xfail-test
|
||||||
|
|
||||||
|
resource r(i: int) {
|
||||||
|
// What happens when destructors throw?
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
@0;
|
||||||
|
let r <- r(0);
|
||||||
|
}
|
16
src/test/run-fail/unwind-stacked.rs
Normal file
16
src/test/run-fail/unwind-stacked.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
let a = @0;
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g() {
|
||||||
|
let b = @0;
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = @0;
|
||||||
|
g();
|
||||||
|
}
|
10
src/test/run-fail/unwind-uninitialized.rs
Normal file
10
src/test/run-fail/unwind-uninitialized.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// error-pattern:fail
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
f();
|
||||||
|
let a = @0;
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
// -*- rust -*-
|
// -*- rust -*-
|
||||||
|
|
||||||
// error-pattern:bounds check
|
// error-pattern:bounds check
|
||||||
// no-valgrind
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let v: [int] = [10];
|
let v: [int] = [10];
|
||||||
let x: int = 0;
|
let x: int = 0;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// -*- rust -*-
|
// -*- rust -*-
|
||||||
|
|
||||||
// error-pattern:bounds check
|
// error-pattern:bounds check
|
||||||
// no-valgrind
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let v: [int] = [10, 20];
|
let v: [int] = [10, 20];
|
||||||
let x: int = 0;
|
let x: int = 0;
|
||||||
|
|
10
src/test/run-pass/native-llvm.rs
Normal file
10
src/test/run-pass/native-llvm.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// xfail-test
|
||||||
|
|
||||||
|
native "llvm" mod llvm {
|
||||||
|
fn thesqrt(n: float) -> float = "sqrt.f64";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = llvm::thesqrt(4.0);
|
||||||
|
assert 1.9 < s && s < 2.1;
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
// xfail-win32
|
||||||
use std;
|
use std;
|
||||||
import std::comm;
|
import std::comm;
|
||||||
import std::task;
|
import std::task;
|
||||||
|
|
14
src/test/run-pass/unwind-box.rs
Normal file
14
src/test/run-pass/unwind-box.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// xfail-win32
|
||||||
|
use std;
|
||||||
|
import std::task;
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
task::unsupervise();
|
||||||
|
let a = @0;
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let g = f;
|
||||||
|
task::spawn(g);
|
||||||
|
}
|
21
src/test/run-pass/unwind-resource.rs
Normal file
21
src/test/run-pass/unwind-resource.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// xfail-win32
|
||||||
|
use std;
|
||||||
|
import std::task;
|
||||||
|
import std::comm;
|
||||||
|
|
||||||
|
resource complainer(c: comm::chan<bool>) {
|
||||||
|
comm::send(c, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(-c: comm::chan<bool>) {
|
||||||
|
task::unsupervise();
|
||||||
|
let c <- complainer(c);
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let p = comm::port();
|
||||||
|
let c = comm::chan(p);
|
||||||
|
task::spawn(bind f(c));
|
||||||
|
assert comm::recv(p);
|
||||||
|
}
|
18
src/test/run-pass/unwind-resource2.rs
Normal file
18
src/test/run-pass/unwind-resource2.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// xfail-win32
|
||||||
|
use std;
|
||||||
|
import std::task;
|
||||||
|
import std::comm;
|
||||||
|
|
||||||
|
resource complainer(c: @int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
task::unsupervise();
|
||||||
|
let c <- complainer(@0);
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let g = f;
|
||||||
|
task::spawn(g);
|
||||||
|
}
|
|
@ -65,3 +65,10 @@ fn test_pipes() {
|
||||||
ret buf;
|
ret buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn waitpid() {
|
||||||
|
let pid = run::spawn_process("false", [], 0, 0, 0);
|
||||||
|
let status = run::waitpid(pid);
|
||||||
|
assert status == 1;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue