about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--RELEASES.txt145
-rw-r--r--doc/rust.md2
-rw-r--r--mk/llvm.mk2
-rw-r--r--mk/platform.mk8
-rw-r--r--mk/rt.mk3
-rw-r--r--src/compiletest/compiletest.rs53
-rw-r--r--src/etc/mingw-fix-include/README.txt6
-rw-r--r--src/etc/mingw-fix-include/bits/c++config.h8
-rw-r--r--src/etc/mingw-fix-include/winbase.h8
-rw-r--r--src/etc/mingw-fix-include/winsock2.h12
-rw-r--r--src/libextra/getopts.rs1017
-rw-r--r--src/libextra/glob.rs39
-rw-r--r--src/libextra/num/bigint.rs4
-rw-r--r--src/libextra/rl.rs21
-rw-r--r--src/libextra/test.rs22
-rw-r--r--src/librustc/back/link.rs2
-rw-r--r--src/librustc/driver/driver.rs65
-rw-r--r--src/librustc/front/test.rs116
-rw-r--r--src/librustc/middle/const_eval.rs5
-rw-r--r--src/librustc/middle/trans/base.rs32
-rw-r--r--src/librustc/middle/trans/context.rs2
-rw-r--r--src/librustc/rustc.rs28
-rw-r--r--src/librustdoc/config.rs10
-rw-r--r--src/librusti/program.rs2
-rw-r--r--src/librustpkg/api.rs57
-rw-r--r--src/librustpkg/exit_codes.rs (renamed from src/test/run-pass/cond-macro.rs)14
-rw-r--r--src/librustpkg/package_id.rs6
-rw-r--r--src/librustpkg/package_source.rs62
-rw-r--r--src/librustpkg/rustpkg.rs335
-rw-r--r--src/librustpkg/target.rs41
-rw-r--r--src/librustpkg/tests.rs135
-rw-r--r--src/librustpkg/util.rs58
-rw-r--r--src/librustpkg/workcache_support.rs5
-rw-r--r--src/libstd/borrow.rs16
-rw-r--r--src/libstd/c_str.rs4
-rw-r--r--src/libstd/char.rs24
-rw-r--r--src/libstd/libc.rs165
-rw-r--r--src/libstd/logging.rs11
-rw-r--r--src/libstd/num/f32.rs148
-rw-r--r--src/libstd/num/f64.rs148
-rw-r--r--src/libstd/num/float.rs174
-rw-r--r--src/libstd/num/uint_macros.rs10
-rw-r--r--src/libstd/option.rs20
-rw-r--r--src/libstd/os.rs14
-rw-r--r--src/libstd/ptr.rs87
-rw-r--r--src/libstd/rand.rs2
-rw-r--r--src/libstd/reflect_stage0.rs493
-rw-r--r--src/libstd/repr_stage0.rs626
-rw-r--r--src/libstd/rt/args.rs12
-rw-r--r--src/libstd/rt/io/buffered.rs4
-rw-r--r--src/libstd/rt/io/mod.rs17
-rw-r--r--src/libstd/rt/io/pipe.rs76
-rw-r--r--src/libstd/rt/io/process.rs278
-rw-r--r--src/libstd/rt/mod.rs12
-rw-r--r--src/libstd/rt/rtio.rs19
-rw-r--r--src/libstd/rt/task.rs11
-rw-r--r--src/libstd/rt/uv/mod.rs12
-rw-r--r--src/libstd/rt/uv/pipe.rs66
-rw-r--r--src/libstd/rt/uv/process.rs219
-rw-r--r--src/libstd/rt/uv/uvio.rs331
-rw-r--r--src/libstd/rt/uv/uvll.rs132
-rw-r--r--src/libstd/run.rs23
-rw-r--r--src/libstd/std.rs6
-rw-r--r--src/libstd/str.rs4
-rw-r--r--src/libstd/sys.rs9
-rw-r--r--src/libstd/unstable/intrinsics.rs101
-rw-r--r--src/libstd/unstable/sync.rs17
-rw-r--r--src/libsyntax/ast_util.rs4
-rw-r--r--src/libsyntax/diagnostic.rs2
-rw-r--r--src/libsyntax/ext/build.rs14
-rw-r--r--src/libsyntax/ext/deriving/default.rs8
-rw-r--r--src/libsyntax/ext/deriving/zero.rs8
-rw-r--r--src/libsyntax/ext/env.rs12
-rw-r--r--src/libsyntax/ext/expand.rs46
-rw-r--r--src/libsyntax/ext/format.rs1
-rw-r--r--src/libsyntax/parse/lexer.rs2
-rw-r--r--src/libsyntax/parse/token.rs3
-rw-r--r--src/libsyntax/print/pp.rs2
-rw-r--r--src/libsyntax/print/pprust.rs14
-rw-r--r--src/rt/rust_builtin.cpp23
-rw-r--r--src/rt/rust_run_program.cpp71
-rw-r--r--src/rt/rust_uv.cpp35
-rw-r--r--src/rt/rustrt.def.in8
-rw-r--r--src/rustdoc_ng/rustdoc_ng.rs11
-rw-r--r--src/snapshots.txt8
-rw-r--r--src/test/bench/shootout-pfib.rs2
-rw-r--r--src/test/pretty/path-type-bounds.rs13
-rw-r--r--src/test/run-pass/cond-macro-no-default.rs23
-rw-r--r--src/test/run-pass/extern-pass-TwoU64s-ref.rs1
-rw-r--r--src/test/run-pass/extern-pass-TwoU64s.rs1
-rw-r--r--src/test/run-pass/extern-return-TwoU64s.rs2
-rw-r--r--src/test/run-pass/getopts_ref.rs4
-rw-r--r--src/test/run-pass/ifmt.rs4
-rw-r--r--src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs2
-rw-r--r--src/test/run-pass/nul-characters.rs44
-rw-r--r--src/test/run-pass/struct-return.rs2
96 files changed, 2864 insertions, 3122 deletions
diff --git a/RELEASES.txt b/RELEASES.txt
index 33f749d0010..379f64cce1a 100644
--- a/RELEASES.txt
+++ b/RELEASES.txt
@@ -1,3 +1,148 @@
+Version 0.8 (October 2013)
+--------------------------
+
+   * ~2100 changes, numerous bugfixes
+
+   * Language
+      * The `for` loop syntax has changed to work with the `Iterator` trait.
+      * At long last, unwinding works on Windows.
+      * Default methods definitely mostly work.
+      * Many trait inheritance bugs fixed.
+      * Owned and borrowed trait objects work more reliably.
+      * `copy` is no longer a keyword. It has been replaced by the `Clone` trait.
+      * rustc no longer emits code for the `debug!` macro unless it is passed
+        `--cfg debug`
+      * mod.rs is now "blessed". When loading `mod foo;`, rustc will now look
+        for foo.rs, then foo/mod.rs, and will generate an error when both are
+        present.
+      * Strings no longer contain trailing nulls. The new `std::c_str` module
+        provides new mechanisms for converting to C strings.
+      * The type of foreign functions is now `extern "C" fn` instead of `*u8'.
+      * The FFI has been overhauled such that foreign functions are called directly,
+        instead of through a stack-switching wrapper.
+      * Calling a foreign function must be done through a Rust function with the
+        `#[fixed_stack_segment]` attribute.
+      * The `externfn!` macro can be used to declare both a foreign function and
+        a `#[fixed_stack_segment]` wrapper at once.
+      * `pub` and `priv` modifiers on `extern` blocks are no longer parsed.
+      * `unsafe` is no longer allowed on extern fns - they are all unsafe.
+      * `priv` is disallowed everywhere except for struct fields and enum variants.
+      * `&T` (besides `&'static T`) is no longer allowed in `@T`.
+      * `ref` bindings in irrefutable patterns work correctly now.
+      * `char` is now prevented from containing invalid code points.
+      * Casting to `bool` is no longer allowed.
+      * `yield` is a reserved keyword.
+      * `typeof` is a reserved keyword.
+      * Crates may be imported by URL with `extern mod foo = "url";`.
+      * Explicit enum discriminants may be given as uints as in `enum E { V = 0u }`
+      * Static vectors can be initialized with repeating elements,
+        e.g. `static foo: [u8, .. 100]: [0, .. 100];`.
+      * Static structs can be initialized with functional record update,
+        e.g. `static foo: Foo = Foo { a: 5, .. bar };`.
+      * `cfg!` can be used to conditionally execute code based on the crate
+        configuration, similarly to `#[cfg(...)]`.
+      * The `unnecessary_qualification` lint detects unneeded module
+        prefixes (default: allow).
+      * Arithmetic operations have been implemented on the SIMD types in
+        `std::unstable::simd`.
+      * Exchange allocation headers were removed, reducing memory usage.
+      * `format!` implements a completely new, extensible, and higher-performance
+        string formatting system. It will replace `fmt!`.
+      * `print!` and `println!` write formatted strings (using the `format!`
+        extension) to stdout.
+      * `write!` and `writeln!` write formatted strings (using the `format!`
+        extension) to the new Writers in `std::rt::io`.
+      * The library section in which a function or static is placed may
+        be specified with `#[link_section = "..."]`.
+      * The `proto!` syntax extension for defining bounded message protocols
+        was removed.
+      * `macro_rules!` is hygenic for `let` declarations.
+      * The `#[export_name]` attribute specifies the name of a symbol.
+      * `unreachable!` can be used to indicate unreachable code, and fails
+        if executed.
+
+   * Libraries
+      * std: Transitioned to the new runtime, written in Rust.
+      * std: Added an experimental I/O library, `rt::io`, based on the new
+        runtime.
+      * std: A new generic `range` function was added to the prelude, replacing
+        `uint::range` and friends.
+      * std: `range_rev` no longer exists. Since range is an iterator it can be
+        reversed with `range(lo, hi).invert()`.
+      * std: The `chain` method on option renamed to `and_then`; `unwrap_or_default`
+        renamed to `unwrap_or`.
+      * std: The `iterator` module was renamed to `iter`.
+      * std: Integral types now support the `checked_add`, `checked_sub`, and
+        `checked_mul` operations for detecting overflow.
+      * std: Many methods in `str`, `vec`, `option, `result` were renamed for
+        consistency.
+      * std: Methods are standardizing on conventions for casting methods:
+        `to_foo` for copying, `into_foo` for moving, `as_foo` for temporary
+        and cheap casts.
+      * std: The `CString` type in `c_str` provides new ways to convert to and
+        from C strings.
+      * std: `DoubleEndedIterator` can yield elements in two directions.
+      * std: The `mut_split` method on vectors partitions an `&mut [T]` into
+        two splices.
+      * std: `str::from_bytes` renamed to `str::from_utf8`.
+      * std: `pop_opt` and `shift_opt` methods added to vectors.
+      * std: The task-local data interface no longer uses @, and keys are
+        no longer function pointers.
+      * std: The `swap_unwrap` method of `Option` renamed to `take_unwrap`.
+      * std: Added `SharedPort` to `comm`.
+      * std: `Eq` has a default method for `ne`; only `eq` is required
+        in implementations.
+      * std: `Ord` has default methods for `le`, `gt` and `le`; only `lt`
+        is required in implementations.
+      * std: `is_utf8` performance is improved, impacting many string functions.
+      * std: `os::MemoryMap` provides cross-platform mmap.
+      * std: `ptr::offset` is now unsafe, but also more optimized. Offsets that
+        are not 'in-bounds' are considered undefined.
+      * std: Many freestanding functions in `vec` removed in favor of methods.
+      * std: Many freestanding functions on scalar types removed in favor of
+        methods.
+      * std: Many options to task builders were removed since they don't make
+        sense in the new scheduler design.
+      * std: More containers implement `FromIterator` so can be created by the
+        `collect` method.
+      * std: More complete atomic types in `unstable::atomics`.
+      * std: `comm::PortSet` removed.
+      * std: Mutating methods in the `Set` and `Map` traits have been moved into
+        the `MutableSet` and `MutableMap` traits. `Container::is_empty`,
+        `Map::contains_key`, `MutableMap::insert`, and `MutableMap::remove` have
+        default implementations.
+      * extra: `dlist`, the doubly-linked list was modernized.
+      * extra: Added a `hex` module with `ToHex` and `FromHex` traits.
+      * extra: Added `glob` module, replacing `std::os::glob`.
+      * extra: `rope` was removed.
+      * extra: `deque` was renamed to `ringbuf`. `RingBuf` implements `Deque`.
+      * extra: `net`, and `timer` were removed. The experimental replacements
+        are `std::rt::io::net` and `std::rt::io::timer`.
+      * extra: Iterators implemented for `SmallIntMap`.
+      * extra: Iterators implemented for `Bitv` and `BitvSet`.
+      * extra: `SmallIntSet` removed. Use `BitvSet`.
+      * extra: Performance of JSON parsing greatly improved.
+      * extra: `semver` updated to SemVer 2.0.0.
+      * extra: `term` handles more terminals correctly.
+      * extra: `dbg` module removed.
+
+   * Other
+      * rustc's debug info generation (`-Z debug-info`) is greatly improved.
+      * rustc accepts `--target-cpu` to compile to a specific CPU architecture,
+        similarly to gcc's `--march` flag.
+      * rustpkg has received many improvements.
+      * rustpkg supports git tags as package IDs.
+      * rustpkg builds into target-specific directories so it can be used for
+        cross-compiling.
+      * The number of concurrent test tasks is controlled by the environment
+        variable RUST_TEST_TASKS.
+      * The test harness can now report metrics for benchmarks.
+      * All tools have man pages.
+      * Programs compiled with `--test` now support the `-h` and `--help` flags.
+      * The runtime uses jemalloc for allocations.
+      * Segmented stacks are temporarily disabled as part of the transition to
+        the new runtime. Stack overflows are possible!
+
 Version 0.7 (July 2013)
 -----------------------
 
diff --git a/doc/rust.md b/doc/rust.md
index 9ebb3384c61..d10238c1483 100644
--- a/doc/rust.md
+++ b/doc/rust.md
@@ -248,7 +248,7 @@ string_body : non_double_quote
             | '\x5c' [ '\x22' | common_escape ] ;
 
 common_escape : '\x5c'
-              | 'n' | 'r' | 't'
+              | 'n' | 'r' | 't' | '0'
               | 'x' hex_digit 2
               | 'u' hex_digit 4
               | 'U' hex_digit 8 ;
diff --git a/mk/llvm.mk b/mk/llvm.mk
index 9e024ffa9f4..9de04bed598 100644
--- a/mk/llvm.mk
+++ b/mk/llvm.mk
@@ -28,7 +28,7 @@ LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
 
 $$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
 	@$$(call E, make: llvm)
-	$$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV)
+	$$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV_$(1))
 	$$(Q)touch $$(LLVM_CONFIG_$(1))
 endif
 
diff --git a/mk/platform.mk b/mk/platform.mk
index ac6cf3c5451..2956c6cd251 100644
--- a/mk/platform.mk
+++ b/mk/platform.mk
@@ -343,6 +343,7 @@ CFG_PATH_MUNGE_mips-unknown-linux-gnu := true
 CFG_LDPATH_mips-unknown-linux-gnu :=
 CFG_RUN_mips-unknown-linux-gnu=
 CFG_RUN_TARG_mips-unknown-linux-gnu=
+RUSTC_FLAGS_mips-unknown-linux-gnu := --linker=$(CXX_mips-unknown-linux-gnu) --target-cpu mips32r2 --target-feature +mips32r2,+o32
 
 # i686-pc-mingw32 configuration
 CC_i686-pc-mingw32=$(CC)
@@ -352,7 +353,7 @@ AR_i686-pc-mingw32=$(AR)
 CFG_LIB_NAME_i686-pc-mingw32=$(1).dll
 CFG_LIB_GLOB_i686-pc-mingw32=$(1)-*.dll
 CFG_LIB_DSYM_GLOB_i686-pc-mingw32=$(1)-*.dylib.dSYM
-CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -m32 -march=i686 -D_WIN32_WINNT=0x0600
+CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -m32 -march=i686 -D_WIN32_WINNT=0x0600 -I$(CFG_SRC_DIR)src/etc/mingw-fix-include
 CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti
 CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g -m32
 CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 :=
@@ -361,6 +362,7 @@ CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
 CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def
 CFG_INSTALL_NAME_i686-pc-mingw32 =
 CFG_LIBUV_LINK_FLAGS_i686-pc-mingw32 := -lWs2_32 -lpsapi -liphlpapi
+CFG_LLVM_BUILD_ENV_i686-pc-mingw32 := CPATH=$(CFG_SRC_DIR)src/etc/mingw-fix-include
 CFG_EXE_SUFFIX_i686-pc-mingw32 := .exe
 CFG_WINDOWSY_i686-pc-mingw32 := 1
 CFG_UNIXY_i686-pc-mingw32 :=
@@ -479,7 +481,7 @@ define CFG_MAKE_TOOLCHAIN
         $$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2)        \
         $$(call CFG_INSTALL_NAME_$(1),$$(4))
 
-  ifneq ($(HOST_$(1)),arm)
+  ifeq ($$(findstring $(HOST_$(1)),arm mips),)
 
   # We're using llvm-mc as our assembler because it supports
   # .cfi pseudo-ops on mac
@@ -491,7 +493,7 @@ define CFG_MAKE_TOOLCHAIN
                     -o=$$(1)
   else
 
-  # For the ARM crosses, use the toolchain assembler
+  # For the ARM and MIPS crosses, use the toolchain assembler
   # XXX: We should be able to use the LLVM assembler
   CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
 
diff --git a/mk/rt.mk b/mk/rt.mk
index 35ee42f9cb4..d1a4b2bc87a 100644
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -24,7 +24,7 @@
 # working under these assumptions).
 
 # Hack for passing flags into LIBUV, see below.
-LIBUV_FLAGS_i386 = -m32 -fPIC
+LIBUV_FLAGS_i386 = -m32 -fPIC -I$(S)src/etc/mingw-fix-include
 LIBUV_FLAGS_x86_64 = -m64 -fPIC
 ifeq ($(OSTYPE_$(1)), linux-androideabi)
 LIBUV_FLAGS_arm = -fPIC -DANDROID -std=gnu99
@@ -71,7 +71,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
               rt/sync/lock_and_signal.cpp \
               rt/sync/rust_thread.cpp \
               rt/rust_builtin.cpp \
-              rt/rust_run_program.cpp \
               rt/rust_rng.cpp \
               rt/rust_upcall.cpp \
               rt/rust_uv.cpp \
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs
index 166638bc359..93324007f98 100644
--- a/src/compiletest/compiletest.rs
+++ b/src/compiletest/compiletest.rs
@@ -17,7 +17,6 @@ extern mod extra;
 
 use std::os;
 use std::rt;
-use std::f64;
 
 use extra::getopts;
 use extra::getopts::groups::{optopt, optflag, reqopt};
@@ -92,10 +91,10 @@ pub fn parse_config(args: ~[~str]) -> config {
     let matches =
         &match getopts::groups::getopts(args_, groups) {
           Ok(m) => m,
-          Err(f) => fail!(getopts::fail_str(f))
+          Err(f) => fail!(f.to_err_msg())
         };
 
-    if getopts::opt_present(matches, "h") || getopts::opt_present(matches, "help") {
+    if matches.opt_present("h") || matches.opt_present("help") {
         let message = fmt!("Usage: %s [OPTIONS]  [TESTNAME...]", argv0);
         println(getopts::groups::usage(message, groups));
         println("");
@@ -103,53 +102,51 @@ pub fn parse_config(args: ~[~str]) -> config {
     }
 
     fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
-        Path(getopts::opt_str(m, nm))
+        Path(m.opt_str(nm).unwrap())
     }
 
     config {
-        compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
-        run_lib_path: getopts::opt_str(matches, "run-lib-path"),
+        compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
+        run_lib_path: matches.opt_str("run-lib-path").unwrap(),
         rustc_path: opt_path(matches, "rustc-path"),
-        clang_path: getopts::opt_maybe_str(matches, "clang-path").map_move(|s| Path(s)),
-        llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map_move(|s| Path(s)),
+        clang_path: matches.opt_str("clang-path").map_move(|s| Path(s)),
+        llvm_bin_path: matches.opt_str("llvm-bin-path").map_move(|s| Path(s)),
         src_base: opt_path(matches, "src-base"),
         build_base: opt_path(matches, "build-base"),
         aux_base: opt_path(matches, "aux-base"),
-        stage_id: getopts::opt_str(matches, "stage-id"),
-        mode: str_mode(getopts::opt_str(matches, "mode")),
-        run_ignored: getopts::opt_present(matches, "ignored"),
+        stage_id: matches.opt_str("stage-id").unwrap(),
+        mode: str_mode(matches.opt_str("mode").unwrap()),
+        run_ignored: matches.opt_present("ignored"),
         filter:
             if !matches.free.is_empty() {
                  Some(matches.free[0].clone())
             } else {
                 None
             },
-        logfile: getopts::opt_maybe_str(matches, "logfile").map_move(|s| Path(s)),
-        save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map_move(|s| Path(s)),
+        logfile: matches.opt_str("logfile").map_move(|s| Path(s)),
+        save_metrics: matches.opt_str("save-metrics").map_move(|s| Path(s)),
         ratchet_metrics:
-            getopts::opt_maybe_str(matches, "ratchet-metrics").map_move(|s| Path(s)),
+            matches.opt_str("ratchet-metrics").map_move(|s| Path(s)),
         ratchet_noise_percent:
-            getopts::opt_maybe_str(matches,
-                                   "ratchet-noise-percent").map_move(|s|
-                                                                     f64::from_str(s).unwrap()),
-        runtool: getopts::opt_maybe_str(matches, "runtool"),
-        rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
-        jit: getopts::opt_present(matches, "jit"),
-        target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
-        adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
+            matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
+        runtool: matches.opt_str("runtool"),
+        rustcflags: matches.opt_str("rustcflags"),
+        jit: matches.opt_present("jit"),
+        target: opt_str2(matches.opt_str("target")).to_str(),
+        adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
         adb_test_dir:
-            opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")).to_str(),
+            opt_str2(matches.opt_str("adb-test-dir")).to_str(),
         adb_device_status:
-            if (opt_str2(getopts::opt_maybe_str(matches, "target")) ==
+            if (opt_str2(matches.opt_str("target")) ==
                 ~"arm-linux-androideabi") {
-                if (opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
+                if (opt_str2(matches.opt_str("adb-test-dir")) !=
                     ~"(none)" &&
-                    opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
+                    opt_str2(matches.opt_str("adb-test-dir")) !=
                     ~"") { true }
                 else { false }
             } else { false },
-        test_shard: test::opt_shard(getopts::opt_maybe_str(matches, "test-shard")),
-        verbose: getopts::opt_present(matches, "verbose")
+        test_shard: test::opt_shard(matches.opt_str("test-shard")),
+        verbose: matches.opt_present("verbose")
     }
 }
 
diff --git a/src/etc/mingw-fix-include/README.txt b/src/etc/mingw-fix-include/README.txt
new file mode 100644
index 00000000000..876db17a248
--- /dev/null
+++ b/src/etc/mingw-fix-include/README.txt
@@ -0,0 +1,6 @@
+The purpose of these headers is to fix issues with mingw v4.0, as described in #9246.
+
+This works by adding this directory to GCC include search path before mingw system headers directories, 
+so we can intercept their inclusions and add missing definitions without having to modify files in mingw/include.
+
+Once mingw fixes all 3 issues mentioned in #9246, this directory and all references to it from rust/mk/* may be removed.
diff --git a/src/etc/mingw-fix-include/bits/c++config.h b/src/etc/mingw-fix-include/bits/c++config.h
new file mode 100644
index 00000000000..4520779e275
--- /dev/null
+++ b/src/etc/mingw-fix-include/bits/c++config.h
@@ -0,0 +1,8 @@
+#ifndef _FIX_CXXCONFIG_H
+#define _FIX_CXXCONFIG_H 1
+
+#define _GLIBCXX_HAVE_FENV_H 1
+
+#include_next <bits/c++config.h>
+
+#endif
diff --git a/src/etc/mingw-fix-include/winbase.h b/src/etc/mingw-fix-include/winbase.h
new file mode 100644
index 00000000000..3be26d1cb34
--- /dev/null
+++ b/src/etc/mingw-fix-include/winbase.h
@@ -0,0 +1,8 @@
+#ifndef _FIX_WINBASE_H
+#define _FIX_WINBASE_H 1
+
+#define NTDDK_VERSION NTDDI_VERSION
+
+#include_next <winbase.h>
+
+#endif
diff --git a/src/etc/mingw-fix-include/winsock2.h b/src/etc/mingw-fix-include/winsock2.h
new file mode 100644
index 00000000000..36b58dcd1ee
--- /dev/null
+++ b/src/etc/mingw-fix-include/winsock2.h
@@ -0,0 +1,12 @@
+#ifndef _FIX_WINSOCK2_H
+#define _FIX_WINSOCK2_H 1
+
+#include_next <winsock2.h>
+
+typedef struct pollfd {
+  SOCKET fd;
+  short  events;
+  short  revents;
+} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
+
+#endif
diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs
index a21d9dc605f..0116c5a1f66 100644
--- a/src/libextra/getopts.rs
+++ b/src/libextra/getopts.rs
@@ -8,93 +8,89 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/*!
- * Simple getopt alternative.
- *
- * Construct a vector of options, either by using reqopt, optopt, and optflag
- * or by building them from components yourself, and pass them to getopts,
- * along with a vector of actual arguments (not including argv[0]). You'll
- * either get a failure code back, or a match. You'll have to verify whether
- * the amount of 'free' arguments in the match is what you expect. Use opt_*
- * accessors to get argument values out of the matches object.
- *
- * Single-character options are expected to appear on the command line with a
- * single preceding dash; multiple-character options are expected to be
- * proceeded by two dashes. Options that expect an argument accept their
- * argument following either a space or an equals sign. Single-character
- * options don't require the space.
- *
- * # Example
- *
- * The following example shows simple command line parsing for an application
- * that requires an input file to be specified, accepts an optional output
- * file name following -o, and accepts both -h and --help as optional flags.
- *
- * ```
- *    extern mod extra;
- *    use extra::getopts::*;
- *    use std::os;
- *
- *    fn do_work(in: &str, out: Option<~str>) {
- *        println(in);
- *        println(match out {
- *            Some(x) => x,
- *            None => ~"No Output"
- *        });
- *    }
- *
- *    fn print_usage(program: &str, _opts: &[Opt]) {
- *        printfln!("Usage: %s [options]", program);
- *        println("-o\t\tOutput");
- *        println("-h --help\tUsage");
- *    }
- *
- *    fn main() {
- *        let args = os::args();
- *
- *        let program = args[0].clone();
- *
- *        let opts = ~[
- *            optopt("o"),
- *            optflag("h"),
- *            optflag("help")
- *        ];
- *        let matches = match getopts(args.tail(), opts) {
- *            Ok(m) => { m }
- *            Err(f) => { fail!(fail_str(f)) }
- *        };
- *        if opt_present(&matches, "h") || opt_present(&matches, "help") {
- *            print_usage(program, opts);
- *            return;
- *        }
- *        let output = opt_maybe_str(&matches, "o");
- *        let input: &str = if !matches.free.is_empty() {
- *            matches.free[0].clone()
- *        } else {
- *            print_usage(program, opts);
- *            return;
- *        };
- *        do_work(input, output);
- *    }
- * ```
- */
-
-#[allow(missing_doc)];
-
+//! Simple getopt alternative.
+//!
+//! Construct a vector of options, either by using reqopt, optopt, and optflag
+//! or by building them from components yourself, and pass them to getopts,
+//! along with a vector of actual arguments (not including argv[0]). You'll
+//! either get a failure code back, or a match. You'll have to verify whether
+//! the amount of 'free' arguments in the match is what you expect. Use opt_*
+//! accessors to get argument values out of the matches object.
+//!
+//! Single-character options are expected to appear on the command line with a
+//! single preceding dash; multiple-character options are expected to be
+//! proceeded by two dashes. Options that expect an argument accept their
+//! argument following either a space or an equals sign. Single-character
+//! options don't require the space.
+//!
+//! # Example
+//!
+//! The following example shows simple command line parsing for an application
+//! that requires an input file to be specified, accepts an optional output
+//! file name following -o, and accepts both -h and --help as optional flags.
+//!
+//! ```
+//! exter mod extra;
+//! use extra::getopts::*;
+//! use std::os;
+//!
+//! fn do_work(inp: &str, out: Option<~str>) {
+//!     println(inp);
+//!     println(match out {
+//!         Some(x) => x,
+//!         None => ~"No Output"
+//!     });
+//! }
+//!
+//! fn print_usage(program: &str, _opts: &[Opt]) {
+//!     printfln!("Usage: %s [options]", program);
+//!     println("-o\t\tOutput");
+//!     println("-h --help\tUsage");
+//! }
+//!
+//! fn main() {
+//!     let args = os::args();
+//!
+//!     let program = args[0].clone();
+//!
+//!     let opts = ~[
+//!         optopt("o"),
+//!         optflag("h"),
+//!         optflag("help")
+//!     ];
+//!     let matches = match getopts(args.tail(), opts) {
+//!         Ok(m) => { m }
+//!         Err(f) => { fail!(f.to_err_msg()) }
+//!     };
+//!     if matches.opt_present("h") || matches.opt_present("help") {
+//!         print_usage(program, opts);
+//!         return;
+//!     }
+//!     let output = matches.opt_str("o");
+//!     let input: &str = if !matches.free.is_empty() {
+//!         matches.free[0].clone()
+//!     } else {
+//!         print_usage(program, opts);
+//!         return;
+//!     };
+//!     do_work(input, output);
+//! }
+//! ```
 
 use std::cmp::Eq;
 use std::result::{Err, Ok};
 use std::result;
 use std::option::{Some, None};
-use std::str;
 use std::vec;
 
+/// Name of an option. Either a string or a single char.
 #[deriving(Clone, Eq)]
 pub enum Name {
     Long(~str),
     Short(char),
 }
 
+/// Describes whether an option has an argument.
 #[deriving(Clone, Eq)]
 pub enum HasArg {
     Yes,
@@ -102,6 +98,7 @@ pub enum HasArg {
     Maybe,
 }
 
+/// Describes how often an option may occur.
 #[deriving(Clone, Eq)]
 pub enum Occur {
     Req,
@@ -109,94 +106,189 @@ pub enum Occur {
     Multi,
 }
 
-/// A description of a possible option
+/// A description of a possible option.
 #[deriving(Clone, Eq)]
 pub struct Opt {
+    /// Name of the option
     name: Name,
+    /// Wheter it has an argument
     hasarg: HasArg,
+    /// How often it can occur
     occur: Occur,
+    /// Which options it aliases
     aliases: ~[Opt],
 }
 
-fn mkname(nm: &str) -> Name {
-  if nm.len() == 1u {
-      Short(nm.char_at(0u))
-  } else {
-      Long(nm.to_owned())
-  }
+/// Describes wether an option is given at all or has a value.
+#[deriving(Clone, Eq)]
+enum Optval {
+    Val(~str),
+    Given,
 }
 
-/// Create an option that is required and takes an argument
-pub fn reqopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]};
+/// The result of checking command line arguments. Contains a vector
+/// of matches and a vector of free strings.
+#[deriving(Clone, Eq)]
+pub struct Matches {
+    /// Options that matched
+    opts: ~[Opt],
+    /// Values of the Options that matched
+    vals: ~[~[Optval]],
+    /// Free string fragments
+    free: ~[~str]
 }
 
-/// Create an option that is optional and takes an argument
-pub fn optopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]};
+/// The type returned when the command line does not conform to the
+/// expected format. Pass this value to <fail_str> to get an error message.
+#[deriving(Clone, Eq, ToStr)]
+pub enum Fail_ {
+    ArgumentMissing(~str),
+    UnrecognizedOption(~str),
+    OptionMissing(~str),
+    OptionDuplicated(~str),
+    UnexpectedArgument(~str),
 }
 
-/// Create an option that is optional and does not take an argument
-pub fn optflag(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]};
+/// The type of failure that occured.
+#[deriving(Eq)]
+pub enum FailType {
+    ArgumentMissing_,
+    UnrecognizedOption_,
+    OptionMissing_,
+    OptionDuplicated_,
+    UnexpectedArgument_,
 }
 
-/** Create an option that is optional, does not take an argument,
-  * and may occur multiple times.
-  */
-pub fn optflagmulti(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]};
-}
+/// The result of parsing a command line with a set of options.
+pub type Result = result::Result<Matches, Fail_>;
 
-/// Create an option that is optional and takes an optional argument
-pub fn optflagopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]};
-}
+impl Name {
+    fn from_str(nm: &str) -> Name {
+        if nm.len() == 1u {
+            Short(nm.char_at(0u))
+        } else {
+            Long(nm.to_owned())
+        }
+    }
 
-/**
- * Create an option that is optional, takes an argument, and may occur
- * multiple times
- */
-pub fn optmulti(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]};
+    fn to_str(&self) -> ~str {
+        match *self {
+            Short(ch) => ch.to_str(),
+            Long(ref s) => s.to_owned()
+        }
+    }
 }
 
-#[deriving(Clone, Eq)]
-enum Optval {
-    Val(~str),
-    Given,
-}
+impl Matches {
+    /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
+    /// No idea what this does.
+    pub fn opt_vals(&self, nm: &str) -> ~[Optval] {
+        match find_opt(self.opts, Name::from_str(nm)) {
+            Some(id) => self.vals[id].clone(),
+            None => fail!("No option '%s' defined", nm)
+        }
+    }
 
-/**
- * The result of checking command line arguments. Contains a vector
- * of matches and a vector of free strings.
- */
-#[deriving(Clone, Eq)]
-pub struct Matches {
-    opts: ~[Opt],
-    vals: ~[~[Optval]],
-    free: ~[~str]
-}
+    /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
+    /// No idea what this does.
+    pub fn opt_val(&self, nm: &str) -> Option<Optval> {
+        let vals = self.opt_vals(nm);
+        if (vals.is_empty()) {
+            None
+        } else {
+            Some(vals[0].clone())
+        }
+    }
+
+    /// Returns true if an option was matched.
+    pub fn opt_present(&self, nm: &str) -> bool {
+        !self.opt_vals(nm).is_empty()
+    }
+
+    /// Returns the number of times an option was matched.
+    pub fn opt_count(&self, nm: &str) -> uint {
+        self.opt_vals(nm).len()
+    }
+
+    /// Returns true if any of several options were matched.
+    pub fn opts_present(&self, names: &[~str]) -> bool {
+        for nm in names.iter() {
+            match find_opt(self.opts, Name::from_str(*nm)) {
+                Some(id) if !self.vals[id].is_empty() => return true,
+                _ => (),
+            };
+        }
+        false
+    }
+
+    /// Returns the string argument supplied to one of several matching options or `None`.
+    pub fn opts_str(&self, names: &[~str]) -> Option<~str> {
+        for nm in names.iter() {
+            match self.opt_val(*nm) {
+                Some(Val(ref s)) => return Some(s.clone()),
+                _ => ()
+            }
+        }
+        None
+    }
+
+    /// Returns a vector of the arguments provided to all matches of the given
+    /// option.
+    ///
+    /// Used when an option accepts multiple values.
+    pub fn opt_strs(&self, nm: &str) -> ~[~str] {
+        let mut acc: ~[~str] = ~[];
+        let r = self.opt_vals(nm);
+        for v in r.iter() {
+            match *v {
+                Val(ref s) => acc.push((*s).clone()),
+                _ => ()
+            }
+        }
+        acc
+    }
+
+    /// Returns the string argument supplied to a matching option or `None`.
+    pub fn opt_str(&self, nm: &str) -> Option<~str> {
+        let vals = self.opt_vals(nm);
+        if vals.is_empty() {
+            return None::<~str>;
+        }
+        match vals[0] {
+            Val(ref s) => Some((*s).clone()),
+            _ => None
+        }
+    }
+
+
+    /// Returns the matching string, a default, or none.
+    ///
+    /// Returns none if the option was not present, `def` if the option was
+    /// present but no argument was provided, and the argument if the option was
+    /// present and an argument was provided.
+    pub fn opt_default(&self, nm: &str, def: &str) -> Option<~str> {
+        let vals = self.opt_vals(nm);
+        if vals.is_empty() { return None; }
+        match vals[0] {
+            Val(ref s) => Some((*s).clone()),
+            _ => Some(def.to_owned())
+        }
+    }
 
-fn is_arg(arg: &str) -> bool {
-    return arg.len() > 1 && arg[0] == '-' as u8;
 }
 
-fn name_str(nm: &Name) -> ~str {
-    return match *nm {
-      Short(ch) => str::from_char(ch),
-      Long(ref s) => (*s).clone()
-    };
+fn is_arg(arg: &str) -> bool {
+    arg.len() > 1 && arg[0] == '-' as u8
 }
 
 fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
-    // search main options
+    // Search main options.
     let pos = opts.iter().position(|opt| opt.name == nm);
     if pos.is_some() {
         return pos
     }
 
-    // search in aliases
+    // Search in aliases.
     for candidate in opts.iter() {
         if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
             return opts.iter().position(|opt| opt.name == candidate.name);
@@ -206,56 +298,101 @@ fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
     None
 }
 
-/**
- * The type returned when the command line does not conform to the
- * expected format. Pass this value to <fail_str> to get an error message.
- */
-#[deriving(Clone, Eq, ToStr)]
-pub enum Fail_ {
-    ArgumentMissing(~str),
-    UnrecognizedOption(~str),
-    OptionMissing(~str),
-    OptionDuplicated(~str),
-    UnexpectedArgument(~str),
+/// Create an option that is required and takes an argument.
+pub fn reqopt(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Yes,
+        occur: Req,
+        aliases: ~[]
+    }
 }
 
-/// Convert a `fail_` enum into an error string
-pub fn fail_str(f: Fail_) -> ~str {
-    return match f {
-        ArgumentMissing(ref nm) => {
-            fmt!("Argument to option '%s' missing.", *nm)
-        }
-        UnrecognizedOption(ref nm) => {
-            fmt!("Unrecognized option: '%s'.", *nm)
-        }
-        OptionMissing(ref nm) => {
-            fmt!("Required option '%s' missing.", *nm)
-        }
-        OptionDuplicated(ref nm) => {
-            fmt!("Option '%s' given more than once.", *nm)
-        }
-        UnexpectedArgument(ref nm) => {
-            fmt!("Option '%s' does not take an argument.", *nm)
-        }
-    };
+/// Create an option that is optional and takes an argument.
+pub fn optopt(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Yes,
+        occur: Optional,
+        aliases: ~[]
+    }
 }
 
-/**
- * The result of parsing a command line with a set of options
- * (result::t<Matches, Fail_>)
- */
-pub type Result = result::Result<Matches, Fail_>;
+/// Create an option that is optional and does not take an argument.
+pub fn optflag(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: No,
+        occur: Optional,
+        aliases: ~[]
+    }
+}
+
+/// Create an option that is optional, does not take an argument,
+/// and may occur multiple times.
+pub fn optflagmulti(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: No,
+        occur: Multi,
+        aliases: ~[]
+    }
+}
+
+/// Create an option that is optional and takes an optional argument.
+pub fn optflagopt(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Maybe,
+        occur: Optional,
+        aliases: ~[]
+    }
+}
+
+/// Create an option that is optional, takes an argument, and may occur
+/// multiple times.
+pub fn optmulti(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Yes,
+        occur: Multi,
+        aliases: ~[]
+    }
+}
 
-/**
- * Parse command line arguments according to the provided options
- *
- * On success returns `ok(Opt)`. Use functions such as `opt_present`
- * `opt_str`, etc. to interrogate results.  Returns `err(Fail_)` on failure.
- * Use <fail_str> to get an error message.
- */
+impl Fail_ {
+    /// Convert a `Fail_` enum into an error string.
+    pub fn to_err_msg(self) -> ~str {
+        match self {
+            ArgumentMissing(ref nm) => {
+                fmt!("Argument to option '%s' missing.", *nm)
+            }
+            UnrecognizedOption(ref nm) => {
+                fmt!("Unrecognized option: '%s'.", *nm)
+            }
+            OptionMissing(ref nm) => {
+                fmt!("Required option '%s' missing.", *nm)
+            }
+            OptionDuplicated(ref nm) => {
+                fmt!("Option '%s' given more than once.", *nm)
+            }
+            UnexpectedArgument(ref nm) => {
+                fmt!("Option '%s' does not take an argument.", *nm)
+            }
+        }
+    }
+}
+
+/// Parse command line arguments according to the provided options.
+///
+/// On success returns `Ok(Opt)`. Use methods such as `opt_present`
+/// `opt_str`, etc. to interrogate results.  Returns `Err(Fail_)` on failure.
+/// Use `to_err_msg` to get an error message.
 pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
     let n_opts = opts.len();
+
     fn f(_x: uint) -> ~[Optval] { return ~[]; }
+
     let mut vals = vec::from_fn(n_opts, f);
     let mut free: ~[~str] = ~[];
     let l = args.len();
@@ -325,12 +462,12 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
                 name_pos += 1;
                 let optid = match find_opt(opts, (*nm).clone()) {
                   Some(id) => id,
-                  None => return Err(UnrecognizedOption(name_str(nm)))
+                  None => return Err(UnrecognizedOption(nm.to_str()))
                 };
                 match opts[optid].hasarg {
                   No => {
                     if !i_arg.is_none() {
-                        return Err(UnexpectedArgument(name_str(nm)));
+                        return Err(UnexpectedArgument(nm.to_str()));
                     }
                     vals[optid].push(Given);
                   }
@@ -346,7 +483,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
                     if !i_arg.is_none() {
                         vals[optid].push(Val(i_arg.clone().unwrap()));
                     } else if i + 1 == l {
-                        return Err(ArgumentMissing(name_str(nm)));
+                        return Err(ArgumentMissing(nm.to_str()));
                     } else { i += 1; vals[optid].push(Val(args[i].clone())); }
                   }
                 }
@@ -360,289 +497,183 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
         let occ = opts[i].occur;
         if occ == Req {
             if n == 0 {
-                return Err(OptionMissing(name_str(&(opts[i].name))));
+                return Err(OptionMissing(opts[i].name.to_str()));
             }
         }
         if occ != Multi {
             if n > 1 {
-                return Err(OptionDuplicated(name_str(&(opts[i].name))));
+                return Err(OptionDuplicated(opts[i].name.to_str()));
             }
         }
         i += 1;
     }
-    return Ok(Matches {opts: opts.to_owned(),
-               vals: vals,
-               free: free});
-}
-
-fn opt_vals(mm: &Matches, nm: &str) -> ~[Optval] {
-    return match find_opt(mm.opts, mkname(nm)) {
-      Some(id) => mm.vals[id].clone(),
-      None => {
-        error!("No option '%s' defined", nm);
-        fail!()
-      }
-    };
-}
-
-fn opt_val(mm: &Matches, nm: &str) -> Option<Optval> {
-    let vals = opt_vals(mm, nm);
-    if (vals.is_empty()) {
-        None
-    } else {
-        Some(opt_vals(mm, nm)[0].clone())
-    }
-}
-
-/// Returns true if an option was matched
-pub fn opt_present(mm: &Matches, nm: &str) -> bool {
-    !opt_vals(mm, nm).is_empty()
-}
-
-/// Returns the number of times an option was matched
-pub fn opt_count(mm: &Matches, nm: &str) -> uint {
-    opt_vals(mm, nm).len()
-}
-
-/// Returns true if any of several options were matched
-pub fn opts_present(mm: &Matches, names: &[~str]) -> bool {
-    for nm in names.iter() {
-        match find_opt(mm.opts, mkname(*nm)) {
-            Some(id) if !mm.vals[id].is_empty() => return true,
-            _ => (),
-        };
-    }
-    false
-}
-
-
-/**
- * Returns the string argument supplied to a matching option
- *
- * Fails if the option was not matched or if the match did not take an
- * argument
- */
-pub fn opt_str(mm: &Matches, nm: &str) -> ~str {
-    return match opt_val(mm, nm) {
-        Some(Val(s)) => s,
-        _ => fail!()
-    };
-}
-
-/**
- * Returns the string argument supplied to one of several matching options
- *
- * Fails if the no option was provided from the given list, or if the no such
- * option took an argument
- */
-pub fn opts_str(mm: &Matches, names: &[~str]) -> ~str {
-    for nm in names.iter() {
-        match opt_val(mm, *nm) {
-          Some(Val(ref s)) => return (*s).clone(),
-          _ => ()
-        }
-    }
-    fail!();
+    Ok(Matches {
+        opts: opts.to_owned(),
+        vals: vals,
+        free: free
+    })
 }
 
-
-/**
- * Returns a vector of the arguments provided to all matches of the given
- * option.
- *
- * Used when an option accepts multiple values.
- */
-pub fn opt_strs(mm: &Matches, nm: &str) -> ~[~str] {
-    let mut acc: ~[~str] = ~[];
-    let r = opt_vals(mm, nm);
-    for v in r.iter() {
-        match *v { Val(ref s) => acc.push((*s).clone()), _ => () }
-    }
-    acc
-}
-
-/// Returns the string argument supplied to a matching option or none
-pub fn opt_maybe_str(mm: &Matches, nm: &str) -> Option<~str> {
-    let vals = opt_vals(mm, nm);
-    if vals.is_empty() { return None::<~str>; }
-    return match vals[0] {
-        Val(ref s) => Some((*s).clone()),
-        _ => None
-    };
-}
-
-
-/**
- * Returns the matching string, a default, or none
- *
- * Returns none if the option was not present, `def` if the option was
- * present but no argument was provided, and the argument if the option was
- * present and an argument was provided.
- */
-pub fn opt_default(mm: &Matches, nm: &str, def: &str) -> Option<~str> {
-    let vals = opt_vals(mm, nm);
-    if vals.is_empty() { return None::<~str>; }
-    return match vals[0] { Val(ref s) => Some::<~str>((*s).clone()),
-                           _      => Some::<~str>(def.to_owned()) }
-}
-
-#[deriving(Eq)]
-pub enum FailType {
-    ArgumentMissing_,
-    UnrecognizedOption_,
-    OptionMissing_,
-    OptionDuplicated_,
-    UnexpectedArgument_,
-}
-
-/** A module which provides a way to specify descriptions and
- *  groups of short and long option names, together.
- */
+/// A module which provides a way to specify descriptions and
+/// groups of short and long option names, together.
 pub mod groups {
     use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
     use getopts::{Short, Yes};
 
-    /** one group of options, e.g., both -h and --help, along with
-     * their shared description and properties
-     */
+    /// One group of options, e.g., both -h and --help, along with
+    /// their shared description and properties.
     #[deriving(Clone, Eq)]
     pub struct OptGroup {
+        /// Short Name of the `OptGroup`
         short_name: ~str,
+        /// Long Name of the `OptGroup`
         long_name: ~str,
+        /// Hint
         hint: ~str,
+        /// Description
         desc: ~str,
+        /// Whether it has an argument
         hasarg: HasArg,
+        /// How often it can occur
         occur: Occur
     }
 
-    /// Create a long option that is required and takes an argument
-    pub fn reqopt(short_name: &str, long_name: &str,
-                  desc: &str, hint: &str) -> OptGroup {
+    impl OptGroup {
+        /// Translate OptGroup into Opt.
+        /// (Both short and long names correspond to different Opts).
+        pub fn long_to_short(&self) -> Opt {
+            let OptGroup {
+                short_name: short_name,
+                long_name: long_name,
+                hasarg: hasarg,
+                occur: occur,
+                _
+            } = (*self).clone();
+
+            match (short_name.len(), long_name.len()) {
+                (0,0) => fail!("this long-format option was given no name"),
+                (0,_) => Opt {
+                    name: Long((long_name)),
+                    hasarg: hasarg,
+                    occur: occur,
+                    aliases: ~[]
+                },
+                (1,0) => Opt {
+                    name: Short(short_name.char_at(0)),
+                    hasarg: hasarg,
+                    occur: occur,
+                    aliases: ~[]
+                },
+                (1,_) => Opt {
+                    name: Long((long_name)),
+                    hasarg: hasarg,
+                    occur:  occur,
+                    aliases: ~[
+                        Opt {
+                            name: Short(short_name.char_at(0)),
+                            hasarg: hasarg,
+                            occur:  occur,
+                            aliases: ~[]
+                        }
+                    ]
+                },
+                (_,_) => fail!("something is wrong with the long-form opt")
+            }
+        }
+    }
+
+    /// Create a long option that is required and takes an argument.
+    pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup { short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Yes,
-                occur: Req};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Yes,
+            occur: Req
+        }
     }
 
-    /// Create a long option that is optional and takes an argument
-    pub fn optopt(short_name: &str, long_name: &str,
-                  desc: &str, hint: &str) -> OptGroup {
+    /// Create a long option that is optional and takes an argument.
+    pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Yes,
-                occur: Optional};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Yes,
+            occur: Optional
+        }
     }
 
-    /// Create a long option that is optional and does not take an argument
-    pub fn optflag(short_name: &str, long_name: &str,
-                   desc: &str) -> OptGroup {
+    /// Create a long option that is optional and does not take an argument.
+    pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: ~"",
-                desc: desc.to_owned(),
-                hasarg: No,
-                occur: Optional};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: ~"",
+            desc: desc.to_owned(),
+            hasarg: No,
+            occur: Optional
+        }
     }
 
     /// Create a long option that can occur more than once and does not
-    /// take an argument
-    pub fn optflagmulti(short_name: &str, long_name: &str,
-                   desc: &str) -> OptGroup {
+    /// take an argument.
+    pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: ~"",
-                desc: desc.to_owned(),
-                hasarg: No,
-                occur: Multi};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: ~"",
+            desc: desc.to_owned(),
+            hasarg: No,
+            occur: Multi
+        }
     }
 
-    /// Create a long option that is optional and takes an optional argument
-    pub fn optflagopt(short_name: &str, long_name: &str,
-                      desc: &str, hint: &str) -> OptGroup {
+    /// Create a long option that is optional and takes an optional argument.
+    pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Maybe,
-                occur: Optional};
-    }
-
-    /**
-     * Create a long option that is optional, takes an argument, and may occur
-     * multiple times
-     */
-    pub fn optmulti(short_name: &str, long_name: &str,
-                    desc: &str, hint: &str) -> OptGroup {
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Maybe,
+            occur: Optional
+        }
+    }
+
+    /// Create a long option that is optional, takes an argument, and may occur
+    /// multiple times.
+    pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Yes,
-                occur: Multi};
-    }
-
-    // translate OptGroup into Opt
-    // (both short and long names correspond to different Opts)
-    pub fn long_to_short(lopt: &OptGroup) -> Opt {
-        let OptGroup{short_name: short_name,
-                     long_name: long_name,
-                     hasarg: hasarg,
-                     occur: occur,
-                     _} = (*lopt).clone();
-
-        match (short_name.len(), long_name.len()) {
-            (0,0) => fail!("this long-format option was given no name"),
-
-            (0,_) => Opt {name: Long((long_name)),
-                          hasarg: hasarg,
-                          occur: occur,
-                          aliases: ~[]},
-
-            (1,0) => Opt {name: Short(short_name.char_at(0)),
-                          hasarg: hasarg,
-                          occur: occur,
-                          aliases: ~[]},
-
-            (1,_) => Opt {name: Long((long_name)),
-                          hasarg: hasarg,
-                          occur:  occur,
-                          aliases: ~[Opt {
-                              name: Short(short_name.char_at(0)),
-                              hasarg: hasarg,
-                              occur:  occur,
-                              aliases: ~[]
-                          }]},
-
-            (_,_) => fail!("something is wrong with the long-form opt")
-        }
-    }
-
-    /*
-     * Parse command line args with the provided long format options
-     */
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Yes,
+            occur: Multi
+        }
+    }
+
+    /// Parse command line args with the provided long format options.
     pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
-        ::getopts::getopts(args, opts.map(long_to_short))
+        ::getopts::getopts(args, opts.map(|x| x.long_to_short()))
     }
 
-    /**
-     * Derive a usage message from a set of long options
-     */
+    /// Derive a usage message from a set of long options.
     pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
 
         let desc_sep = "\n" + " ".repeat(24);
@@ -721,28 +752,24 @@ pub mod groups {
             row
         });
 
-        return brief.to_owned() +
-               "\n\nOptions:\n" +
-               rows.collect::<~[~str]>().connect("\n") +
-               "\n";
-    }
-
-    /** Splits a string into substrings with possibly internal whitespace,
-     *  each of them at most `lim` bytes long. The substrings have leading and trailing
-     *  whitespace removed, and are only cut at whitespace boundaries.
-     *
-     *  Note: Function was moved here from `std::str` because this module is the only place that
-     *  uses it, and because it was to specific for a general string function.
-     *
-     *  #Failure:
-     *
-     *  Fails during iteration if the string contains a non-whitespace
-     *  sequence longer than the limit.
-     */
+        fmt!("%s\n\nOptions:\n%s\n", brief, rows.collect::<~[~str]>().connect("\n"))
+    }
+
+    /// Splits a string into substrings with possibly internal whitespace,
+    /// each of them at most `lim` bytes long. The substrings have leading and trailing
+    /// whitespace removed, and are only cut at whitespace boundaries.
+    ///
+    /// Note: Function was moved here from `std::str` because this module is the only place that
+    /// uses it, and because it was to specific for a general string function.
+    ///
+    /// #Failure:
+    ///
+    /// Fails during iteration if the string contains a non-whitespace
+    /// sequence longer than the limit.
     fn each_split_within<'a>(ss: &'a str,
                              lim: uint,
                              it: &fn(&'a str) -> bool) -> bool {
-        // Just for fun, let's write this as an state machine:
+        // Just for fun, let's write this as a state machine:
 
         enum SplitWithinState {
             A,  // leading whitespace, initial state
@@ -853,8 +880,8 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "test")));
-            assert_eq!(opt_str(m, "test"), ~"20");
+            assert!(m.opt_present("test"));
+            assert_eq!(m.opt_str("test").unwrap(), ~"20");
           }
           _ => { fail!("test_reqopt_long failed"); }
         }
@@ -900,8 +927,8 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
+            assert!(m.opt_present("t"));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -949,8 +976,8 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "test")));
-            assert_eq!(opt_str(m, "test"), ~"20");
+            assert!(m.opt_present("test"));
+            assert_eq!(m.opt_str("test").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -962,7 +989,7 @@ mod tests {
         let opts = ~[optopt("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "test")),
+          Ok(ref m) => assert!(!m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -996,8 +1023,8 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
+            assert!((m.opt_present("t")));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -1009,7 +1036,7 @@ mod tests {
         let opts = ~[optopt("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "t")),
+          Ok(ref m) => assert!(!m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1044,7 +1071,7 @@ mod tests {
         let opts = ~[optflag("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(opt_present(m, "test")),
+          Ok(ref m) => assert!(m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -1055,7 +1082,7 @@ mod tests {
         let opts = ~[optflag("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "test")),
+          Ok(ref m) => assert!(!m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -1067,7 +1094,7 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Err(f) => {
-            error!(fail_str(f.clone()));
+            error!(f.clone().to_err_msg());
             check_fail_type(f, UnexpectedArgument_);
           }
           _ => fail!()
@@ -1091,7 +1118,7 @@ mod tests {
         let opts = ~[optflag("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(opt_present(m, "t")),
+          Ok(ref m) => assert!(m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1102,7 +1129,7 @@ mod tests {
         let opts = ~[optflag("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "t")),
+          Ok(ref m) => assert!(!m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1141,7 +1168,7 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "v"), 1);
+            assert_eq!(m.opt_count("v"), 1);
           }
           _ => fail!()
         }
@@ -1154,7 +1181,7 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "v"), 2);
+            assert_eq!(m.opt_count("v"), 2);
           }
           _ => fail!()
         }
@@ -1167,7 +1194,7 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "v"), 2);
+            assert_eq!(m.opt_count("v"), 2);
           }
           _ => fail!()
         }
@@ -1180,7 +1207,7 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "verbose"), 1);
+            assert_eq!(m.opt_count("verbose"), 1);
           }
           _ => fail!()
         }
@@ -1193,7 +1220,7 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "verbose"), 2);
+            assert_eq!(m.opt_count("verbose"), 2);
           }
           _ => fail!()
         }
@@ -1207,8 +1234,8 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "test")));
-            assert_eq!(opt_str(m, "test"), ~"20");
+            assert!((m.opt_present("test")));
+            assert_eq!(m.opt_str("test").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -1220,7 +1247,7 @@ mod tests {
         let opts = ~[optmulti("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "test")),
+          Ok(ref m) => assert!(!m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -1243,9 +1270,9 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-              assert!(opt_present(m, "test"));
-              assert_eq!(opt_str(m, "test"), ~"20");
-              let pair = opt_strs(m, "test");
+              assert!(m.opt_present("test"));
+              assert_eq!(m.opt_str("test").unwrap(), ~"20");
+              let pair = m.opt_strs("test");
               assert!(pair[0] == ~"20");
               assert!(pair[1] == ~"30");
           }
@@ -1260,8 +1287,8 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
+            assert!((m.opt_present("t")));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -1273,7 +1300,7 @@ mod tests {
         let opts = ~[optmulti("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "t")),
+          Ok(ref m) => assert!(!m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1296,9 +1323,9 @@ mod tests {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
-            let pair = opt_strs(m, "t");
+            assert!((m.opt_present("t")));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
+            let pair = m.opt_strs("t");
             assert!(pair[0] == ~"20");
             assert!(pair[1] == ~"30");
           }
@@ -1343,18 +1370,18 @@ mod tests {
           Ok(ref m) => {
             assert!(m.free[0] == ~"prog");
             assert!(m.free[1] == ~"free1");
-            assert_eq!(opt_str(m, "s"), ~"20");
+            assert_eq!(m.opt_str("s").unwrap(), ~"20");
             assert!(m.free[2] == ~"free2");
-            assert!((opt_present(m, "flag")));
-            assert_eq!(opt_str(m, "long"), ~"30");
-            assert!((opt_present(m, "f")));
-            let pair = opt_strs(m, "m");
+            assert!((m.opt_present("flag")));
+            assert_eq!(m.opt_str("long").unwrap(), ~"30");
+            assert!((m.opt_present("f")));
+            let pair = m.opt_strs("m");
             assert!(pair[0] == ~"40");
             assert!(pair[1] == ~"50");
-            let pair = opt_strs(m, "n");
+            let pair = m.opt_strs("n");
             assert!(pair[0] == ~"-A B");
             assert!(pair[1] == ~"-60 70");
-            assert!((!opt_present(m, "notpresent")));
+            assert!((!m.opt_present("notpresent")));
           }
           _ => fail!()
         }
@@ -1369,34 +1396,34 @@ mod tests {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(opts_present(matches_single, [~"e"]));
-        assert!(opts_present(matches_single, [~"encrypt", ~"e"]));
-        assert!(opts_present(matches_single, [~"e", ~"encrypt"]));
-        assert!(!opts_present(matches_single, [~"encrypt"]));
-        assert!(!opts_present(matches_single, [~"thing"]));
-        assert!(!opts_present(matches_single, []));
+        assert!(matches_single.opts_present([~"e"]));
+        assert!(matches_single.opts_present([~"encrypt", ~"e"]));
+        assert!(matches_single.opts_present([~"e", ~"encrypt"]));
+        assert!(!matches_single.opts_present([~"encrypt"]));
+        assert!(!matches_single.opts_present([~"thing"]));
+        assert!(!matches_single.opts_present([]));
 
-        assert_eq!(opts_str(matches_single, [~"e"]), ~"foo");
-        assert_eq!(opts_str(matches_single, [~"e", ~"encrypt"]), ~"foo");
-        assert_eq!(opts_str(matches_single, [~"encrypt", ~"e"]), ~"foo");
+        assert_eq!(matches_single.opts_str([~"e"]).unwrap(), ~"foo");
+        assert_eq!(matches_single.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
+        assert_eq!(matches_single.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
 
         let args_both = ~[~"-e", ~"foo", ~"--encrypt", ~"foo"];
         let matches_both = &match getopts(args_both, opts) {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(opts_present(matches_both, [~"e"]));
-        assert!(opts_present(matches_both, [~"encrypt"]));
-        assert!(opts_present(matches_both, [~"encrypt", ~"e"]));
-        assert!(opts_present(matches_both, [~"e", ~"encrypt"]));
-        assert!(!opts_present(matches_both, [~"f"]));
-        assert!(!opts_present(matches_both, [~"thing"]));
-        assert!(!opts_present(matches_both, []));
+        assert!(matches_both.opts_present([~"e"]));
+        assert!(matches_both.opts_present([~"encrypt"]));
+        assert!(matches_both.opts_present([~"encrypt", ~"e"]));
+        assert!(matches_both.opts_present([~"e", ~"encrypt"]));
+        assert!(!matches_both.opts_present([~"f"]));
+        assert!(!matches_both.opts_present([~"thing"]));
+        assert!(!matches_both.opts_present([]));
 
-        assert_eq!(opts_str(matches_both, [~"e"]), ~"foo");
-        assert_eq!(opts_str(matches_both, [~"encrypt"]), ~"foo");
-        assert_eq!(opts_str(matches_both, [~"e", ~"encrypt"]), ~"foo");
-        assert_eq!(opts_str(matches_both, [~"encrypt", ~"e"]), ~"foo");
+        assert_eq!(matches_both.opts_str([~"e"]).unwrap(), ~"foo");
+        assert_eq!(matches_both.opts_str([~"encrypt"]).unwrap(), ~"foo");
+        assert_eq!(matches_both.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
+        assert_eq!(matches_both.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
     }
 
     #[test]
@@ -1407,10 +1434,10 @@ mod tests {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(opts_present(matches, [~"L"]));
-        assert_eq!(opts_str(matches, [~"L"]), ~"foo");
-        assert!(opts_present(matches, [~"M"]));
-        assert_eq!(opts_str(matches, [~"M"]), ~".");
+        assert!(matches.opts_present([~"L"]));
+        assert_eq!(matches.opts_str([~"L"]).unwrap(), ~"foo");
+        assert!(matches.opts_present([~"M"]));
+        assert_eq!(matches.opts_str([~"M"]).unwrap(), ~".");
 
     }
 
@@ -1475,7 +1502,7 @@ mod tests {
         short.aliases = ~[reqopt("b")];
         let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
 
-        assert_eq!(groups::long_to_short(&verbose), short);
+        assert_eq!(verbose.long_to_short(), short);
     }
 
     #[test]
@@ -1519,8 +1546,8 @@ mod tests {
         let args = ~[~"-a", ~"--apple", ~"-a"];
 
         let matches = groups::getopts(args, opts).unwrap();
-        assert_eq!(3, opt_count(&matches, "a"));
-        assert_eq!(3, opt_count(&matches, "apple"));
+        assert_eq!(3, matches.opt_count("a"));
+        assert_eq!(3, matches.opt_count("apple"));
     }
 
     #[test]
diff --git a/src/libextra/glob.rs b/src/libextra/glob.rs
index 39a4ac61846..43a4ecf5616 100644
--- a/src/libextra/glob.rs
+++ b/src/libextra/glob.rs
@@ -137,16 +137,6 @@ fn list_dir_sorted(path: &Path) -> ~[Path] {
 /**
  * A compiled Unix shell style pattern.
  */
-#[cfg(stage0)]
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-pub struct Pattern {
-    priv tokens: ~[PatternToken]
-}
-
-/**
- * A compiled Unix shell style pattern.
- */
-#[cfg(not(stage0))]
 #[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
 pub struct Pattern {
     priv tokens: ~[PatternToken]
@@ -465,39 +455,10 @@ fn is_sep(c: char) -> bool {
     }
 }
 
-/**
- * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
- */
-#[cfg(stage0)]
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-pub struct MatchOptions {
-
-    /**
-     * Whether or not patterns should be matched in a case-sensitive manner. This
-     * currently only considers upper/lower case relationships between ASCII characters,
-     * but in future this might be extended to work with Unicode.
-     */
-    case_sensitive: bool,
-
-    /**
-     * If this is true then path-component separator characters (e.g. `/` on Posix)
-     * must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
-     */
-    require_literal_separator: bool,
-
-    /**
-     * If this is true then paths that contain components that start with a `.` will
-     * not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
-     * will not match. This is useful because such files are conventionally considered
-     * hidden on Unix systems and it might be desirable to skip them when listing files.
-     */
-    require_literal_leading_dot: bool
-}
 
 /**
  * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
  */
-#[cfg(not(stage0))]
 #[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
 pub struct MatchOptions {
 
diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs
index 039694f5881..936efed94e4 100644
--- a/src/libextra/num/bigint.rs
+++ b/src/libextra/num/bigint.rs
@@ -115,8 +115,8 @@ impl TotalOrd for BigUint {
         if s_len > o_len { return Greater;  }
 
         for (&self_i, &other_i) in self.data.rev_iter().zip(other.data.rev_iter()) {
-            cond!((self_i < other_i) { return Less; }
-                  (self_i > other_i) { return Greater; })
+            if self_i < other_i { return Less; }
+            if self_i > other_i { return Greater; }
         }
         return Equal;
     }
diff --git a/src/libextra/rl.rs b/src/libextra/rl.rs
index 74b7aea9978..9476bcb8926 100644
--- a/src/libextra/rl.rs
+++ b/src/libextra/rl.rs
@@ -13,25 +13,6 @@ use std::libc::{c_char, c_int};
 use std::{local_data, str, rt};
 use std::unstable::finally::Finally;
 
-#[cfg(stage0)]
-pub mod rustrt {
-    use std::libc::{c_char, c_int};
-
-    extern {
-        fn linenoise(prompt: *c_char) -> *c_char;
-        fn linenoiseHistoryAdd(line: *c_char) -> c_int;
-        fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
-        fn linenoiseHistorySave(file: *c_char) -> c_int;
-        fn linenoiseHistoryLoad(file: *c_char) -> c_int;
-        fn linenoiseSetCompletionCallback(callback: *u8);
-        fn linenoiseAddCompletion(completions: *(), line: *c_char);
-
-        fn rust_take_linenoise_lock();
-        fn rust_drop_linenoise_lock();
-    }
-}
-
-#[cfg(not(stage0))]
 pub mod rustrt {
     use std::libc::{c_char, c_int};
 
@@ -109,7 +90,7 @@ pub fn read(prompt: &str) -> Option<~str> {
 
 pub type CompletionCb = @fn(~str, @fn(~str));
 
-static complete_key: local_data::Key<CompletionCb> = &local_data::Key;
+local_data_key!(complete_key: CompletionCb)
 
 /// Bind to the main completion callback in the current task.
 ///
diff --git a/src/libextra/test.rs b/src/libextra/test.rs
index 4dcb48d2751..cc80da1506a 100644
--- a/src/libextra/test.rs
+++ b/src/libextra/test.rs
@@ -226,11 +226,11 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
     let matches =
         match groups::getopts(args_, optgroups()) {
           Ok(m) => m,
-          Err(f) => return Err(getopts::fail_str(f))
+          Err(f) => return Err(f.to_err_msg())
         };
 
-    if getopts::opt_present(&matches, "h") { usage(args[0], "h"); }
-    if getopts::opt_present(&matches, "help") { usage(args[0], "help"); }
+    if matches.opt_present("h") { usage(args[0], "h"); }
+    if matches.opt_present("help") { usage(args[0], "help"); }
 
     let filter =
         if matches.free.len() > 0 {
@@ -239,25 +239,25 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
             None
         };
 
-    let run_ignored = getopts::opt_present(&matches, "ignored");
+    let run_ignored = matches.opt_present("ignored");
 
-    let logfile = getopts::opt_maybe_str(&matches, "logfile");
+    let logfile = matches.opt_str("logfile");
     let logfile = logfile.map_move(|s| Path(s));
 
-    let run_benchmarks = getopts::opt_present(&matches, "bench");
+    let run_benchmarks = matches.opt_present("bench");
     let run_tests = ! run_benchmarks ||
-        getopts::opt_present(&matches, "test");
+        matches.opt_present("test");
 
-    let ratchet_metrics = getopts::opt_maybe_str(&matches, "ratchet-metrics");
+    let ratchet_metrics = matches.opt_str("ratchet-metrics");
     let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s));
 
-    let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent");
+    let ratchet_noise_percent = matches.opt_str("ratchet-noise-percent");
     let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| from_str::<f64>(s).unwrap());
 
-    let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics");
+    let save_metrics = matches.opt_str("save-metrics");
     let save_metrics = save_metrics.map_move(|s| Path(s));
 
-    let test_shard = getopts::opt_maybe_str(&matches, "test-shard");
+    let test_shard = matches.opt_str("test-shard");
     let test_shard = opt_shard(test_shard);
 
     let test_opts = TestOpts {
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 1fbbc1db05a..ee7fbed9e9f 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -190,7 +190,7 @@ pub mod jit {
 
     // The stage1 compiler won't work, but that doesn't really matter. TLS
     // changed only very recently to allow storage of owned values.
-    static engine_key: local_data::Key<~Engine> = &local_data::Key;
+    local_data_key!(engine_key: ~Engine)
 
     fn set_engine(engine: ~Engine) {
         local_data::set(engine_key, engine)
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 5078d0ded18..bd0462119bd 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -30,7 +30,6 @@ use std::io;
 use std::os;
 use std::vec;
 use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt};
-use extra::getopts::{opt_present};
 use extra::getopts;
 use syntax::ast;
 use syntax::abi;
@@ -606,15 +605,15 @@ pub fn build_session_options(binary: @str,
                              matches: &getopts::Matches,
                              demitter: diagnostic::Emitter)
                           -> @session::options {
-    let crate_type = if opt_present(matches, "lib") {
+    let crate_type = if matches.opt_present("lib") {
         session::lib_crate
-    } else if opt_present(matches, "bin") {
+    } else if matches.opt_present("bin") {
         session::bin_crate
     } else {
         session::unknown_crate
     };
-    let parse_only = opt_present(matches, "parse-only");
-    let no_trans = opt_present(matches, "no-trans");
+    let parse_only = matches.opt_present("parse-only");
+    let no_trans = matches.opt_present("no-trans");
 
     let lint_levels = [lint::allow, lint::warn,
                        lint::deny, lint::forbid];
@@ -627,8 +626,8 @@ pub fn build_session_options(binary: @str,
         // to_ascii_move and to_str_move to not do a unnecessary copy.
         let level_short = level_name.slice_chars(0, 1);
         let level_short = level_short.to_ascii().to_upper().to_str_ascii();
-        let flags = vec::append(getopts::opt_strs(matches, level_short),
-                                getopts::opt_strs(matches, level_name));
+        let flags = vec::append(matches.opt_strs(level_short),
+                                matches.opt_strs(level_name));
         for lint_name in flags.iter() {
             let lint_name = lint_name.replace("-", "_");
             match lint_dict.find_equiv(&lint_name) {
@@ -644,7 +643,7 @@ pub fn build_session_options(binary: @str,
     }
 
     let mut debugging_opts = 0u;
-    let debug_flags = getopts::opt_strs(matches, "Z");
+    let debug_flags = matches.opt_strs("Z");
     let debug_map = session::debugging_opts_map();
     for debug_flag in debug_flags.iter() {
         let mut this_bit = 0u;
@@ -670,31 +669,31 @@ pub fn build_session_options(binary: @str,
     let output_type =
         if parse_only || no_trans {
             link::output_type_none
-        } else if opt_present(matches, "S") &&
-                  opt_present(matches, "emit-llvm") {
+        } else if matches.opt_present("S") &&
+                  matches.opt_present("emit-llvm") {
             link::output_type_llvm_assembly
-        } else if opt_present(matches, "S") {
+        } else if matches.opt_present("S") {
             link::output_type_assembly
-        } else if opt_present(matches, "c") {
+        } else if matches.opt_present("c") {
             link::output_type_object
-        } else if opt_present(matches, "emit-llvm") {
+        } else if matches.opt_present("emit-llvm") {
             link::output_type_bitcode
         } else { link::output_type_exe };
-    let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
-    let target = getopts::opt_maybe_str(matches, "target").unwrap_or(host_triple());
-    let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or(~"generic");
-    let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or(~"");
-    let save_temps = getopts::opt_present(matches, "save-temps");
+    let sysroot_opt = matches.opt_str("sysroot").map_move(|m| @Path(m));
+    let target = matches.opt_str("target").unwrap_or(host_triple());
+    let target_cpu = matches.opt_str("target-cpu").unwrap_or(~"generic");
+    let target_feature = matches.opt_str("target-feature").unwrap_or(~"");
+    let save_temps = matches.opt_present("save-temps");
     let opt_level = {
         if (debugging_opts & session::no_opt) != 0 {
             No
-        } else if opt_present(matches, "O") {
-            if opt_present(matches, "opt-level") {
+        } else if matches.opt_present("O") {
+            if matches.opt_present("opt-level") {
                 early_error(demitter, ~"-O and --opt-level both provided");
             }
             Default
-        } else if opt_present(matches, "opt-level") {
-            match getopts::opt_str(matches, "opt-level") {
+        } else if matches.opt_present("opt-level") {
+            match matches.opt_str("opt-level").unwrap() {
               ~"0" => No,
               ~"1" => Less,
               ~"2" => Default,
@@ -720,18 +719,17 @@ pub fn build_session_options(binary: @str,
 
     let statik = debugging_opts & session::statik != 0;
 
-    let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
-    let linker = getopts::opt_maybe_str(matches, "linker");
-    let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
+    let addl_lib_search_paths = matches.opt_strs("L").map(|s| Path(*s));
+    let linker = matches.opt_str("linker");
+    let linker_args = matches.opt_strs("link-args").flat_map( |a| {
         a.split_iter(' ').map(|arg| arg.to_owned()).collect()
     });
 
-    let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
-    let test = opt_present(matches, "test");
-    let android_cross_path = getopts::opt_maybe_str(
-        matches, "android-cross-path");
+    let cfg = parse_cfgspecs(matches.opt_strs("cfg"), demitter);
+    let test = matches.opt_present("test");
+    let android_cross_path = matches.opt_str("android-cross-path");
 
-    let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
+    let custom_passes = match matches.opt_str("passes") {
         None => ~[],
         Some(s) => {
             s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
@@ -739,7 +737,7 @@ pub fn build_session_options(binary: @str,
             }).collect()
         }
     };
-    let llvm_args = match getopts::opt_maybe_str(matches, "llvm-args") {
+    let llvm_args = match matches.opt_str("llvm-args") {
         None => ~[],
         Some(s) => {
             s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
@@ -1020,7 +1018,6 @@ mod test {
     use driver::driver::{build_session_options, optgroups};
 
     use extra::getopts::groups::getopts;
-    use extra::getopts;
     use syntax::attr;
     use syntax::diagnostic;
 
@@ -1030,7 +1027,7 @@ mod test {
         let matches =
             &match getopts([~"--test"], optgroups()) {
               Ok(m) => m,
-              Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
+              Err(f) => fail!("test_switch_implies_cfg_test: %s", f.to_err_msg())
             };
         let sessopts = build_session_options(
             @"rustc", matches, diagnostic::emit);
@@ -1047,7 +1044,7 @@ mod test {
             &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
               Ok(m) => m,
               Err(f) => {
-                fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
+                fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", f.to_err_msg());
               }
             };
         let sessopts = build_session_options(
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index 9c788065133..49176c7bc17 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -293,50 +293,6 @@ fn mk_std(cx: &TestCtxt) -> ast::view_item {
     }
 }
 
-#[cfg(stage0)]
-fn mk_test_module(cx: &TestCtxt) -> @ast::item {
-
-    // Link to extra
-    let view_items = ~[mk_std(cx)];
-
-    // A constant vector of test descriptors.
-    let tests = mk_tests(cx);
-
-    // The synthesized main function which will call the console test runner
-    // with our list of tests
-    let ext_cx = cx.ext_cx;
-    let mainfn = (quote_item!(
-        pub fn main() {
-            #[main];
-            extra::test::test_main_static(::std::os::args(), TESTS);
-        }
-    )).unwrap();
-
-    let testmod = ast::_mod {
-        view_items: view_items,
-        items: ~[mainfn, tests],
-    };
-    let item_ = ast::item_mod(testmod);
-
-    // This attribute tells resolve to let us call unexported functions
-    let resolve_unexported_attr =
-        attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));
-
-    let item = ast::item {
-        ident: cx.sess.ident_of("__test"),
-        attrs: ~[resolve_unexported_attr],
-        id: ast::DUMMY_NODE_ID,
-        node: item_,
-        vis: ast::public,
-        span: dummy_sp(),
-     };
-
-    debug!("Synthetic test module:\n%s\n",
-           pprust::item_to_str(@item.clone(), cx.sess.intr()));
-
-    return @item;
-}
-#[cfg(not(stage0))]
 fn mk_test_module(cx: &TestCtxt) -> @ast::item {
 
     // Link to extra
@@ -407,21 +363,6 @@ fn path_node_global(ids: ~[ast::Ident]) -> ast::Path {
     }
 }
 
-#[cfg(stage0)]
-fn mk_tests(cx: &TestCtxt) -> @ast::item {
-
-    let ext_cx = cx.ext_cx;
-
-    // The vector of test_descs for this crate
-    let test_descs = mk_test_descs(cx);
-
-    (quote_item!(
-        pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
-            $test_descs
-        ;
-    )).unwrap()
-}
-#[cfg(not(stage0))]
 fn mk_tests(cx: &TestCtxt) -> @ast::item {
     // The vector of test_descs for this crate
     let test_descs = mk_test_descs(cx);
@@ -461,63 +402,6 @@ fn mk_test_descs(cx: &TestCtxt) -> @ast::Expr {
     }
 }
 
-#[cfg(stage0)]
-fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
-    let span = test.span;
-    let path = test.path.clone();
-
-    let ext_cx = cx.ext_cx;
-
-    debug!("encoding %s", ast_util::path_name_i(path));
-
-    let name_lit: ast::lit =
-        nospan(ast::lit_str(ast_util::path_name_i(path).to_managed()));
-
-    let name_expr = @ast::Expr {
-          id: ast::DUMMY_NODE_ID,
-          node: ast::ExprLit(@name_lit),
-          span: span
-    };
-
-    let fn_path = path_node_global(path);
-
-    let fn_expr = @ast::Expr {
-        id: ast::DUMMY_NODE_ID,
-        node: ast::ExprPath(fn_path),
-        span: span,
-    };
-
-    let t_expr = if test.bench {
-        quote_expr!( self::extra::test::StaticBenchFn($fn_expr) )
-    } else {
-        quote_expr!( self::extra::test::StaticTestFn($fn_expr) )
-    };
-
-    let ignore_expr = if test.ignore {
-        quote_expr!( true )
-    } else {
-        quote_expr!( false )
-    };
-
-    let fail_expr = if test.should_fail {
-        quote_expr!( true )
-    } else {
-        quote_expr!( false )
-    };
-
-    let e = quote_expr!(
-        self::extra::test::TestDescAndFn {
-            desc: self::extra::test::TestDesc {
-                name: self::extra::test::StaticTestName($name_expr),
-                ignore: $ignore_expr,
-                should_fail: $fail_expr
-            },
-            testfn: $t_expr,
-        }
-    );
-    e
-}
-#[cfg(not(stage0))]
 fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
     let span = test.span;
     let path = test.path.clone();
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 2e5e87f225a..bba3ca9f212 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -19,7 +19,6 @@ use syntax::visit;
 use syntax::visit::Visitor;
 use syntax::ast::*;
 
-use std::float;
 use std::hashmap::{HashMap, HashSet};
 
 //
@@ -476,9 +475,9 @@ pub fn lit_to_const(lit: &lit) -> const_val {
       lit_int(n, _) => const_int(n),
       lit_uint(n, _) => const_uint(n),
       lit_int_unsuffixed(n) => const_int(n),
-      lit_float(n, _) => const_float(float::from_str(n).unwrap() as f64),
+      lit_float(n, _) => const_float(from_str::<float>(n).unwrap() as f64),
       lit_float_unsuffixed(n) =>
-        const_float(float::from_str(n).unwrap() as f64),
+        const_float(from_str::<float>(n).unwrap() as f64),
       lit_nil => const_int(0i64),
       lit_bool(b) => const_bool(b)
     }
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 6f70d2e601d..f7fcd8f908d 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -92,7 +92,7 @@ use syntax::visit::Visitor;
 
 pub use middle::trans::context::task_llcx;
 
-static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key;
+local_data_key!(task_local_insn_key: @~[&'static str])
 
 pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
     let opt = local_data::get(task_local_insn_key, |k| k.map_move(|k| *k));
@@ -2388,38 +2388,12 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
     let et = ccx.sess.entry_type.unwrap();
     match et {
         session::EntryMain => {
-            let llfn = create_main(ccx, main_llfn);
-            create_entry_fn(ccx, llfn, true);
+            create_entry_fn(ccx, main_llfn, true);
         }
         session::EntryStart => create_entry_fn(ccx, main_llfn, false),
         session::EntryNone => {}    // Do nothing.
     }
 
-    fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
-        let nt = ty::mk_nil();
-        let llfty = type_of_rust_fn(ccx, [], nt);
-        let llfdecl = decl_fn(ccx.llmod, "_rust_main",
-                              lib::llvm::CCallConv, llfty);
-
-        let fcx = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
-
-        // the args vector built in create_entry_fn will need
-        // be updated if this assertion starts to fail.
-        assert!(!fcx.caller_expects_out_pointer);
-
-        let bcx = fcx.entry_bcx.unwrap();
-        // Call main.
-        let llenvarg = unsafe {
-            let env_arg = fcx.env_arg_pos();
-            llvm::LLVMGetParam(llfdecl, env_arg as c_uint)
-        };
-        let args = ~[llenvarg];
-        Call(bcx, main_llfn, args, []);
-
-        finish_fn(fcx, bcx);
-        return llfdecl;
-    }
-
     fn create_entry_fn(ccx: @mut CrateContext,
                        rust_main: ValueRef,
                        use_start_lang_item: bool) {
@@ -2660,7 +2634,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                             foreign::register_foreign_item_fn(ccx, abis, &path, ni)
                         }
                         ast::foreign_item_static(*) => {
-                            let ident = token::ident_to_str(&ni.ident);
+                            let ident = foreign::link_name(ccx, ni);
                             let g = do ident.with_c_str |buf| {
                                 unsafe {
                                     let ty = type_of(ccx, ty);
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 7e1c2c369b1..e342bcaf4fa 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -287,7 +287,7 @@ impl Drop for CrateContext {
     }
 }
 
-static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
+local_data_key!(task_local_llcx_key: @ContextRef)
 
 pub fn task_llcx() -> ContextRef {
     let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k));
diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs
index bca2ceb2f84..8c3e198e5d6 100644
--- a/src/librustc/rustc.rs
+++ b/src/librustc/rustc.rs
@@ -40,7 +40,7 @@ use std::result;
 use std::str;
 use std::task;
 use std::vec;
-use extra::getopts::{groups, opt_present};
+use extra::getopts::groups;
 use extra::getopts;
 use syntax::codemap;
 use syntax::diagnostic;
@@ -134,7 +134,7 @@ pub fn version(argv0: &str) {
 
 pub fn usage(argv0: &str) {
     let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
-    printfln!("%s\
+    printfln!("%s\n\
 Additional help:
     -W help             Print 'lint' options and default settings
     -Z help             Print internal options for debugging rustc\n",
@@ -204,39 +204,39 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
         &match getopts::groups::getopts(args, optgroups()) {
           Ok(m) => m,
           Err(f) => {
-            early_error(demitter, getopts::fail_str(f));
+            early_error(demitter, f.to_err_msg());
           }
         };
 
-    if opt_present(matches, "h") || opt_present(matches, "help") {
+    if matches.opt_present("h") || matches.opt_present("help") {
         usage(binary);
         return;
     }
 
     // Display the available lint options if "-W help" or only "-W" is given.
-    let lint_flags = vec::append(getopts::opt_strs(matches, "W"),
-                                 getopts::opt_strs(matches, "warn"));
+    let lint_flags = vec::append(matches.opt_strs("W"),
+                                 matches.opt_strs("warn"));
 
     let show_lint_options = lint_flags.iter().any(|x| x == &~"help") ||
-        (opt_present(matches, "W") && lint_flags.is_empty());
+        (matches.opt_present("W") && lint_flags.is_empty());
 
     if show_lint_options {
         describe_warnings();
         return;
     }
 
-    let r = getopts::opt_strs(matches, "Z");
+    let r = matches.opt_strs("Z");
     if r.iter().any(|x| x == &~"help") {
         describe_debug_flags();
         return;
     }
 
-    if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
+    if matches.opt_str("passes") == Some(~"list") {
         unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
         return;
     }
 
-    if opt_present(matches, "v") || opt_present(matches, "version") {
+    if matches.opt_present("v") || matches.opt_present("version") {
         version(binary);
         return;
     }
@@ -256,10 +256,10 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
 
     let sopts = build_session_options(binary, matches, demitter);
     let sess = build_session(sopts, demitter);
-    let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
-    let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
+    let odir = matches.opt_str("out-dir").map_move(|o| Path(o));
+    let ofile = matches.opt_str("o").map_move(|o| Path(o));
     let cfg = build_configuration(sess);
-    let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
+    let pretty = do matches.opt_default("pretty", "normal").map_move |a| {
         parse_pretty(sess, a)
     };
     match pretty {
@@ -269,7 +269,7 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
       }
       None::<PpMode> => {/* continue */ }
     }
-    let ls = opt_present(matches, "ls");
+    let ls = matches.opt_present("ls");
     if ls {
         match input {
           file_input(ref ifile) => {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index ff6401456b6..71ece178807 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -125,7 +125,7 @@ pub fn parse_config_(
             }
         }
         Err(f) => {
-            Err(getopts::fail_str(f))
+            Err(f.to_err_msg())
         }
     }
 }
@@ -139,7 +139,7 @@ fn config_from_opts(
     let config = default_config(input_crate);
     let result = result::Ok(config);
     let result = do result.and_then |config| {
-        let output_dir = getopts::opt_maybe_str(matches, opt_output_dir());
+        let output_dir = matches.opt_str(opt_output_dir());
         let output_dir = output_dir.map_move(|s| Path(s));
         result::Ok(Config {
             output_dir: output_dir.unwrap_or(config.output_dir.clone()),
@@ -147,7 +147,7 @@ fn config_from_opts(
         })
     };
     let result = do result.and_then |config| {
-        let output_format = getopts::opt_maybe_str(matches, opt_output_format());
+        let output_format = matches.opt_str(opt_output_format());
         do output_format.map_move_default(result::Ok(config.clone())) |output_format| {
             do parse_output_format(output_format).and_then |output_format| {
                 result::Ok(Config {
@@ -159,7 +159,7 @@ fn config_from_opts(
     };
     let result = do result.and_then |config| {
         let output_style =
-            getopts::opt_maybe_str(matches, opt_output_style());
+            matches.opt_str(opt_output_style());
         do output_style.map_move_default(result::Ok(config.clone())) |output_style| {
             do parse_output_style(output_style).and_then |output_style| {
                 result::Ok(Config {
@@ -171,7 +171,7 @@ fn config_from_opts(
     };
     let process_output = Cell::new(process_output);
     let result = do result.and_then |config| {
-        let pandoc_cmd = getopts::opt_maybe_str(matches, opt_pandoc_cmd());
+        let pandoc_cmd = matches.opt_str(opt_pandoc_cmd());
         let pandoc_cmd = maybe_find_pandoc(
             &config, pandoc_cmd, process_output.take());
         do pandoc_cmd.and_then |pandoc_cmd| {
diff --git a/src/librusti/program.rs b/src/librusti/program.rs
index 9208191e364..4deaa458f19 100644
--- a/src/librusti/program.rs
+++ b/src/librusti/program.rs
@@ -60,7 +60,7 @@ struct LocalVariable {
 }
 
 type LocalCache = @mut HashMap<~str, @~[u8]>;
-static tls_key: local_data::Key<LocalCache> = &local_data::Key;
+local_data_key!(tls_key: LocalCache)
 
 impl Program {
     pub fn new() -> Program {
diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs
index 727bbcb30b4..e1092458ffa 100644
--- a/src/librustpkg/api.rs
+++ b/src/librustpkg/api.rs
@@ -12,6 +12,7 @@ use context::*;
 use crate::*;
 use package_id::*;
 use package_source::*;
+use target::*;
 use version::Version;
 use workcache_support::*;
 
@@ -63,56 +64,40 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
 pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
                  lib: Path) {
     let cx = default_context(sysroot);
-    let subroot = root.clone();
-    let subversion = version.clone();
-    let sublib = lib.clone();
-    do cx.workcache_context.with_prep(name) |prep| {
-        let pkg_src = PkgSrc {
-            workspace: subroot.clone(),
-            start_dir: subroot.push("src").push(name),
-            id: PkgId{ version: subversion.clone(), ..PkgId::new(name)},
-            libs: ~[mk_crate(sublib.clone())],
+    let pkg_src = PkgSrc {
+            workspace: root.clone(),
+            start_dir: root.push("src").push(name),
+            id: PkgId{ version: version, ..PkgId::new(name)},
+            // n.b. This assumes the package only has one crate
+            libs: ~[mk_crate(lib)],
             mains: ~[],
             tests: ~[],
             benchs: ~[]
         };
-        pkg_src.declare_inputs(prep);
-        let subcx = cx.clone();
-        let subsrc = pkg_src.clone();
-        do prep.exec |exec| {
-            subsrc.build(exec, &subcx.clone(), ~[]);
-        }
-    };
+    pkg_src.build(&cx, ~[]);
 }
 
 pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
                  main: Path) {
     let cx = default_context(sysroot);
-    let subroot = root.clone();
-    let submain = main.clone();
-    do cx.workcache_context.with_prep(name) |prep| {
-        let pkg_src = PkgSrc {
-            workspace: subroot.clone(),
-            start_dir: subroot.push("src").push(name),
-            id: PkgId{ version: version.clone(), ..PkgId::new(name)},
-            libs: ~[],
-            mains: ~[mk_crate(submain.clone())],
-            tests: ~[],
-            benchs: ~[]
-        };
-        pkg_src.declare_inputs(prep);
-        let subsrc = pkg_src.clone();
-        let subcx = cx.clone();
-        do prep.exec |exec| {
-            subsrc.clone().build(exec, &subcx.clone(), ~[]);
-        }
-    }
+    let pkg_src = PkgSrc {
+        workspace: root.clone(),
+        start_dir: root.push("src").push(name),
+        id: PkgId{ version: version, ..PkgId::new(name)},
+        libs: ~[],
+        // n.b. This assumes the package only has one crate
+        mains: ~[mk_crate(main)],
+        tests: ~[],
+        benchs: ~[]
+    };
+
+    pkg_src.build(&cx, ~[]);
 }
 
 pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
     let cx = default_context(sysroot);
     let pkgid = PkgId{ version: version, ..PkgId::new(name)};
-    cx.install(PkgSrc::new(workspace, false, pkgid));
+    cx.install(PkgSrc::new(workspace, false, pkgid), &Everything);
 }
 
 fn mk_crate(p: Path) -> Crate {
diff --git a/src/test/run-pass/cond-macro.rs b/src/librustpkg/exit_codes.rs
index 61a51b67261..484f6bdcaec 100644
--- a/src/test/run-pass/cond-macro.rs
+++ b/src/librustpkg/exit_codes.rs
@@ -8,16 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn clamp<T:Ord + Signed>(x: T, mn: T, mx: T) -> T {
-    cond!(
-        (x > mx) { mx }
-        (x < mn) { mn }
-        _        { x  }
-    )
-}
-
-fn main() {
-    assert_eq!(clamp(1, 2, 4), 2);
-    assert_eq!(clamp(8, 2, 4), 4);
-    assert_eq!(clamp(3, 2, 4), 3);
-}
+pub static copy_failed_code: int = 65;
diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs
index bc2fcdd7fe9..52b986cb6e7 100644
--- a/src/librustpkg/package_id.rs
+++ b/src/librustpkg/package_id.rs
@@ -108,6 +108,12 @@ impl PkgId {
         }
     }
 
+    // This is the workcache function name for the *installed*
+    // binaries for this package (as opposed to the built ones,
+    // which are per-crate).
+    pub fn install_tag(&self) -> ~str {
+        fmt!("install(%s)", self.to_str())
+    }
 }
 
 struct Prefixes {
diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs
index b5ded6f3faf..4bf647b011d 100644
--- a/src/librustpkg/package_source.rs
+++ b/src/librustpkg/package_source.rs
@@ -22,6 +22,7 @@ use path_util::{find_dir_using_rust_path_hack, default_workspace, make_dir_rwx_r
 use util::compile_crate;
 use workspace::is_workspace;
 use workcache_support;
+use workcache_support::crate_tag;
 use extra::workcache;
 
 // An enumeration of the unpacked source of a package workspace.
@@ -231,7 +232,7 @@ impl PkgSrc {
         p.filestem().map_default(false, |p| { p == &self.id.short_name.as_slice() })
     }
 
-    fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
+    pub fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
         assert!(p.components.len() > prefix);
         let mut sub = Path("");
         for c in p.components.slice(prefix, p.components.len()).iter() {
@@ -286,7 +287,6 @@ impl PkgSrc {
 
     fn build_crates(&self,
                     ctx: &BuildContext,
-                    exec: &mut workcache::Exec,
                     destination_dir: &Path,
                     crates: &[Crate],
                     cfgs: &[~str],
@@ -297,25 +297,40 @@ impl PkgSrc {
             let path_str = path.to_str();
             let cfgs = crate.cfgs + cfgs;
 
-            let result =
-                // compile_crate should return the path of the output artifact
-                compile_crate(ctx,
-                              exec,
-                              &self.id,
-                              &path,
-                              destination_dir,
-                              crate.flags,
-                              cfgs,
-                              false,
-                              what).to_str();
-            debug!("Result of compiling %s was %s", path_str, result);
+            do ctx.workcache_context.with_prep(crate_tag(&path)) |prep| {
+                debug!("Building crate %s, declaring it as an input", path.to_str());
+                prep.declare_input("file", path.to_str(),
+                                   workcache_support::digest_file_with_date(&path));
+                let subpath = path.clone();
+                let subcfgs = cfgs.clone();
+                let subpath_str = path_str.clone();
+                let subcx = ctx.clone();
+                let id = self.id.clone();
+                let sub_dir = destination_dir.clone();
+                let sub_flags = crate.flags.clone();
+                do prep.exec |exec| {
+                    let result = compile_crate(&subcx,
+                                               exec,
+                                               &id,
+                                               &subpath,
+                                               &sub_dir,
+                                               sub_flags,
+                                               subcfgs,
+                                               false,
+                                               what).to_str();
+                    debug!("Result of compiling %s was %s", subpath_str, result);
+                    result
+                }
+            };
         }
     }
 
     /// Declare all the crate files in the package source as inputs
+    /// (to the package)
     pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
         let to_do = ~[self.libs.clone(), self.mains.clone(),
                       self.tests.clone(), self.benchs.clone()];
+        debug!("In declare inputs, self = %s", self.to_str());
         for cs in to_do.iter() {
             for c in cs.iter() {
                 let path = self.start_dir.push_rel(&c.file).normalize();
@@ -330,7 +345,6 @@ impl PkgSrc {
     // It would be better if build returned a Path, but then Path would have to derive
     // Encodable.
     pub fn build(&self,
-                 exec: &mut workcache::Exec,
                  build_context: &BuildContext,
                  cfgs: ~[~str]) -> ~str {
         use conditions::not_a_workspace::cond;
@@ -360,13 +374,23 @@ impl PkgSrc {
         let benchs = self.benchs.clone();
         debug!("Building libs in %s, destination = %s",
                destination_workspace.to_str(), destination_workspace.to_str());
-        self.build_crates(build_context, exec, &destination_workspace, libs, cfgs, Lib);
+        self.build_crates(build_context, &destination_workspace, libs, cfgs, Lib);
         debug!("Building mains");
-        self.build_crates(build_context, exec, &destination_workspace, mains, cfgs, Main);
+        self.build_crates(build_context, &destination_workspace, mains, cfgs, Main);
         debug!("Building tests");
-        self.build_crates(build_context, exec, &destination_workspace, tests, cfgs, Test);
+        self.build_crates(build_context, &destination_workspace, tests, cfgs, Test);
         debug!("Building benches");
-        self.build_crates(build_context, exec, &destination_workspace, benchs, cfgs, Bench);
+        self.build_crates(build_context, &destination_workspace, benchs, cfgs, Bench);
         destination_workspace.to_str()
     }
+
+    /// Debugging
+    pub fn dump_crates(&self) {
+        let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
+        for crate_set in crate_sets.iter() {
+            for c in crate_set.iter() {
+                debug!("Built crate: %s", c.file.to_str())
+            }
+        }
+    }
 }
diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs
index 2a0cf5fea34..0187a8d189c 100644
--- a/src/librustpkg/rustpkg.rs
+++ b/src/librustpkg/rustpkg.rs
@@ -22,11 +22,10 @@ extern mod extra;
 extern mod rustc;
 extern mod syntax;
 
-use std::{io, os, result, run, str};
+use std::{io, os, result, run, str, task};
 pub use std::path::Path;
 
 use extra::workcache;
-use extra::arc::RWArc;
 use rustc::driver::{driver, session};
 use rustc::metadata::filesearch;
 use rustc::metadata::filesearch::rust_path;
@@ -45,12 +44,16 @@ use context::{Context, BuildContext,
                        LLVMAssemble, LLVMCompileBitcode};
 use package_id::PkgId;
 use package_source::PkgSrc;
-use workcache_support::{discover_outputs, digest_only_date};
+use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
+// use workcache_support::{discover_outputs, digest_only_date};
+use workcache_support::digest_only_date;
+use exit_codes::copy_failed_code;
 
 pub mod api;
 mod conditions;
 mod context;
 mod crate;
+mod exit_codes;
 mod installed_packages;
 mod messages;
 mod package_id;
@@ -172,19 +175,18 @@ impl<'self> PkgScript<'self> {
 pub trait CtxMethods {
     fn run(&self, cmd: &str, args: ~[~str]);
     fn do_cmd(&self, _cmd: &str, _pkgname: &str);
-    fn build_from_src(&self, pkg_src: PkgSrc);
     /// Returns the destination workspace
-    fn build(&self, exec: &mut workcache::Exec, pkg_src: PkgSrc) -> Path;
+    fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
     fn clean(&self, workspace: &Path, id: &PkgId);
     fn info(&self);
     /// Returns a pair. First component is a list of installed paths,
     /// second is a list of declared and discovered inputs
-    fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
+    fn install(&self, src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]);
     /// Returns a list of installed files
     fn install_no_build(&self,
                         source_workspace: &Path,
                         target_workspace: &Path,
-                        id: &PkgId) -> ~[Path];
+                        id: &PkgId) -> ~[~str];
     fn prefer(&self, _id: &str, _vers: Option<~str>);
     fn test(&self);
     fn uninstall(&self, _id: &str, _vers: Option<~str>);
@@ -193,20 +195,6 @@ pub trait CtxMethods {
 }
 
 impl CtxMethods for BuildContext {
-    fn build_from_src(&self, pkg_src: PkgSrc) {
-        let tag = pkg_src.id.to_str();
-        debug!("package source = %s", pkg_src.to_str());
-        do self.workcache_context.with_prep(tag) |prep| {
-            let subsrc = pkg_src.clone();
-            let subself = self.clone();
-            declare_package_script_dependency(prep, &subsrc);
-            pkg_src.declare_inputs(prep);
-            do prep.exec |exec| {
-                subself.build(exec, subsrc.clone());
-            }
-        }
-    }
-
     fn run(&self, cmd: &str, args: ~[~str]) {
         match cmd {
             "build" => {
@@ -215,11 +203,13 @@ impl CtxMethods for BuildContext {
                         None if self.context.use_rust_path_hack => {
                             let cwd = os::getcwd();
                             let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
-                            self.build_from_src(PkgSrc::new(cwd, true, pkgid));
+                            let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
+                            self.build(&mut pkg_src, &Everything);
                         }
                         None => { usage::build(); return; }
                         Some((ws, pkgid)) => {
-                            self.build_from_src(PkgSrc::new(ws, false, pkgid));
+                            let mut pkg_src = PkgSrc::new(ws, false, pkgid);
+                            self.build(&mut pkg_src, &Everything);
                         }
                     }
                 }
@@ -230,8 +220,8 @@ impl CtxMethods for BuildContext {
                     do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
                         debug!("found pkg %s in workspace %s, trying to build",
                                pkgid.to_str(), workspace.to_str());
-                        let pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
-                        self.build_from_src(pkg_src);
+                        let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
+                        self.build(&mut pkg_src, &Everything);
                         true
                     };
                 }
@@ -271,12 +261,12 @@ impl CtxMethods for BuildContext {
                             let cwd = os::getcwd();
                             let inferred_pkgid =
                                 PkgId::new(cwd.components[cwd.components.len() - 1]);
-                            self.install(PkgSrc::new(cwd, true, inferred_pkgid));
+                            self.install(PkgSrc::new(cwd, true, inferred_pkgid), &Everything);
                         }
                         None  => { usage::install(); return; }
                         Some((ws, pkgid))                => {
                             let pkg_src = PkgSrc::new(ws, false, pkgid);
-                            self.install(pkg_src);
+                            self.install(pkg_src, &Everything);
                       }
                   }
                 }
@@ -291,14 +281,14 @@ impl CtxMethods for BuildContext {
                         let rp = rust_path();
                         assert!(!rp.is_empty());
                         let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
-                        self.install(src);
+                        self.install(src, &Everything);
                     }
                     else {
                         for workspace in workspaces.iter() {
                             let src = PkgSrc::new(workspace.clone(),
                                                   self.context.use_rust_path_hack,
                                                   pkgid.clone());
-                            self.install(src);
+                            self.install(src, &Everything);
                         };
                     }
                 }
@@ -366,7 +356,9 @@ impl CtxMethods for BuildContext {
 
     /// Returns the destination workspace
     /// In the case of a custom build, we don't know, so we just return the source workspace
-    fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
+    /// what_to_build says: "Just build the lib.rs file in one subdirectory,
+    /// don't walk anything recursively." Or else, everything.
+    fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) -> Path {
         let workspace = pkg_src.workspace.clone();
         let pkgid = pkg_src.id.clone();
 
@@ -384,7 +376,7 @@ impl CtxMethods for BuildContext {
             let default_ws = default_workspace();
             debug!("Calling build recursively with %? and %?", default_ws.to_str(),
                    pkgid.to_str());
-            return self.build(exec, PkgSrc::new(default_ws, false, pkgid.clone()));
+            return self.build(&mut PkgSrc::new(default_ws, false, pkgid.clone()), what_to_build);
         }
 
         // Is there custom build logic? If so, use it
@@ -395,12 +387,21 @@ impl CtxMethods for BuildContext {
         let cfgs = match pkg_src.package_script_option() {
             Some(package_script_path) => {
                 let sysroot = self.sysroot_to_use();
-                let (cfgs, hook_result) = {
-                    let pscript = PkgScript::parse(@sysroot.clone(),
-                                                   package_script_path.clone(),
-                                                   &workspace.clone(),
-                                                   &pkgid);
-                    pscript.run_custom(exec, &sysroot)
+                let (cfgs, hook_result) =
+                    do self.workcache_context.with_prep(package_script_path.to_str()) |prep| {
+                    let sub_sysroot = sysroot.clone();
+                    let package_script_path_clone = package_script_path.clone();
+                    let sub_ws = workspace.clone();
+                    let sub_id = pkgid.clone();
+                    declare_package_script_dependency(prep, &*pkg_src);
+                    do prep.exec |exec| {
+                        let pscript = PkgScript::parse(@sub_sysroot.clone(),
+                                                       package_script_path_clone.clone(),
+                                                       &sub_ws,
+                                                       &sub_id);
+
+                        pscript.run_custom(exec, &sub_sysroot)
+                    }
                 };
                 debug!("Command return code = %?", hook_result);
                 if hook_result != 0 {
@@ -419,10 +420,31 @@ impl CtxMethods for BuildContext {
         // If there was a package script, it should have finished
         // the build already. Otherwise...
         if !custom {
-            // Find crates inside the workspace
-            pkg_src.find_crates();
+            match what_to_build {
+                // Find crates inside the workspace
+                &Everything => pkg_src.find_crates(),
+                // Don't infer any crates -- just build the one that was requested
+                &JustOne(ref p) => {
+                    // We expect that p is relative to the package source's start directory,
+                    // so check that assumption
+                    debug!("JustOne: p = %s", p.to_str());
+                    assert!(os::path_exists(&pkg_src.start_dir.push_rel(p)));
+                    if is_lib(p) {
+                        PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
+                    } else if is_main(p) {
+                        PkgSrc::push_crate(&mut pkg_src.mains, 0, p);
+                    } else if is_test(p) {
+                        PkgSrc::push_crate(&mut pkg_src.tests, 0, p);
+                    } else if is_bench(p) {
+                        PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
+                    } else {
+                        warn(fmt!("Not building any crates for dependency %s", p.to_str()));
+                        return workspace.clone();
+                    }
+                }
+            }
             // Build it!
-            let rs_path = pkg_src.build(exec, self, cfgs);
+            let rs_path = pkg_src.build(self, cfgs);
             Path(rs_path)
         }
         else {
@@ -452,56 +474,54 @@ impl CtxMethods for BuildContext {
         fail!("info not yet implemented");
     }
 
-    fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
-
-        let id = &pkg_src.id;
-
-        let installed_files = RWArc::new(~[]);
-        let inputs = RWArc::new(~[]);
-        // FIXME #7402: Use RUST_PATH to determine target dir
-        self.workcache_context.with_prep(id.to_str(), |p| pkg_src.declare_inputs(p));
-        do self.workcache_context.with_prep(id.to_str()) |prep| {
-            let sub_inputs = inputs.clone();
-            let sub_files  = installed_files.clone();
-            let subsrc = pkg_src.clone();
-            let subself = self.clone();
-            let id_str = id.to_str();
-            let sub_id = id.clone();
-            sub_inputs.write(|r| *r = prep.lookup_declared_inputs().map(|v|
-                                          { (~"file", (*v).clone()) }));
-            do prep.exec |exec| {
-                let destination_workspace = subself.build(exec, subsrc.clone()).to_str();
-                // See #7402: This still isn't quite right yet; we want to
-                // install to the first workspace in the RUST_PATH if there's
-                // a non-default RUST_PATH. This code installs to the same
-                // workspace the package was built in.
-                let actual_workspace = if path_util::user_set_rust_path() {
-                    default_workspace()
-                }
-                else {
-                    Path(destination_workspace)
-                };
-                debug!("install: destination workspace = %s, id = %s, installing to %s",
-                       destination_workspace, id_str, actual_workspace.to_str());
-                let result = subself.install_no_build(&Path(destination_workspace),
-                                                      &actual_workspace,
-                                                      &sub_id);
-                debug!("install: id = %s, about to call discover_outputs, %?",
-                       id_str, result.to_str());
-
-                discover_outputs(exec, result.clone());
-                sub_files.write(|r| { *r = result.clone(); });
-                sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
-                note(fmt!("Installed package %s to %s", id_str, actual_workspace.to_str()));
+    fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
+
+        let id = pkg_src.id.clone();
+
+        let mut installed_files = ~[];
+        let inputs = ~[];
+
+        // workcache only knows about *crates*. Building a package
+        // just means inferring all the crates in it, then building each one.
+        let destination_workspace = self.build(&mut pkg_src, what).to_str();
+
+        let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
+                      pkg_src.tests.clone(), pkg_src.benchs.clone()];
+        debug!("In declare inputs for %s", id.to_str());
+        for cs in to_do.iter() {
+            for c in cs.iter() {
+                let path = pkg_src.start_dir.push_rel(&c.file).normalize();
+                debug!("Recording input: %s", path.to_str());
+                installed_files.push(path);
             }
+        }
+        // See #7402: This still isn't quite right yet; we want to
+        // install to the first workspace in the RUST_PATH if there's
+        // a non-default RUST_PATH. This code installs to the same
+        // workspace the package was built in.
+        let actual_workspace = if path_util::user_set_rust_path() {
+            default_workspace()
+        }
+            else {
+            Path(destination_workspace)
         };
-        (installed_files.unwrap(), inputs.unwrap())
+        debug!("install: destination workspace = %s, id = %s, installing to %s",
+               destination_workspace, id.to_str(), actual_workspace.to_str());
+        let result = self.install_no_build(&Path(destination_workspace),
+                                           &actual_workspace,
+                                           &id).map(|s| Path(*s));
+        debug!("install: id = %s, about to call discover_outputs, %?",
+               id.to_str(), result.to_str());
+        installed_files = installed_files + result;
+        note(fmt!("Installed package %s to %s", id.to_str(), actual_workspace.to_str()));
+        (installed_files, inputs)
     }
 
+    // again, working around lack of Encodable for Path
     fn install_no_build(&self,
                         source_workspace: &Path,
                         target_workspace: &Path,
-                        id: &PkgId) -> ~[Path] {
+                        id: &PkgId) -> ~[~str] {
         use conditions::copy_failed::cond;
 
         // Now copy stuff into the install dirs
@@ -511,32 +531,59 @@ impl CtxMethods for BuildContext {
         let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
 
         debug!("target_exec = %s target_lib = %? \
-                maybe_executable = %? maybe_library = %?",
+               maybe_executable = %? maybe_library = %?",
                target_exec.to_str(), target_lib,
                maybe_executable, maybe_library);
 
-        let mut outputs = ~[];
-
-        for exec in maybe_executable.iter() {
-            debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
-            if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
-                 os::copy_file(exec, &target_exec)) {
-                cond.raise(((*exec).clone(), target_exec.clone()));
+        do self.workcache_context.with_prep(id.install_tag()) |prep| {
+            for ee in maybe_executable.iter() {
+                prep.declare_input("binary",
+                                   ee.to_str(),
+                                   workcache_support::digest_only_date(ee));
             }
-            outputs.push(target_exec.clone());
-        }
-        for lib in maybe_library.iter() {
-            let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \
-                                                didn't install it!", lib.to_str()));
-            let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib"));
-            debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
-            if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
-                 os::copy_file(lib, &target_lib)) {
-                cond.raise(((*lib).clone(), target_lib.clone()));
+            for ll in maybe_library.iter() {
+                prep.declare_input("binary",
+                                   ll.to_str(),
+                                   workcache_support::digest_only_date(ll));
+            }
+            let subex = maybe_executable.clone();
+            let sublib = maybe_library.clone();
+            let sub_target_ex = target_exec.clone();
+            let sub_target_lib = target_lib.clone();
+
+            do prep.exec |exe_thing| {
+                let mut outputs = ~[];
+
+                for exec in subex.iter() {
+                    debug!("Copying: %s -> %s", exec.to_str(), sub_target_ex.to_str());
+                    if !(os::mkdir_recursive(&sub_target_ex.dir_path(), U_RWX) &&
+                         os::copy_file(exec, &sub_target_ex)) {
+                        cond.raise(((*exec).clone(), sub_target_ex.clone()));
+                    }
+                    exe_thing.discover_output("binary",
+                        sub_target_ex.to_str(),
+                        workcache_support::digest_only_date(&sub_target_ex));
+                    outputs.push(sub_target_ex.to_str());
+                }
+                for lib in sublib.iter() {
+                    let target_lib = sub_target_lib
+                        .clone().expect(fmt!("I built %s but apparently \
+                                             didn't install it!", lib.to_str()));
+                    let target_lib = target_lib
+                        .pop().push(lib.filename().expect("weird target lib"));
+                    debug!("Copying: %s -> %s", lib.to_str(), sub_target_lib.to_str());
+                    if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
+                         os::copy_file(lib, &target_lib)) {
+                        cond.raise(((*lib).clone(), target_lib.clone()));
+                    }
+                    exe_thing.discover_output("binary",
+                                              target_lib.to_str(),
+                                              workcache_support::digest_only_date(&target_lib));
+                    outputs.push(target_lib.to_str());
+                }
+                outputs
             }
-            outputs.push(target_lib.clone());
         }
-        outputs
     }
 
     fn prefer(&self, _id: &str, _vers: Option<~str>)  {
@@ -594,53 +641,53 @@ pub fn main_args(args: &[~str]) {
     let matches = &match getopts::getopts(args, opts) {
         result::Ok(m) => m,
         result::Err(f) => {
-            error(fmt!("%s", getopts::fail_str(f)));
+            error(fmt!("%s", f.to_err_msg()));
 
             return;
         }
     };
-    let mut help = getopts::opt_present(matches, "h") ||
-                   getopts::opt_present(matches, "help");
-    let no_link = getopts::opt_present(matches, "no-link");
-    let no_trans = getopts::opt_present(matches, "no-trans");
-    let supplied_sysroot = getopts::opt_val(matches, "sysroot");
-    let generate_asm = getopts::opt_present(matches, "S") ||
-        getopts::opt_present(matches, "assembly");
-    let parse_only = getopts::opt_present(matches, "parse-only");
-    let pretty = getopts::opt_present(matches, "pretty");
-    let emit_llvm = getopts::opt_present(matches, "emit-llvm");
-
-    if getopts::opt_present(matches, "v") ||
-       getopts::opt_present(matches, "version") {
+    let mut help = matches.opt_present("h") ||
+                   matches.opt_present("help");
+    let no_link = matches.opt_present("no-link");
+    let no_trans = matches.opt_present("no-trans");
+    let supplied_sysroot = matches.opt_val("sysroot");
+    let generate_asm = matches.opt_present("S") ||
+        matches.opt_present("assembly");
+    let parse_only = matches.opt_present("parse-only");
+    let pretty = matches.opt_present("pretty");
+    let emit_llvm = matches.opt_present("emit-llvm");
+
+    if matches.opt_present("v") ||
+       matches.opt_present("version") {
         rustc::version(args[0]);
         return;
     }
 
-    let use_rust_path_hack = getopts::opt_present(matches, "r") ||
-                             getopts::opt_present(matches, "rust-path-hack");
+    let use_rust_path_hack = matches.opt_present("r") ||
+                             matches.opt_present("rust-path-hack");
 
-    let linker = getopts::opt_maybe_str(matches, "linker");
-    let link_args = getopts::opt_maybe_str(matches, "link-args");
-    let cfgs = getopts::opt_strs(matches, "cfg") + getopts::opt_strs(matches, "c");
+    let linker = matches.opt_str("linker");
+    let link_args = matches.opt_str("link-args");
+    let cfgs = matches.opt_strs("cfg") + matches.opt_strs("c");
     let mut user_supplied_opt_level = true;
-    let opt_level = match getopts::opt_maybe_str(matches, "opt-level") {
+    let opt_level = match matches.opt_str("opt-level") {
         Some(~"0") => session::No,
         Some(~"1") => session::Less,
         Some(~"2") => session::Default,
         Some(~"3") => session::Aggressive,
-        _ if getopts::opt_present(matches, "O") => session::Default,
+        _ if matches.opt_present("O") => session::Default,
         _ => {
             user_supplied_opt_level = false;
             session::No
         }
     };
 
-    let save_temps = getopts::opt_present(matches, "save-temps");
-    let target     = getopts::opt_maybe_str(matches, "target");
-    let target_cpu = getopts::opt_maybe_str(matches, "target-cpu");
+    let save_temps = matches.opt_present("save-temps");
+    let target     = matches.opt_str("target");
+    let target_cpu = matches.opt_str("target-cpu");
     let experimental_features = {
-        let strs = getopts::opt_strs(matches, "Z");
-        if getopts::opt_present(matches, "Z") {
+        let strs = matches.opt_strs("Z");
+        if matches.opt_present("Z") {
             Some(strs)
         }
         else {
@@ -726,15 +773,27 @@ pub fn main_args(args: &[~str]) {
 
     debug!("Using sysroot: %s", sroot.to_str());
     debug!("Will store workcache in %s", default_workspace().to_str());
-    BuildContext {
-        context: Context {
-        cfgs: cfgs,
-        rustc_flags: rustc_flags,
-        use_rust_path_hack: use_rust_path_hack,
-        sysroot: sroot, // Currently, only tests override this
-    },
-        workcache_context: api::default_context(default_workspace()).workcache_context
-    }.run(*cmd, remaining_args)
+
+    let rm_args = remaining_args.clone();
+    let sub_cmd = cmd.clone();
+    // Wrap the rest in task::try in case of a condition failure in a task
+    let result = do task::try {
+        BuildContext {
+            context: Context {
+                cfgs: cfgs.clone(),
+                rustc_flags: rustc_flags.clone(),
+                use_rust_path_hack: use_rust_path_hack,
+                sysroot: sroot.clone(), // Currently, only tests override this
+            },
+            workcache_context: api::default_context(default_workspace()).workcache_context
+        }.run(sub_cmd, rm_args.clone())
+    };
+    // FIXME #9262: This is using the same error code for all errors,
+    // and at least one test case succeeds if rustpkg returns copy_failed_code,
+    // when actually, it might set the exit code for that even if a different
+    // unhandled condition got raised.
+    if result.is_err() { os::set_exit_status(copy_failed_code); }
+
 }
 
 /**
diff --git a/src/librustpkg/target.rs b/src/librustpkg/target.rs
index 03c2f5a4fe4..9d3ad1f39a7 100644
--- a/src/librustpkg/target.rs
+++ b/src/librustpkg/target.rs
@@ -16,8 +16,45 @@ pub enum OutputType { Main, Lib, Bench, Test }
 
 #[deriving(Eq)]
 pub enum Target {
-    // In-place build
+    /// In-place build
     Build,
-    // Install to bin/ or lib/ dir
+    /// Install to bin/ or lib/ dir
     Install
 }
+
+#[deriving(Eq, Clone)]
+pub enum WhatToBuild {
+    /// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
+    JustOne(Path),
+    /// Build everything
+    Everything
+}
+
+pub fn is_lib(p: &Path) -> bool {
+    file_is(p, "lib")
+}
+
+pub fn is_main(p: &Path) -> bool {
+    file_is(p, "main")
+}
+
+pub fn is_test(p: &Path) -> bool {
+    file_is(p, "test")
+}
+
+pub fn is_bench(p: &Path) -> bool {
+    file_is(p, "bench")
+}
+
+fn file_is(p: &Path, stem: &str) -> bool {
+    match p.filestem() {
+        Some(s) if s == stem => true,
+        _ => false
+    }
+}
+
+pub fn lib_name_of(p: &Path) -> Path {
+    p.push("lib.rs")
+}
+
+pub static lib_crate_filename: &'static str = "lib.rs";
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index 952931fa97a..918cc366799 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -34,11 +34,7 @@ use rustc::driver::driver::{build_session, build_session_options, host_triple, o
 use syntax::diagnostic;
 use target::*;
 use package_source::PkgSrc;
-
-/// Returns the last-modified date as an Option
-fn datestamp(p: &Path) -> Option<libc::time_t> {
-    p.stat().map(|stat| stat.st_mtime)
-}
+use util::datestamp;
 
 fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
     let context = workcache::Context::new(
@@ -224,18 +220,26 @@ fn rustpkg_exec() -> Path {
 }
 
 fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
-    command_line_test_with_env(args, cwd, None).expect("Command line test failed")
+    match command_line_test_with_env(args, cwd, None) {
+        Success(r) => r,
+        _ => fail!("Command line test failed")
+    }
 }
 
-fn command_line_test_partial(args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
+fn command_line_test_partial(args: &[~str], cwd: &Path) -> ProcessResult {
     command_line_test_with_env(args, cwd, None)
 }
 
+enum ProcessResult {
+    Success(ProcessOutput),
+    Fail(int) // exit code
+}
+
 /// Runs `rustpkg` (based on the directory that this executable was
 /// invoked from) with the given arguments, in the given working directory.
 /// Returns the process's output.
 fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
-    -> Option<ProcessOutput> {
+    -> ProcessResult {
     let cmd = rustpkg_exec().to_str();
     let env_str = match env {
         Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
@@ -266,10 +270,10 @@ to make sure the command succeeded
         debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
               cmd, args, output.status,
               str::from_utf8(output.output) + str::from_utf8(output.error));
-        None
+        Fail(output.status)
     }
     else {
-        Some(output)
+        Success(output)
     }
 }
 
@@ -410,8 +414,11 @@ fn command_line_test_output(args: &[~str]) -> ~[~str] {
 
 fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
     let mut result = ~[];
-    let p_output = command_line_test_with_env(args,
-        &os::getcwd(), Some(env)).expect("Command-line test failed");
+    let p_output = match command_line_test_with_env(args,
+        &os::getcwd(), Some(env)) {
+        Fail(_) => fail!("Command-line test failed"),
+        Success(r) => r
+    };
     let test_output = str::from_utf8(p_output.output);
     for s in test_output.split_iter('\n') {
         result.push(s.to_owned());
@@ -420,9 +427,9 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~
 }
 
 // assumes short_name and path are one and the same -- I should fix
-fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path {
-    debug!("lib_output_file_name: given %s and parent %s and short name %s",
-           workspace.to_str(), parent, short_name);
+fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
+    debug!("lib_output_file_name: given %s and short name %s",
+           workspace.to_str(), short_name);
     library_in_workspace(&Path(short_name),
                          short_name,
                          Build,
@@ -450,19 +457,18 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
 }
 
 /// Add a comment at the end
-fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
+fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) {
     use conditions::bad_path::cond;
     let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
-    let contents = os::list_dir_path(&pkg_src_dir);
     let mut maybe_p = None;
-    for p in contents.iter() {
-        if p.filetype() == Some(".rs") {
-            maybe_p = Some(p);
-            break;
-        }
+    let maybe_file = pkg_src_dir.push(filename);
+    debug!("Trying to frob %s -- %s", pkg_src_dir.to_str(), filename);
+    if os::path_exists(&maybe_file) {
+        maybe_p = Some(maybe_file);
     }
+    debug!("Frobbed? %?", maybe_p);
     match maybe_p {
-        Some(p) => {
+        Some(ref p) => {
             let w = io::file_writer(p, &[io::Append]);
             match w {
                 Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
@@ -499,7 +505,7 @@ fn test_install_valid() {
     debug!("temp_workspace = %s", temp_workspace.to_str());
     // should have test, bench, lib, and main
     let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
-    ctxt.install(src);
+    ctxt.install(src, &Everything);
     // Check that all files exist
     let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
     debug!("exec = %s", exec.to_str());
@@ -528,7 +534,7 @@ fn test_install_invalid() {
     // Uses task::try because of #9001
     let result = do task::try {
         let pkg_src = PkgSrc::new(temp_workspace.clone(), false, pkgid.clone());
-        ctxt.install(pkg_src);
+        ctxt.install(pkg_src, &Everything);
     };
     // Not the best test -- doesn't test that we failed in the right way.
     // Best we can do for now.
@@ -939,26 +945,28 @@ fn no_rebuilding() {
 }
 
 #[test]
-#[ignore]
 fn no_rebuilding_dep() {
     let p_id = PkgId::new("foo");
     let dep_id = PkgId::new("bar");
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     command_line_test([~"build", ~"foo"], &workspace);
-    let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
-                                                  ".rust",
-                                                  "bar"));
-    let foo_date_1 = datestamp(&output_file_name(&workspace, ~"foo"));
+    let bar_lib = lib_output_file_name(&workspace, "bar");
+    let bar_date_1 = datestamp(&bar_lib);
+
+    frob_source_file(&workspace, &p_id, "main.rs");
+
+    // Now make `bar` read-only so that subsequent rebuilds of it will fail
+    assert!(chmod_read_only(&bar_lib));
+
+    match command_line_test_partial([~"build", ~"foo"], &workspace) {
+        Success(*) => (), // ok
+        Fail(status) if status == 65 => fail!("no_rebuilding_dep failed: it tried to rebuild bar"),
+        Fail(_) => fail!("no_rebuilding_dep failed for some other reason")
+    }
 
-    frob_source_file(&workspace, &p_id);
-    command_line_test([~"build", ~"foo"], &workspace);
     let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
-                                                  ".rust",
-                                                  "bar"));
-    let foo_date_2 = datestamp(&output_file_name(&workspace, ~"foo"));
+                                                   "bar"));
     assert_eq!(bar_date_1, bar_date_2);
-    assert!(foo_date_1 < foo_date_2);
-    assert!(foo_date_1 > bar_date_1);
 }
 
 #[test]
@@ -967,7 +975,7 @@ fn do_rebuild_dep_dates_change() {
     let dep_id = PkgId::new("bar");
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     command_line_test([~"build", ~"foo"], &workspace);
-    let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
+    let bar_lib_name = lib_output_file_name(&workspace, "bar");
     let bar_date = datestamp(&bar_lib_name);
     debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
     touch_source_file(&workspace, &dep_id);
@@ -983,11 +991,11 @@ fn do_rebuild_dep_only_contents_change() {
     let dep_id = PkgId::new("bar");
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     command_line_test([~"build", ~"foo"], &workspace);
-    let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
-    frob_source_file(&workspace, &dep_id);
+    let bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
+    frob_source_file(&workspace, &dep_id, "lib.rs");
     // should adjust the datestamp
     command_line_test([~"build", ~"foo"], &workspace);
-    let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+    let new_bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
     assert!(new_bar_date > bar_date);
 }
 
@@ -1309,7 +1317,6 @@ fn rust_path_hack_build_no_arg() {
 }
 
 #[test]
-#[ignore (reason = "#7402 not yet implemented")]
 fn rust_path_install_target() {
     let dir_for_path = mkdtemp(&os::tmpdir(),
         "source_workspace").expect("rust_path_install_target failed");
@@ -1464,10 +1471,13 @@ fn test_cfg_fail() {
     let workspace = create_local_package(&p_id);
     writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
                "#[cfg(quux)] fn main() {}");
-    assert!(command_line_test_partial([test_sysroot().to_str(),
+    match command_line_test_partial([test_sysroot().to_str(),
                        ~"build",
                        ~"foo"],
-                      &workspace).is_none());
+                      &workspace) {
+        Success(*) => fail!("test_cfg_fail failed"),
+        _          => ()
+    }
 }
 
 
@@ -1680,6 +1690,21 @@ fn test_target_specific_install_dir() {
     assert_executable_exists(&workspace, "foo");
 }
 
+#[test]
+fn test_dependencies_terminate() {
+ //   let a_id = PkgId::new("a");
+    let b_id = PkgId::new("b");
+//    let workspace = create_local_package_with_dep(&b_id, &a_id);
+    let workspace = create_local_package(&b_id);
+    let b_dir = workspace.push_many([~"src", ~"b-0.1"]);
+  //  writeFile(&b_dir.push("lib.rs"), "extern mod a; pub fn f() {}");
+    let b_subdir = b_dir.push("test");
+    assert!(os::mkdir_recursive(&b_subdir, U_RWX));
+    writeFile(&b_subdir.push("test.rs"),
+              "extern mod b; use b::f; #[test] fn g() { f() }");
+    command_line_test([~"install", ~"b"], &workspace);
+}
+
 /// Returns true if p exists and is executable
 fn is_executable(p: &Path) -> bool {
     use std::libc::consts::os::posix88::{S_IXUSR};
@@ -1689,3 +1714,25 @@ fn is_executable(p: &Path) -> bool {
         Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint
     }
 }
+
+#[cfg(target_os = "win32")]
+fn chmod_read_only(p: &Path) -> bool {
+    #[fixed_stack_segment];
+    unsafe {
+        do p.to_str().with_c_str |src_buf| {
+            libc::chmod(src_buf, libc::consts::os::posix88::S_IRUSR as c_int) == 0 as libc::c_int
+        }
+    }
+}
+
+#[cfg(not(target_os = "win32"))]
+fn chmod_read_only(p: &Path) -> bool {
+    #[fixed_stack_segment];
+    unsafe {
+        do p.to_str().with_c_str |src_buf| {
+            libc::chmod(src_buf,
+                        libc::consts::os::posix88::S_IRUSR as libc::mode_t) == 0
+                as libc::c_int
+        }
+    }
+}
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index ab883b50f8c..64f76dcdc60 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::libc;
 use std::os;
 use extra::workcache;
 use rustc::driver::{driver, session};
@@ -26,7 +27,7 @@ use workspace::pkg_parent_workspaces;
 use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
 use messages::error;
 
-pub use target::{OutputType, Main, Lib, Bench, Test};
+pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
 use workcache_support::{digest_file_with_date, digest_only_date};
 
 // It would be nice to have the list of commands in just one place -- for example,
@@ -171,6 +172,8 @@ pub fn compile_input(context: &BuildContext,
     // not sure if we should support anything else
 
     let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path);
+    // Make the output directory if it doesn't exist already
+    assert!(os::mkdir_recursive(&out_dir, U_RWX));
 
     let binary = os::args()[0].to_managed();
 
@@ -220,7 +223,7 @@ pub fn compile_input(context: &BuildContext,
         optimize: if opt { session::Aggressive } else { session::No },
         test: what == Test || what == Bench,
         maybe_sysroot: Some(sysroot_to_use),
-        addl_lib_search_paths: @mut (~[out_dir.clone()]),
+        addl_lib_search_paths: @mut (~[]),
         output_type: output_type,
         .. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
     };
@@ -329,6 +332,9 @@ pub fn compile_crate_from_input(input: &Path,
     // Register dependency on the source file
     exec.discover_input("file", input.to_str(), digest_file_with_date(input));
 
+    debug!("Built %s, date = %?", outputs.out_filename.to_str(),
+           datestamp(&outputs.out_filename));
+
     Some(outputs.out_filename)
 }
 
@@ -409,7 +415,8 @@ pub fn find_and_install_dependencies(context: &BuildContext,
                             workspaces[0]
                         };
                         let (outputs_disc, inputs_disc) =
-                            context.install(PkgSrc::new(dep_workspace.clone(), false, pkg_id));
+                            context.install(PkgSrc::new(dep_workspace.clone(),
+                                false, pkg_id), &JustOne(Path(lib_crate_filename)));
                         debug!("Installed %s, returned %? dependencies and \
                                %? transitive dependencies",
                                lib_name, outputs_disc.len(), inputs_disc.len());
@@ -435,10 +442,11 @@ pub fn find_and_install_dependencies(context: &BuildContext,
                         debug!("Adding additional search path: %s", lib_name);
                         let installed_library =
                             installed_library_in_workspace(&Path(lib_name), &dep_workspace)
-                                .expect( fmt!("rustpkg failed to install dependency %s",
+                                .expect(fmt!("rustpkg failed to install dependency %s",
                                               lib_name));
                         let install_dir = installed_library.pop();
-                        debug!("Installed %s into %s", lib_name, install_dir.to_str());
+                        debug!("Installed %s into %s [%?]", lib_name, install_dir.to_str(),
+                               datestamp(&installed_library));
                         save(install_dir);
                     }
                 }}
@@ -449,37 +457,6 @@ pub fn find_and_install_dependencies(context: &BuildContext,
     };
 }
 
-#[cfg(windows)]
-pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    /* FIXME (#1768): Investigate how to do this on win32
-       Node wraps symlinks by having a .bat,
-       but that won't work with minGW. */
-
-    false
-}
-
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "android")]
-#[cfg(target_os = "freebsd")]
-#[cfg(target_os = "macos")]
-pub fn link_exe(src: &Path, dest: &Path) -> bool {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    use std::c_str::ToCStr;
-    use std::libc;
-
-    unsafe {
-        do src.with_c_str |src_buf| {
-            do dest.with_c_str |dest_buf| {
-                libc::link(src_buf, dest_buf) == 0 as libc::c_int &&
-                    libc::chmod(dest_buf, 755) == 0 as libc::c_int
-            }
-        }
-    }
-}
-
 pub fn mk_string_lit(s: @str) -> ast::lit {
     Spanned {
         node: ast::lit_str(s),
@@ -516,3 +493,12 @@ pub fn option_to_vec<T>(x: Option<T>) -> ~[T] {
 // tjc: cheesy
 fn debug_flags() -> ~[~str] { ~[] }
 // static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
+
+
+/// Returns the last-modified date as an Option
+pub fn datestamp(p: &Path) -> Option<libc::time_t> {
+    debug!("Scrutinizing datestamp for %s - does it exist? %?", p.to_str(), os::path_exists(p));
+    let out = p.stat().map(|stat| stat.st_mtime);
+    debug!("Date = %?", out);
+    out.map(|t| { *t as libc::time_t })
+}
diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs
index e2416782d98..daf35c988c8 100644
--- a/src/librustpkg/workcache_support.rs
+++ b/src/librustpkg/workcache_support.rs
@@ -56,3 +56,8 @@ pub fn discover_outputs(e: &mut workcache::Exec, outputs: ~[Path]) {
         e.discover_output("binary", p.to_str(), digest_only_date(p));
     }
 }
+
+/// Returns the function name for building a crate
+pub fn crate_tag(p: &Path) -> ~str {
+    p.to_str() // implicitly, it's "build(p)"...
+}
diff --git a/src/libstd/borrow.rs b/src/libstd/borrow.rs
index 6c3d4c5f1fb..0626b3fc618 100644
--- a/src/libstd/borrow.rs
+++ b/src/libstd/borrow.rs
@@ -22,7 +22,7 @@ pub fn to_uint<T>(thing: &T) -> uint {
 /// Determine if two borrowed pointers point to the same thing.
 #[inline]
 pub fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool {
-    to_uint(thing) == to_uint(other)
+    (thing as *T) == (other as *T)
 }
 
 // Equality for region pointers
@@ -70,3 +70,17 @@ impl<'self, T: TotalEq> TotalEq for &'self T {
     #[inline]
     fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::ref_eq;
+
+    #[test]
+    fn test_ref_eq() {
+        let x = 1;
+        let y = 1;
+
+        assert!(ref_eq(&x, &x));
+        assert!(!ref_eq(&x, &y));
+    }
+}
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
index 75598b300a3..67b5aff8466 100644
--- a/src/libstd/c_str.rs
+++ b/src/libstd/c_str.rs
@@ -30,9 +30,7 @@ pub enum NullByteResolution {
 
 condition! {
     // This should be &[u8] but there's a lifetime issue (#5370).
-    // NOTE: this super::NullByteResolution should be NullByteResolution
-    // Change this next time the snapshot is updated.
-    pub null_byte: (~[u8]) -> super::NullByteResolution;
+    pub null_byte: (~[u8]) -> NullByteResolution;
 }
 
 /// The representation of a C String.
diff --git a/src/libstd/char.rs b/src/libstd/char.rs
index 911d883f88a..431fc27a202 100644
--- a/src/libstd/char.rs
+++ b/src/libstd/char.rs
@@ -281,11 +281,11 @@ pub fn escape_unicode(c: char, f: &fn(char)) {
     // avoid calling str::to_str_radix because we don't really need to allocate
     // here.
     f('\\');
-    let pad = cond!(
-        (c <= '\xff')   { f('x'); 2 }
-        (c <= '\uffff') { f('u'); 4 }
-        _               { f('U'); 8 }
-    );
+    let pad = match () {
+        _ if c <= '\xff'    => { f('x'); 2 }
+        _ if c <= '\uffff'  => { f('u'); 4 }
+        _                   => { f('U'); 8 }
+    };
     for offset in range_step::<i32>(4 * (pad - 1), -1, -4) {
         unsafe {
             match ((c as i32) >> offset) & 0xf {
@@ -329,13 +329,13 @@ pub fn len_utf8_bytes(c: char) -> uint {
     static MAX_FOUR_B:  uint = 2097152u;
 
     let code = c as uint;
-    cond!(
-        (code < MAX_ONE_B)   { 1u }
-        (code < MAX_TWO_B)   { 2u }
-        (code < MAX_THREE_B) { 3u }
-        (code < MAX_FOUR_B)  { 4u }
-        _ { fail!("invalid character!") }
-    )
+    match () {
+        _ if code < MAX_ONE_B   => 1u,
+        _ if code < MAX_TWO_B   => 2u,
+        _ if code < MAX_THREE_B => 3u,
+        _ if code < MAX_FOUR_B  => 4u,
+        _                       => fail!("invalid character!"),
+    }
 }
 
 impl ToStr for char {
diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs
index 790dc886c04..a5a2def450e 100644
--- a/src/libstd/libc.rs
+++ b/src/libstd/libc.rs
@@ -294,7 +294,6 @@ pub mod types {
                 pub type ssize_t = i32;
             }
             #[cfg(target_arch = "x86")]
-            #[cfg(target_arch = "mips")]
             pub mod posix01 {
                 use libc::types::os::arch::c95::{c_short, c_long, time_t};
                 use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t};
@@ -305,7 +304,6 @@ pub mod types {
                 pub type blksize_t = i32;
                 pub type blkcnt_t = i32;
 
-                #[cfg(target_arch = "x86")]
                 pub struct stat {
                     st_dev: dev_t,
                     __pad1: c_short,
@@ -328,30 +326,6 @@ pub mod types {
                     __unused4: c_long,
                     __unused5: c_long,
                 }
-
-                #[cfg(target_arch = "mips")]
-                pub struct stat {
-                    st_dev: c_ulong,
-                    st_pad1: [c_long, ..3],
-                    st_ino: ino_t,
-                    st_mode: mode_t,
-                    st_nlink: nlink_t,
-                    st_uid: uid_t,
-                    st_gid: gid_t,
-                    st_rdev: c_ulong,
-                    st_pad2: [c_long, ..2],
-                    st_size: off_t,
-                    st_pad3: c_long,
-                    st_atime: time_t,
-                    st_atime_nsec: c_long,
-                    st_mtime: time_t,
-                    st_mtime_nsec: c_long,
-                    st_ctime: time_t,
-                    st_ctime_nsec: c_long,
-                    st_blksize: blksize_t,
-                    st_blocks: blkcnt_t,
-                    st_pad5: [c_long, ..14],
-                }
             }
             #[cfg(target_arch = "arm")]
             pub mod posix01 {
@@ -385,6 +359,40 @@ pub mod types {
                     st_ino: c_ulonglong
                 }
             }
+            #[cfg(target_arch = "mips")]
+            pub mod posix01 {
+                use libc::types::os::arch::c95::{c_long, c_ulong, time_t};
+                use libc::types::os::arch::posix88::{gid_t, ino_t};
+                use libc::types::os::arch::posix88::{mode_t, off_t};
+                use libc::types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u32;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i32;
+
+                pub struct stat {
+                    st_dev: c_ulong,
+                    st_pad1: [c_long, ..3],
+                    st_ino: ino_t,
+                    st_mode: mode_t,
+                    st_nlink: nlink_t,
+                    st_uid: uid_t,
+                    st_gid: gid_t,
+                    st_rdev: c_ulong,
+                    st_pad2: [c_long, ..2],
+                    st_size: off_t,
+                    st_pad3: c_long,
+                    st_atime: time_t,
+                    st_atime_nsec: c_long,
+                    st_mtime: time_t,
+                    st_mtime_nsec: c_long,
+                    st_ctime: time_t,
+                    st_ctime_nsec: c_long,
+                    st_blksize: blksize_t,
+                    st_blocks: blkcnt_t,
+                    st_pad5: [c_long, ..14],
+                }
+            }
             pub mod posix08 {}
             pub mod bsd44 {}
             pub mod extra {}
@@ -1633,6 +1641,111 @@ pub mod consts {
             pub static EPIPE : c_int = 32;
             pub static EDOM : c_int = 33;
             pub static ERANGE : c_int = 34;
+
+            pub static ENOMSG: c_int = 35;
+            pub static EIDRM: c_int = 36;
+            pub static ECHRNG: c_int = 37;
+            pub static EL2NSYNC: c_int = 38;
+            pub static EL3HLT: c_int = 39;
+            pub static EL3RST: c_int = 40;
+            pub static ELNRNG: c_int = 41;
+            pub static EUNATCH: c_int = 42;
+            pub static ENOCSI: c_int = 43;
+            pub static EL2HLT: c_int = 44;
+            pub static EDEADLK: c_int = 45;
+            pub static ENOLCK: c_int = 46;
+            pub static EBADE: c_int = 50;
+            pub static EBADR: c_int = 51;
+            pub static EXFULL: c_int = 52;
+            pub static ENOANO: c_int = 53;
+            pub static EBADRQC: c_int = 54;
+            pub static EBADSLT: c_int = 55;
+            pub static EDEADLOCK: c_int = 56;
+            pub static EBFONT: c_int = 59;
+            pub static ENOSTR: c_int = 60;
+            pub static ENODATA: c_int = 61;
+            pub static ETIME: c_int = 62;
+            pub static ENOSR: c_int = 63;
+            pub static ENONET: c_int = 64;
+            pub static ENOPKG: c_int = 65;
+            pub static EREMOTE: c_int = 66;
+            pub static ENOLINK: c_int = 67;
+            pub static EADV: c_int = 68;
+            pub static ESRMNT: c_int = 69;
+            pub static ECOMM: c_int = 70;
+            pub static EPROTO: c_int = 71;
+            pub static EDOTDOT: c_int = 73;
+            pub static EMULTIHOP: c_int = 74;
+            pub static EBADMSG: c_int = 77;
+            pub static ENAMETOOLONG: c_int = 78;
+            pub static EOVERFLOW: c_int = 79;
+            pub static ENOTUNIQ: c_int = 80;
+            pub static EBADFD: c_int = 81;
+            pub static EREMCHG: c_int = 82;
+            pub static ELIBACC: c_int = 83;
+            pub static ELIBBAD: c_int = 84;
+            pub static ELIBSCN: c_int = 95;
+            pub static ELIBMAX: c_int = 86;
+            pub static ELIBEXEC: c_int = 87;
+            pub static EILSEQ: c_int = 88;
+            pub static ENOSYS: c_int = 89;
+            pub static ELOOP: c_int = 90;
+            pub static ERESTART: c_int = 91;
+            pub static ESTRPIPE: c_int = 92;
+            pub static ENOTEMPTY: c_int = 93;
+            pub static EUSERS: c_int = 94;
+            pub static ENOTSOCK: c_int = 95;
+            pub static EDESTADDRREQ: c_int = 96;
+            pub static EMSGSIZE: c_int = 97;
+            pub static EPROTOTYPE: c_int = 98;
+            pub static ENOPROTOOPT: c_int = 99;
+            pub static EPROTONOSUPPORT: c_int = 120;
+            pub static ESOCKTNOSUPPORT: c_int = 121;
+            pub static EOPNOTSUPP: c_int = 122;
+            pub static EPFNOSUPPORT: c_int = 123;
+            pub static EAFNOSUPPORT: c_int = 124;
+            pub static EADDRINUSE: c_int = 125;
+            pub static EADDRNOTAVAIL: c_int = 126;
+            pub static ENETDOWN: c_int = 127;
+            pub static ENETUNREACH: c_int = 128;
+            pub static ENETRESET: c_int = 129;
+            pub static ECONNABORTED: c_int = 130;
+            pub static ECONNRESET: c_int = 131;
+            pub static ENOBUFS: c_int = 132;
+            pub static EISCONN: c_int = 133;
+            pub static ENOTCONN: c_int = 134;
+            pub static EUCLEAN: c_int = 135;
+            pub static ENOTNAM: c_int = 137;
+            pub static ENAVAIL: c_int = 138;
+            pub static EISNAM: c_int = 139;
+            pub static EREMOTEIO: c_int = 140;
+            pub static ESHUTDOWN: c_int = 143;
+            pub static ETOOMANYREFS: c_int = 144;
+            pub static ETIMEDOUT: c_int = 145;
+            pub static ECONNREFUSED: c_int = 146;
+            pub static EHOSTDOWN: c_int = 147;
+            pub static EHOSTUNREACH: c_int = 148;
+            pub static EWOULDBLOCK: c_int = EAGAIN;
+            pub static EALREADY: c_int = 149;
+            pub static EINPROGRESS: c_int = 150;
+            pub static ESTALE: c_int = 151;
+            pub static ECANCELED: c_int = 158;
+
+            pub static ENOMEDIUM: c_int = 159;
+            pub static EMEDIUMTYPE: c_int = 160;
+            pub static ENOKEY: c_int = 161;
+            pub static EKEYEXPIRED: c_int = 162;
+            pub static EKEYREVOKED: c_int = 163;
+            pub static EKEYREJECTED: c_int = 164;
+
+            pub static EOWNERDEAD: c_int = 165;
+            pub static ENOTRECOVERABLE: c_int = 166;
+
+            pub static ERFKILL: c_int = 167;
+
+            pub static EHWPOISON: c_int = 168;
+
+            pub static EDQUOT: c_int = 1133;
         }
         pub mod posix01 {
             use libc::types::os::arch::c95::c_int;
diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs
index b39b3102a34..1a463a499cb 100644
--- a/src/libstd/logging.rs
+++ b/src/libstd/logging.rs
@@ -37,17 +37,6 @@ pub fn console_off() {
     rt::logging::console_off();
 }
 
-#[cfg(not(test), stage0)]
-#[lang="log_type"]
-#[allow(missing_doc)]
-pub fn log_type<T>(_level: u32, object: &T) {
-    use sys;
-
-    // XXX: Bad allocation
-    let msg = sys::log_str(object);
-    newsched_log_str(msg);
-}
-
 fn newsched_log_str(msg: ~str) {
     use rt::task::Task;
     use rt::local::Local;
diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs
index 0addcce3eb6..2787e028645 100644
--- a/src/libstd/num/f32.rs
+++ b/src/libstd/num/f32.rs
@@ -206,35 +206,35 @@ impl Orderable for f32 {
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn min(&self, other: &f32) -> f32 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self < *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self < *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn max(&self, other: &f32) -> f32 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self > *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self > *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns the number constrained within the range `mn <= self <= mx`.
     /// If any of the numbers are `NaN` then `NaN` is returned.
     #[inline]
     fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
-        cond!(
-            (self.is_NaN())   { *self }
-            (!(*self <= *mx)) { *mx   }
-            (!(*self >= *mn)) { *mn   }
-            _                 { *self }
-        )
+        match () {
+            _ if self.is_NaN()   => *self,
+            _ if !(*self <= *mx) => *mx,
+            _ if !(*self >= *mn) => *mn,
+            _                    => *self,
+        }
     }
 }
 
@@ -823,39 +823,6 @@ impl num::ToStrRadix for f32 {
 }
 
 ///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently,  '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number.  Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<f32> {
-    strconv::from_str_common(num, 10u, true, true, true,
-                             strconv::ExpDec, false, false)
-}
-
-///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
 ///
@@ -888,40 +855,65 @@ pub fn from_str_hex(num: &str) -> Option<f32> {
                              strconv::ExpBin, false, false)
 }
 
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
-    strconv::from_str_common(num, rdx, true, true, false,
-                             strconv::ExpNone, false, false)
-}
-
 impl FromStr for f32 {
+    ///
+    /// Convert a string in base 10 to a float.
+    /// Accepts a optional decimal exponent.
+    ///
+    /// This function accepts strings such as
+    ///
+    /// * '3.14'
+    /// * '+3.14', equivalent to '3.14'
+    /// * '-3.14'
+    /// * '2.5E10', or equivalently, '2.5e10'
+    /// * '2.5E-10'
+    /// * '.' (understood as 0)
+    /// * '5.'
+    /// * '.5', or, equivalently,  '0.5'
+    /// * '+inf', 'inf', '-inf', 'NaN'
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number.  Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
-    fn from_str(val: &str) -> Option<f32> { from_str(val) }
+    fn from_str(val: &str) -> Option<f32> {
+        strconv::from_str_common(val, 10u, true, true, true,
+                                 strconv::ExpDec, false, false)
+    }
 }
 
 impl num::FromStrRadix for f32 {
+    ///
+    /// Convert a string in an given base to a float.
+    ///
+    /// Due to possible conflicts, this function does **not** accept
+    /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+    /// does it recognize exponents of any kind.
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    /// * radix - The base to use. Must lie in the range [2 .. 36]
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number. Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
     fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
-        from_str_radix(val, rdx)
+        strconv::from_str_common(val, rdx, true, true, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs
index b0675278238..afc22ec212b 100644
--- a/src/libstd/num/f64.rs
+++ b/src/libstd/num/f64.rs
@@ -229,35 +229,35 @@ impl Orderable for f64 {
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn min(&self, other: &f64) -> f64 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self < *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self < *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn max(&self, other: &f64) -> f64 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self > *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self > *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns the number constrained within the range `mn <= self <= mx`.
     /// If any of the numbers are `NaN` then `NaN` is returned.
     #[inline]
     fn clamp(&self, mn: &f64, mx: &f64) -> f64 {
-        cond!(
-            (self.is_NaN())   { *self }
-            (!(*self <= *mx)) { *mx   }
-            (!(*self >= *mn)) { *mn   }
-            _                 { *self }
-        )
+        match () {
+            _ if self.is_NaN()   => *self,
+            _ if !(*self <= *mx) => *mx,
+            _ if !(*self >= *mn) => *mn,
+            _                    => *self,
+        }
     }
 }
 
@@ -870,39 +870,6 @@ impl num::ToStrRadix for f64 {
 }
 
 ///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently,  '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number.  Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<f64> {
-    strconv::from_str_common(num, 10u, true, true, true,
-                             strconv::ExpDec, false, false)
-}
-
-///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
 ///
@@ -935,40 +902,65 @@ pub fn from_str_hex(num: &str) -> Option<f64> {
                              strconv::ExpBin, false, false)
 }
 
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
-    strconv::from_str_common(num, rdx, true, true, false,
-                             strconv::ExpNone, false, false)
-}
-
 impl FromStr for f64 {
+    ///
+    /// Convert a string in base 10 to a float.
+    /// Accepts a optional decimal exponent.
+    ///
+    /// This function accepts strings such as
+    ///
+    /// * '3.14'
+    /// * '+3.14', equivalent to '3.14'
+    /// * '-3.14'
+    /// * '2.5E10', or equivalently, '2.5e10'
+    /// * '2.5E-10'
+    /// * '.' (understood as 0)
+    /// * '5.'
+    /// * '.5', or, equivalently,  '0.5'
+    /// * '+inf', 'inf', '-inf', 'NaN'
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number.  Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
-    fn from_str(val: &str) -> Option<f64> { from_str(val) }
+    fn from_str(val: &str) -> Option<f64> {
+        strconv::from_str_common(val, 10u, true, true, true,
+                                 strconv::ExpDec, false, false)
+    }
 }
 
 impl num::FromStrRadix for f64 {
+    ///
+    /// Convert a string in an given base to a float.
+    ///
+    /// Due to possible conflicts, this function does **not** accept
+    /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+    /// does it recognize exponents of any kind.
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    /// * radix - The base to use. Must lie in the range [2 .. 36]
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number. Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
     fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
-        from_str_radix(val, rdx)
+        strconv::from_str_common(val, rdx, true, true, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
diff --git a/src/libstd/num/float.rs b/src/libstd/num/float.rs
index 3952f5478f7..b86422edc03 100644
--- a/src/libstd/num/float.rs
+++ b/src/libstd/num/float.rs
@@ -188,39 +188,6 @@ impl num::ToStrRadix for float {
 }
 
 ///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently,  '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number.  Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<float> {
-    strconv::from_str_common(num, 10u, true, true, true,
-                             strconv::ExpDec, false, false)
-}
-
-///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
 ///
@@ -253,40 +220,65 @@ pub fn from_str_hex(num: &str) -> Option<float> {
                              strconv::ExpBin, false, false)
 }
 
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, radix: uint) -> Option<float> {
-    strconv::from_str_common(num, radix, true, true, false,
-                             strconv::ExpNone, false, false)
-}
-
 impl FromStr for float {
+    ///
+    /// Convert a string in base 10 to a float.
+    /// Accepts a optional decimal exponent.
+    ///
+    /// This function accepts strings such as
+    ///
+    /// * '3.14'
+    /// * '+3.14', equivalent to '3.14'
+    /// * '-3.14'
+    /// * '2.5E10', or equivalently, '2.5e10'
+    /// * '2.5E-10'
+    /// * '.' (understood as 0)
+    /// * '5.'
+    /// * '.5', or, equivalently,  '0.5'
+    /// * '+inf', 'inf', '-inf', 'NaN'
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number.  Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
-    fn from_str(val: &str) -> Option<float> { from_str(val) }
+    fn from_str(val: &str) -> Option<float> {
+        strconv::from_str_common(val, 10u, true, true, true,
+                                 strconv::ExpDec, false, false)
+    }
 }
 
 impl num::FromStrRadix for float {
+    ///
+    /// Convert a string in an given base to a float.
+    ///
+    /// Due to possible conflicts, this function does **not** accept
+    /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+    /// does it recognize exponents of any kind.
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    /// * radix - The base to use. Must lie in the range [2 .. 36]
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number. Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
     fn from_str_radix(val: &str, radix: uint) -> Option<float> {
-        from_str_radix(val, radix)
+        strconv::from_str_common(val, radix, true, true, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
@@ -1316,49 +1308,49 @@ mod tests {
 
     #[test]
     pub fn test_from_str() {
-        assert_eq!(from_str("3"), Some(3.));
-        assert_eq!(from_str("3.14"), Some(3.14));
-        assert_eq!(from_str("+3.14"), Some(3.14));
-        assert_eq!(from_str("-3.14"), Some(-3.14));
-        assert_eq!(from_str("2.5E10"), Some(25000000000.));
-        assert_eq!(from_str("2.5e10"), Some(25000000000.));
-        assert_eq!(from_str("25000000000.E-10"), Some(2.5));
-        assert_eq!(from_str("."), Some(0.));
-        assert_eq!(from_str(".e1"), Some(0.));
-        assert_eq!(from_str(".e-1"), Some(0.));
-        assert_eq!(from_str("5."), Some(5.));
-        assert_eq!(from_str(".5"), Some(0.5));
-        assert_eq!(from_str("0.5"), Some(0.5));
-        assert_eq!(from_str("-.5"), Some(-0.5));
-        assert_eq!(from_str("-5"), Some(-5.));
-        assert_eq!(from_str("inf"), Some(infinity));
-        assert_eq!(from_str("+inf"), Some(infinity));
-        assert_eq!(from_str("-inf"), Some(neg_infinity));
+        assert_eq!(from_str::<float>("3"), Some(3.));
+        assert_eq!(from_str::<float>("3.14"), Some(3.14));
+        assert_eq!(from_str::<float>("+3.14"), Some(3.14));
+        assert_eq!(from_str::<float>("-3.14"), Some(-3.14));
+        assert_eq!(from_str::<float>("2.5E10"), Some(25000000000.));
+        assert_eq!(from_str::<float>("2.5e10"), Some(25000000000.));
+        assert_eq!(from_str::<float>("25000000000.E-10"), Some(2.5));
+        assert_eq!(from_str::<float>("."), Some(0.));
+        assert_eq!(from_str::<float>(".e1"), Some(0.));
+        assert_eq!(from_str::<float>(".e-1"), Some(0.));
+        assert_eq!(from_str::<float>("5."), Some(5.));
+        assert_eq!(from_str::<float>(".5"), Some(0.5));
+        assert_eq!(from_str::<float>("0.5"), Some(0.5));
+        assert_eq!(from_str::<float>("-.5"), Some(-0.5));
+        assert_eq!(from_str::<float>("-5"), Some(-5.));
+        assert_eq!(from_str::<float>("inf"), Some(infinity));
+        assert_eq!(from_str::<float>("+inf"), Some(infinity));
+        assert_eq!(from_str::<float>("-inf"), Some(neg_infinity));
         // note: NaN != NaN, hence this slightly complex test
-        match from_str("NaN") {
+        match from_str::<float>("NaN") {
             Some(f) => assert!(f.is_NaN()),
             None => fail!()
         }
         // note: -0 == 0, hence these slightly more complex tests
-        match from_str("-0") {
+        match from_str::<float>("-0") {
             Some(v) if v.is_zero() => assert!(v.is_negative()),
             _ => fail!()
         }
-        match from_str("0") {
+        match from_str::<float>("0") {
             Some(v) if v.is_zero() => assert!(v.is_positive()),
             _ => fail!()
         }
 
-        assert!(from_str("").is_none());
-        assert!(from_str("x").is_none());
-        assert!(from_str(" ").is_none());
-        assert!(from_str("   ").is_none());
-        assert!(from_str("e").is_none());
-        assert!(from_str("E").is_none());
-        assert!(from_str("E1").is_none());
-        assert!(from_str("1e1e1").is_none());
-        assert!(from_str("1e1.1").is_none());
-        assert!(from_str("1e1-1").is_none());
+        assert!(from_str::<float>("").is_none());
+        assert!(from_str::<float>("x").is_none());
+        assert!(from_str::<float>(" ").is_none());
+        assert!(from_str::<float>("   ").is_none());
+        assert!(from_str::<float>("e").is_none());
+        assert!(from_str::<float>("E").is_none());
+        assert!(from_str::<float>("E1").is_none());
+        assert!(from_str::<float>("1e1e1").is_none());
+        assert!(from_str::<float>("1e1.1").is_none());
+        assert!(from_str::<float>("1e1-1").is_none());
     }
 
     #[test]
diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs
index 0a9c912a6e2..7cd1be7ab74 100644
--- a/src/libstd/num/uint_macros.rs
+++ b/src/libstd/num/uint_macros.rs
@@ -70,11 +70,11 @@ impl Orderable for $T {
     /// Returns the number constrained within the range `mn <= self <= mx`.
     #[inline]
     fn clamp(&self, mn: &$T, mx: &$T) -> $T {
-        cond!(
-            (*self > *mx) { *mx   }
-            (*self < *mn) { *mn   }
-            _             { *self }
-        )
+        match () {
+            _ if (*self > *mx) => *mx,
+            _ if (*self < *mn) => *mn,
+            _                  => *self,
+        }
     }
 }
 
diff --git a/src/libstd/option.rs b/src/libstd/option.rs
index 9b6d0a77cd8..42878f6effb 100644
--- a/src/libstd/option.rs
+++ b/src/libstd/option.rs
@@ -467,15 +467,6 @@ impl<T: Default> Option<T> {
             None => Default::default()
         }
     }
-
-    /// Returns self or `Some`-wrapped default value
-    #[inline]
-    pub fn or_default(self) -> Option<T> {
-        match self {
-            None => Some(Default::default()),
-            x => x,
-        }
-    }
 }
 
 impl<T> Default for Option<T> {
@@ -483,7 +474,7 @@ impl<T> Default for Option<T> {
     fn default() -> Option<T> { None }
 }
 
-impl<T:Zero> Option<T> {
+impl<T: Zero> Option<T> {
     /// Returns the contained value or zero (for this type)
     #[inline]
     pub fn unwrap_or_zero(self) -> T {
@@ -492,15 +483,6 @@ impl<T:Zero> Option<T> {
             None => Zero::zero()
         }
     }
-
-    /// Returns self or `Some`-wrapped zero value
-    #[inline]
-    pub fn or_zero(self) -> Option<T> {
-        match self {
-            None => Some(Zero::zero()),
-            x => x
-        }
-    }
 }
 
 /// An iterator that yields either one or zero elements
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 215bda264ad..1dc1d1d6776 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -148,18 +148,6 @@ pub mod win32 {
     }
 }
 
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
-    (fn $name:ident ()) => (
-        extern {
-            fn $name();
-        }
-    )
-)
-}
-
 /*
 Accessing environment variables is not generally threadsafe.
 Serialize access through a global lock.
@@ -1659,7 +1647,7 @@ pub mod consts {
     pub use os::consts::arm::*;
 
     #[cfg(target_arch = "mips")]
-    use os::consts::mips::*;
+    pub use os::consts::mips::*;
 
     pub mod unix {
         pub static FAMILY: &'static str = "unix";
diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs
index 6e90e2a1070..135acb106a1 100644
--- a/src/libstd/ptr.rs
+++ b/src/libstd/ptr.rs
@@ -16,31 +16,13 @@ use clone::Clone;
 use cmp::Equiv;
 use iter::{range, Iterator};
 use option::{Option, Some, None};
-#[cfg(stage0)]
-use sys;
 use unstable::intrinsics;
 use util::swap;
 
 #[cfg(not(test))] use cmp::{Eq, Ord};
 
-/// Calculate the offset from a pointer. The count *must* be in bounds or
-/// otherwise the loads of this address are undefined.
-#[inline]
-#[cfg(stage0)]
-pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
-    (ptr as uint + (count as uint) * sys::size_of::<T>()) as *T
-}
-
-/// Calculate the offset from a mut pointer
-#[inline]
-#[cfg(stage0)]
-pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
-    (ptr as uint + (count as uint) * sys::size_of::<T>()) as *mut T
-}
-
 /// Calculate the offset from a pointer
 #[inline]
-#[cfg(not(stage0))]
 pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
     intrinsics::offset(ptr, count)
 }
@@ -48,7 +30,6 @@ pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
 /// Calculate the offset from a mut pointer. The count *must* be in bounds or
 /// otherwise the loads of this address are undefined.
 #[inline]
-#[cfg(not(stage0))]
 pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
     intrinsics::offset(ptr as *T, count) as *mut T
 }
@@ -383,17 +364,7 @@ impl<T> RawPtr<T> for *mut T {
 }
 
 // Equality for pointers
-#[cfg(stage0, not(test))]
-impl<T> Eq for *T {
-    #[inline]
-    fn eq(&self, other: &*T) -> bool {
-        (*self as uint) == (*other as uint)
-    }
-    #[inline]
-    fn ne(&self, other: &*T) -> bool { !self.eq(other) }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Eq for *T {
     #[inline]
     fn eq(&self, other: &*T) -> bool {
@@ -403,17 +374,7 @@ impl<T> Eq for *T {
     fn ne(&self, other: &*T) -> bool { !self.eq(other) }
 }
 
-#[cfg(stage0, not(test))]
-impl<T> Eq for *mut T {
-    #[inline]
-    fn eq(&self, other: &*mut T) -> bool {
-        (*self as uint) == (*other as uint)
-    }
-    #[inline]
-    fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Eq for *mut T {
     #[inline]
     fn eq(&self, other: &*mut T) -> bool {
@@ -480,27 +441,7 @@ mod externfnpointers {
 }
 
 // Comparison for pointers
-#[cfg(stage0, not(test))]
-impl<T> Ord for *T {
-    #[inline]
-    fn lt(&self, other: &*T) -> bool {
-        (*self as uint) < (*other as uint)
-    }
-    #[inline]
-    fn le(&self, other: &*T) -> bool {
-        (*self as uint) <= (*other as uint)
-    }
-    #[inline]
-    fn ge(&self, other: &*T) -> bool {
-        (*self as uint) >= (*other as uint)
-    }
-    #[inline]
-    fn gt(&self, other: &*T) -> bool {
-        (*self as uint) > (*other as uint)
-    }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Ord for *T {
     #[inline]
     fn lt(&self, other: &*T) -> bool {
@@ -520,27 +461,7 @@ impl<T> Ord for *T {
     }
 }
 
-#[cfg(stage0, not(test))]
-impl<T> Ord for *mut T {
-    #[inline]
-    fn lt(&self, other: &*mut T) -> bool {
-        (*self as uint) < (*other as uint)
-    }
-    #[inline]
-    fn le(&self, other: &*mut T) -> bool {
-        (*self as uint) <= (*other as uint)
-    }
-    #[inline]
-    fn ge(&self, other: &*mut T) -> bool {
-        (*self as uint) >= (*other as uint)
-    }
-    #[inline]
-    fn gt(&self, other: &*mut T) -> bool {
-        (*self as uint) > (*other as uint)
-    }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Ord for *mut T {
     #[inline]
     fn lt(&self, other: &*mut T) -> bool {
diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs
index 1330096ee36..8ca247edb59 100644
--- a/src/libstd/rand.rs
+++ b/src/libstd/rand.rs
@@ -915,7 +915,7 @@ pub fn seed() -> ~[u8] {
 }
 
 // used to make space in TLS for a random number generator
-static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key;
+local_data_key!(tls_rng_state: @@mut IsaacRng)
 
 /**
  * Gives back a lazily initialized task-local random number generator,
diff --git a/src/libstd/reflect_stage0.rs b/src/libstd/reflect_stage0.rs
deleted file mode 100644
index 56e0f83e05c..00000000000
--- a/src/libstd/reflect_stage0.rs
+++ /dev/null
@@ -1,493 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-Runtime type reflection
-
-*/
-
-#[allow(missing_doc)];
-
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor};
-use libc::c_void;
-use sys;
-use unstable::raw;
-
-/**
- * Trait for visitor that wishes to reflect on data. To use this, create a
- * struct that encapsulates the set of pointers you wish to walk through a
- * data structure, and implement both `MovePtr` for it as well as `TyVisitor`;
- * then build a MovePtrAdaptor wrapped around your struct.
- */
-pub trait MovePtr {
-    fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void);
-    fn push_ptr(&self);
-    fn pop_ptr(&self);
-}
-
-/// Helper function for alignment calculation.
-#[inline]
-pub fn align(size: uint, align: uint) -> uint {
-    ((size + align) - 1u) & !(align - 1u)
-}
-
-/// Adaptor to wrap around visitors implementing MovePtr.
-pub struct MovePtrAdaptor<V> {
-    inner: V
-}
-pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> {
-    MovePtrAdaptor { inner: v }
-}
-
-impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> {
-    #[inline]
-    pub fn bump(&self, sz: uint) {
-        do self.inner.move_ptr() |p| {
-            ((p as uint) + sz) as *c_void
-        };
-    }
-
-    #[inline]
-    pub fn align(&self, a: uint) {
-        do self.inner.move_ptr() |p| {
-            align(p as uint, a) as *c_void
-        };
-    }
-
-    #[inline]
-    pub fn align_to<T>(&self) {
-        self.align(sys::min_align_of::<T>());
-    }
-
-    #[inline]
-    pub fn bump_past<T>(&self) {
-        self.bump(sys::size_of::<T>());
-    }
-}
-
-/// Abstract type-directed pointer-movement using the MovePtr trait
-impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
-    fn visit_bot(&self) -> bool {
-        self.align_to::<()>();
-        if ! self.inner.visit_bot() { return false; }
-        self.bump_past::<()>();
-        true
-    }
-
-    fn visit_nil(&self) -> bool {
-        self.align_to::<()>();
-        if ! self.inner.visit_nil() { return false; }
-        self.bump_past::<()>();
-        true
-    }
-
-    fn visit_bool(&self) -> bool {
-        self.align_to::<bool>();
-        if ! self.inner.visit_bool() { return false; }
-        self.bump_past::<bool>();
-        true
-    }
-
-    fn visit_int(&self) -> bool {
-        self.align_to::<int>();
-        if ! self.inner.visit_int() { return false; }
-        self.bump_past::<int>();
-        true
-    }
-
-    fn visit_i8(&self) -> bool {
-        self.align_to::<i8>();
-        if ! self.inner.visit_i8() { return false; }
-        self.bump_past::<i8>();
-        true
-    }
-
-    fn visit_i16(&self) -> bool {
-        self.align_to::<i16>();
-        if ! self.inner.visit_i16() { return false; }
-        self.bump_past::<i16>();
-        true
-    }
-
-    fn visit_i32(&self) -> bool {
-        self.align_to::<i32>();
-        if ! self.inner.visit_i32() { return false; }
-        self.bump_past::<i32>();
-        true
-    }
-
-    fn visit_i64(&self) -> bool {
-        self.align_to::<i64>();
-        if ! self.inner.visit_i64() { return false; }
-        self.bump_past::<i64>();
-        true
-    }
-
-    fn visit_uint(&self) -> bool {
-        self.align_to::<uint>();
-        if ! self.inner.visit_uint() { return false; }
-        self.bump_past::<uint>();
-        true
-    }
-
-    fn visit_u8(&self) -> bool {
-        self.align_to::<u8>();
-        if ! self.inner.visit_u8() { return false; }
-        self.bump_past::<u8>();
-        true
-    }
-
-    fn visit_u16(&self) -> bool {
-        self.align_to::<u16>();
-        if ! self.inner.visit_u16() { return false; }
-        self.bump_past::<u16>();
-        true
-    }
-
-    fn visit_u32(&self) -> bool {
-        self.align_to::<u32>();
-        if ! self.inner.visit_u32() { return false; }
-        self.bump_past::<u32>();
-        true
-    }
-
-    fn visit_u64(&self) -> bool {
-        self.align_to::<u64>();
-        if ! self.inner.visit_u64() { return false; }
-        self.bump_past::<u64>();
-        true
-    }
-
-    fn visit_float(&self) -> bool {
-        self.align_to::<float>();
-        if ! self.inner.visit_float() { return false; }
-        self.bump_past::<float>();
-        true
-    }
-
-    fn visit_f32(&self) -> bool {
-        self.align_to::<f32>();
-        if ! self.inner.visit_f32() { return false; }
-        self.bump_past::<f32>();
-        true
-    }
-
-    fn visit_f64(&self) -> bool {
-        self.align_to::<f64>();
-        if ! self.inner.visit_f64() { return false; }
-        self.bump_past::<f64>();
-        true
-    }
-
-    fn visit_char(&self) -> bool {
-        self.align_to::<char>();
-        if ! self.inner.visit_char() { return false; }
-        self.bump_past::<char>();
-        true
-    }
-
-    fn visit_estr_box(&self) -> bool {
-        self.align_to::<@str>();
-        if ! self.inner.visit_estr_box() { return false; }
-        self.bump_past::<@str>();
-        true
-    }
-
-    fn visit_estr_uniq(&self) -> bool {
-        self.align_to::<~str>();
-        if ! self.inner.visit_estr_uniq() { return false; }
-        self.bump_past::<~str>();
-        true
-    }
-
-    fn visit_estr_slice(&self) -> bool {
-        self.align_to::<&'static str>();
-        if ! self.inner.visit_estr_slice() { return false; }
-        self.bump_past::<&'static str>();
-        true
-    }
-
-    fn visit_estr_fixed(&self, n: uint,
-                        sz: uint,
-                        align: uint) -> bool {
-        self.align(align);
-        if ! self.inner.visit_estr_fixed(n, sz, align) { return false; }
-        self.bump(sz);
-        true
-    }
-
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<@u8>();
-        if ! self.inner.visit_box(mtbl, inner) { return false; }
-        self.bump_past::<@u8>();
-        true
-    }
-
-    fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~u8>();
-        if ! self.inner.visit_uniq(mtbl, inner) { return false; }
-        self.bump_past::<~u8>();
-        true
-    }
-
-    fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~u8>();
-        if ! self.inner.visit_uniq_managed(mtbl, inner) { return false; }
-        self.bump_past::<~u8>();
-        true
-    }
-
-    fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<*u8>();
-        if ! self.inner.visit_ptr(mtbl, inner) { return false; }
-        self.bump_past::<*u8>();
-        true
-    }
-
-    fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<&'static u8>();
-        if ! self.inner.visit_rptr(mtbl, inner) { return false; }
-        self.bump_past::<&'static u8>();
-        true
-    }
-
-    fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<raw::Vec<()>>();
-        if ! self.inner.visit_vec(mtbl, inner) { return false; }
-        true
-    }
-
-    fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~[u8]>();
-        if ! self.inner.visit_vec(mtbl, inner) { return false; }
-        self.bump_past::<~[u8]>();
-        true
-    }
-
-    fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<@[u8]>();
-        if ! self.inner.visit_evec_box(mtbl, inner) { return false; }
-        self.bump_past::<@[u8]>();
-        true
-    }
-
-    fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~[u8]>();
-        if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; }
-        self.bump_past::<~[u8]>();
-        true
-    }
-
-    fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~[@u8]>();
-        if ! self.inner.visit_evec_uniq_managed(mtbl, inner) { return false; }
-        self.bump_past::<~[@u8]>();
-        true
-    }
-
-    fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<&'static [u8]>();
-        if ! self.inner.visit_evec_slice(mtbl, inner) { return false; }
-        self.bump_past::<&'static [u8]>();
-        true
-    }
-
-    fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
-                        mtbl: uint, inner: *TyDesc) -> bool {
-        self.align(align);
-        if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) {
-            return false;
-        }
-        self.bump(sz);
-        true
-    }
-
-    fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_rec_field(&self, i: uint, name: &str,
-                       mtbl: uint, inner: *TyDesc) -> bool {
-        unsafe { self.align((*inner).align); }
-        if ! self.inner.visit_rec_field(i, name, mtbl, inner) {
-            return false;
-        }
-        unsafe { self.bump((*inner).size); }
-        true
-    }
-
-    fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint)
-                      -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_class(n_fields, sz, align) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_class_field(&self, i: uint, name: &str,
-                         mtbl: uint, inner: *TyDesc) -> bool {
-        unsafe { self.align((*inner).align); }
-        if ! self.inner.visit_class_field(i, name, mtbl, inner) {
-            return false;
-        }
-        unsafe { self.bump((*inner).size); }
-        true
-    }
-
-    fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
-                      -> bool {
-        if ! self.inner.visit_leave_class(n_fields, sz, align) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
-        unsafe { self.align((*inner).align); }
-        if ! self.inner.visit_tup_field(i, inner) { return false; }
-        unsafe { self.bump((*inner).size); }
-        true
-    }
-
-    fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_enter_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool {
-        if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) {
-            return false
-        }
-        true
-    }
-
-    fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool {
-        if ! self.inner.visit_fn_input(i, mode, inner) { return false; }
-        true
-    }
-
-    fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool {
-        if ! self.inner.visit_fn_output(retstyle, inner) { return false; }
-        true
-    }
-
-    fn visit_leave_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool {
-        if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enter_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint)
-                     -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enter_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool {
-        if ! self.inner.visit_enter_enum_variant(variant, disr_val,
-                                                 n_fields, name) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
-        self.inner.push_ptr();
-        self.bump(offset);
-        if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
-        self.inner.pop_ptr();
-        true
-    }
-
-    fn visit_leave_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool {
-        if ! self.inner.visit_leave_enum_variant(variant, disr_val,
-                                                 n_fields, name) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_leave_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint) -> bool {
-        if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) {
-            return false;
-        }
-        self.bump(sz);
-        true
-    }
-
-    fn visit_trait(&self) -> bool {
-        self.align_to::<@TyVisitor>();
-        if ! self.inner.visit_trait() { return false; }
-        self.bump_past::<@TyVisitor>();
-        true
-    }
-
-    fn visit_param(&self, i: uint) -> bool {
-        if ! self.inner.visit_param(i) { return false; }
-        true
-    }
-
-    fn visit_self(&self) -> bool {
-        self.align_to::<&'static u8>();
-        if ! self.inner.visit_self() { return false; }
-        self.align_to::<&'static u8>();
-        true
-    }
-
-    fn visit_type(&self) -> bool {
-        if ! self.inner.visit_type() { return false; }
-        true
-    }
-
-    fn visit_opaque_box(&self) -> bool {
-        self.align_to::<@u8>();
-        if ! self.inner.visit_opaque_box() { return false; }
-        self.bump_past::<@u8>();
-        true
-    }
-
-    fn visit_closure_ptr(&self, ck: uint) -> bool {
-        self.align_to::<@fn()>();
-        if ! self.inner.visit_closure_ptr(ck) { return false; }
-        self.bump_past::<@fn()>();
-        true
-    }
-}
diff --git a/src/libstd/repr_stage0.rs b/src/libstd/repr_stage0.rs
deleted file mode 100644
index cbce2005141..00000000000
--- a/src/libstd/repr_stage0.rs
+++ /dev/null
@@ -1,626 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-More runtime type reflection
-
-*/
-
-#[allow(missing_doc)];
-
-use cast::transmute;
-use char;
-use container::Container;
-use io::{Writer, WriterUtil};
-use iter::Iterator;
-use libc::c_void;
-use option::{Some, None};
-use ptr;
-use reflect;
-use reflect::{MovePtr, align};
-use str::StrSlice;
-use to_str::ToStr;
-use vec::OwnedVector;
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
-use unstable::raw;
-
-#[cfg(test)] use io;
-
-/// Helpers
-
-trait EscapedCharWriter {
-    fn write_escaped_char(&self, ch: char);
-}
-
-impl EscapedCharWriter for @Writer {
-    fn write_escaped_char(&self, ch: char) {
-        match ch {
-            '\t' => self.write_str("\\t"),
-            '\r' => self.write_str("\\r"),
-            '\n' => self.write_str("\\n"),
-            '\\' => self.write_str("\\\\"),
-            '\'' => self.write_str("\\'"),
-            '"' => self.write_str("\\\""),
-            '\x20'..'\x7e' => self.write_char(ch),
-            _ => {
-                do char::escape_unicode(ch) |c| {
-                    self.write_char(c);
-                }
-            }
-        }
-    }
-}
-
-/// Representations
-
-trait Repr {
-    fn write_repr(&self, writer: @Writer);
-}
-
-impl Repr for () {
-    fn write_repr(&self, writer: @Writer) { writer.write_str("()"); }
-}
-
-impl Repr for bool {
-    fn write_repr(&self, writer: @Writer) {
-        writer.write_str(if *self { "true" } else { "false" })
-    }
-}
-
-macro_rules! int_repr(($ty:ident) => (impl Repr for $ty {
-    fn write_repr(&self, writer: @Writer) {
-        do ::$ty::to_str_bytes(*self, 10u) |bits| {
-            writer.write(bits);
-        }
-    }
-}))
-
-int_repr!(int)
-int_repr!(i8)
-int_repr!(i16)
-int_repr!(i32)
-int_repr!(i64)
-int_repr!(uint)
-int_repr!(u8)
-int_repr!(u16)
-int_repr!(u32)
-int_repr!(u64)
-
-macro_rules! num_repr(($ty:ident) => (impl Repr for $ty {
-    fn write_repr(&self, writer: @Writer) {
-        let s = self.to_str();
-        writer.write(s.as_bytes());
-    }
-}))
-
-num_repr!(float)
-num_repr!(f32)
-num_repr!(f64)
-
-// New implementation using reflect::MovePtr
-
-enum VariantState {
-    SearchingFor(int),
-    Matched,
-    AlreadyFound
-}
-
-pub struct ReprVisitor {
-    ptr: @mut *c_void,
-    ptr_stk: @mut ~[*c_void],
-    var_stk: @mut ~[VariantState],
-    writer: @Writer
-}
-pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
-    ReprVisitor {
-        ptr: @mut ptr,
-        ptr_stk: @mut ~[],
-        var_stk: @mut ~[],
-        writer: writer,
-    }
-}
-
-impl MovePtr for ReprVisitor {
-    #[inline]
-    fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
-        *self.ptr = adjustment(*self.ptr);
-    }
-    fn push_ptr(&self) {
-        self.ptr_stk.push(*self.ptr);
-    }
-    fn pop_ptr(&self) {
-        *self.ptr = self.ptr_stk.pop();
-    }
-}
-
-impl ReprVisitor {
-    // Various helpers for the TyVisitor impl
-
-    #[inline]
-    pub fn get<T>(&self, f: &fn(&T)) -> bool {
-        unsafe {
-            f(transmute::<*c_void,&T>(*self.ptr));
-        }
-        true
-    }
-
-    #[inline]
-    pub fn visit_inner(&self, inner: *TyDesc) -> bool {
-        self.visit_ptr_inner(*self.ptr, inner)
-    }
-
-    #[inline]
-    pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
-        unsafe {
-            let u = ReprVisitor(ptr, self.writer);
-            let v = reflect::MovePtrAdaptor(u);
-            visit_tydesc(inner, @v as @TyVisitor);
-            true
-        }
-    }
-
-    #[inline]
-    pub fn write<T:Repr>(&self) -> bool {
-        do self.get |v:&T| {
-            v.write_repr(self.writer);
-        }
-    }
-
-    pub fn write_escaped_slice(&self, slice: &str) {
-        self.writer.write_char('"');
-        for ch in slice.iter() {
-            self.writer.write_escaped_char(ch);
-        }
-        self.writer.write_char('"');
-    }
-
-    pub fn write_mut_qualifier(&self, mtbl: uint) {
-        if mtbl == 0 {
-            self.writer.write_str("mut ");
-        } else if mtbl == 1 {
-            // skip, this is ast::m_imm
-        } else {
-            assert_eq!(mtbl, 2);
-            self.writer.write_str("const ");
-        }
-    }
-
-    pub fn write_vec_range(&self,
-                           _mtbl: uint,
-                           ptr: *(),
-                           len: uint,
-                           inner: *TyDesc)
-                           -> bool {
-        let mut p = ptr as *u8;
-        let (sz, al) = unsafe { ((*inner).size, (*inner).align) };
-        self.writer.write_char('[');
-        let mut first = true;
-        let mut left = len;
-        // unit structs have 0 size, and don't loop forever.
-        let dec = if sz == 0 {1} else {sz};
-        while left > 0 {
-            if first {
-                first = false;
-            } else {
-                self.writer.write_str(", ");
-            }
-            self.visit_ptr_inner(p as *c_void, inner);
-            unsafe {
-                p = align(ptr::offset(p, sz as int) as uint, al) as *u8;
-            }
-            left -= dec;
-        }
-        self.writer.write_char(']');
-        true
-    }
-
-    pub fn write_unboxed_vec_repr(&self,
-                                  mtbl: uint,
-                                  v: &raw::Vec<()>,
-                                  inner: *TyDesc)
-                                  -> bool {
-        self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data),
-                             v.fill, inner)
-    }
-}
-
-impl TyVisitor for ReprVisitor {
-    fn visit_bot(&self) -> bool {
-        self.writer.write_str("!");
-        true
-    }
-    fn visit_nil(&self) -> bool { self.write::<()>() }
-    fn visit_bool(&self) -> bool { self.write::<bool>() }
-    fn visit_int(&self) -> bool { self.write::<int>() }
-    fn visit_i8(&self) -> bool { self.write::<i8>() }
-    fn visit_i16(&self) -> bool { self.write::<i16>() }
-    fn visit_i32(&self) -> bool { self.write::<i32>()  }
-    fn visit_i64(&self) -> bool { self.write::<i64>() }
-
-    fn visit_uint(&self) -> bool { self.write::<uint>() }
-    fn visit_u8(&self) -> bool { self.write::<u8>() }
-    fn visit_u16(&self) -> bool { self.write::<u16>() }
-    fn visit_u32(&self) -> bool { self.write::<u32>() }
-    fn visit_u64(&self) -> bool { self.write::<u64>() }
-
-    fn visit_float(&self) -> bool { self.write::<float>() }
-    fn visit_f32(&self) -> bool { self.write::<f32>() }
-    fn visit_f64(&self) -> bool { self.write::<f64>() }
-
-    fn visit_char(&self) -> bool {
-        do self.get::<char> |&ch| {
-            self.writer.write_char('\'');
-            self.writer.write_escaped_char(ch);
-            self.writer.write_char('\'');
-        }
-    }
-
-    fn visit_estr_box(&self) -> bool {
-        do self.get::<@str> |s| {
-            self.writer.write_char('@');
-            self.write_escaped_slice(*s);
-        }
-    }
-    fn visit_estr_uniq(&self) -> bool {
-        do self.get::<~str> |s| {
-            self.writer.write_char('~');
-            self.write_escaped_slice(*s);
-        }
-    }
-    fn visit_estr_slice(&self) -> bool {
-        do self.get::<&str> |s| {
-            self.write_escaped_slice(*s);
-        }
-    }
-
-    // Type no longer exists, vestigial function.
-    fn visit_estr_fixed(&self, _n: uint, _sz: uint,
-                        _align: uint) -> bool { fail!(); }
-
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('@');
-        self.write_mut_qualifier(mtbl);
-        do self.get::<&raw::Box<()>> |b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, inner);
-        }
-    }
-
-    fn visit_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('~');
-        do self.get::<*c_void> |b| {
-            self.visit_ptr_inner(*b, inner);
-        }
-    }
-
-    fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('~');
-        do self.get::<&raw::Box<()>> |b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, inner);
-        }
-    }
-
-    fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool {
-        do self.get::<*c_void> |p| {
-            self.writer.write_str(fmt!("(0x%x as *())",
-                                       *p as uint));
-        }
-    }
-
-    fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('&');
-        self.write_mut_qualifier(mtbl);
-        do self.get::<*c_void> |p| {
-            self.visit_ptr_inner(*p, inner);
-        }
-    }
-
-    // Type no longer exists, vestigial function.
-    fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); }
-
-
-    fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<raw::Vec<()>> |b| {
-            self.write_unboxed_vec_repr(mtbl, b, inner);
-        }
-    }
-
-    fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<&raw::Box<raw::Vec<()>>> |b| {
-            self.writer.write_char('@');
-            self.write_mut_qualifier(mtbl);
-            self.write_unboxed_vec_repr(mtbl, &b.data, inner);
-        }
-    }
-
-    fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<&raw::Vec<()>> |b| {
-            self.writer.write_char('~');
-            self.write_unboxed_vec_repr(mtbl, *b, inner);
-        }
-    }
-
-    fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<&raw::Box<raw::Vec<()>>> |b| {
-            self.writer.write_char('~');
-            self.write_unboxed_vec_repr(mtbl, &b.data, inner);
-        }
-    }
-
-    fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<raw::Slice<()>> |s| {
-            self.writer.write_char('&');
-            self.write_vec_range(mtbl, s.data, s.len, inner);
-        }
-    }
-
-    fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint,
-                        mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<()> |b| {
-            self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner);
-        }
-    }
-
-    fn visit_enter_rec(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('{');
-        true
-    }
-
-    fn visit_rec_field(&self, i: uint, name: &str,
-                       mtbl: uint, inner: *TyDesc) -> bool {
-        if i != 0 {
-            self.writer.write_str(", ");
-        }
-        self.write_mut_qualifier(mtbl);
-        self.writer.write_str(name);
-        self.writer.write_str(": ");
-        self.visit_inner(inner);
-        true
-    }
-
-    fn visit_leave_rec(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('}');
-        true
-    }
-
-    fn visit_enter_class(&self, _n_fields: uint,
-                         _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('{');
-        true
-    }
-    fn visit_class_field(&self, i: uint, name: &str,
-                         mtbl: uint, inner: *TyDesc) -> bool {
-        if i != 0 {
-            self.writer.write_str(", ");
-        }
-        self.write_mut_qualifier(mtbl);
-        self.writer.write_str(name);
-        self.writer.write_str(": ");
-        self.visit_inner(inner);
-        true
-    }
-    fn visit_leave_class(&self, _n_fields: uint,
-                         _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('}');
-        true
-    }
-
-    fn visit_enter_tup(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('(');
-        true
-    }
-    fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
-        if i != 0 {
-            self.writer.write_str(", ");
-        }
-        self.visit_inner(inner);
-        true
-    }
-    fn visit_leave_tup(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        if _n_fields == 1 {
-            self.writer.write_char(',');
-        }
-        self.writer.write_char(')');
-        true
-    }
-
-    fn visit_enter_enum(&self,
-                        _n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        _sz: uint,
-                        _align: uint) -> bool {
-        let var_stk: &mut ~[VariantState] = self.var_stk;
-        let disr = unsafe {
-            get_disr(transmute(*self.ptr))
-        };
-        var_stk.push(SearchingFor(disr));
-        true
-    }
-
-    fn visit_enter_enum_variant(&self, _variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool {
-        let mut write = false;
-        match self.var_stk.pop() {
-            SearchingFor(sought) => {
-                if disr_val == sought {
-                    self.var_stk.push(Matched);
-                    write = true;
-                } else {
-                    self.var_stk.push(SearchingFor(sought));
-                }
-            }
-            Matched | AlreadyFound => {
-                self.var_stk.push(AlreadyFound);
-            }
-        }
-
-        if write {
-            self.writer.write_str(name);
-            if n_fields > 0 {
-                self.writer.write_char('(');
-            }
-        }
-        true
-    }
-
-    fn visit_enum_variant_field(&self,
-                                i: uint,
-                                _offset: uint,
-                                inner: *TyDesc)
-                                -> bool {
-        match self.var_stk[self.var_stk.len() - 1] {
-            Matched => {
-                if i != 0 {
-                    self.writer.write_str(", ");
-                }
-                if ! self.visit_inner(inner) {
-                    return false;
-                }
-            }
-            _ => ()
-        }
-        true
-    }
-
-    fn visit_leave_enum_variant(&self, _variant: uint,
-                                _disr_val: int,
-                                n_fields: uint,
-                                _name: &str) -> bool {
-        match self.var_stk[self.var_stk.len() - 1] {
-            Matched => {
-                if n_fields > 0 {
-                    self.writer.write_char(')');
-                }
-            }
-            _ => ()
-        }
-        true
-    }
-
-    fn visit_leave_enum(&self,
-                        _n_variants: uint,
-                        _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        _sz: uint,
-                        _align: uint)
-                        -> bool {
-        let var_stk: &mut ~[VariantState] = self.var_stk;
-        match var_stk.pop() {
-            SearchingFor(*) => fail!("enum value matched no variant"),
-            _ => true
-        }
-    }
-
-    fn visit_enter_fn(&self, _purity: uint, _proto: uint,
-                      _n_inputs: uint, _retstyle: uint) -> bool { true }
-    fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
-        true
-    }
-    fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
-        true
-    }
-    fn visit_leave_fn(&self, _purity: uint, _proto: uint,
-                      _n_inputs: uint, _retstyle: uint) -> bool { true }
-
-
-    fn visit_trait(&self) -> bool { true }
-    fn visit_param(&self, _i: uint) -> bool { true }
-    fn visit_self(&self) -> bool { true }
-    fn visit_type(&self) -> bool { true }
-
-    fn visit_opaque_box(&self) -> bool {
-        self.writer.write_char('@');
-        do self.get::<&raw::Box<()>> |b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, b.type_desc);
-        }
-    }
-
-    fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
-}
-
-pub fn write_repr<T>(writer: @Writer, object: &T) {
-    unsafe {
-        let ptr = ptr::to_unsafe_ptr(object) as *c_void;
-        let tydesc = get_tydesc::<T>();
-        let u = ReprVisitor(ptr, writer);
-        let v = reflect::MovePtrAdaptor(u);
-        visit_tydesc(tydesc, @v as @TyVisitor)
-    }
-}
-
-#[cfg(test)]
-struct P {a: int, b: float}
-
-#[test]
-fn test_repr() {
-
-    fn exact_test<T>(t: &T, e:&str) {
-        let s : &str = io::with_str_writer(|w| write_repr(w, t));
-        if s != e {
-            error!("expected '%s', got '%s'",
-                   e, s);
-        }
-        assert_eq!(s, e);
-    }
-
-    exact_test(&10, "10");
-    exact_test(&true, "true");
-    exact_test(&false, "false");
-    exact_test(&1.234, "1.234");
-    exact_test(&(&"hello"), "\"hello\"");
-    exact_test(&(@"hello"), "@\"hello\"");
-    exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\"");
-
-    exact_test(&(@10), "@10");
-    exact_test(&(@mut 10), "@10"); // FIXME: #4210: incorrect
-    exact_test(&((@mut 10, 2)), "(@mut 10, 2)");
-    exact_test(&(~10), "~10");
-    exact_test(&(&10), "&10");
-    let mut x = 10;
-    exact_test(&(&mut x), "&mut 10");
-    exact_test(&(@mut [1, 2]), "@mut [1, 2]");
-
-    exact_test(&(1,), "(1,)");
-    exact_test(&(@[1,2,3,4,5,6,7,8]),
-               "@[1, 2, 3, 4, 5, 6, 7, 8]");
-    exact_test(&(@[1u8,2u8,3u8,4u8]),
-               "@[1, 2, 3, 4]");
-    exact_test(&(@["hi", "there"]),
-               "@[\"hi\", \"there\"]");
-    exact_test(&(~["hi", "there"]),
-               "~[\"hi\", \"there\"]");
-    exact_test(&(&["hi", "there"]),
-               "&[\"hi\", \"there\"]");
-    exact_test(&(P{a:10, b:1.234}),
-               "{a: 10, b: 1.234}");
-    exact_test(&(@P{a:10, b:1.234}),
-               "@{a: 10, b: 1.234}");
-    exact_test(&(~P{a:10, b:1.234}),
-               "~{a: 10, b: 1.234}");
-    exact_test(&(10_u8, ~"hello"),
-               "(10, ~\"hello\")");
-    exact_test(&(10_u16, ~"hello"),
-               "(10, ~\"hello\")");
-    exact_test(&(10_u32, ~"hello"),
-               "(10, ~\"hello\")");
-    exact_test(&(10_u64, ~"hello"),
-               "(10, ~\"hello\")");
-
-    struct Foo;
-    exact_test(&(~[Foo, Foo, Foo]), "~[{}, {}, {}]");
-}
diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs
index afa8d3261fc..d8317c34f50 100644
--- a/src/libstd/rt/args.rs
+++ b/src/libstd/rt/args.rs
@@ -117,18 +117,6 @@ mod imp {
         }
     }
 
-    #[cfg(stage0)]
-    mod macro_hack {
-    #[macro_escape];
-    macro_rules! externfn(
-        (fn $name:ident () $(-> $ret_ty:ty),*) => (
-            extern {
-                fn $name() $(-> $ret_ty),*;
-            }
-        )
-    )
-    }
-
     externfn!(fn rust_take_global_args_lock())
     externfn!(fn rust_drop_global_args_lock())
     externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
diff --git a/src/libstd/rt/io/buffered.rs b/src/libstd/rt/io/buffered.rs
index 579e581d87e..7988f640687 100644
--- a/src/libstd/rt/io/buffered.rs
+++ b/src/libstd/rt/io/buffered.rs
@@ -126,7 +126,7 @@ impl<R: Reader> Decorator<R> for BufferedReader<R> {
 
 /// Wraps a Writer and buffers output to it
 ///
-/// NOTE: `BufferedWriter` will NOT flush its buffer when dropped.
+/// Note that `BufferedWriter` will NOT flush its buffer when dropped.
 pub struct BufferedWriter<W> {
     priv inner: W,
     priv buf: ~[u8],
@@ -204,7 +204,7 @@ impl<W: Reader> Reader for InternalBufferedWriter<W> {
 
 /// Wraps a Stream and buffers input and output to and from it
 ///
-/// NOTE: `BufferedStream` will NOT flush its output buffer when dropped.
+/// Note that `BufferedStream` will NOT flush its output buffer when dropped.
 // FIXME #9155 this should be a newtype struct
 pub struct BufferedStream<S> {
     priv inner: BufferedReader<InternalBufferedWriter<S>>
diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs
index 871b41039d1..6b405b0948a 100644
--- a/src/libstd/rt/io/mod.rs
+++ b/src/libstd/rt/io/mod.rs
@@ -260,6 +260,9 @@ pub use self::net::ip::IpAddr;
 pub use self::net::tcp::TcpListener;
 pub use self::net::tcp::TcpStream;
 pub use self::net::udp::UdpStream;
+pub use self::pipe::PipeStream;
+pub use self::pipe::UnboundPipeStream;
+pub use self::process::Process;
 
 // Some extension traits that all Readers and Writers get.
 pub use self::extensions::ReaderUtil;
@@ -269,6 +272,12 @@ pub use self::extensions::WriterByteConversions;
 /// Synchronous, non-blocking file I/O.
 pub mod file;
 
+/// Synchronous, in-memory I/O.
+pub mod pipe;
+
+/// Child process management.
+pub mod process;
+
 /// Synchronous, non-blocking network I/O.
 pub mod net;
 
@@ -388,17 +397,13 @@ impl ToStr for IoErrorKind {
 // XXX: Can't put doc comments on macros
 // Raised by `I/O` operations on error.
 condition! {
-    // NOTE: this super::IoError should be IoError
-    // Change this next time the snapshot is updated.
-    pub io_error: super::IoError -> ();
+    pub io_error: IoError -> ();
 }
 
 // XXX: Can't put doc comments on macros
 // Raised by `read` on error
 condition! {
-    // NOTE: this super::IoError should be IoError
-    // Change this next time the snapshot it updated.
-    pub read_error: super::IoError -> ();
+    pub read_error: IoError -> ();
 }
 
 /// Helper for wrapper calls where you want to
diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs
new file mode 100644
index 00000000000..7e6c59ffd0b
--- /dev/null
+++ b/src/libstd/rt/io/pipe.rs
@@ -0,0 +1,76 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Synchronous, in-memory pipes.
+//!
+//! Currently these aren't particularly useful, there only exists bindings
+//! enough so that pipes can be created to child processes.
+
+use prelude::*;
+use super::{Reader, Writer};
+use rt::io::{io_error, read_error, EndOfFile};
+use rt::local::Local;
+use rt::rtio::{RtioPipe, RtioPipeObject, IoFactoryObject, IoFactory};
+use rt::rtio::RtioUnboundPipeObject;
+
+pub struct PipeStream(RtioPipeObject);
+pub struct UnboundPipeStream(~RtioUnboundPipeObject);
+
+impl PipeStream {
+    /// Creates a new pipe initialized, but not bound to any particular
+    /// source/destination
+    pub fn new() -> Option<UnboundPipeStream> {
+        let pipe = unsafe {
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
+            (*io).pipe_init(false)
+        };
+        match pipe {
+            Ok(p) => Some(UnboundPipeStream(p)),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+
+    pub fn bind(inner: RtioPipeObject) -> PipeStream {
+        PipeStream(inner)
+    }
+}
+
+impl Reader for PipeStream {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        match (**self).read(buf) {
+            Ok(read) => Some(read),
+            Err(ioerr) => {
+                // EOF is indicated by returning None
+                if ioerr.kind != EndOfFile {
+                    read_error::cond.raise(ioerr);
+                }
+                return None;
+            }
+        }
+    }
+
+    fn eof(&mut self) -> bool { fail!() }
+}
+
+impl Writer for PipeStream {
+    fn write(&mut self, buf: &[u8]) {
+        match (**self).write(buf) {
+            Ok(_) => (),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+            }
+        }
+    }
+
+    fn flush(&mut self) { fail!() }
+}
diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs
new file mode 100644
index 00000000000..e92b0d3b7b5
--- /dev/null
+++ b/src/libstd/rt/io/process.rs
@@ -0,0 +1,278 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Bindings for executing child processes
+
+use prelude::*;
+
+use libc;
+use rt::io;
+use rt::io::io_error;
+use rt::local::Local;
+use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};
+
+pub struct Process {
+    priv handle: ~RtioProcessObject,
+    io: ~[Option<io::PipeStream>],
+}
+
+/// This configuration describes how a new process should be spawned. This is
+/// translated to libuv's own configuration
+pub struct ProcessConfig<'self> {
+    /// Path to the program to run
+    program: &'self str,
+
+    /// Arguments to pass to the program (doesn't include the program itself)
+    args: &'self [~str],
+
+    /// Optional environment to specify for the program. If this is None, then
+    /// it will inherit the current process's environment.
+    env: Option<&'self [(~str, ~str)]>,
+
+    /// Optional working directory for the new process. If this is None, then
+    /// the current directory of the running process is inherited.
+    cwd: Option<&'self str>,
+
+    /// Any number of streams/file descriptors/pipes may be attached to this
+    /// process. This list enumerates the file descriptors and such for the
+    /// process to be spawned, and the file descriptors inherited will start at
+    /// 0 and go to the length of this array.
+    ///
+    /// Standard file descriptors are:
+    ///
+    ///     0 - stdin
+    ///     1 - stdout
+    ///     2 - stderr
+    io: ~[StdioContainer]
+}
+
+/// Describes what to do with a standard io stream for a child process.
+pub enum StdioContainer {
+    /// This stream will be ignored. This is the equivalent of attaching the
+    /// stream to `/dev/null`
+    Ignored,
+
+    /// The specified file descriptor is inherited for the stream which it is
+    /// specified for.
+    InheritFd(libc::c_int),
+
+    // XXX: these two shouldn't have libuv-specific implementation details
+
+    /// The specified libuv stream is inherited for the corresponding file
+    /// descriptor it is assigned to.
+    // XXX: this needs to be thought out more.
+    //InheritStream(uv::net::StreamWatcher),
+
+    /// Creates a pipe for the specified file descriptor which will be directed
+    /// into the previously-initialized pipe passed in.
+    ///
+    /// The first boolean argument is whether the pipe is readable, and the
+    /// second is whether it is writable. These properties are from the view of
+    /// the *child* process, not the parent process.
+    CreatePipe(io::UnboundPipeStream,
+               bool /* readable */,
+               bool /* writable */),
+}
+
+impl Process {
+    /// Creates a new pipe initialized, but not bound to any particular
+    /// source/destination
+    pub fn new(config: ProcessConfig) -> Option<Process> {
+        let process = unsafe {
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
+            (*io).spawn(config)
+        };
+        match process {
+            Ok((p, io)) => Some(Process{
+                handle: p,
+                io: io.move_iter().map(|p|
+                    p.map_move(|p| io::PipeStream::bind(p))
+                ).collect()
+            }),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+
+    /// Returns the process id of this child process
+    pub fn id(&self) -> libc::pid_t { self.handle.id() }
+
+    /// Sends the specified signal to the child process, returning whether the
+    /// signal could be delivered or not.
+    ///
+    /// Note that this is purely a wrapper around libuv's `uv_process_kill`
+    /// function.
+    ///
+    /// If the signal delivery fails, then the `io_error` condition is raised on
+    pub fn signal(&mut self, signal: int) {
+        match self.handle.kill(signal) {
+            Ok(()) => {}
+            Err(err) => {
+                io_error::cond.raise(err)
+            }
+        }
+    }
+
+    /// Wait for the child to exit completely, returning the status that it
+    /// exited with. This function will continue to have the same return value
+    /// after it has been called at least once.
+    pub fn wait(&mut self) -> int { self.handle.wait() }
+}
+
+impl Drop for Process {
+    fn drop(&mut self) {
+        // Close all I/O before exiting to ensure that the child doesn't wait
+        // forever to print some text or something similar.
+        for _ in range(0, self.io.len()) {
+            self.io.pop();
+        }
+
+        self.wait();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+    use super::*;
+
+    use rt::io::{Reader, Writer};
+    use rt::io::pipe::*;
+    use str;
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn smoke() {
+        let io = ~[];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"true"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert_eq!(p.wait(), 0);
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn smoke_failure() {
+        let io = ~[];
+        let args = ProcessConfig {
+            program: "if-this-is-a-binary-then-the-world-has-ended",
+            args: [],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert!(p.wait() != 0);
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn exit_reported_right() {
+        let io = ~[];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"exit 1"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert_eq!(p.wait(), 1);
+    }
+
+    fn read_all(input: &mut Reader) -> ~str {
+        let mut ret = ~"";
+        let mut buf = [0, ..1024];
+        loop {
+            match input.read(buf) {
+                None | Some(0) => { break }
+                Some(n) => { ret = ret + str::from_utf8(buf.slice_to(n)); }
+            }
+        }
+        return ret;
+    }
+
+    fn run_output(args: ProcessConfig) -> ~str {
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert!(p.io[0].is_none());
+        assert!(p.io[1].is_some());
+        let ret = read_all(p.io[1].get_mut_ref() as &mut Reader);
+        assert_eq!(p.wait(), 0);
+        return ret;
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn stdout_works() {
+        let pipe = PipeStream::new().unwrap();
+        let io = ~[Ignored, CreatePipe(pipe, false, true)];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"echo foobar"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        assert_eq!(run_output(args), ~"foobar\n");
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn set_cwd_works() {
+        let pipe = PipeStream::new().unwrap();
+        let io = ~[Ignored, CreatePipe(pipe, false, true)];
+        let cwd = Some("/");
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"pwd"],
+            env: None,
+            cwd: cwd,
+            io: io,
+        };
+        assert_eq!(run_output(args), ~"/\n");
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn stdin_works() {
+        let input = PipeStream::new().unwrap();
+        let output = PipeStream::new().unwrap();
+        let io = ~[CreatePipe(input, true, false),
+                   CreatePipe(output, false, true)];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"read line; echo $line"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let mut p = Process::new(args).expect("didn't create a proces?!");
+        p.io[0].get_mut_ref().write("foobar".as_bytes());
+        p.io[0] = None; // close stdin;
+        let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
+        assert_eq!(p.wait(), 0);
+        assert_eq!(out, ~"foobar\n");
+    }
+}
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 53f62786b62..6df857b8d55 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -198,18 +198,6 @@ pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn())
     return exit_code;
 }
 
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
-    (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
-        extern {
-            fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
-        }
-    )
-)
-}
-
 /// One-time runtime initialization.
 ///
 /// Initializes global state, including frobbing
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
index d05a3a26169..ca521c792dc 100644
--- a/src/libstd/rt/rtio.rs
+++ b/src/libstd/rt/rtio.rs
@@ -8,11 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use libc;
 use option::*;
 use result::*;
 use libc::c_int;
 
 use rt::io::IoError;
+use super::io::process::ProcessConfig;
 use super::io::net::ip::{IpAddr, SocketAddr};
 use rt::uv::uvio;
 use path::Path;
@@ -31,6 +33,9 @@ pub type RtioTcpListenerObject = uvio::UvTcpListener;
 pub type RtioUdpSocketObject = uvio::UvUdpSocket;
 pub type RtioTimerObject = uvio::UvTimer;
 pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
+pub type RtioPipeObject = uvio::UvPipeStream;
+pub type RtioUnboundPipeObject = uvio::UvUnboundPipe;
+pub type RtioProcessObject = uvio::UvProcess;
 
 pub trait EventLoop {
     fn run(&mut self);
@@ -79,6 +84,9 @@ pub trait IoFactory {
     fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
     fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
         Result<~[Path], IoError>;
+    fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError>;
+    fn spawn(&mut self, config: ProcessConfig)
+            -> Result<(~RtioProcessObject, ~[Option<RtioPipeObject>]), IoError>;
 }
 
 pub trait RtioTcpListener : RtioSocket {
@@ -135,3 +143,14 @@ pub trait RtioFileStream {
     fn tell(&self) -> Result<u64, IoError>;
     fn flush(&mut self) -> Result<(), IoError>;
 }
+
+pub trait RtioProcess {
+    fn id(&self) -> libc::pid_t;
+    fn kill(&mut self, signal: int) -> Result<(), IoError>;
+    fn wait(&mut self) -> int;
+}
+
+pub trait RtioPipe {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
+}
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index 09f5ee7febb..09bd89ec94a 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -444,17 +444,10 @@ impl Unwinder {
         }
 
         extern {
-            #[cfg(not(stage0))]
             #[rust_stack]
             fn rust_try(f: extern "C" fn(*c_void, *c_void),
                         code: *c_void,
                         data: *c_void) -> uintptr_t;
-
-            #[cfg(stage0)]
-            #[rust_stack]
-            fn rust_try(f: *u8,
-                        code: *c_void,
-                        data: *c_void) -> uintptr_t;
         }
     }
 
@@ -490,10 +483,10 @@ mod test {
     fn tls() {
         use local_data;
         do run_in_newsched_task() {
-            static key: local_data::Key<@~str> = &local_data::Key;
+            local_data_key!(key: @~str)
             local_data::set(key, @~"data");
             assert!(*local_data::get(key, |k| k.map_move(|k| *k)).unwrap() == ~"data");
-            static key2: local_data::Key<@~str> = &local_data::Key;
+            local_data_key!(key2: @~str)
             local_data::set(key2, @~"data");
             assert!(*local_data::get(key2, |k| k.map_move(|k| *k)).unwrap() == ~"data");
         }
diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs
index 451d454d2d8..95b2059d538 100644
--- a/src/libstd/rt/uv/mod.rs
+++ b/src/libstd/rt/uv/mod.rs
@@ -58,6 +58,8 @@ pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher};
 pub use self::idle::IdleWatcher;
 pub use self::timer::TimerWatcher;
 pub use self::async::AsyncWatcher;
+pub use self::process::Process;
+pub use self::pipe::Pipe;
 
 /// The implementation of `rtio` for libuv
 pub mod uvio;
@@ -71,6 +73,8 @@ pub mod idle;
 pub mod timer;
 pub mod async;
 pub mod addrinfo;
+pub mod process;
+pub mod pipe;
 
 /// XXX: Loop(*handle) is buggy with destructors. Normal structs
 /// with dtors may not be destructured, but tuple structs can,
@@ -127,6 +131,8 @@ pub type NullCallback = ~fn();
 pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
 pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
 pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
+// first int is exit_status, second is term_signal
+pub type ExitCallback = ~fn(Process, int, int, Option<UvError>);
 pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
 pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
 pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
@@ -145,7 +151,8 @@ struct WatcherData {
     timer_cb: Option<TimerCallback>,
     async_cb: Option<AsyncCallback>,
     udp_recv_cb: Option<UdpReceiveCallback>,
-    udp_send_cb: Option<UdpSendCallback>
+    udp_send_cb: Option<UdpSendCallback>,
+    exit_cb: Option<ExitCallback>,
 }
 
 pub trait WatcherInterop {
@@ -177,7 +184,8 @@ impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
                 timer_cb: None,
                 async_cb: None,
                 udp_recv_cb: None,
-                udp_send_cb: None
+                udp_send_cb: None,
+                exit_cb: None,
             };
             let data = transmute::<~WatcherData, *c_void>(data);
             uvll::set_data_for_uv_handle(self.native_handle(), data);
diff --git a/src/libstd/rt/uv/pipe.rs b/src/libstd/rt/uv/pipe.rs
new file mode 100644
index 00000000000..1147c731a60
--- /dev/null
+++ b/src/libstd/rt/uv/pipe.rs
@@ -0,0 +1,66 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+use libc;
+
+use rt::uv;
+use rt::uv::net;
+use rt::uv::uvll;
+
+pub struct Pipe(*uvll::uv_pipe_t);
+
+impl uv::Watcher for Pipe {}
+
+impl Pipe {
+    pub fn new(loop_: &uv::Loop, ipc: bool) -> Pipe {
+        unsafe {
+            let handle = uvll::malloc_handle(uvll::UV_NAMED_PIPE);
+            assert!(handle.is_not_null());
+            let ipc = ipc as libc::c_int;
+            assert_eq!(uvll::pipe_init(loop_.native_handle(), handle, ipc), 0);
+            let mut ret: Pipe =
+                    uv::NativeHandle::from_native_handle(handle);
+            ret.install_watcher_data();
+            ret
+        }
+    }
+
+    pub fn as_stream(&self) -> net::StreamWatcher {
+        net::StreamWatcher(**self as *uvll::uv_stream_t)
+    }
+
+    pub fn close(self, cb: uv::NullCallback) {
+        {
+            let mut this = self;
+            let data = this.get_watcher_data();
+            assert!(data.close_cb.is_none());
+            data.close_cb = Some(cb);
+        }
+
+        unsafe { uvll::close(self.native_handle(), close_cb); }
+
+        extern fn close_cb(handle: *uvll::uv_pipe_t) {
+            let mut process: Pipe = uv::NativeHandle::from_native_handle(handle);
+            process.get_watcher_data().close_cb.take_unwrap()();
+            process.drop_watcher_data();
+            unsafe { uvll::free_handle(handle as *libc::c_void) }
+        }
+    }
+}
+
+impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe {
+    fn from_native_handle(handle: *uvll::uv_pipe_t) -> Pipe {
+        Pipe(handle)
+    }
+    fn native_handle(&self) -> *uvll::uv_pipe_t {
+        match self { &Pipe(ptr) => ptr }
+    }
+}
diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs
new file mode 100644
index 00000000000..ccfa1ff87db
--- /dev/null
+++ b/src/libstd/rt/uv/process.rs
@@ -0,0 +1,219 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+use cell::Cell;
+use libc;
+use ptr;
+use util;
+use vec;
+
+use rt::io::process::*;
+use rt::uv;
+use rt::uv::uvio::UvPipeStream;
+use rt::uv::uvll;
+
+/// A process wraps the handle of the underlying uv_process_t.
+pub struct Process(*uvll::uv_process_t);
+
+impl uv::Watcher for Process {}
+
+impl Process {
+    /// Creates a new process, ready to spawn inside an event loop
+    pub fn new() -> Process {
+        let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
+        assert!(handle.is_not_null());
+        let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
+        ret.install_watcher_data();
+        return ret;
+    }
+
+    /// Spawn a new process inside the specified event loop.
+    ///
+    /// The `config` variable will be passed down to libuv, and the `exit_cb`
+    /// will be run only once, when the process exits.
+    ///
+    /// Returns either the corresponding process object or an error which
+    /// occurred.
+    pub fn spawn(&mut self, loop_: &uv::Loop, mut config: ProcessConfig,
+                 exit_cb: uv::ExitCallback)
+                    -> Result<~[Option<UvPipeStream>], uv::UvError>
+    {
+        let cwd = config.cwd.map_move(|s| s.to_c_str());
+
+        extern fn on_exit(p: *uvll::uv_process_t,
+                          exit_status: libc::c_int,
+                          term_signal: libc::c_int) {
+            let mut p: Process = uv::NativeHandle::from_native_handle(p);
+            let err = match exit_status {
+                0 => None,
+                _ => uv::status_to_maybe_uv_error(-1)
+            };
+            p.get_watcher_data().exit_cb.take_unwrap()(p,
+                                                       exit_status as int,
+                                                       term_signal as int,
+                                                       err);
+        }
+
+        let io = util::replace(&mut config.io, ~[]);
+        let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(io.len());
+        let mut ret_io = vec::with_capacity(io.len());
+        unsafe {
+            vec::raw::set_len(&mut stdio, io.len());
+            for (slot, other) in stdio.iter().zip(io.move_iter()) {
+                let io = set_stdio(slot as *uvll::uv_stdio_container_t, other);
+                ret_io.push(io);
+            }
+        }
+
+        let exit_cb = Cell::new(exit_cb);
+        let ret_io = Cell::new(ret_io);
+        do with_argv(config.program, config.args) |argv| {
+            do with_env(config.env) |envp| {
+                let options = uvll::uv_process_options_t {
+                    exit_cb: on_exit,
+                    file: unsafe { *argv },
+                    args: argv,
+                    env: envp,
+                    cwd: match cwd {
+                        Some(ref cwd) => cwd.with_ref(|p| p),
+                        None => ptr::null(),
+                    },
+                    flags: 0,
+                    stdio_count: stdio.len() as libc::c_int,
+                    stdio: stdio.as_imm_buf(|p, _| p),
+                    uid: 0,
+                    gid: 0,
+                };
+
+                match unsafe {
+                    uvll::spawn(loop_.native_handle(), **self, options)
+                } {
+                    0 => {
+                        (*self).get_watcher_data().exit_cb = Some(exit_cb.take());
+                        Ok(ret_io.take())
+                    }
+                    err => Err(uv::UvError(err))
+                }
+            }
+        }
+    }
+
+    /// Sends a signal to this process.
+    ///
+    /// This is a wrapper around `uv_process_kill`
+    pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
+        match unsafe {
+            uvll::process_kill(self.native_handle(), signum as libc::c_int)
+        } {
+            0 => Ok(()),
+            err => Err(uv::UvError(err))
+        }
+    }
+
+    /// Returns the process id of a spawned process
+    pub fn pid(&self) -> libc::pid_t {
+        unsafe { uvll::process_pid(**self) as libc::pid_t }
+    }
+
+    /// Closes this handle, invoking the specified callback once closed
+    pub fn close(self, cb: uv::NullCallback) {
+        {
+            let mut this = self;
+            let data = this.get_watcher_data();
+            assert!(data.close_cb.is_none());
+            data.close_cb = Some(cb);
+        }
+
+        unsafe { uvll::close(self.native_handle(), close_cb); }
+
+        extern fn close_cb(handle: *uvll::uv_process_t) {
+            let mut process: Process = uv::NativeHandle::from_native_handle(handle);
+            process.get_watcher_data().close_cb.take_unwrap()();
+            process.drop_watcher_data();
+            unsafe { uvll::free_handle(handle as *libc::c_void) }
+        }
+    }
+}
+
+unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
+                    io: StdioContainer) -> Option<UvPipeStream> {
+    match io {
+        Ignored => {
+            uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE);
+            None
+        }
+        InheritFd(fd) => {
+            uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
+            uvll::set_stdio_container_fd(dst, fd);
+            None
+        }
+        CreatePipe(pipe, readable, writable) => {
+            let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
+            if readable {
+                flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
+            }
+            if writable {
+                flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
+            }
+            let handle = pipe.pipe.as_stream().native_handle();
+            uvll::set_stdio_container_flags(dst, flags);
+            uvll::set_stdio_container_stream(dst, handle);
+            Some(pipe.bind())
+        }
+    }
+}
+
+/// Converts the program and arguments to the argv array expected by libuv
+fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
+    // First, allocation space to put all the C-strings (we need to have
+    // ownership of them somewhere
+    let mut c_strs = vec::with_capacity(args.len() + 1);
+    c_strs.push(prog.to_c_str());
+    for arg in args.iter() {
+        c_strs.push(arg.to_c_str());
+    }
+
+    // Next, create the char** array
+    let mut c_args = vec::with_capacity(c_strs.len() + 1);
+    for s in c_strs.iter() {
+        c_args.push(s.with_ref(|p| p));
+    }
+    c_args.push(ptr::null());
+    c_args.as_imm_buf(|buf, _| f(buf))
+}
+
+/// Converts the environment to the env array expected by libuv
+fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
+    let env = match env {
+        Some(s) => s,
+        None => { return f(ptr::null()); }
+    };
+    // As with argv, create some temporary storage and then the actual array
+    let mut envp = vec::with_capacity(env.len());
+    for &(ref key, ref value) in env.iter() {
+        envp.push(fmt!("%s=%s", *key, *value).to_c_str());
+    }
+    let mut c_envp = vec::with_capacity(envp.len() + 1);
+    for s in envp.iter() {
+        c_envp.push(s.with_ref(|p| p));
+    }
+    c_envp.push(ptr::null());
+    c_envp.as_imm_buf(|buf, _| f(buf))
+}
+
+impl uv::NativeHandle<*uvll::uv_process_t> for Process {
+    fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
+        Process(handle)
+    }
+    fn native_handle(&self) -> *uvll::uv_process_t {
+        match self { &Process(ptr) => ptr }
+    }
+}
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index 76dcf6daae6..ed6e16c8fdb 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -13,7 +13,7 @@ use cast::transmute;
 use cast;
 use cell::Cell;
 use clone::Clone;
-use libc::{c_int, c_uint, c_void};
+use libc::{c_int, c_uint, c_void, pid_t};
 use ops::Drop;
 use option::*;
 use ptr;
@@ -22,6 +22,8 @@ use result::*;
 use rt::io::IoError;
 use rt::io::net::ip::{SocketAddr, IpAddr};
 use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd};
+use rt::io::process::ProcessConfig;
+use rt::kill::BlockedTask;
 use rt::local::Local;
 use rt::rtio::*;
 use rt::sched::{Scheduler, SchedHandle};
@@ -735,6 +737,64 @@ impl IoFactory for UvIoFactory {
         assert!(!result_cell.is_empty());
         return result_cell.take();
     }
+
+    fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError> {
+        let home = get_handle_to_current_scheduler!();
+        Ok(~UvUnboundPipe { pipe: Pipe::new(self.uv_loop(), ipc), home: home })
+    }
+
+    fn spawn(&mut self, config: ProcessConfig)
+            -> Result<(~RtioProcessObject, ~[Option<RtioPipeObject>]), IoError>
+    {
+        // Sadly, we must create the UvProcess before we actually call uv_spawn
+        // so that the exit_cb can close over it and notify it when the process
+        // has exited.
+        let mut ret = ~UvProcess {
+            process: Process::new(),
+            home: None,
+            exit_status: None,
+            term_signal: None,
+            exit_error: None,
+            descheduled: None,
+        };
+        let ret_ptr = unsafe {
+            *cast::transmute::<&~UvProcess, &*mut UvProcess>(&ret)
+        };
+
+        // The purpose of this exit callback is to record the data about the
+        // exit and then wake up the task which may be waiting for the process
+        // to exit. This is all performed in the current io-loop, and the
+        // implementation of UvProcess ensures that reading these fields always
+        // occurs on the current io-loop.
+        let exit_cb: ExitCallback = |_, exit_status, term_signal, error| {
+            unsafe {
+                assert!((*ret_ptr).exit_status.is_none());
+                (*ret_ptr).exit_status = Some(exit_status);
+                (*ret_ptr).term_signal = Some(term_signal);
+                (*ret_ptr).exit_error = error;
+                match (*ret_ptr).descheduled.take() {
+                    Some(task) => {
+                        let scheduler: ~Scheduler = Local::take();
+                        scheduler.resume_blocked_task_immediately(task);
+                    }
+                    None => {}
+                }
+            }
+        };
+
+        match ret.process.spawn(self.uv_loop(), config, exit_cb) {
+            Ok(io) => {
+                // Only now do we actually get a handle to this scheduler.
+                ret.home = Some(get_handle_to_current_scheduler!());
+                Ok((ret, io))
+            }
+            Err(uverr) => {
+                // We still need to close the process handle we created, but
+                // that's taken care for us in the destructor of UvProcess
+                Err(uv_error_to_io_error(uverr))
+            }
+        }
+    }
 }
 
 pub struct UvTcpListener {
@@ -856,6 +916,126 @@ impl RtioTcpAcceptor for UvTcpAcceptor {
     }
 }
 
+fn read_stream(mut watcher: StreamWatcher,
+               scheduler: ~Scheduler,
+               buf: &mut [u8]) -> Result<uint, IoError> {
+    let result_cell = Cell::new_empty();
+    let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
+
+    let buf_ptr: *&mut [u8] = &buf;
+    do scheduler.deschedule_running_task_and_then |_sched, task| {
+        let task_cell = Cell::new(task);
+        // XXX: We shouldn't reallocate these callbacks every
+        // call to read
+        let alloc: AllocCallback = |_| unsafe {
+            slice_to_uv_buf(*buf_ptr)
+        };
+        do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
+
+            // Stop reading so that no read callbacks are
+            // triggered before the user calls `read` again.
+            // XXX: Is there a performance impact to calling
+            // stop here?
+            watcher.read_stop();
+
+            let result = if status.is_none() {
+                assert!(nread >= 0);
+                Ok(nread as uint)
+            } else {
+                Err(uv_error_to_io_error(status.unwrap()))
+            };
+
+            unsafe { (*result_cell_ptr).put_back(result); }
+
+            let scheduler: ~Scheduler = Local::take();
+            scheduler.resume_blocked_task_immediately(task_cell.take());
+        }
+    }
+
+    assert!(!result_cell.is_empty());
+    result_cell.take()
+}
+
+fn write_stream(mut watcher: StreamWatcher,
+                scheduler: ~Scheduler,
+                buf: &[u8]) -> Result<(), IoError> {
+    let result_cell = Cell::new_empty();
+    let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+    let buf_ptr: *&[u8] = &buf;
+    do scheduler.deschedule_running_task_and_then |_, task| {
+        let task_cell = Cell::new(task);
+        let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
+        do watcher.write(buf) |_watcher, status| {
+            let result = if status.is_none() {
+                Ok(())
+            } else {
+                Err(uv_error_to_io_error(status.unwrap()))
+            };
+
+            unsafe { (*result_cell_ptr).put_back(result); }
+
+            let scheduler: ~Scheduler = Local::take();
+            scheduler.resume_blocked_task_immediately(task_cell.take());
+        }
+    }
+
+    assert!(!result_cell.is_empty());
+    result_cell.take()
+}
+
+pub struct UvUnboundPipe {
+    pipe: Pipe,
+    home: SchedHandle,
+}
+
+impl HomingIO for UvUnboundPipe {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvUnboundPipe {
+    fn drop(&mut self) {
+        do self.home_for_io |self_| {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task_cell = Cell::new(task);
+                do self_.pipe.close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task_cell.take());
+                }
+            }
+        }
+    }
+}
+
+impl UvUnboundPipe {
+    pub unsafe fn bind(~self) -> UvPipeStream {
+        UvPipeStream { inner: self }
+    }
+}
+
+pub struct UvPipeStream {
+    priv inner: ~UvUnboundPipe,
+}
+
+impl UvPipeStream {
+    pub fn new(inner: ~UvUnboundPipe) -> UvPipeStream {
+        UvPipeStream { inner: inner }
+    }
+}
+
+impl RtioPipe for UvPipeStream {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
+        do self.inner.home_for_io_with_sched |self_, scheduler| {
+            read_stream(self_.pipe.as_stream(), scheduler, buf)
+        }
+    }
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+        do self.inner.home_for_io_with_sched |self_, scheduler| {
+            write_stream(self_.pipe.as_stream(), scheduler, buf)
+        }
+    }
+}
+
 pub struct UvTcpStream {
     watcher: TcpWatcher,
     home: SchedHandle,
@@ -890,70 +1070,13 @@ impl RtioSocket for UvTcpStream {
 impl RtioTcpStream for UvTcpStream {
     fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
         do self.home_for_io_with_sched |self_, scheduler| {
-            let result_cell = Cell::new_empty();
-            let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
-
-            let buf_ptr: *&mut [u8] = &buf;
-            do scheduler.deschedule_running_task_and_then |_sched, task| {
-                let task_cell = Cell::new(task);
-                // XXX: We shouldn't reallocate these callbacks every
-                // call to read
-                let alloc: AllocCallback = |_| unsafe {
-                    slice_to_uv_buf(*buf_ptr)
-                };
-                let mut watcher = self_.watcher.as_stream();
-                do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
-
-                    // Stop reading so that no read callbacks are
-                    // triggered before the user calls `read` again.
-                    // XXX: Is there a performance impact to calling
-                    // stop here?
-                    watcher.read_stop();
-
-                    let result = if status.is_none() {
-                        assert!(nread >= 0);
-                        Ok(nread as uint)
-                    } else {
-                        Err(uv_error_to_io_error(status.unwrap()))
-                    };
-
-                    unsafe { (*result_cell_ptr).put_back(result); }
-
-                    let scheduler: ~Scheduler = Local::take();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                }
-            }
-
-            assert!(!result_cell.is_empty());
-            result_cell.take()
+            read_stream(self_.watcher.as_stream(), scheduler, buf)
         }
     }
 
     fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
         do self.home_for_io_with_sched |self_, scheduler| {
-            let result_cell = Cell::new_empty();
-            let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
-            let buf_ptr: *&[u8] = &buf;
-            do scheduler.deschedule_running_task_and_then |_, task| {
-                let task_cell = Cell::new(task);
-                let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
-                let mut watcher = self_.watcher.as_stream();
-                do watcher.write(buf) |_watcher, status| {
-                    let result = if status.is_none() {
-                        Ok(())
-                    } else {
-                        Err(uv_error_to_io_error(status.unwrap()))
-                    };
-
-                    unsafe { (*result_cell_ptr).put_back(result); }
-
-                    let scheduler: ~Scheduler = Local::take();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                }
-            }
-
-            assert!(!result_cell.is_empty());
-            result_cell.take()
+            write_stream(self_.watcher.as_stream(), scheduler, buf)
         }
     }
 
@@ -1240,8 +1363,7 @@ impl UvTimer {
 
 impl Drop for UvTimer {
     fn drop(&mut self) {
-        let self_ = unsafe { transmute::<&UvTimer, &mut UvTimer>(self) };
-        do self_.home_for_io_with_sched |self_, scheduler| {
+        do self.home_for_io_with_sched |self_, scheduler| {
             rtdebug!("closing UvTimer");
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
@@ -1356,13 +1478,12 @@ impl UvFileStream {
 
 impl Drop for UvFileStream {
     fn drop(&mut self) {
-        let self_ = unsafe { transmute::<&UvFileStream, &mut UvFileStream>(self) };
         if self.close_on_drop {
-            do self_.home_for_io_with_sched |self_, scheduler| {
+            do self.home_for_io_with_sched |self_, scheduler| {
                 do scheduler.deschedule_running_task_and_then |_, task| {
                     let task_cell = Cell::new(task);
                     let close_req = file::FsRequest::new();
-                    do close_req.close(&self.loop_, self_.fd) |_,_| {
+                    do close_req.close(&self_.loop_, self_.fd) |_,_| {
                         let scheduler: ~Scheduler = Local::take();
                         scheduler.resume_blocked_task_immediately(task_cell.take());
                     };
@@ -1405,6 +1526,86 @@ impl RtioFileStream for UvFileStream {
     }
 }
 
+pub struct UvProcess {
+    process: process::Process,
+
+    // Sadly, this structure must be created before we return it, so in that
+    // brief interim the `home` is None.
+    home: Option<SchedHandle>,
+
+    // All None until the process exits (exit_error may stay None)
+    priv exit_status: Option<int>,
+    priv term_signal: Option<int>,
+    priv exit_error: Option<UvError>,
+
+    // Used to store which task to wake up from the exit_cb
+    priv descheduled: Option<BlockedTask>,
+}
+
+impl HomingIO for UvProcess {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.home.get_mut_ref() }
+}
+
+impl Drop for UvProcess {
+    fn drop(&mut self) {
+        let close = |self_: &mut UvProcess| {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task = Cell::new(task);
+                do self_.process.close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task.take());
+                }
+            }
+        };
+
+        // If home is none, then this process never actually successfully
+        // spawned, so there's no need to switch event loops
+        if self.home.is_none() {
+            close(self)
+        } else {
+            self.home_for_io(close)
+        }
+    }
+}
+
+impl RtioProcess for UvProcess {
+    fn id(&self) -> pid_t {
+        self.process.pid()
+    }
+
+    fn kill(&mut self, signal: int) -> Result<(), IoError> {
+        do self.home_for_io |self_| {
+            match self_.process.kill(signal) {
+                Ok(()) => Ok(()),
+                Err(uverr) => Err(uv_error_to_io_error(uverr))
+            }
+        }
+    }
+
+    fn wait(&mut self) -> int {
+        // Make sure (on the home scheduler) that we have an exit status listed
+        do self.home_for_io |self_| {
+            match self_.exit_status {
+                Some(*) => {}
+                None => {
+                    // If there's no exit code previously listed, then the
+                    // process's exit callback has yet to be invoked. We just
+                    // need to deschedule ourselves and wait to be reawoken.
+                    let scheduler: ~Scheduler = Local::take();
+                    do scheduler.deschedule_running_task_and_then |_, task| {
+                        assert!(self_.descheduled.is_none());
+                        self_.descheduled = Some(task);
+                    }
+                    assert!(self_.exit_status.is_some());
+                }
+            }
+        }
+
+        self.exit_status.unwrap()
+    }
+}
+
 #[test]
 fn test_simple_io_no_connect() {
     do run_in_mt_newsched_task {
diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs
index 42102a52e2e..790bf53a291 100644
--- a/src/libstd/rt/uv/uvll.rs
+++ b/src/libstd/rt/uv/uvll.rs
@@ -31,7 +31,6 @@
 
 use c_str::ToCStr;
 use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t};
-#[cfg(not(stage0))]
 use libc::ssize_t;
 use libc::{malloc, free};
 use libc;
@@ -67,6 +66,19 @@ pub mod errors {
     pub static EPIPE: c_int = -libc::EPIPE;
 }
 
+pub static PROCESS_SETUID: c_int = 1 << 0;
+pub static PROCESS_SETGID: c_int = 1 << 1;
+pub static PROCESS_WINDOWS_VERBATIM_ARGUMENTS: c_int = 1 << 2;
+pub static PROCESS_DETACHED: c_int = 1 << 3;
+pub static PROCESS_WINDOWS_HIDE: c_int = 1 << 4;
+
+pub static STDIO_IGNORE: c_int = 0x00;
+pub static STDIO_CREATE_PIPE: c_int = 0x01;
+pub static STDIO_INHERIT_FD: c_int = 0x02;
+pub static STDIO_INHERIT_STREAM: c_int = 0x04;
+pub static STDIO_READABLE_PIPE: c_int = 0x10;
+pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
+
 // see libuv/include/uv-unix.h
 #[cfg(unix)]
 pub struct uv_buf_t {
@@ -81,6 +93,26 @@ pub struct uv_buf_t {
     base: *u8,
 }
 
+pub struct uv_process_options_t {
+    exit_cb: uv_exit_cb,
+    file: *libc::c_char,
+    args: **libc::c_char,
+    env: **libc::c_char,
+    cwd: *libc::c_char,
+    flags: libc::c_uint,
+    stdio_count: libc::c_int,
+    stdio: *uv_stdio_container_t,
+    uid: uv_uid_t,
+    gid: uv_gid_t,
+}
+
+// These fields are private because they must be interfaced with through the
+// functions below.
+pub struct uv_stdio_container_t {
+    priv flags: libc::c_int,
+    priv stream: *uv_stream_t,
+}
+
 pub type uv_handle_t = c_void;
 pub type uv_loop_t = c_void;
 pub type uv_idle_t = c_void;
@@ -95,6 +127,8 @@ pub type uv_stream_t = c_void;
 pub type uv_fs_t = c_void;
 pub type uv_udp_send_t = c_void;
 pub type uv_getaddrinfo_t = c_void;
+pub type uv_process_t = c_void;
+pub type uv_pipe_t = c_void;
 
 pub struct uv_timespec_t {
     tv_sec: libc::c_long,
@@ -149,76 +183,39 @@ impl uv_stat_t {
     }
 }
 
-#[cfg(stage0)]
-pub type uv_idle_cb = *u8;
-#[cfg(stage0)]
-pub type uv_alloc_cb = *u8;
-#[cfg(stage0)]
-pub type uv_read_cb = *u8;
-#[cfg(stage0)]
-pub type uv_udp_send_cb = *u8;
-#[cfg(stage0)]
-pub type uv_udp_recv_cb = *u8;
-#[cfg(stage0)]
-pub type uv_close_cb = *u8;
-#[cfg(stage0)]
-pub type uv_walk_cb = *u8;
-#[cfg(stage0)]
-pub type uv_async_cb = *u8;
-#[cfg(stage0)]
-pub type uv_connect_cb = *u8;
-#[cfg(stage0)]
-pub type uv_connection_cb = *u8;
-#[cfg(stage0)]
-pub type uv_timer_cb = *u8;
-#[cfg(stage0)]
-pub type uv_write_cb = *u8;
-#[cfg(stage0)]
-pub type uv_getaddrinfo_cb = *u8;
-
-#[cfg(not(stage0))]
 pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
                                     status: c_int);
-#[cfg(not(stage0))]
 pub type uv_alloc_cb = extern "C" fn(stream: *uv_stream_t,
                                      suggested_size: size_t) -> uv_buf_t;
-#[cfg(not(stage0))]
 pub type uv_read_cb = extern "C" fn(stream: *uv_stream_t,
                                     nread: ssize_t,
                                     buf: uv_buf_t);
-#[cfg(not(stage0))]
 pub type uv_udp_send_cb = extern "C" fn(req: *uv_udp_send_t,
                                         status: c_int);
-#[cfg(not(stage0))]
 pub type uv_udp_recv_cb = extern "C" fn(handle: *uv_udp_t,
                                         nread: ssize_t,
                                         buf: uv_buf_t,
                                         addr: *sockaddr,
                                         flags: c_uint);
-#[cfg(not(stage0))]
 pub type uv_close_cb = extern "C" fn(handle: *uv_handle_t);
-#[cfg(not(stage0))]
 pub type uv_walk_cb = extern "C" fn(handle: *uv_handle_t,
                                     arg: *c_void);
-#[cfg(not(stage0))]
 pub type uv_async_cb = extern "C" fn(handle: *uv_async_t,
                                      status: c_int);
-#[cfg(not(stage0))]
 pub type uv_connect_cb = extern "C" fn(handle: *uv_connect_t,
                                        status: c_int);
-#[cfg(not(stage0))]
 pub type uv_connection_cb = extern "C" fn(handle: *uv_connection_t,
                                           status: c_int);
-#[cfg(not(stage0))]
 pub type uv_timer_cb = extern "C" fn(handle: *uv_timer_t,
                                      status: c_int);
-#[cfg(not(stage0))]
 pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
                                      status: c_int);
-#[cfg(not(stage0))]
 pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t,
                                            status: c_int,
                                            res: *addrinfo);
+pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t,
+                                    exit_status: c_int,
+                                    term_signal: c_int);
 
 pub type sockaddr = c_void;
 pub type sockaddr_in = c_void;
@@ -267,6 +264,11 @@ pub struct addrinfo {
     ai_next: *addrinfo
 }
 
+#[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
+#[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
+#[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
+#[cfg(windows)] pub type uv_gid_t = libc::c_uchar;
+
 #[deriving(Eq)]
 pub enum uv_handle_type {
     UV_UNKNOWN_HANDLE,
@@ -828,6 +830,45 @@ pub unsafe fn fs_req_cleanup(req: *uv_fs_t) {
     rust_uv_fs_req_cleanup(req);
 }
 
+pub unsafe fn spawn(loop_ptr: *c_void, result: *uv_process_t,
+                    options: uv_process_options_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    return rust_uv_spawn(loop_ptr, result, options);
+}
+
+pub unsafe fn process_kill(p: *uv_process_t, signum: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    return rust_uv_process_kill(p, signum);
+}
+
+pub unsafe fn process_pid(p: *uv_process_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    return rust_uv_process_pid(p);
+}
+
+pub unsafe fn set_stdio_container_flags(c: *uv_stdio_container_t,
+                                        flags: libc::c_int) {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_set_stdio_container_flags(c, flags);
+}
+
+pub unsafe fn set_stdio_container_fd(c: *uv_stdio_container_t,
+                                     fd: libc::c_int) {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_set_stdio_container_fd(c, fd);
+}
+
+pub unsafe fn set_stdio_container_stream(c: *uv_stdio_container_t,
+                                         stream: *uv_stream_t) {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_set_stdio_container_stream(c, stream);
+}
+
+pub unsafe fn pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_uv_pipe_init(loop_ptr, p, ipc)
+}
+
 // data access helpers
 pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
     #[fixed_stack_segment]; #[inline(never)];
@@ -1050,4 +1091,13 @@ extern {
                            node: *c_char, service: *c_char,
                            hints: *addrinfo) -> c_int;
     fn rust_uv_freeaddrinfo(ai: *addrinfo);
+    fn rust_uv_spawn(loop_ptr: *c_void, outptr: *uv_process_t,
+                     options: uv_process_options_t) -> c_int;
+    fn rust_uv_process_kill(p: *uv_process_t, signum: c_int) -> c_int;
+    fn rust_uv_process_pid(p: *uv_process_t) -> c_int;
+    fn rust_set_stdio_container_flags(c: *uv_stdio_container_t, flags: c_int);
+    fn rust_set_stdio_container_fd(c: *uv_stdio_container_t, fd: c_int);
+    fn rust_set_stdio_container_stream(c: *uv_stdio_container_t,
+                                       stream: *uv_stream_t);
+    fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int;
 }
diff --git a/src/libstd/run.rs b/src/libstd/run.rs
index 83646dc59b3..362eab17fe7 100644
--- a/src/libstd/run.rs
+++ b/src/libstd/run.rs
@@ -643,15 +643,28 @@ fn spawn_process_os(prog: &str, args: &[~str],
     use libc::funcs::bsd44::getdtablesize;
 
     mod rustrt {
-        use libc::c_void;
-
         #[abi = "cdecl"]
         extern {
             pub fn rust_unset_sigprocmask();
-            pub fn rust_set_environ(envp: *c_void);
         }
     }
 
+    #[cfg(windows)]
+    unsafe fn set_environ(_envp: *c_void) {}
+    #[cfg(target_os = "macos")]
+    unsafe fn set_environ(envp: *c_void) {
+        externfn!(fn _NSGetEnviron() -> *mut *c_void);
+
+        *_NSGetEnviron() = envp;
+    }
+    #[cfg(not(target_os = "macos"), not(windows))]
+    unsafe fn set_environ(envp: *c_void) {
+        extern {
+            static mut environ: *c_void;
+        }
+        environ = envp;
+    }
+
     unsafe {
 
         let pid = fork();
@@ -685,7 +698,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
 
         do with_envp(env) |envp| {
             if !envp.is_null() {
-                rustrt::rust_set_environ(envp);
+                set_environ(envp);
             }
             do with_argv(prog, args) |argv| {
                 execvp(*argv, argv);
@@ -736,8 +749,6 @@ fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
             let mut tmps = vec::with_capacity(env.len());
 
             for pair in env.iter() {
-                // Use of match here is just to workaround limitations
-                // in the stage0 irrefutable pattern impl.
                 let kv = fmt!("%s=%s", pair.first(), pair.second());
                 tmps.push(kv.to_c_str());
             }
diff --git a/src/libstd/std.rs b/src/libstd/std.rs
index 05433c47059..e9d5dd416ad 100644
--- a/src/libstd/std.rs
+++ b/src/libstd/std.rs
@@ -179,14 +179,8 @@ pub mod run;
 pub mod sys;
 pub mod cast;
 pub mod fmt;
-#[cfg(stage0)] #[path = "repr_stage0.rs"]
-pub mod repr;
-#[cfg(not(stage0))]
 pub mod repr;
 pub mod cleanup;
-#[cfg(stage0)] #[path = "reflect_stage0.rs"]
-pub mod reflect;
-#[cfg(not(stage0))]
 pub mod reflect;
 pub mod condition;
 pub mod logging;
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index 93cac8797bb..9707d592a2e 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -1107,8 +1107,8 @@ pub mod raw {
             Some(limit) => (true, limit),
             None => (false, 0)
         };
-        while(*(curr_ptr as *libc::c_char) != 0 as libc::c_char
-             && ((limited_count && ctr < limit) || !limited_count)) {
+        while(((limited_count && ctr < limit) || !limited_count)
+              && *(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
             let env_pair = from_c_str(
                 curr_ptr as *libc::c_char);
             result.push(env_pair);
diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs
index 3d35de0f898..c315c3f9dfc 100644
--- a/src/libstd/sys.rs
+++ b/src/libstd/sys.rs
@@ -14,8 +14,6 @@
 
 use c_str::ToCStr;
 use cast;
-#[cfg(stage0)]
-use io;
 use libc;
 use libc::{c_char, size_t};
 use repr;
@@ -92,7 +90,6 @@ pub fn refcount<T>(t: @T) -> uint {
     }
 }
 
-#[cfg(not(stage0))]
 pub fn log_str<T>(t: &T) -> ~str {
     use rt::io;
     use rt::io::Decorator;
@@ -101,12 +98,6 @@ pub fn log_str<T>(t: &T) -> ~str {
     repr::write_repr(&mut result as &mut io::Writer, t);
     str::from_utf8_owned(result.inner())
 }
-#[cfg(stage0)]
-pub fn log_str<T>(t: &T) -> ~str {
-    do io::with_str_writer |w| {
-        repr::write_repr(w, t)
-    }
-}
 
 /// Trait for initiating task failure.
 pub trait FailWithCause {
diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs
index c3791d18b38..349739a5ea6 100644
--- a/src/libstd/unstable/intrinsics.rs
+++ b/src/libstd/unstable/intrinsics.rs
@@ -76,103 +76,7 @@ pub struct TyDesc {
 pub enum Opaque { }
 
 #[lang="ty_visitor"]
-#[cfg(not(test), stage0)]
-pub trait TyVisitor {
-    fn visit_bot(&self) -> bool;
-    fn visit_nil(&self) -> bool;
-    fn visit_bool(&self) -> bool;
-
-    fn visit_int(&self) -> bool;
-    fn visit_i8(&self) -> bool;
-    fn visit_i16(&self) -> bool;
-    fn visit_i32(&self) -> bool;
-    fn visit_i64(&self) -> bool;
-
-    fn visit_uint(&self) -> bool;
-    fn visit_u8(&self) -> bool;
-    fn visit_u16(&self) -> bool;
-    fn visit_u32(&self) -> bool;
-    fn visit_u64(&self) -> bool;
-
-    fn visit_float(&self) -> bool;
-    fn visit_f32(&self) -> bool;
-    fn visit_f64(&self) -> bool;
-
-    fn visit_char(&self) -> bool;
-
-    fn visit_estr_box(&self) -> bool;
-    fn visit_estr_uniq(&self) -> bool;
-    fn visit_estr_slice(&self) -> bool;
-    fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool;
-
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool;
-
-    fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
-                        mtbl: uint, inner: *TyDesc) -> bool;
-
-    fn visit_enter_rec(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-    fn visit_rec_field(&self, i: uint, name: &str,
-                       mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_rec(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-
-    fn visit_enter_class(&self, n_fields: uint,
-                         sz: uint, align: uint) -> bool;
-    fn visit_class_field(&self, i: uint, name: &str,
-                         mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_class(&self, n_fields: uint,
-                         sz: uint, align: uint) -> bool;
-
-    fn visit_enter_tup(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-    fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_tup(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-
-    fn visit_enter_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint) -> bool;
-    fn visit_enter_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool;
-    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool;
-    fn visit_leave_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint) -> bool;
-
-    fn visit_enter_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool;
-    fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool;
-    fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool;
-
-    fn visit_trait(&self) -> bool;
-    fn visit_param(&self, i: uint) -> bool;
-    fn visit_self(&self) -> bool;
-    fn visit_type(&self) -> bool;
-    fn visit_opaque_box(&self) -> bool;
-    fn visit_closure_ptr(&self, ck: uint) -> bool;
-}
-
-#[lang="ty_visitor"]
-#[cfg(not(test), not(stage0))]
+#[cfg(not(test))]
 pub trait TyVisitor {
     fn visit_bot(&mut self) -> bool;
     fn visit_nil(&mut self) -> bool;
@@ -424,9 +328,6 @@ extern "rust-intrinsic" {
     /// Returns `true` if a type is managed (will be allocated on the local heap)
     pub fn contains_managed<T>() -> bool;
 
-    #[cfg(stage0)]
-    pub fn visit_tydesc(td: *TyDesc, tv: &TyVisitor);
-    #[cfg(not(stage0))]
     pub fn visit_tydesc(td: *TyDesc, tv: &mut TyVisitor);
 
     pub fn frame_address(f: &once fn(*u8));
diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs
index 1dafeb27a0e..c2ef2300fc2 100644
--- a/src/libstd/unstable/sync.rs
+++ b/src/libstd/unstable/sync.rs
@@ -411,23 +411,6 @@ impl<T:Send> Exclusive<T> {
     }
 }
 
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
-    (fn $name:ident () $(-> $ret_ty:ty),*) => (
-        extern {
-            fn $name() $(-> $ret_ty),*;
-        }
-    );
-    (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
-        extern {
-            fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
-        }
-    )
-)
-}
-
 externfn!(fn rust_create_little_lock() -> rust_little_lock)
 externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
 externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index cbc6b604bb7..f0f86911f50 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -804,7 +804,7 @@ pub fn new_sctable_internal() -> SCTable {
 
 // fetch the SCTable from TLS, create one if it doesn't yet exist.
 pub fn get_sctable() -> @mut SCTable {
-    static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
+    local_data_key!(sctable_key: @@mut SCTable)
     match local_data::get(sctable_key, |k| k.map_move(|k| *k)) {
         None => {
             let new_table = @@mut new_sctable_internal();
@@ -841,7 +841,7 @@ pub type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
 // okay, I admit, putting this in TLS is not so nice:
 // fetch the SCTable from TLS, create one if it doesn't yet exist.
 pub fn get_resolve_table() -> @mut ResolveTable {
-    static resolve_table_key: local_data::Key<@@mut ResolveTable> = &local_data::Key;
+    local_data_key!(resolve_table_key: @@mut ResolveTable)
     match local_data::get(resolve_table_key, |k| k.map(|&k| *k)) {
         None => {
             let new_table = @@mut HashMap::new();
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index 536267a2235..5e9714ca5b2 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -187,7 +187,7 @@ fn diagnosticcolor(lvl: level) -> term::color::Color {
 }
 
 fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
-    static tls_terminal: local_data::Key<@Option<term::Terminal>> = &local_data::Key;
+    local_data_key!(tls_terminal: @Option<term::Terminal>)
 
     let stderr = io::stderr();
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 6cb5a93a313..889c2a5976e 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -644,25 +644,11 @@ impl AstBuilder for @ExtCtxt {
 
         self.expr(span, ast::ExprFnBlock(fn_decl, blk))
     }
-    #[cfg(stage0)]
-    fn lambda0(&self, _span: Span, blk: ast::Block) -> @ast::Expr {
-        let ext_cx = *self;
-        let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
-        quote_expr!(|| $blk_e )
-    }
-    #[cfg(not(stage0))]
     fn lambda0(&self, _span: Span, blk: ast::Block) -> @ast::Expr {
         let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
         quote_expr!(*self, || $blk_e )
     }
 
-    #[cfg(stage0)]
-    fn lambda1(&self, _span: Span, blk: ast::Block, ident: ast::Ident) -> @ast::Expr {
-        let ext_cx = *self;
-        let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
-        quote_expr!(|$ident| $blk_e )
-    }
-    #[cfg(not(stage0))]
     fn lambda1(&self, _span: Span, blk: ast::Block, ident: ast::Ident) -> @ast::Expr {
         let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
         quote_expr!(*self, |$ident| $blk_e )
diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs
index 0c7bbefc690..d8c78842808 100644
--- a/src/libsyntax/ext/deriving/default.rs
+++ b/src/libsyntax/ext/deriving/default.rs
@@ -47,9 +47,7 @@ fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Exp
         cx.ident_of("Default"),
         cx.ident_of("default")
     ];
-    let default_call = || {
-        cx.expr_call_global(span, default_ident.clone(), ~[])
-    };
+    let default_call = cx.expr_call_global(span, default_ident.clone(), ~[]);
 
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
@@ -58,13 +56,13 @@ fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Exp
                     if count == 0 {
                         cx.expr_ident(span, substr.type_ident)
                     } else {
-                        let exprs = vec::from_fn(count, |_| default_call());
+                        let exprs = vec::from_elem(count, default_call);
                         cx.expr_call_ident(span, substr.type_ident, exprs)
                     }
                 }
                 Right(ref fields) => {
                     let default_fields = do fields.map |ident| {
-                        cx.field_imm(span, *ident, default_call())
+                        cx.field_imm(span, *ident, default_call)
                     };
                     cx.expr_struct_ident(span, substr.type_ident, default_fields)
                 }
diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs
index fc527d44b53..2546cfc2e39 100644
--- a/src/libsyntax/ext/deriving/zero.rs
+++ b/src/libsyntax/ext/deriving/zero.rs
@@ -62,9 +62,7 @@ fn zero_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
         cx.ident_of("Zero"),
         cx.ident_of("zero")
     ];
-    let zero_call = || {
-        cx.expr_call_global(span, zero_ident.clone(), ~[])
-    };
+    let zero_call = cx.expr_call_global(span, zero_ident.clone(), ~[]);
 
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
@@ -73,13 +71,13 @@ fn zero_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
                     if count == 0 {
                         cx.expr_ident(span, substr.type_ident)
                     } else {
-                        let exprs = vec::from_fn(count, |_| zero_call());
+                        let exprs = vec::from_elem(count, zero_call);
                         cx.expr_call_ident(span, substr.type_ident, exprs)
                     }
                 }
                 Right(ref fields) => {
                     let zero_fields = do fields.map |ident| {
-                        cx.field_imm(span, *ident, zero_call())
+                        cx.field_imm(span, *ident, zero_call)
                     };
                     cx.expr_struct_ident(span, substr.type_ident, zero_fields)
                 }
diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs
index ac8a7d513dd..e97af9cbfb1 100644
--- a/src/libsyntax/ext/env.rs
+++ b/src/libsyntax/ext/env.rs
@@ -22,18 +22,6 @@ use ext::build::AstBuilder;
 
 use std::os;
 
-#[cfg(stage0)]
-pub fn expand_option_env(ext_cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
-    -> base::MacResult {
-    let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!");
-
-    let e = match os::getenv(var) {
-      None => quote_expr!(::std::option::None::<&'static str>),
-      Some(s) => quote_expr!(::std::option::Some($s))
-    };
-    MRExpr(e)
-}
-#[cfg(not(stage0))]
 pub fn expand_option_env(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
     -> base::MacResult {
     let var = get_single_str_from_tts(cx, sp, tts, "option_env!");
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index ac094c27a81..0bee7895420 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -863,9 +863,7 @@ pub fn std_macros() -> @str {
 
                 use super::*;
 
-                static key: ::std::local_data::Key<
-                    @::std::condition::Handler<$input, $out>> =
-                    &::std::local_data::Key;
+                local_data_key!(key: @::std::condition::Handler<$input, $out>)
 
                 pub static cond :
                     ::std::condition::Condition<$input,$out> =
@@ -884,9 +882,7 @@ pub fn std_macros() -> @str {
 
                 use super::*;
 
-                static key: ::std::local_data::Key<
-                    @::std::condition::Handler<$input, $out>> =
-                    &::std::local_data::Key;
+                local_data_key!(key: @::std::condition::Handler<$input, $out>)
 
                 pub static cond :
                     ::std::condition::Condition<$input,$out> =
@@ -898,42 +894,6 @@ pub fn std_macros() -> @str {
         }
     )
 
-    //
-    // A scheme-style conditional that helps to improve code clarity in some instances when
-    // the `if`, `else if`, and `else` keywords obscure predicates undesirably.
-    //
-    // # Example
-    //
-    // ~~~
-    // let clamped =
-    //     if x > mx { mx }
-    //     else if x < mn { mn }
-    //     else { x };
-    // ~~~
-    //
-    // Using `cond!`, the above could be written as:
-    //
-    // ~~~
-    // let clamped = cond!(
-    //     (x > mx) { mx }
-    //     (x < mn) { mn }
-    //     _        { x  }
-    // );
-    // ~~~
-    //
-    // The optional default case is denoted by `_`.
-    //
-    macro_rules! cond (
-        ( $(($pred:expr) $body:block)+ _ $default:block ) => (
-            $(if $pred $body else)+
-            $default
-        );
-        // for if the default case was ommitted
-        ( $(($pred:expr) $body:block)+ ) => (
-            $(if $pred $body)else+
-        );
-    )
-
     // NOTE(acrichto): start removing this after the next snapshot
     macro_rules! printf (
         ($arg:expr) => (
@@ -975,8 +935,6 @@ pub fn std_macros() -> @str {
         ($($arg:tt)*) => (::std::io::println(format!($($arg)*)))
     )
 
-    // NOTE: use this after a snapshot lands to abstract the details
-    // of the TLS interface.
     macro_rules! local_data_key (
         ($name:ident: $ty:ty) => (
             static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
index 9f4e55b1a92..cace4648df2 100644
--- a/src/libsyntax/ext/format.rs
+++ b/src/libsyntax/ext/format.rs
@@ -76,6 +76,7 @@ impl Context {
                 self.ecx.span_err(sp, "expected token: `,`");
                 return (extra, None);
             }
+            if *p.token == token::EOF { break } // accept trailing commas
             if named || (token::is_ident(p.token) &&
                          p.look_ahead(1, |t| *t == token::EQ)) {
                 named = true;
diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs
index c267a673fce..0bc9e619274 100644
--- a/src/libsyntax/parse/lexer.rs
+++ b/src/libsyntax/parse/lexer.rs
@@ -699,6 +699,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
               '\\' => { c2 = '\\'; }
               '\'' => { c2 = '\''; }
               '"' => { c2 = '"'; }
+              '0' => { c2 = '\x00'; }
               'x' => { c2 = scan_numeric_escape(rdr, 2u); }
               'u' => { c2 = scan_numeric_escape(rdr, 4u); }
               'U' => { c2 = scan_numeric_escape(rdr, 8u); }
@@ -738,6 +739,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
                   '\'' => accum_str.push_char('\''),
                   '"' => accum_str.push_char('"'),
                   '\n' => consume_whitespace(rdr),
+                  '0' => accum_str.push_char('\x00'),
                   'x' => {
                     accum_str.push_char(scan_numeric_escape(rdr, 2u));
                   }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index fa00b536837..a8df737e49f 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -490,8 +490,7 @@ fn mk_fresh_ident_interner() -> @ident_interner {
 // if an interner exists in TLS, return it. Otherwise, prepare a
 // fresh one.
 pub fn get_ident_interner() -> @ident_interner {
-    static key: local_data::Key<@@::parse::token::ident_interner> =
-        &local_data::Key;
+    local_data_key!(key: @@::parse::token::ident_interner)
     match local_data::get(key, |k| k.map_move(|k| *k)) {
         Some(interner) => *interner,
         None => {
diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs
index af2a4977082..615f3301373 100644
--- a/src/libsyntax/print/pp.rs
+++ b/src/libsyntax/print/pp.rs
@@ -243,7 +243,7 @@ pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer {
  * the entire buffered window, but can't output anything until the size is >=
  * 0 (sizes are set to negative while they're pending calculation).
  *
- * So SCAN takeks input and buffers tokens and pending calculations, while
+ * So SCAN takes input and buffers tokens and pending calculations, while
  * PRINT gobbles up completed calculations and tokens from the buffer. The
  * theory is that the two can never get more than 3N tokens apart, because
  * once there's "obviously" too much data to fit on a line, in a size
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index ec84cbda973..b5868cbc63d 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1535,15 +1535,15 @@ fn print_path_(s: @ps,
 
         print_ident(s, segment.identifier);
 
-        if segment.lifetime.is_some() || !segment.types.is_empty() {
-            // If this is the last segment, print the bounds.
-            if i == path.segments.len() - 1 {
-                match *opt_bounds {
-                    None => {}
-                    Some(ref bounds) => print_bounds(s, bounds, true),
-                }
+        // If this is the last segment, print the bounds.
+        if i == path.segments.len() - 1 {
+            match *opt_bounds {
+                None => {}
+                Some(ref bounds) => print_bounds(s, bounds, true),
             }
+        }
 
+        if segment.lifetime.is_some() || !segment.types.is_empty() {
             if colons_before_params {
                 word(s.s, "::")
             }
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 4b718303f2c..8877b082588 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -643,6 +643,29 @@ rust_valgrind_stack_deregister(unsigned int id) {
   VALGRIND_STACK_DEREGISTER(id);
 }
 
+#if defined(__WIN32__)
+
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+    // empty stub for windows to keep linker happy
+}
+
+#else
+
+#include <signal.h>
+#include <unistd.h>
+
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+    // this can't be safely converted to rust code because the
+    // representation of sigset_t is platform-dependent
+    sigset_t sset;
+    sigemptyset(&sset);
+    sigprocmask(SIG_SETMASK, &sset, NULL);
+}
+
+#endif
+
 //
 // Local Variables:
 // mode: C++
diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp
deleted file mode 100644
index 25cbaf822f0..00000000000
--- a/src/rt/rust_run_program.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-#include "rust_globals.h"
-
-#ifdef __APPLE__
-#include <crt_externs.h>
-#endif
-
-#if defined(__WIN32__)
-
-extern "C" CDECL void
-rust_unset_sigprocmask() {
-    // empty stub for windows to keep linker happy
-}
-
-extern "C" CDECL void
-rust_set_environ(void* envp) {
-    // empty stub for windows to keep linker happy
-}
-
-#elif defined(__GNUC__)
-
-#include <signal.h>
-#include <unistd.h>
-
-#ifdef __FreeBSD__
-extern char **environ;
-#endif
-
-extern "C" CDECL void
-rust_unset_sigprocmask() {
-    // this can't be safely converted to rust code because the
-    // representation of sigset_t is platform-dependent
-    sigset_t sset;
-    sigemptyset(&sset);
-    sigprocmask(SIG_SETMASK, &sset, NULL);
-}
-
-extern "C" CDECL void
-rust_set_environ(void* envp) {
-    // FIXME: this could actually be converted to rust (see issue #2674)
-#ifdef __APPLE__
-    *_NSGetEnviron() = (char **) envp;
-#else
-    environ = (char **) envp;
-#endif
-}
-
-#else
-#error "Platform not supported."
-#endif
-
-//
-// Local Variables:
-// mode: C++
-// 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/rt/rust_uv.cpp b/src/rt/rust_uv.cpp
index 9b460cffd74..3e9b8ba136e 100644
--- a/src/rt/rust_uv.cpp
+++ b/src/rt/rust_uv.cpp
@@ -602,3 +602,38 @@ extern "C" int
 rust_uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) {
   return uv_fs_readdir(loop, req, path, flags, cb);
 }
+
+extern "C" int
+rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) {
+  return uv_spawn(loop, p, options);
+}
+
+extern "C" int
+rust_uv_process_kill(uv_process_t *p, int signum) {
+  return uv_process_kill(p, signum);
+}
+
+extern "C" void
+rust_set_stdio_container_flags(uv_stdio_container_t *c, int flags) {
+  c->flags = (uv_stdio_flags) flags;
+}
+
+extern "C" void
+rust_set_stdio_container_fd(uv_stdio_container_t *c, int fd) {
+  c->data.fd = fd;
+}
+
+extern "C" void
+rust_set_stdio_container_stream(uv_stdio_container_t *c, uv_stream_t *stream) {
+  c->data.stream = stream;
+}
+
+extern "C" int
+rust_uv_process_pid(uv_process_t* p) {
+  return p->pid;
+}
+
+extern "C" int
+rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) {
+  return uv_pipe_init(loop, p, ipc);
+}
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index 3be958837dc..7a9149187d8 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -25,7 +25,6 @@ rust_list_dir_wfd_fp_buf
 rust_log_console_on
 rust_log_console_off
 rust_should_log_console
-rust_set_environ
 rust_unset_sigprocmask
 rust_env_pairs
 upcall_rust_personality
@@ -198,3 +197,10 @@ rust_drop_linenoise_lock
 rust_get_test_int
 rust_get_task
 rust_uv_get_loop_from_getaddrinfo_req
+rust_uv_spawn
+rust_uv_process_kill
+rust_set_stdio_container_flags
+rust_set_stdio_container_fd
+rust_set_stdio_container_stream
+rust_uv_process_pid
+rust_uv_pipe_init
diff --git a/src/rustdoc_ng/rustdoc_ng.rs b/src/rustdoc_ng/rustdoc_ng.rs
index ec6ad6974e9..a4e3bc50d11 100644
--- a/src/rustdoc_ng/rustdoc_ng.rs
+++ b/src/rustdoc_ng/rustdoc_ng.rs
@@ -41,7 +41,6 @@ pub fn main() {
 }
 
 pub fn main_args(args: &[~str]) {
-    use extra::getopts::*;
     use extra::getopts::groups::*;
 
     let opts = ~[
@@ -56,20 +55,20 @@ pub fn main_args(args: &[~str]) {
 
     let matches = getopts(args.tail(), opts).unwrap();
 
-    if opt_present(&matches, "h") || opt_present(&matches, "help") {
+    if matches.opt_present("h") || matches.opt_present("help") {
         println(usage(args[0], opts));
         return;
     }
 
-    let libs = Cell::new(opt_strs(&matches, "L").map(|s| Path(*s)));
+    let libs = Cell::new(matches.opt_strs("L").map(|s| Path(*s)));
 
-    let mut passes = if opt_present(&matches, "n") {
+    let mut passes = if matches.opt_present("n") {
         ~[]
     } else {
         ~[~"collapse-docs", ~"clean-comments", ~"collapse-privacy" ]
     };
 
-    opt_strs(&matches, "a").map(|x| passes.push(x.clone()));
+    matches.opt_strs("a").map(|x| passes.push(x.clone()));
 
     if matches.free.len() != 1 {
         println(usage(args[0], opts));
@@ -99,7 +98,7 @@ pub fn main_args(args: &[~str]) {
         })
     }
 
-    for pname in opt_strs(&matches, "p").move_iter() {
+    for pname in matches.opt_strs("p").move_iter() {
         pm.load_plugin(pname);
     }
 
diff --git a/src/snapshots.txt b/src/snapshots.txt
index ad170d9173f..705cf50632a 100644
--- a/src/snapshots.txt
+++ b/src/snapshots.txt
@@ -1,3 +1,11 @@
+S 2013-09-17 cbd1eef
+  freebsd-x86_64 9166867a8859076343cb3e57da918b5c0eea720b
+  linux-i386 38347b579312ff30c36d257a1161660eb0ae8422
+  linux-x86_64 0c169bba5d6729d0c0f096d61d9274fb082b4b34
+  macos-i386 1eb229510dd12b91800674566b8dad401a3f80d3
+  macos-x86_64 1c5d8e29b9671af93963e1b5fa9fcca081124a39
+  winnt-i386 56baa04a1f02235ebc5a75be05aa65fdc822a4e6
+
 S 2013-08-14 e7b5729
   freebsd-x86_64 9de0b5583a5c4413f9e77df7071498385e936dd2
   linux-i386 29119a9072f74c639c2bad998edc40e582da540e
diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs
index 7029ca2a492..0896682b322 100644
--- a/src/test/bench/shootout-pfib.rs
+++ b/src/test/bench/shootout-pfib.rs
@@ -64,7 +64,7 @@ fn parse_opts(argv: ~[~str]) -> Config {
 
     match getopts::getopts(opt_args, opts) {
       Ok(ref m) => {
-          return Config {stress: getopts::opt_present(m, "stress")}
+          return Config {stress: m.opt_present("stress")}
       }
       Err(_) => { fail!(); }
     }
diff --git a/src/test/pretty/path-type-bounds.rs b/src/test/pretty/path-type-bounds.rs
new file mode 100644
index 00000000000..a62fbdeeb18
--- /dev/null
+++ b/src/test/pretty/path-type-bounds.rs
@@ -0,0 +1,13 @@
+// pp-exact
+
+trait Tr { }
+impl Tr for int;
+
+fn foo(x: ~Tr: Freeze) -> ~Tr: Freeze { x }
+
+fn main() {
+    let x: ~Tr: Freeze;
+
+    ~1 as ~Tr: Freeze;
+}
+
diff --git a/src/test/run-pass/cond-macro-no-default.rs b/src/test/run-pass/cond-macro-no-default.rs
deleted file mode 100644
index 8bd1a772e55..00000000000
--- a/src/test/run-pass/cond-macro-no-default.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn clamp<T:Ord + Signed>(x: T, mn: T, mx: T) -> T {
-    cond!(
-        (x > mx) { return mx; }
-        (x < mn) { return mn; }
-    )
-    return x;
-}
-
-fn main() {
-    assert_eq!(clamp(1, 2, 4), 2);
-    assert_eq!(clamp(8, 2, 4), 4);
-    assert_eq!(clamp(3, 2, 4), 3);
-}
diff --git a/src/test/run-pass/extern-pass-TwoU64s-ref.rs b/src/test/run-pass/extern-pass-TwoU64s-ref.rs
index 1937c366831..ed9871b5edb 100644
--- a/src/test/run-pass/extern-pass-TwoU64s-ref.rs
+++ b/src/test/run-pass/extern-pass-TwoU64s-ref.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // Test that we ignore modes when calling extern functions.
+// xfail-fast #9205
 
 #[deriving(Eq)]
 struct TwoU64s {
diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs
index b543099b3b8..772970ce8a3 100644
--- a/src/test/run-pass/extern-pass-TwoU64s.rs
+++ b/src/test/run-pass/extern-pass-TwoU64s.rs
@@ -14,6 +14,7 @@
 // xfail-fast This works standalone on windows but not with check-fast.
 // possibly because there is another test that uses this extern fn but gives it
 // a different signature
+// xfail-fast #9205
 
 #[deriving(Eq)]
 struct TwoU64s {
diff --git a/src/test/run-pass/extern-return-TwoU64s.rs b/src/test/run-pass/extern-return-TwoU64s.rs
index 4dc31d71526..7fcbe3670fc 100644
--- a/src/test/run-pass/extern-return-TwoU64s.rs
+++ b/src/test/run-pass/extern-return-TwoU64s.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// xfail-fast #9205
+
 struct TwoU64s {
     one: u64, two: u64
 }
diff --git a/src/test/run-pass/getopts_ref.rs b/src/test/run-pass/getopts_ref.rs
index cebd2910070..d1964b5d94b 100644
--- a/src/test/run-pass/getopts_ref.rs
+++ b/src/test/run-pass/getopts_ref.rs
@@ -20,8 +20,8 @@ pub fn main() {
 
     match getopts(args, opts) {
         Ok(ref m)  =>
-            assert!(!opt_present(m, "b")),
-        Err(ref f) => fail!(fail_str((*f).clone()))
+            assert!(!m.opt_present("b")),
+        Err(ref f) => fail!((*f).clone().to_err_msg())
     };
 
 }
diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs
index 351bad193da..6ca21c6c5a1 100644
--- a/src/test/run-pass/ifmt.rs
+++ b/src/test/run-pass/ifmt.rs
@@ -243,6 +243,10 @@ pub fn main() {
     }
 
     test_format_args();
+
+    // test that trailing commas are acceptable
+    format!("{}", "test",);
+    format!("{foo}", foo="test",);
 }
 
 // Basic test to make sure that we can invoke the `write!` macro with an
diff --git a/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs b/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs
index 1492b5895ba..2f2b736294a 100644
--- a/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs
+++ b/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-pretty #9253 pretty printer doesn't preserve the bounds on trait objects
-
 /*
 
 #7673 Polymorphically creating traits barely works
diff --git a/src/test/run-pass/nul-characters.rs b/src/test/run-pass/nul-characters.rs
new file mode 100644
index 00000000000..2a301d0b0fd
--- /dev/null
+++ b/src/test/run-pass/nul-characters.rs
@@ -0,0 +1,44 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main()
+{
+    let all_nuls1 = "\0\x00\u0000\U00000000";
+    let all_nuls2 = "\U00000000\u0000\x00\0";
+    let all_nuls3 = "\u0000\U00000000\x00\0";
+    let all_nuls4 = "\x00\u0000\0\U00000000";
+
+    // sizes for two should suffice
+    assert_eq!(all_nuls1.len(), 4); 
+    assert_eq!(all_nuls2.len(), 4);
+
+    // string equality should pass between the strings
+    assert_eq!(all_nuls1, all_nuls2);
+    assert_eq!(all_nuls2, all_nuls3);
+    assert_eq!(all_nuls3, all_nuls4);
+    
+    // all extracted characters in all_nuls are equivalent to each other
+    for c1 in all_nuls1.iter()
+    {
+        for c2 in all_nuls1.iter()
+        {
+            assert_eq!(c1,c2);
+        }
+    }
+    
+    // testing equality between explicit character literals
+    assert_eq!('\0', '\x00');
+    assert_eq!('\u0000', '\x00');
+    assert_eq!('\u0000', '\U00000000');
+
+    // NUL characters should make a difference
+    assert!("Hello World" != "Hello \0World");
+    assert!("Hello World" != "Hello World\0");
+}
diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs
index 3f63902eb31..a1f5a2392b1 100644
--- a/src/test/run-pass/struct-return.rs
+++ b/src/test/run-pass/struct-return.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// xfail-fast #9205
+
 pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
 pub struct Floats { a: f64, b: u8, c: f64 }