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:
Brian Anderson 2011-09-12 09:36:51 -07:00
commit 393deeb06f
49 changed files with 491 additions and 106 deletions

View file

@ -114,7 +114,7 @@ ifdef CFG_UNIXY
endif
ifdef CFG_VALGRIND
CFG_VALGRIND += --leak-check=full \
--error-exitcode=1 \
--error-exitcode=100 \
--quiet --suppressions=$(CFG_SRC_DIR)src/etc/x86.supp
endif
endif

View file

@ -37,7 +37,8 @@ type upcalls =
log_type: ValueRef,
dynastack_mark: ValueRef,
dynastack_alloc: ValueRef,
dynastack_free: ValueRef};
dynastack_free: ValueRef,
rust_personality: ValueRef};
fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
@ -89,7 +90,9 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
dynastack_alloc:
d("dynastack_alloc_2", [T_size_t(), T_ptr(tydesc_type)],
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:

View file

@ -572,6 +572,9 @@ native "cdecl" mod llvm = "rustllvm" {
fn LLVMBuildInvoke(B: BuilderRef, Fn: ValueRef, Args: *ValueRef,
NumArgs: uint, Then: BasicBlockRef,
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;
/* Add a case to the switch instruction */
@ -580,6 +583,12 @@ native "cdecl" mod llvm = "rustllvm" {
/* Add a destination to the indirectbr instruction */
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 */
fn LLVMBuildAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf)
-> ValueRef;

View file

@ -3715,7 +3715,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
for the call itself is unreachable. */
let retval = C_nil();
if !is_terminated(bcx) {
FastCall(bcx, faddr, llargs);
bcx = invoke_fastcall(bcx, faddr, llargs).bcx;
alt lliterbody {
none. {
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);
}
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) ->
result {
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()));
V_filename = PointerCast(cx, V_filename, T_ptr(T_i8()));
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);
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];
}
}
FastCall(bcx, llcallee, llargs);
bcx = invoke_fastcall(bcx, llcallee, llargs).bcx;
bcx = trans_block_cleanups(bcx, cx);
let next_cx = new_sub_block_ctxt(in_cx, "next");
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.
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 {
some(init) {
@ -4405,35 +4468,38 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> result {
bcx.fcx.lllocals, false);
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 {
some(init) { might_not_init(init.expr) }
some(init) { might_not_init(ccx, init.expr) }
none. { true }
}
}
fn might_not_init(expr: @ast::expr) -> bool {
type env = @mutable bool;
let e = @mutable false;
// FIXME: Probably also need to account for expressions that
// fail but since we don't unwind yet, it doesn't seem to be a
// problem
fn might_not_init(ccx: @crate_ctxt, expr: @ast::expr) -> bool {
type env = {mutable mightnt: bool,
ccx: @crate_ctxt};
let e = {mutable mightnt: false,
ccx: ccx};
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 =
visit::mk_vt(@{visit_expr:
fn (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 }
_ { false }
};
if might_not_init {
*e = true;
} else { visit::visit_expr(ex, e, v); }
} with *visit::default_visitor()});
visit::mk_vt(@{visit_expr: visit_expr
with *visit::default_visitor()});
visitor.visit_expr(expr, e, visitor);
ret *e;
ret e.mightnt;
}
}

View file

@ -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 {
assert (!cx.terminated);
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:
// mode: rust

View file

@ -27,7 +27,8 @@ for t in os.listdir(run_pass):
f = codecs.open(os.path.join(run_pass, t), "r", "utf8")
s = f.read()
if not ("xfail-test" in s or
"xfail-fast" in s):
"xfail-fast" in s or
"xfail-win32" in s):
stage2_tests.append(t)
if "main(args: [str])" in s:
take_args[t] = True

View file

@ -6,6 +6,7 @@ export run_program;
export start_program;
export program_output;
export spawn_process;
export waitpid;
native "rust" mod rustrt {
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 {
ret os::waitpid(spawn_process(prog, args, 0, 0, 0));
ret waitpid(spawn_process(prog, args, 0, 0, 0));
}
type program =
@ -87,7 +88,7 @@ fn start_program(prog: str, args: [str]) -> @program_res {
if finished { ret 0; }
finished = true;
self.close_input();
ret os::waitpid(pid);
ret waitpid(pid);
}
fn destroy() {
self.finish();
@ -117,6 +118,44 @@ fn program_output(prog: str, args: [str]) ->
out: read_all(pr.output()),
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:
// mode: rust
// fill-column: 78;

View file

@ -26,7 +26,6 @@ export configure_test_task;
export joinable;
native "rust" mod rustrt {
fn hack_allow_leaks();
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
// test runner or else we couldn't keep running tests
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:

View file

@ -15,13 +15,13 @@ memory_region::alloc_header *memory_region::get_header(void *mem) {
memory_region::memory_region(rust_srv *srv, bool synchronized) :
_srv(srv), _parent(NULL), _live_allocations(0),
_detailed_leaks(srv->env->detailed_leaks),
_synchronized(synchronized), _hack_allow_leaks(false) {
_synchronized(synchronized) {
}
memory_region::memory_region(memory_region *parent) :
_srv(parent->_srv), _parent(parent), _live_allocations(0),
_detailed_leaks(parent->_detailed_leaks),
_synchronized(parent->_synchronized), _hack_allow_leaks(false) {
_synchronized(parent->_synchronized) {
}
void memory_region::add_alloc() {
@ -127,18 +127,13 @@ memory_region::~memory_region() {
assert(leak_count == _live_allocations);
}
#endif
if (!_hack_allow_leaks && _live_allocations > 0) {
if (_live_allocations > 0) {
_srv->fatal(msg, __FILE__, __LINE__,
"%d objects", _live_allocations);
}
if (_synchronized) { _lock.unlock(); }
}
void
memory_region::hack_allow_leaks() {
_hack_allow_leaks = true;
}
void
memory_region::release_alloc(void *mem) {
alloc_header *alloc = get_header(mem);

View file

@ -32,7 +32,6 @@ private:
const bool _detailed_leaks;
const bool _synchronized;
lock_and_signal _lock;
bool _hack_allow_leaks;
void add_alloc();
void dec_alloc();
@ -46,10 +45,6 @@ public:
void *realloc(void *mem, size_t size);
void free(void *mem);
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 claim_alloc(void *mem);

View file

@ -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 {
RUST_REFCOUNTED(rust_box)

View file

@ -99,6 +99,9 @@ static size_t const TIME_SLICE_IN_MS = 10;
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
// ref_count.

View file

@ -140,7 +140,7 @@ rust_kernel::fail() {
// Runtime to terminate it in an unusual way" when trying to shutdown
// cleanly.
#if defined(__WIN32__)
exit(1);
exit(rval);
#endif
for(size_t i = 0; i < num_threads; ++i) {
rust_scheduler *thread = threads[i];

View file

@ -71,7 +71,7 @@ rust_scheduler::fail() {
log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed",
name, this);
I(this, kernel->rval == 0);
kernel->rval = 1;
kernel->rval = PROC_FAIL_CODE;
kernel->fail();
}

View file

@ -137,18 +137,6 @@ struct rust_closure_env {
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
void task_start_wrapper(spawn_args *a)
{

View file

@ -1,6 +1,8 @@
#include "rust_gc.h"
#include "rust_internal.h"
#include "rust_upcall.h"
#include <stdint.h>
#include <unwind.h>
// Upcalls.
@ -190,6 +192,26 @@ upcall_dynastack_free(rust_task *task, void *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:
// mode: C++

View file

@ -28,7 +28,6 @@ get_task_id
get_task_pointer
get_task_trampoline
get_time
hack_allow_leaks
last_os_error
leak
migrate_alloc
@ -78,5 +77,6 @@ upcall_vec_grow
upcall_vec_push
upcall_log_type
upcall_malloc
upcall_rust_personality
upcall_shared_malloc
upcall_shared_free

View file

@ -25,6 +25,7 @@ LLVMAddAttribute
LLVMAddBasicAliasAnalysisPass
LLVMAddCFGSimplificationPass
LLVMAddCase
LLVMAddClause
LLVMAddConstantMergePass
LLVMAddConstantPropagationPass
LLVMAddCorrelatedValuePropagationPass
@ -122,6 +123,7 @@ LLVMBuildIntToPtr
LLVMBuildInvoke
LLVMBuildIsNotNull
LLVMBuildIsNull
LLVMBuildLandingPad
LLVMBuildLShr
LLVMBuildLoad
LLVMBuildMalloc
@ -141,6 +143,7 @@ LLVMBuildPhi
LLVMBuildPointerCast
LLVMBuildPtrDiff
LLVMBuildPtrToInt
LLVMBuildResume
LLVMBuildRet
LLVMBuildRetVoid
LLVMBuildSDiv
@ -548,6 +551,7 @@ LLVMRunPassManager
LLVMRunStaticConstructors
LLVMRunStaticDestructors
LLVMSetAlignment
LLVMSetCleanup
LLVMSetCurrentDebugLocation
LLVMSetDataLayout
LLVMSetFunctionCallConv

View file

@ -1,3 +1,4 @@
// xfail-test
// based on:
// http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=java

View file

@ -110,8 +110,9 @@ fn run_tests(config: config) {
let opts = test_opts(config);
let cx = {config: config, procsrv: procsrv::mk()};
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);
if !res { fail "Some tests failed"; }
}
fn test_opts(config: config) -> test::test_opts {

View file

@ -16,10 +16,7 @@ type test_props = {
compile_flags: option::t<str>,
// If present, the name of a file that this test should match when
// pretty-printed
pp_exact: option::t<str>,
// FIXME: no-valgrind is a temporary directive until all of run-fail
// is valgrind-clean
no_valgrind: bool
pp_exact: option::t<str>
};
// Load any test directives embedded in the file
@ -27,7 +24,6 @@ fn load_props(testfile: str) -> test_props {
let error_patterns = [];
let compile_flags = option::none;
let pp_exact = option::none;
let no_valgrind = false;
for each ln: str in iter_header(testfile) {
alt parse_error_pattern(ln) {
option::some(ep) { error_patterns += [ep]; }
@ -41,16 +37,11 @@ fn load_props(testfile: str) -> test_props {
if option::is_none(pp_exact) {
pp_exact = parse_pp_exact(ln, testfile);
}
if no_valgrind == false {
no_valgrind = parse_name_directive(ln, "no-valgrind");
}
}
ret {
error_patterns: error_patterns,
compile_flags: compile_flags,
pp_exact: pp_exact,
no_valgrind: no_valgrind
pp_exact: pp_exact
};
}
@ -59,11 +50,16 @@ fn is_test_ignored(config: config, testfile: str) -> bool {
for each ln: str in iter_header(testfile) {
// FIXME: Can't return or break from iterator
found = found || parse_name_directive(ln, "xfail-test");
found = found || parse_name_directive(ln, xfail_target());
if (config.mode == common::mode_pretty) {
found = found || parse_name_directive(ln, "xfail-pretty");
}
}
ret found;
fn xfail_target() -> str {
"xfail-" + std::os::target_os()
}
}
iter iter_header(testfile: str) -> str {

View file

@ -66,7 +66,7 @@ fn run(handle: handle, lib_path: str, prog: str, args: [str],
writeclose(resp.infd, input);
let output = readclose(resp.outfd);
let errput = readclose(resp.errfd);
let status = os::waitpid(resp.pid);
let status = run::waitpid(resp.pid);
ret {status: status, out: output, err: errput};
}

View file

@ -51,19 +51,21 @@ fn run_rfail_test(cx: cx, props: test_props, testfile: str) {
procres = exec_compiled_test(cx, props, testfile);
if procres.status == 0 {
fatal_procres("run-fail test didn't produce an error!", procres);
}
// 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;
// The value our Makefile configures valgrind to return on failure
const valgrind_err: int = 100;
if procres.status == valgrind_err {
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);
}
@ -251,10 +253,9 @@ fn make_exe_name(config: config, testfile: str) -> str {
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 {
let toolargs =
if !props.no_valgrind {
let toolargs = {
// If we've got another tool to run under (valgrind),
// then split apart its command
let runtool =
@ -263,7 +264,7 @@ fn make_run_args(config: config, props: test_props, testfile: str) ->
option::none. { option::none }
};
split_maybe_args(runtool)
} else { [] };
};
let args = toolargs + [make_exe_name(config, testfile)];
ret {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};

View file

@ -1,3 +1,2 @@
// error-pattern:wooooo
// no-valgrind
fn main() { let a = 1; if 1 == 1 { a = 2; } fail "woooo" + "o"; }

View file

@ -1,5 +1,4 @@
// error-pattern:meh
// no-valgrind
use std;
fn main() { let str_var: str = "meh"; fail #fmt["%s", str_var]; }

View file

@ -1,8 +1,7 @@
// -*- rust -*-
// error-pattern:1 == 2
// no-valgrind
// xfail-test
use std;
import std::task;
import std::comm::port;

View file

@ -0,0 +1,6 @@
// error-pattern:fail
fn main() {
let a = @0;
assert false;
}

View file

@ -0,0 +1,10 @@
// error-pattern:fail
fn failfn() {
fail;
}
fn main() {
@0;
failfn();
}

View file

@ -0,0 +1,8 @@
// error-pattern:fail
pure fn p(a: @int) -> bool { false }
fn main() {
let a = @0;
check p(a);
}

View file

@ -0,0 +1,10 @@
// error-pattern:fail
fn f(a: @int) {
fail;
}
fn main() {
let g = bind f(@0);
g();
}

View file

@ -0,0 +1,6 @@
// error-pattern:fail
fn main() {
@0;
fail;
}

View file

@ -0,0 +1,7 @@
// error-pattern:fail
fn f() -> @int { fail; }
fn main() {
let a: @int = f();
}

View file

@ -0,0 +1,7 @@
// error-pattern:fail
fn main() {
let a: @int = {
fail;
};
}

View file

@ -0,0 +1,12 @@
// error-pattern:fail
iter x() -> int {
fail;
put 0;
}
fn main() {
let a = @0;
for each x in x() {
}
}

View file

@ -0,0 +1,12 @@
// error-pattern:fail
iter x() -> int {
let a = @0;
put 1;
}
fn main() {
for each x in x() {
fail;
}
}

View 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"
} ();
});
}

View 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"]);
}
}

View file

@ -0,0 +1,11 @@
// error-pattern:fail
fn main() {
let a = @0;
{
let b = @0;
{
fail;
}
}
}

View 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);
}

View 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();
}

View file

@ -0,0 +1,10 @@
// error-pattern:fail
fn f() {
fail;
}
fn main() {
f();
let a = @0;
}

View file

@ -1,7 +1,6 @@
// -*- rust -*-
// error-pattern:bounds check
// no-valgrind
fn main() {
let v: [int] = [10];
let x: int = 0;

View file

@ -1,7 +1,6 @@
// -*- rust -*-
// error-pattern:bounds check
// no-valgrind
fn main() {
let v: [int] = [10, 20];
let x: int = 0;

View 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;
}

View file

@ -1,3 +1,4 @@
// xfail-win32
use std;
import std::comm;
import std::task;

View 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);
}

View 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);
}

View 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);
}

View file

@ -65,3 +65,10 @@ fn test_pipes() {
ret buf;
}
}
#[test]
fn waitpid() {
let pid = run::spawn_process("false", [], 0, 0, 0);
let status = run::waitpid(pid);
assert status == 1;
}