]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #8886 : cmr/rust/test-restructure, r=cmr
authorbors <bors@rust-lang.org>
Fri, 30 Aug 2013 21:00:43 +0000 (14:00 -0700)
committerbors <bors@rust-lang.org>
Fri, 30 Aug 2013 21:00:43 +0000 (14:00 -0700)
101 files changed:
.gitmodules
doc/rust.md
doc/tutorial-tasks.md
mk/llvm.mk
mk/platform.mk
mk/rt.mk
mk/tests.mk
src/compiletest/common.rs
src/compiletest/compiletest.rs
src/compiletest/procsrv.rs
src/compiletest/runtest.rs
src/etc/emacs/rust-mode.el
src/etc/vim/syntax/rust.vim
src/libextra/dlist.rs
src/libextra/test.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/meth.rs
src/librustc/middle/trans/type_use.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/mod.rs
src/librustdoc/markdown_writer.rs
src/librustpkg/source_control.rs
src/librustpkg/tests.rs
src/libstd/c_str.rs
src/libstd/io.rs
src/libstd/iter.rs [deleted file]
src/libstd/local_data.rs
src/libstd/logging.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/num/float.rs
src/libstd/num/num.rs
src/libstd/num/uint.rs
src/libstd/os.rs
src/libstd/prelude.rs
src/libstd/ptr.rs
src/libstd/reflect.rs
src/libstd/reflect_stage0.rs [new file with mode: 0644]
src/libstd/repr.rs
src/libstd/repr_stage0.rs [new file with mode: 0644]
src/libstd/rt/args.rs
src/libstd/rt/comm.rs
src/libstd/rt/io/file.rs
src/libstd/rt/io/mod.rs
src/libstd/rt/io/net/tcp.rs
src/libstd/rt/io/pipe.rs [deleted file]
src/libstd/rt/io/support.rs
src/libstd/rt/local_ptr.rs
src/libstd/rt/mod.rs
src/libstd/rt/rtio.rs
src/libstd/rt/sched.rs
src/libstd/rt/stack.rs
src/libstd/rt/task.rs
src/libstd/rt/util.rs
src/libstd/rt/uv/async.rs
src/libstd/rt/uv/file.rs
src/libstd/rt/uv/idle.rs
src/libstd/rt/uv/mod.rs
src/libstd/rt/uv/net.rs
src/libstd/rt/uv/pipe.rs [deleted file]
src/libstd/rt/uv/process.rs [deleted file]
src/libstd/rt/uv/timer.rs
src/libstd/rt/uv/uvio.rs
src/libstd/rt/uv/uvll.rs
src/libstd/run.rs
src/libstd/select.rs
src/libstd/std.rs
src/libstd/str.rs
src/libstd/sys.rs
src/libstd/task/local_data_priv.rs [deleted file]
src/libstd/task/mod.rs
src/libstd/unstable/dynamic_lib.rs
src/libstd/unstable/intrinsics.rs
src/libstd/unstable/sync.rs
src/libstd/vec.rs
src/libsyntax/ast.rs
src/libsyntax/fold.rs
src/libsyntax/oldvisit.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/libuv
src/llvm
src/rt/rust_uv.cpp
src/rt/rustrt.def.in
src/rustllvm/PassWrapper.cpp
src/rustllvm/RustWrapper.cpp
src/test/auxiliary/nested_item.rs [new file with mode: 0644]
src/test/compile-fail/issue-5239-1.rs [new file with mode: 0644]
src/test/compile-fail/keyword-typeof.rs [new file with mode: 0644]
src/test/compile-fail/lint-unused-import-tricky-globs.rs [new file with mode: 0644]
src/test/compile-fail/no-unsafe-self.rs [new file with mode: 0644]
src/test/run-fail/test-tasks-invalid-value.rs [new file with mode: 0644]
src/test/run-pass/core-run-destroy.rs
src/test/run-pass/issue-5239-2.rs [new file with mode: 0644]
src/test/run-pass/nested_item_main.rs [new file with mode: 0644]
src/test/run-pass/reflect-visit-data.rs
src/test/run-pass/reflect-visit-type.rs

index fa979b6d868ef4bebdcc7a79891e4f61e27ce328..88ead6e608d5c4ee00212451f47c281d09d00846 100644 (file)
@@ -4,5 +4,5 @@
        branch = master
 [submodule "src/libuv"]
        path = src/libuv
-       url = https://github.com/alexcrichton/libuv.git
+       url = https://github.com/brson/libuv.git
        branch = master
index 08c04c6c8887e9c046c0b9991073385eecbe187c..b33006733ab37ab5d760ed35c9d56b0752fd525d 100644 (file)
@@ -209,7 +209,7 @@ break
 do
 else enum extern
 false fn for
-if impl
+if impl in
 let loop
 match mod mut
 priv pub
index d190c332e6633ade92d1a9ac944aef034caca1db..18f35cf39a8a24895f1067949f41216c3a403a0d 100644 (file)
@@ -113,21 +113,6 @@ do spawn {
 }
 ~~~
 
-By default, the scheduler multiplexes tasks across the available cores, running
-in parallel. Thus, on a multicore machine, running the following code
-should interleave the output in vaguely random order.
-
-~~~
-# use std::io::print;
-# use std::task::spawn;
-
-for child_task_number in range(0, 20) {
-    do spawn {
-       print(fmt!("I am child number %d\n", child_task_number));
-    }
-}
-~~~
-
 ## Communication
 
 Now that we have spawned a new task, it would be nice if we could
index 896718be6c451b9cfa67248c1168bcee2809ab5b..12ccc55d4fae135020c85a0529f26f7046cefd54 100644 (file)
@@ -26,7 +26,7 @@ ifeq ($(CFG_LLVM_ROOT),)
 
 $$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS)
        @$$(call E, make: llvm)
-       $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1))
+       $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV)
        $$(Q)touch $$(LLVM_CONFIG_$(1))
 endif
 
index 3e7ad914daba19fab8c1c62a9c3e16a031a4af08..6ee5420664d8e1c819efa0bfe8a000519b6a6a0d 100644 (file)
@@ -26,7 +26,10 @@ endef
 $(foreach t,$(CFG_TARGET_TRIPLES),$(eval $(call DEF_OSTYPE_VAR,$(t))))
 $(foreach t,$(CFG_TARGET_TRIPLES),$(info cfg: os for $(t) is $(OSTYPE_$(t))))
 
-CFG_GCCISH_CFLAGS += -DUSE_UTF8
+# FIXME: no-omit-frame-pointer is just so that task_start_wrapper
+# has a frame pointer and the stack walker can understand it. Turning off
+# frame pointers everywhere is overkill
+CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer -DUSE_UTF8
 
 # On Darwin, we need to run dsymutil so the debugging information ends
 # up in the right place.  On other platforms, it automatically gets
@@ -150,6 +153,7 @@ CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-no-whole-archive
 CFG_DEF_SUFFIX_x86_64-unknown-linux-gnu := .linux.def
 CFG_INSTALL_NAME_x86_64-unknown-linux-gnu =
 CFG_LIBUV_LINK_FLAGS_x86_64-unknown-linux-gnu =
+CFG_LLVM_BUILD_ENV_x86_64-unknown-linux-gnu="CXXFLAGS=-fno-omit-frame-pointer"
 CFG_EXE_SUFFIX_x86_64-unknown-linux-gnu =
 CFG_WINDOWSY_x86_64-unknown-linux-gnu :=
 CFG_UNIXY_x86_64-unknown-linux-gnu := 1
@@ -175,6 +179,7 @@ CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-no-whole-archive
 CFG_DEF_SUFFIX_i686-unknown-linux-gnu := .linux.def
 CFG_INSTALL_NAME_i686-unknown-linux-gnu =
 CFG_LIBUV_LINK_FLAGS_i686-unknown-linux-gnu =
+CFG_LLVM_BUILD_ENV_i686-unknown-linux-gnu="CXXFLAGS=-fno-omit-frame-pointer"
 CFG_EXE_SUFFIX_i686-unknown-linux-gnu =
 CFG_WINDOWSY_i686-unknown-linux-gnu :=
 CFG_UNIXY_i686-unknown-linux-gnu := 1
index 823dfd94c1a65af4e11abfa2cd9c916290b31195..c260945cbc9b035bb11c4e76967c2c4097e2d1ad 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -41,6 +41,11 @@ ifneq ($(strip $(findstring snap,$(MAKECMDGOALS))),)
        SNAP_DEFINES=-DRUST_SNAPSHOT
 endif
 
+define DEF_LIBUV_ARCH_VAR
+  LIBUV_ARCH_$(1) = $$(subst i386,ia32,$$(subst x86_64,x64,$$(HOST_$(1))))
+endef
+$(foreach t,$(CFG_TARGET_TRIPLES),$(eval $(call DEF_LIBUV_ARCH_VAR,$(t))))
+
 define DEF_RUNTIME_TARGETS
 
 ######################################################################
@@ -163,49 +168,36 @@ LIBUV_DEPS := $$(wildcard \
               $$(S)src/libuv/*/*/*/*)
 endif
 
-LIBUV_GYP := $$(S)src/libuv/build/gyp
-LIBUV_MAKEFILE_$(1)_$(2) := $$(CFG_BUILD_DIR)rt/$(1)/stage$(2)/libuv/Makefile
-LIBUV_NO_LOAD = run-benchmarks.target.mk run-tests.target.mk \
-               uv_dtrace_header.target.mk uv_dtrace_provider.target.mk
-
-$$(LIBUV_MAKEFILE_$(1)_$(2)): $$(LIBUV_GYP)
-       (cd $(S)src/libuv/ && \
-        $$(CFG_PYTHON) ./gyp_uv -f make -Dtarget_arch=$$(HOST_$(1)) -D ninja \
-          -Goutput_dir=$$(@D) --generator-output $$(@D))
-
 # XXX: Shouldn't need platform-specific conditions here
 ifdef CFG_WINDOWSY_$(1)
 $$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
-       $$(Q)rm -f $$(S)src/libuv/libuv.a
-       $$(Q)$$(MAKE) -C $$(S)src/libuv -f Makefile.mingw \
-               CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
-               AR="$$(AR_$(1))" \
+       $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
+               builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
+               OS=mingw \
                V=$$(VERBOSE)
-       $$(Q)cp $$(S)src/libuv/libuv.a $$@
 else ifeq ($(OSTYPE_$(1)), linux-androideabi)
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
-       $$(Q)$$(MAKE) -C $$(@D) \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
+       $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
                CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
                LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
                CC="$$(CC_$(1))" \
                CXX="$$(CXX_$(1))" \
+               LINK="$$(CXX_$(1))" \
                AR="$$(AR_$(1))" \
-               host=android OS=linux \
-               builddir="." \
+               PLATFORM=android \
                BUILDTYPE=Release \
-               NO_LOAD="$$(LIBUV_NO_LOAD)" \
+               builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
+               host=android OS=linux \
                V=$$(VERBOSE)
 else
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
-       $$(Q)$$(MAKE) -C $$(@D) \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
+       $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
                CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
                LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
                CC="$$(CC_$(1))" \
                CXX="$$(CXX_$(1))" \
                AR="$$(AR_$(1))" \
-               builddir="." \
-               BUILDTYPE=Release \
-               NO_LOAD="$$(LIBUV_NO_LOAD)" \
+               builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
                V=$$(VERBOSE)
 endif
 
@@ -269,7 +261,3 @@ endef
 $(foreach stage,$(STAGES), \
        $(foreach target,$(CFG_TARGET_TRIPLES), \
         $(eval $(call DEF_RUNTIME_TARGETS,$(target),$(stage)))))
-
-$(LIBUV_GYP):
-       mkdir -p $(S)src/libuv/build
-       git clone https://git.chromium.org/external/gyp.git $(S)src/libuv/build/gyp
index 67b2a26c3af44c50113424eb778810b3c590664b..c6a4badaed07787d5a642f20c3ea6b2ff0911027 100644 (file)
@@ -869,7 +869,8 @@ $(foreach host,$(CFG_HOST_TRIPLES), \
  $(eval $(foreach target,$(CFG_TARGET_TRIPLES), \
    $(eval $(call DEF_CHECK_FAST_FOR_T_H,,$(target),$(host))))))
 
-check-fast: tidy check-fast-H-$(CFG_BUILD_TRIPLE)
+check-fast: tidy check-fast-H-$(CFG_BUILD_TRIPLE) check-stage2-std check-stage2-extra
+       $(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
 
 define DEF_CHECK_FAST_FOR_H
 
index 3ae3600cf88c6a41759e1571b25a625f2fd163f8..6a365ae05dd951b3c262d3d1e87516f27198d3da 100644 (file)
@@ -83,9 +83,6 @@ pub struct config {
     // Run tests using the JIT
     jit: bool,
 
-    // Run tests using the new runtime
-    newrt: bool,
-
     // Target system to be tested
     target: ~str,
 
index 8de79749b54f3f57053fd9db1c59709addeb7e14..be8f9655010bbfa8ccaca45ce7007b68f5fb311c 100644 (file)
@@ -71,7 +71,6 @@ pub fn parse_config(args: ~[~str]) -> config {
           optopt("", "ratchet-noise-percent",
                  "percent change in metrics to consider noise", "N"),
           optflag("", "jit", "run tests under the JIT"),
-          optflag("", "newrt", "run tests on the new runtime / scheduler"),
           optopt("", "target", "the target to build for", "TARGET"),
           optopt("", "adb-path", "path to the android debugger", "PATH"),
           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
@@ -135,7 +134,6 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
         runtool: getopts::opt_maybe_str(matches, "runtool"),
         rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
         jit: getopts::opt_present(matches, "jit"),
-        newrt: getopts::opt_present(matches, "newrt"),
         target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
         adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
         adb_test_dir:
@@ -169,7 +167,6 @@ pub fn log_config(config: &config) {
     logv(c, fmt!("runtool: %s", opt_str(&config.runtool)));
     logv(c, fmt!("rustcflags: %s", opt_str(&config.rustcflags)));
     logv(c, fmt!("jit: %b", config.jit));
-    logv(c, fmt!("newrt: %b", config.newrt));
     logv(c, fmt!("target: %s", config.target));
     logv(c, fmt!("adb_path: %s", config.adb_path));
     logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
index 74627829c60ff52b2f37c4e03d6a6582c654edf3..45e4f756d7a15752a7e3d3e7ed672ac2547c8296 100644 (file)
@@ -54,10 +54,10 @@ pub fn run(lib_path: &str,
         in_fd: None,
         out_fd: None,
         err_fd: None
-    }).unwrap();
+    });
 
     for input in input.iter() {
-        proc.input().write(input.as_bytes());
+        proc.input().write_str(*input);
     }
     let output = proc.finish_with_output();
 
index 16de4f8e82233dbdbd1b1c5c4c54d1981cfacc6e..ea94ce662ac1e726779d5ded99db5e2897e9b7cd 100644 (file)
 use util;
 use util::logv;
 
+use std::cell::Cell;
 use std::io;
 use std::os;
 use std::str;
+use std::task::{spawn_sched, SingleThreaded};
 use std::vec;
+use std::unstable::running_on_valgrind;
 
 use extra::test::MetricMap;
 
 pub fn run(config: config, testfile: ~str) {
-    let mut _mm = MetricMap::new();
-    run_metrics(config, testfile, &mut _mm);
+    let config = Cell::new(config);
+    let testfile = Cell::new(testfile);
+    // FIXME #6436: Creating another thread to run the test because this
+    // is going to call waitpid. The new scheduler has some strange
+    // interaction between the blocking tasks and 'friend' schedulers
+    // that destroys parallelism if we let normal schedulers block.
+    // It should be possible to remove this spawn once std::run is
+    // rewritten to be non-blocking.
+    //
+    // We do _not_ create another thread if we're running on V because
+    // it serializes all threads anyways.
+    if running_on_valgrind() {
+        let config = config.take();
+        let testfile = testfile.take();
+        let mut _mm = MetricMap::new();
+        run_metrics(config, testfile, &mut _mm);
+    } else {
+        do spawn_sched(SingleThreaded) {
+            let config = config.take();
+            let testfile = testfile.take();
+            let mut _mm = MetricMap::new();
+            run_metrics(config, testfile, &mut _mm);
+        }
+    }
 }
 
 pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
@@ -522,15 +547,13 @@ fn compile_test_(config: &config, props: &TestProps,
 fn exec_compiled_test(config: &config, props: &TestProps,
                       testfile: &Path) -> ProcRes {
 
-    // If testing the new runtime then set the RUST_NEWRT env var
     let env = props.exec_env.clone();
-    let env = if config.newrt { env + &[(~"RUST_NEWRT", ~"1")] } else { env };
 
     match config.target {
 
         ~"arm-linux-androideabi" => {
             if (config.adb_device_status) {
-                _arm_exec_compiled_test(config, props, testfile)
+                _arm_exec_compiled_test(config, props, testfile, env)
             } else {
                 _dummy_exec_compiled_test(config, props, testfile)
             }
@@ -756,7 +779,7 @@ fn fatal_ProcRes(err: ~str, ProcRes: &ProcRes) -> ! {
 }
 
 fn _arm_exec_compiled_test(config: &config, props: &TestProps,
-                      testfile: &Path) -> ProcRes {
+                      testfile: &Path, env: ~[(~str, ~str)]) -> ProcRes {
 
     let args = make_run_args(config, props, testfile);
     let cmdline = make_cmdline("", args.prog, args.args);
@@ -782,6 +805,9 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
 
     // run test via adb_run_wrapper
     runargs.push(~"shell");
+    for (key, val) in env.move_iter() {
+        runargs.push(fmt!("%s=%s", key, val));
+    }
     runargs.push(fmt!("%s/adb_run_wrapper.sh", config.adb_test_dir));
     runargs.push(fmt!("%s", config.adb_test_dir));
     runargs.push(fmt!("%s", prog_short));
index 4bb0c4040306b18a350a27108833bb5708d39184..92b85247e4891a670dae04ef92f9497bdc757d53 100644 (file)
@@ -5,6 +5,7 @@
 ;; Url: https://github.com/mozilla/rust
 
 (eval-when-compile (require 'cl))
+(eval-when-compile (require 'misc))
 
 ;; Syntax definitions and helpers
 (defvar rust-mode-syntax-table
 
     table))
 
-(defcustom rust-indent-offset default-tab-width
-  "*Indent Rust code by this number of spaces.
-
-The initializer is `DEFAULT-TAB-WIDTH'.")
+(defcustom rust-indent-offset 4
+  "*Indent Rust code by this number of spaces.")
 
 (defun rust-paren-level () (nth 0 (syntax-ppss)))
 (defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss)))
@@ -59,19 +58,39 @@ The initializer is `DEFAULT-TAB-WIDTH'.")
               ;; A closing brace is 1 level unindended
               ((looking-at "}") (* rust-indent-offset (- level 1)))
 
+              ; Doc comments in /** style with leading * indent to line up the *s
+              ((and (nth 4 (syntax-ppss)) (looking-at "*"))
+               (+ 1 (* rust-indent-offset level)))
+
               ;; If we're in any other token-tree / sexp, then:
               ;;  - [ or ( means line up with the opening token
-              ;;  - { means indent to either nesting-level * tab width,
+              ;;  - { means indent to either nesting-level * rust-indent-offset,
               ;;    or one further indent from that if either current line
               ;;    begins with 'else', or previous line didn't end in
-              ;;    semi, comma or brace, and wasn't an attribute. PHEW.
+              ;;    semi, comma or brace (other than whitespace and line
+              ;;    comments) , and wasn't an attribute.  But if we have 
+              ;;    something after the open brace and ending with a comma,
+              ;;    treat it as fields and align them.  PHEW.
               ((> level 0)
                (let ((pt (point)))
                  (rust-rewind-irrelevant)
                  (backward-up-list)
-                 (if (looking-at "[[(]")
-                     (+ 1 (current-column))
+                 (cond 
+                  ((and
+                      (looking-at "[[(]")
+                      ; We don't want to indent out to the open bracket if the
+                      ; open bracket ends the line
+                      (save-excursion 
+                        (forward-char)
+                        (not (looking-at "[[:space:]]*\\(?://.*\\)?$"))))
+                   (+ 1 (current-column)))
+                  ;; Check for fields on the same line as the open curly brace:
+                  ((looking-at "{[[:blank:]]*[^}\n]*,[[:space:]]*$")
                    (progn
+                    (forward-char)
+                    (forward-to-word 1)
+                    (current-column)))
+                  (t (progn
                      (goto-char pt)
                      (back-to-indentation)
                      (if (looking-at "\\<else\\>")
@@ -81,12 +100,12 @@ The initializer is `DEFAULT-TAB-WIDTH'.")
                          (beginning-of-line)
                          (rust-rewind-irrelevant)
                          (end-of-line)
-                         (if (looking-back "[{};,]")
+                         (if (looking-back "[,;{}(][[:space:]]*\\(?://.*\\)?")
                              (* rust-indent-offset level)
                            (back-to-indentation)
                            (if (looking-at "#")
                                (* rust-indent-offset level)
-                             (* rust-indent-offset (+ 1 level))))))))))
+                             (* rust-indent-offset (+ 1 level)))))))))))
 
               ;; Otherwise we're in a column-zero definition
               (t 0))))))
index 260b23cb70be4c01dee0e6e233309cb56642f3b6..b5e52939635977bede356378a109b735a6208807 100644 (file)
@@ -33,7 +33,7 @@ syn match     rustIdentifier  contains=rustIdentifierPrime "\%([^[:cntrl:][:spac
 syn match     rustFuncName    "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
 
 " reserved
-syn keyword   rustKeyword     be
+syn keyword   rustKeyword     be yield typeof
 
 syn keyword   rustType        int uint float char bool u8 u16 u32 u64 f32
 syn keyword   rustType        f64 i8 i16 i32 i64 str Self
index 8e641073637853e103c1c08e29f0fa465a21cf04..fa8b50fbf672994c71b15571264efe104597557d 100644 (file)
@@ -594,7 +594,7 @@ fn eq(&self, other: &DList<A>) -> bool {
     }
 
     fn ne(&self, other: &DList<A>) -> bool {
-        self.len() != other.len() &&
+        self.len() != other.len() ||
             iterator::order::ne(self.iter(), other.iter())
     }
 }
@@ -978,6 +978,10 @@ fn test_eq() {
         assert!(n != m);
         m.push_back(1);
         assert_eq!(&n, &m);
+
+        let n = list_from([2,3,4]);
+        let m = list_from([1,2,3]);
+        assert!(n != m);
     }
 
     #[test]
index ccade8f19bebc456104c316f15726333364555ac..73f6d2e1bda8be85e217c8082f1bdbad9c64c2b5 100644 (file)
@@ -203,7 +203,7 @@ fn usage(binary: &str, helpstr: &str) -> ! {
 have a substring match, only those tests are run.
 
 By default, all tests are run in parallel. This can be altered with the
-RUST_THREADS environment variable when running tests (set it to 1).
+RUST_TEST_TASKS environment variable when running tests (set it to 1).
 
 Test Attributes:
 
@@ -740,9 +740,20 @@ fn run_tests(opts: &TestOpts,
 
 fn get_concurrency() -> uint {
     use std::rt;
-    let threads = rt::util::default_sched_threads();
-    if threads == 1 { 1 }
-    else { threads * SCHED_OVERCOMMIT }
+    match os::getenv("RUST_TEST_TASKS") {
+        Some(s) => {
+            let opt_n: Option<uint> = FromStr::from_str(s);
+            match opt_n {
+                Some(n) if n > 0 => n,
+                _ => fail!("RUST_TEST_TASKS is `%s`, should be a positive integer.", s)
+            }
+        }
+        None => {
+            let threads = rt::util::default_sched_threads();
+            if threads == 1 { 1 }
+            else { threads * SCHED_OVERCOMMIT }
+        }
+    }
 }
 
 pub fn filter_tests(
index 2989f1047298ccace23c91427c3adab797062ffb..c5be424e2846cfe9419e8b8b012beecce2594d5a 100644 (file)
@@ -2585,11 +2585,13 @@ pub fn resolve_glob_import(@mut self,
                 debug!("(resolving glob import) ... for value target");
                 dest_import_resolution.value_target =
                     Some(Target(containing_module, name_bindings));
+                dest_import_resolution.value_id = id;
             }
             if name_bindings.defined_in_public_namespace(TypeNS) {
                 debug!("(resolving glob import) ... for type target");
                 dest_import_resolution.type_target =
                     Some(Target(containing_module, name_bindings));
+                dest_import_resolution.type_id = id;
             }
         };
 
index 1fc682912b35f38af8c22ec3bf9d056d6f6e9168..1dc30d2221da897d53b4afb9882eba90515c12a1 100644 (file)
@@ -87,6 +87,7 @@
 use syntax::print::pprust::stmt_to_str;
 use syntax::{ast, ast_util, codemap, ast_map};
 use syntax::abi::{X86, X86_64, Arm, Mips};
+use syntax::visit::Visitor;
 
 pub use middle::trans::context::task_llcx;
 
@@ -2162,6 +2163,14 @@ pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
     }
 }
 
+pub struct TransItemVisitor;
+
+impl Visitor<@mut CrateContext> for TransItemVisitor {
+    fn visit_item(&mut self, i: @ast::item, ccx: @mut CrateContext) {
+        trans_item(ccx, i);
+    }
+}
+
 pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
     let _icx = push_ctxt("trans_item");
     let path = match ccx.tcx.items.get_copy(&item.id) {
@@ -2193,15 +2202,10 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
                      item.id,
                      item.attrs);
         } else {
-            for stmt in body.stmts.iter() {
-                match stmt.node {
-                  ast::stmt_decl(@codemap::spanned { node: ast::decl_item(i),
-                                                 _ }, _) => {
-                    trans_item(ccx, i);
-                  }
-                  _ => ()
-                }
-            }
+            // Be sure to travel more than just one layer deep to catch nested
+            // items in blocks and such.
+            let mut v = TransItemVisitor;
+            v.visit_block(body, ccx);
         }
       }
       ast::item_impl(ref generics, _, _, ref ms) => {
@@ -2366,20 +2370,12 @@ fn create_entry_fn(ccx: @mut CrateContext,
                                &ccx.int_type);
 
         // FIXME #4404 android JNI hacks
-        let llfn = if *ccx.sess.building_library {
-            decl_cdecl_fn(ccx.llmod, "amain", llfty)
+        let main_name = if *ccx.sess.building_library {
+            "amain"
         } else {
-            let main_name = match ccx.sess.targ_cfg.os {
-                session::os_win32 => {
-                    match ccx.sess.targ_cfg.arch {
-                        X86 => ~"WinMain@16",
-                        _ => ~"WinMain",
-                    }
-                },
-                _ => ~"main",
-            };
-            decl_cdecl_fn(ccx.llmod, main_name, llfty)
+            "main"
         };
+        let llfn = decl_cdecl_fn(ccx.llmod, main_name, llfty);
         let llbb = do "top".with_c_str |buf| {
             unsafe {
                 llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
index 717dfbb67845396e7561dea48bd44fa6b07125b9..fb4dd8a74fb61cd9e89a158f8b89e450beefbae6 100644 (file)
@@ -37,6 +37,7 @@
 use syntax::ast_map::{path, path_mod, path_name};
 use syntax::ast_util;
 use syntax::{ast, ast_map};
+use syntax::visit;
 
 /**
 The main "translation" pass for methods.  Generates code
@@ -56,7 +57,15 @@ pub fn trans_impl(ccx: @mut CrateContext,
     debug!("trans_impl(path=%s, name=%s, id=%?)",
            path.repr(tcx), name.repr(tcx), id);
 
-    if !generics.ty_params.is_empty() { return; }
+    // Both here and below with generic methods, be sure to recurse and look for
+    // items that we need to translate.
+    if !generics.ty_params.is_empty() {
+        let mut v = TransItemVisitor;
+        for method in methods.iter() {
+            visit::walk_method_helper(&mut v, *method, ccx);
+        }
+        return;
+    }
     let sub_path = vec::append_one(path, path_name(name));
     for method in methods.iter() {
         if method.generics.ty_params.len() == 0u {
@@ -69,6 +78,9 @@ pub fn trans_impl(ccx: @mut CrateContext,
                          *method,
                          None,
                          llfn);
+        } else {
+            let mut v = TransItemVisitor;
+            visit::walk_method_helper(&mut v, *method, ccx);
         }
     }
 }
index c67035021a3aab9f282abac4491cfefbd450a661..bf65986b5ba9bd60ba4f9a3f0b60edd0bd8bd77f 100644 (file)
@@ -149,7 +149,7 @@ fn store_type_uses(cx: Context, fn_id: def_id) -> @~[type_uses] {
                     "visit_tydesc"  | "forget" | "frame_address" |
                     "morestack_addr" => 0,
 
-                    "offset" | "offset_inbounds" |
+                    "offset" |
                     "memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
                     "memset32" | "memset64" => use_repr,
 
index 6f90953cd413ab2c3274cc257759178e48e32cec..a3673928df768c6e9f108100a9d609cfa537c3e7 100644 (file)
@@ -4572,7 +4572,7 @@ pub fn visitor_object_ty(tcx: ctxt,
                  trait_ref.def_id,
                  trait_ref.substs.clone(),
                  RegionTraitStore(region),
-                 ast::m_imm,
+                 ast::m_mutbl,
                  EmptyBuiltinBounds())))
 }
 
index 17b4716ad508e8927ab4c5953c0171dfa5db8a57..6ebcf4facc180e43413c5644f7cfcc606c767e7d 100644 (file)
@@ -517,6 +517,9 @@ fn check_path_args(tcx: ty::ctxt,
           }
         }
       }
+      ast::ty_typeof(_e) => {
+          tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
+      }
       ast::ty_infer => {
         // ty_infer should only appear as the type of arguments or return
         // values in a fn_expr, or as the type of local variables.  Both of
index 706d6871f8639c69d54ec9309aab268fd4c17344..0b27a581a2aa4bc6cb4fc5bf041c147574b99964 100644 (file)
@@ -3663,20 +3663,6 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
                    mutbl: ast::m_imm
                }))
             }
-            "offset_inbounds" => {
-              (1,
-               ~[
-                  ty::mk_ptr(tcx, ty::mt {
-                      ty: param(ccx, 0),
-                      mutbl: ast::m_imm
-                  }),
-                  ty::mk_int()
-               ],
-               ty::mk_ptr(tcx, ty::mt {
-                   ty: param(ccx, 0),
-                   mutbl: ast::m_imm
-               }))
-            }
             "memcpy32" => {
               (1,
                ~[
index 635d02196fe47fdbec14beed9bdad5a7ee624402..c13e85ea71659724ac3b46102a5b905125f458a2 100644 (file)
@@ -104,14 +104,14 @@ fn pandoc_writer(
     ];
 
     do generic_writer |markdown| {
+        use std::io::WriterUtil;
+
         debug!("pandoc cmd: %s", pandoc_cmd);
         debug!("pandoc args: %s", pandoc_args.connect(" "));
 
-        let proc = run::Process::new(pandoc_cmd, pandoc_args,
-                                     run::ProcessOptions::new());
-        let mut proc = proc.unwrap();
+        let mut proc = run::Process::new(pandoc_cmd, pandoc_args, run::ProcessOptions::new());
 
-        proc.input().write(markdown.as_bytes());
+        proc.input().write_str(markdown);
         let output = proc.finish_with_output();
 
         debug!("pandoc result: %i", output.status);
index c67a81581393d977e5b5040fafbdc39237c89364..caa004a53b22879363807268745510a0926659bf 100644 (file)
@@ -89,7 +89,7 @@ pub fn git_clone_general(source: &str, target: &Path, v: &Version) -> bool {
 
 fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput {
     let mut prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
-                                ,..ProcessOptions::new()}).unwrap();
+                                ,..ProcessOptions::new()});
     prog.finish_with_output()
 }
 
index b0d996ea0afa81d126c6644c0c888b6bbd98a374..98999da41c81633bad276bce6142f104889d20fe 100644 (file)
@@ -112,14 +112,13 @@ fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path {
 
 fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) {
     let cwd = (*cwd).clone();
-    let prog = run::Process::new("git", args, run::ProcessOptions {
+    let mut prog = run::Process::new("git", args, run::ProcessOptions {
         env: env,
         dir: Some(&cwd),
         in_fd: None,
         out_fd: None,
         err_fd: None
     });
-    let mut prog = prog.unwrap();
     let rslt = prog.finish_with_output();
     if rslt.status != 0 {
         fail!("%s [git returned %?, output = %s, error = %s]", err_msg,
@@ -227,7 +226,7 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
         in_fd: None,
         out_fd: None,
         err_fd: None
-    }).unwrap();
+    });
     let output = prog.finish_with_output();
     debug!("Output from command %s with args %? was %s {%s}[%?]",
                     cmd, args, str::from_bytes(output.output),
@@ -1028,17 +1027,16 @@ fn test_extern_mod() {
                      test_sysroot().to_str(),
                      exec_file.to_str());
 
-    let prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
-                                                  ~"--sysroot", test_sysroot().to_str(),
-                                                  ~"-o", exec_file.to_str()],
-                                 run::ProcessOptions {
+    let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
+                                                      ~"--sysroot", test_sysroot().to_str(),
+                                               ~"-o", exec_file.to_str()],
+                                     run::ProcessOptions {
         env: env,
         dir: Some(&dir),
         in_fd: None,
         out_fd: None,
         err_fd: None
     });
-    let mut prog = prog.unwrap();
     let outp = prog.finish_with_output();
     if outp.status != 0 {
         fail!("output was %s, error was %s",
index df2fe70ff0e12a9d97abad9682debece3938edcb..70b04e37ee1ff3785de55096c1f9c56fb773073a 100644 (file)
@@ -179,7 +179,7 @@ fn to_c_str(&self) -> CString {
         do cs.with_mut_ref |buf| {
             for i in range(0, self.len()) {
                 unsafe {
-                    let p = buf.offset_inbounds(i as int);
+                    let p = buf.offset(i as int);
                     if *p == 0 {
                         match null_byte::cond.raise(self.to_owned()) {
                             Truncate => break,
@@ -222,7 +222,7 @@ fn next(&mut self) -> Option<libc::c_char> {
         if ch == 0 {
             None
         } else {
-            self.ptr = ptr::offset(self.ptr, 1);
+            self.ptr = unsafe { ptr::offset(self.ptr, 1) };
             Some(ch)
         }
     }
index e3f88033bd06bc74296c46e91e9d7b9d97a571ee..25b94e1e45dcd902350aaf004099c63337bd1477 100644 (file)
@@ -619,7 +619,7 @@ pub trait ReaderUtil {
 
 impl<T:Reader> ReaderUtil for T {
 
-    fn read_bytes(&self,len: uint) -> ~[u8] {
+    fn read_bytes(&self, len: uint) -> ~[u8] {
         let mut bytes = vec::with_capacity(len);
         unsafe { vec::raw::set_len(&mut bytes, len); }
 
diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs
deleted file mode 100644 (file)
index ce528bc..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2012-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.
-
-/*! Times trait
-
-~~~ {.rust}
-use iter::Times;
-let ten = 10 as uint;
-let mut accum = 0;
-do ten.times { accum += 1; }
-~~~
-
-*/
-
-#[allow(missing_doc)]
-pub trait Times {
-    fn times(&self, it: &fn());
-}
-
index 5d6610e6b55a315c68c955259abf503398ba697f..88e7dd692fec850419d90e5a512a31d02d66c49a 100644 (file)
 
 */
 
+use cast;
+use libc;
 use prelude::*;
-
-use task::local_data_priv::*;
-
-#[cfg(test)] use task;
+use rt::task::{Task, LocalStorage};
+use util;
 
 /**
  * Indexes a task-local data slot. This pointer is used for comparison to
 
 pub enum KeyValue<T> { Key }
 
-/**
- * Remove a task-local data value from the table, returning the
- * reference that was originally created to insert it.
- */
-pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
-    unsafe { local_pop(Handle::new(), key) }
-}
-
-/**
- * Retrieve a task-local data value. It will also be kept alive in the
- * table until explicitly removed.
- */
-pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
-    unsafe { local_get(Handle::new(), key, f) }
-}
+trait LocalData {}
+impl<T: 'static> LocalData for T {}
 
-/**
- * Retrieve a mutable borrowed pointer to a task-local data value.
- */
-pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
-    unsafe { local_get_mut(Handle::new(), key, f) }
+// The task-local-map stores all TLS information for the currently running task.
+// It is stored as an owned pointer into the runtime, and it's only allocated
+// when TLS is used for the first time. This map must be very carefully
+// constructed because it has many mutable loans unsoundly handed out on it to
+// the various invocations of TLS requests.
+//
+// One of the most important operations is loaning a value via `get` to a
+// caller. In doing so, the slot that the TLS entry is occupying cannot be
+// invalidated because upon returning it's loan state must be updated. Currently
+// the TLS map is a vector, but this is possibly dangerous because the vector
+// can be reallocated/moved when new values are pushed onto it.
+//
+// This problem currently isn't solved in a very elegant way. Inside the `get`
+// function, it internally "invalidates" all references after the loan is
+// finished and looks up into the vector again. In theory this will prevent
+// pointers from being moved under our feet so long as LLVM doesn't go too crazy
+// with the optimizations.
+//
+// n.b. If TLS is used heavily in future, this could be made more efficient with
+//      a proper map.
+#[doc(hidden)]
+pub type Map = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
+type TLSValue = ~LocalData;
+
+// Gets the map from the runtime. Lazily initialises if not done so already.
+unsafe fn get_local_map() -> &mut Map {
+    use rt::local::Local;
+
+    let task: *mut Task = Local::unsafe_borrow();
+    match &mut (*task).storage {
+        // If the at_exit function is already set, then we just need to take
+        // a loan out on the TLS map stored inside
+        &LocalStorage(Some(ref mut map_ptr)) => {
+            return map_ptr;
+        }
+        // If this is the first time we've accessed TLS, perform similar
+        // actions to the oldsched way of doing things.
+        &LocalStorage(ref mut slot) => {
+            *slot = Some(~[]);
+            match *slot {
+                Some(ref mut map_ptr) => { return map_ptr }
+                None => abort()
+            }
+        }
+    }
 }
 
-/**
- * Store a value in task-local data. If this key already has a value,
- * that value is overwritten (and its destructor is run).
- */
-pub fn set<T: 'static>(key: Key<T>, data: T) {
-    unsafe { local_set(Handle::new(), key, data) }
+#[deriving(Eq)]
+enum LoanState {
+    NoLoan, ImmLoan, MutLoan
 }
 
-/**
- * Modify a task-local data value. If the function returns 'None', the
- * data is removed (and its reference dropped).
- */
-pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
-    unsafe {
-        match f(pop(::cast::unsafe_copy(&key))) {
-            Some(next) => { set(key, next); }
-            None => {}
+impl LoanState {
+    fn describe(&self) -> &'static str {
+        match *self {
+            NoLoan => "no loan",
+            ImmLoan => "immutable",
+            MutLoan => "mutable"
         }
     }
 }
 
-#[test]
-fn test_tls_multitask() {
-    static my_key: Key<@~str> = &Key;
-    set(my_key, @~"parent data");
-    do task::spawn {
-        // TLS shouldn't carry over.
-        assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
-        set(my_key, @~"child data");
-        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
-                ~"child data");
-        // should be cleaned up for us
+fn key_to_key_value<T: 'static>(key: Key<T>) -> *libc::c_void {
+    unsafe { cast::transmute(key) }
+}
+
+/// Removes a task-local value from task-local storage. This will return
+/// Some(value) if the key was present in TLS, otherwise it will return None.
+///
+/// A runtime assertion will be triggered it removal of TLS value is attempted
+/// while the value is still loaned out via `get` or `get_mut`.
+pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
+    let map = unsafe { get_local_map() };
+    let key_value = key_to_key_value(key);
+
+    for entry in map.mut_iter() {
+        match *entry {
+            Some((k, _, loan)) if k == key_value => {
+                if loan != NoLoan {
+                    fail!("TLS value cannot be removed because it is currently \
+                          borrowed as %s", loan.describe());
+                }
+                // Move the data out of the `entry` slot via util::replace.
+                // This is guaranteed to succeed because we already matched
+                // on `Some` above.
+                let data = match util::replace(entry, None) {
+                    Some((_, data, _)) => data,
+                    None => abort()
+                };
+
+                // Move `data` into transmute to get out the memory that it
+                // owns, we must free it manually later.
+                let (_vtable, box): (uint, ~~T) = unsafe {
+                    cast::transmute(data)
+                };
+
+                // Now that we own `box`, we can just move out of it as we would
+                // with any other data.
+                return Some(**box);
+            }
+            _ => {}
+        }
     }
-    // Must work multiple times
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+    return None;
 }
 
-#[test]
-fn test_tls_overwrite() {
-    static my_key: Key<@~str> = &Key;
-    set(my_key, @~"first data");
-    set(my_key, @~"next data"); // Shouldn't leak.
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+/// Retrieves a value from TLS. The closure provided is yielded `Some` of a
+/// reference to the value located in TLS if one exists, or `None` if the key
+/// provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via the `get_mut` method provided.
+pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
+    get_with(key, ImmLoan, f)
 }
 
-#[test]
-fn test_tls_pop() {
-    static my_key: Key<@~str> = &Key;
-    set(my_key, @~"weasel");
-    assert!(*(pop(my_key).unwrap()) == ~"weasel");
-    // Pop must remove the data from the map.
-    assert!(pop(my_key).is_none());
+/// Retrieves a mutable value from TLS. The closure provided is yielded `Some`
+/// of a reference to the mutable value located in TLS if one exists, or `None`
+/// if the key provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via this or the `get` methods. This is similar to how it's a runtime
+/// error to take two mutable loans on an `@mut` box.
+pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
+    do get_with(key, MutLoan) |x| {
+        match x {
+            None => f(None),
+            // We're violating a lot of compiler guarantees with this
+            // invocation of `transmute_mut`, but we're doing runtime checks to
+            // ensure that it's always valid (only one at a time).
+            //
+            // there is no need to be upset!
+            Some(x) => { f(Some(unsafe { cast::transmute_mut(x) })) }
+        }
+    }
 }
 
-#[test]
-fn test_tls_modify() {
-    static my_key: Key<@~str> = &Key;
-    modify(my_key, |data| {
-        match data {
-            Some(@ref val) => fail!("unwelcome value: %s", *val),
-            None           => Some(@~"first data")
+fn get_with<T: 'static, U>(key: Key<T>,
+                           state: LoanState,
+                           f: &fn(Option<&T>) -> U) -> U {
+    // This function must be extremely careful. Because TLS can store owned
+    // values, and we must have some form of `get` function other than `pop`,
+    // this function has to give a `&` reference back to the caller.
+    //
+    // One option is to return the reference, but this cannot be sound because
+    // the actual lifetime of the object is not known. The slot in TLS could not
+    // be modified until the object goes out of scope, but the TLS code cannot
+    // know when this happens.
+    //
+    // For this reason, the reference is yielded to a specified closure. This
+    // way the TLS code knows exactly what the lifetime of the yielded pointer
+    // is, allowing callers to acquire references to owned data. This is also
+    // sound so long as measures are taken to ensure that while a TLS slot is
+    // loaned out to a caller, it's not modified recursively.
+    let map = unsafe { get_local_map() };
+    let key_value = key_to_key_value(key);
+
+    let pos = map.iter().position(|entry| {
+        match *entry {
+            Some((k, _, _)) if k == key_value => true, _ => false
         }
     });
-    modify(my_key, |data| {
-        match data {
-            Some(@~"first data") => Some(@~"next data"),
-            Some(@ref val)       => fail!("wrong value: %s", *val),
-            None                 => fail!("missing value")
+    match pos {
+        None => { return f(None); }
+        Some(i) => {
+            let ret;
+            let mut return_loan = false;
+            match map[i] {
+                Some((_, ref data, ref mut loan)) => {
+                    match (state, *loan) {
+                        (_, NoLoan) => {
+                            *loan = state;
+                            return_loan = true;
+                        }
+                        (ImmLoan, ImmLoan) => {}
+                        (want, cur) => {
+                            fail!("TLS slot cannot be borrowed as %s because \
+                                   it is already borrowed as %s",
+                                  want.describe(), cur.describe());
+                        }
+                    }
+                    // data was created with `~~T as ~LocalData`, so we extract
+                    // pointer part of the trait, (as ~~T), and then use
+                    // compiler coercions to achieve a '&' pointer.
+                    unsafe {
+                        match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data){
+                            (_vtable, ref box) => {
+                                let value: &T = **box;
+                                ret = f(Some(value));
+                            }
+                        }
+                    }
+                }
+                _ => abort()
+            }
+
+            // n.b. 'data' and 'loans' are both invalid pointers at the point
+            // 'f' returned because `f` could have appended more TLS items which
+            // in turn relocated the vector. Hence we do another lookup here to
+            // fixup the loans.
+            if return_loan {
+                match map[i] {
+                    Some((_, _, ref mut loan)) => { *loan = NoLoan; }
+                    None => abort()
+                }
+            }
+            return ret;
         }
-    });
-    assert!(*(pop(my_key).unwrap()) == ~"next data");
+    }
 }
 
-#[test]
-fn test_tls_crust_automorestack_memorial_bug() {
-    // This might result in a stack-canary clobber if the runtime fails to
-    // set sp_limit to 0 when calling the cleanup extern - it might
-    // automatically jump over to the rust stack, which causes next_c_sp
-    // to get recorded as something within a rust stack segment. Then a
-    // subsequent upcall (esp. for logging, think vsnprintf) would run on
-    // a stack smaller than 1 MB.
-    static my_key: Key<@~str> = &Key;
-    do task::spawn {
-        set(my_key, @~"hax");
-    }
+fn abort() -> ! {
+    #[fixed_stack_segment]; #[inline(never)];
+    unsafe { libc::abort() }
 }
 
-#[test]
-fn test_tls_multiple_types() {
-    static str_key: Key<@~str> = &Key;
-    static box_key: Key<@@()> = &Key;
-    static int_key: Key<@int> = &Key;
-    do task::spawn {
-        set(str_key, @~"string data");
-        set(box_key, @@());
-        set(int_key, @42);
+/// Inserts a value into task local storage. If the key is already present in
+/// TLS, then the previous value is removed and replaced with the provided data.
+///
+/// It is considered a runtime error to attempt to set a key which is currently
+/// on loan via the `get` or `get_mut` methods.
+pub fn set<T: 'static>(key: Key<T>, data: T) {
+    let map = unsafe { get_local_map() };
+    let keyval = key_to_key_value(key);
+
+    // When the task-local map is destroyed, all the data needs to be cleaned
+    // up. For this reason we can't do some clever tricks to store '~T' as a
+    // '*c_void' or something like that. To solve the problem, we cast
+    // everything to a trait (LocalData) which is then stored inside the map.
+    // Upon destruction of the map, all the objects will be destroyed and the
+    // traits have enough information about them to destroy themselves.
+    //
+    // FIXME(#7673): This should be "~data as ~LocalData" (only one sigil)
+    let data = ~~data as ~LocalData:;
+
+    fn insertion_position(map: &mut Map,
+                          key: *libc::c_void) -> Option<uint> {
+        // First see if the map contains this key already
+        let curspot = map.iter().position(|entry| {
+            match *entry {
+                Some((ekey, _, loan)) if key == ekey => {
+                    if loan != NoLoan {
+                        fail!("TLS value cannot be overwritten because it is
+                               already borrowed as %s", loan.describe())
+                    }
+                    true
+                }
+                _ => false,
+            }
+        });
+        // If it doesn't contain the key, just find a slot that's None
+        match curspot {
+            Some(i) => Some(i),
+            None => map.iter().position(|entry| entry.is_none())
+        }
+    }
+
+    // The type of the local data map must ascribe to Send, so we do the
+    // transmute here to add the Send bound back on. This doesn't actually
+    // matter because TLS will always own the data (until its moved out) and
+    // we're not actually sending it to other schedulers or anything.
+    let data: ~LocalData = unsafe { cast::transmute(data) };
+    match insertion_position(map, keyval) {
+        Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
+        None => { map.push(Some((keyval, data, NoLoan))); }
     }
 }
 
-#[test]
-fn test_tls_overwrite_multiple_types() {
-    static str_key: Key<@~str> = &Key;
-    static box_key: Key<@@()> = &Key;
-    static int_key: Key<@int> = &Key;
-    do task::spawn {
-        set(str_key, @~"string data");
-        set(int_key, @42);
-        // This could cause a segfault if overwriting-destruction is done
-        // with the crazy polymorphic transmute rather than the provided
-        // finaliser.
-        set(int_key, @31337);
+/// Modifies a task-local value by temporarily removing it from task-local
+/// storage and then re-inserting if `Some` is returned from the closure.
+///
+/// This function will have the same runtime errors as generated from `pop` and
+/// `set` (the key must not currently be on loan
+pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
+    match f(pop(key)) {
+        Some(next) => { set(key, next); }
+        None => {}
     }
 }
 
-#[test]
-#[should_fail]
-fn test_tls_cleanup_on_failure() {
-    static str_key: Key<@~str> = &Key;
-    static box_key: Key<@@()> = &Key;
-    static int_key: Key<@int> = &Key;
-    set(str_key, @~"parent data");
-    set(box_key, @@());
-    do task::spawn {
-        // spawn_linked
-        set(str_key, @~"string data");
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+    use super::*;
+    use task;
+
+    #[test]
+    fn test_tls_multitask() {
+        static my_key: Key<@~str> = &Key;
+        set(my_key, @~"parent data");
+        do task::spawn {
+            // TLS shouldn't carry over.
+            assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
+            set(my_key, @~"child data");
+            assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
+                    ~"child data");
+            // should be cleaned up for us
+        }
+        // Must work multiple times
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+    }
+
+    #[test]
+    fn test_tls_overwrite() {
+        static my_key: Key<@~str> = &Key;
+        set(my_key, @~"first data");
+        set(my_key, @~"next data"); // Shouldn't leak.
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+    }
+
+    #[test]
+    fn test_tls_pop() {
+        static my_key: Key<@~str> = &Key;
+        set(my_key, @~"weasel");
+        assert!(*(pop(my_key).unwrap()) == ~"weasel");
+        // Pop must remove the data from the map.
+        assert!(pop(my_key).is_none());
+    }
+
+    #[test]
+    fn test_tls_modify() {
+        static my_key: Key<@~str> = &Key;
+        modify(my_key, |data| {
+            match data {
+                Some(@ref val) => fail!("unwelcome value: %s", *val),
+                None           => Some(@~"first data")
+            }
+        });
+        modify(my_key, |data| {
+            match data {
+                Some(@~"first data") => Some(@~"next data"),
+                Some(@ref val)       => fail!("wrong value: %s", *val),
+                None                 => fail!("missing value")
+            }
+        });
+        assert!(*(pop(my_key).unwrap()) == ~"next data");
+    }
+
+    #[test]
+    fn test_tls_crust_automorestack_memorial_bug() {
+        // This might result in a stack-canary clobber if the runtime fails to
+        // set sp_limit to 0 when calling the cleanup extern - it might
+        // automatically jump over to the rust stack, which causes next_c_sp
+        // to get recorded as something within a rust stack segment. Then a
+        // subsequent upcall (esp. for logging, think vsnprintf) would run on
+        // a stack smaller than 1 MB.
+        static my_key: Key<@~str> = &Key;
+        do task::spawn {
+            set(my_key, @~"hax");
+        }
+    }
+
+    #[test]
+    fn test_tls_multiple_types() {
+        static str_key: Key<@~str> = &Key;
+        static box_key: Key<@@()> = &Key;
+        static int_key: Key<@int> = &Key;
+        do task::spawn {
+            set(str_key, @~"string data");
+            set(box_key, @@());
+            set(int_key, @42);
+        }
+    }
+
+    #[test]
+    fn test_tls_overwrite_multiple_types() {
+        static str_key: Key<@~str> = &Key;
+        static box_key: Key<@@()> = &Key;
+        static int_key: Key<@int> = &Key;
+        do task::spawn {
+            set(str_key, @~"string data");
+            set(int_key, @42);
+            // This could cause a segfault if overwriting-destruction is done
+            // with the crazy polymorphic transmute rather than the provided
+            // finaliser.
+            set(int_key, @31337);
+        }
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_tls_cleanup_on_failure() {
+        static str_key: Key<@~str> = &Key;
+        static box_key: Key<@@()> = &Key;
+        static int_key: Key<@int> = &Key;
+        set(str_key, @~"parent data");
         set(box_key, @@());
-        set(int_key, @42);
+        do task::spawn {
+            // spawn_linked
+            set(str_key, @~"string data");
+            set(box_key, @@());
+            set(int_key, @42);
+            fail!();
+        }
+        // Not quite nondeterministic.
+        set(int_key, @31337);
         fail!();
     }
-    // Not quite nondeterministic.
-    set(int_key, @31337);
-    fail!();
-}
 
-#[test]
-fn test_static_pointer() {
-    static key: Key<@&'static int> = &Key;
-    static VALUE: int = 0;
-    let v: @&'static int = @&VALUE;
-    set(key, v);
-}
+    #[test]
+    fn test_static_pointer() {
+        static key: Key<@&'static int> = &Key;
+        static VALUE: int = 0;
+        let v: @&'static int = @&VALUE;
+        set(key, v);
+    }
 
-#[test]
-fn test_owned() {
-    static key: Key<~int> = &Key;
-    set(key, ~1);
+    #[test]
+    fn test_owned() {
+        static key: Key<~int> = &Key;
+        set(key, ~1);
 
-    do get(key) |v| {
         do get(key) |v| {
             do get(key) |v| {
+                do get(key) |v| {
+                    assert_eq!(**v.unwrap(), 1);
+                }
                 assert_eq!(**v.unwrap(), 1);
             }
             assert_eq!(**v.unwrap(), 1);
         }
-        assert_eq!(**v.unwrap(), 1);
-    }
-    set(key, ~2);
-    do get(key) |v| {
-        assert_eq!(**v.unwrap(), 2);
+        set(key, ~2);
+        do get(key) |v| {
+            assert_eq!(**v.unwrap(), 2);
+        }
     }
-}
 
-#[test]
-fn test_get_mut() {
-    static key: Key<int> = &Key;
-    set(key, 1);
+    #[test]
+    fn test_get_mut() {
+        static key: Key<int> = &Key;
+        set(key, 1);
 
-    do get_mut(key) |v| {
-        *v.unwrap() = 2;
-    }
+        do get_mut(key) |v| {
+            *v.unwrap() = 2;
+        }
 
-    do get(key) |v| {
-        assert_eq!(*v.unwrap(), 2);
+        do get(key) |v| {
+            assert_eq!(*v.unwrap(), 2);
+        }
     }
-}
 
-#[test]
-fn test_same_key_type() {
-    static key1: Key<int> = &Key;
-    static key2: Key<int> = &Key;
-    static key3: Key<int> = &Key;
-    static key4: Key<int> = &Key;
-    static key5: Key<int> = &Key;
-    set(key1, 1);
-    set(key2, 2);
-    set(key3, 3);
-    set(key4, 4);
-    set(key5, 5);
-
-    get(key1, |x| assert_eq!(*x.unwrap(), 1));
-    get(key2, |x| assert_eq!(*x.unwrap(), 2));
-    get(key3, |x| assert_eq!(*x.unwrap(), 3));
-    get(key4, |x| assert_eq!(*x.unwrap(), 4));
-    get(key5, |x| assert_eq!(*x.unwrap(), 5));
-}
+    #[test]
+    fn test_same_key_type() {
+        static key1: Key<int> = &Key;
+        static key2: Key<int> = &Key;
+        static key3: Key<int> = &Key;
+        static key4: Key<int> = &Key;
+        static key5: Key<int> = &Key;
+        set(key1, 1);
+        set(key2, 2);
+        set(key3, 3);
+        set(key4, 4);
+        set(key5, 5);
+
+        get(key1, |x| assert_eq!(*x.unwrap(), 1));
+        get(key2, |x| assert_eq!(*x.unwrap(), 2));
+        get(key3, |x| assert_eq!(*x.unwrap(), 3));
+        get(key4, |x| assert_eq!(*x.unwrap(), 4));
+        get(key5, |x| assert_eq!(*x.unwrap(), 5));
+    }
 
-#[test]
-#[should_fail]
-fn test_nested_get_set1() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get(key) |_| {
+    #[test]
+    #[should_fail]
+    fn test_nested_get_set1() {
+        static key: Key<int> = &Key;
         set(key, 4);
+        do get(key) |_| {
+            set(key, 4);
+        }
     }
-}
 
-#[test]
-#[should_fail]
-fn test_nested_get_mut2() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get(key) |_| {
-        get_mut(key, |_| {})
+    #[test]
+    #[should_fail]
+    fn test_nested_get_mut2() {
+        static key: Key<int> = &Key;
+        set(key, 4);
+        do get(key) |_| {
+            get_mut(key, |_| {})
+        }
     }
-}
 
-#[test]
-#[should_fail]
-fn test_nested_get_mut3() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get_mut(key) |_| {
-        get(key, |_| {})
+    #[test]
+    #[should_fail]
+    fn test_nested_get_mut3() {
+        static key: Key<int> = &Key;
+        set(key, 4);
+        do get_mut(key) |_| {
+            get(key, |_| {})
+        }
     }
-}
 
-#[test]
-#[should_fail]
-fn test_nested_get_mut4() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get_mut(key) |_| {
-        get_mut(key, |_| {})
+    #[test]
+    #[should_fail]
+    fn test_nested_get_mut4() {
+        static key: Key<int> = &Key;
+        set(key, 4);
+        do get_mut(key) |_| {
+            get_mut(key, |_| {})
+        }
     }
 }
index 215067ea729197c99e71c7e56609bc3a7304d277..a885a4f722789470cf9a6fe53e8c70b7f1a162ef 100644 (file)
@@ -41,16 +41,10 @@ pub fn console_off() {
 #[lang="log_type"]
 #[allow(missing_doc)]
 pub fn log_type<T>(_level: u32, object: &T) {
-    use io;
-    use repr;
-    use str;
-
-    let bytes = do io::with_bytes_writer |writer| {
-        repr::write_repr(writer, object);
-    };
+    use sys;
 
     // XXX: Bad allocation
-    let msg = str::from_bytes(bytes);
+    let msg = sys::log_str(object);
     newsched_log_str(msg);
 }
 
index 1c59eaf021969ea446b182f3723e5b8200409442..6757e3020daa83f36edce2dc990b36d7a6c40d15 100644 (file)
@@ -1142,6 +1142,10 @@ fn test_abs_sub() {
         assert_eq!(infinity.abs_sub(&1f32), infinity);
         assert_eq!(0f32.abs_sub(&neg_infinity), infinity);
         assert_eq!(0f32.abs_sub(&infinity), 0f32);
+    }
+
+    #[test] #[ignore(cfg(windows))] // FIXME #8663
+    fn test_abs_sub_nowin() {
         assert!(NaN.abs_sub(&-1f32).is_NaN());
         assert!(1f32.abs_sub(&NaN).is_NaN());
     }
@@ -1267,7 +1271,10 @@ fn test_frexp() {
 
         assert_eq!(0f32.frexp(), (0f32, 0));
         assert_eq!((-0f32).frexp(), (-0f32, 0));
+    }
 
+    #[test] #[ignore(cfg(windows))] // FIXME #8755
+    fn test_frexp_nowin() {
         let inf: f32 = Float::infinity();
         let neg_inf: f32 = Float::neg_infinity();
         let nan: f32 = Float::NaN();
index 8f5d6473aea2f4f3763de9c6f0790e9ed1ffb9fb..59389c285570b950d87b0c809e557027f947da51 100644 (file)
@@ -1192,6 +1192,10 @@ fn test_abs_sub() {
         assert_eq!(infinity.abs_sub(&1f64), infinity);
         assert_eq!(0f64.abs_sub(&neg_infinity), infinity);
         assert_eq!(0f64.abs_sub(&infinity), 0f64);
+    }
+
+    #[test] #[ignore(cfg(windows))] // FIXME #8663
+    fn test_abs_sub_nowin() {
         assert!(NaN.abs_sub(&-1f64).is_NaN());
         assert!(1f64.abs_sub(&NaN).is_NaN());
     }
@@ -1316,7 +1320,10 @@ fn test_frexp() {
 
         assert_eq!(0f64.frexp(), (0f64, 0));
         assert_eq!((-0f64).frexp(), (-0f64, 0));
+    }
 
+    #[test] #[ignore(cfg(windows))] // FIXME #8755
+    fn test_frexp_nowin() {
         let inf: f64 = Float::infinity();
         let neg_inf: f64 = Float::neg_infinity();
         let nan: f64 = Float::NaN();
index d019de2468bdfa568699d8c76a0d8412da0ebd37..909eac0cb69b1628b15e6fbcc936bffe0a653e75 100644 (file)
@@ -1163,6 +1163,10 @@ fn test_abs_sub() {
         assert_eq!(infinity.abs_sub(&1f), infinity);
         assert_eq!(0f.abs_sub(&neg_infinity), infinity);
         assert_eq!(0f.abs_sub(&infinity), 0f);
+    }
+
+    #[test] #[ignore(cfg(windows))] // FIXME #8663
+    fn test_abs_sub_nowin() {
         assert!(NaN.abs_sub(&-1f).is_NaN());
         assert!(1f.abs_sub(&NaN).is_NaN());
     }
@@ -1288,7 +1292,10 @@ fn test_frexp() {
 
         assert_eq!(0f.frexp(), (0f, 0));
         assert_eq!((-0f).frexp(), (-0f, 0));
+    }
 
+    #[test] #[ignore(cfg(windows))] // FIXME #8755
+    fn test_frexp_nowin() {
         let inf: float = Float::infinity();
         let neg_inf: float = Float::neg_infinity();
         let nan: float = Float::NaN();
index 80ab0caac670ccdc911cabd92b808d8ad6da32ad..3cb110d84643b11487ea30697be6e3f2f0aadf95 100644 (file)
@@ -80,6 +80,19 @@ pub trait Signed: Num
 
 pub trait Unsigned: Num {}
 
+/// Times trait
+///
+/// ~~~ {.rust}
+/// use num::Times;
+/// let ten = 10 as uint;
+/// let mut accum = 0;
+/// do ten.times { accum += 1; }
+/// ~~~
+///
+pub trait Times {
+    fn times(&self, it: &fn());
+}
+
 pub trait Integer: Num
                  + Orderable
                  + Div<Self,Self>
index 86bc98e53fcb6605cca989137c733653f47326df..e23bdc576d36f4ffa62afad7c7f8b93dd55c0995 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Operations and constants for `uint`
 
-use iter;
+use num;
 use sys;
 
 pub use self::generated::*;
@@ -70,7 +70,7 @@ pub fn div_round(x: uint, y: uint) -> uint {
 ///
 pub fn div_floor(x: uint, y: uint) -> uint { return x / y; }
 
-impl iter::Times for uint {
+impl num::Times for uint {
     #[inline]
     ///
     /// A convenience form for basic repetition. Given a uint `x`,
@@ -162,7 +162,7 @@ fn test_div() {
 
 #[test]
 pub fn test_times() {
-    use iter::Times;
+    use num::Times;
     let ten = 10 as uint;
     let mut accum = 0;
     do ten.times { accum += 1; }
index 7aae9425302255fdfaadac1a28a1612cdaf88096..07e0b0857a181984ac64220e41eaf2b411e5be91 100644 (file)
@@ -1418,12 +1418,12 @@ pub fn page_size() -> uint {
 pub fn page_size() -> uint {
     #[fixed_stack_segment]; #[inline(never)];
 
-  unsafe {
-    let mut info = libc::SYSTEM_INFO::new();
-    libc::GetSystemInfo(&mut info);
+    unsafe {
+        let mut info = libc::SYSTEM_INFO::new();
+        libc::GetSystemInfo(&mut info);
 
-    return info.dwPageSize as uint;
-  }
+        return info.dwPageSize as uint;
+    }
 }
 
 pub struct MemoryMap {
@@ -1458,7 +1458,6 @@ pub enum MapError {
     // Windows-specific errors
     ErrUnsupProt,
     ErrUnsupOffset,
-    ErrNeedRW,
     ErrAlreadyExists,
     ErrVirtualAlloc(uint),
     ErrCreateFileMappingW(uint),
@@ -1477,7 +1476,6 @@ fn to_str(&self) -> ~str {
             ErrUnknown(code) => fmt!("Unknown error=%?", code),
             ErrUnsupProt => ~"Protection mode unsupported",
             ErrUnsupOffset => ~"Offset in virtual memory mode is unsupported",
-            ErrNeedRW => ~"File mapping should be at least readable/writable",
             ErrAlreadyExists => ~"File mapping for specified file already exists",
             ErrVirtualAlloc(code) => fmt!("VirtualAlloc failure=%?", code),
             ErrCreateFileMappingW(code) => fmt!("CreateFileMappingW failure=%?", code),
@@ -1542,6 +1540,10 @@ pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError>
             })
         }
     }
+
+    pub fn granularity() -> uint {
+        page_size()
+    }
 }
 
 #[cfg(unix)]
@@ -1617,21 +1619,21 @@ pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError>
                 })
             }
         } else {
-            let dwDesiredAccess = match (readable, writable) {
-                (true, true) => libc::FILE_MAP_ALL_ACCESS,
-                (true, false) => libc::FILE_MAP_READ,
-                (false, true) => libc::FILE_MAP_WRITE,
-                _ => {
-                    return Err(ErrNeedRW);
-                }
+            let dwDesiredAccess = match (executable, readable, writable) {
+                (false, true, false) => libc::FILE_MAP_READ,
+                (false, true, true) => libc::FILE_MAP_WRITE,
+                (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
+                (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
+                _ => return Err(ErrUnsupProt) // Actually, because of the check above,
+                                              // we should never get here.
             };
             unsafe {
                 let hFile = libc::get_osfhandle(fd) as HANDLE;
                 let mapping = libc::CreateFileMappingW(hFile,
                                                        ptr::mut_null(),
                                                        flProtect,
-                                                       (len >> 32) as DWORD,
-                                                       (len & 0xffff_ffff) as DWORD,
+                                                       0,
+                                                       0,
                                                        ptr::null());
                 if mapping == ptr::mut_null() {
                     return Err(ErrCreateFileMappingW(errno()));
@@ -1641,7 +1643,7 @@ pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError>
                 }
                 let r = libc::MapViewOfFile(mapping,
                                             dwDesiredAccess,
-                                            (offset >> 32) as DWORD,
+                                            ((len as u64) >> 32) as DWORD,
                                             (offset & 0xffff_ffff) as DWORD,
                                             0);
                 match r as uint {
@@ -1655,6 +1657,19 @@ pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError>
             }
         }
     }
+
+    /// Granularity of MapAddr() and MapOffset() parameter values.
+    /// This may be greater than the value returned by page_size().
+    pub fn granularity() -> uint {
+        #[fixed_stack_segment]; #[inline(never)];
+
+        unsafe {
+            let mut info = libc::SYSTEM_INFO::new();
+            libc::GetSystemInfo(&mut info);
+
+            return info.dwAllocationGranularity as uint;
+        }
+    }
 }
 
 #[cfg(windows)]
@@ -1663,20 +1678,22 @@ fn drop(&self) {
         #[fixed_stack_segment]; #[inline(never)];
 
         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
+        use libc::consts::os::extra::FALSE;
 
         unsafe {
             match self.kind {
-                MapVirtual => match libc::VirtualFree(self.data as *mut c_void,
-                                                      self.len,
-                                                      libc::MEM_RELEASE) {
-                    0 => error!(fmt!("VirtualFree failed: %?", errno())),
-                    _ => ()
+                MapVirtual => {
+                    if libc::VirtualFree(self.data as *mut c_void,
+                                         self.len,
+                                         libc::MEM_RELEASE) == FALSE {
+                        error!(fmt!("VirtualFree failed: %?", errno()));
+                    }
                 },
                 MapFile(mapping) => {
-                    if libc::UnmapViewOfFile(self.data as LPCVOID) != 0 {
+                    if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
                         error!(fmt!("UnmapViewOfFile failed: %?", errno()));
                     }
-                    if libc::CloseHandle(mapping as HANDLE) != 0 {
+                    if libc::CloseHandle(mapping as HANDLE) == FALSE {
                         error!(fmt!("CloseHandle failed: %?", errno()));
                     }
                 }
@@ -2108,7 +2125,7 @@ fn lseek_(fd: c_int, size: uint) {
         }
 
         let path = tmpdir().push("mmap_file.tmp");
-        let size = page_size() * 2;
+        let size = MemoryMap::granularity() * 2;
         remove_file(&path);
 
         let fd = unsafe {
index bfe5b498f8f1327e2edbb455bbb9f2f852e9767a..24b3dc20260b1f96edf24eb135238bc0610e9d9b 100644 (file)
@@ -49,7 +49,7 @@
 pub use char::Char;
 pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
 pub use hash::Hash;
-pub use iter::Times;
+pub use num::Times;
 pub use iterator::{FromIterator, Extendable};
 pub use iterator::{Iterator, DoubleEndedIterator, RandomAccessIterator, ClonableIterator};
 pub use iterator::{OrdIterator, MutableDoubleEndedIterator};
index 860b1f4b7683b704151fc8bb95578ee13c70d374..02469527b7af66a741181950c9e85c7ab0ec4ec6 100644 (file)
 use unstable::intrinsics;
 use util::swap;
 
-#[cfg(not(test))] use ops::{Add,Sub};
-#[cfg(not(test))] use num::Int;
-
 #[cfg(not(test))] use cmp::{Eq, Ord};
 
-/// Calculate the offset from a pointer
+/// 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 fn offset<T>(ptr: *T, count: int) -> *T {
+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 fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
+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 fn offset<T>(ptr: *T, count: int) -> *T {
-    unsafe { intrinsics::offset(ptr, count) }
+pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
+    intrinsics::offset(ptr, count)
 }
 
-/// Calculate the offset from a mut pointer
+/// 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 fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
-    unsafe { intrinsics::offset(ptr as *T, count) as *mut T }
+pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
+    intrinsics::offset(ptr as *T, count) as *mut T
 }
 
 /// Return the offset of the first null pointer in `buf`.
@@ -293,8 +292,7 @@ pub trait RawPtr<T> {
     fn is_not_null(&self) -> bool;
     fn to_uint(&self) -> uint;
     unsafe fn to_option(&self) -> Option<&T>;
-    fn offset(&self, count: int) -> Self;
-    unsafe fn offset_inbounds(self, count: int) -> Self;
+    unsafe fn offset(self, count: int) -> Self;
 }
 
 /// Extension methods for immutable pointers
@@ -332,16 +330,10 @@ unsafe fn to_option(&self) -> Option<&T> {
         }
     }
 
-    /// Calculates the offset from a pointer.
-    #[inline]
-    fn offset(&self, count: int) -> *T { offset(*self, count) }
-
     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
     /// the object, or one-byte-past-the-end.
     #[inline]
-    unsafe fn offset_inbounds(self, count: int) -> *T {
-        intrinsics::offset_inbounds(self, count)
-    }
+    unsafe fn offset(self, count: int) -> *T { offset(self, count) }
 }
 
 /// Extension methods for mutable pointers
@@ -379,10 +371,6 @@ unsafe fn to_option(&self) -> Option<&T> {
         }
     }
 
-    /// Calculates the offset from a mutable pointer.
-    #[inline]
-    fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
-
     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
     /// the object, or one-byte-past-the-end. An arithmetic overflow is also
     /// undefined behaviour.
@@ -390,9 +378,7 @@ fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
     /// This method should be preferred over `offset` when the guarantee can be
     /// satisfied, to enable better optimization.
     #[inline]
-    unsafe fn offset_inbounds(self, count: int) -> *mut T {
-        intrinsics::offset_inbounds(self as *T, count) as *mut T
-    }
+    unsafe fn offset(self, count: int) -> *mut T { mut_offset(self, count) }
 }
 
 // Equality for pointers
@@ -513,46 +499,6 @@ fn gt(&self, other: &*mut T) -> bool {
     }
 }
 
-#[cfg(not(test))]
-impl<T, I: Int> Add<I, *T> for *T {
-    /// Add an integer value to a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
-    #[inline]
-    fn add(&self, rhs: &I) -> *T {
-        self.offset(rhs.to_int() as int)
-    }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *T> for *T {
-    /// Subtract an integer value from a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
-    #[inline]
-    fn sub(&self, rhs: &I) -> *T {
-        self.offset(-rhs.to_int() as int)
-    }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Add<I, *mut T> for *mut T {
-    /// Add an integer value to a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
-    #[inline]
-    fn add(&self, rhs: &I) -> *mut T {
-        self.offset(rhs.to_int() as int)
-    }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *mut T> for *mut T {
-    /// Subtract an integer value from a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
-    #[inline]
-    fn sub(&self, rhs: &I) -> *mut T {
-        self.offset(-rhs.to_int() as int)
-    }
-}
-
 #[cfg(test)]
 pub mod ptr_tests {
     use super::*;
@@ -635,7 +581,7 @@ fn test_is_null() {
         assert!(p.is_null());
         assert!(!p.is_not_null());
 
-        let q = offset(p, 1);
+        let q = unsafe { offset(p, 1) };
         assert!(!q.is_null());
         assert!(q.is_not_null());
 
@@ -643,7 +589,7 @@ fn test_is_null() {
         assert!(mp.is_null());
         assert!(!mp.is_not_null());
 
-        let mq = mp.offset(1);
+        let mq = unsafe { mp.offset(1) };
         assert!(!mq.is_null());
         assert!(mq.is_not_null());
     }
@@ -672,20 +618,20 @@ fn test_ptr_addition() {
         unsafe {
             let xs = ~[5, ..16];
             let mut ptr = to_ptr(xs);
-            let end = ptr + 16;
+            let end = ptr.offset(16);
 
             while ptr < end {
                 assert_eq!(*ptr, 5);
-                ptr = ptr + 1u;
+                ptr = ptr.offset(1);
             }
 
             let mut xs_mut = xs.clone();
             let mut m_ptr = to_mut_ptr(xs_mut);
-            let m_end = m_ptr + 16i16;
+            let m_end = m_ptr.offset(16);
 
             while m_ptr < m_end {
                 *m_ptr += 5;
-                m_ptr = m_ptr + 1u8;
+                m_ptr = m_ptr.offset(1);
             }
 
             assert_eq!(xs_mut, ~[10, ..16]);
@@ -702,17 +648,17 @@ fn test_ptr_subtraction() {
             let ptr = to_ptr(xs);
 
             while idx >= 0i8 {
-                assert_eq!(*(ptr + idx), idx as int);
+                assert_eq!(*(ptr.offset(idx as int)), idx as int);
                 idx = idx - 1i8;
             }
 
             let mut xs_mut = xs.clone();
             let m_start = to_mut_ptr(xs_mut);
-            let mut m_ptr = m_start + 9u32;
+            let mut m_ptr = m_start.offset(9);
 
             while m_ptr >= m_start {
                 *m_ptr += *m_ptr;
-                m_ptr = m_ptr - 1i8;
+                m_ptr = m_ptr.offset(-1);
             }
 
             assert_eq!(xs_mut, ~[0,2,4,6,8,10,12,14,16,18]);
index 56e0f83e05cf0ea722ae87f93a52dd82f474da9a..724877db00a1763bebb0518da6ec7693f9e7be9c 100644 (file)
@@ -28,9 +28,9 @@
  * 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);
+    fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void);
+    fn push_ptr(&mut self);
+    fn pop_ptr(&mut self);
 }
 
 /// Helper function for alignment calculation.
@@ -49,173 +49,173 @@ pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> {
 
 impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> {
     #[inline]
-    pub fn bump(&self, sz: uint) {
+    pub fn bump(&mut self, sz: uint) {
         do self.inner.move_ptr() |p| {
             ((p as uint) + sz) as *c_void
         };
     }
 
     #[inline]
-    pub fn align(&self, a: uint) {
+    pub fn align(&mut self, a: uint) {
         do self.inner.move_ptr() |p| {
             align(p as uint, a) as *c_void
         };
     }
 
     #[inline]
-    pub fn align_to<T>(&self) {
+    pub fn align_to<T>(&mut self) {
         self.align(sys::min_align_of::<T>());
     }
 
     #[inline]
-    pub fn bump_past<T>(&self) {
+    pub fn bump_past<T>(&mut 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 {
+    fn visit_bot(&mut self) -> bool {
         self.align_to::<()>();
         if ! self.inner.visit_bot() { return false; }
         self.bump_past::<()>();
         true
     }
 
-    fn visit_nil(&self) -> bool {
+    fn visit_nil(&mut self) -> bool {
         self.align_to::<()>();
         if ! self.inner.visit_nil() { return false; }
         self.bump_past::<()>();
         true
     }
 
-    fn visit_bool(&self) -> bool {
+    fn visit_bool(&mut self) -> bool {
         self.align_to::<bool>();
         if ! self.inner.visit_bool() { return false; }
         self.bump_past::<bool>();
         true
     }
 
-    fn visit_int(&self) -> bool {
+    fn visit_int(&mut self) -> bool {
         self.align_to::<int>();
         if ! self.inner.visit_int() { return false; }
         self.bump_past::<int>();
         true
     }
 
-    fn visit_i8(&self) -> bool {
+    fn visit_i8(&mut self) -> bool {
         self.align_to::<i8>();
         if ! self.inner.visit_i8() { return false; }
         self.bump_past::<i8>();
         true
     }
 
-    fn visit_i16(&self) -> bool {
+    fn visit_i16(&mut self) -> bool {
         self.align_to::<i16>();
         if ! self.inner.visit_i16() { return false; }
         self.bump_past::<i16>();
         true
     }
 
-    fn visit_i32(&self) -> bool {
+    fn visit_i32(&mut self) -> bool {
         self.align_to::<i32>();
         if ! self.inner.visit_i32() { return false; }
         self.bump_past::<i32>();
         true
     }
 
-    fn visit_i64(&self) -> bool {
+    fn visit_i64(&mut self) -> bool {
         self.align_to::<i64>();
         if ! self.inner.visit_i64() { return false; }
         self.bump_past::<i64>();
         true
     }
 
-    fn visit_uint(&self) -> bool {
+    fn visit_uint(&mut self) -> bool {
         self.align_to::<uint>();
         if ! self.inner.visit_uint() { return false; }
         self.bump_past::<uint>();
         true
     }
 
-    fn visit_u8(&self) -> bool {
+    fn visit_u8(&mut self) -> bool {
         self.align_to::<u8>();
         if ! self.inner.visit_u8() { return false; }
         self.bump_past::<u8>();
         true
     }
 
-    fn visit_u16(&self) -> bool {
+    fn visit_u16(&mut self) -> bool {
         self.align_to::<u16>();
         if ! self.inner.visit_u16() { return false; }
         self.bump_past::<u16>();
         true
     }
 
-    fn visit_u32(&self) -> bool {
+    fn visit_u32(&mut self) -> bool {
         self.align_to::<u32>();
         if ! self.inner.visit_u32() { return false; }
         self.bump_past::<u32>();
         true
     }
 
-    fn visit_u64(&self) -> bool {
+    fn visit_u64(&mut self) -> bool {
         self.align_to::<u64>();
         if ! self.inner.visit_u64() { return false; }
         self.bump_past::<u64>();
         true
     }
 
-    fn visit_float(&self) -> bool {
+    fn visit_float(&mut self) -> bool {
         self.align_to::<float>();
         if ! self.inner.visit_float() { return false; }
         self.bump_past::<float>();
         true
     }
 
-    fn visit_f32(&self) -> bool {
+    fn visit_f32(&mut self) -> bool {
         self.align_to::<f32>();
         if ! self.inner.visit_f32() { return false; }
         self.bump_past::<f32>();
         true
     }
 
-    fn visit_f64(&self) -> bool {
+    fn visit_f64(&mut self) -> bool {
         self.align_to::<f64>();
         if ! self.inner.visit_f64() { return false; }
         self.bump_past::<f64>();
         true
     }
 
-    fn visit_char(&self) -> bool {
+    fn visit_char(&mut self) -> bool {
         self.align_to::<char>();
         if ! self.inner.visit_char() { return false; }
         self.bump_past::<char>();
         true
     }
 
-    fn visit_estr_box(&self) -> bool {
+    fn visit_estr_box(&mut 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 {
+    fn visit_estr_uniq(&mut 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 {
+    fn visit_estr_slice(&mut 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,
+    fn visit_estr_fixed(&mut self, n: uint,
                         sz: uint,
                         align: uint) -> bool {
         self.align(align);
@@ -224,83 +224,83 @@ fn visit_estr_fixed(&self, n: uint,
         true
     }
 
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
+    fn visit_box(&mut 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 {
+    fn visit_uniq(&mut 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 {
+    fn visit_uniq_managed(&mut 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 {
+    fn visit_ptr(&mut 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 {
+    fn visit_rptr(&mut 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 {
+    fn visit_unboxed_vec(&mut 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 {
+    fn visit_vec(&mut 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 {
+    fn visit_evec_box(&mut 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 {
+    fn visit_evec_uniq(&mut 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 {
+    fn visit_evec_uniq_managed(&mut 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 {
+    fn visit_evec_slice(&mut 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,
+    fn visit_evec_fixed(&mut 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) {
@@ -310,13 +310,13 @@ fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
         true
     }
 
-    fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+    fn visit_enter_rec(&mut 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,
+    fn visit_rec_field(&mut 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) {
@@ -326,12 +326,12 @@ fn visit_rec_field(&self, i: uint, name: &str,
         true
     }
 
-    fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+    fn visit_leave_rec(&mut 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)
+    fn visit_enter_class(&mut self, n_fields: uint, sz: uint, align: uint)
                       -> bool {
         self.align(align);
         if ! self.inner.visit_enter_class(n_fields, sz, align) {
@@ -340,7 +340,7 @@ fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint)
         true
     }
 
-    fn visit_class_field(&self, i: uint, name: &str,
+    fn visit_class_field(&mut 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) {
@@ -350,7 +350,7 @@ fn visit_class_field(&self, i: uint, name: &str,
         true
     }
 
-    fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
+    fn visit_leave_class(&mut self, n_fields: uint, sz: uint, align: uint)
                       -> bool {
         if ! self.inner.visit_leave_class(n_fields, sz, align) {
             return false;
@@ -358,25 +358,25 @@ fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
         true
     }
 
-    fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+    fn visit_enter_tup(&mut 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 {
+    fn visit_tup_field(&mut 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 {
+    fn visit_leave_tup(&mut 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,
+    fn visit_enter_fn(&mut self, purity: uint, proto: uint,
                       n_inputs: uint, retstyle: uint) -> bool {
         if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) {
             return false
@@ -384,17 +384,17 @@ fn visit_enter_fn(&self, purity: uint, proto: uint,
         true
     }
 
-    fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool {
+    fn visit_fn_input(&mut 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 {
+    fn visit_fn_output(&mut 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,
+    fn visit_leave_fn(&mut self, purity: uint, proto: uint,
                       n_inputs: uint, retstyle: uint) -> bool {
         if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) {
             return false;
@@ -402,7 +402,7 @@ fn visit_leave_fn(&self, purity: uint, proto: uint,
         true
     }
 
-    fn visit_enter_enum(&self, n_variants: uint,
+    fn visit_enter_enum(&mut self, n_variants: uint,
                         get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         sz: uint, align: uint)
                      -> bool {
@@ -413,7 +413,7 @@ fn visit_enter_enum(&self, n_variants: uint,
         true
     }
 
-    fn visit_enter_enum_variant(&self, variant: uint,
+    fn visit_enter_enum_variant(&mut self, variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
                                 name: &str) -> bool {
@@ -424,7 +424,7 @@ fn visit_enter_enum_variant(&self, variant: uint,
         true
     }
 
-    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
+    fn visit_enum_variant_field(&mut 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; }
@@ -432,7 +432,7 @@ fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> boo
         true
     }
 
-    fn visit_leave_enum_variant(&self, variant: uint,
+    fn visit_leave_enum_variant(&mut self, variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
                                 name: &str) -> bool {
@@ -443,7 +443,7 @@ fn visit_leave_enum_variant(&self, variant: uint,
         true
     }
 
-    fn visit_leave_enum(&self, n_variants: uint,
+    fn visit_leave_enum(&mut 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) {
@@ -453,38 +453,38 @@ fn visit_leave_enum(&self, n_variants: uint,
         true
     }
 
-    fn visit_trait(&self) -> bool {
+    fn visit_trait(&mut 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 {
+    fn visit_param(&mut self, i: uint) -> bool {
         if ! self.inner.visit_param(i) { return false; }
         true
     }
 
-    fn visit_self(&self) -> bool {
+    fn visit_self(&mut 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 {
+    fn visit_type(&mut self) -> bool {
         if ! self.inner.visit_type() { return false; }
         true
     }
 
-    fn visit_opaque_box(&self) -> bool {
+    fn visit_opaque_box(&mut 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 {
+    fn visit_closure_ptr(&mut self, ck: uint) -> bool {
         self.align_to::<@fn()>();
         if ! self.inner.visit_closure_ptr(ck) { return false; }
         self.bump_past::<@fn()>();
diff --git a/src/libstd/reflect_stage0.rs b/src/libstd/reflect_stage0.rs
new file mode 100644 (file)
index 0000000..56e0f83
--- /dev/null
@@ -0,0 +1,493 @@
+// 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
+    }
+}
index ad4658d2f42bb1a7bbdb01e6d9dec192790ec5d4..15f4c24060c0684b45731256436f39b4b887198d 100644 (file)
@@ -19,7 +19,7 @@
 use cast::transmute;
 use char;
 use container::Container;
-use io::{Writer, WriterUtil};
+use rt::io;
 use iterator::Iterator;
 use libc::c_void;
 use option::{Some, None};
 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);
+    fn write_repr(&self, writer: &mut io::Writer);
 }
 
 impl Repr for () {
-    fn write_repr(&self, writer: @Writer) { writer.write_str("()"); }
+    fn write_repr(&self, writer: &mut io::Writer) {
+        writer.write("()".as_bytes());
+    }
 }
 
 impl Repr for bool {
-    fn write_repr(&self, writer: @Writer) {
-        writer.write_str(if *self { "true" } else { "false" })
+    fn write_repr(&self, writer: &mut io::Writer) {
+        let s = if *self { "true" } else { "false" };
+        writer.write(s.as_bytes())
     }
 }
 
 impl Repr for int {
-    fn write_repr(&self, writer: @Writer) {
+    fn write_repr(&self, writer: &mut io::Writer) {
         do ::int::to_str_bytes(*self, 10u) |bits| {
             writer.write(bits);
         }
@@ -84,7 +60,7 @@ fn write_repr(&self, writer: @Writer) {
 }
 
 macro_rules! int_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
-    fn write_repr(&self, writer: @Writer) {
+    fn write_repr(&self, writer: &mut io::Writer) {
         do ::$ty::to_str_bytes(*self, 10u) |bits| {
             writer.write(bits);
             writer.write(bytes!($suffix));
@@ -103,14 +79,14 @@ fn write_repr(&self, writer: @Writer) {
 int_repr!(u64, "u64")
 
 impl Repr for float {
-    fn write_repr(&self, writer: @Writer) {
+    fn write_repr(&self, writer: &mut io::Writer) {
         let s = self.to_str();
         writer.write(s.as_bytes());
     }
 }
 
 macro_rules! num_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
-    fn write_repr(&self, writer: @Writer) {
+    fn write_repr(&self, writer: &mut io::Writer) {
         let s = self.to_str();
         writer.write(s.as_bytes());
         writer.write(bytes!($suffix));
@@ -128,87 +104,97 @@ enum VariantState {
     AlreadyFound
 }
 
-pub struct ReprVisitor {
-    ptr: @mut *c_void,
-    ptr_stk: @mut ~[*c_void],
-    var_stk: @mut ~[VariantState],
-    writer: @Writer
+pub struct ReprVisitor<'self> {
+    ptr: *c_void,
+    ptr_stk: ~[*c_void],
+    var_stk: ~[VariantState],
+    writer: &'self mut io::Writer
 }
-pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
+
+pub fn ReprVisitor<'a>(ptr: *c_void,
+                       writer: &'a mut io::Writer) -> ReprVisitor<'a> {
     ReprVisitor {
-        ptr: @mut ptr,
-        ptr_stk: @mut ~[],
-        var_stk: @mut ~[],
+        ptr: ptr,
+        ptr_stk: ~[],
+        var_stk: ~[],
         writer: writer,
     }
 }
 
-impl MovePtr for ReprVisitor {
+impl<'self> MovePtr for ReprVisitor<'self> {
     #[inline]
-    fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
-        *self.ptr = adjustment(*self.ptr);
+    fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void) {
+        self.ptr = adjustment(self.ptr);
     }
-    fn push_ptr(&self) {
-        self.ptr_stk.push(*self.ptr);
+    fn push_ptr(&mut self) {
+        self.ptr_stk.push(self.ptr);
     }
-    fn pop_ptr(&self) {
-        *self.ptr = self.ptr_stk.pop();
+    fn pop_ptr(&mut self) {
+        self.ptr = self.ptr_stk.pop();
     }
 }
 
-impl ReprVisitor {
+impl<'self> ReprVisitor<'self> {
     // Various helpers for the TyVisitor impl
 
     #[inline]
-    pub fn get<T>(&self, f: &fn(&T)) -> bool {
+    pub fn get<T>(&mut self, f: &fn(&mut ReprVisitor, &T)) -> bool {
         unsafe {
-            f(transmute::<*c_void,&T>(*self.ptr));
+            f(self, transmute::<*c_void,&T>(self.ptr));
         }
         true
     }
 
     #[inline]
-    pub fn visit_inner(&self, inner: *TyDesc) -> bool {
-        self.visit_ptr_inner(*self.ptr, inner)
+    pub fn visit_inner(&mut self, inner: *TyDesc) -> bool {
+        self.visit_ptr_inner(self.ptr, inner)
     }
 
     #[inline]
-    pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
+    pub fn visit_ptr_inner(&mut 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);
+            // This should call the constructor up above, but due to limiting
+            // issues we have to recreate it here.
+            let u = ReprVisitor {
+                ptr: ptr,
+                ptr_stk: ~[],
+                var_stk: ~[],
+                writer: ::cast::transmute_copy(&self.writer),
+            };
+            let mut v = reflect::MovePtrAdaptor(u);
+            // Obviously this should not be a thing, but blame #8401 for now
+            visit_tydesc(inner, &mut v as &mut TyVisitor);
             true
         }
     }
 
     #[inline]
-    pub fn write<T:Repr>(&self) -> bool {
-        do self.get |v:&T| {
-            v.write_repr(self.writer);
+    pub fn write<T:Repr>(&mut self) -> bool {
+        do self.get |this, v:&T| {
+            v.write_repr(unsafe { ::cast::transmute_copy(&this.writer) });
         }
     }
 
-    pub fn write_escaped_slice(&self, slice: &str) {
-        self.writer.write_char('"');
+    pub fn write_escaped_slice(&mut self, slice: &str) {
+        self.writer.write(['"' as u8]);
         for ch in slice.iter() {
-            self.writer.write_escaped_char(ch);
+            self.write_escaped_char(ch);
         }
-        self.writer.write_char('"');
+        self.writer.write(['"' as u8]);
     }
 
-    pub fn write_mut_qualifier(&self, mtbl: uint) {
+    pub fn write_mut_qualifier(&mut self, mtbl: uint) {
         if mtbl == 0 {
-            self.writer.write_str("mut ");
+            self.writer.write("mut ".as_bytes());
         } else if mtbl == 1 {
             // skip, this is ast::m_imm
         } else {
             assert_eq!(mtbl, 2);
-            self.writer.write_str("const ");
+            self.writer.write("const ".as_bytes());
         }
     }
 
-    pub fn write_vec_range(&self,
+    pub fn write_vec_range(&mut self,
                            _mtbl: uint,
                            ptr: *(),
                            len: uint,
@@ -216,7 +202,7 @@ pub fn write_vec_range(&self,
                            -> bool {
         let mut p = ptr as *u8;
         let (sz, al) = unsafe { ((*inner).size, (*inner).align) };
-        self.writer.write_char('[');
+        self.writer.write(['[' as u8]);
         let mut first = true;
         let mut left = len;
         // unit structs have 0 size, and don't loop forever.
@@ -225,17 +211,17 @@ pub fn write_vec_range(&self,
             if first {
                 first = false;
             } else {
-                self.writer.write_str(", ");
+                self.writer.write(", ".as_bytes());
             }
             self.visit_ptr_inner(p as *c_void, inner);
-            p = align(ptr::offset(p, sz as int) as uint, al) as *u8;
+            p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8;
             left -= dec;
         }
-        self.writer.write_char(']');
+        self.writer.write([']' as u8]);
         true
     }
 
-    pub fn write_unboxed_vec_repr(&self,
+    pub fn write_unboxed_vec_repr(&mut self,
                                   mtbl: uint,
                                   v: &raw::Vec<()>,
                                   inner: *TyDesc)
@@ -243,239 +229,246 @@ pub fn write_unboxed_vec_repr(&self,
         self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data),
                              v.fill, inner)
     }
+
+    fn write_escaped_char(&mut self, ch: char) {
+        match ch {
+            '\t' => self.writer.write("\\t".as_bytes()),
+            '\r' => self.writer.write("\\r".as_bytes()),
+            '\n' => self.writer.write("\\n".as_bytes()),
+            '\\' => self.writer.write("\\\\".as_bytes()),
+            '\'' => self.writer.write("\\'".as_bytes()),
+            '"' => self.writer.write("\\\"".as_bytes()),
+            '\x20'..'\x7e' => self.writer.write([ch as u8]),
+            _ => {
+                do char::escape_unicode(ch) |c| {
+                    self.writer.write([c as u8]);
+                }
+            }
+        }
+    }
 }
 
-impl TyVisitor for ReprVisitor {
-    fn visit_bot(&self) -> bool {
-        self.writer.write_str("!");
+impl<'self> TyVisitor for ReprVisitor<'self> {
+    fn visit_bot(&mut self) -> bool {
+        self.writer.write("!".as_bytes());
         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_nil(&mut self) -> bool { self.write::<()>() }
+    fn visit_bool(&mut self) -> bool { self.write::<bool>() }
+    fn visit_int(&mut self) -> bool { self.write::<int>() }
+    fn visit_i8(&mut self) -> bool { self.write::<i8>() }
+    fn visit_i16(&mut self) -> bool { self.write::<i16>() }
+    fn visit_i32(&mut self) -> bool { self.write::<i32>()  }
+    fn visit_i64(&mut 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_uint(&mut self) -> bool { self.write::<uint>() }
+    fn visit_u8(&mut self) -> bool { self.write::<u8>() }
+    fn visit_u16(&mut self) -> bool { self.write::<u16>() }
+    fn visit_u32(&mut self) -> bool { self.write::<u32>() }
+    fn visit_u64(&mut 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_float(&mut self) -> bool { self.write::<float>() }
+    fn visit_f32(&mut self) -> bool { self.write::<f32>() }
+    fn visit_f64(&mut 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_char(&mut self) -> bool {
+        do self.get::<char> |this, &ch| {
+            this.writer.write(['\'' as u8]);
+            this.write_escaped_char(ch);
+            this.writer.write(['\'' as u8]);
         }
     }
 
-    fn visit_estr_box(&self) -> bool {
-        do self.get::<@str> |s| {
-            self.writer.write_char('@');
-            self.write_escaped_slice(*s);
+    fn visit_estr_box(&mut self) -> bool {
+        do self.get::<@str> |this, s| {
+            this.writer.write(['@' as u8]);
+            this.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_uniq(&mut self) -> bool {
+        do self.get::<~str> |this, s| {
+            this.writer.write(['~' as u8]);
+            this.write_escaped_slice(*s);
         }
     }
 
-    fn visit_estr_slice(&self) -> bool {
-        do self.get::<&str> |s| {
-            self.write_escaped_slice(*s);
+    fn visit_estr_slice(&mut self) -> bool {
+        do self.get::<&str> |this, s| {
+            this.write_escaped_slice(*s);
         }
     }
 
     // Type no longer exists, vestigial function.
-    fn visit_estr_fixed(&self, _n: uint, _sz: uint,
+    fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
                         _align: uint) -> bool { fail!(); }
 
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('@');
+    fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+        self.writer.write(['@' as u8]);
         self.write_mut_qualifier(mtbl);
-        do self.get::<&raw::Box<()>> |b| {
+        do self.get::<&raw::Box<()>> |this, b| {
             let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, inner);
+            this.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(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
+        self.writer.write(['~' as u8]);
+        do self.get::<*c_void> |this, b| {
+            this.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| {
+    fn visit_uniq_managed(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
+        self.writer.write(['~' as u8]);
+        do self.get::<&raw::Box<()>> |this, b| {
             let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, inner);
+            this.visit_ptr_inner(p, inner);
         }
     }
 
-    #[cfg(stage0)]
-    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_ptr(&mut self, mtbl: uint, _inner: *TyDesc) -> bool {
+        do self.get::<*c_void> |this, p| {
+            write!(this.writer, "({} as *", *p);
+            this.write_mut_qualifier(mtbl);
+            this.writer.write("())".as_bytes());
         }
     }
 
-    #[cfg(not(stage0))]
-    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));
-            self.write_mut_qualifier(mtbl);
-            self.writer.write_str("())");
-        }
-    }
-
-    fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('&');
+    fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+        self.writer.write(['&' as u8]);
         self.write_mut_qualifier(mtbl);
-        do self.get::<*c_void> |p| {
-            self.visit_ptr_inner(*p, inner);
+        do self.get::<*c_void> |this, p| {
+            this.visit_ptr_inner(*p, inner);
         }
     }
 
     // Type no longer exists, vestigial function.
-    fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); }
+    fn visit_vec(&mut 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_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+        do self.get::<raw::Vec<()>> |this, b| {
+            this.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_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+        do self.get::<&raw::Box<raw::Vec<()>>> |this, b| {
+            this.writer.write(['@' as u8]);
+            this.write_mut_qualifier(mtbl);
+            this.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(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+        do self.get::<&raw::Vec<()>> |this, b| {
+            this.writer.write(['~' as u8]);
+            this.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_uniq_managed(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+        do self.get::<&raw::Box<raw::Vec<()>>> |this, b| {
+            this.writer.write(['~' as u8]);
+            this.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_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+        do self.get::<raw::Slice<()>> |this, s| {
+            this.writer.write(['&' as u8]);
+            this.write_vec_range(mtbl, s.data, s.len, inner);
         }
     }
 
-    fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint,
+    fn visit_evec_fixed(&mut 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);
+        do self.get::<()> |this, b| {
+            this.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner);
         }
     }
 
-    fn visit_enter_rec(&self, _n_fields: uint,
+    fn visit_enter_rec(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('{');
+        self.writer.write(['{' as u8]);
         true
     }
 
-    fn visit_rec_field(&self, i: uint, name: &str,
+    fn visit_rec_field(&mut self, i: uint, name: &str,
                        mtbl: uint, inner: *TyDesc) -> bool {
         if i != 0 {
-            self.writer.write_str(", ");
+            self.writer.write(", ".as_bytes());
         }
         self.write_mut_qualifier(mtbl);
-        self.writer.write_str(name);
-        self.writer.write_str(": ");
+        self.writer.write(name.as_bytes());
+        self.writer.write(": ".as_bytes());
         self.visit_inner(inner);
         true
     }
 
-    fn visit_leave_rec(&self, _n_fields: uint,
+    fn visit_leave_rec(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('}');
+        self.writer.write(['}' as u8]);
         true
     }
 
-    fn visit_enter_class(&self, _n_fields: uint,
+    fn visit_enter_class(&mut self, _n_fields: uint,
                          _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('{');
+        self.writer.write(['{' as u8]);
         true
     }
-    fn visit_class_field(&self, i: uint, name: &str,
+    fn visit_class_field(&mut self, i: uint, name: &str,
                          mtbl: uint, inner: *TyDesc) -> bool {
         if i != 0 {
-            self.writer.write_str(", ");
+            self.writer.write(", ".as_bytes());
         }
         self.write_mut_qualifier(mtbl);
-        self.writer.write_str(name);
-        self.writer.write_str(": ");
+        self.writer.write(name.as_bytes());
+        self.writer.write(": ".as_bytes());
         self.visit_inner(inner);
         true
     }
-    fn visit_leave_class(&self, _n_fields: uint,
+    fn visit_leave_class(&mut self, _n_fields: uint,
                          _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('}');
+        self.writer.write(['}' as u8]);
         true
     }
 
-    fn visit_enter_tup(&self, _n_fields: uint,
+    fn visit_enter_tup(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('(');
+        self.writer.write(['(' as u8]);
         true
     }
-    fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
+    fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool {
         if i != 0 {
-            self.writer.write_str(", ");
+            self.writer.write(", ".as_bytes());
         }
         self.visit_inner(inner);
         true
     }
-    fn visit_leave_tup(&self, _n_fields: uint,
+    fn visit_leave_tup(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool {
         if _n_fields == 1 {
-            self.writer.write_char(',');
+            self.writer.write([',' as u8]);
         }
-        self.writer.write_char(')');
+        self.writer.write([')' as u8]);
         true
     }
 
-    fn visit_enter_enum(&self,
+    fn visit_enter_enum(&mut 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))
+            get_disr(transmute(self.ptr))
         };
-        var_stk.push(SearchingFor(disr));
+        self.var_stk.push(SearchingFor(disr));
         true
     }
 
-    fn visit_enter_enum_variant(&self, _variant: uint,
+    fn visit_enter_enum_variant(&mut self, _variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
                                 name: &str) -> bool {
@@ -495,15 +488,15 @@ fn visit_enter_enum_variant(&self, _variant: uint,
         }
 
         if write {
-            self.writer.write_str(name);
+            self.writer.write(name.as_bytes());
             if n_fields > 0 {
-                self.writer.write_char('(');
+                self.writer.write(['(' as u8]);
             }
         }
         true
     }
 
-    fn visit_enum_variant_field(&self,
+    fn visit_enum_variant_field(&mut self,
                                 i: uint,
                                 _offset: uint,
                                 inner: *TyDesc)
@@ -511,7 +504,7 @@ fn visit_enum_variant_field(&self,
         match self.var_stk[self.var_stk.len() - 1] {
             Matched => {
                 if i != 0 {
-                    self.writer.write_str(", ");
+                    self.writer.write(", ".as_bytes());
                 }
                 if ! self.visit_inner(inner) {
                     return false;
@@ -522,14 +515,14 @@ fn visit_enum_variant_field(&self,
         true
     }
 
-    fn visit_leave_enum_variant(&self, _variant: uint,
+    fn visit_leave_enum_variant(&mut 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(')');
+                    self.writer.write([')' as u8]);
                 }
             }
             _ => ()
@@ -537,54 +530,53 @@ fn visit_leave_enum_variant(&self, _variant: uint,
         true
     }
 
-    fn visit_leave_enum(&self,
+    fn visit_leave_enum(&mut 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() {
+        match self.var_stk.pop() {
             SearchingFor(*) => fail!("enum value matched no variant"),
             _ => true
         }
     }
 
-    fn visit_enter_fn(&self, _purity: uint, _proto: uint,
+    fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
                       _n_inputs: uint, _retstyle: uint) -> bool { true }
-    fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
+    fn visit_fn_input(&mut self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
         true
     }
-    fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
+    fn visit_fn_output(&mut self, _retstyle: uint, _inner: *TyDesc) -> bool {
         true
     }
-    fn visit_leave_fn(&self, _purity: uint, _proto: uint,
+    fn visit_leave_fn(&mut 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_trait(&mut self) -> bool { true }
+    fn visit_param(&mut self, _i: uint) -> bool { true }
+    fn visit_self(&mut self) -> bool { true }
+    fn visit_type(&mut self) -> bool { true }
 
-    fn visit_opaque_box(&self) -> bool {
-        self.writer.write_char('@');
-        do self.get::<&raw::Box<()>> |b| {
+    fn visit_opaque_box(&mut self) -> bool {
+        self.writer.write(['@' as u8]);
+        do self.get::<&raw::Box<()>> |this, b| {
             let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, b.type_desc);
+            this.visit_ptr_inner(p, b.type_desc);
         }
     }
 
-    fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
+    fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
 }
 
-pub fn write_repr<T>(writer: @Writer, object: &T) {
+pub fn write_repr<T>(writer: &mut io::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)
+        let mut v = reflect::MovePtrAdaptor(u);
+        visit_tydesc(tydesc, &mut v as &mut TyVisitor);
     }
 }
 
@@ -593,14 +585,15 @@ struct P {a: int, b: float}
 
 #[test]
 fn test_repr() {
+    use str;
+    use str::Str;
+    use rt::io::Decorator;
 
     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);
+        let mut m = io::mem::MemWriter::new();
+        write_repr(&mut m as &mut io::Writer, t);
+        let s = str::from_bytes_owned(m.inner());
+        assert_eq!(s.as_slice(), e);
     }
 
     exact_test(&10, "10");
diff --git a/src/libstd/repr_stage0.rs b/src/libstd/repr_stage0.rs
new file mode 100644 (file)
index 0000000..4e580d9
--- /dev/null
@@ -0,0 +1,626 @@
+// 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 iterator::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]), "~[{}, {}, {}]");
+}
index baaf3d44e79d3b22231985f60255dd6ec6d5afdd..e5075f8818a0b38f7d525c06e6205186743027d8 100644 (file)
@@ -55,10 +55,11 @@ pub fn clone() -> Option<~[~str]> {
 mod imp {
     use libc;
     use option::{Option, Some, None};
-    use iterator::{Iterator, range};
+    use iterator::Iterator;
     use str;
     use unstable::finally::Finally;
     use util;
+    use vec;
 
     pub unsafe fn init(argc: int, argv: **u8) {
         let args = load_argc_and_argv(argc, argv);
@@ -111,11 +112,9 @@ fn get_global_ptr() -> *mut Option<~~[~str]> {
 
     // Copied from `os`.
     unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> ~[~str] {
-        let mut args = ~[];
-        for i in range(0u, argc as uint) {
-            args.push(str::raw::from_c_str(*(argv as **libc::c_char).offset(i as int)));
+        do vec::from_fn(argc as uint) |i| {
+            str::raw::from_c_str(*(argv as **libc::c_char).offset(i as int))
         }
-        args
     }
 
     #[cfg(stage0)]
index 4b1881409f44f54e35f002342ee9bf23350e5411..4f5f26513b4c6fcf558cd52ab22bbac382a7f2d3 100644 (file)
@@ -718,7 +718,7 @@ mod test {
     use option::*;
     use rt::test::*;
     use cell::Cell;
-    use iter::Times;
+    use num::Times;
     use rt::util;
 
     #[test]
index 534e308a1a6e8dc65e0414560617070abe56aaa7..3fb0072040664c52e834a64baa48e5cff237a1ee 100644 (file)
@@ -71,6 +71,9 @@ pub struct FileStream {
     last_nread: int,
 }
 
+impl FileStream {
+}
+
 impl Reader for FileStream {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
         match self.fd.read(buf) {
@@ -165,6 +168,7 @@ fn file_test_smoke_test_impl() {
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_smoke_test() {
     file_test_smoke_test_impl();
 }
@@ -232,6 +236,7 @@ fn file_test_io_non_positional_read_impl() {
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_non_positional_read() {
     file_test_io_non_positional_read_impl();
 }
@@ -264,6 +269,7 @@ fn file_test_io_seeking_impl() {
     }
 }
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_seek_and_tell_smoke_test() {
     file_test_io_seeking_impl();
 }
@@ -295,6 +301,7 @@ fn file_test_io_seek_and_write_impl() {
     }
 }
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_seek_and_write() {
     file_test_io_seek_and_write_impl();
 }
@@ -334,6 +341,7 @@ fn file_test_io_seek_shakedown_impl() {
     }
 }
 #[test]
+#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_seek_shakedown() {
     file_test_io_seek_shakedown_impl();
 }
index 038fca9a1ade441c2e0a867ee1cf3eb89ae3a71f..116d240308a36c9cabf988df7d4bfe93c6762f53 100644 (file)
 /// Synchronous, non-blocking file I/O.
 pub mod file;
 
-/// Synchronous, in-memory I/O.
-pub mod pipe;
-
 /// Synchronous, non-blocking network I/O.
 pub mod net {
     pub mod tcp;
index dc7135f4a61ecb2bea11351b4a6b67fc3e6c9d52..ce66cd0de59c2e656281bcea1875126553024d59 100644 (file)
@@ -16,7 +16,7 @@
 use rt::rtio::{IoFactory, IoFactoryObject,
                RtioSocket, RtioTcpListener,
                RtioTcpListenerObject, RtioTcpStream,
-               RtioTcpStreamObject, RtioStream};
+               RtioTcpStreamObject};
 use rt::local::Local;
 
 pub struct TcpStream(~RtioTcpStreamObject);
@@ -69,7 +69,7 @@ pub fn socket_name(&mut self) -> Option<SocketAddr> {
 
 impl Reader for TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        match (***self).read(buf) {
+        match (**self).read(buf) {
             Ok(read) => Some(read),
             Err(ioerr) => {
                 // EOF is indicated by returning None
@@ -86,7 +86,7 @@ fn eof(&mut self) -> bool { fail!() }
 
 impl Writer for TcpStream {
     fn write(&mut self, buf: &[u8]) {
-        match (***self).write(buf) {
+        match (**self).write(buf) {
             Ok(_) => (),
             Err(ioerr) => io_error::cond.raise(ioerr),
         }
@@ -162,11 +162,12 @@ fn bind_error() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8811
     fn connect_error() {
         do run_in_newsched_task {
             let mut called = false;
             do io_error::cond.trap(|e| {
-                assert_eq!(e.kind, ConnectionRefused);
+                assert!(e.kind == ConnectionRefused);
                 called = true;
             }).inside {
                 let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
@@ -258,6 +259,7 @@ fn read_eof_ip6() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8811
     fn read_eof_twice_ip4() {
         do run_in_newsched_task {
             let addr = next_test_ip4();
@@ -280,6 +282,7 @@ fn read_eof_twice_ip4() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8811
     fn read_eof_twice_ip6() {
         do run_in_newsched_task {
             let addr = next_test_ip6();
@@ -302,6 +305,7 @@ fn read_eof_twice_ip6() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8811
     fn write_close_ip4() {
         do run_in_newsched_task {
             let addr = next_test_ip4();
@@ -331,6 +335,7 @@ fn write_close_ip4() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8811
     fn write_close_ip6() {
         do run_in_newsched_task {
             let addr = next_test_ip6();
diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs
deleted file mode 100644 (file)
index 02b3d0f..0000000
+++ /dev/null
@@ -1,77 +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.
-
-//! 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::{RtioPipeObject, RtioStream, IoFactoryObject, IoFactory};
-use rt::uv::pipe;
-
-pub struct PipeStream(~RtioPipeObject);
-
-impl PipeStream {
-    /// Creates a new pipe initialized, but not bound to any particular
-    /// source/destination
-    pub fn new() -> Option<PipeStream> {
-        let pipe = unsafe {
-            let io: *mut IoFactoryObject = Local::unsafe_borrow();
-            (*io).pipe_init(false)
-        };
-        match pipe {
-            Ok(p) => Some(PipeStream(p)),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
-    }
-
-    /// Extracts the underlying libuv pipe to be bound to another source.
-    pub fn uv_pipe(&self) -> pipe::Pipe {
-        // Did someone say multiple layers of indirection?
-        (**self).uv_pipe()
-    }
-}
-
-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!() }
-}
index 7bace5d6df2ccfdba1cfe7538ab05cbed10da6cb..afbff77f9883226e03e4985eb696c06de631e2a1 100644 (file)
@@ -33,6 +33,7 @@ mod test {
     use super::PathLike;
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8812
     fn path_like_smoke_test() {
         let expected = "/home";
         let path = Path(expected);
index e843fd1adef07aa6e258ac16cc52c628b1b374f7..3f9b7fc83df9822b618ff658f97db38f4cad4999 100644 (file)
@@ -121,27 +121,20 @@ pub unsafe fn borrow<T>(f: &fn(&mut T)) {
 /// For the Scheduler pointer to be aliased
 pub unsafe fn unsafe_borrow<T>() -> *mut T {
     let key = tls_key();
-    let mut void_ptr: *mut c_void = tls::get(key);
+    let void_ptr = tls::get(key);
     if void_ptr.is_null() {
         rtabort!("thread-local pointer is null. bogus!");
     }
-    let ptr: *mut *mut c_void = &mut void_ptr;
-    let ptr: *mut ~T = ptr as *mut ~T;
-    let ptr: *mut T = &mut **ptr;
-    return ptr;
+    void_ptr as *mut T
 }
 
 pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
     let key = tls_key();
-    let mut void_ptr: *mut c_void = tls::get(key);
+    let void_ptr = tls::get(key);
     if void_ptr.is_null() {
-        return None;
-    }
-    {
-        let ptr: *mut *mut c_void = &mut void_ptr;
-        let ptr: *mut ~T = ptr as *mut ~T;
-        let ptr: *mut T = &mut **ptr;
-        return Some(ptr);
+        None
+    } else {
+        Some(void_ptr as *mut T)
     }
 }
 
index 6dbeb8c0ea9271d091e60c282aeccfb8a706393c..14ff1fd58044f56b3b7717e556ddbbe056a4abbd 100644 (file)
 */
 
 #[doc(hidden)];
-#[deny(unused_imports)];
-#[deny(unused_mut)];
-#[deny(unused_variable)];
-#[deny(unused_unsafe)];
 
 use cell::Cell;
 use clone::Clone;
 use container::Container;
-use iterator::{Iterator, range};
+use iterator::Iterator;
 use option::{Option, None, Some};
 use ptr::RawPtr;
 use rt::local::Local;
@@ -75,7 +71,8 @@
 use rt::uv::uvio::UvEventLoop;
 use unstable::atomics::{AtomicInt, SeqCst};
 use unstable::sync::UnsafeArc;
-use vec::{OwnedVector, MutableVector};
+use vec;
+use vec::{OwnedVector, MutableVector, ImmutableVector};
 
 /// The global (exchange) heap.
 pub mod global_heap;
@@ -255,11 +252,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
 
     // Create a work queue for each scheduler, ntimes. Create an extra
     // for the main thread if that flag is set. We won't steal from it.
-    let mut work_queues = ~[];
-    for _ in range(0u, nscheds) {
-        let work_queue: WorkQueue<~Task> = WorkQueue::new();
-        work_queues.push(work_queue);
-    }
+    let work_queues: ~[WorkQueue<~Task>] = vec::from_fn(nscheds, |_| WorkQueue::new());
 
     // The schedulers.
     let mut scheds = ~[];
@@ -267,13 +260,13 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
     // sent the Shutdown message to terminate the schedulers.
     let mut handles = ~[];
 
-    for i in range(0u, nscheds) {
+    for work_queue in work_queues.iter() {
         rtdebug!("inserting a regular scheduler");
 
         // Every scheduler is driven by an I/O event loop.
         let loop_ = ~UvEventLoop::new();
         let mut sched = ~Scheduler::new(loop_,
-                                        work_queues[i].clone(),
+                                        work_queue.clone(),
                                         work_queues.clone(),
                                         sleepers.clone());
         let handle = sched.make_handle();
@@ -362,9 +355,8 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
     }
 
     // Run each remaining scheduler in a thread.
-    while !scheds.is_empty() {
+    for sched in scheds.move_rev_iter() {
         rtdebug!("creating regular schedulers");
-        let sched = scheds.pop();
         let sched_cell = Cell::new(sched);
         let thread = do Thread::start {
             let mut sched = sched_cell.take();
index 1a7ef6ea309b9ac78c4f781298b782a93b131c93..1788b7a04e33446c3e8c04b77671481eed5bea29 100644 (file)
@@ -8,14 +8,12 @@
 // 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::net::ip::{IpAddr, SocketAddr};
-use rt::uv;
 use rt::uv::uvio;
 use path::Path;
 use super::io::support::PathLike;
@@ -32,9 +30,6 @@
 pub type RtioUdpSocketObject = uvio::UvUdpSocket;
 pub type RtioTimerObject = uvio::UvTimer;
 pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
-pub type RtioPipeObject = uvio::UvPipeStream;
-pub type RtioProcessObject = uvio::UvProcess;
-pub type RtioProcessConfig<'self> = uv::process::Config<'self>;
 
 pub trait EventLoop {
     fn run(&mut self);
@@ -77,13 +72,6 @@ pub trait IoFactory {
     fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
         -> Result<~RtioFileStream, IoError>;
     fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
-    fn pipe_init(&mut self, ipc: bool) -> Result<~RtioPipeObject, IoError>;
-    fn spawn(&mut self, config: &RtioProcessConfig) -> Result<~RtioProcessObject, IoError>;
-}
-
-pub trait RtioStream {
-    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
-    fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
 }
 
 pub trait RtioTcpListener : RtioSocket {
@@ -92,7 +80,9 @@ pub trait RtioTcpListener : RtioSocket {
     fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>;
 }
 
-pub trait RtioTcpStream : RtioSocket + RtioStream {
+pub trait RtioTcpStream : RtioSocket {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
     fn peer_name(&mut self) -> Result<SocketAddr, IoError>;
     fn control_congestion(&mut self) -> Result<(), IoError>;
     fn nodelay(&mut self) -> Result<(), IoError>;
@@ -134,9 +124,3 @@ 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;
-}
index b393832871dd7dae2074f028d5fafea4c8fa612c..6aa66a6ab6bcd886d00b23aed6093c2e7e0d221a 100644 (file)
@@ -1114,7 +1114,7 @@ fn no_missed_messages() {
     #[test]
     fn multithreading() {
         use rt::comm::*;
-        use iter::Times;
+        use num::Times;
         use vec::OwnedVector;
         use container::Container;
 
index 4b2a9b7a6cce40b418df65d081be82ac787a5ab9..da70659acec2edfe577607b7a54b1fa1152cad27 100644 (file)
@@ -46,7 +46,9 @@ pub fn start(&self) -> *uint {
 
     /// Point one word beyond the high end of the allocated stack
     pub fn end(&self) -> *uint {
-        vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+        unsafe {
+            vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+        }
     }
 }
 
index b1ab7a6cd5d3eb0b96b9f91dbc6baa7dd36ad70c..da81aab0f7849eb6bfd5742629af46168b383219 100644 (file)
@@ -16,8 +16,8 @@
 use borrow;
 use cast::transmute;
 use cleanup;
+use local_data;
 use libc::{c_void, uintptr_t};
-use ptr;
 use prelude::*;
 use option::{Option, Some, None};
 use rt::borrowck;
@@ -80,7 +80,7 @@ pub enum SchedHome {
 }
 
 pub struct GarbageCollector;
-pub struct LocalStorage(*c_void, Option<extern "Rust" fn(*c_void)>);
+pub struct LocalStorage(Option<local_data::Map>);
 
 pub struct Unwinder {
     unwinding: bool,
@@ -130,7 +130,7 @@ pub fn new_sched_task() -> Task {
         Task {
             heap: LocalHeap::new(),
             gc: GarbageCollector,
-            storage: LocalStorage(ptr::null(), None),
+            storage: LocalStorage(None),
             logger: StdErrLogger,
             unwinder: Unwinder { unwinding: false },
             taskgroup: None,
@@ -164,7 +164,7 @@ pub fn new_root_homed(stack_pool: &mut StackPool,
         Task {
             heap: LocalHeap::new(),
             gc: GarbageCollector,
-            storage: LocalStorage(ptr::null(), None),
+            storage: LocalStorage(None),
             logger: StdErrLogger,
             unwinder: Unwinder { unwinding: false },
             taskgroup: None,
@@ -186,7 +186,7 @@ pub fn new_child_homed(&mut self,
         Task {
             heap: LocalHeap::new(),
             gc: GarbageCollector,
-            storage: LocalStorage(ptr::null(), None),
+            storage: LocalStorage(None),
             logger: StdErrLogger,
             unwinder: Unwinder { unwinding: false },
             taskgroup: None,
@@ -233,15 +233,8 @@ pub fn run(&mut self, f: &fn()) {
 
             // Run the task main function, then do some cleanup.
             do f.finally {
-
-                // Destroy task-local storage. This may run user dtors.
-                match self.storage {
-                    LocalStorage(ptr, Some(ref dtor)) => {
-                        (*dtor)(ptr)
-                    }
-                    _ => ()
-                }
-
+                // First, destroy task-local storage. This may run user dtors.
+                //
                 // FIXME #8302: Dear diary. I'm so tired and confused.
                 // There's some interaction in rustc between the box
                 // annihilator and the TLS dtor by which TLS is
@@ -253,7 +246,13 @@ pub fn run(&mut self, f: &fn()) {
                 // TLS would be reinitialized but never destroyed,
                 // but somehow this works. I have no idea what's going
                 // on but this seems to make things magically work. FML.
-                self.storage = LocalStorage(ptr::null(), None);
+                //
+                // (added after initial comment) A possible interaction here is
+                // that the destructors for the objects in TLS themselves invoke
+                // TLS, or possibly some destructors for those objects being
+                // annihilated invoke TLS. Sadly these two operations seemed to
+                // be intertwined, and miraculously work for now...
+                self.storage.take();
 
                 // Destroy remaining boxes. Also may run user dtors.
                 unsafe { cleanup::annihilate(); }
index 9113f03ffee1cd9402574ea4db971ffbd30be56c..6f39cbbade3d47265aa7e4201bf7c32860b5012c 100644 (file)
@@ -11,7 +11,7 @@
 use container::Container;
 use from_str::FromStr;
 use libc;
-use option::{Some, None};
+use option::{Some, None, Option};
 use os;
 use str::StrSlice;
 use unstable::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
@@ -57,7 +57,13 @@ pub fn limit_thread_creation_due_to_osx_and_valgrind() -> bool {
 /// either `RUST_THREADS` or `num_cpus`.
 pub fn default_sched_threads() -> uint {
     match os::getenv("RUST_THREADS") {
-        Some(nstr) => FromStr::from_str(nstr).unwrap(),
+        Some(nstr) => {
+            let opt_n: Option<uint> = FromStr::from_str(nstr);
+            match opt_n {
+                Some(n) if n > 0 => n,
+                _ => rtabort!("`RUST_THREADS` is `%s`, should be a positive integer", nstr)
+            }
+        }
         None => {
             if limit_thread_creation_due_to_osx_and_valgrind() {
                 1
index ff7bb9dd03abcf8403fd40a0d703e44c2c339618..d0ca38317cbededd13675b41c17ad764ee7f982b 100644 (file)
@@ -34,7 +34,7 @@ pub fn new(loop_: &mut Loop, cb: AsyncCallback) -> AsyncWatcher {
 
         extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
             let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
-            let status = status_to_maybe_uv_error(status);
+            let status = status_to_maybe_uv_error(watcher, status);
             let data = watcher.get_watcher_data();
             let cb = data.async_cb.get_ref();
             (*cb)(watcher, status);
index 5c77181d7eb83a7098a3cb194a85ee89c6157fa8..eaf7024244040cca6790a997e4147f435817d7b2 100644 (file)
@@ -11,8 +11,8 @@
 use prelude::*;
 use ptr::null;
 use libc::c_void;
-use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, UvError};
-use rt::uv::status_to_maybe_uv_error;
+use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
+             status_to_maybe_uv_error_with_loop, UvError};
 use rt::uv::uvll;
 use rt::uv::uvll::*;
 use super::super::io::support::PathLike;
@@ -62,7 +62,7 @@ pub fn open<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int,
     pub fn open_sync<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int)
           -> Result<int, UvError> {
         let result = FsRequest::open_common(loop_, path, flags, mode, None);
-        sync_cleanup(result)
+        sync_cleanup(loop_, result)
     }
 
     fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) -> int {
@@ -83,11 +83,11 @@ fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) ->
     }
     pub fn unlink<P: PathLike>(loop_: &Loop, path: &P, cb: FsCallback) {
         let result = FsRequest::unlink_common(loop_, path, Some(cb));
-        sync_cleanup(result);
+        sync_cleanup(loop_, result);
     }
     pub fn unlink_sync<P: PathLike>(loop_: &Loop, path: &P) -> Result<int, UvError> {
         let result = FsRequest::unlink_common(loop_, path, None);
-        sync_cleanup(result)
+        sync_cleanup(loop_, result)
     }
 
     pub fn install_req_data(&self, cb: Option<FsCallback>) {
@@ -139,8 +139,9 @@ fn native_handle(&self) -> *uvll::uv_fs_t {
         match self { &FsRequest(ptr) => ptr }
     }
 }
-    fn sync_cleanup(result: int) -> Result<int, UvError> {
-        match status_to_maybe_uv_error(result as i32) {
+    fn sync_cleanup(loop_: &Loop, result: int)
+          -> Result<int, UvError> {
+        match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
             Some(err) => Err(err),
             None => Ok(result)
         }
@@ -183,7 +184,7 @@ pub fn write(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
     pub fn write_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
           -> Result<int, UvError> {
         let result = self.write_common(loop_, buf, offset, None);
-        sync_cleanup(result)
+        sync_cleanup(loop_, result)
     }
 
     fn read_common(&mut self, loop_: &Loop, buf: Buf,
@@ -211,7 +212,7 @@ pub fn read(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
     pub fn read_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
           -> Result<int, UvError> {
         let result = self.read_common(loop_, buf, offset, None);
-        sync_cleanup(result)
+        sync_cleanup(loop_, result)
     }
 
     fn close_common(self, loop_: &Loop, cb: Option<FsCallback>) -> int {
@@ -233,11 +234,12 @@ pub fn close(self, loop_: &Loop, cb: FsCallback) {
     }
     pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
         let result = self.close_common(loop_, None);
-        sync_cleanup(result)
+        sync_cleanup(loop_, result)
     }
 }
 extern fn compl_cb(req: *uv_fs_t) {
     let mut req: FsRequest = NativeHandle::from_native_handle(req);
+    let loop_ = req.get_loop();
     // pull the user cb out of the req data
     let cb = {
         let data = req.get_req_data();
@@ -248,7 +250,8 @@ pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
     // in uv_fs_open calls, the result will be the fd in the
     // case of success, otherwise it's -1 indicating an error
     let result = req.get_result();
-    let status = status_to_maybe_uv_error(result);
+    let status = status_to_maybe_uv_error_with_loop(
+        loop_.native_handle(), result);
     // we have a req and status, call the user cb..
     // only giving the user a ref to the FsRequest, as we
     // have to clean it up, afterwards (and they aren't really
@@ -405,11 +408,13 @@ fn file_test_full_simple_impl_sync() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8814
     fn file_test_full_simple() {
         file_test_full_simple_impl();
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8814
     fn file_test_full_simple_sync() {
         file_test_full_simple_impl_sync();
     }
index 8cbcd7b77c0824fdea0b1df2e1234cdc0a412b3c..a21146620ca823ec8643adfdb84c00f31a391b38 100644 (file)
@@ -43,7 +43,7 @@ pub fn start(&mut self, cb: IdleCallback) {
             let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
             let data = idle_watcher.get_watcher_data();
             let cb: &IdleCallback = data.idle_cb.get_ref();
-            let status = status_to_maybe_uv_error(status);
+            let status = status_to_maybe_uv_error(idle_watcher, status);
             (*cb)(idle_watcher, status);
         }
     }
@@ -57,7 +57,7 @@ pub fn restart(&mut self) {
             let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
             let data = idle_watcher.get_watcher_data();
             let cb: &IdleCallback = data.idle_cb.get_ref();
-            let status = status_to_maybe_uv_error(status);
+            let status = status_to_maybe_uv_error(idle_watcher, status);
             (*cb)(idle_watcher, status);
         }
     }
index 700b80c7398b53675416cb92cbbc8a168c6d9b57..75b9a5ac553e8eff77d5d096730081f2e12cd902 100644 (file)
@@ -58,8 +58,6 @@
 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;
@@ -72,8 +70,6 @@
 pub mod idle;
 pub mod timer;
 pub mod async;
-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,
@@ -130,8 +126,6 @@ fn native_handle(&self) -> *uvll::uv_loop_t {
 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>);
@@ -149,8 +143,7 @@ struct WatcherData {
     timer_cb: Option<TimerCallback>,
     async_cb: Option<AsyncCallback>,
     udp_recv_cb: Option<UdpReceiveCallback>,
-    udp_send_cb: Option<UdpSendCallback>,
-    exit_cb: Option<ExitCallback>,
+    udp_send_cb: Option<UdpSendCallback>
 }
 
 pub trait WatcherInterop {
@@ -182,8 +175,7 @@ fn install_watcher_data(&mut self) {
                 timer_cb: None,
                 async_cb: None,
                 udp_recv_cb: None,
-                udp_send_cb: None,
-                exit_cb: None,
+                udp_send_cb: None
             };
             let data = transmute::<~WatcherData, *c_void>(data);
             uvll::set_data_for_uv_handle(self.native_handle(), data);
@@ -210,12 +202,12 @@ fn drop_watcher_data(&mut self) {
 // XXX: Need to define the error constants like EOF so they can be
 // compared to the UvError type
 
-pub struct UvError(c_int);
+pub struct UvError(uvll::uv_err_t);
 
 impl UvError {
     pub fn name(&self) -> ~str {
         unsafe {
-            let inner = match self { &UvError(a) => a };
+            let inner = match self { &UvError(ref a) => a };
             let name_str = uvll::err_name(inner);
             assert!(name_str.is_not_null());
             from_c_str(name_str)
@@ -224,7 +216,7 @@ pub fn name(&self) -> ~str {
 
     pub fn desc(&self) -> ~str {
         unsafe {
-            let inner = match self { &UvError(a) => a };
+            let inner = match self { &UvError(ref a) => a };
             let desc_str = uvll::strerror(inner);
             assert!(desc_str.is_not_null());
             from_c_str(desc_str)
@@ -232,7 +224,7 @@ pub fn desc(&self) -> ~str {
     }
 
     pub fn is_eof(&self) -> bool {
-        **self == uvll::EOF
+        self.code == uvll::EOF
     }
 }
 
@@ -244,10 +236,18 @@ fn to_str(&self) -> ~str {
 
 #[test]
 fn error_smoke_test() {
-    let err: UvError = UvError(uvll::EOF);
+    let err = uvll::uv_err_t { code: 1, sys_errno_: 1 };
+    let err: UvError = UvError(err);
     assert_eq!(err.to_str(), ~"EOF: end of file");
 }
 
+pub fn last_uv_error<H, W: Watcher + NativeHandle<*H>>(watcher: &W) -> UvError {
+    unsafe {
+        let loop_ = watcher.event_loop();
+        UvError(uvll::last_error(loop_.native_handle()))
+    }
+}
+
 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
     unsafe {
         // Importing error constants
@@ -255,10 +255,10 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
         use rt::io::*;
 
         // uv error descriptions are static
-        let c_desc = uvll::strerror(*uverr);
+        let c_desc = uvll::strerror(&*uverr);
         let desc = str::raw::c_str_to_static_slice(c_desc);
 
-        let kind = match *uverr {
+        let kind = match uverr.code {
             UNKNOWN => OtherIoError,
             OK => OtherIoError,
             EOF => EndOfFile,
@@ -266,8 +266,8 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
             ECONNREFUSED => ConnectionRefused,
             ECONNRESET => ConnectionReset,
             EPIPE => BrokenPipe,
-            err => {
-                rtdebug!("uverr.code %d", err as int);
+            _ => {
+                rtdebug!("uverr.code %u", uverr.code as uint);
                 // XXX: Need to map remaining uv error types
                 OtherIoError
             }
@@ -281,12 +281,31 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
     }
 }
 
-/// Convert a callback status to a UvError
-pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
-    if status >= 0 {
+/// Given a uv handle, convert a callback status to a UvError
+pub fn status_to_maybe_uv_error_with_loop(
+    loop_: *uvll::uv_loop_t,
+    status: c_int) -> Option<UvError> {
+    if status != -1 {
+        None
+    } else {
+        unsafe {
+            rtdebug!("loop: %x", loop_ as uint);
+            let err = uvll::last_error(loop_);
+            Some(UvError(err))
+        }
+    }
+}
+/// Given a uv handle, convert a callback status to a UvError
+pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
+                                                                 status: c_int) -> Option<UvError> {
+    if status != -1 {
         None
     } else {
-        Some(UvError(status))
+        unsafe {
+            rtdebug!("handle: %x", handle.native_handle() as uint);
+            let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle());
+            status_to_maybe_uv_error_with_loop(loop_, status)
+        }
     }
 }
 
index 1581b0170878fb0f7276c732860d7e6e2ef65df1..3ff6e90e32d2998c25fd96fc65136a8a83135a76 100644 (file)
@@ -16,6 +16,7 @@
 use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback,
              status_to_maybe_uv_error};
 use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
+use rt::uv::last_uv_error;
 use vec;
 use str;
 use from_str::{FromStr};
@@ -136,7 +137,7 @@ pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) {
             rtdebug!("buf len: %d", buf.len as int);
             let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
             let cb = stream_watcher.get_watcher_data().read_cb.get_ref();
-            let status = status_to_maybe_uv_error(nread as c_int);
+            let status = status_to_maybe_uv_error(stream_watcher, nread as c_int);
             (*cb)(stream_watcher, nread as int, buf, status);
         }
     }
@@ -166,7 +167,7 @@ pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) {
             let mut stream_watcher = write_request.stream();
             write_request.delete();
             let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap();
-            let status = status_to_maybe_uv_error(status);
+            let status = status_to_maybe_uv_error(stream_watcher, status);
             cb(stream_watcher, status);
         }
     }
@@ -231,7 +232,7 @@ pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
             };
             match result {
                 0 => Ok(()),
-                _ => Err(UvError(result)),
+                _ => Err(last_uv_error(self)),
             }
         }
     }
@@ -259,7 +260,7 @@ pub fn connect(&mut self, address: SocketAddr, cb: ConnectionCallback) {
                 let mut stream_watcher = connect_request.stream();
                 connect_request.delete();
                 let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
-                let status = status_to_maybe_uv_error(status);
+                let status = status_to_maybe_uv_error(stream_watcher, status);
                 cb(stream_watcher, status);
             }
         }
@@ -282,7 +283,7 @@ pub fn listen(&mut self, cb: ConnectionCallback) {
             rtdebug!("connection_cb");
             let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
             let cb = stream_watcher.get_watcher_data().connect_cb.get_ref();
-            let status = status_to_maybe_uv_error(status);
+            let status = status_to_maybe_uv_error(stream_watcher, status);
             (*cb)(stream_watcher, status);
         }
     }
@@ -326,7 +327,7 @@ pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
             };
             match result {
                 0 => Ok(()),
-                _ => Err(UvError(result)),
+                _ => Err(last_uv_error(self)),
             }
         }
     }
@@ -359,7 +360,7 @@ pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) {
             rtdebug!("buf len: %d", buf.len as int);
             let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
             let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref();
-            let status = status_to_maybe_uv_error(nread as c_int);
+            let status = status_to_maybe_uv_error(udp_watcher, nread as c_int);
             let addr = uv_socket_addr_to_socket_addr(sockaddr_to_UvSocketAddr(addr));
             (*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status);
         }
@@ -394,7 +395,7 @@ pub fn send(&mut self, buf: Buf, address: SocketAddr, cb: UdpSendCallback) {
             let mut udp_watcher = send_request.handle();
             send_request.delete();
             let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap();
-            let status = status_to_maybe_uv_error(status);
+            let status = status_to_maybe_uv_error(udp_watcher, status);
             cb(udp_watcher, status);
         }
     }
@@ -600,6 +601,7 @@ fn udp_bind_close_ip6() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8815
     fn listen_ip4() {
         do run_in_bare_thread() {
             static MAX: int = 10;
@@ -674,6 +676,7 @@ fn listen_ip4() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8815
     fn listen_ip6() {
         do run_in_bare_thread() {
             static MAX: int = 10;
@@ -750,6 +753,7 @@ fn listen_ip6() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8815
     fn udp_recv_ip4() {
         do run_in_bare_thread() {
             static MAX: int = 10;
@@ -810,6 +814,7 @@ fn udp_recv_ip4() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8815
     fn udp_recv_ip6() {
         do run_in_bare_thread() {
             static MAX: int = 10;
diff --git a/src/libstd/rt/uv/pipe.rs b/src/libstd/rt/uv/pipe.rs
deleted file mode 100644 (file)
index 1147c73..0000000
+++ /dev/null
@@ -1,66 +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.
-
-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
deleted file mode 100644 (file)
index a02cf67..0000000
+++ /dev/null
@@ -1,264 +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.
-
-use prelude::*;
-use libc;
-use ptr;
-use vec;
-use cell::Cell;
-
-use rt::uv;
-use rt::uv::net;
-use rt::uv::pipe;
-use rt::uv::uvll;
-
-/// A process wraps the handle of the underlying uv_process_t.
-pub struct Process(*uvll::uv_process_t);
-
-/// This configuration describes how a new process should be spawned. This is
-/// translated to libuv's own configuration
-pub struct Config<'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: &'self [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),
-
-    /// The specified libuv stream is inherited for the corresponding file
-    /// descriptor it is assigned to.
-    InheritStream(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(pipe::Pipe, bool /* readable */, bool /* writable */),
-}
-
-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, config: &Config,
-                 exit_cb: uv::ExitCallback) -> Result<(), 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 mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(
-                                config.io.len());
-        unsafe {
-            vec::raw::set_len(&mut stdio, config.io.len());
-            for (slot, &other) in stdio.iter().zip(config.io.iter()) {
-                set_stdio(slot as *uvll::uv_stdio_container_t, other);
-            }
-        }
-
-        let exit_cb = Cell::new(exit_cb);
-        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(())
-                    }
-                    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) {
-    match io {
-        Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); }
-        InheritFd(fd) => {
-            uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
-            uvll::set_stdio_container_fd(dst, fd);
-        }
-        InheritStream(stream) => {
-            uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_STREAM);
-            uvll::set_stdio_container_stream(dst, stream.native_handle());
-        }
-        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;
-            }
-            uvll::set_stdio_container_flags(dst, flags);
-            uvll::set_stdio_container_stream(dst,
-                                             pipe.as_stream().native_handle());
-        }
-    }
-}
-
-/// 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 }
-    }
-}
index 7b09cf2eb0e3ab058f4c2cf2d65526585964e758..eaa5e77a6da2fe71b3a67a11105dc5acee18c4f5 100644 (file)
@@ -43,7 +43,7 @@ pub fn start(&mut self, timeout: u64, repeat: u64, cb: TimerCallback) {
             let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
             let data = watcher.get_watcher_data();
             let cb = data.timer_cb.get_ref();
-            let status = status_to_maybe_uv_error(status);
+            let status = status_to_maybe_uv_error(watcher, status);
             (*cb)(watcher, status);
         }
     }
index c771f93cef5e0de13b9b80e62b47fad4411662c2..f282432dcb5063cfd5c665acda282e6c417c3310 100644 (file)
@@ -13,7 +13,7 @@
 use cast;
 use cell::Cell;
 use clone::Clone;
-use libc::{c_int, c_uint, c_void, pid_t};
+use libc::{c_int, c_uint, c_void};
 use ops::Drop;
 use option::*;
 use ptr;
@@ -22,7 +22,6 @@
 use rt::io::IoError;
 use rt::io::net::ip::{SocketAddr, IpAddr};
 use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd};
-use rt::kill::BlockedTask;
 use rt::local::Local;
 use rt::rtio::*;
 use rt::sched::{Scheduler, SchedHandle};
@@ -149,7 +148,7 @@ fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
     };
 
     if r != 0 {
-        let status = status_to_maybe_uv_error(r);
+        let status = status_to_maybe_uv_error(handle, r);
         return Err(uv_error_to_io_error(status.unwrap()));
     }
 
@@ -592,63 +591,6 @@ fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
         assert!(!result_cell.is_empty());
         return result_cell.take();
     }
-
-    fn pipe_init(&mut self, ipc: bool) -> Result<~RtioPipeObject, IoError> {
-        let home = get_handle_to_current_scheduler!();
-        Ok(~UvPipeStream { pipe: Pipe::new(self.uv_loop(), ipc), home: home })
-    }
-
-    fn spawn(&mut self,
-             config: &process::Config) -> Result<~RtioProcessObject, 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(()) => {
-                // Only now do we actually get a handle to this scheduler.
-                ret.home = Some(get_handle_to_current_scheduler!());
-                Ok(ret)
-            }
-            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 {
@@ -737,7 +679,7 @@ fn accept_simultaneously(&mut self) -> Result<(), IoError> {
                 uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 1 as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher(), r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -750,7 +692,7 @@ fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
                 uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 0 as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher(), r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -758,15 +700,40 @@ fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
     }
 }
 
-trait UvStream: HomingIO {
-    fn as_stream(&mut self) -> StreamWatcher;
+pub struct UvTcpStream {
+    watcher: TcpWatcher,
+    home: SchedHandle,
+}
+
+impl HomingIO for UvTcpStream {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
 }
 
-// FIXME(#3429) I would rather this be `impl<T: UvStream> RtioStream for T` but
-//              that has conflicts with other traits that also have methods
-//              called `read` and `write`
-macro_rules! rtiostream(($t:ident) => {
-impl RtioStream for $t {
+impl Drop for UvTcpStream {
+    fn drop(&self) {
+        // XXX need mutable finalizer
+        let this = unsafe { transmute::<&UvTcpStream, &mut UvTcpStream>(self) };
+        do this.home_for_io_with_sched |self_, scheduler| {
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task_cell = Cell::new(task);
+                do self_.watcher.as_stream().close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task_cell.take());
+                }
+            }
+        }
+    }
+}
+
+impl RtioSocket for UvTcpStream {
+    fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
+        do self.home_for_io |self_| {
+            socket_name(Tcp, self_.watcher)
+        }
+    }
+}
+
+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();
@@ -780,7 +747,7 @@ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
                 let alloc: AllocCallback = |_| unsafe {
                     slice_to_uv_buf(*buf_ptr)
                 };
-                let mut watcher = self_.as_stream();
+                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
@@ -816,7 +783,7 @@ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
             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_.as_stream();
+                let mut watcher = self_.watcher.as_stream();
                 do watcher.write(buf) |_watcher, status| {
                     let result = if status.is_none() {
                         Ok(())
@@ -835,85 +802,7 @@ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
             result_cell.take()
         }
     }
-}
-})
-
-rtiostream!(UvPipeStream)
-rtiostream!(UvTcpStream)
-
-pub struct UvPipeStream {
-    pipe: Pipe,
-    home: SchedHandle,
-}
-
-impl UvStream for UvPipeStream {
-    fn as_stream(&mut self) -> StreamWatcher { self.pipe.as_stream() }
-}
-
-impl HomingIO for UvPipeStream {
-    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvPipeStream {
-    fn drop(&self) {
-        // FIXME(#4330): should not need a transmute
-        let this = unsafe { cast::transmute_mut(self) };
-        do this.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 UvPipeStream {
-    pub fn uv_pipe(&self) -> Pipe { self.pipe }
-}
 
-pub struct UvTcpStream {
-    watcher: TcpWatcher,
-    home: SchedHandle,
-}
-
-impl HomingIO for UvTcpStream {
-    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvTcpStream {
-    fn drop(&self) {
-        // FIXME(#4330): should not need a transmute
-        let this = unsafe { cast::transmute_mut(self) };
-        do this.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_.watcher.as_stream().close {
-                    let scheduler: ~Scheduler = Local::take();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                }
-            }
-        }
-    }
-}
-
-impl UvStream for UvTcpStream {
-    fn as_stream(&mut self) -> StreamWatcher { self.watcher.as_stream() }
-}
-
-impl RtioSocket for UvTcpStream {
-    fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
-        do self.home_for_io |self_| {
-            socket_name(Tcp, self_.watcher)
-        }
-    }
-}
-
-impl RtioTcpStream for UvTcpStream {
     fn peer_name(&mut self) -> Result<SocketAddr, IoError> {
         do self.home_for_io |self_| {
             socket_name(TcpPeer, self_.watcher)
@@ -924,7 +813,7 @@ fn control_congestion(&mut self) -> Result<(), IoError> {
         do self.home_for_io |self_| {
             let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 0 as c_int) };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -935,7 +824,7 @@ fn nodelay(&mut self) -> Result<(), IoError> {
         do self.home_for_io |self_| {
             let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 1 as c_int) };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -949,7 +838,7 @@ fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
                                     delay_in_seconds as c_uint)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -962,7 +851,7 @@ fn letdie(&mut self) -> Result<(), IoError> {
                 uvll::tcp_keepalive(self_.watcher.native_handle(), 0 as c_int, 0 as c_uint)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1074,7 +963,7 @@ fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
                 }
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1090,7 +979,7 @@ fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
                 }
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1104,7 +993,7 @@ fn loop_multicast_locally(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 1 as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1118,7 +1007,7 @@ fn dont_loop_multicast_locally(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 0 as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1132,7 +1021,7 @@ fn multicast_time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
                 uvll::udp_set_multicast_ttl(self_.watcher.native_handle(), ttl as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1146,7 +1035,7 @@ fn time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
                 uvll::udp_set_ttl(self_.watcher.native_handle(), ttl as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1160,7 +1049,7 @@ fn hear_broadcasts(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_broadcast(self_.watcher.native_handle(), 1 as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1174,7 +1063,7 @@ fn ignore_broadcasts(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_broadcast(self_.watcher.native_handle(), 0 as c_int)
             };
 
-            match status_to_maybe_uv_error(r) {
+            match status_to_maybe_uv_error(self_.watcher, r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1361,89 +1250,6 @@ fn flush(&mut self) -> Result<(), IoError> {
     }
 }
 
-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(&self) {
-        // FIXME(#4330): should not need a transmute
-        let this = unsafe { cast::transmute_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 this.home.is_none() {
-            close(this)
-        } else {
-            this.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_newsched_task {
@@ -1860,6 +1666,7 @@ fn test_read_read_read() {
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8816
 fn test_udp_twice() {
     do run_in_newsched_task {
         let server_addr = next_test_ip4();
@@ -1994,6 +1801,7 @@ fn file_test_uvio_full_simple_impl() {
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8816
 fn file_test_uvio_full_simple() {
     do run_in_newsched_task {
         file_test_uvio_full_simple_impl();
index 24e070ca239d1bfbc855dfb799fae2c08dffabaa..d2e3b4176f96150dc443248e10d44bd6ba0e8f33 100644 (file)
 use libc;
 use prelude::*;
 use ptr;
+use str;
 use vec;
 
-pub use self::errors::*;
-
+pub static UNKNOWN: c_int = -1;
 pub static OK: c_int = 0;
-pub static EOF: c_int = -4095;
-pub static UNKNOWN: c_int = -4094;
-
-// uv-errno.h redefines error codes for windows, but not for unix...
-
-#[cfg(windows)]
-pub mod errors {
-    use libc::c_int;
+pub static EOF: c_int = 1;
+pub static EADDRINFO: c_int = 2;
+pub static EACCES: c_int = 3;
+pub static ECONNREFUSED: c_int = 12;
+pub static ECONNRESET: c_int = 13;
+pub static EPIPE: c_int = 36;
 
-    pub static EACCES: c_int = -4093;
-    pub static ECONNREFUSED: c_int = -4079;
-    pub static ECONNRESET: c_int = -4078;
-    pub static EPIPE: c_int = -4048;
+pub struct uv_err_t {
+    code: c_int,
+    sys_errno_: c_int
 }
-#[cfg(not(windows))]
-pub mod errors {
-    use libc;
-    use libc::c_int;
-
-    pub static EACCES: c_int = -libc::EACCES;
-    pub static ECONNREFUSED: c_int = -libc::ECONNREFUSED;
-    pub static ECONNRESET: c_int = -libc::ECONNRESET;
-    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;
 
 pub struct uv_buf_t {
     base: *u8,
     len: libc::size_t,
 }
 
-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;
@@ -118,8 +72,6 @@ pub struct uv_stdio_container_t {
 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_process_t = c_void;
-pub type uv_pipe_t = c_void;
 
 #[cfg(stage0)]
 pub type uv_idle_cb = *u8;
@@ -145,8 +97,6 @@ pub struct uv_stdio_container_t {
 pub type uv_timer_cb = *u8;
 #[cfg(stage0)]
 pub type uv_write_cb = *u8;
-#[cfg(stage0)]
-pub type uv_exit_cb = *u8;
 
 #[cfg(not(stage0))]
 pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
@@ -187,21 +137,12 @@ pub struct uv_stdio_container_t {
 #[cfg(not(stage0))]
 pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
                                      status: c_int);
-#[cfg(not(stage0))]
-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;
 pub type sockaddr_in6 = c_void;
 pub type sockaddr_storage = c_void;
 
-#[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,
@@ -286,6 +227,7 @@ fn handle_sanity_check() {
 }
 
 #[test]
+#[ignore(cfg(windows))] // FIXME #8817
 #[fixed_stack_segment]
 #[inline(never)]
 fn request_sanity_check() {
@@ -546,12 +488,20 @@ pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
     return rust_uv_read_stop(stream as *c_void);
 }
 
-pub unsafe fn strerror(err: c_int) -> *c_char {
+pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
     #[fixed_stack_segment]; #[inline(never)];
+
+    return rust_uv_last_error(loop_handle);
+}
+
+pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_strerror(err);
 }
-pub unsafe fn err_name(err: c_int) -> *c_char {
+pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
     #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_err_name(err);
 }
 
@@ -705,45 +655,6 @@ 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)];
@@ -810,6 +721,22 @@ pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
 
     return rust_uv_get_len_from_buf(buf);
 }
+pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
+    let err = last_error(uv_loop);
+    let err_ptr = ptr::to_unsafe_ptr(&err);
+    let err_name = str::raw::from_c_str(err_name(err_ptr));
+    let err_msg = str::raw::from_c_str(strerror(err_ptr));
+    return fmt!("LIBUV ERROR: name: %s msg: %s",
+                    err_name, err_msg);
+}
+
+pub unsafe fn get_last_err_data(uv_loop: *c_void) -> uv_err_data {
+    let err = last_error(uv_loop);
+    let err_ptr = ptr::to_unsafe_ptr(&err);
+    let err_name = str::raw::from_c_str(err_name(err_ptr));
+    let err_msg = str::raw::from_c_str(strerror(err_ptr));
+    uv_err_data { err_name: err_name, err_msg: err_msg }
+}
 
 pub struct uv_err_data {
     err_name: ~str,
@@ -842,8 +769,9 @@ fn rust_uv_async_init(loop_handle: *c_void,
                           cb: uv_async_cb) -> c_int;
     fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int;
     fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t);
-    fn rust_uv_strerror(err: c_int) -> *c_char;
-    fn rust_uv_err_name(err: c_int) -> *c_char;
+    fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t;
+    fn rust_uv_strerror(err: *uv_err_t) -> *c_char;
+    fn rust_uv_err_name(err: *uv_err_t) -> *c_char;
     fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in;
     fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6;
     fn rust_uv_free_ip4_addr(addr: *sockaddr_in);
@@ -929,13 +857,4 @@ fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
     fn rust_uv_set_data_for_req(req: *c_void, data: *c_void);
     fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
     fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t;
-    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;
 }
index b91aac2224401a532dcd9f54afda9ceb7f8a144f..7fc2deff97d8bd34538c1d3c4a236c05dcba0c03 100644 (file)
 
 //! Process spawning.
 
+#[allow(missing_doc)];
+
+use c_str::ToCStr;
 use cast;
-use cell::Cell;
+use clone::Clone;
 use comm::{stream, SharedChan, GenericChan, GenericPort};
-#[cfg(not(windows))]
+use io;
+use libc::{pid_t, c_void, c_int};
 use libc;
-use libc::{pid_t, c_int};
+use option::{Some, None};
+use os;
 use prelude::*;
+use ptr;
 use task;
 use vec::ImmutableVector;
 
-use rt::io;
-use rt::local::Local;
-use rt::rtio::{IoFactoryObject, RtioProcessObject, RtioProcess, IoFactory};
-use rt::uv::process;
-
 /**
  * A value representing a child process.
  *
  * for the process to terminate.
  */
 pub struct Process {
+
     /// The unique id of the process (this should never be negative).
     priv pid: pid_t,
 
-    /// The internal handle to the underlying libuv process.
-    priv handle: ~RtioProcessObject,
+    /**
+     * A handle to the process - on unix this will always be NULL, but on
+     * windows it will be a HANDLE to the process, which will prevent the
+     * pid being re-used until the handle is closed.
+     */
+    priv handle: *(),
 
-    /// Some(fd), or None when stdin is being redirected from a fd not created
-    /// by Process::new.
-    priv input: Option<~io::Writer>,
+    /// Some(fd), or None when stdin is being redirected from a fd not created by Process::new.
+    priv input: Option<c_int>,
 
-    /// Some(file), or None when stdout is being redirected to a fd not created
-    /// by Process::new.
-    priv output: Option<~io::Reader>,
+    /// Some(file), or None when stdout is being redirected to a fd not created by Process::new.
+    priv output: Option<*libc::FILE>,
 
-    /// Some(file), or None when stderr is being redirected to a fd not created
-    /// by Process::new.
-    priv error: Option<~io::Reader>,
+    /// Some(file), or None when stderr is being redirected to a fd not created by Process::new.
+    priv error: Option<*libc::FILE>,
+
+    /// None until finish() is called.
+    priv exit_code: Option<int>,
 }
 
 /// Options that can be given when starting a Process.
@@ -87,27 +93,26 @@ pub struct ProcessOptions<'self> {
      * If this is None then a new pipe will be created for the new program's
      * output and Process.output() will provide a Reader to read from this pipe.
      *
-     * If this is Some(file-descriptor) then the new process will write its
-     * output to the given file descriptor, Process.output_redirected() will
-     * return true, and Process.output() will fail.
+     * If this is Some(file-descriptor) then the new process will write its output
+     * to the given file descriptor, Process.output_redirected() will return
+     * true, and Process.output() will fail.
      */
     out_fd: Option<c_int>,
 
     /**
-     * If this is None then a new pipe will be created for the new progam's
-     * error stream and Process.error() will provide a Reader to read from this
-     * pipe.
+     * If this is None then a new pipe will be created for the new program's
+     * error stream and Process.error() will provide a Reader to read from this pipe.
      *
-     * If this is Some(file-descriptor) then the new process will write its
-     * error output to the given file descriptor, Process.error_redirected()
-     * will return true, and and Process.error() will fail.
+     * If this is Some(file-descriptor) then the new process will write its error output
+     * to the given file descriptor, Process.error_redirected() will return true, and
+     * and Process.error() will fail.
      */
     err_fd: Option<c_int>,
 }
 
-impl<'self> ProcessOptions<'self> {
+impl <'self> ProcessOptions<'self> {
     /// Return a ProcessOptions that has None in every field.
-    pub fn new() -> ProcessOptions {
+    pub fn new<'a>() -> ProcessOptions<'a> {
         ProcessOptions {
             env: None,
             dir: None,
@@ -120,6 +125,7 @@ pub fn new() -> ProcessOptions {
 
 /// The output of a finished process.
 pub struct ProcessOutput {
+
     /// The status (exit code) of the process.
     status: int,
 
@@ -142,159 +148,223 @@ impl Process {
      *             the working directory and the standard IO streams.
      */
     pub fn new(prog: &str, args: &[~str],
-               options: ProcessOptions) -> Option<Process> {
-        // First, translate all the stdio options into their libuv equivalents
-        let (uv_stdin, stdin) = match options.in_fd {
-            Some(fd) => (process::InheritFd(fd), None),
+               options: ProcessOptions)
+               -> Process {
+        #[fixed_stack_segment]; #[inline(never)];
+
+        let (in_pipe, in_fd) = match options.in_fd {
             None => {
-                let p = io::pipe::PipeStream::new().expect("need stdin pipe");
-                (process::CreatePipe(p.uv_pipe(), true, false),
-                 Some(~p as ~io::Writer))
-            }
+                let pipe = os::pipe();
+                (Some(pipe), pipe.input)
+            },
+            Some(fd) => (None, fd)
         };
-        let (uv_stdout, stdout) = match options.out_fd {
-            Some(fd) => (process::InheritFd(fd), None),
+        let (out_pipe, out_fd) = match options.out_fd {
             None => {
-                let p = io::pipe::PipeStream::new().expect("need stdout pipe");
-                (process::CreatePipe(p.uv_pipe(), false, true),
-                 Some(~p as ~io::Reader))
-            }
+                let pipe = os::pipe();
+                (Some(pipe), pipe.out)
+            },
+            Some(fd) => (None, fd)
         };
-        let (uv_stderr, stderr) = match options.err_fd {
-            Some(fd) => (process::InheritFd(fd), None),
+        let (err_pipe, err_fd) = match options.err_fd {
             None => {
-                let p = io::pipe::PipeStream::new().expect("need stderr pipe");
-                (process::CreatePipe(p.uv_pipe(), false, true),
-                 Some(~p as ~io::Reader))
-            }
+                let pipe = os::pipe();
+                (Some(pipe), pipe.out)
+            },
+            Some(fd) => (None, fd)
         };
 
-        // Next, massage our options into the libuv options
-        let dir = options.dir.map(|d| d.to_str());
-        let dir = dir.map(|d| d.as_slice());
-        let config = process::Config {
-            program: prog,
-            args: args,
-            env: options.env.map(|e| e.as_slice()),
-            cwd: dir,
-            io: [uv_stdin, uv_stdout, uv_stderr],
-        };
+        let res = spawn_process_os(prog, args, options.env.clone(), options.dir,
+                                   in_fd, out_fd, err_fd);
 
-        // Finally, actually spawn the process
         unsafe {
-            let io: *mut IoFactoryObject = Local::unsafe_borrow();
-            match (*io).spawn(&config) {
-                Ok(handle) => {
-                    Some(Process {
-                        pid: handle.id(),
-                        handle: handle,
-                        input: stdin,
-                        output: stdout,
-                        error: stderr,
-                    })
-                }
-                Err(*) => { None }
-            }
+            for pipe in in_pipe.iter() { libc::close(pipe.input); }
+            for pipe in out_pipe.iter() { libc::close(pipe.out); }
+            for pipe in err_pipe.iter() { libc::close(pipe.out); }
+        }
+
+        Process {
+            pid: res.pid,
+            handle: res.handle,
+            input: in_pipe.map(|pipe| pipe.out),
+            output: out_pipe.map(|pipe| os::fdopen(pipe.input)),
+            error: err_pipe.map(|pipe| os::fdopen(pipe.input)),
+            exit_code: None,
         }
     }
 
     /// Returns the unique id of the process
     pub fn get_id(&self) -> pid_t { self.pid }
 
+    fn input_fd(&mut self) -> c_int {
+        match self.input {
+            Some(fd) => fd,
+            None => fail!("This Process's stdin was redirected to an \
+                           existing file descriptor.")
+        }
+    }
+
+    fn output_file(&mut self) -> *libc::FILE {
+        match self.output {
+            Some(file) => file,
+            None => fail!("This Process's stdout was redirected to an \
+                           existing file descriptor.")
+        }
+    }
+
+    fn error_file(&mut self) -> *libc::FILE {
+        match self.error {
+            Some(file) => file,
+            None => fail!("This Process's stderr was redirected to an \
+                           existing file descriptor.")
+        }
+    }
+
     /**
-     * Returns a rt::io::Writer that can be used to write to this Process's
-     * stdin.
+     * Returns whether this process is reading its stdin from an existing file
+     * descriptor rather than a pipe that was created specifically for this
+     * process.
      *
-     * Fails if this Process's stdin was redirected to an existing file
-     * descriptor.
+     * If this method returns true then self.input() will fail.
      */
-    pub fn input<'a>(&'a mut self) -> &'a mut io::Writer {
-        let ret: &mut io::Writer = *self.input.get_mut_ref();
-        return ret;
+    pub fn input_redirected(&self) -> bool {
+        self.input.is_none()
     }
 
     /**
-     * Returns a rt::io::Reader that can be used to read from this Process's
-     * stdout.
+     * Returns whether this process is writing its stdout to an existing file
+     * descriptor rather than a pipe that was created specifically for this
+     * process.
      *
-     * Fails if this Process's stdout was redirected to an existing file
-     * descriptor.
+     * If this method returns true then self.output() will fail.
      */
-    pub fn output<'a>(&'a mut self) -> &'a mut io::Reader {
-        let ret: &mut io::Reader = *self.output.get_mut_ref();
-        return ret;
+    pub fn output_redirected(&self) -> bool {
+        self.output.is_none()
     }
 
     /**
-     * Returns a rt::io::Reader that can be used to read from this Process's
-     * stderr.
+     * Returns whether this process is writing its stderr to an existing file
+     * descriptor rather than a pipe that was created specifically for this
+     * process.
      *
-     * Fails if this Process's stderr was redirected to an existing file
-     * descriptor.
+     * If this method returns true then self.error() will fail.
      */
-    pub fn error<'a>(&'a mut self) -> &'a mut io::Reader {
-        let ret: &mut io::Reader = *self.error.get_mut_ref();
-        return ret;
+    pub fn error_redirected(&self) -> bool {
+        self.error.is_none()
     }
 
     /**
-     * Closes the handle to stdin, waits for the child process to terminate, and
-     * returns the exit code.
+     * Returns an io::Writer that can be used to write to this Process's stdin.
      *
-     * If the child has already been finished then the exit code is returned.
+     * Fails if this Process's stdin was redirected to an existing file descriptor.
      */
-    pub fn finish(&mut self) -> int {
-        // We're not going to be giving any more input, so close the input by
-        // destroying it. Also, if the output is desired, then
-        // finish_with_output is called so we discard all the outputs here. Note
-        // that the process may not terminate if we don't destroy stdio because
-        // it'll be waiting in a write which we'll just never read.
-        self.input.take();
-        self.output.take();
-        self.error.take();
+    pub fn input(&mut self) -> @io::Writer {
+        // FIXME: the Writer can still be used after self is destroyed: #2625
+       io::fd_writer(self.input_fd(), false)
+    }
 
-        self.handle.wait()
+    /**
+     * Returns an io::Reader that can be used to read from this Process's stdout.
+     *
+     * Fails if this Process's stdout was redirected to an existing file descriptor.
+     */
+    pub fn output(&mut self) -> @io::Reader {
+        // FIXME: the Reader can still be used after self is destroyed: #2625
+        io::FILE_reader(self.output_file(), false)
     }
 
     /**
-     * Closes the handle to stdin, waits for the child process to terminate,
-     * and reads and returns all remaining output of stdout and stderr, along
-     * with the exit code.
+     * Returns an io::Reader that can be used to read from this Process's stderr.
      *
-     * If the child has already been finished then the exit code and any
-     * remaining unread output of stdout and stderr will be returned.
+     * Fails if this Process's stderr was redirected to an existing file descriptor.
+     */
+    pub fn error(&mut self) -> @io::Reader {
+        // FIXME: the Reader can still be used after self is destroyed: #2625
+        io::FILE_reader(self.error_file(), false)
+    }
+
+    /**
+     * Closes the handle to the child process's stdin.
      *
-     * This method will fail if the child process's stdout or stderr streams
-     * were redirected to existing file descriptors, or if this method has
-     * already been called.
+     * If this process is reading its stdin from an existing file descriptor, then this
+     * method does nothing.
      */
-    pub fn finish_with_output(&mut self) -> ProcessOutput {
-        // This should probably be a helper method in rt::io
-        fn read_everything(input: &mut io::Reader) -> ~[u8] {
-            let mut result = ~[];
-            let mut buf = [0u8, ..1024];
-            loop {
-                match input.read(buf) {
-                    Some(i) => { result = result + buf.slice_to(i) }
-                    None => break
+    pub fn close_input(&mut self) {
+        #[fixed_stack_segment]; #[inline(never)];
+        match self.input {
+            Some(-1) | None => (),
+            Some(fd) => {
+                unsafe {
+                    libc::close(fd);
                 }
+                self.input = Some(-1);
             }
-            return result;
         }
+    }
+
+    fn close_outputs(&mut self) {
+        #[fixed_stack_segment]; #[inline(never)];
+        fclose_and_null(&mut self.output);
+        fclose_and_null(&mut self.error);
+
+        fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
+            #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
+            match *f_opt {
+                Some(f) if !f.is_null() => {
+                    unsafe {
+                        libc::fclose(f);
+                        *f_opt = Some(0 as *libc::FILE);
+                    }
+                },
+                _ => ()
+            }
+        }
+    }
+
+    /**
+     * Closes the handle to stdin, waits for the child process to terminate,
+     * and returns the exit code.
+     *
+     * If the child has already been finished then the exit code is returned.
+     */
+    pub fn finish(&mut self) -> int {
+        for &code in self.exit_code.iter() {
+            return code;
+        }
+        self.close_input();
+        let code = waitpid(self.pid);
+        self.exit_code = Some(code);
+        return code;
+    }
 
+    /**
+     * Closes the handle to stdin, waits for the child process to terminate, and reads
+     * and returns all remaining output of stdout and stderr, along with the exit code.
+     *
+     * If the child has already been finished then the exit code and any remaining
+     * unread output of stdout and stderr will be returned.
+     *
+     * This method will fail if the child process's stdout or stderr streams were
+     * redirected to existing file descriptors.
+     */
+    pub fn finish_with_output(&mut self) -> ProcessOutput {
+        let output_file = self.output_file();
+        let error_file = self.error_file();
+
+        // Spawn two entire schedulers to read both stdout and sterr
+        // in parallel so we don't deadlock while blocking on one
+        // or the other. FIXME (#2625): Surely there's a much more
+        // clever way to do this.
         let (p, ch) = stream();
         let ch = SharedChan::new(ch);
         let ch_clone = ch.clone();
-
-        let stderr = Cell::new(self.error.take().unwrap());
-        do task::spawn {
-            let output = read_everything(stderr.take());
-            ch.send((2, output));
+        do task::spawn_sched(task::SingleThreaded) {
+            let errput = io::FILE_reader(error_file, false);
+            ch.send((2, errput.read_whole_stream()));
         }
-        let stdout = Cell::new(self.output.take().unwrap());
-        do task::spawn {
-            let output = read_everything(stdout.take());
-            ch_clone.send((1, output));
+        do task::spawn_sched(task::SingleThreaded) {
+            let output = io::FILE_reader(output_file, false);
+            ch_clone.send((1, output.read_whole_stream()));
         }
 
         let status = self.finish();
@@ -312,6 +382,40 @@ fn read_everything(input: &mut io::Reader) -> ~[u8] {
                               error: errs};
     }
 
+    fn destroy_internal(&mut self, force: bool) {
+        // if the process has finished, and therefore had waitpid called,
+        // and we kill it, then on unix we might ending up killing a
+        // newer process that happens to have the same (re-used) id
+        if self.exit_code.is_none() {
+            killpid(self.pid, force);
+            self.finish();
+        }
+
+        #[cfg(windows)]
+        fn killpid(pid: pid_t, _force: bool) {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe {
+                libc::funcs::extra::kernel32::TerminateProcess(
+                    cast::transmute(pid), 1);
+            }
+        }
+
+        #[cfg(unix)]
+        fn killpid(pid: pid_t, force: bool) {
+            #[fixed_stack_segment]; #[inline(never)];
+
+            let signal = if force {
+                libc::consts::os::posix88::SIGKILL
+            } else {
+                libc::consts::os::posix88::SIGTERM
+            };
+
+            unsafe {
+                libc::funcs::posix88::signal::kill(pid, signal as c_int);
+            }
+        }
+    }
+
     /**
      * Terminates the process, giving it a chance to clean itself up if
      * this is supported by the operating system.
@@ -319,12 +423,7 @@ fn read_everything(input: &mut io::Reader) -> ~[u8] {
      * On Posix OSs SIGTERM will be sent to the process. On Win32
      * TerminateProcess(..) will be called.
      */
-    pub fn destroy(&mut self) {
-        #[cfg(windows)]      fn sigterm() -> int { 15 }
-        #[cfg(not(windows))] fn sigterm() -> int { libc::SIGTERM as int }
-        self.handle.kill(sigterm());
-        self.finish();
-    }
+    pub fn destroy(&mut self) { self.destroy_internal(false); }
 
     /**
      * Terminates the process as soon as possible without giving it a
@@ -333,22 +432,378 @@ pub fn destroy(&mut self) {
      * On Posix OSs SIGKILL will be sent to the process. On Win32
      * TerminateProcess(..) will be called.
      */
-    pub fn force_destroy(&mut self) {
-        #[cfg(windows)]      fn sigkill() -> int { 9 }
-        #[cfg(not(windows))] fn sigkill() -> int { libc::SIGKILL as int }
-        self.handle.kill(sigkill());
-        self.finish();
-    }
+    pub fn force_destroy(&mut self) { self.destroy_internal(true); }
 }
 
 impl Drop for Process {
     fn drop(&self) {
         // FIXME(#4330) Need self by value to get mutability.
         let mut_self: &mut Process = unsafe { cast::transmute(self) };
+
         mut_self.finish();
+        mut_self.close_outputs();
+        free_handle(self.handle);
+    }
+}
+
+struct SpawnProcessResult {
+    pid: pid_t,
+    handle: *(),
+}
+
+#[cfg(windows)]
+fn spawn_process_os(prog: &str, args: &[~str],
+                    env: Option<~[(~str, ~str)]>,
+                    dir: Option<&Path>,
+                    in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
+    use libc::consts::os::extra::{
+        TRUE, FALSE,
+        STARTF_USESTDHANDLES,
+        INVALID_HANDLE_VALUE,
+        DUPLICATE_SAME_ACCESS
+    };
+    use libc::funcs::extra::kernel32::{
+        GetCurrentProcess,
+        DuplicateHandle,
+        CloseHandle,
+        CreateProcessA
+    };
+    use libc::funcs::extra::msvcrt::get_osfhandle;
+
+    use sys;
+
+    unsafe {
+
+        let mut si = zeroed_startupinfo();
+        si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
+        si.dwFlags = STARTF_USESTDHANDLES;
+
+        let cur_proc = GetCurrentProcess();
+
+        let orig_std_in = get_osfhandle(in_fd) as HANDLE;
+        if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
+            fail!("failure in get_osfhandle: %s", os::last_os_error());
+        }
+        if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
+                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+            fail!("failure in DuplicateHandle: %s", os::last_os_error());
+        }
+
+        let orig_std_out = get_osfhandle(out_fd) as HANDLE;
+        if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
+            fail!("failure in get_osfhandle: %s", os::last_os_error());
+        }
+        if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
+                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+            fail!("failure in DuplicateHandle: %s", os::last_os_error());
+        }
+
+        let orig_std_err = get_osfhandle(err_fd) as HANDLE;
+        if orig_std_err == INVALID_HANDLE_VALUE as HANDLE {
+            fail!("failure in get_osfhandle: %s", os::last_os_error());
+        }
+        if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
+                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+            fail!("failure in DuplicateHandle: %s", os::last_os_error());
+        }
+
+        let cmd = make_command_line(prog, args);
+        let mut pi = zeroed_process_information();
+        let mut create_err = None;
+
+        do with_envp(env) |envp| {
+            do with_dirp(dir) |dirp| {
+                do cmd.with_c_str |cmdp| {
+                    let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
+                                                 ptr::mut_null(), ptr::mut_null(), TRUE,
+                                                 0, envp, dirp, &mut si, &mut pi);
+                    if created == FALSE {
+                        create_err = Some(os::last_os_error());
+                    }
+                }
+            }
+        }
+
+        CloseHandle(si.hStdInput);
+        CloseHandle(si.hStdOutput);
+        CloseHandle(si.hStdError);
+
+        for msg in create_err.iter() {
+            fail!("failure in CreateProcess: %s", *msg);
+        }
+
+        // We close the thread handle because we don't care about keeping the thread id valid,
+        // and we aren't keeping the thread handle around to be able to close it later. We don't
+        // close the process handle however because we want the process id to stay valid at least
+        // until the calling code closes the process handle.
+        CloseHandle(pi.hThread);
+
+        SpawnProcessResult {
+            pid: pi.dwProcessId as pid_t,
+            handle: pi.hProcess as *()
+        }
+    }
+}
+
+#[cfg(windows)]
+fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
+    libc::types::os::arch::extra::STARTUPINFO {
+        cb: 0,
+        lpReserved: ptr::mut_null(),
+        lpDesktop: ptr::mut_null(),
+        lpTitle: ptr::mut_null(),
+        dwX: 0,
+        dwY: 0,
+        dwXSize: 0,
+        dwYSize: 0,
+        dwXCountChars: 0,
+        dwYCountCharts: 0,
+        dwFillAttribute: 0,
+        dwFlags: 0,
+        wShowWindow: 0,
+        cbReserved2: 0,
+        lpReserved2: ptr::mut_null(),
+        hStdInput: ptr::mut_null(),
+        hStdOutput: ptr::mut_null(),
+        hStdError: ptr::mut_null()
+    }
+}
+
+#[cfg(windows)]
+fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
+    libc::types::os::arch::extra::PROCESS_INFORMATION {
+        hProcess: ptr::mut_null(),
+        hThread: ptr::mut_null(),
+        dwProcessId: 0,
+        dwThreadId: 0
+    }
+}
+
+// FIXME: this is only pub so it can be tested (see issue #4536)
+#[cfg(windows)]
+pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
+    let mut cmd = ~"";
+    append_arg(&mut cmd, prog);
+    for arg in args.iter() {
+        cmd.push_char(' ');
+        append_arg(&mut cmd, *arg);
+    }
+    return cmd;
+
+    fn append_arg(cmd: &mut ~str, arg: &str) {
+        let quote = arg.iter().any(|c| c == ' ' || c == '\t');
+        if quote {
+            cmd.push_char('"');
+        }
+        for i in range(0u, arg.len()) {
+            append_char_at(cmd, arg, i);
+        }
+        if quote {
+            cmd.push_char('"');
+        }
+    }
+
+    fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
+        match arg[i] as char {
+            '"' => {
+                // Escape quotes.
+                cmd.push_str("\\\"");
+            }
+            '\\' => {
+                if backslash_run_ends_in_quote(arg, i) {
+                    // Double all backslashes that are in runs before quotes.
+                    cmd.push_str("\\\\");
+                } else {
+                    // Pass other backslashes through unescaped.
+                    cmd.push_char('\\');
+                }
+            }
+            c => {
+                cmd.push_char(c);
+            }
+        }
+    }
+
+    fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
+        while i < s.len() && s[i] as char == '\\' {
+            i += 1;
+        }
+        return i < s.len() && s[i] as char == '"';
+    }
+}
+
+#[cfg(unix)]
+fn spawn_process_os(prog: &str, args: &[~str],
+                    env: Option<~[(~str, ~str)]>,
+                    dir: Option<&Path>,
+                    in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
+    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);
+        }
+    }
+
+    unsafe {
+
+        let pid = fork();
+        if pid < 0 {
+            fail!("failure in fork: %s", os::last_os_error());
+        } else if pid > 0 {
+            return SpawnProcessResult {pid: pid, handle: ptr::null()};
+        }
+
+        rustrt::rust_unset_sigprocmask();
+
+        if dup2(in_fd, 0) == -1 {
+            fail!("failure in dup2(in_fd, 0): %s", os::last_os_error());
+        }
+        if dup2(out_fd, 1) == -1 {
+            fail!("failure in dup2(out_fd, 1): %s", os::last_os_error());
+        }
+        if dup2(err_fd, 2) == -1 {
+            fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
+        }
+        // close all other fds
+        for fd in range(3, getdtablesize()).invert() {
+            close(fd as c_int);
+        }
+
+        do with_dirp(dir) |dirp| {
+            if !dirp.is_null() && chdir(dirp) == -1 {
+                fail!("failure in chdir: %s", os::last_os_error());
+            }
+        }
+
+        do with_envp(env) |envp| {
+            if !envp.is_null() {
+                rustrt::rust_set_environ(envp);
+            }
+            do with_argv(prog, args) |argv| {
+                execvp(*argv, argv);
+                // execvp only returns if an error occurred
+                fail!("failure in execvp: %s", os::last_os_error());
+            }
+        }
+    }
+}
+
+#[cfg(unix)]
+fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
+    use vec;
+
+    // We can't directly convert `str`s into `*char`s, as someone needs to hold
+    // a reference to the intermediary byte buffers. So first build an array to
+    // hold all the ~[u8] byte strings.
+    let mut tmps = vec::with_capacity(args.len() + 1);
+
+    tmps.push(prog.to_c_str());
+
+    for arg in args.iter() {
+        tmps.push(arg.to_c_str());
+    }
+
+    // Next, convert each of the byte strings into a pointer. This is
+    // technically unsafe as the caller could leak these pointers out of our
+    // scope.
+    let mut ptrs = do tmps.map |tmp| {
+        tmp.with_ref(|buf| buf)
+    };
+
+    // Finally, make sure we add a null pointer.
+    ptrs.push(ptr::null());
+
+    ptrs.as_imm_buf(|buf, _| cb(buf))
+}
+
+#[cfg(unix)]
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
+    use vec;
+
+    // On posixy systems we can pass a char** for envp, which is a
+    // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
+    // have a temporary buffer to hold the intermediary `~[u8]` byte strings.
+    match env {
+        Some(env) => {
+            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());
+            }
+
+            // Once again, this is unsafe.
+            let mut ptrs = do tmps.map |tmp| {
+                tmp.with_ref(|buf| buf)
+            };
+            ptrs.push(ptr::null());
+
+            do ptrs.as_imm_buf |buf, _| {
+                unsafe { cb(cast::transmute(buf)) }
+            }
+        }
+        _ => cb(ptr::null())
+    }
+}
+
+#[cfg(windows)]
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
+    // On win32 we pass an "environment block" which is not a char**, but
+    // rather a concatenation of null-terminated k=v\0 sequences, with a final
+    // \0 to terminate.
+    match env {
+        Some(env) => {
+            let mut blk = ~[];
+
+            for pair in env.iter() {
+                let kv = fmt!("%s=%s", pair.first(), pair.second());
+                blk.push_all(kv.as_bytes());
+                blk.push(0);
+            }
+
+            blk.push(0);
+
+            do blk.as_imm_buf |p, _len| {
+                unsafe { cb(cast::transmute(p)) }
+            }
+        }
+        _ => cb(ptr::mut_null())
+    }
+}
+
+fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
+    match d {
+      Some(dir) => dir.with_c_str(|buf| cb(buf)),
+      None => cb(ptr::null())
+    }
+}
+
+#[cfg(windows)]
+fn free_handle(handle: *()) {
+    #[fixed_stack_segment]; #[inline(never)];
+    unsafe {
+        libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
     }
 }
 
+#[cfg(unix)]
+fn free_handle(_handle: *()) {
+    // unix has no process handle object, just a pid
+}
+
 /**
  * Spawns a process and waits for it to terminate. The process will
  * inherit the current stdin/stdout/stderr file descriptors.
@@ -369,7 +824,7 @@ pub fn process_status(prog: &str, args: &[~str]) -> int {
         in_fd: Some(0),
         out_fd: Some(1),
         err_fd: Some(2)
-    }).unwrap();
+    });
     prog.finish()
 }
 
@@ -386,38 +841,162 @@ pub fn process_status(prog: &str, args: &[~str]) -> int {
  * The process's stdout/stderr output and exit code.
  */
 pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput {
-    let mut prog = Process::new(prog, args, ProcessOptions::new()).unwrap();
+    let mut prog = Process::new(prog, args, ProcessOptions::new());
     prog.finish_with_output()
 }
 
+/**
+ * Waits for a process to exit and returns the exit code, failing
+ * if there is no process with the specified id.
+ *
+ * Note that this is private to avoid race conditions on unix where if
+ * a user calls waitpid(some_process.get_id()) then some_process.finish()
+ * and some_process.destroy() and some_process.finalize() will then either
+ * operate on a none-existent process or, even worse, on a newer process
+ * with the same id.
+ */
+fn waitpid(pid: pid_t) -> int {
+    return waitpid_os(pid);
+
+    #[cfg(windows)]
+    fn waitpid_os(pid: pid_t) -> int {
+        #[fixed_stack_segment]; #[inline(never)];
+
+        use libc::types::os::arch::extra::DWORD;
+        use libc::consts::os::extra::{
+            SYNCHRONIZE,
+            PROCESS_QUERY_INFORMATION,
+            FALSE,
+            STILL_ACTIVE,
+            INFINITE,
+            WAIT_FAILED
+        };
+        use libc::funcs::extra::kernel32::{
+            OpenProcess,
+            GetExitCodeProcess,
+            CloseHandle,
+            WaitForSingleObject
+        };
+
+        unsafe {
+
+            let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
+            if proc.is_null() {
+                fail!("failure in OpenProcess: %s", os::last_os_error());
+            }
+
+            loop {
+                let mut status = 0;
+                if GetExitCodeProcess(proc, &mut status) == FALSE {
+                    CloseHandle(proc);
+                    fail!("failure in GetExitCodeProcess: %s", os::last_os_error());
+                }
+                if status != STILL_ACTIVE {
+                    CloseHandle(proc);
+                    return status as int;
+                }
+                if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
+                    CloseHandle(proc);
+                    fail!("failure in WaitForSingleObject: %s", os::last_os_error());
+                }
+            }
+        }
+    }
+
+    #[cfg(unix)]
+    fn waitpid_os(pid: pid_t) -> int {
+        #[fixed_stack_segment]; #[inline(never)];
+
+        use libc::funcs::posix01::wait::*;
+
+        #[cfg(target_os = "linux")]
+        #[cfg(target_os = "android")]
+        fn WIFEXITED(status: i32) -> bool {
+            (status & 0xffi32) == 0i32
+        }
+
+        #[cfg(target_os = "macos")]
+        #[cfg(target_os = "freebsd")]
+        fn WIFEXITED(status: i32) -> bool {
+            (status & 0x7fi32) == 0i32
+        }
+
+        #[cfg(target_os = "linux")]
+        #[cfg(target_os = "android")]
+        fn WEXITSTATUS(status: i32) -> i32 {
+            (status >> 8i32) & 0xffi32
+        }
+
+        #[cfg(target_os = "macos")]
+        #[cfg(target_os = "freebsd")]
+        fn WEXITSTATUS(status: i32) -> i32 {
+            status >> 8i32
+        }
+
+        let mut status = 0 as c_int;
+        if unsafe { waitpid(pid, &mut status, 0) } == -1 {
+            fail!("failure in waitpid: %s", os::last_os_error());
+        }
+
+        return if WIFEXITED(status) {
+            WEXITSTATUS(status) as int
+        } else {
+            1
+        };
+    }
+}
+
 #[cfg(test)]
 mod tests {
+    use io;
+    use libc::c_int;
+    use option::{Option, None, Some};
     use os;
     use path::Path;
-    use prelude::*;
+    use run;
     use str;
-    use super::*;
     use unstable::running_on_valgrind;
 
+    #[test]
+    #[cfg(windows)]
+    fn test_make_command_line() {
+        assert_eq!(
+            run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
+            ~"prog aaa bbb ccc"
+        );
+        assert_eq!(
+            run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
+            ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
+        );
+        assert_eq!(
+            run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
+            ~"\"C:\\Program Files\\test\" aa\\\"bb"
+        );
+        assert_eq!(
+            run::make_command_line("echo", [~"a b c"]),
+            ~"echo \"a b c\""
+        );
+    }
+
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_process_status() {
-        assert_eq!(process_status("false", []), 1);
-        assert_eq!(process_status("true", []), 0);
+        assert_eq!(run::process_status("false", []), 1);
+        assert_eq!(run::process_status("true", []), 0);
     }
     #[test]
     #[cfg(target_os="android")]
     fn test_process_status() {
-        assert_eq!(process_status("/system/bin/sh", [~"-c",~"false"]), 1);
-        assert_eq!(process_status("/system/bin/sh", [~"-c",~"true"]), 0);
+        assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"false"]), 1);
+        assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"true"]), 0);
     }
 
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_process_output_output() {
 
-        let ProcessOutput {status, output, error}
-             = process_output("echo", [~"hello"]);
+        let run::ProcessOutput {status, output, error}
+             = run::process_output("echo", [~"hello"]);
         let output_str = str::from_bytes(output);
 
         assert_eq!(status, 0);
@@ -431,8 +1010,8 @@ fn test_process_output_output() {
     #[cfg(target_os="android")]
     fn test_process_output_output() {
 
-        let ProcessOutput {status, output, error}
-             = process_output("/system/bin/sh", [~"-c",~"echo hello"]);
+        let run::ProcessOutput {status, output, error}
+             = run::process_output("/system/bin/sh", [~"-c",~"echo hello"]);
         let output_str = str::from_bytes(output);
 
         assert_eq!(status, 0);
@@ -447,8 +1026,8 @@ fn test_process_output_output() {
     #[cfg(not(target_os="android"))]
     fn test_process_output_error() {
 
-        let ProcessOutput {status, output, error}
-             = process_output("mkdir", [~"."]);
+        let run::ProcessOutput {status, output, error}
+             = run::process_output("mkdir", [~"."]);
 
         assert_eq!(status, 1);
         assert_eq!(output, ~[]);
@@ -458,40 +1037,90 @@ fn test_process_output_error() {
     #[cfg(target_os="android")]
     fn test_process_output_error() {
 
-        let ProcessOutput {status, output, error}
-             = process_output("/system/bin/mkdir", [~"."]);
+        let run::ProcessOutput {status, output, error}
+             = run::process_output("/system/bin/mkdir", [~"."]);
 
         assert_eq!(status, 255);
         assert_eq!(output, ~[]);
         assert!(!error.is_empty());
     }
 
+    #[test]
+    fn test_pipes() {
+
+        let pipe_in = os::pipe();
+        let pipe_out = os::pipe();
+        let pipe_err = os::pipe();
+
+        let mut proc = run::Process::new("cat", [], run::ProcessOptions {
+            dir: None,
+            env: None,
+            in_fd: Some(pipe_in.input),
+            out_fd: Some(pipe_out.out),
+            err_fd: Some(pipe_err.out)
+        });
+
+        assert!(proc.input_redirected());
+        assert!(proc.output_redirected());
+        assert!(proc.error_redirected());
+
+        os::close(pipe_in.input);
+        os::close(pipe_out.out);
+        os::close(pipe_err.out);
+
+        let expected = ~"test";
+        writeclose(pipe_in.out, expected);
+        let actual = readclose(pipe_out.input);
+        readclose(pipe_err.input);
+        proc.finish();
+
+        assert_eq!(expected, actual);
+    }
+
+    fn writeclose(fd: c_int, s: &str) {
+        let writer = io::fd_writer(fd, false);
+        writer.write_str(s);
+        os::close(fd);
+    }
+
+    fn readclose(fd: c_int) -> ~str {
+        #[fixed_stack_segment]; #[inline(never)];
+
+        unsafe {
+            let file = os::fdopen(fd);
+            let reader = io::FILE_reader(file, false);
+            let buf = reader.read_whole_stream();
+            os::fclose(file);
+            str::from_bytes(buf)
+        }
+    }
+
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_finish_once() {
-        let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
+        let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
         assert_eq!(prog.finish(), 1);
     }
     #[test]
     #[cfg(target_os="android")]
     fn test_finish_once() {
-        let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
-                                    ProcessOptions::new()).unwrap();
+        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
+                                         run::ProcessOptions::new());
         assert_eq!(prog.finish(), 1);
     }
 
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_finish_twice() {
-        let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
+        let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
         assert_eq!(prog.finish(), 1);
         assert_eq!(prog.finish(), 1);
     }
     #[test]
     #[cfg(target_os="android")]
     fn test_finish_twice() {
-        let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
-                                    ProcessOptions::new()).unwrap();
+        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
+                                         run::ProcessOptions::new());
         assert_eq!(prog.finish(), 1);
         assert_eq!(prog.finish(), 1);
     }
@@ -500,9 +1129,8 @@ fn test_finish_twice() {
     #[cfg(not(target_os="android"))]
     fn test_finish_with_output_once() {
 
-        let prog = Process::new("echo", [~"hello"], ProcessOptions::new());
-        let mut prog = prog.unwrap();
-        let ProcessOutput {status, output, error}
+        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
+        let run::ProcessOutput {status, output, error}
             = prog.finish_with_output();
         let output_str = str::from_bytes(output);
 
@@ -517,10 +1145,28 @@ fn test_finish_with_output_once() {
     #[cfg(target_os="android")]
     fn test_finish_with_output_once() {
 
-        let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
-                                    ProcessOptions::new()).unwrap();
-        let ProcessOutput {status, output, error}
+        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+                                         run::ProcessOptions::new());
+        let run::ProcessOutput {status, output, error}
+            = prog.finish_with_output();
+        let output_str = str::from_bytes(output);
+
+        assert_eq!(status, 0);
+        assert_eq!(output_str.trim().to_owned(), ~"hello");
+        // FIXME #7224
+        if !running_on_valgrind() {
+            assert_eq!(error, ~[]);
+        }
+    }
+
+    #[test]
+    #[cfg(not(target_os="android"))]
+    fn test_finish_with_output_twice() {
+
+        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
+        let run::ProcessOutput {status, output, error}
             = prog.finish_with_output();
+
         let output_str = str::from_bytes(output);
 
         assert_eq!(status, 0);
@@ -529,61 +1175,97 @@ fn test_finish_with_output_once() {
         if !running_on_valgrind() {
             assert_eq!(error, ~[]);
         }
+
+        let run::ProcessOutput {status, output, error}
+            = prog.finish_with_output();
+
+        assert_eq!(status, 0);
+        assert_eq!(output, ~[]);
+        // FIXME #7224
+        if !running_on_valgrind() {
+            assert_eq!(error, ~[]);
+        }
+    }
+    #[test]
+    #[cfg(target_os="android")]
+    fn test_finish_with_output_twice() {
+
+        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+                                         run::ProcessOptions::new());
+        let run::ProcessOutput {status, output, error}
+            = prog.finish_with_output();
+
+        let output_str = str::from_bytes(output);
+
+        assert_eq!(status, 0);
+        assert_eq!(output_str.trim().to_owned(), ~"hello");
+        // FIXME #7224
+        if !running_on_valgrind() {
+            assert_eq!(error, ~[]);
+        }
+
+        let run::ProcessOutput {status, output, error}
+            = prog.finish_with_output();
+
+        assert_eq!(status, 0);
+        assert_eq!(output, ~[]);
+        // FIXME #7224
+        if !running_on_valgrind() {
+            assert_eq!(error, ~[]);
+        }
     }
 
     #[test]
     #[should_fail]
     #[cfg(not(windows),not(target_os="android"))]
     fn test_finish_with_output_redirected() {
-        let mut prog = Process::new("echo", [~"hello"], ProcessOptions {
+        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions {
             env: None,
             dir: None,
             in_fd: Some(0),
             out_fd: Some(1),
             err_fd: Some(2)
-        }).unwrap();
-        // this should fail because it is not valid to read the output when it
-        // was redirected
+        });
+        // this should fail because it is not valid to read the output when it was redirected
         prog.finish_with_output();
     }
     #[test]
     #[should_fail]
     #[cfg(not(windows),target_os="android")]
     fn test_finish_with_output_redirected() {
-        let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
-                                    ProcessOptions {
+        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+                                         run::ProcessOptions {
             env: None,
             dir: None,
             in_fd: Some(0),
             out_fd: Some(1),
             err_fd: Some(2)
-        }).unwrap();
-        // this should fail because it is not valid to read the output when it
-        // was redirected
+        });
+        // this should fail because it is not valid to read the output when it was redirected
         prog.finish_with_output();
     }
 
     #[cfg(unix,not(target_os="android"))]
-    fn run_pwd(dir: Option<&Path>) -> Process {
-        Process::new("pwd", [], ProcessOptions {
+    fn run_pwd(dir: Option<&Path>) -> run::Process {
+        run::Process::new("pwd", [], run::ProcessOptions {
             dir: dir,
-            .. ProcessOptions::new()
-        }).unwrap()
+            .. run::ProcessOptions::new()
+        })
     }
     #[cfg(unix,target_os="android")]
-    fn run_pwd(dir: Option<&Path>) -> Process {
-        Process::new("/system/bin/sh", [~"-c",~"pwd"], ProcessOptions {
+    fn run_pwd(dir: Option<&Path>) -> run::Process {
+        run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions {
             dir: dir,
-            .. ProcessOptions::new()
-        }).unwrap()
+            .. run::ProcessOptions::new()
+        })
     }
 
     #[cfg(windows)]
-    fn run_pwd(dir: Option<&Path>) -> Process {
-        Process::new("cmd", [~"/c", ~"cd"], ProcessOptions {
+    fn run_pwd(dir: Option<&Path>) -> run::Process {
+        run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions {
             dir: dir,
-            .. ProcessOptions::new()
-        }).unwrap()
+            .. run::ProcessOptions::new()
+        })
     }
 
     #[test]
@@ -619,26 +1301,26 @@ fn test_change_working_directory() {
     }
 
     #[cfg(unix,not(target_os="android"))]
-    fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
-        Process::new("env", [], ProcessOptions {
+    fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
+        run::Process::new("env", [], run::ProcessOptions {
             env: env,
-            .. ProcessOptions::new()
-        }).unwrap()
+            .. run::ProcessOptions::new()
+        })
     }
     #[cfg(unix,target_os="android")]
-    fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
-        Process::new("/system/bin/sh", [~"-c",~"set"], ProcessOptions {
+    fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
+        run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
             env: env,
-            .. ProcessOptions::new()
-        }).unwrap()
+            .. run::ProcessOptions::new()
+        })
     }
 
     #[cfg(windows)]
-    fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
-        Process::new("cmd", [~"/c", ~"set"], ProcessOptions {
+    fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
+        run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
             env: env,
-            .. ProcessOptions::new()
-        }).unwrap()
+            .. run::ProcessOptions::new()
+        })
     }
 
     #[test]
@@ -675,6 +1357,7 @@ fn test_inherit_env() {
 
     #[test]
     fn test_add_to_env() {
+
         let mut new_env = os::env();
         new_env.push((~"RUN_TEST_NEW_ENV", ~"123"));
 
index f121158d4c525cfe02254028531fb6bb0815bd9b..d0afeb4be85610d834fdfc51bb7553ccba782230 100644 (file)
@@ -126,7 +126,7 @@ pub fn select2<TA, A: SelectPort<TA>, TB, B: SelectPort<TB>>(mut a: A, mut b: B)
 mod test {
     use super::*;
     use clone::Clone;
-    use iter::Times;
+    use num::Times;
     use option::*;
     use rt::comm::*;
     use rt::test::*;
index ad3e4368daa5298c3e4f07e3b9a7c9316d0810ac..ce0202ded7eda2ecd890394c07b439a88ae73038 100644 (file)
@@ -140,7 +140,6 @@ pub mod linkhack {
 pub mod from_str;
 #[path = "num/num.rs"]
 pub mod num;
-pub mod iter;
 pub mod iterator;
 pub mod to_str;
 pub mod to_bytes;
@@ -179,8 +178,14 @@ pub mod linkhack {
 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;
@@ -220,4 +225,3 @@ mod std {
     pub use fmt;
     pub use to_bytes;
 }
-
index e6cadd04a5b6ea9eb82068df94d20f53336fccd8..4b01d29a98b96d6fb14d13c22c85323df7349875 100644 (file)
@@ -21,7 +21,7 @@
 use char::Char;
 use clone::{Clone, DeepClone};
 use container::{Container, Mutable};
-use iter::Times;
+use num::Times;
 use iterator::{Iterator, FromIterator, Extendable};
 use iterator::{Filter, AdditiveIterator, Map};
 use iterator::{Invert, DoubleEndedIterator};
@@ -621,8 +621,7 @@ enum NormalizationForm {
 #[deriving(Clone)]
 struct NormalizationIterator<'self> {
     priv kind: NormalizationForm,
-    priv index: uint,
-    priv string: &'self str,
+    priv iter: CharIterator<'self>,
     priv buffer: ~[(char, u8)],
     priv sorted: bool
 }
@@ -650,16 +649,17 @@ fn next(&mut self) -> Option<char> {
             NFKD => char::decompose_compatible
         };
 
-        while !self.sorted && self.index < self.string.len() {
-            let CharRange {ch, next} = self.string.char_range_at(self.index);
-            self.index = next;
-            do decomposer(ch) |d| {
-                let class = canonical_combining_class(d);
-                if class == 0 && !self.sorted {
-                    canonical_sort(self.buffer);
-                    self.sorted = true;
+        if !self.sorted {
+            for ch in self.iter {
+                do decomposer(ch) |d| {
+                    let class = canonical_combining_class(d);
+                    if class == 0 && !self.sorted {
+                        canonical_sort(self.buffer);
+                        self.sorted = true;
+                    }
+                    self.buffer.push((d, class));
                 }
-                self.buffer.push((d, class));
+                if self.sorted { break }
             }
         }
 
@@ -678,7 +678,10 @@ fn next(&mut self) -> Option<char> {
         }
     }
 
-    fn size_hint(&self) -> (uint, Option<uint>) { (self.string.len(), None) }
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        let (lower, _) = self.iter.size_hint();
+        (lower, None)
+    }
 }
 
 /// Replace all occurrences of one string with another
@@ -907,46 +910,6 @@ pub fn with_capacity(capacity: uint) -> ~str {
     }
 }
 
-/// As char_len but for a slice of a string
-///
-/// # Arguments
-///
-/// * s - A valid string
-/// * start - The position inside `s` where to start counting in bytes
-/// * end - The position where to stop counting
-///
-/// # Return value
-///
-/// The number of Unicode characters in `s` between the given indices.
-pub fn count_chars(s: &str, start: uint, end: uint) -> uint {
-    assert!(s.is_char_boundary(start));
-    assert!(s.is_char_boundary(end));
-    let mut i = start;
-    let mut len = 0u;
-    while i < end {
-        let next = s.char_range_at(i).next;
-        len += 1u;
-        i = next;
-    }
-    return len;
-}
-
-/// Counts the number of bytes taken by the first `n` chars in `s`
-/// starting from `start`.
-pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint {
-    assert!(s.is_char_boundary(start));
-    let mut end = start;
-    let mut cnt = n;
-    let l = s.len();
-    while cnt > 0u {
-        assert!(end < l);
-        let next = s.char_range_at(end).next;
-        cnt -= 1u;
-        end = next;
-    }
-    end - start
-}
-
 // https://tools.ietf.org/html/rfc3629
 static UTF8_CHAR_WIDTH: [u8, ..256] = [
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@@ -1092,7 +1055,7 @@ pub unsafe fn slice_bytes<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
     pub unsafe fn slice_unchecked<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
         do s.as_imm_buf |sbuf, _n| {
              cast::transmute(Slice {
-                 data: sbuf.offset_inbounds(begin as int),
+                 data: sbuf.offset(begin as int),
                  len: end - begin,
              })
         }
@@ -1628,8 +1591,7 @@ fn word_iter(&self) -> WordIterator<'self> {
     /// Returns the string in Unicode Normalization Form D (canonical decomposition)
     fn nfd_iter(&self) -> NormalizationIterator<'self> {
         NormalizationIterator {
-            index: 0,
-            string: *self,
+            iter: self.iter(),
             buffer: ~[],
             sorted: false,
             kind: NFD
@@ -1639,8 +1601,7 @@ fn nfd_iter(&self) -> NormalizationIterator<'self> {
     /// Returns the string in Unicode Normalization Form KD (compatibility decomposition)
     fn nfkd_iter(&self) -> NormalizationIterator<'self> {
         NormalizationIterator {
-            index: 0,
-            string: *self,
+            iter: self.iter(),
             buffer: ~[],
             sorted: false,
             kind: NFKD
@@ -1712,6 +1673,7 @@ fn slice_chars(&self, begin: uint, end: uint) -> &'self str {
             if count == end { end_byte = Some(idx); break; }
             count += 1;
         }
+        if begin_byte.is_none() && count == begin { begin_byte = Some(self.len()) }
         if end_byte.is_none() && count == end { end_byte = Some(self.len()) }
 
         match (begin_byte, end_byte) {
@@ -2699,8 +2661,11 @@ fn test_slice_chars() {
         fn t(a: &str, b: &str, start: uint) {
             assert_eq!(a.slice_chars(start, start + b.char_len()), b);
         }
+        t("", "", 0);
         t("hello", "llo", 2);
         t("hello", "el", 1);
+        t("αβλ", "β", 1);
+        t("αβλ", "", 3);
         assert_eq!("ะเทศไท", "ประเทศไทย中华Việt Nam".slice_chars(2, 8));
     }
 
index cb0753fb2e5dee4a45ea3a8d8bbbf871a3857a83..cfc285488a90f30c218e3d9dddd474687a62910d 100644 (file)
@@ -14,6 +14,7 @@
 
 use c_str::ToCStr;
 use cast;
+#[cfg(stage0)]
 use io;
 use libc;
 use libc::{c_char, size_t};
@@ -91,9 +92,19 @@ pub fn refcount<T>(t: @T) -> uint {
     }
 }
 
+#[cfg(not(stage0))]
 pub fn log_str<T>(t: &T) -> ~str {
-    do io::with_str_writer |wr| {
-        repr::write_repr(wr, t)
+    use rt::io;
+    use rt::io::Decorator;
+
+    let mut result = io::mem::MemWriter::new();
+    repr::write_repr(&mut result as &mut io::Writer, t);
+    str::from_bytes_owned(result.inner())
+}
+#[cfg(stage0)]
+pub fn log_str<T>(t: &T) -> ~str {
+    do io::with_str_writer |w| {
+        repr::write_repr(w, t)
     }
 }
 
diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs
deleted file mode 100644 (file)
index 2c2dfd8..0000000
+++ /dev/null
@@ -1,322 +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.
-
-#[allow(missing_doc)];
-
-use cast;
-use libc;
-use local_data;
-use prelude::*;
-use ptr;
-use unstable::raw;
-use util;
-
-use rt::task::{Task, LocalStorage};
-
-pub enum Handle {
-    NewHandle(*mut LocalStorage)
-}
-
-impl Handle {
-    pub fn new() -> Handle {
-        use rt::local::Local;
-        unsafe {
-            let task: *mut Task = Local::unsafe_borrow();
-            NewHandle(&mut (*task).storage)
-        }
-    }
-}
-
-#[deriving(Eq)]
-enum LoanState {
-    NoLoan, ImmLoan, MutLoan
-}
-
-impl LoanState {
-    fn describe(&self) -> &'static str {
-        match *self {
-            NoLoan => "no loan",
-            ImmLoan => "immutable",
-            MutLoan => "mutable"
-        }
-    }
-}
-
-trait LocalData {}
-impl<T: 'static> LocalData for T {}
-
-// The task-local-map stores all TLS information for the currently running task.
-// It is stored as an owned pointer into the runtime, and it's only allocated
-// when TLS is used for the first time. This map must be very carefully
-// constructed because it has many mutable loans unsoundly handed out on it to
-// the various invocations of TLS requests.
-//
-// One of the most important operations is loaning a value via `get` to a
-// caller. In doing so, the slot that the TLS entry is occupying cannot be
-// invalidated because upon returning it's loan state must be updated. Currently
-// the TLS map is a vector, but this is possibly dangerous because the vector
-// can be reallocated/moved when new values are pushed onto it.
-//
-// This problem currently isn't solved in a very elegant way. Inside the `get`
-// function, it internally "invalidates" all references after the loan is
-// finished and looks up into the vector again. In theory this will prevent
-// pointers from being moved under our feet so long as LLVM doesn't go too crazy
-// with the optimizations.
-//
-// n.b. Other structures are not sufficient right now:
-//          * HashMap uses ~[T] internally (push reallocates/moves)
-//          * TreeMap is plausible, but it's in extra
-//          * dlist plausible, but not in std
-//          * a custom owned linked list was attempted, but difficult to write
-//            and involved a lot of extra code bloat
-//
-// n.b. Has to be stored with a pointer at outermost layer; the foreign call
-//      returns void *.
-//
-// n.b. If TLS is used heavily in future, this could be made more efficient with
-//      a proper map.
-type TaskLocalMap = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
-type TLSValue = ~LocalData:;
-
-fn cleanup_task_local_map(map_ptr: *libc::c_void) {
-    unsafe {
-        assert!(!map_ptr.is_null());
-        // Get and keep the single reference that was created at the
-        // beginning.
-        let _map: TaskLocalMap = cast::transmute(map_ptr);
-        // All local_data will be destroyed along with the map.
-    }
-}
-
-// Gets the map from the runtime. Lazily initialises if not done so already.
-unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
-
-    unsafe fn newsched_map(local: *mut LocalStorage) -> &mut TaskLocalMap {
-        // This is based on the same idea as the oldsched code above.
-        match &mut *local {
-            // If the at_exit function is already set, then we just need to take
-            // a loan out on the TLS map stored inside
-            &LocalStorage(ref mut map_ptr, Some(_)) => {
-                assert!(map_ptr.is_not_null());
-                return cast::transmute(map_ptr);
-            }
-            // If this is the first time we've accessed TLS, perform similar
-            // actions to the oldsched way of doing things.
-            &LocalStorage(ref mut map_ptr, ref mut at_exit) => {
-                assert!(map_ptr.is_null());
-                assert!(at_exit.is_none());
-                let map: TaskLocalMap = ~[];
-                *map_ptr = cast::transmute(map);
-                *at_exit = Some(cleanup_task_local_map);
-                return cast::transmute(map_ptr);
-            }
-        }
-    }
-
-    match handle {
-        NewHandle(local_storage) => newsched_map(local_storage)
-    }
-}
-
-unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
-    let pair: raw::Closure = cast::transmute_copy(&key);
-    return pair.code as *libc::c_void;
-}
-
-pub unsafe fn local_pop<T: 'static>(handle: Handle,
-                                    key: local_data::Key<T>) -> Option<T> {
-    let map = get_local_map(handle);
-    let key_value = key_to_key_value(key);
-
-    for entry in map.mut_iter() {
-        match *entry {
-            Some((k, _, loan)) if k == key_value => {
-                if loan != NoLoan {
-                    fail!("TLS value cannot be removed because it is already \
-                          borrowed as %s", loan.describe());
-                }
-                // Move the data out of the `entry` slot via util::replace. This
-                // is guaranteed to succeed because we already matched on `Some`
-                // above.
-                let data = match util::replace(entry, None) {
-                    Some((_, data, _)) => data,
-                    None => abort(),
-                };
-
-                // Move `data` into transmute to get out the memory that it
-                // owns, we must free it manually later.
-                let (_vtable, box): (uint, ~~T) = cast::transmute(data);
-
-                // Read the box's value (using the compiler's built-in
-                // auto-deref functionality to obtain a pointer to the base)
-                let ret = ptr::read_ptr(cast::transmute::<&T, *mut T>(*box));
-
-                // Finally free the allocated memory. we don't want this to
-                // actually touch the memory inside because it's all duplicated
-                // now, so the box is transmuted to a 0-sized type. We also use
-                // a type which references `T` because currently the layout
-                // could depend on whether T contains managed pointers or not.
-                let _: ~~[T, ..0] = cast::transmute(box);
-
-                // Everything is now deallocated, and we own the value that was
-                // located inside TLS, so we now return it.
-                return Some(ret);
-            }
-            _ => {}
-        }
-    }
-    return None;
-}
-
-pub unsafe fn local_get<T: 'static, U>(handle: Handle,
-                                       key: local_data::Key<T>,
-                                       f: &fn(Option<&T>) -> U) -> U {
-    local_get_with(handle, key, ImmLoan, f)
-}
-
-pub unsafe fn local_get_mut<T: 'static, U>(handle: Handle,
-                                           key: local_data::Key<T>,
-                                           f: &fn(Option<&mut T>) -> U) -> U {
-    do local_get_with(handle, key, MutLoan) |x| {
-        match x {
-            None => f(None),
-            // We're violating a lot of compiler guarantees with this
-            // invocation of `transmute_mut`, but we're doing runtime checks to
-            // ensure that it's always valid (only one at a time).
-            //
-            // there is no need to be upset!
-            Some(x) => { f(Some(cast::transmute_mut(x))) }
-        }
-    }
-}
-
-unsafe fn local_get_with<T: 'static, U>(handle: Handle,
-                                        key: local_data::Key<T>,
-                                        state: LoanState,
-                                        f: &fn(Option<&T>) -> U) -> U {
-    // This function must be extremely careful. Because TLS can store owned
-    // values, and we must have some form of `get` function other than `pop`,
-    // this function has to give a `&` reference back to the caller.
-    //
-    // One option is to return the reference, but this cannot be sound because
-    // the actual lifetime of the object is not known. The slot in TLS could not
-    // be modified until the object goes out of scope, but the TLS code cannot
-    // know when this happens.
-    //
-    // For this reason, the reference is yielded to a specified closure. This
-    // way the TLS code knows exactly what the lifetime of the yielded pointer
-    // is, allowing callers to acquire references to owned data. This is also
-    // sound so long as measures are taken to ensure that while a TLS slot is
-    // loaned out to a caller, it's not modified recursively.
-    let map = get_local_map(handle);
-    let key_value = key_to_key_value(key);
-
-    let pos = map.iter().position(|entry| {
-        match *entry {
-            Some((k, _, _)) if k == key_value => true, _ => false
-        }
-    });
-    match pos {
-        None => { return f(None); }
-        Some(i) => {
-            let ret;
-            let mut return_loan = false;
-            match map[i] {
-                Some((_, ref data, ref mut loan)) => {
-                    match (state, *loan) {
-                        (_, NoLoan) => {
-                            *loan = state;
-                            return_loan = true;
-                        }
-                        (ImmLoan, ImmLoan) => {}
-                        (want, cur) => {
-                            fail!("TLS slot cannot be borrowed as %s because \
-                                   it is already borrowed as %s",
-                                  want.describe(), cur.describe());
-                        }
-                    }
-                    // data was created with `~~T as ~LocalData`, so we extract
-                    // pointer part of the trait, (as ~~T), and then use
-                    // compiler coercions to achieve a '&' pointer.
-                    match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data) {
-                        (_vtable, ref box) => {
-                            let value: &T = **box;
-                            ret = f(Some(value));
-                        }
-                    }
-                }
-                _ => abort()
-            }
-
-            // n.b. 'data' and 'loans' are both invalid pointers at the point
-            // 'f' returned because `f` could have appended more TLS items which
-            // in turn relocated the vector. Hence we do another lookup here to
-            // fixup the loans.
-            if return_loan {
-                match map[i] {
-                    Some((_, _, ref mut loan)) => { *loan = NoLoan; }
-                    None => { abort(); }
-                }
-            }
-            return ret;
-        }
-    }
-}
-
-fn abort() -> ! {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    unsafe { libc::abort() }
-}
-
-pub unsafe fn local_set<T: 'static>(handle: Handle,
-                                    key: local_data::Key<T>,
-                                    data: T) {
-    let map = get_local_map(handle);
-    let keyval = key_to_key_value(key);
-
-    // When the task-local map is destroyed, all the data needs to be cleaned
-    // up. For this reason we can't do some clever tricks to store '~T' as a
-    // '*c_void' or something like that. To solve the problem, we cast
-    // everything to a trait (LocalData) which is then stored inside the map.
-    // Upon destruction of the map, all the objects will be destroyed and the
-    // traits have enough information about them to destroy themselves.
-    //
-    // FIXME(#7673): This should be "~data as ~LocalData" (without the colon at
-    //               the end, and only one sigil)
-    let data = ~~data as ~LocalData:;
-
-    fn insertion_position(map: &mut TaskLocalMap,
-                          key: *libc::c_void) -> Option<uint> {
-        // First see if the map contains this key already
-        let curspot = map.iter().position(|entry| {
-            match *entry {
-                Some((ekey, _, loan)) if key == ekey => {
-                    if loan != NoLoan {
-                        fail!("TLS value cannot be overwritten because it is
-                               already borrowed as %s", loan.describe())
-                    }
-                    true
-                }
-                _ => false,
-            }
-        });
-        // If it doesn't contain the key, just find a slot that's None
-        match curspot {
-            Some(i) => Some(i),
-            None => map.iter().position(|entry| entry.is_none())
-        }
-    }
-
-    match insertion_position(map, keyval) {
-        Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
-        None => { map.push(Some((keyval, data, NoLoan))); }
-    }
-}
index c0b331c52eeb0715412171f323aed79f7cda0cab..b52dd3a906bd687811f8a829f8386d26d5dda037 100644 (file)
@@ -52,7 +52,6 @@
 #[cfg(test)] use ptr;
 #[cfg(test)] use task;
 
-mod local_data_priv;
 pub mod spawn;
 
 /**
index 90cf49cad1ccf2a9553507091bfa31c925ee146b..db106de76d94e4ce5eb97d3097da2a2fdcd378ee 100644 (file)
@@ -90,6 +90,7 @@ mod test {
     use libc;
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME #8818
     fn test_loading_cosine() {
         // The math library does not need to be loaded since it is already
         // statically linked in
index 796567bd561196a3903f67a81b3547af5e63249c..018f8532eab7c412615f453d2e644bd3546b2a9a 100644 (file)
@@ -73,7 +73,7 @@ pub struct TyDesc {
 pub enum Opaque { }
 
 #[lang="ty_visitor"]
-#[cfg(not(test))]
+#[cfg(not(test), stage0)]
 pub trait TyVisitor {
     fn visit_bot(&self) -> bool;
     fn visit_nil(&self) -> bool;
@@ -168,6 +168,102 @@ fn visit_leave_fn(&self, purity: uint, proto: uint,
     fn visit_closure_ptr(&self, ck: uint) -> bool;
 }
 
+#[lang="ty_visitor"]
+#[cfg(not(test), not(stage0))]
+pub trait TyVisitor {
+    fn visit_bot(&mut self) -> bool;
+    fn visit_nil(&mut self) -> bool;
+    fn visit_bool(&mut self) -> bool;
+
+    fn visit_int(&mut self) -> bool;
+    fn visit_i8(&mut self) -> bool;
+    fn visit_i16(&mut self) -> bool;
+    fn visit_i32(&mut self) -> bool;
+    fn visit_i64(&mut self) -> bool;
+
+    fn visit_uint(&mut self) -> bool;
+    fn visit_u8(&mut self) -> bool;
+    fn visit_u16(&mut self) -> bool;
+    fn visit_u32(&mut self) -> bool;
+    fn visit_u64(&mut self) -> bool;
+
+    fn visit_float(&mut self) -> bool;
+    fn visit_f32(&mut self) -> bool;
+    fn visit_f64(&mut self) -> bool;
+
+    fn visit_char(&mut self) -> bool;
+
+    fn visit_estr_box(&mut self) -> bool;
+    fn visit_estr_uniq(&mut self) -> bool;
+    fn visit_estr_slice(&mut self) -> bool;
+    fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool;
+
+    fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_uniq_managed(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_ptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+
+    fn visit_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_evec_uniq_managed(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
+                        mtbl: uint, inner: *TyDesc) -> bool;
+
+    fn visit_enter_rec(&mut self, n_fields: uint,
+                       sz: uint, align: uint) -> bool;
+    fn visit_rec_field(&mut self, i: uint, name: &str,
+                       mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_leave_rec(&mut self, n_fields: uint,
+                       sz: uint, align: uint) -> bool;
+
+    fn visit_enter_class(&mut self, n_fields: uint,
+                         sz: uint, align: uint) -> bool;
+    fn visit_class_field(&mut self, i: uint, name: &str,
+                         mtbl: uint, inner: *TyDesc) -> bool;
+    fn visit_leave_class(&mut self, n_fields: uint,
+                         sz: uint, align: uint) -> bool;
+
+    fn visit_enter_tup(&mut self, n_fields: uint,
+                       sz: uint, align: uint) -> bool;
+    fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool;
+    fn visit_leave_tup(&mut self, n_fields: uint,
+                       sz: uint, align: uint) -> bool;
+
+    fn visit_enter_enum(&mut self, n_variants: uint,
+                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        sz: uint, align: uint) -> bool;
+    fn visit_enter_enum_variant(&mut self, variant: uint,
+                                disr_val: int,
+                                n_fields: uint,
+                                name: &str) -> bool;
+    fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool;
+    fn visit_leave_enum_variant(&mut self, variant: uint,
+                                disr_val: int,
+                                n_fields: uint,
+                                name: &str) -> bool;
+    fn visit_leave_enum(&mut self, n_variants: uint,
+                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        sz: uint, align: uint) -> bool;
+
+    fn visit_enter_fn(&mut self, purity: uint, proto: uint,
+                      n_inputs: uint, retstyle: uint) -> bool;
+    fn visit_fn_input(&mut self, i: uint, mode: uint, inner: *TyDesc) -> bool;
+    fn visit_fn_output(&mut self, retstyle: uint, inner: *TyDesc) -> bool;
+    fn visit_leave_fn(&mut self, purity: uint, proto: uint,
+                      n_inputs: uint, retstyle: uint) -> bool;
+
+    fn visit_trait(&mut self) -> bool;
+    fn visit_param(&mut self, i: uint) -> bool;
+    fn visit_self(&mut self) -> bool;
+    fn visit_type(&mut self) -> bool;
+    fn visit_opaque_box(&mut self) -> bool;
+    fn visit_closure_ptr(&mut self, ck: uint) -> bool;
+}
+
 #[abi = "rust-intrinsic"]
 extern "rust-intrinsic" {
 
@@ -325,26 +421,23 @@ fn visit_leave_fn(&self, purity: uint, proto: uint,
     /// 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));
 
     /// Get the address of the `__morestack` stack growth function.
     pub fn morestack_addr() -> *();
 
-    /// Calculates the offset from a pointer.
-    ///
-    /// This is implemented as an intrinsic to avoid converting to and from an
-    /// integer, since the conversion would throw away aliasing information.
-    pub fn offset<T>(dst: *T, offset: int) -> *T;
-
     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
     /// the object, or one-byte-past-the-end. An arithmetic overflow is also
     /// undefined behaviour.
     ///
-    /// This intrinsic should be preferred over `offset` when the guarantee can
-    /// be satisfied, to enable better optimization.
-    pub fn offset_inbounds<T>(dst: *T, offset: int) -> *T;
+    /// This is implemented as an intrinsic to avoid converting to and from an
+    /// integer, since the conversion would throw away aliasing information.
+    pub fn offset<T>(dst: *T, offset: int) -> *T;
 
     /// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
     /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
index 8d1545ea2b4506061f8c1d1c48c3bf2b3af34a3b..26313323291e5e8d4bef786dec5d989cc6942971 100644 (file)
@@ -26,6 +26,7 @@
 /// An atomically reference counted pointer.
 ///
 /// Enforces no shared-memory safety.
+#[unsafe_no_drop_flag]
 pub struct UnsafeArc<T> {
     data: *mut ArcData<T>,
 }
@@ -221,8 +222,9 @@ fn clone(&self) -> UnsafeArc<T> {
 impl<T> Drop for UnsafeArc<T>{
     fn drop(&self) {
         unsafe {
+            // Happens when destructing an unwrapper's handle and from `#[unsafe_no_drop_flag]`
             if self.data.is_null() {
-                return; // Happens when destructing an unwrapper's handle.
+                return
             }
             let mut data: ~ArcData<T> = cast::transmute(self.data);
             // Must be acquire+release, not just release, to make sure this
@@ -440,6 +442,12 @@ mod tests {
     use super::{Exclusive, UnsafeArc, atomically};
     use task;
     use util;
+    use sys::size_of;
+
+    #[test]
+    fn test_size() {
+        assert_eq!(size_of::<UnsafeArc<[int, ..10]>>(), size_of::<*[int, ..10]>());
+    }
 
     #[test]
     fn test_atomically() {
index 8cd1b09468d46c721755f9e5cabc95335351be25..12aebe20161a03f337c7a6a677984d17de73e300 100644 (file)
@@ -896,7 +896,7 @@ fn iter(self) -> VecIterator<'self, T> {
                             lifetime: cast::transmute(p)}
             } else {
                 VecIterator{ptr: p,
-                            end: p.offset_inbounds(self.len() as int),
+                            end: p.offset(self.len() as int),
                             lifetime: cast::transmute(p)}
             }
         }
@@ -1884,7 +1884,7 @@ fn mut_iter(self) -> VecMutIterator<'self, T> {
                                lifetime: cast::transmute(p)}
             } else {
                 VecMutIterator{ptr: p,
-                               end: p.offset_inbounds(self.len() as int),
+                               end: p.offset(self.len() as int),
                                lifetime: cast::transmute(p)}
             }
         }
@@ -2247,7 +2247,7 @@ fn next(&mut self) -> Option<$elem> {
                             // same pointer.
                             cast::transmute(self.ptr as uint + 1)
                         } else {
-                            self.ptr.offset_inbounds(1)
+                            self.ptr.offset(1)
                         };
 
                         Some(cast::transmute(old))
@@ -2279,7 +2279,7 @@ fn next_back(&mut self) -> Option<$elem> {
                             // See above for why 'ptr.offset' isn't used
                             cast::transmute(self.end as uint - 1)
                         } else {
-                            self.end.offset_inbounds(-1)
+                            self.end.offset(-1)
                         };
                         Some(cast::transmute(self.end))
                     }
index 44015a8b443f092b899f7102beb53f48ffbca9f8..aec279e9c53bd1bff8d8ffbb7c570fd6f9e7992c 100644 (file)
@@ -791,6 +791,7 @@ pub enum ty_ {
     ty_tup(~[Ty]),
     ty_path(Path, Option<OptVec<TyParamBound>>, NodeId), // for #7264; see above
     ty_mac(mac),
+    ty_typeof(@expr),
     // ty_infer means the type should be inferred instead of it having been
     // specified. This should only appear at the "top level" of a type and not
     // nested in one.
index 458737e2fbf0bad484310ff5336bd2628942aa4f..6e3cd8e71597178664b8be07e86feaebb62a8b9e 100644 (file)
@@ -697,6 +697,7 @@ fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
                 fld.fold_expr(e)
             )
         }
+        ty_typeof(e) => ty_typeof(fld.fold_expr(e)),
         ty_mac(ref mac) => ty_mac(fold_mac(mac))
     }
 }
index 56576ee359960b0a40f5fcedaab5a899def08679..e1dcdb9222c7bdc654b13848d0be63822143c7f9 100644 (file)
@@ -279,6 +279,9 @@ pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
             (v.visit_ty)(mt.ty, (e.clone(), v));
             (v.visit_expr)(ex, (e.clone(), v));
         },
+        ty_typeof(ex) => {
+            (v.visit_expr)(ex, (e.clone(), v));
+        }
         ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
     }
 }
index 8ca858b7935eceedd2b818e4ee91469ea6e61bf6..ea7a7540e363dce1a3f520a3e090e54f57bd31b2 100644 (file)
@@ -51,7 +51,7 @@
 use ast::{sty_box, sty_region, sty_static, sty_uniq, sty_value};
 use ast::{token_tree, trait_method, trait_ref, tt_delim, tt_seq, tt_tok};
 use ast::{tt_nonterminal, tuple_variant_kind, Ty, ty_, ty_bot, ty_box};
-use ast::{TypeField, ty_fixed_length_vec, ty_closure, ty_bare_fn};
+use ast::{TypeField, ty_fixed_length_vec, ty_closure, ty_bare_fn, ty_typeof};
 use ast::{ty_infer, TypeMethod};
 use ast::{ty_nil, TyParam, TyParamBound, ty_path, ty_ptr, ty_rptr};
 use ast::{ty_tup, ty_u32, ty_uniq, ty_vec, uniq};
@@ -1136,6 +1136,13 @@ pub fn parse_ty(&self, _: bool) -> Ty {
             let result = self.parse_ty_closure(ast::BorrowedSigil, None);
             self.obsolete(*self.last_span, ObsoleteBareFnType);
             result
+        } else if self.eat_keyword(keywords::Typeof) {
+            // TYPEOF
+            // In order to not be ambiguous, the type must be surrounded by parens.
+            self.expect(&token::LPAREN);
+            let e = self.parse_expr();
+            self.expect(&token::RPAREN);
+            ty_typeof(e)
         } else if *self.token == token::MOD_SEP
             || is_ident_or_path(self.token) {
             // NAMED TYPE
@@ -3610,6 +3617,19 @@ fn maybe_parse_borrowed_explicit_self(this: &Parser) -> ast::explicit_self_ {
             self.bump();
             sty_value
           }
+          token::BINOP(token::STAR) => {
+            // Possibly "*self" or "*mut self" -- not supported. Try to avoid
+            // emitting cryptic "unexpected token" errors.
+            self.bump();
+            if self.token_is_mutability(self.token) {
+                self.bump();
+            }
+            if self.is_self_ident() {
+                self.span_err(*self.span, "cannot pass self by unsafe pointer");
+                self.bump();
+            }
+            sty_value
+          }
           _ => {
             sty_static
           }
index 0d7def84003e4d27ee13962544995c5f47ebb139..8128a4e905c16ff77e90bcfc4214bc34438bc1bd 100644 (file)
@@ -478,6 +478,7 @@ fn mk_fresh_ident_interner() -> @ident_interner {
         "be",                 // 64
         "pure",               // 65
         "yield",              // 66
+        "typeof",             // 67
     ];
 
     @ident_interner {
@@ -595,6 +596,7 @@ pub enum Keyword {
         True,
         Trait,
         Type,
+        Typeof,
         Unsafe,
         Use,
         While,
@@ -639,6 +641,7 @@ pub fn to_ident(&self) -> ident {
                 True => ident { name: 57, ctxt: 0 },
                 Trait => ident { name: 58, ctxt: 0 },
                 Type => ident { name: 59, ctxt: 0 },
+                Typeof => ident { name: 67, ctxt: 0 },
                 Unsafe => ident { name: 60, ctxt: 0 },
                 Use => ident { name: 61, ctxt: 0 },
                 While => ident { name: 62, ctxt: 0 },
@@ -660,7 +663,7 @@ pub fn is_keyword(kw: keywords::Keyword, tok: &Token) -> bool {
 pub fn is_any_keyword(tok: &Token) -> bool {
     match *tok {
         token::IDENT(sid, false) => match sid.name {
-            8 | 27 | 32 .. 66 => true,
+            8 | 27 | 32 .. 67 => true,
             _ => false,
         },
         _ => false
@@ -680,7 +683,7 @@ pub fn is_strict_keyword(tok: &Token) -> bool {
 pub fn is_reserved_keyword(tok: &Token) -> bool {
     match *tok {
         token::IDENT(sid, false) => match sid.name {
-            64 .. 66 => true,
+            64 .. 67 => true,
             _ => false,
         },
         _ => false,
index d449ba4eb5fb4609c3045958a7fdb004d1da3f0c..9c31d982590eafd4c943bcd3dc55575239711d9e 100644 (file)
@@ -435,6 +435,11 @@ pub fn print_type(s: @ps, ty: &ast::Ty) {
         print_expr(s, v);
         word(s.s, "]");
       }
+      ast::ty_typeof(e) => {
+          word(s.s, "typeof(");
+          print_expr(s, e);
+          word(s.s, ")");
+      }
       ast::ty_mac(_) => {
           fail!("print_type doesn't know how to print a ty_mac");
       }
index e5b7823ae44ecc9a5e1ae7335bd47b93829669a7..79304aebea2d47afb94f0f9b31afe0781ab1ec1c 100644 (file)
@@ -314,6 +314,9 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
             visitor.visit_ty(mutable_type.ty, env.clone());
             visitor.visit_expr(expression, env)
         }
+        ty_typeof(expression) => {
+            visitor.visit_expr(expression, env)
+        }
         ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
     }
 }
index ef2bcd134164adcaa072dcb56e62b737fdcb075e..dfae9c3e958dc086d9c0ab068cd76d196c95a433 160000 (submodule)
--- a/src/libuv
+++ b/src/libuv
@@ -1 +1 @@
-Subproject commit ef2bcd134164adcaa072dcb56e62b737fdcb075e
+Subproject commit dfae9c3e958dc086d9c0ab068cd76d196c95a433
index 0964c68ddf2c67ce455e7443a06f4bb3db9e92bb..08a3bd96ee6e1d141494f0014ede75d9871114c4 160000 (submodule)
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit 0964c68ddf2c67ce455e7443a06f4bb3db9e92bb
+Subproject commit 08a3bd96ee6e1d141494f0014ede75d9871114c4
index a181e76df5ca70f1bb31ee21a93c7c4be96fcd6a..8ef4572f8108f0170b577359475da5cde9fbad4b 100644 (file)
@@ -329,13 +329,20 @@ rust_uv_get_len_from_buf(uv_buf_t buf) {
     return buf.len;
 }
 
+extern "C" uv_err_t
+rust_uv_last_error(uv_loop_t* loop) {
+    return uv_last_error(loop);
+}
+
 extern "C" const char*
-rust_uv_strerror(int err) {
+rust_uv_strerror(uv_err_t* err_ptr) {
+    uv_err_t err = *err_ptr;
     return uv_strerror(err);
 }
 
 extern "C" const char*
-rust_uv_err_name(int err) {
+rust_uv_err_name(uv_err_t* err_ptr) {
+    uv_err_t err = *err_ptr;
     return uv_err_name(err);
 }
 
@@ -546,37 +553,3 @@ extern "C" uv_loop_t*
 rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
   return req->loop;
 }
-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);
-}
index 2fc1a91a132da55d66c5ba660612398ebbfe06d1..b668d3944066252084add406d8c8043e66f6e0e8 100644 (file)
@@ -47,6 +47,7 @@ rust_uv_timer_start
 rust_uv_timer_stop
 rust_uv_tcp_init
 rust_uv_buf_init
+rust_uv_last_error
 rust_uv_strerror
 rust_uv_err_name
 rust_uv_ip4_addr
@@ -190,11 +191,4 @@ rust_drop_global_args_lock
 rust_take_change_dir_lock
 rust_drop_change_dir_lock
 rust_get_test_int
-rust_get_task
-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
+rust_get_task
\ No newline at end of file
index 56ba56cf89377fb2ea265ce1dca82df995bb5c70..431b620e68f77b1eafadfc99912e874f36cd07f2 100644 (file)
@@ -78,6 +78,7 @@ LLVMRustCreateTargetMachine(const char *triple,
     }
 
     TargetOptions Options;
+    Options.NoFramePointerElim = true;
     Options.EnableSegmentedStacks = EnableSegmentedStacks;
     Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
     Options.FloatABIType =
index 40ee486ec2d9c6a2906e75f4ce132bc58024b1d1..54af6fe7e73bafe60f73384f211c0c06bbc5e933 100644 (file)
@@ -284,6 +284,7 @@ LLVMRustBuildJIT(void* mem,
   std::string Err;
   TargetOptions Options;
   Options.JITEmitDebugInfo = true;
+  Options.NoFramePointerElim = true;
   Options.EnableSegmentedStacks = EnableSegmentedStacks;
   RustMCJITMemoryManager* MM = (RustMCJITMemoryManager*) mem;
   assert(MM);
diff --git a/src/test/auxiliary/nested_item.rs b/src/test/auxiliary/nested_item.rs
new file mode 100644 (file)
index 0000000..e9dde0d
--- /dev/null
@@ -0,0 +1,40 @@
+// 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.
+
+// original problem
+fn foo<T>() -> int {
+    {
+        static foo: int = 2;
+        foo
+    }
+}
+
+// issue 8134
+struct Foo;
+impl<T> Foo {
+    pub fn foo(&self) {
+        static X: uint = 1;
+    }
+}
+
+// issue 8134
+pub struct Parser<T>;
+impl<T: std::iterator::Iterator<char>> Parser<T> {
+    fn in_doctype(&mut self) {
+        static DOCTYPEPattern: [char, ..6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
+    }
+}
+
+struct Bar;
+impl<T> Foo {
+    pub fn bar(&self) {
+        static X: uint = 1;
+    }
+}
diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs
new file mode 100644 (file)
index 0000000..97317ec
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
+
+// Regression test for issue #5239
+
+fn main() {
+    let x: &fn(int) -> int = |ref x| { x += 1; }; //~ ERROR binary operation + cannot be applied to type `&int`
+}
diff --git a/src/test/compile-fail/keyword-typeof.rs b/src/test/compile-fail/keyword-typeof.rs
new file mode 100644 (file)
index 0000000..c428753
--- /dev/null
@@ -0,0 +1,13 @@
+// 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 main() {
+    let typeof = (); //~ ERROR `typeof` is a reserved keyword
+}
diff --git a/src/test/compile-fail/lint-unused-import-tricky-globs.rs b/src/test/compile-fail/lint-unused-import-tricky-globs.rs
new file mode 100644 (file)
index 0000000..918b11b
--- /dev/null
@@ -0,0 +1,84 @@
+// 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.
+
+#[deny(unused_imports)];
+
+mod A {
+    pub fn p() {}
+}
+mod B {
+    pub fn p() {}
+}
+
+mod C {
+    pub fn q() {}
+}
+mod D {
+    pub fn q() {}
+}
+
+mod E {
+    pub fn r() {}
+}
+mod F {
+    pub fn r() {}
+}
+
+mod G {
+    pub fn s() {}
+    pub fn t() {}
+}
+mod H {
+    pub fn s() {}
+}
+
+mod I {
+    pub fn u() {}
+    pub fn v() {}
+}
+mod J {
+    pub fn u() {}
+    pub fn v() {}
+}
+
+mod K {
+    pub fn w() {}
+}
+mod L {
+    pub fn w() {}
+}
+
+mod m {
+   use A::p; //~ ERROR: unused import
+   use B::p;
+   use C::q; //~ ERROR: unused import
+   use D::*;
+   use E::*; //~ ERROR: unused import
+   use F::r;
+   use G::*;
+   use H::*;
+   use I::*;
+   use J::v;
+   use K::*; //~ ERROR: unused import
+   use L::*;
+
+   #[main]
+   fn my_main() {
+       p();
+       q();
+       r();
+       s();
+       t();
+       u();
+       v();
+       w();
+   }
+}
+
diff --git a/src/test/compile-fail/no-unsafe-self.rs b/src/test/compile-fail/no-unsafe-self.rs
new file mode 100644 (file)
index 0000000..0bf73bb
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+trait A {
+    fn foo(*mut self); //~ ERROR cannot pass self by unsafe pointer
+    fn bar(*self); //~ ERROR cannot pass self by unsafe pointer
+}
+
+struct X;
+impl A for X {
+    fn foo(*mut self) { } //~ ERROR cannot pass self by unsafe pointer
+    fn bar(*self) { } //~ ERROR cannot pass self by unsafe pointer
+}
+
+fn main() { }
diff --git a/src/test/run-fail/test-tasks-invalid-value.rs b/src/test/run-fail/test-tasks-invalid-value.rs
new file mode 100644 (file)
index 0000000..74531de
--- /dev/null
@@ -0,0 +1,19 @@
+// 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.
+
+// This checks that RUST_TEST_TASKS not being 1, 2, ... is detected
+// properly.
+
+// error-pattern:should be a positive integer
+// compile-flags: --test
+// exec-env:RUST_TEST_TASKS=foo
+
+#[test]
+fn do_nothing() {}
index 90e63fc977d866841394f491be862265b95ef0c2..2551d1a5cfcba32455e421de89a3cae23a37c9b8 100644 (file)
 
 #[test]
 fn test_destroy_once() {
-    let p = run::Process::new("echo", [], run::ProcessOptions::new());
-    let mut p = p.unwrap();
+    let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
     p.destroy(); // this shouldn't crash (and nor should the destructor)
 }
 
 #[test]
 fn test_destroy_twice() {
-    let p = run::Process::new("echo", [], run::ProcessOptions::new());
-    let mut p = p.unwrap();
+    let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
     p.destroy(); // this shouldnt crash...
     p.destroy(); // ...and nor should this (and nor should the destructor)
 }
@@ -76,8 +74,7 @@ fn process_exists(pid: libc::pid_t) -> bool {
     }
 
     // this process will stay alive indefinitely trying to read from stdin
-    let p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
-    let mut p = p.unwrap();
+    let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
 
     assert!(process_exists(p.get_id()));
 
diff --git a/src/test/run-pass/issue-5239-2.rs b/src/test/run-pass/issue-5239-2.rs
new file mode 100644 (file)
index 0000000..dac3c95
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+// Regression test for issue #5239
+
+fn main() { 
+    let _f: &fn(int) -> int = |ref x: int| { *x };
+    let foo = 10;
+    assert!(_f(foo) == 10);
+}
diff --git a/src/test/run-pass/nested_item_main.rs b/src/test/run-pass/nested_item_main.rs
new file mode 100644 (file)
index 0000000..5ce05fe
--- /dev/null
@@ -0,0 +1,19 @@
+// 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.
+
+// aux-build:nested_item.rs
+// xfail-fast
+
+extern mod nested_item;
+
+pub fn main() {
+    assert_eq!(2, nested_item::foo::<()>());
+    assert_eq!(2, nested_item::foo::<int>());
+}
index b56cef4277f5742faec632f7a3098b8e4a1e4d80..efa3286e94a19b0634700cab9f224a3a8c3913db 100644 (file)
@@ -21,7 +21,7 @@
 
 /// Trait for visitor that wishes to reflect on data.
 trait movable_ptr {
-    fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void);
+    fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void);
 }
 
 /// Helper function for alignment calculation.
@@ -35,26 +35,26 @@ fn align(size: uint, align: uint) -> uint {
 impl<V:TyVisitor + movable_ptr> ptr_visit_adaptor<V> {
 
     #[inline(always)]
-    pub fn bump(&self, sz: uint) {
+    pub fn bump(&mut self, sz: uint) {
       do self.inner.move_ptr() |p| {
             ((p as uint) + sz) as *c_void
       };
     }
 
     #[inline(always)]
-    pub fn align(&self, a: uint) {
+    pub fn align(&mut self, a: uint) {
       do self.inner.move_ptr() |p| {
             align(p as uint, a) as *c_void
       };
     }
 
     #[inline(always)]
-    pub fn align_to<T>(&self) {
+    pub fn align_to<T>(&mut self) {
         self.align(sys::min_align_of::<T>());
     }
 
     #[inline(always)]
-    pub fn bump_past<T>(&self) {
+    pub fn bump_past<T>(&mut self) {
         self.bump(sys::size_of::<T>());
     }
 
@@ -62,147 +62,147 @@ pub fn bump_past<T>(&self) {
 
 impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
 
-    fn visit_bot(&self) -> bool {
+    fn visit_bot(&mut self) -> bool {
         self.align_to::<()>();
         if ! self.inner.visit_bot() { return false; }
         self.bump_past::<()>();
         true
     }
 
-    fn visit_nil(&self) -> bool {
+    fn visit_nil(&mut self) -> bool {
         self.align_to::<()>();
         if ! self.inner.visit_nil() { return false; }
         self.bump_past::<()>();
         true
     }
 
-    fn visit_bool(&self) -> bool {
+    fn visit_bool(&mut self) -> bool {
         self.align_to::<bool>();
         if ! self.inner.visit_bool() { return false; }
         self.bump_past::<bool>();
         true
     }
 
-    fn visit_int(&self) -> bool {
+    fn visit_int(&mut self) -> bool {
         self.align_to::<int>();
         if ! self.inner.visit_int() { return false; }
         self.bump_past::<int>();
         true
     }
 
-    fn visit_i8(&self) -> bool {
+    fn visit_i8(&mut self) -> bool {
         self.align_to::<i8>();
         if ! self.inner.visit_i8() { return false; }
         self.bump_past::<i8>();
         true
     }
 
-    fn visit_i16(&self) -> bool {
+    fn visit_i16(&mut self) -> bool {
         self.align_to::<i16>();
         if ! self.inner.visit_i16() { return false; }
         self.bump_past::<i16>();
         true
     }
 
-    fn visit_i32(&self) -> bool {
+    fn visit_i32(&mut self) -> bool {
         self.align_to::<i32>();
         if ! self.inner.visit_i32() { return false; }
         self.bump_past::<i32>();
         true
     }
 
-    fn visit_i64(&self) -> bool {
+    fn visit_i64(&mut self) -> bool {
         self.align_to::<i64>();
         if ! self.inner.visit_i64() { return false; }
         self.bump_past::<i64>();
         true
     }
 
-    fn visit_uint(&self) -> bool {
+    fn visit_uint(&mut self) -> bool {
         self.align_to::<uint>();
         if ! self.inner.visit_uint() { return false; }
         self.bump_past::<uint>();
         true
     }
 
-    fn visit_u8(&self) -> bool {
+    fn visit_u8(&mut self) -> bool {
         self.align_to::<u8>();
         if ! self.inner.visit_u8() { return false; }
         self.bump_past::<u8>();
         true
     }
 
-    fn visit_u16(&self) -> bool {
+    fn visit_u16(&mut self) -> bool {
         self.align_to::<u16>();
         if ! self.inner.visit_u16() { return false; }
         self.bump_past::<u16>();
         true
     }
 
-    fn visit_u32(&self) -> bool {
+    fn visit_u32(&mut self) -> bool {
         self.align_to::<u32>();
         if ! self.inner.visit_u32() { return false; }
         self.bump_past::<u32>();
         true
     }
 
-    fn visit_u64(&self) -> bool {
+    fn visit_u64(&mut self) -> bool {
         self.align_to::<u64>();
         if ! self.inner.visit_u64() { return false; }
         self.bump_past::<u64>();
         true
     }
 
-    fn visit_float(&self) -> bool {
+    fn visit_float(&mut self) -> bool {
         self.align_to::<float>();
         if ! self.inner.visit_float() { return false; }
         self.bump_past::<float>();
         true
     }
 
-    fn visit_f32(&self) -> bool {
+    fn visit_f32(&mut self) -> bool {
         self.align_to::<f32>();
         if ! self.inner.visit_f32() { return false; }
         self.bump_past::<f32>();
         true
     }
 
-    fn visit_f64(&self) -> bool {
+    fn visit_f64(&mut self) -> bool {
         self.align_to::<f64>();
         if ! self.inner.visit_f64() { return false; }
         self.bump_past::<f64>();
         true
     }
 
-    fn visit_char(&self) -> bool {
+    fn visit_char(&mut self) -> bool {
         self.align_to::<char>();
         if ! self.inner.visit_char() { return false; }
         self.bump_past::<char>();
         true
     }
 
-    fn visit_estr_box(&self) -> bool {
+    fn visit_estr_box(&mut 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 {
+    fn visit_estr_uniq(&mut 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 {
+    fn visit_estr_slice(&mut 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,
+    fn visit_estr_fixed(&mut self, n: uint,
                         sz: uint,
                         align: uint) -> bool {
         self.align(align);
@@ -211,42 +211,42 @@ fn visit_estr_fixed(&self, n: uint,
         true
     }
 
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
+    fn visit_box(&mut 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 {
+    fn visit_uniq(&mut 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 {
+    fn visit_uniq_managed(&mut 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 {
+    fn visit_ptr(&mut 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 {
+    fn visit_rptr(&mut 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 {
+    fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
         self.align_to::<Vec<()>>();
         // FIXME (#3732): Inner really has to move its own pointers on this one.
         // or else possibly we could have some weird interface wherein we
@@ -256,42 +256,42 @@ fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
         true
     }
 
-    fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
+    fn visit_vec(&mut 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 {
+    fn visit_evec_box(&mut 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 {
+    fn visit_evec_uniq(&mut 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 {
+    fn visit_evec_uniq_managed(&mut 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 {
+    fn visit_evec_slice(&mut 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,
+    fn visit_evec_fixed(&mut 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) {
@@ -301,24 +301,24 @@ fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
         true
     }
 
-    fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+    fn visit_enter_rec(&mut 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,
+    fn visit_rec_field(&mut self, i: uint, name: &str,
                        mtbl: uint, inner: *TyDesc) -> bool {
         if ! self.inner.visit_rec_field(i, name, mtbl, inner) { return false; }
         true
     }
 
-    fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+    fn visit_leave_rec(&mut 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)
+    fn visit_enter_class(&mut self, n_fields: uint, sz: uint, align: uint)
                       -> bool {
         self.align(align);
         if ! self.inner.visit_enter_class(n_fields, sz, align) {
@@ -327,7 +327,7 @@ fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint)
         true
     }
 
-    fn visit_class_field(&self, i: uint, name: &str,
+    fn visit_class_field(&mut self, i: uint, name: &str,
                          mtbl: uint, inner: *TyDesc) -> bool {
         if ! self.inner.visit_class_field(i, name, mtbl, inner) {
             return false;
@@ -335,7 +335,7 @@ fn visit_class_field(&self, i: uint, name: &str,
         true
     }
 
-    fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
+    fn visit_leave_class(&mut self, n_fields: uint, sz: uint, align: uint)
                       -> bool {
         if ! self.inner.visit_leave_class(n_fields, sz, align) {
             return false;
@@ -343,23 +343,23 @@ fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
         true
     }
 
-    fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+    fn visit_enter_tup(&mut 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 {
+    fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool {
         if ! self.inner.visit_tup_field(i, inner) { return false; }
         true
     }
 
-    fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+    fn visit_leave_tup(&mut 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,
+    fn visit_enter_fn(&mut self, purity: uint, proto: uint,
                       n_inputs: uint, retstyle: uint) -> bool {
         if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) {
             return false
@@ -367,17 +367,17 @@ fn visit_enter_fn(&self, purity: uint, proto: uint,
         true
     }
 
-    fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool {
+    fn visit_fn_input(&mut 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 {
+    fn visit_fn_output(&mut 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,
+    fn visit_leave_fn(&mut self, purity: uint, proto: uint,
                       n_inputs: uint, retstyle: uint) -> bool {
         if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) {
             return false;
@@ -385,7 +385,7 @@ fn visit_leave_fn(&self, purity: uint, proto: uint,
         true
     }
 
-    fn visit_enter_enum(&self, n_variants: uint,
+    fn visit_enter_enum(&mut self, n_variants: uint,
                         get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         sz: uint, align: uint)
                      -> bool {
@@ -394,7 +394,7 @@ fn visit_enter_enum(&self, n_variants: uint,
         true
     }
 
-    fn visit_enter_enum_variant(&self, variant: uint,
+    fn visit_enter_enum_variant(&mut self, variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
                                 name: &str) -> bool {
@@ -405,12 +405,12 @@ fn visit_enter_enum_variant(&self, variant: uint,
         true
     }
 
-    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
+    fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool {
         if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
         true
     }
 
-    fn visit_leave_enum_variant(&self, variant: uint,
+    fn visit_leave_enum_variant(&mut self, variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
                                 name: &str) -> bool {
@@ -421,7 +421,7 @@ fn visit_leave_enum_variant(&self, variant: uint,
         true
     }
 
-    fn visit_leave_enum(&self, n_variants: uint,
+    fn visit_leave_enum(&mut self, n_variants: uint,
                         get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         sz: uint, align: uint)
                      -> bool {
@@ -429,38 +429,38 @@ fn visit_leave_enum(&self, n_variants: uint,
         true
     }
 
-    fn visit_trait(&self) -> bool {
+    fn visit_trait(&mut 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 {
+    fn visit_param(&mut self, i: uint) -> bool {
         if ! self.inner.visit_param(i) { return false; }
         true
     }
 
-    fn visit_self(&self) -> bool {
+    fn visit_self(&mut 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 {
+    fn visit_type(&mut self) -> bool {
         if ! self.inner.visit_type() { return false; }
         true
     }
 
-    fn visit_opaque_box(&self) -> bool {
+    fn visit_opaque_box(&mut 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 {
+    fn visit_closure_ptr(&mut self, ck: uint) -> bool {
         self.align_to::<@fn()>();
         if ! self.inner.visit_closure_ptr(ck) { return false; }
         self.bump_past::<@fn()>();
@@ -477,17 +477,17 @@ struct Stuff {
 }
 
 impl my_visitor {
-    pub fn get<T:Clone>(&self, f: &fn(T)) {
+    pub fn get<T:Clone>(&mut self, f: &fn(T)) {
         unsafe {
             f((*(self.ptr1 as *T)).clone());
         }
     }
 
-    pub fn visit_inner(&self, inner: *TyDesc) -> bool {
+    pub fn visit_inner(&mut self, inner: *TyDesc) -> bool {
         unsafe {
             let u = my_visitor(**self);
-            let v = ptr_visit_adaptor::<my_visitor>(Inner {inner: u});
-            visit_tydesc(inner, &v as &TyVisitor);
+            let mut v = ptr_visit_adaptor::<my_visitor>(Inner {inner: u});
+            visit_tydesc(inner, &mut v as &mut TyVisitor);
             true
         }
     }
@@ -496,7 +496,7 @@ pub fn visit_inner(&self, inner: *TyDesc) -> bool {
 struct Inner<V> { inner: V }
 
 impl movable_ptr for my_visitor {
-    fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
+    fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void) {
         self.ptr1 = adjustment(self.ptr1);
         self.ptr2 = adjustment(self.ptr2);
     }
@@ -504,125 +504,125 @@ fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
 
 impl TyVisitor for my_visitor {
 
-    fn visit_bot(&self) -> bool { true }
-    fn visit_nil(&self) -> bool { true }
-    fn visit_bool(&self) -> bool {
+    fn visit_bot(&mut self) -> bool { true }
+    fn visit_nil(&mut self) -> bool { true }
+    fn visit_bool(&mut self) -> bool {
         do self.get::<bool>() |b| {
             self.vals.push(b.to_str());
         };
         true
     }
-    fn visit_int(&self) -> bool {
+    fn visit_int(&mut self) -> bool {
         do self.get::<int>() |i| {
             self.vals.push(i.to_str());
         };
         true
     }
-    fn visit_i8(&self) -> bool { true }
-    fn visit_i16(&self) -> bool { true }
-    fn visit_i32(&self) -> bool { true }
-    fn visit_i64(&self) -> bool { true }
+    fn visit_i8(&mut self) -> bool { true }
+    fn visit_i16(&mut self) -> bool { true }
+    fn visit_i32(&mut self) -> bool { true }
+    fn visit_i64(&mut self) -> bool { true }
 
-    fn visit_uint(&self) -> bool { true }
-    fn visit_u8(&self) -> bool { true }
-    fn visit_u16(&self) -> bool { true }
-    fn visit_u32(&self) -> bool { true }
-    fn visit_u64(&self) -> bool { true }
+    fn visit_uint(&mut self) -> bool { true }
+    fn visit_u8(&mut self) -> bool { true }
+    fn visit_u16(&mut self) -> bool { true }
+    fn visit_u32(&mut self) -> bool { true }
+    fn visit_u64(&mut self) -> bool { true }
 
-    fn visit_float(&self) -> bool { true }
-    fn visit_f32(&self) -> bool { true }
-    fn visit_f64(&self) -> bool { true }
+    fn visit_float(&mut self) -> bool { true }
+    fn visit_f32(&mut self) -> bool { true }
+    fn visit_f64(&mut self) -> bool { true }
 
-    fn visit_char(&self) -> bool { true }
+    fn visit_char(&mut self) -> bool { true }
 
-    fn visit_estr_box(&self) -> bool { true }
-    fn visit_estr_uniq(&self) -> bool { true }
-    fn visit_estr_slice(&self) -> bool { true }
-    fn visit_estr_fixed(&self, _n: uint, _sz: uint,
+    fn visit_estr_box(&mut self) -> bool { true }
+    fn visit_estr_uniq(&mut self) -> bool { true }
+    fn visit_estr_slice(&mut self) -> bool { true }
+    fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
                         _align: uint) -> bool { true }
 
-    fn visit_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_uniq_managed(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_rptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-
-    fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_unboxed_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_uniq_managed(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_slice(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_fixed(&self, _n: uint, _sz: uint, _align: uint,
+    fn visit_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_uniq_managed(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_ptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_rptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+
+    fn visit_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_unboxed_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_uniq_managed(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint,
                         _mtbl: uint, _inner: *TyDesc) -> bool { true }
 
-    fn visit_enter_rec(&self, _n_fields: uint,
+    fn visit_enter_rec(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
-    fn visit_rec_field(&self, _i: uint, _name: &str,
+    fn visit_rec_field(&mut self, _i: uint, _name: &str,
                        _mtbl: uint, inner: *TyDesc) -> bool {
         error!("rec field!");
         self.visit_inner(inner)
     }
-    fn visit_leave_rec(&self, _n_fields: uint,
+    fn visit_leave_rec(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_class(&self, _n_fields: uint,
+    fn visit_enter_class(&mut self, _n_fields: uint,
                          _sz: uint, _align: uint) -> bool { true }
-    fn visit_class_field(&self, _i: uint, _name: &str,
+    fn visit_class_field(&mut self, _i: uint, _name: &str,
                          _mtbl: uint, inner: *TyDesc) -> bool {
         self.visit_inner(inner)
     }
-    fn visit_leave_class(&self, _n_fields: uint,
+    fn visit_leave_class(&mut self, _n_fields: uint,
                          _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_tup(&self, _n_fields: uint,
+    fn visit_enter_tup(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
-    fn visit_tup_field(&self, _i: uint, inner: *TyDesc) -> bool {
+    fn visit_tup_field(&mut self, _i: uint, inner: *TyDesc) -> bool {
         error!("tup field!");
         self.visit_inner(inner)
     }
-    fn visit_leave_tup(&self, _n_fields: uint,
+    fn visit_leave_tup(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_enum(&self, _n_variants: uint,
+    fn visit_enter_enum(&mut self, _n_variants: uint,
                         _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         _sz: uint, _align: uint) -> bool {
         // FIXME (#3732): this needs to rewind between enum variants, or something.
         true
     }
-    fn visit_enter_enum_variant(&self, _variant: uint,
+    fn visit_enter_enum_variant(&mut self, _variant: uint,
                                 _disr_val: int,
                                 _n_fields: uint,
                                 _name: &str) -> bool { true }
-    fn visit_enum_variant_field(&self, _i: uint, _offset: uint, inner: *TyDesc) -> bool {
+    fn visit_enum_variant_field(&mut self, _i: uint, _offset: uint, inner: *TyDesc) -> bool {
         self.visit_inner(inner)
     }
-    fn visit_leave_enum_variant(&self, _variant: uint,
+    fn visit_leave_enum_variant(&mut self, _variant: uint,
                                 _disr_val: int,
                                 _n_fields: uint,
                                 _name: &str) -> bool { true }
-    fn visit_leave_enum(&self, _n_variants: uint,
+    fn visit_leave_enum(&mut self, _n_variants: uint,
                         _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_fn(&self, _purity: uint, _proto: uint,
+    fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
                       _n_inputs: uint, _retstyle: uint) -> bool { true }
-    fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
+    fn visit_fn_input(&mut self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
         true
     }
-    fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
+    fn visit_fn_output(&mut self, _retstyle: uint, _inner: *TyDesc) -> bool {
         true
     }
-    fn visit_leave_fn(&self, _purity: uint, _proto: uint,
+    fn visit_leave_fn(&mut 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 { true }
-    fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
+    fn visit_trait(&mut self) -> bool { true }
+    fn visit_param(&mut self, _i: uint) -> bool { true }
+    fn visit_self(&mut self) -> bool { true }
+    fn visit_type(&mut self) -> bool { true }
+    fn visit_opaque_box(&mut self) -> bool { true }
+    fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
 }
 
 fn get_tydesc_for<T>(_t: T) -> *TyDesc {
@@ -640,12 +640,11 @@ pub fn main() {
         let u = my_visitor(@mut Stuff {ptr1: p,
                                        ptr2: p,
                                        vals: ~[]});
-        let v = ptr_visit_adaptor(Inner {inner: u});
+        let mut v = ptr_visit_adaptor(Inner {inner: u});
         let td = get_tydesc_for(r);
         error!("tydesc sz: %u, align: %u",
                (*td).size, (*td).align);
-        let v = &v as &TyVisitor;
-        visit_tydesc(td, v);
+        visit_tydesc(td, &mut v as &mut TyVisitor);
 
         let r = u.vals.clone();
         for s in r.iter() {
index 1462d8aace130cbe73a31ffe699a91306cabe679..934d6117647df63c9d947c0070a6130f146cb009 100644 (file)
@@ -15,157 +15,150 @@ struct MyVisitor {
 }
 
 impl TyVisitor for MyVisitor {
-    fn visit_bot(&self) -> bool {
+    fn visit_bot(&mut self) -> bool {
         self.types.push(~"bot");
         error!("visited bot type");
         true
     }
-    fn visit_nil(&self) -> bool {
+    fn visit_nil(&mut self) -> bool {
         self.types.push(~"nil");
         error!("visited nil type");
         true
     }
-    fn visit_bool(&self) -> bool {
+    fn visit_bool(&mut self) -> bool {
         self.types.push(~"bool");
         error!("visited bool type");
         true
     }
-    fn visit_int(&self) -> bool {
+    fn visit_int(&mut self) -> bool {
         self.types.push(~"int");
         error!("visited int type");
         true
     }
-    fn visit_i8(&self) -> bool {
+    fn visit_i8(&mut self) -> bool {
         self.types.push(~"i8");
         error!("visited i8 type");
         true
     }
-    fn visit_i16(&self) -> bool {
+    fn visit_i16(&mut self) -> bool {
         self.types.push(~"i16");
         error!("visited i16 type");
         true
     }
-    fn visit_i32(&self) -> bool { true }
-    fn visit_i64(&self) -> bool { true }
+    fn visit_i32(&mut self) -> bool { true }
+    fn visit_i64(&mut self) -> bool { true }
 
-    fn visit_uint(&self) -> bool { true }
-    fn visit_u8(&self) -> bool { true }
-    fn visit_u16(&self) -> bool { true }
-    fn visit_u32(&self) -> bool { true }
-    fn visit_u64(&self) -> bool { true }
+    fn visit_uint(&mut self) -> bool { true }
+    fn visit_u8(&mut self) -> bool { true }
+    fn visit_u16(&mut self) -> bool { true }
+    fn visit_u32(&mut self) -> bool { true }
+    fn visit_u64(&mut self) -> bool { true }
 
-    fn visit_float(&self) -> bool { true }
-    fn visit_f32(&self) -> bool { true }
-    fn visit_f64(&self) -> bool { true }
+    fn visit_float(&mut self) -> bool { true }
+    fn visit_f32(&mut self) -> bool { true }
+    fn visit_f64(&mut self) -> bool { true }
 
-    fn visit_char(&self) -> bool { true }
+    fn visit_char(&mut self) -> bool { true }
 
-    fn visit_estr_box(&self) -> bool { true }
-    fn visit_estr_uniq(&self) -> bool { true }
-    fn visit_estr_slice(&self) -> bool { true }
-    fn visit_estr_fixed(&self,
+    fn visit_estr_box(&mut self) -> bool { true }
+    fn visit_estr_uniq(&mut self) -> bool { true }
+    fn visit_estr_slice(&mut self) -> bool { true }
+    fn visit_estr_fixed(&mut self,
                         _sz: uint, _sz: uint,
                         _align: uint) -> bool { true }
 
-    fn visit_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_uniq_managed(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_rptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_uniq_managed(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_ptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_rptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
 
-    fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_unboxed_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool {
+    fn visit_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_unboxed_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_uniq(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
         self.types.push(~"[");
-        unsafe {
-            visit_tydesc(inner, (&*self) as &TyVisitor);
-        }
+        unsafe { visit_tydesc(inner, &mut *self as &mut TyVisitor); }
         self.types.push(~"]");
         true
     }
-    fn visit_evec_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
+    fn visit_evec_uniq_managed(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
         self.types.push(~"[");
-        unsafe {
-            visit_tydesc(inner, (&*self) as &TyVisitor);
-        }
+        unsafe { visit_tydesc(inner, &mut *self as &mut TyVisitor) };
         self.types.push(~"]");
         true
     }
-    fn visit_evec_slice(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_evec_fixed(&self, _n: uint, _sz: uint, _align: uint,
+    fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint,
                         _mtbl: uint, _inner: *TyDesc) -> bool { true }
 
-    fn visit_enter_rec(&self, _n_fields: uint,
+    fn visit_enter_rec(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
-    fn visit_rec_field(&self, _i: uint, _name: &str,
+    fn visit_rec_field(&mut self, _i: uint, _name: &str,
                        _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_leave_rec(&self, _n_fields: uint,
+    fn visit_leave_rec(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_class(&self, _n_fields: uint,
+    fn visit_enter_class(&mut self, _n_fields: uint,
                          _sz: uint, _align: uint) -> bool { true }
-    fn visit_class_field(&self, _i: uint, _name: &str,
+    fn visit_class_field(&mut self, _i: uint, _name: &str,
                          _mtbl: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_leave_class(&self, _n_fields: uint,
+    fn visit_leave_class(&mut self, _n_fields: uint,
                          _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_tup(&self, _n_fields: uint,
+    fn visit_enter_tup(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
-    fn visit_tup_field(&self, _i: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_leave_tup(&self, _n_fields: uint,
+    fn visit_tup_field(&mut self, _i: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_leave_tup(&mut self, _n_fields: uint,
                        _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_enum(&self, _n_variants: uint,
+    fn visit_enter_enum(&mut self, _n_variants: uint,
                         _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         _sz: uint, _align: uint) -> bool { true }
-    fn visit_enter_enum_variant(&self,
+    fn visit_enter_enum_variant(&mut self,
                                 _variant: uint,
                                 _disr_val: int,
                                 _n_fields: uint,
                                 _name: &str) -> bool { true }
-    fn visit_enum_variant_field(&self, _i: uint, _offset: uint, _inner: *TyDesc) -> bool { true }
-    fn visit_leave_enum_variant(&self,
+    fn visit_enum_variant_field(&mut self, _i: uint, _offset: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_leave_enum_variant(&mut self,
                                 _variant: uint,
                                 _disr_val: int,
                                 _n_fields: uint,
                                 _name: &str) -> bool { true }
-    fn visit_leave_enum(&self,
+    fn visit_leave_enum(&mut self,
                         _n_variants: uint,
                         _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         _sz: uint, _align: uint) -> bool { true }
 
-    fn visit_enter_fn(&self, _purity: uint, _proto: uint,
+    fn visit_enter_fn(&mut 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,
+    fn visit_fn_input(&mut self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_fn_output(&mut self, _retstyle: uint, _inner: *TyDesc) -> bool { true }
+    fn visit_leave_fn(&mut 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 { true }
-    fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
+    fn visit_trait(&mut self) -> bool { true }
+    fn visit_param(&mut self, _i: uint) -> bool { true }
+    fn visit_self(&mut self) -> bool { true }
+    fn visit_type(&mut self) -> bool { true }
+    fn visit_opaque_box(&mut self) -> bool { true }
+    fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
 }
 
-fn visit_ty<T>(v: &TyVisitor) {
-    unsafe {
-        visit_tydesc(get_tydesc::<T>(), v);
-    }
+fn visit_ty<T>(v: &mut MyVisitor) {
+    unsafe { visit_tydesc(get_tydesc::<T>(), v as &mut TyVisitor) }
 }
 
 pub fn main() {
-    let v = @MyVisitor {types: @mut ~[]};
-    let vv = v as @TyVisitor;
-
-    visit_ty::<bool>(vv);
-    visit_ty::<int>(vv);
-    visit_ty::<i8>(vv);
-    visit_ty::<i16>(vv);
-    visit_ty::<~[int]>(vv);
+    let mut v = MyVisitor {types: @mut ~[]};
+
+    visit_ty::<bool>(&mut v);
+    visit_ty::<int>(&mut v);
+    visit_ty::<i8>(&mut v);
+    visit_ty::<i16>(&mut v);
+    visit_ty::<~[int]>(&mut v);
 
     for s in v.types.iter() {
         printfln!("type: %s", (*s).clone());