]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #9313 : brson/rust/relnotes, r=thestinger
authorbors <bors@rust-lang.org>
Thu, 19 Sep 2013 15:40:59 +0000 (08:40 -0700)
committerbors <bors@rust-lang.org>
Thu, 19 Sep 2013 15:40:59 +0000 (08:40 -0700)
261 files changed:
.gitattributes
Makefile.in
doc/rust.md
doc/tutorial-ffi.md
doc/tutorial-rustpkg.md [new file with mode: 0644]
doc/tutorial-tasks.md
doc/tutorial.md
man/rustpkg.1
mk/clean.mk
mk/dist.mk
mk/install.mk
mk/llvm.mk
mk/platform.mk
mk/rt.mk
mk/tests.mk
mk/tools.mk
src/compiletest/compiletest.rs
src/driver/driver.rs
src/etc/mingw-fix-include/README.txt [new file with mode: 0644]
src/etc/mingw-fix-include/bits/c++config.h [new file with mode: 0644]
src/etc/mingw-fix-include/winbase.h [new file with mode: 0644]
src/etc/mingw-fix-include/winsock2.h [new file with mode: 0644]
src/libextra/arc.rs
src/libextra/arena.rs
src/libextra/c_vec.rs
src/libextra/dlist.rs
src/libextra/fileinput.rs
src/libextra/future.rs
src/libextra/getopts.rs
src/libextra/glob.rs
src/libextra/json.rs
src/libextra/num/bigint.rs
src/libextra/rc.rs
src/libextra/rl.rs
src/libextra/task_pool.rs
src/libextra/test.rs
src/libextra/workcache.rs
src/librustc/back/link.rs
src/librustc/driver/driver.rs
src/librustc/front/test.rs
src/librustc/lib/llvm.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/build.rs
src/librustc/middle/trans/builder.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/closure.rs
src/librustc/middle/trans/common.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/context.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/foreign.rs
src/librustc/middle/trans/inline.rs
src/librustc/middle/trans/monomorphize.rs
src/librustc/middle/trans/reflect.rs
src/librustc/rustc.rs
src/librustc/util/common.rs
src/librustdoc/config.rs
src/librustdoc/demo.rs
src/librusti/program.rs
src/librustpkg/api.rs
src/librustpkg/exit_codes.rs [new file with mode: 0644]
src/librustpkg/package_id.rs
src/librustpkg/package_source.rs
src/librustpkg/rustpkg.rs
src/librustpkg/target.rs
src/librustpkg/tests.rs
src/librustpkg/usage.rs
src/librustpkg/util.rs
src/librustpkg/workcache_support.rs
src/libstd/at_vec.rs
src/libstd/borrow.rs
src/libstd/c_str.rs
src/libstd/char.rs
src/libstd/condition.rs
src/libstd/io.rs
src/libstd/libc.rs
src/libstd/logging.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/num/float.rs
src/libstd/num/uint.rs
src/libstd/num/uint_macros.rs
src/libstd/ops.rs
src/libstd/option.rs
src/libstd/os.rs
src/libstd/ptr.rs
src/libstd/rand.rs
src/libstd/reflect_stage0.rs [deleted file]
src/libstd/repr_stage0.rs [deleted file]
src/libstd/rt/args.rs
src/libstd/rt/comm.rs
src/libstd/rt/io/buffered.rs
src/libstd/rt/io/extensions.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 [new file with mode: 0644]
src/libstd/rt/io/process.rs [new file with mode: 0644]
src/libstd/rt/io/support.rs
src/libstd/rt/kill.rs
src/libstd/rt/local_heap.rs
src/libstd/rt/mod.rs
src/libstd/rt/rc.rs
src/libstd/rt/rtio.rs
src/libstd/rt/sched.rs
src/libstd/rt/stack.rs
src/libstd/rt/task.rs
src/libstd/rt/thread.rs
src/libstd/rt/uv/file.rs
src/libstd/rt/uv/mod.rs
src/libstd/rt/uv/pipe.rs [new file with mode: 0644]
src/libstd/rt/uv/process.rs [new file with mode: 0644]
src/libstd/rt/uv/uvio.rs
src/libstd/rt/uv/uvll.rs
src/libstd/run.rs
src/libstd/std.rs
src/libstd/str.rs
src/libstd/sys.rs
src/libstd/task/spawn.rs
src/libstd/unstable/atomics.rs
src/libstd/unstable/dynamic_lib.rs
src/libstd/unstable/finally.rs
src/libstd/unstable/intrinsics.rs
src/libstd/unstable/sync.rs
src/libstd/util.rs
src/libstd/vec.rs
src/libsyntax/ast_util.rs
src/libsyntax/diagnostic.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/bytes.rs
src/libsyntax/ext/env.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/format.rs
src/libsyntax/parse/lexer.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pp.rs
src/libsyntax/print/pprust.rs
src/rt/rust_builtin.cpp
src/rt/rust_run_program.cpp [deleted file]
src/rt/rust_uv.cpp
src/rt/rustrt.def.in
src/rustdoc_ng/clean.rs
src/rustdoc_ng/lib.rs [deleted file]
src/rustdoc_ng/main.rs [deleted file]
src/rustdoc_ng/rustdoc_ng.rs [new file with mode: 0644]
src/snapshots.txt
src/test/auxiliary/issue-2526.rs
src/test/auxiliary/issue-3012-1.rs
src/test/auxiliary/issue-4208-cc.rs [new file with mode: 0644]
src/test/auxiliary/issue2170lib.rs
src/test/auxiliary/moves_based_on_type_lib.rs
src/test/auxiliary/xcrate_address_insignificant.rs [new file with mode: 0644]
src/test/auxiliary/xcrate_static_addresses.rs
src/test/bench/shootout-pfib.rs
src/test/bench/task-perf-alloc-unwind.rs
src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-1.rs
src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-2.rs
src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-3.rs
src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-4.rs
src/test/compile-fail/bind-by-move-no-sub-bindings.rs
src/test/compile-fail/block-must-not-have-result-res.rs
src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs
src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs
src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs
src/test/compile-fail/copy-a-resource.rs
src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs
src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs
src/test/compile-fail/drop-on-non-struct.rs
src/test/compile-fail/explicit-call-to-dtor.rs
src/test/compile-fail/explicit-call-to-supertrait-dtor.rs
src/test/compile-fail/functional-struct-update-noncopyable.rs
src/test/compile-fail/issue-2548.rs
src/test/compile-fail/issue-2823.rs
src/test/compile-fail/issue-3214.rs
src/test/compile-fail/kindck-destructor-owned.rs
src/test/compile-fail/no-send-res-ports.rs
src/test/compile-fail/noncopyable-class.rs
src/test/compile-fail/pinned-deep-copy.rs
src/test/compile-fail/repeat-to-run-dtor-twice.rs
src/test/compile-fail/unique-object-noncopyable.rs
src/test/compile-fail/unique-pinned-nocopy.rs
src/test/compile-fail/unique-vec-res.rs
src/test/compile-fail/use-after-move-self-based-on-type.rs
src/test/compile-fail/vec-res-add.rs
src/test/debug-info/boxed-struct.rs
src/test/debug-info/c-style-enum-in-composite.rs
src/test/debug-info/packed-struct-with-destructor.rs
src/test/debug-info/struct-with-destructor.rs
src/test/pretty/path-type-bounds.rs [new file with mode: 0644]
src/test/run-fail/issue-2061.rs
src/test/run-fail/morestack2.rs
src/test/run-fail/morestack3.rs
src/test/run-fail/morestack4.rs
src/test/run-fail/rt-set-exit-status-fail2.rs
src/test/run-fail/too-much-recursion-unwinding.rs
src/test/run-fail/unwind-box-res.rs
src/test/run-fail/unwind-resource-fail.rs
src/test/run-fail/unwind-resource-fail2.rs
src/test/run-fail/unwind-resource-fail3.rs
src/test/run-pass/attr-no-drop-flag-size.rs
src/test/run-pass/borrowck-unary-move-2.rs
src/test/run-pass/class-attributes-1.rs
src/test/run-pass/class-attributes-2.rs
src/test/run-pass/class-dtor.rs
src/test/run-pass/cond-macro-no-default.rs [deleted file]
src/test/run-pass/cond-macro.rs [deleted file]
src/test/run-pass/drop-trait-generic.rs
src/test/run-pass/drop-trait.rs
src/test/run-pass/extern-pass-TwoU64s-ref.rs
src/test/run-pass/extern-pass-TwoU64s.rs
src/test/run-pass/extern-return-TwoU64s.rs
src/test/run-pass/getopts_ref.rs
src/test/run-pass/ifmt.rs
src/test/run-pass/init-res-into-things.rs
src/test/run-pass/issue-2487-a.rs
src/test/run-pass/issue-2708.rs
src/test/run-pass/issue-2718.rs
src/test/run-pass/issue-2735-2.rs
src/test/run-pass/issue-2735-3.rs
src/test/run-pass/issue-2895.rs
src/test/run-pass/issue-3220.rs
src/test/run-pass/issue-3563-3.rs
src/test/run-pass/issue-4208.rs [new file with mode: 0644]
src/test/run-pass/issue-4252.rs
src/test/run-pass/issue-4735.rs
src/test/run-pass/issue-5008-borrowed-traitobject-method-call.rs [new file with mode: 0644]
src/test/run-pass/issue-6341.rs
src/test/run-pass/issue-6344-let.rs
src/test/run-pass/issue-6344-match.rs
src/test/run-pass/issue-7519-match-unit-in-arg.rs [new file with mode: 0644]
src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs [new file with mode: 0644]
src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs [new file with mode: 0644]
src/test/run-pass/issue-979.rs
src/test/run-pass/nested-enum-same-names.rs [new file with mode: 0644]
src/test/run-pass/newtype-struct-drop-run.rs
src/test/run-pass/newtype-struct-with-dtor.rs
src/test/run-pass/nul-characters.rs [new file with mode: 0644]
src/test/run-pass/option-unwrap.rs
src/test/run-pass/resource-assign-is-not-copy.rs
src/test/run-pass/resource-cycle.rs
src/test/run-pass/resource-cycle2.rs
src/test/run-pass/resource-cycle3.rs
src/test/run-pass/resource-destruct.rs
src/test/run-pass/resource-in-struct.rs
src/test/run-pass/send-resource.rs
src/test/run-pass/struct-literal-dtor.rs
src/test/run-pass/struct-return.rs
src/test/run-pass/task-killjoin-rsrc.rs
src/test/run-pass/type-param-constraints.rs
src/test/run-pass/unique-pinned-nocopy-2.rs
src/test/run-pass/unit-like-struct-drop-run.rs
src/test/run-pass/unwind-resource.rs
src/test/run-pass/unwind-resource2.rs
src/test/run-pass/vec-slice-drop.rs
src/test/run-pass/xcrate-address-insignificant.rs [new file with mode: 0644]
src/test/run-pass/xcrate-static-addresses.rs

index 10505d47e6c5d6d092d1b2fa619760df8055bc1a..70b2a5cd90ea032c72b119633e6d5f6b94aea76b 100644 (file)
@@ -1,6 +1,6 @@
 [attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
 
-* text=auto
+* text eol=lf
 *.cpp rust
 *.h rust
 *.rs rust
@@ -8,6 +8,3 @@ src/rt/msvc/* -whitespace
 src/rt/vg/* -whitespace
 src/rt/linenoise/* -whitespace
 src/rt/jemalloc/**/* -whitespace
-src/rt/jemalloc/include/jemalloc/jemalloc.h.in text eol=lf
-src/rt/jemalloc/include/jemalloc/jemalloc_defs.h.in text eol=lf
-src/rt/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in text eol=lf
index 171ce8f19253d57014b80c7962dbc03c67143faa..a1c276cd3d20395715570a8f66fa3b16a1ae160b 100644 (file)
@@ -442,6 +442,7 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
        $$(TSREQ$(1)_T_$(2)_H_$(3)) \
        $$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
        $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
+       $$(HBIN$(1)_H_$(3))/rustdoc_ng$$(X_$(3)) \
        $$(HBIN$(1)_H_$(3))/rusti$$(X_$(3)) \
        $$(HBIN$(1)_H_$(3))/rust$$(X_$(3)) \
        $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
index 8e1028b472737d6399eb2e379b2a06c2708478a8..d10238c1483377c382c6af22122418ad39853803 100644 (file)
@@ -248,7 +248,7 @@ string_body : non_double_quote
             | '\x5c' [ '\x22' | common_escape ] ;
 
 common_escape : '\x5c'
-              | 'n' | 'r' | 't'
+              | 'n' | 'r' | 't' | '0'
               | 'x' hex_digit 2
               | 'u' hex_digit 4
               | 'U' hex_digit 8 ;
@@ -962,24 +962,76 @@ parameters to allow methods with that trait to be called on values
 of that type.
 
 
-#### Unsafe functions
-
-Unsafe functions are those containing unsafe operations that are not contained in an [`unsafe` block](#unsafe-blocks).
-Such a function must be prefixed with the keyword `unsafe`.
+#### Unsafety
 
 Unsafe operations are those that potentially violate the memory-safety guarantees of Rust's static semantics.
-Specifically, the following operations are considered unsafe:
+
+The following language level features cannot be used in the safe subset of Rust:
 
   - Dereferencing a [raw pointer](#pointer-types).
-  - Casting a [raw pointer](#pointer-types) to a safe pointer type.
-  - Calling an unsafe function.
+  - Calling an unsafe function (including an intrinsic or foreign function).
 
-##### Unsafe blocks
+##### Unsafe functions
 
-A block of code can also be prefixed with the `unsafe` keyword, to permit a sequence of unsafe operations in an otherwise-safe function.
-This facility exists because the static semantics of Rust are a necessary approximation of the dynamic semantics.
-When a programmer has sufficient conviction that a sequence of unsafe operations is actually safe, they can encapsulate that sequence (taken as a whole) within an `unsafe` block. The compiler will consider uses of such code "safe", to the surrounding context.
+Unsafe functions are functions that are not safe in all contexts and/or for all possible inputs.
+Such a function must be prefixed with the keyword `unsafe`.
+
+##### Unsafe blocks
 
+A block of code can also be prefixed with the `unsafe` keyword, to permit calling `unsafe` functions
+or dereferencing raw pointers within a safe function.
+
+When a programmer has sufficient conviction that a sequence of potentially unsafe operations is
+actually safe, they can encapsulate that sequence (taken as a whole) within an `unsafe` block. The
+compiler will consider uses of such code safe, in the surrounding context.
+
+Unsafe blocks are used to wrap foreign libraries, make direct use of hardware or implement features
+not directly present in the language. For example, Rust provides the language features necessary to
+implement memory-safe concurrency in the language but the implementation of tasks and message
+passing is in the standard library.
+
+Rust's type system is a conservative approximation of the dynamic safety requirements, so in some
+cases there is a performance cost to using safe code.  For example, a doubly-linked list is not a
+tree structure and can only be represented with managed or reference-counted pointers in safe code.
+By using `unsafe` blocks to represent the reverse links as raw pointers, it can be implemented with
+only owned pointers.
+
+##### Behavior considered unsafe
+
+This is a list of behavior which is forbidden in all Rust code. Type checking provides the guarantee
+that these issues are never caused by safe code. An `unsafe` block or function is responsible for
+never invoking this behaviour or exposing an API making it possible for it to occur in safe code.
+
+* Data races
+* Dereferencing a null/dangling raw pointer
+* Mutating an immutable value/reference, if it is not marked as non-`Freeze`
+* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values) (uninitialized) memory
+* Breaking the [pointer aliasing rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules)
+  with raw pointers (a subset of the rules used by C)
+* Invoking undefined behavior via compiler intrinsics:
+    * Indexing outside of the bounds of an object with `std::ptr::offset` (`offset` intrinsic), with
+      the exception of one byte past the end which is permitted.
+    * Using `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64` instrinsics) on
+      overlapping buffers
+* Invalid values in primitive types, even in private fields/locals:
+    * Dangling/null pointers in non-raw pointers, or slices
+    * A value other than `false` (0) or `true` (1) in a `bool`
+    * A discriminant in an `enum` not included in the type definition
+    * A value in a `char` which is a surrogate or above `char::MAX`
+    * non-UTF-8 byte sequences in a `str`
+
+##### Behaviour not considered unsafe
+
+This is a list of behaviour not considered *unsafe* in Rust terms, but that may be undesired.
+
+* Deadlocks
+* Reading data from private fields (`std::repr`, `format!("{:?}", x)`)
+* Leaks due to reference count cycles, even in the global heap
+* Exiting without calling destructors
+* Sending signals
+* Accessing/modifying the file system
+* Unsigned integer overflow (well-defined as wrapping)
+* Signed integer overflow (well-defined as two's complement representation wrapping)
 
 #### Diverging functions
 
index e3c1c48944458190c6ac6ff6f424ecedc1862fc8..3deaeb14b83f1b389c7f1ca8d4ee13de6e154ba3 100644 (file)
@@ -321,7 +321,7 @@ impl<T: Send> Unique<T> {
 
 #[unsafe_destructor]
 impl<T: Send> Drop for Unique<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment];
         #[inline(never)];
         
diff --git a/doc/tutorial-rustpkg.md b/doc/tutorial-rustpkg.md
new file mode 100644 (file)
index 0000000..43d8309
--- /dev/null
@@ -0,0 +1,223 @@
+% Rust Packaging Tutorial
+
+# Introduction
+
+Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to
+package up your Rust code and share it with other people. This tutorial will
+get you started on all of the concepts and commands you need to give the gift
+of Rust code to someone else.
+
+## Installing External Packages
+
+First, let's try to use an external package somehow. I've made a sample package
+called `hello` to demonstrate how to do so.  Here's how `hello` is used:
+
+~~~~
+extern mod hello;
+
+fn main() {
+    hello::world();
+}
+~~~~
+
+Easy! But if you try to compile this, you'll get an error:
+
+~~~~ {.notrust}
+$ rustc main.rs 
+main.rs:1:0: 1:17 error: can't find crate for `hello`
+main.rs:1 extern mod hello;
+          ^~~~~~~~~~~~~~~~~
+
+~~~~
+
+This makes sense, as we haven't gotten it from anywhere yet!  Luckily for us,
+`rustpkg` has an easy way to fetch others' code: the `install` command. It's
+used like this:
+
+~~~ {.notrust}
+$ rustpkg install pkg_id
+~~~
+
+This will install a package named 'pkg_id' into your current Rust environment.
+I called it 'pkg_id' in this example because `rustpkg` calls this a 'package
+identifier.' When using it with an external package like this, it's often a
+URI fragment.  You see, Rust has no central authority for packages. You can
+build your own `hello` library if you want, and that's fine. We'd both host
+them in different places and different projects would rely on whichever version
+they preferred.
+
+To install the `hello` library, simply run this in your terminal:
+
+~~~ {.notrust}
+$ rustpkg install github.com/steveklabnik/hello
+~~~
+
+You should see a message that looks like this:
+
+~~~ {.notrust}
+note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust
+~~~
+
+Now, compiling our example should work:
+
+~~~ {.notrust}
+$ rustc main.rs
+$ ./main 
+Hello, world.
+~~~
+
+Simple! That's all it takes.
+
+## Workspaces
+
+Before we can talk about how to make packages of your own, you have to
+understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply
+a directory that has certain sub-directories that `rustpkg` expects. Different
+Rust projects will go into different workspaces.
+
+A workspace consists of any directory that has the following
+directories:
+
+* `src`: The directory where all the source code goes.
+* `build`: This directory contains all of the build output.
+* `lib`: The directory where any libraries distributed with the package go.
+* `bin`: This directory holds any binaries distributed with the package.
+
+There are also default file names you'll want to follow as well:
+
+* `main.rs`: A file that's going to become an executable.
+* `lib.rs`: A file that's going to become a library.
+
+## Building your own Package
+
+Now that you've got workspaces down, let's build your own copy of `hello`. Go
+to wherever you keep your personal projects, and let's make all of the
+directories we'll need. I'll refer to this personal project directory as
+`~/src` for the rest of this tutorial.
+
+### Creating our workspace
+
+~~~ {.notrust}
+$ cd ~/src
+$ mkdir -p hello/src/hello
+$ cd hello
+~~~
+
+Easy enough! Let's do one or two more things that are nice to do:
+
+~~~ {.notrust}
+$ git init .
+$ cat > README.md
+# hello
+
+A simple package for Rust.
+
+## Installation
+
+```
+$ rustpkg install github.com/YOUR_USERNAME/hello
+```
+^D
+$ cat > .gitignore
+.rust
+build
+^D
+$ git commit -am "Initial commit."
+~~~
+
+If you're not familliar with the `cat >` idiom, it will make files with the
+text you type inside. Control-D (`^D`) ends the text for the file.
+
+Anyway, we've got a README and a `.gitignore`. Let's talk about that
+`.gitignore` for a minute: we are ignoring two directories, `build` and
+`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't
+want to check those into a repository. `.rust` is a directory that `rustpkg`
+uses to keep track of its own settings, as well as the source code of any other
+external packages that this workspace uses. This is where that `rustpkg
+install` puts all of its files. Those are also not to go into our repository,
+so we ignore it all as well.
+
+Next, let's add a source file:
+
+~~~
+#[desc = "A hello world Rust package."];
+#[license = "MIT"];
+
+pub fn world() {
+    println("Hello, world.");
+}
+~~~
+
+Put this into `src/hello/lib.rs`. Let's talk about each of these attributes:
+
+### Crate attributes for packages
+
+`license` is equally simple: the license we want this code to have. I chose MIT
+here, but you should pick whatever license makes the most sense for you.
+
+`desc` is a description of the package and what it does. This should just be a
+sentence or two.
+
+### Building your package
+
+Building your package is simple:
+
+~~~ {.notrust}
+$ rustpkg build hello
+~~~
+
+This will compile `src/hello/lib.rs` into a library. After this process
+completes, you'll want to check out `build`:
+
+~~~ {.notrust}
+$ ls build/x86_64-unknown-linux-gnu/hello/
+libhello-ed8619dad9ce7d58-0.1.0.so
+~~~
+
+This directory naming structure is called a 'build triple,' and is because I'm
+on 64 bit Linux. Yours may differ based on platform.
+
+You'll also notice that `src/hello/lib.rs` turned into
+`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the
+library name, a hash of its content, and the version.
+
+Now that your library builds, you'll want to commit:
+
+~~~ {.notrust}
+$ git add src
+$ git commit -m "Adding source code."
+~~~
+
+If you're using GitHub, after creating the project, do this:
+
+~~~ {.notrust}
+$ git remote add origin git@github.com:YOUR_USERNAME/hello.git
+$ git push origin -u master
+~~~
+
+Now you can install and use it! Go anywhere else in your filesystem:
+
+~~~ {.notrust}
+$ cd ~/src/foo
+$ rustpkg install github/YOUR_USERNAME/hello
+WARNING: The Rust package manager is experimental and may be unstable
+note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust
+~~~
+
+That's it!
+
+## More resources
+
+There's a lot more going on with `rustpkg`, this is just to get you started.
+Check out [the rustpkg manual](rustpkg.html) for the full details on how to
+customize `rustpkg`.
+
+A tag was created on GitHub specifically for `rustpkg`-related issues. You can
+[see all the Issues for rustpkg
+here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open),
+with bugs as well as new feature plans. `rustpkg` is still under development,
+and so may be a bit flaky at the moment.
+
+You may also want to check out [this blog
+post](http://tim.dreamwidth.org/1820526.html), which contains some of the early
+design decisions and justifications.
index 18f35cf39a8a24895f1067949f41216c3a403a0d..aa63a0112d029b5b02a1630d0bd67efd0c4da662 100644 (file)
@@ -47,8 +47,7 @@ concurrency at this writing:
 
 * [`std::task`] - All code relating to tasks and task scheduling,
 * [`std::comm`] - The message passing interface,
-* [`std::pipes`] - The underlying messaging infrastructure,
-* [`extra::comm`] - Additional messaging types based on `std::pipes`,
+* [`extra::comm`] - Additional messaging types based on `std::comm`,
 * [`extra::sync`] - More exotic synchronization tools, including locks,
 * [`extra::arc`] - The Arc (atomically reference counted) type,
   for safely sharing immutable data,
@@ -56,7 +55,6 @@ concurrency at this writing:
 
 [`std::task`]: std/task.html
 [`std::comm`]: std/comm.html
-[`std::pipes`]: std/pipes.html
 [`extra::comm`]: extra/comm.html
 [`extra::sync`]: extra/sync.html
 [`extra::arc`]: extra/arc.html
@@ -125,7 +123,7 @@ receiving messages. Pipes are low-level communication building-blocks and so
 come in a variety of forms, each one appropriate for a different use case. In
 what follows, we cover the most commonly used varieties.
 
-The simplest way to create a pipe is to use the `pipes::stream`
+The simplest way to create a pipe is to use the `comm::stream`
 function to create a `(Port, Chan)` pair. In Rust parlance, a *channel*
 is a sending endpoint of a pipe, and a *port* is the receiving
 endpoint. Consider the following example of calculating two results
index 637dbb10c23559616db7121f659a5cd804356e0d..d9b55ba4d956510913c9049f849014e2a9288971 100644 (file)
@@ -1898,7 +1898,7 @@ struct TimeBomb {
 }
 
 impl Drop for TimeBomb {
-    fn drop(&self) {
+    fn drop(&mut self) {
         for _ in range(0, self.explosivity) {
             println("blam!");
         }
@@ -2979,6 +2979,7 @@ tutorials on individual topics.
 * [The foreign function interface][ffi]
 * [Containers and iterators](tutorial-container.html)
 * [Error-handling and Conditions](tutorial-conditions.html)
+* [Packaging up Rust code](rustpkg)
 
 There is further documentation on the [wiki], however those tend to be even more out of date as this document.
 
@@ -2986,6 +2987,7 @@ There is further documentation on the [wiki], however those tend to be even more
 [tasks]: tutorial-tasks.html
 [macros]: tutorial-macros.html
 [ffi]: tutorial-ffi.html
+[rustpkg]: tutorial-rustpkg.html
 
 [wiki]: https://github.com/mozilla/rust/wiki/Docs
 
index a3178e616c6739536a141afd37552db037d5c2be..09564e86779e8acfa05d03152fd29203f8167b79 100644 (file)
@@ -11,6 +11,8 @@ This tool is a package manager for applications written in the Rust language,
 available at <\fBhttps://www.rust-lang.org\fR>. It provides commands to build,
 install and test Rust programs.
 
+\fBrustpkg\fR is still a work in progress. See \fBdoc/rustpkg.md\fR in the Rust source distribution for future plans.
+
 .SH COMMANDS
 
 .TP
@@ -25,10 +27,6 @@ Remove all generated files from the \fIbuild\fR directory in the target's worksp
 Builds the specified target, and all its dependencies, and then installs the
 build products into the \fIlib\fR and \fIbin\fR directories of their respective
 workspaces.
-.TP
-\fBtest\fR
-Builds the module called \fItest.rs\fR in the specified workspace, and then runs
-the resulting executable in test mode.
 
 .SS "BUILD COMMAND"
 
@@ -58,20 +56,9 @@ of the first entry in RUST_PATH.
 
 Examples:
 
-    $ rustpkg install git://github.com/mozilla/servo.git#1.2
+    $ rustpkg install github.com/mozilla/servo.git#1.2
     $ rustpkg install rust-glfw
 
-.SS "TEST COMMAND"
-
-    rustpkg test \fI[pkgname]\fR
-
-The test command is a shortcut for the command line:
-
-    $ rustc --test <filename> -o <filestem>test~ && ./<filestem>test~
-
-Note the suffix on the output filename (the word "test" followed by a tilde),
-which should ensure the file does not clash with a user-generated files.
-
 .SH "ENVIRONMENT"
 
 .TP
@@ -186,7 +173,7 @@ rust, rustc, rustdoc, rusti
 See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
 
 .SH "AUTHOR"
-See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare
+See \fBAUTHORS.txt\fR in the Rust source distribution. Graydon Hoare
 <\fIgraydon@mozilla.com\fR> is the project leader.
 
 .SH "COPYRIGHT"
index 5e8d9835db20f2b80d98542e2d5563a36b122964..30ec6b15bfefe701b14e586a5b2607ff9311277b 100644 (file)
@@ -68,6 +68,7 @@ clean$(1)_H_$(2):
        $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X_$(2))
        $(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X_$(2))
        $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X_$(2))
+       $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc_ng$(X_$(2))
        $(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X_$(2))
        $(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
        $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
@@ -105,6 +106,7 @@ clean$(1)_T_$(2)_H_$(3):
        $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X_$(2))
        $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X_$(2))
        $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X_$(2))
+       $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc_ng$(X_$(2))
        $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rusti$(X_$(2))
        $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
        $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
index 4a980edf7673141df16ae7895f9c14c37e9b5f7e..34230e6a5aaff3d143ad3b6fa50e7d3e0a130ab8 100644 (file)
@@ -39,6 +39,7 @@ PKG_FILES := \
       libsyntax                                \
       rt                                       \
       librustdoc                               \
+      rustdoc_ng                               \
       rustllvm                                 \
       snapshots.txt                            \
       test)                                    \
index bc4633b8225c4b6d8b46abbd98a082c457e288e2..3989e4f8119c8de74fa23db457bfba30e3edb3fb 100644 (file)
@@ -140,6 +140,7 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE))
        $(Q)$(call INSTALL,$(HB2),$(PHB),rustc$(X_$(CFG_BUILD_TRIPLE)))
        $(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD_TRIPLE)))
        $(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD_TRIPLE)))
+       $(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc_ng$(X_$(CFG_BUILD_TRIPLE)))
        $(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X_$(CFG_BUILD_TRIPLE)))
        $(Q)$(call INSTALL,$(HB2),$(PHB),rust$(X_$(CFG_BUILD_TRIPLE)))
        $(Q)$(call INSTALL_LIB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE)))
@@ -171,6 +172,7 @@ uninstall:
        $(Q)rm -f $(PHB)/rusti$(X_$(CFG_BUILD_TRIPLE))
        $(Q)rm -f $(PHB)/rust$(X_$(CFG_BUILD_TRIPLE))
        $(Q)rm -f $(PHB)/rustdoc$(X_$(CFG_BUILD_TRIPLE))
+       $(Q)rm -f $(PHB)/rustdoc_ng$(X_$(CFG_BUILD_TRIPLE))
        $(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))
        $(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))
        $(Q)for i in \
@@ -180,6 +182,7 @@ uninstall:
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE))) \
+          $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOCNG_GLOB_$(CFG_BUILD_TRIPLE))) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE))) \
           $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE))) \
         ; \
index 9e024ffa9f46e3de07f3238fb9bf3d068795a917..9de04bed59800d74d31ce012391ee0097543d130 100644 (file)
@@ -28,7 +28,7 @@ LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
 
 $$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
        @$$(call E, make: llvm)
-       $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV)
+       $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV_$(1))
        $$(Q)touch $$(LLVM_CONFIG_$(1))
 endif
 
index 6ee5420664d8e1c819efa0bfe8a000519b6a6a0d..2956c6cd251e61f62e7ff36b3edfac07b3a1aa96 100644 (file)
@@ -47,8 +47,11 @@ else
   CFG_GCCISH_CFLAGS += -O2
 endif
 
+# The soname thing is for supporting a statically linked jemalloc.
+# see https://blog.mozilla.org/jseward/2012/06/05/valgrind-now-supports-jemalloc-builds-directly/
 ifdef CFG_VALGRIND
   CFG_VALGRIND += --error-exitcode=100 \
+                  --soname-synonyms=somalloc=NONE \
                   --quiet \
                   --suppressions=$(CFG_SRC_DIR)src/etc/x86.supp \
                   $(OS_SUPP)
@@ -340,6 +343,7 @@ CFG_PATH_MUNGE_mips-unknown-linux-gnu := true
 CFG_LDPATH_mips-unknown-linux-gnu :=
 CFG_RUN_mips-unknown-linux-gnu=
 CFG_RUN_TARG_mips-unknown-linux-gnu=
+RUSTC_FLAGS_mips-unknown-linux-gnu := --linker=$(CXX_mips-unknown-linux-gnu) --target-cpu mips32r2 --target-feature +mips32r2,+o32
 
 # i686-pc-mingw32 configuration
 CC_i686-pc-mingw32=$(CC)
@@ -349,7 +353,7 @@ AR_i686-pc-mingw32=$(AR)
 CFG_LIB_NAME_i686-pc-mingw32=$(1).dll
 CFG_LIB_GLOB_i686-pc-mingw32=$(1)-*.dll
 CFG_LIB_DSYM_GLOB_i686-pc-mingw32=$(1)-*.dylib.dSYM
-CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -m32 -march=i686 -D_WIN32_WINNT=0x0600
+CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -m32 -march=i686 -D_WIN32_WINNT=0x0600 -I$(CFG_SRC_DIR)src/etc/mingw-fix-include
 CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti
 CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g -m32
 CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 :=
@@ -358,6 +362,7 @@ CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
 CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def
 CFG_INSTALL_NAME_i686-pc-mingw32 =
 CFG_LIBUV_LINK_FLAGS_i686-pc-mingw32 := -lWs2_32 -lpsapi -liphlpapi
+CFG_LLVM_BUILD_ENV_i686-pc-mingw32 := CPATH=$(CFG_SRC_DIR)src/etc/mingw-fix-include
 CFG_EXE_SUFFIX_i686-pc-mingw32 := .exe
 CFG_WINDOWSY_i686-pc-mingw32 := 1
 CFG_UNIXY_i686-pc-mingw32 :=
@@ -476,7 +481,7 @@ define CFG_MAKE_TOOLCHAIN
         $$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2)        \
         $$(call CFG_INSTALL_NAME_$(1),$$(4))
 
-  ifneq ($(HOST_$(1)),arm)
+  ifeq ($$(findstring $(HOST_$(1)),arm mips),)
 
   # We're using llvm-mc as our assembler because it supports
   # .cfi pseudo-ops on mac
@@ -488,7 +493,7 @@ define CFG_MAKE_TOOLCHAIN
                     -o=$$(1)
   else
 
-  # For the ARM crosses, use the toolchain assembler
+  # For the ARM and MIPS crosses, use the toolchain assembler
   # XXX: We should be able to use the LLVM assembler
   CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
 
index 35ee42f9cb4ea08d61f190614462bae4bff80dcf..d1a4b2bc87a2c9f9f5af109d8008c47237b38056 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -24,7 +24,7 @@
 # working under these assumptions).
 
 # Hack for passing flags into LIBUV, see below.
-LIBUV_FLAGS_i386 = -m32 -fPIC
+LIBUV_FLAGS_i386 = -m32 -fPIC -I$(S)src/etc/mingw-fix-include
 LIBUV_FLAGS_x86_64 = -m64 -fPIC
 ifeq ($(OSTYPE_$(1)), linux-androideabi)
 LIBUV_FLAGS_arm = -fPIC -DANDROID -std=gnu99
@@ -71,7 +71,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
               rt/sync/lock_and_signal.cpp \
               rt/sync/rust_thread.cpp \
               rt/rust_builtin.cpp \
-              rt/rust_run_program.cpp \
               rt/rust_rng.cpp \
               rt/rust_upcall.cpp \
               rt/rust_uv.cpp \
index c6b4c9da37afa82a50c2603bfedc538d52d560b1..28bbddc787f450582b8388a46d6d1c4d981ae9a7 100644 (file)
@@ -15,7 +15,7 @@
 
 # The names of crates that must be tested
 TEST_TARGET_CRATES = std extra
-TEST_HOST_CRATES = rust rusti rustpkg rustc rustdoc syntax
+TEST_HOST_CRATES = rust rusti rustpkg rustc rustdoc rustdocng syntax
 TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
 
 # Markdown files under doc/ that should have their code extracted and run
@@ -393,6 +393,14 @@ $(3)/stage$(1)/test/rustdoctest-$(2)$$(X_$(2)):                                    \
        @$$(call E, compile_and_link: $$@)
        $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
 
+$(3)/stage$(1)/test/rustdocngtest-$(2)$$(X_$(2)):                          \
+               $$(RUSTDOCNG_LIB) $$(RUSTDOCNG_INPUTS)          \
+               $$(SREQ$(1)_T_$(2)_H_$(3)) \
+               $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
+               $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
+       @$$(call E, compile_and_link: $$@)
+       $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
+
 endef
 
 $(foreach host,$(CFG_HOST_TRIPLES), \
index 848fa8447b693b6f3879f284a526aff64524ace2..212b7e570f7820ad1bf5a175bf099d959921c5a0 100644 (file)
@@ -25,7 +25,7 @@ RUSTDOC_INPUTS := $(wildcard $(S)src/librustdoc/*.rs)
 
 # rustdoc_ng, the next generation documentation tool
 
-RUSTDOCNG_LIB := $(S)src/rustdoc_ng/lib.rs
+RUSTDOCNG_LIB := $(S)src/rustdoc_ng/rustdoc_ng.rs
 RUSTDOCNG_INPUTS := $(wildcard $(S)src/rustdoc_ng/*.rs)
 
 # Rusti, the JIT REPL
@@ -208,6 +208,14 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOCNG_$(4)):                                      \
                $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOCNG_DSYM_GLOB_$(4))) \
                $$(HLIB$(2)_H_$(4))
 
+$$(HBIN$(2)_H_$(4))/rustdoc_ng$$(X_$(4)):                              \
+               $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc_ng$$(X_$(4)) \
+               $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOCNG_$(4))    \
+               $$(HSREQ$(2)_H_$(4))                            \
+               | $$(HBIN$(2)_H_$(4))/
+       @$$(call E, cp: $$@)
+       $$(Q)cp $$< $$@
+
 $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTI_$(4)):                                      \
                $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
                $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4))                        \
index 166638bc359bf98e4c560ad6d82187492b5cf4e3..93324007f982ead5389c6f8555fc36f7436eb0ee 100644 (file)
@@ -17,7 +17,6 @@
 
 use std::os;
 use std::rt;
-use std::f64;
 
 use extra::getopts;
 use extra::getopts::groups::{optopt, optflag, reqopt};
@@ -92,10 +91,10 @@ pub fn parse_config(args: ~[~str]) -> config {
     let matches =
         &match getopts::groups::getopts(args_, groups) {
           Ok(m) => m,
-          Err(f) => fail!(getopts::fail_str(f))
+          Err(f) => fail!(f.to_err_msg())
         };
 
-    if getopts::opt_present(matches, "h") || getopts::opt_present(matches, "help") {
+    if matches.opt_present("h") || matches.opt_present("help") {
         let message = fmt!("Usage: %s [OPTIONS]  [TESTNAME...]", argv0);
         println(getopts::groups::usage(message, groups));
         println("");
@@ -103,53 +102,51 @@ pub fn parse_config(args: ~[~str]) -> config {
     }
 
     fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
-        Path(getopts::opt_str(m, nm))
+        Path(m.opt_str(nm).unwrap())
     }
 
     config {
-        compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
-        run_lib_path: getopts::opt_str(matches, "run-lib-path"),
+        compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
+        run_lib_path: matches.opt_str("run-lib-path").unwrap(),
         rustc_path: opt_path(matches, "rustc-path"),
-        clang_path: getopts::opt_maybe_str(matches, "clang-path").map_move(|s| Path(s)),
-        llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map_move(|s| Path(s)),
+        clang_path: matches.opt_str("clang-path").map_move(|s| Path(s)),
+        llvm_bin_path: matches.opt_str("llvm-bin-path").map_move(|s| Path(s)),
         src_base: opt_path(matches, "src-base"),
         build_base: opt_path(matches, "build-base"),
         aux_base: opt_path(matches, "aux-base"),
-        stage_id: getopts::opt_str(matches, "stage-id"),
-        mode: str_mode(getopts::opt_str(matches, "mode")),
-        run_ignored: getopts::opt_present(matches, "ignored"),
+        stage_id: matches.opt_str("stage-id").unwrap(),
+        mode: str_mode(matches.opt_str("mode").unwrap()),
+        run_ignored: matches.opt_present("ignored"),
         filter:
             if !matches.free.is_empty() {
                  Some(matches.free[0].clone())
             } else {
                 None
             },
-        logfile: getopts::opt_maybe_str(matches, "logfile").map_move(|s| Path(s)),
-        save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map_move(|s| Path(s)),
+        logfile: matches.opt_str("logfile").map_move(|s| Path(s)),
+        save_metrics: matches.opt_str("save-metrics").map_move(|s| Path(s)),
         ratchet_metrics:
-            getopts::opt_maybe_str(matches, "ratchet-metrics").map_move(|s| Path(s)),
+            matches.opt_str("ratchet-metrics").map_move(|s| Path(s)),
         ratchet_noise_percent:
-            getopts::opt_maybe_str(matches,
-                                   "ratchet-noise-percent").map_move(|s|
-                                                                     f64::from_str(s).unwrap()),
-        runtool: getopts::opt_maybe_str(matches, "runtool"),
-        rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
-        jit: getopts::opt_present(matches, "jit"),
-        target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
-        adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
+            matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
+        runtool: matches.opt_str("runtool"),
+        rustcflags: matches.opt_str("rustcflags"),
+        jit: matches.opt_present("jit"),
+        target: opt_str2(matches.opt_str("target")).to_str(),
+        adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
         adb_test_dir:
-            opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")).to_str(),
+            opt_str2(matches.opt_str("adb-test-dir")).to_str(),
         adb_device_status:
-            if (opt_str2(getopts::opt_maybe_str(matches, "target")) ==
+            if (opt_str2(matches.opt_str("target")) ==
                 ~"arm-linux-androideabi") {
-                if (opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
+                if (opt_str2(matches.opt_str("adb-test-dir")) !=
                     ~"(none)" &&
-                    opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
+                    opt_str2(matches.opt_str("adb-test-dir")) !=
                     ~"") { true }
                 else { false }
             } else { false },
-        test_shard: test::opt_shard(getopts::opt_maybe_str(matches, "test-shard")),
-        verbose: getopts::opt_present(matches, "verbose")
+        test_shard: test::opt_shard(matches.opt_str("test-shard")),
+        verbose: matches.opt_present("verbose")
     }
 }
 
index e81a3230e134384101441c8cc6a206a54e5af6e1..991bb914fd07f708d31b35a6ca3ef3ee4bc3a045 100644 (file)
@@ -23,4 +23,7 @@
 #[cfg(rustc)]
 extern mod this(name = "rustc");
 
+#[cfg(rustdoc_ng)]
+extern mod this(name = "rustdoc_ng");
+
 fn main() { this::main() }
diff --git a/src/etc/mingw-fix-include/README.txt b/src/etc/mingw-fix-include/README.txt
new file mode 100644 (file)
index 0000000..876db17
--- /dev/null
@@ -0,0 +1,6 @@
+The purpose of these headers is to fix issues with mingw v4.0, as described in #9246.
+
+This works by adding this directory to GCC include search path before mingw system headers directories, 
+so we can intercept their inclusions and add missing definitions without having to modify files in mingw/include.
+
+Once mingw fixes all 3 issues mentioned in #9246, this directory and all references to it from rust/mk/* may be removed.
diff --git a/src/etc/mingw-fix-include/bits/c++config.h b/src/etc/mingw-fix-include/bits/c++config.h
new file mode 100644 (file)
index 0000000..4520779
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _FIX_CXXCONFIG_H
+#define _FIX_CXXCONFIG_H 1
+
+#define _GLIBCXX_HAVE_FENV_H 1
+
+#include_next <bits/c++config.h>
+
+#endif
diff --git a/src/etc/mingw-fix-include/winbase.h b/src/etc/mingw-fix-include/winbase.h
new file mode 100644 (file)
index 0000000..3be26d1
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _FIX_WINBASE_H
+#define _FIX_WINBASE_H 1
+
+#define NTDDK_VERSION NTDDI_VERSION
+
+#include_next <winbase.h>
+
+#endif
diff --git a/src/etc/mingw-fix-include/winsock2.h b/src/etc/mingw-fix-include/winsock2.h
new file mode 100644 (file)
index 0000000..36b58dc
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _FIX_WINSOCK2_H
+#define _FIX_WINSOCK2_H 1
+
+#include_next <winsock2.h>
+
+typedef struct pollfd {
+  SOCKET fd;
+  short  events;
+  short  revents;
+} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
+
+#endif
index 3fbfae52c6300bf925d071a95c611447149476ec..ca8000c984d4af53005eacfd917dc45515581838 100644 (file)
@@ -313,7 +313,7 @@ struct PoisonOnFail {
 }
 
 impl Drop for PoisonOnFail {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             /* assert!(!*self.failed);
                -- might be false in case of cond.wait() */
index e24e747d61ab42ab3f8bf88b4913fc85fdd79125..63c8e2010b07ac24f344689dbf92e34ad67c7f01 100644 (file)
@@ -93,7 +93,7 @@ fn chunk(size: uint, is_pod: bool) -> Chunk {
 
 #[unsafe_destructor]
 impl Drop for Arena {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             destroy_chunk(&self.head);
             do self.chunks.each |chunk| {
index 6ae67e7c794ef49d5f7df494c1f3a22c706a60d5..30bce3a81708cafaf940db617210c2ebe0fe7053 100644 (file)
@@ -56,7 +56,7 @@ struct DtorRes {
 
 #[unsafe_destructor]
 impl Drop for DtorRes {
-    fn drop(&self) {
+    fn drop(&mut self) {
         match self.dtor {
             option::None => (),
             option::Some(f) => f()
index ac296ad527ee5f973f26e5a979e8f4de1a86b2d1..da5d5d00e80cf07aaed1b16f16a1b1fa99e454a8 100644 (file)
@@ -415,14 +415,11 @@ pub fn insert_ordered(&mut self, elt: T) {
 
 #[unsafe_destructor]
 impl<T> Drop for DList<T> {
-    fn drop(&self) {
-        let mut_self = unsafe {
-            cast::transmute_mut(self)
-        };
+    fn drop(&mut self) {
         // Dissolve the dlist in backwards direction
         // Just dropping the list_head can lead to stack exhaustion
         // when length is >> 1_000_000
-        let mut tail = mut_self.list_tail;
+        let mut tail = self.list_tail;
         loop {
             match tail.resolve() {
                 None => break,
@@ -432,9 +429,9 @@ fn drop(&self) {
                 }
             }
         }
-        mut_self.length = 0;
-        mut_self.list_head = None;
-        mut_self.list_tail = Rawlink::none();
+        self.length = 0;
+        self.list_head = None;
+        self.list_tail = Rawlink::none();
     }
 }
 
index 020da792ed7f3c9c29b495eb4e050c449b10d4e4..25d11d413c06a360c5525de3534303902aee57a5 100644 (file)
@@ -433,7 +433,6 @@ fn make_file(path : &Path, contents: &[~str]) {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_make_path_option_vec() {
         let strs = [~"some/path",
                     ~"some/other/path"];
@@ -448,7 +447,6 @@ fn test_make_path_option_vec() {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_fileinput_read_byte() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -479,7 +477,6 @@ fn test_fileinput_read_byte() {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_fileinput_read() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -500,7 +497,6 @@ fn test_fileinput_read() {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_input_vec() {
         let mut all_lines = ~[];
         let filenames = make_path_option_vec(vec::from_fn(
@@ -524,7 +520,6 @@ fn test_input_vec() {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_input_vec_state() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -547,7 +542,6 @@ fn test_input_vec_state() {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_empty_files() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -572,7 +566,6 @@ fn test_empty_files() {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_no_trailing_newline() {
         let f1 =
             Some(Path("tmp/lib-fileinput-test-no-trailing-newline-1.tmp"));
@@ -598,7 +591,6 @@ fn test_no_trailing_newline() {
 
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_next_file() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -630,7 +622,6 @@ fn test_next_file() {
 
     #[test]
     #[should_fail]
-    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_input_vec_missing_file() {
         do input_vec(make_path_option_vec([~"this/file/doesnt/exist"], true)) |line| {
             println(line);
index ce56a3dcaa69b479e42277311eaee69ae75efb4a..74a551c6f6d560fb7d0b3dee859df088bf307108 100644 (file)
@@ -43,7 +43,7 @@ pub struct Future<A> {
 // over ~fn's that have pipes and so forth within!
 #[unsafe_destructor]
 impl<A> Drop for Future<A> {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 enum FutureState<A> {
index a21d9dc605f40ccc18afa5650cf97a6233c1ae18..0116c5a1f66013df4f01744ea2f6dafaf30eb88f 100644 (file)
@@ -8,93 +8,89 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/*!
- * Simple getopt alternative.
- *
- * Construct a vector of options, either by using reqopt, optopt, and optflag
- * or by building them from components yourself, and pass them to getopts,
- * along with a vector of actual arguments (not including argv[0]). You'll
- * either get a failure code back, or a match. You'll have to verify whether
- * the amount of 'free' arguments in the match is what you expect. Use opt_*
- * accessors to get argument values out of the matches object.
- *
- * Single-character options are expected to appear on the command line with a
- * single preceding dash; multiple-character options are expected to be
- * proceeded by two dashes. Options that expect an argument accept their
- * argument following either a space or an equals sign. Single-character
- * options don't require the space.
- *
- * # Example
- *
- * The following example shows simple command line parsing for an application
- * that requires an input file to be specified, accepts an optional output
- * file name following -o, and accepts both -h and --help as optional flags.
- *
- * ```
- *    extern mod extra;
- *    use extra::getopts::*;
- *    use std::os;
- *
- *    fn do_work(in: &str, out: Option<~str>) {
- *        println(in);
- *        println(match out {
- *            Some(x) => x,
- *            None => ~"No Output"
- *        });
- *    }
- *
- *    fn print_usage(program: &str, _opts: &[Opt]) {
- *        printfln!("Usage: %s [options]", program);
- *        println("-o\t\tOutput");
- *        println("-h --help\tUsage");
- *    }
- *
- *    fn main() {
- *        let args = os::args();
- *
- *        let program = args[0].clone();
- *
- *        let opts = ~[
- *            optopt("o"),
- *            optflag("h"),
- *            optflag("help")
- *        ];
- *        let matches = match getopts(args.tail(), opts) {
- *            Ok(m) => { m }
- *            Err(f) => { fail!(fail_str(f)) }
- *        };
- *        if opt_present(&matches, "h") || opt_present(&matches, "help") {
- *            print_usage(program, opts);
- *            return;
- *        }
- *        let output = opt_maybe_str(&matches, "o");
- *        let input: &str = if !matches.free.is_empty() {
- *            matches.free[0].clone()
- *        } else {
- *            print_usage(program, opts);
- *            return;
- *        };
- *        do_work(input, output);
- *    }
- * ```
- */
-
-#[allow(missing_doc)];
-
+//! Simple getopt alternative.
+//!
+//! Construct a vector of options, either by using reqopt, optopt, and optflag
+//! or by building them from components yourself, and pass them to getopts,
+//! along with a vector of actual arguments (not including argv[0]). You'll
+//! either get a failure code back, or a match. You'll have to verify whether
+//! the amount of 'free' arguments in the match is what you expect. Use opt_*
+//! accessors to get argument values out of the matches object.
+//!
+//! Single-character options are expected to appear on the command line with a
+//! single preceding dash; multiple-character options are expected to be
+//! proceeded by two dashes. Options that expect an argument accept their
+//! argument following either a space or an equals sign. Single-character
+//! options don't require the space.
+//!
+//! # Example
+//!
+//! The following example shows simple command line parsing for an application
+//! that requires an input file to be specified, accepts an optional output
+//! file name following -o, and accepts both -h and --help as optional flags.
+//!
+//! ```
+//! exter mod extra;
+//! use extra::getopts::*;
+//! use std::os;
+//!
+//! fn do_work(inp: &str, out: Option<~str>) {
+//!     println(inp);
+//!     println(match out {
+//!         Some(x) => x,
+//!         None => ~"No Output"
+//!     });
+//! }
+//!
+//! fn print_usage(program: &str, _opts: &[Opt]) {
+//!     printfln!("Usage: %s [options]", program);
+//!     println("-o\t\tOutput");
+//!     println("-h --help\tUsage");
+//! }
+//!
+//! fn main() {
+//!     let args = os::args();
+//!
+//!     let program = args[0].clone();
+//!
+//!     let opts = ~[
+//!         optopt("o"),
+//!         optflag("h"),
+//!         optflag("help")
+//!     ];
+//!     let matches = match getopts(args.tail(), opts) {
+//!         Ok(m) => { m }
+//!         Err(f) => { fail!(f.to_err_msg()) }
+//!     };
+//!     if matches.opt_present("h") || matches.opt_present("help") {
+//!         print_usage(program, opts);
+//!         return;
+//!     }
+//!     let output = matches.opt_str("o");
+//!     let input: &str = if !matches.free.is_empty() {
+//!         matches.free[0].clone()
+//!     } else {
+//!         print_usage(program, opts);
+//!         return;
+//!     };
+//!     do_work(input, output);
+//! }
+//! ```
 
 use std::cmp::Eq;
 use std::result::{Err, Ok};
 use std::result;
 use std::option::{Some, None};
-use std::str;
 use std::vec;
 
+/// Name of an option. Either a string or a single char.
 #[deriving(Clone, Eq)]
 pub enum Name {
     Long(~str),
     Short(char),
 }
 
+/// Describes whether an option has an argument.
 #[deriving(Clone, Eq)]
 pub enum HasArg {
     Yes,
@@ -102,6 +98,7 @@ pub enum HasArg {
     Maybe,
 }
 
+/// Describes how often an option may occur.
 #[deriving(Clone, Eq)]
 pub enum Occur {
     Req,
@@ -109,94 +106,189 @@ pub enum Occur {
     Multi,
 }
 
-/// A description of a possible option
+/// A description of a possible option.
 #[deriving(Clone, Eq)]
 pub struct Opt {
+    /// Name of the option
     name: Name,
+    /// Wheter it has an argument
     hasarg: HasArg,
+    /// How often it can occur
     occur: Occur,
+    /// Which options it aliases
     aliases: ~[Opt],
 }
 
-fn mkname(nm: &str) -> Name {
-  if nm.len() == 1u {
-      Short(nm.char_at(0u))
-  } else {
-      Long(nm.to_owned())
-  }
+/// Describes wether an option is given at all or has a value.
+#[deriving(Clone, Eq)]
+enum Optval {
+    Val(~str),
+    Given,
 }
 
-/// Create an option that is required and takes an argument
-pub fn reqopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]};
+/// The result of checking command line arguments. Contains a vector
+/// of matches and a vector of free strings.
+#[deriving(Clone, Eq)]
+pub struct Matches {
+    /// Options that matched
+    opts: ~[Opt],
+    /// Values of the Options that matched
+    vals: ~[~[Optval]],
+    /// Free string fragments
+    free: ~[~str]
 }
 
-/// Create an option that is optional and takes an argument
-pub fn optopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]};
+/// The type returned when the command line does not conform to the
+/// expected format. Pass this value to <fail_str> to get an error message.
+#[deriving(Clone, Eq, ToStr)]
+pub enum Fail_ {
+    ArgumentMissing(~str),
+    UnrecognizedOption(~str),
+    OptionMissing(~str),
+    OptionDuplicated(~str),
+    UnexpectedArgument(~str),
 }
 
-/// Create an option that is optional and does not take an argument
-pub fn optflag(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]};
+/// The type of failure that occured.
+#[deriving(Eq)]
+pub enum FailType {
+    ArgumentMissing_,
+    UnrecognizedOption_,
+    OptionMissing_,
+    OptionDuplicated_,
+    UnexpectedArgument_,
 }
 
-/** Create an option that is optional, does not take an argument,
-  * and may occur multiple times.
-  */
-pub fn optflagmulti(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]};
-}
+/// The result of parsing a command line with a set of options.
+pub type Result = result::Result<Matches, Fail_>;
 
-/// Create an option that is optional and takes an optional argument
-pub fn optflagopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]};
-}
+impl Name {
+    fn from_str(nm: &str) -> Name {
+        if nm.len() == 1u {
+            Short(nm.char_at(0u))
+        } else {
+            Long(nm.to_owned())
+        }
+    }
 
-/**
- * Create an option that is optional, takes an argument, and may occur
- * multiple times
- */
-pub fn optmulti(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]};
+    fn to_str(&self) -> ~str {
+        match *self {
+            Short(ch) => ch.to_str(),
+            Long(ref s) => s.to_owned()
+        }
+    }
 }
 
-#[deriving(Clone, Eq)]
-enum Optval {
-    Val(~str),
-    Given,
-}
+impl Matches {
+    /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
+    /// No idea what this does.
+    pub fn opt_vals(&self, nm: &str) -> ~[Optval] {
+        match find_opt(self.opts, Name::from_str(nm)) {
+            Some(id) => self.vals[id].clone(),
+            None => fail!("No option '%s' defined", nm)
+        }
+    }
 
-/**
- * The result of checking command line arguments. Contains a vector
- * of matches and a vector of free strings.
- */
-#[deriving(Clone, Eq)]
-pub struct Matches {
-    opts: ~[Opt],
-    vals: ~[~[Optval]],
-    free: ~[~str]
-}
+    /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
+    /// No idea what this does.
+    pub fn opt_val(&self, nm: &str) -> Option<Optval> {
+        let vals = self.opt_vals(nm);
+        if (vals.is_empty()) {
+            None
+        } else {
+            Some(vals[0].clone())
+        }
+    }
+
+    /// Returns true if an option was matched.
+    pub fn opt_present(&self, nm: &str) -> bool {
+        !self.opt_vals(nm).is_empty()
+    }
+
+    /// Returns the number of times an option was matched.
+    pub fn opt_count(&self, nm: &str) -> uint {
+        self.opt_vals(nm).len()
+    }
+
+    /// Returns true if any of several options were matched.
+    pub fn opts_present(&self, names: &[~str]) -> bool {
+        for nm in names.iter() {
+            match find_opt(self.opts, Name::from_str(*nm)) {
+                Some(id) if !self.vals[id].is_empty() => return true,
+                _ => (),
+            };
+        }
+        false
+    }
+
+    /// Returns the string argument supplied to one of several matching options or `None`.
+    pub fn opts_str(&self, names: &[~str]) -> Option<~str> {
+        for nm in names.iter() {
+            match self.opt_val(*nm) {
+                Some(Val(ref s)) => return Some(s.clone()),
+                _ => ()
+            }
+        }
+        None
+    }
+
+    /// Returns a vector of the arguments provided to all matches of the given
+    /// option.
+    ///
+    /// Used when an option accepts multiple values.
+    pub fn opt_strs(&self, nm: &str) -> ~[~str] {
+        let mut acc: ~[~str] = ~[];
+        let r = self.opt_vals(nm);
+        for v in r.iter() {
+            match *v {
+                Val(ref s) => acc.push((*s).clone()),
+                _ => ()
+            }
+        }
+        acc
+    }
+
+    /// Returns the string argument supplied to a matching option or `None`.
+    pub fn opt_str(&self, nm: &str) -> Option<~str> {
+        let vals = self.opt_vals(nm);
+        if vals.is_empty() {
+            return None::<~str>;
+        }
+        match vals[0] {
+            Val(ref s) => Some((*s).clone()),
+            _ => None
+        }
+    }
+
+
+    /// Returns the matching string, a default, or none.
+    ///
+    /// Returns none if the option was not present, `def` if the option was
+    /// present but no argument was provided, and the argument if the option was
+    /// present and an argument was provided.
+    pub fn opt_default(&self, nm: &str, def: &str) -> Option<~str> {
+        let vals = self.opt_vals(nm);
+        if vals.is_empty() { return None; }
+        match vals[0] {
+            Val(ref s) => Some((*s).clone()),
+            _ => Some(def.to_owned())
+        }
+    }
 
-fn is_arg(arg: &str) -> bool {
-    return arg.len() > 1 && arg[0] == '-' as u8;
 }
 
-fn name_str(nm: &Name) -> ~str {
-    return match *nm {
-      Short(ch) => str::from_char(ch),
-      Long(ref s) => (*s).clone()
-    };
+fn is_arg(arg: &str) -> bool {
+    arg.len() > 1 && arg[0] == '-' as u8
 }
 
 fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
-    // search main options
+    // Search main options.
     let pos = opts.iter().position(|opt| opt.name == nm);
     if pos.is_some() {
         return pos
     }
 
-    // search in aliases
+    // Search in aliases.
     for candidate in opts.iter() {
         if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
             return opts.iter().position(|opt| opt.name == candidate.name);
@@ -206,56 +298,101 @@ fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
     None
 }
 
-/**
- * The type returned when the command line does not conform to the
- * expected format. Pass this value to <fail_str> to get an error message.
- */
-#[deriving(Clone, Eq, ToStr)]
-pub enum Fail_ {
-    ArgumentMissing(~str),
-    UnrecognizedOption(~str),
-    OptionMissing(~str),
-    OptionDuplicated(~str),
-    UnexpectedArgument(~str),
+/// Create an option that is required and takes an argument.
+pub fn reqopt(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Yes,
+        occur: Req,
+        aliases: ~[]
+    }
 }
 
-/// Convert a `fail_` enum into an error string
-pub fn fail_str(f: Fail_) -> ~str {
-    return match f {
-        ArgumentMissing(ref nm) => {
-            fmt!("Argument to option '%s' missing.", *nm)
-        }
-        UnrecognizedOption(ref nm) => {
-            fmt!("Unrecognized option: '%s'.", *nm)
-        }
-        OptionMissing(ref nm) => {
-            fmt!("Required option '%s' missing.", *nm)
-        }
-        OptionDuplicated(ref nm) => {
-            fmt!("Option '%s' given more than once.", *nm)
-        }
-        UnexpectedArgument(ref nm) => {
-            fmt!("Option '%s' does not take an argument.", *nm)
-        }
-    };
+/// Create an option that is optional and takes an argument.
+pub fn optopt(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Yes,
+        occur: Optional,
+        aliases: ~[]
+    }
 }
 
-/**
- * The result of parsing a command line with a set of options
- * (result::t<Matches, Fail_>)
- */
-pub type Result = result::Result<Matches, Fail_>;
+/// Create an option that is optional and does not take an argument.
+pub fn optflag(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: No,
+        occur: Optional,
+        aliases: ~[]
+    }
+}
+
+/// Create an option that is optional, does not take an argument,
+/// and may occur multiple times.
+pub fn optflagmulti(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: No,
+        occur: Multi,
+        aliases: ~[]
+    }
+}
+
+/// Create an option that is optional and takes an optional argument.
+pub fn optflagopt(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Maybe,
+        occur: Optional,
+        aliases: ~[]
+    }
+}
+
+/// Create an option that is optional, takes an argument, and may occur
+/// multiple times.
+pub fn optmulti(name: &str) -> Opt {
+    Opt {
+        name: Name::from_str(name),
+        hasarg: Yes,
+        occur: Multi,
+        aliases: ~[]
+    }
+}
 
-/**
- * Parse command line arguments according to the provided options
- *
- * On success returns `ok(Opt)`. Use functions such as `opt_present`
- * `opt_str`, etc. to interrogate results.  Returns `err(Fail_)` on failure.
- * Use <fail_str> to get an error message.
- */
+impl Fail_ {
+    /// Convert a `Fail_` enum into an error string.
+    pub fn to_err_msg(self) -> ~str {
+        match self {
+            ArgumentMissing(ref nm) => {
+                fmt!("Argument to option '%s' missing.", *nm)
+            }
+            UnrecognizedOption(ref nm) => {
+                fmt!("Unrecognized option: '%s'.", *nm)
+            }
+            OptionMissing(ref nm) => {
+                fmt!("Required option '%s' missing.", *nm)
+            }
+            OptionDuplicated(ref nm) => {
+                fmt!("Option '%s' given more than once.", *nm)
+            }
+            UnexpectedArgument(ref nm) => {
+                fmt!("Option '%s' does not take an argument.", *nm)
+            }
+        }
+    }
+}
+
+/// Parse command line arguments according to the provided options.
+///
+/// On success returns `Ok(Opt)`. Use methods such as `opt_present`
+/// `opt_str`, etc. to interrogate results.  Returns `Err(Fail_)` on failure.
+/// Use `to_err_msg` to get an error message.
 pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
     let n_opts = opts.len();
+
     fn f(_x: uint) -> ~[Optval] { return ~[]; }
+
     let mut vals = vec::from_fn(n_opts, f);
     let mut free: ~[~str] = ~[];
     let l = args.len();
@@ -325,12 +462,12 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
                 name_pos += 1;
                 let optid = match find_opt(opts, (*nm).clone()) {
                   Some(id) => id,
-                  None => return Err(UnrecognizedOption(name_str(nm)))
+                  None => return Err(UnrecognizedOption(nm.to_str()))
                 };
                 match opts[optid].hasarg {
                   No => {
                     if !i_arg.is_none() {
-                        return Err(UnexpectedArgument(name_str(nm)));
+                        return Err(UnexpectedArgument(nm.to_str()));
                     }
                     vals[optid].push(Given);
                   }
@@ -346,7 +483,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
                     if !i_arg.is_none() {
                         vals[optid].push(Val(i_arg.clone().unwrap()));
                     } else if i + 1 == l {
-                        return Err(ArgumentMissing(name_str(nm)));
+                        return Err(ArgumentMissing(nm.to_str()));
                     } else { i += 1; vals[optid].push(Val(args[i].clone())); }
                   }
                 }
@@ -360,289 +497,183 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
         let occ = opts[i].occur;
         if occ == Req {
             if n == 0 {
-                return Err(OptionMissing(name_str(&(opts[i].name))));
+                return Err(OptionMissing(opts[i].name.to_str()));
             }
         }
         if occ != Multi {
             if n > 1 {
-                return Err(OptionDuplicated(name_str(&(opts[i].name))));
+                return Err(OptionDuplicated(opts[i].name.to_str()));
             }
         }
         i += 1;
     }
-    return Ok(Matches {opts: opts.to_owned(),
-               vals: vals,
-               free: free});
-}
-
-fn opt_vals(mm: &Matches, nm: &str) -> ~[Optval] {
-    return match find_opt(mm.opts, mkname(nm)) {
-      Some(id) => mm.vals[id].clone(),
-      None => {
-        error!("No option '%s' defined", nm);
-        fail!()
-      }
-    };
-}
-
-fn opt_val(mm: &Matches, nm: &str) -> Option<Optval> {
-    let vals = opt_vals(mm, nm);
-    if (vals.is_empty()) {
-        None
-    } else {
-        Some(opt_vals(mm, nm)[0].clone())
-    }
-}
-
-/// Returns true if an option was matched
-pub fn opt_present(mm: &Matches, nm: &str) -> bool {
-    !opt_vals(mm, nm).is_empty()
-}
-
-/// Returns the number of times an option was matched
-pub fn opt_count(mm: &Matches, nm: &str) -> uint {
-    opt_vals(mm, nm).len()
-}
-
-/// Returns true if any of several options were matched
-pub fn opts_present(mm: &Matches, names: &[~str]) -> bool {
-    for nm in names.iter() {
-        match find_opt(mm.opts, mkname(*nm)) {
-            Some(id) if !mm.vals[id].is_empty() => return true,
-            _ => (),
-        };
-    }
-    false
-}
-
-
-/**
- * Returns the string argument supplied to a matching option
- *
- * Fails if the option was not matched or if the match did not take an
- * argument
- */
-pub fn opt_str(mm: &Matches, nm: &str) -> ~str {
-    return match opt_val(mm, nm) {
-        Some(Val(s)) => s,
-        _ => fail!()
-    };
-}
-
-/**
- * Returns the string argument supplied to one of several matching options
- *
- * Fails if the no option was provided from the given list, or if the no such
- * option took an argument
- */
-pub fn opts_str(mm: &Matches, names: &[~str]) -> ~str {
-    for nm in names.iter() {
-        match opt_val(mm, *nm) {
-          Some(Val(ref s)) => return (*s).clone(),
-          _ => ()
-        }
-    }
-    fail!();
+    Ok(Matches {
+        opts: opts.to_owned(),
+        vals: vals,
+        free: free
+    })
 }
 
-
-/**
- * Returns a vector of the arguments provided to all matches of the given
- * option.
- *
- * Used when an option accepts multiple values.
- */
-pub fn opt_strs(mm: &Matches, nm: &str) -> ~[~str] {
-    let mut acc: ~[~str] = ~[];
-    let r = opt_vals(mm, nm);
-    for v in r.iter() {
-        match *v { Val(ref s) => acc.push((*s).clone()), _ => () }
-    }
-    acc
-}
-
-/// Returns the string argument supplied to a matching option or none
-pub fn opt_maybe_str(mm: &Matches, nm: &str) -> Option<~str> {
-    let vals = opt_vals(mm, nm);
-    if vals.is_empty() { return None::<~str>; }
-    return match vals[0] {
-        Val(ref s) => Some((*s).clone()),
-        _ => None
-    };
-}
-
-
-/**
- * Returns the matching string, a default, or none
- *
- * Returns none if the option was not present, `def` if the option was
- * present but no argument was provided, and the argument if the option was
- * present and an argument was provided.
- */
-pub fn opt_default(mm: &Matches, nm: &str, def: &str) -> Option<~str> {
-    let vals = opt_vals(mm, nm);
-    if vals.is_empty() { return None::<~str>; }
-    return match vals[0] { Val(ref s) => Some::<~str>((*s).clone()),
-                           _      => Some::<~str>(def.to_owned()) }
-}
-
-#[deriving(Eq)]
-pub enum FailType {
-    ArgumentMissing_,
-    UnrecognizedOption_,
-    OptionMissing_,
-    OptionDuplicated_,
-    UnexpectedArgument_,
-}
-
-/** A module which provides a way to specify descriptions and
- *  groups of short and long option names, together.
- */
+/// A module which provides a way to specify descriptions and
+/// groups of short and long option names, together.
 pub mod groups {
     use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
     use getopts::{Short, Yes};
 
-    /** one group of options, e.g., both -h and --help, along with
-     * their shared description and properties
-     */
+    /// One group of options, e.g., both -h and --help, along with
+    /// their shared description and properties.
     #[deriving(Clone, Eq)]
     pub struct OptGroup {
+        /// Short Name of the `OptGroup`
         short_name: ~str,
+        /// Long Name of the `OptGroup`
         long_name: ~str,
+        /// Hint
         hint: ~str,
+        /// Description
         desc: ~str,
+        /// Whether it has an argument
         hasarg: HasArg,
+        /// How often it can occur
         occur: Occur
     }
 
-    /// Create a long option that is required and takes an argument
-    pub fn reqopt(short_name: &str, long_name: &str,
-                  desc: &str, hint: &str) -> OptGroup {
+    impl OptGroup {
+        /// Translate OptGroup into Opt.
+        /// (Both short and long names correspond to different Opts).
+        pub fn long_to_short(&self) -> Opt {
+            let OptGroup {
+                short_name: short_name,
+                long_name: long_name,
+                hasarg: hasarg,
+                occur: occur,
+                _
+            } = (*self).clone();
+
+            match (short_name.len(), long_name.len()) {
+                (0,0) => fail!("this long-format option was given no name"),
+                (0,_) => Opt {
+                    name: Long((long_name)),
+                    hasarg: hasarg,
+                    occur: occur,
+                    aliases: ~[]
+                },
+                (1,0) => Opt {
+                    name: Short(short_name.char_at(0)),
+                    hasarg: hasarg,
+                    occur: occur,
+                    aliases: ~[]
+                },
+                (1,_) => Opt {
+                    name: Long((long_name)),
+                    hasarg: hasarg,
+                    occur:  occur,
+                    aliases: ~[
+                        Opt {
+                            name: Short(short_name.char_at(0)),
+                            hasarg: hasarg,
+                            occur:  occur,
+                            aliases: ~[]
+                        }
+                    ]
+                },
+                (_,_) => fail!("something is wrong with the long-form opt")
+            }
+        }
+    }
+
+    /// Create a long option that is required and takes an argument.
+    pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup { short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Yes,
-                occur: Req};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Yes,
+            occur: Req
+        }
     }
 
-    /// Create a long option that is optional and takes an argument
-    pub fn optopt(short_name: &str, long_name: &str,
-                  desc: &str, hint: &str) -> OptGroup {
+    /// Create a long option that is optional and takes an argument.
+    pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Yes,
-                occur: Optional};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Yes,
+            occur: Optional
+        }
     }
 
-    /// Create a long option that is optional and does not take an argument
-    pub fn optflag(short_name: &str, long_name: &str,
-                   desc: &str) -> OptGroup {
+    /// Create a long option that is optional and does not take an argument.
+    pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: ~"",
-                desc: desc.to_owned(),
-                hasarg: No,
-                occur: Optional};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: ~"",
+            desc: desc.to_owned(),
+            hasarg: No,
+            occur: Optional
+        }
     }
 
     /// Create a long option that can occur more than once and does not
-    /// take an argument
-    pub fn optflagmulti(short_name: &str, long_name: &str,
-                   desc: &str) -> OptGroup {
+    /// take an argument.
+    pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: ~"",
-                desc: desc.to_owned(),
-                hasarg: No,
-                occur: Multi};
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: ~"",
+            desc: desc.to_owned(),
+            hasarg: No,
+            occur: Multi
+        }
     }
 
-    /// Create a long option that is optional and takes an optional argument
-    pub fn optflagopt(short_name: &str, long_name: &str,
-                      desc: &str, hint: &str) -> OptGroup {
+    /// Create a long option that is optional and takes an optional argument.
+    pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Maybe,
-                occur: Optional};
-    }
-
-    /**
-     * Create a long option that is optional, takes an argument, and may occur
-     * multiple times
-     */
-    pub fn optmulti(short_name: &str, long_name: &str,
-                    desc: &str, hint: &str) -> OptGroup {
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Maybe,
+            occur: Optional
+        }
+    }
+
+    /// Create a long option that is optional, takes an argument, and may occur
+    /// multiple times.
+    pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
         let len = short_name.len();
         assert!(len == 1 || len == 0);
-        return OptGroup {short_name: short_name.to_owned(),
-                long_name: long_name.to_owned(),
-                hint: hint.to_owned(),
-                desc: desc.to_owned(),
-                hasarg: Yes,
-                occur: Multi};
-    }
-
-    // translate OptGroup into Opt
-    // (both short and long names correspond to different Opts)
-    pub fn long_to_short(lopt: &OptGroup) -> Opt {
-        let OptGroup{short_name: short_name,
-                     long_name: long_name,
-                     hasarg: hasarg,
-                     occur: occur,
-                     _} = (*lopt).clone();
-
-        match (short_name.len(), long_name.len()) {
-            (0,0) => fail!("this long-format option was given no name"),
-
-            (0,_) => Opt {name: Long((long_name)),
-                          hasarg: hasarg,
-                          occur: occur,
-                          aliases: ~[]},
-
-            (1,0) => Opt {name: Short(short_name.char_at(0)),
-                          hasarg: hasarg,
-                          occur: occur,
-                          aliases: ~[]},
-
-            (1,_) => Opt {name: Long((long_name)),
-                          hasarg: hasarg,
-                          occur:  occur,
-                          aliases: ~[Opt {
-                              name: Short(short_name.char_at(0)),
-                              hasarg: hasarg,
-                              occur:  occur,
-                              aliases: ~[]
-                          }]},
-
-            (_,_) => fail!("something is wrong with the long-form opt")
-        }
-    }
-
-    /*
-     * Parse command line args with the provided long format options
-     */
+        OptGroup {
+            short_name: short_name.to_owned(),
+            long_name: long_name.to_owned(),
+            hint: hint.to_owned(),
+            desc: desc.to_owned(),
+            hasarg: Yes,
+            occur: Multi
+        }
+    }
+
+    /// Parse command line args with the provided long format options.
     pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
-        ::getopts::getopts(args, opts.map(long_to_short))
+        ::getopts::getopts(args, opts.map(|x| x.long_to_short()))
     }
 
-    /**
-     * Derive a usage message from a set of long options
-     */
+    /// Derive a usage message from a set of long options.
     pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
 
         let desc_sep = "\n" + " ".repeat(24);
@@ -721,28 +752,24 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
             row
         });
 
-        return brief.to_owned() +
-               "\n\nOptions:\n" +
-               rows.collect::<~[~str]>().connect("\n") +
-               "\n";
-    }
-
-    /** Splits a string into substrings with possibly internal whitespace,
-     *  each of them at most `lim` bytes long. The substrings have leading and trailing
-     *  whitespace removed, and are only cut at whitespace boundaries.
-     *
-     *  Note: Function was moved here from `std::str` because this module is the only place that
-     *  uses it, and because it was to specific for a general string function.
-     *
-     *  #Failure:
-     *
-     *  Fails during iteration if the string contains a non-whitespace
-     *  sequence longer than the limit.
-     */
+        fmt!("%s\n\nOptions:\n%s\n", brief, rows.collect::<~[~str]>().connect("\n"))
+    }
+
+    /// Splits a string into substrings with possibly internal whitespace,
+    /// each of them at most `lim` bytes long. The substrings have leading and trailing
+    /// whitespace removed, and are only cut at whitespace boundaries.
+    ///
+    /// Note: Function was moved here from `std::str` because this module is the only place that
+    /// uses it, and because it was to specific for a general string function.
+    ///
+    /// #Failure:
+    ///
+    /// Fails during iteration if the string contains a non-whitespace
+    /// sequence longer than the limit.
     fn each_split_within<'a>(ss: &'a str,
                              lim: uint,
                              it: &fn(&'a str) -> bool) -> bool {
-        // Just for fun, let's write this as an state machine:
+        // Just for fun, let's write this as a state machine:
 
         enum SplitWithinState {
             A,  // leading whitespace, initial state
@@ -853,8 +880,8 @@ fn test_reqopt_long() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "test")));
-            assert_eq!(opt_str(m, "test"), ~"20");
+            assert!(m.opt_present("test"));
+            assert_eq!(m.opt_str("test").unwrap(), ~"20");
           }
           _ => { fail!("test_reqopt_long failed"); }
         }
@@ -900,8 +927,8 @@ fn test_reqopt_short() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
+            assert!(m.opt_present("t"));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -949,8 +976,8 @@ fn test_optopt_long() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "test")));
-            assert_eq!(opt_str(m, "test"), ~"20");
+            assert!(m.opt_present("test"));
+            assert_eq!(m.opt_str("test").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -962,7 +989,7 @@ fn test_optopt_long_missing() {
         let opts = ~[optopt("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "test")),
+          Ok(ref m) => assert!(!m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -996,8 +1023,8 @@ fn test_optopt_short() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
+            assert!((m.opt_present("t")));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -1009,7 +1036,7 @@ fn test_optopt_short_missing() {
         let opts = ~[optopt("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "t")),
+          Ok(ref m) => assert!(!m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1044,7 +1071,7 @@ fn test_optflag_long() {
         let opts = ~[optflag("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(opt_present(m, "test")),
+          Ok(ref m) => assert!(m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -1055,7 +1082,7 @@ fn test_optflag_long_missing() {
         let opts = ~[optflag("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "test")),
+          Ok(ref m) => assert!(!m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -1067,7 +1094,7 @@ fn test_optflag_long_arg() {
         let rs = getopts(args, opts);
         match rs {
           Err(f) => {
-            error!(fail_str(f.clone()));
+            error!(f.clone().to_err_msg());
             check_fail_type(f, UnexpectedArgument_);
           }
           _ => fail!()
@@ -1091,7 +1118,7 @@ fn test_optflag_short() {
         let opts = ~[optflag("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(opt_present(m, "t")),
+          Ok(ref m) => assert!(m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1102,7 +1129,7 @@ fn test_optflag_short_missing() {
         let opts = ~[optflag("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "t")),
+          Ok(ref m) => assert!(!m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1141,7 +1168,7 @@ fn test_optflagmulti_short1() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "v"), 1);
+            assert_eq!(m.opt_count("v"), 1);
           }
           _ => fail!()
         }
@@ -1154,7 +1181,7 @@ fn test_optflagmulti_short2a() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "v"), 2);
+            assert_eq!(m.opt_count("v"), 2);
           }
           _ => fail!()
         }
@@ -1167,7 +1194,7 @@ fn test_optflagmulti_short2b() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "v"), 2);
+            assert_eq!(m.opt_count("v"), 2);
           }
           _ => fail!()
         }
@@ -1180,7 +1207,7 @@ fn test_optflagmulti_long1() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "verbose"), 1);
+            assert_eq!(m.opt_count("verbose"), 1);
           }
           _ => fail!()
         }
@@ -1193,7 +1220,7 @@ fn test_optflagmulti_long2() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert_eq!(opt_count(m, "verbose"), 2);
+            assert_eq!(m.opt_count("verbose"), 2);
           }
           _ => fail!()
         }
@@ -1207,8 +1234,8 @@ fn test_optmulti_long() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "test")));
-            assert_eq!(opt_str(m, "test"), ~"20");
+            assert!((m.opt_present("test")));
+            assert_eq!(m.opt_str("test").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -1220,7 +1247,7 @@ fn test_optmulti_long_missing() {
         let opts = ~[optmulti("test")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "test")),
+          Ok(ref m) => assert!(!m.opt_present("test")),
           _ => fail!()
         }
     }
@@ -1243,9 +1270,9 @@ fn test_optmulti_long_multi() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-              assert!(opt_present(m, "test"));
-              assert_eq!(opt_str(m, "test"), ~"20");
-              let pair = opt_strs(m, "test");
+              assert!(m.opt_present("test"));
+              assert_eq!(m.opt_str("test").unwrap(), ~"20");
+              let pair = m.opt_strs("test");
               assert!(pair[0] == ~"20");
               assert!(pair[1] == ~"30");
           }
@@ -1260,8 +1287,8 @@ fn test_optmulti_short() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
+            assert!((m.opt_present("t")));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
           }
           _ => fail!()
         }
@@ -1273,7 +1300,7 @@ fn test_optmulti_short_missing() {
         let opts = ~[optmulti("t")];
         let rs = getopts(args, opts);
         match rs {
-          Ok(ref m) => assert!(!opt_present(m, "t")),
+          Ok(ref m) => assert!(!m.opt_present("t")),
           _ => fail!()
         }
     }
@@ -1296,9 +1323,9 @@ fn test_optmulti_short_multi() {
         let rs = getopts(args, opts);
         match rs {
           Ok(ref m) => {
-            assert!((opt_present(m, "t")));
-            assert_eq!(opt_str(m, "t"), ~"20");
-            let pair = opt_strs(m, "t");
+            assert!((m.opt_present("t")));
+            assert_eq!(m.opt_str("t").unwrap(), ~"20");
+            let pair = m.opt_strs("t");
             assert!(pair[0] == ~"20");
             assert!(pair[1] == ~"30");
           }
@@ -1343,18 +1370,18 @@ fn test_combined() {
           Ok(ref m) => {
             assert!(m.free[0] == ~"prog");
             assert!(m.free[1] == ~"free1");
-            assert_eq!(opt_str(m, "s"), ~"20");
+            assert_eq!(m.opt_str("s").unwrap(), ~"20");
             assert!(m.free[2] == ~"free2");
-            assert!((opt_present(m, "flag")));
-            assert_eq!(opt_str(m, "long"), ~"30");
-            assert!((opt_present(m, "f")));
-            let pair = opt_strs(m, "m");
+            assert!((m.opt_present("flag")));
+            assert_eq!(m.opt_str("long").unwrap(), ~"30");
+            assert!((m.opt_present("f")));
+            let pair = m.opt_strs("m");
             assert!(pair[0] == ~"40");
             assert!(pair[1] == ~"50");
-            let pair = opt_strs(m, "n");
+            let pair = m.opt_strs("n");
             assert!(pair[0] == ~"-A B");
             assert!(pair[1] == ~"-60 70");
-            assert!((!opt_present(m, "notpresent")));
+            assert!((!m.opt_present("notpresent")));
           }
           _ => fail!()
         }
@@ -1369,34 +1396,34 @@ fn test_multi() {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(opts_present(matches_single, [~"e"]));
-        assert!(opts_present(matches_single, [~"encrypt", ~"e"]));
-        assert!(opts_present(matches_single, [~"e", ~"encrypt"]));
-        assert!(!opts_present(matches_single, [~"encrypt"]));
-        assert!(!opts_present(matches_single, [~"thing"]));
-        assert!(!opts_present(matches_single, []));
+        assert!(matches_single.opts_present([~"e"]));
+        assert!(matches_single.opts_present([~"encrypt", ~"e"]));
+        assert!(matches_single.opts_present([~"e", ~"encrypt"]));
+        assert!(!matches_single.opts_present([~"encrypt"]));
+        assert!(!matches_single.opts_present([~"thing"]));
+        assert!(!matches_single.opts_present([]));
 
-        assert_eq!(opts_str(matches_single, [~"e"]), ~"foo");
-        assert_eq!(opts_str(matches_single, [~"e", ~"encrypt"]), ~"foo");
-        assert_eq!(opts_str(matches_single, [~"encrypt", ~"e"]), ~"foo");
+        assert_eq!(matches_single.opts_str([~"e"]).unwrap(), ~"foo");
+        assert_eq!(matches_single.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
+        assert_eq!(matches_single.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
 
         let args_both = ~[~"-e", ~"foo", ~"--encrypt", ~"foo"];
         let matches_both = &match getopts(args_both, opts) {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(opts_present(matches_both, [~"e"]));
-        assert!(opts_present(matches_both, [~"encrypt"]));
-        assert!(opts_present(matches_both, [~"encrypt", ~"e"]));
-        assert!(opts_present(matches_both, [~"e", ~"encrypt"]));
-        assert!(!opts_present(matches_both, [~"f"]));
-        assert!(!opts_present(matches_both, [~"thing"]));
-        assert!(!opts_present(matches_both, []));
+        assert!(matches_both.opts_present([~"e"]));
+        assert!(matches_both.opts_present([~"encrypt"]));
+        assert!(matches_both.opts_present([~"encrypt", ~"e"]));
+        assert!(matches_both.opts_present([~"e", ~"encrypt"]));
+        assert!(!matches_both.opts_present([~"f"]));
+        assert!(!matches_both.opts_present([~"thing"]));
+        assert!(!matches_both.opts_present([]));
 
-        assert_eq!(opts_str(matches_both, [~"e"]), ~"foo");
-        assert_eq!(opts_str(matches_both, [~"encrypt"]), ~"foo");
-        assert_eq!(opts_str(matches_both, [~"e", ~"encrypt"]), ~"foo");
-        assert_eq!(opts_str(matches_both, [~"encrypt", ~"e"]), ~"foo");
+        assert_eq!(matches_both.opts_str([~"e"]).unwrap(), ~"foo");
+        assert_eq!(matches_both.opts_str([~"encrypt"]).unwrap(), ~"foo");
+        assert_eq!(matches_both.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
+        assert_eq!(matches_both.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
     }
 
     #[test]
@@ -1407,10 +1434,10 @@ fn test_nospace() {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(opts_present(matches, [~"L"]));
-        assert_eq!(opts_str(matches, [~"L"]), ~"foo");
-        assert!(opts_present(matches, [~"M"]));
-        assert_eq!(opts_str(matches, [~"M"]), ~".");
+        assert!(matches.opts_present([~"L"]));
+        assert_eq!(matches.opts_str([~"L"]).unwrap(), ~"foo");
+        assert!(matches.opts_present([~"M"]));
+        assert_eq!(matches.opts_str([~"M"]).unwrap(), ~".");
 
     }
 
@@ -1475,7 +1502,7 @@ fn test_groups_long_to_short() {
         short.aliases = ~[reqopt("b")];
         let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
 
-        assert_eq!(groups::long_to_short(&verbose), short);
+        assert_eq!(verbose.long_to_short(), short);
     }
 
     #[test]
@@ -1519,8 +1546,8 @@ fn test_groups_aliases_long_and_short() {
         let args = ~[~"-a", ~"--apple", ~"-a"];
 
         let matches = groups::getopts(args, opts).unwrap();
-        assert_eq!(3, opt_count(&matches, "a"));
-        assert_eq!(3, opt_count(&matches, "apple"));
+        assert_eq!(3, matches.opt_count("a"));
+        assert_eq!(3, matches.opt_count("apple"));
     }
 
     #[test]
index 39a4ac618466cfebf469c2f830283821e63c6133..43a4ecf56168f6a36139eadc7a8acc1491db2a13 100644 (file)
@@ -137,16 +137,6 @@ fn list_dir_sorted(path: &Path) -> ~[Path] {
 /**
  * A compiled Unix shell style pattern.
  */
-#[cfg(stage0)]
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-pub struct Pattern {
-    priv tokens: ~[PatternToken]
-}
-
-/**
- * A compiled Unix shell style pattern.
- */
-#[cfg(not(stage0))]
 #[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
 pub struct Pattern {
     priv tokens: ~[PatternToken]
@@ -465,39 +455,10 @@ fn is_sep(c: char) -> bool {
     }
 }
 
-/**
- * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
- */
-#[cfg(stage0)]
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-pub struct MatchOptions {
-
-    /**
-     * Whether or not patterns should be matched in a case-sensitive manner. This
-     * currently only considers upper/lower case relationships between ASCII characters,
-     * but in future this might be extended to work with Unicode.
-     */
-    case_sensitive: bool,
-
-    /**
-     * If this is true then path-component separator characters (e.g. `/` on Posix)
-     * must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
-     */
-    require_literal_separator: bool,
-
-    /**
-     * If this is true then paths that contain components that start with a `.` will
-     * not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
-     * will not match. This is useful because such files are conventionally considered
-     * hidden on Unix systems and it might be desirable to skip them when listing files.
-     */
-    require_literal_leading_dot: bool
-}
 
 /**
  * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
  */
-#[cfg(not(stage0))]
 #[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
 pub struct MatchOptions {
 
index f76dc05b2773d9e9b738f02e34dd06f5ae0c06f4..e0e860d102e056da13346c1d2e383fc0edfc8be4 100644 (file)
@@ -135,18 +135,21 @@ fn emit_enum_variant(&mut self,
                          _id: uint,
                          cnt: uint,
                          f: &fn(&mut Encoder)) {
-        // enums are encoded as strings or vectors:
+        // enums are encoded as strings or objects
         // Bunny => "Bunny"
-        // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]]
-
+        // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
         if cnt == 0 {
             self.wr.write_str(escape_str(name));
         } else {
-            self.wr.write_char('[');
+            self.wr.write_char('{');
+            self.wr.write_str("\"variant\"");
+            self.wr.write_char(':');
             self.wr.write_str(escape_str(name));
             self.wr.write_char(',');
+            self.wr.write_str("\"fields\"");
+            self.wr.write_str(":[");
             f(self);
-            self.wr.write_char(']');
+            self.wr.write_str("]}");
         }
     }
 
@@ -947,14 +950,20 @@ fn read_enum_variant<T>(&mut self,
         debug!("read_enum_variant(names=%?)", names);
         let name = match self.stack.pop() {
             String(s) => s,
-            List(list) => {
-                for v in list.move_rev_iter() {
-                    self.stack.push(v);
-                }
-                match self.stack.pop() {
-                    String(s) => s,
-                    value => fail!("invalid variant name: %?", value),
+            Object(o) => {
+                let n = match o.find(&~"variant").expect("invalidly encoded json") {
+                    &String(ref s) => s.clone(),
+                    _ => fail!("invalidly encoded json"),
+                };
+                match o.find(&~"fields").expect("invalidly encoded json") {
+                    &List(ref l) => {
+                        for field in l.rev_iter() {
+                            self.stack.push(field.clone());
+                        }
+                    },
+                    _ => fail!("invalidly encoded json")
                 }
+                n
             }
             ref json => fail!("invalid variant: %?", *json),
         };
@@ -1517,7 +1526,7 @@ fn test_write_enum() {
                 let mut encoder = Encoder(wr);
                 animal.encode(&mut encoder);
             },
-            ~"[\"Frog\",\"Henry\",349]"
+            ~"{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
         );
         assert_eq!(
             do io::with_str_writer |wr| {
@@ -1921,14 +1930,14 @@ fn test_decode_enum() {
         assert_eq!(value, Dog);
 
         let mut decoder =
-            Decoder(from_str("[\"Frog\",\"Henry\",349]").unwrap());
+            Decoder(from_str("{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}").unwrap());
         let value: Animal = Decodable::decode(&mut decoder);
         assert_eq!(value, Frog(~"Henry", 349));
     }
 
     #[test]
     fn test_decode_map() {
-        let s = ~"{\"a\": \"Dog\", \"b\": [\"Frog\", \"Henry\", 349]}";
+        let s = ~"{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\"fields\":[\"Henry\", 349]}}";
         let mut decoder = Decoder(from_str(s).unwrap());
         let mut map: TreeMap<~str, Animal> = Decodable::decode(&mut decoder);
 
index 24f44c8a2a8ec5ab7ca1b3e56ea727ffe1abb973..936efed94e474c2012a780db72b0789e4dd9476a 100644 (file)
@@ -115,8 +115,8 @@ fn cmp(&self, other: &BigUint) -> Ordering {
         if s_len > o_len { return Greater;  }
 
         for (&self_i, &other_i) in self.data.rev_iter().zip(other.data.rev_iter()) {
-            cond!((self_i < other_i) { return Less; }
-                  (self_i > other_i) { return Greater; })
+            if self_i < other_i { return Less; }
+            if self_i > other_i { return Greater; }
         }
         return Equal;
     }
@@ -697,6 +697,13 @@ fn shr_bits(&self, n_bits: uint) -> BigUint {
         }
         return BigUint::new(shifted);
     }
+
+    /// Determines the fewest bits necessary to express the BigUint.
+    pub fn bits(&self) -> uint {
+        if self.is_zero() { return 0; }
+        let zeros = self.data.last().leading_zeros();
+        return self.data.len()*BigDigit::bits - (zeros as uint);
+    }
 }
 
 #[cfg(target_word_size = "64")]
@@ -1115,10 +1122,23 @@ trait RandBigInt {
 
     /// Generate a random BigInt of the given bit size.
     fn gen_bigint(&mut self, bit_size: uint) -> BigInt;
+
+    /// Generate a random BigUint less than the given bound. Fails
+    /// when the bound is zero.
+    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint;
+
+    /// Generate a random BigUint within the given range. The lower
+    /// bound is inclusive; the upper bound is exclusive. Fails when
+    /// the upper bound is not greater than the lower bound.
+    fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;
+
+    /// Generate a random BigInt within the given range. The lower
+    /// bound is inclusive; the upper bound is exclusive. Fails when
+    /// the upper bound is not greater than the lower bound.
+    fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
 }
 
 impl<R: Rng> RandBigInt for R {
-    /// Generate a random BigUint of the given bit size.
     fn gen_biguint(&mut self, bit_size: uint) -> BigUint {
         let (digits, rem) = bit_size.div_rem(&BigDigit::bits);
         let mut data = vec::with_capacity(digits+1);
@@ -1132,7 +1152,6 @@ fn gen_biguint(&mut self, bit_size: uint) -> BigUint {
         return BigUint::new(data);
     }
 
-    /// Generate a random BigInt of the given bit size.
     fn gen_bigint(&mut self, bit_size: uint) -> BigInt {
         // Generate a random BigUint...
         let biguint = self.gen_biguint(bit_size);
@@ -1154,6 +1173,32 @@ fn gen_bigint(&mut self, bit_size: uint) -> BigInt {
         };
         return BigInt::from_biguint(sign, biguint);
     }
+
+    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
+        assert!(!bound.is_zero());
+        let bits = bound.bits();
+        loop {
+            let n = self.gen_biguint(bits);
+            if n < *bound { return n; }
+        }
+    }
+
+    fn gen_biguint_range(&mut self,
+                         lbound: &BigUint,
+                         ubound: &BigUint)
+                         -> BigUint {
+        assert!(*lbound < *ubound);
+        return *lbound + self.gen_biguint_below(&(*ubound - *lbound));
+    }
+
+    fn gen_bigint_range(&mut self,
+                        lbound: &BigInt,
+                        ubound: &BigInt)
+                        -> BigInt {
+        assert!(*lbound < *ubound);
+        let delta = (*ubound - *lbound).to_biguint();
+        return *lbound + self.gen_biguint_below(&delta).to_bigint();
+    }
 }
 
 impl BigInt {
@@ -1780,12 +1825,63 @@ fn check(n: uint, s: &str) {
         check(30, "265252859812191058636308480000000");
     }
 
+    #[test]
+    fn test_bits() {
+        assert_eq!(BigUint::new(~[0,0,0,0]).bits(), 0);
+        assert_eq!(BigUint::from_uint(0).bits(), 0);
+        assert_eq!(BigUint::from_uint(1).bits(), 1);
+        assert_eq!(BigUint::from_uint(3).bits(), 2);
+        let n: BigUint = FromStrRadix::from_str_radix("4000000000", 16).unwrap();
+        assert_eq!(n.bits(), 39);
+        let one: BigUint = One::one();
+        assert_eq!((one << 426).bits(), 427);
+    }
+
     #[test]
     fn test_rand() {
         let mut rng = task_rng();
         let _n: BigUint = rng.gen_biguint(137);
         assert!(rng.gen_biguint(0).is_zero());
     }
+
+    #[test]
+    fn test_rand_range() {
+        let mut rng = task_rng();
+
+        do 10.times {
+            assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236),
+                                            &BigInt::from_uint(237)),
+                       BigInt::from_uint(236));
+        }
+
+        let l = BigUint::from_uint(403469000 + 2352);
+        let u = BigUint::from_uint(403469000 + 3513);
+        do 1000.times {
+            let n: BigUint = rng.gen_biguint_below(&u);
+            assert!(n < u);
+
+            let n: BigUint = rng.gen_biguint_range(&l, &u);
+            assert!(n >= l);
+            assert!(n < u);
+        }
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_zero_rand_range() {
+        task_rng().gen_biguint_range(&BigUint::from_uint(54),
+                                     &BigUint::from_uint(54));
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_negative_rand_range() {
+        let mut rng = task_rng();
+        let l = BigUint::from_uint(2352);
+        let u = BigUint::from_uint(3513);
+        // Switching u and l should fail:
+        let _n: BigUint = rng.gen_biguint_range(&u, &l);
+    }
 }
 
 #[cfg(test)]
@@ -2237,6 +2333,48 @@ fn test_rand() {
         let _n: BigInt = rng.gen_bigint(137);
         assert!(rng.gen_bigint(0).is_zero());
     }
+
+    #[test]
+    fn test_rand_range() {
+        let mut rng = task_rng();
+
+        do 10.times {
+            assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236),
+                                            &BigInt::from_uint(237)),
+                       BigInt::from_uint(236));
+        }
+
+        fn check(l: BigInt, u: BigInt) {
+            let mut rng = task_rng();
+            do 1000.times {
+                let n: BigInt = rng.gen_bigint_range(&l, &u);
+                assert!(n >= l);
+                assert!(n < u);
+            }
+        }
+        let l = BigInt::from_uint(403469000 + 2352);
+        let u = BigInt::from_uint(403469000 + 3513);
+        check( l.clone(),  u.clone());
+        check(-l.clone(),  u.clone());
+        check(-u.clone(), -l.clone());
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_zero_rand_range() {
+        task_rng().gen_bigint_range(&IntConvertible::from_int(54),
+                                    &IntConvertible::from_int(54));
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_negative_rand_range() {
+        let mut rng = task_rng();
+        let l = BigInt::from_uint(2352);
+        let u = BigInt::from_uint(3513);
+        // Switching u and l should fail:
+        let _n: BigInt = rng.gen_bigint_range(&u, &l);
+    }
 }
 
 #[cfg(test)]
index 86fbbd4c3cc597f62e4978a9e26904cd295d7b65..fa7cd9025eb7ce2bd65f1acc6945e7dfcff5ebc2 100644 (file)
@@ -73,7 +73,7 @@ pub fn borrow<'r>(&'r self) -> &'r T {
 
 #[unsafe_destructor]
 impl<T> Drop for Rc<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             if self.ptr.is_not_null() {
                 (*self.ptr).count -= 1;
@@ -218,7 +218,7 @@ pub fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U {
 
 #[unsafe_destructor]
 impl<T> Drop for RcMut<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             if self.ptr.is_not_null() {
                 (*self.ptr).count -= 1;
index 74b7aea99787794ad9735519ca9a49023b285d5d..9476bcb8926ee705e9a119c3fea47dc0343b850c 100644 (file)
 use std::{local_data, str, rt};
 use std::unstable::finally::Finally;
 
-#[cfg(stage0)]
-pub mod rustrt {
-    use std::libc::{c_char, c_int};
-
-    extern {
-        fn linenoise(prompt: *c_char) -> *c_char;
-        fn linenoiseHistoryAdd(line: *c_char) -> c_int;
-        fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
-        fn linenoiseHistorySave(file: *c_char) -> c_int;
-        fn linenoiseHistoryLoad(file: *c_char) -> c_int;
-        fn linenoiseSetCompletionCallback(callback: *u8);
-        fn linenoiseAddCompletion(completions: *(), line: *c_char);
-
-        fn rust_take_linenoise_lock();
-        fn rust_drop_linenoise_lock();
-    }
-}
-
-#[cfg(not(stage0))]
 pub mod rustrt {
     use std::libc::{c_char, c_int};
 
@@ -109,7 +90,7 @@ pub fn read(prompt: &str) -> Option<~str> {
 
 pub type CompletionCb = @fn(~str, @fn(~str));
 
-static complete_key: local_data::Key<CompletionCb> = &local_data::Key;
+local_data_key!(complete_key: CompletionCb)
 
 /// Bind to the main completion callback in the current task.
 ///
index f1bf9e81c7251238224989d37622efa4afe6770f..46244c15a832eb2a1d472cce72c8783db2f48620 100644 (file)
@@ -34,7 +34,7 @@ pub struct TaskPool<T> {
 
 #[unsafe_destructor]
 impl<T> Drop for TaskPool<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         for channel in self.channels.iter() {
             channel.send(Quit);
         }
index 4dcb48d27516e6661d368cb563f333506e6f3e28..cc80da1506aa17b3a16118609dd6ff3f3cbcb37e 100644 (file)
@@ -226,11 +226,11 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
     let matches =
         match groups::getopts(args_, optgroups()) {
           Ok(m) => m,
-          Err(f) => return Err(getopts::fail_str(f))
+          Err(f) => return Err(f.to_err_msg())
         };
 
-    if getopts::opt_present(&matches, "h") { usage(args[0], "h"); }
-    if getopts::opt_present(&matches, "help") { usage(args[0], "help"); }
+    if matches.opt_present("h") { usage(args[0], "h"); }
+    if matches.opt_present("help") { usage(args[0], "help"); }
 
     let filter =
         if matches.free.len() > 0 {
@@ -239,25 +239,25 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
             None
         };
 
-    let run_ignored = getopts::opt_present(&matches, "ignored");
+    let run_ignored = matches.opt_present("ignored");
 
-    let logfile = getopts::opt_maybe_str(&matches, "logfile");
+    let logfile = matches.opt_str("logfile");
     let logfile = logfile.map_move(|s| Path(s));
 
-    let run_benchmarks = getopts::opt_present(&matches, "bench");
+    let run_benchmarks = matches.opt_present("bench");
     let run_tests = ! run_benchmarks ||
-        getopts::opt_present(&matches, "test");
+        matches.opt_present("test");
 
-    let ratchet_metrics = getopts::opt_maybe_str(&matches, "ratchet-metrics");
+    let ratchet_metrics = matches.opt_str("ratchet-metrics");
     let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s));
 
-    let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent");
+    let ratchet_noise_percent = matches.opt_str("ratchet-noise-percent");
     let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| from_str::<f64>(s).unwrap());
 
-    let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics");
+    let save_metrics = matches.opt_str("save-metrics");
     let save_metrics = save_metrics.map_move(|s| Path(s));
 
-    let test_shard = getopts::opt_maybe_str(&matches, "test-shard");
+    let test_shard = matches.opt_str("test-shard");
     let test_shard = opt_shard(test_shard);
 
     let test_opts = TestOpts {
index 2b2ecb79294c456b68782631c28b498cd4efe573..24ab8360e8fab4ff2ddc6c9bb6defabbbd979d4a 100644 (file)
@@ -198,10 +198,9 @@ fn load(&mut self) {
     }
 }
 
-// FIXME #4330: use &mut self here
 #[unsafe_destructor]
 impl Drop for Database {
-    fn drop(&self) {
+    fn drop(&mut self) {
         if self.db_dirty {
             self.save();
         }
index 18a7e65a6dd7af2f5d2bf1e950a098b6c61963c7..ee7fbed9e9f1183846e4cd515f93aa75bef2c22f 100644 (file)
@@ -105,7 +105,7 @@ pub trait Engine {}
     impl Engine for LLVMJITData {}
 
     impl Drop for LLVMJITData {
-        fn drop(&self) {
+        fn drop(&mut self) {
             unsafe {
                 llvm::LLVMDisposeExecutionEngine(self.ee);
                 llvm::LLVMContextDispose(self.llcx);
@@ -190,7 +190,7 @@ pub fn exec(sess: Session,
 
     // The stage1 compiler won't work, but that doesn't really matter. TLS
     // changed only very recently to allow storage of owned values.
-    static engine_key: local_data::Key<~Engine> = &local_data::Key;
+    local_data_key!(engine_key: ~Engine)
 
     fn set_engine(engine: ~Engine) {
         local_data::set(engine_key, engine)
index 5078d0ded18d129e225bf7d56ccf3031634d38e1..bd0462119bdedb0b06d1a9e80d794b4aeb71cd50 100644 (file)
@@ -30,7 +30,6 @@
 use std::os;
 use std::vec;
 use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt};
-use extra::getopts::{opt_present};
 use extra::getopts;
 use syntax::ast;
 use syntax::abi;
@@ -606,15 +605,15 @@ pub fn build_session_options(binary: @str,
                              matches: &getopts::Matches,
                              demitter: diagnostic::Emitter)
                           -> @session::options {
-    let crate_type = if opt_present(matches, "lib") {
+    let crate_type = if matches.opt_present("lib") {
         session::lib_crate
-    } else if opt_present(matches, "bin") {
+    } else if matches.opt_present("bin") {
         session::bin_crate
     } else {
         session::unknown_crate
     };
-    let parse_only = opt_present(matches, "parse-only");
-    let no_trans = opt_present(matches, "no-trans");
+    let parse_only = matches.opt_present("parse-only");
+    let no_trans = matches.opt_present("no-trans");
 
     let lint_levels = [lint::allow, lint::warn,
                        lint::deny, lint::forbid];
@@ -627,8 +626,8 @@ pub fn build_session_options(binary: @str,
         // to_ascii_move and to_str_move to not do a unnecessary copy.
         let level_short = level_name.slice_chars(0, 1);
         let level_short = level_short.to_ascii().to_upper().to_str_ascii();
-        let flags = vec::append(getopts::opt_strs(matches, level_short),
-                                getopts::opt_strs(matches, level_name));
+        let flags = vec::append(matches.opt_strs(level_short),
+                                matches.opt_strs(level_name));
         for lint_name in flags.iter() {
             let lint_name = lint_name.replace("-", "_");
             match lint_dict.find_equiv(&lint_name) {
@@ -644,7 +643,7 @@ pub fn build_session_options(binary: @str,
     }
 
     let mut debugging_opts = 0u;
-    let debug_flags = getopts::opt_strs(matches, "Z");
+    let debug_flags = matches.opt_strs("Z");
     let debug_map = session::debugging_opts_map();
     for debug_flag in debug_flags.iter() {
         let mut this_bit = 0u;
@@ -670,31 +669,31 @@ fn set_llvm_debug() {
     let output_type =
         if parse_only || no_trans {
             link::output_type_none
-        } else if opt_present(matches, "S") &&
-                  opt_present(matches, "emit-llvm") {
+        } else if matches.opt_present("S") &&
+                  matches.opt_present("emit-llvm") {
             link::output_type_llvm_assembly
-        } else if opt_present(matches, "S") {
+        } else if matches.opt_present("S") {
             link::output_type_assembly
-        } else if opt_present(matches, "c") {
+        } else if matches.opt_present("c") {
             link::output_type_object
-        } else if opt_present(matches, "emit-llvm") {
+        } else if matches.opt_present("emit-llvm") {
             link::output_type_bitcode
         } else { link::output_type_exe };
-    let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
-    let target = getopts::opt_maybe_str(matches, "target").unwrap_or(host_triple());
-    let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or(~"generic");
-    let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or(~"");
-    let save_temps = getopts::opt_present(matches, "save-temps");
+    let sysroot_opt = matches.opt_str("sysroot").map_move(|m| @Path(m));
+    let target = matches.opt_str("target").unwrap_or(host_triple());
+    let target_cpu = matches.opt_str("target-cpu").unwrap_or(~"generic");
+    let target_feature = matches.opt_str("target-feature").unwrap_or(~"");
+    let save_temps = matches.opt_present("save-temps");
     let opt_level = {
         if (debugging_opts & session::no_opt) != 0 {
             No
-        } else if opt_present(matches, "O") {
-            if opt_present(matches, "opt-level") {
+        } else if matches.opt_present("O") {
+            if matches.opt_present("opt-level") {
                 early_error(demitter, ~"-O and --opt-level both provided");
             }
             Default
-        } else if opt_present(matches, "opt-level") {
-            match getopts::opt_str(matches, "opt-level") {
+        } else if matches.opt_present("opt-level") {
+            match matches.opt_str("opt-level").unwrap() {
               ~"0" => No,
               ~"1" => Less,
               ~"2" => Default,
@@ -720,18 +719,17 @@ fn set_llvm_debug() {
 
     let statik = debugging_opts & session::statik != 0;
 
-    let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
-    let linker = getopts::opt_maybe_str(matches, "linker");
-    let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
+    let addl_lib_search_paths = matches.opt_strs("L").map(|s| Path(*s));
+    let linker = matches.opt_str("linker");
+    let linker_args = matches.opt_strs("link-args").flat_map( |a| {
         a.split_iter(' ').map(|arg| arg.to_owned()).collect()
     });
 
-    let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
-    let test = opt_present(matches, "test");
-    let android_cross_path = getopts::opt_maybe_str(
-        matches, "android-cross-path");
+    let cfg = parse_cfgspecs(matches.opt_strs("cfg"), demitter);
+    let test = matches.opt_present("test");
+    let android_cross_path = matches.opt_str("android-cross-path");
 
-    let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
+    let custom_passes = match matches.opt_str("passes") {
         None => ~[],
         Some(s) => {
             s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
@@ -739,7 +737,7 @@ fn set_llvm_debug() {
             }).collect()
         }
     };
-    let llvm_args = match getopts::opt_maybe_str(matches, "llvm-args") {
+    let llvm_args = match matches.opt_str("llvm-args") {
         None => ~[],
         Some(s) => {
             s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
@@ -1020,7 +1018,6 @@ mod test {
     use driver::driver::{build_session_options, optgroups};
 
     use extra::getopts::groups::getopts;
-    use extra::getopts;
     use syntax::attr;
     use syntax::diagnostic;
 
@@ -1030,7 +1027,7 @@ fn test_switch_implies_cfg_test() {
         let matches =
             &match getopts([~"--test"], optgroups()) {
               Ok(m) => m,
-              Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
+              Err(f) => fail!("test_switch_implies_cfg_test: %s", f.to_err_msg())
             };
         let sessopts = build_session_options(
             @"rustc", matches, diagnostic::emit);
@@ -1047,7 +1044,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
             &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
               Ok(m) => m,
               Err(f) => {
-                fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
+                fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", f.to_err_msg());
               }
             };
         let sessopts = build_session_options(
index 9c7880651337a8ff8236d3a9382de122ccf5cfad..49176c7bc17d53559ab858c81fd85b40092c0303 100644 (file)
@@ -293,50 +293,6 @@ fn mk_std(cx: &TestCtxt) -> ast::view_item {
     }
 }
 
-#[cfg(stage0)]
-fn mk_test_module(cx: &TestCtxt) -> @ast::item {
-
-    // Link to extra
-    let view_items = ~[mk_std(cx)];
-
-    // A constant vector of test descriptors.
-    let tests = mk_tests(cx);
-
-    // The synthesized main function which will call the console test runner
-    // with our list of tests
-    let ext_cx = cx.ext_cx;
-    let mainfn = (quote_item!(
-        pub fn main() {
-            #[main];
-            extra::test::test_main_static(::std::os::args(), TESTS);
-        }
-    )).unwrap();
-
-    let testmod = ast::_mod {
-        view_items: view_items,
-        items: ~[mainfn, tests],
-    };
-    let item_ = ast::item_mod(testmod);
-
-    // This attribute tells resolve to let us call unexported functions
-    let resolve_unexported_attr =
-        attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));
-
-    let item = ast::item {
-        ident: cx.sess.ident_of("__test"),
-        attrs: ~[resolve_unexported_attr],
-        id: ast::DUMMY_NODE_ID,
-        node: item_,
-        vis: ast::public,
-        span: dummy_sp(),
-     };
-
-    debug!("Synthetic test module:\n%s\n",
-           pprust::item_to_str(@item.clone(), cx.sess.intr()));
-
-    return @item;
-}
-#[cfg(not(stage0))]
 fn mk_test_module(cx: &TestCtxt) -> @ast::item {
 
     // Link to extra
@@ -407,21 +363,6 @@ fn path_node_global(ids: ~[ast::Ident]) -> ast::Path {
     }
 }
 
-#[cfg(stage0)]
-fn mk_tests(cx: &TestCtxt) -> @ast::item {
-
-    let ext_cx = cx.ext_cx;
-
-    // The vector of test_descs for this crate
-    let test_descs = mk_test_descs(cx);
-
-    (quote_item!(
-        pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
-            $test_descs
-        ;
-    )).unwrap()
-}
-#[cfg(not(stage0))]
 fn mk_tests(cx: &TestCtxt) -> @ast::item {
     // The vector of test_descs for this crate
     let test_descs = mk_test_descs(cx);
@@ -461,63 +402,6 @@ fn mk_test_descs(cx: &TestCtxt) -> @ast::Expr {
     }
 }
 
-#[cfg(stage0)]
-fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
-    let span = test.span;
-    let path = test.path.clone();
-
-    let ext_cx = cx.ext_cx;
-
-    debug!("encoding %s", ast_util::path_name_i(path));
-
-    let name_lit: ast::lit =
-        nospan(ast::lit_str(ast_util::path_name_i(path).to_managed()));
-
-    let name_expr = @ast::Expr {
-          id: ast::DUMMY_NODE_ID,
-          node: ast::ExprLit(@name_lit),
-          span: span
-    };
-
-    let fn_path = path_node_global(path);
-
-    let fn_expr = @ast::Expr {
-        id: ast::DUMMY_NODE_ID,
-        node: ast::ExprPath(fn_path),
-        span: span,
-    };
-
-    let t_expr = if test.bench {
-        quote_expr!( self::extra::test::StaticBenchFn($fn_expr) )
-    } else {
-        quote_expr!( self::extra::test::StaticTestFn($fn_expr) )
-    };
-
-    let ignore_expr = if test.ignore {
-        quote_expr!( true )
-    } else {
-        quote_expr!( false )
-    };
-
-    let fail_expr = if test.should_fail {
-        quote_expr!( true )
-    } else {
-        quote_expr!( false )
-    };
-
-    let e = quote_expr!(
-        self::extra::test::TestDescAndFn {
-            desc: self::extra::test::TestDesc {
-                name: self::extra::test::StaticTestName($name_expr),
-                ignore: $ignore_expr,
-                should_fail: $fail_expr
-            },
-            testfn: $t_expr,
-        }
-    );
-    e
-}
-#[cfg(not(stage0))]
 fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
     let span = test.span;
     let path = test.path.clone();
index beadcf3a19df8282bb06091ddf4f56c730703dab..49798288d40d0820b4343e4911b787be5176ab33 100644 (file)
@@ -2325,7 +2325,7 @@ pub struct target_data_res {
 }
 
 impl Drop for target_data_res {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposeTargetData(self.TD);
         }
@@ -2361,7 +2361,7 @@ pub struct pass_manager_res {
 }
 
 impl Drop for pass_manager_res {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposePassManager(self.PM);
         }
@@ -2397,7 +2397,7 @@ pub struct object_file_res {
 }
 
 impl Drop for object_file_res {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposeObjectFile(self.ObjectFile);
         }
@@ -2434,7 +2434,7 @@ pub struct section_iter_res {
 }
 
 impl Drop for section_iter_res {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposeSectionIterator(self.SI);
         }
index 692e4e345df63fb84ea128c48c226141b1fb5dca..9e65e4ec18a97685311070f4239efe2c9cd23e9a 100644 (file)
@@ -60,6 +60,7 @@ pub struct EncodeParams<'self> {
     reexports2: middle::resolve::ExportMap2,
     item_symbols: &'self HashMap<ast::NodeId, ~str>,
     discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+    non_inlineable_statics: &'self HashSet<ast::NodeId>,
     link_meta: &'self LinkMeta,
     cstore: @mut cstore::CStore,
     encode_inlined_item: encode_inlined_item<'self>,
@@ -89,6 +90,7 @@ pub struct EncodeContext<'self> {
     reexports2: middle::resolve::ExportMap2,
     item_symbols: &'self HashMap<ast::NodeId, ~str>,
     discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+    non_inlineable_statics: &'self HashSet<ast::NodeId>,
     link_meta: &'self LinkMeta,
     cstore: &'self cstore::CStore,
     encode_inlined_item: encode_inlined_item<'self>,
@@ -907,7 +909,9 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
         encode_name(ecx, ebml_w, item.ident);
         let elt = ast_map::path_pretty_name(item.ident, item.id as u64);
         encode_path(ecx, ebml_w, path, elt);
-        (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+        if !ecx.non_inlineable_statics.contains(&item.id) {
+            (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+        }
         ebml_w.end_tag();
       }
       item_fn(_, purity, _, ref generics, _) => {
@@ -1728,6 +1732,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         encode_inlined_item,
         link_meta,
         reachable,
+        non_inlineable_statics,
         _
     } = parms;
     let type_abbrevs = @mut HashMap::new();
@@ -1739,6 +1744,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         reexports2: reexports2,
         item_symbols: item_symbols,
         discrim_symbols: discrim_symbols,
+        non_inlineable_statics: non_inlineable_statics,
         link_meta: link_meta,
         cstore: cstore,
         encode_inlined_item: encode_inlined_item,
index 2e5e87f225a2acd700a2d95aa9dafa94bbf19d45..bba3ca9f212a9897c60e03f200ca6e37ecf9af55 100644 (file)
@@ -19,7 +19,6 @@
 use syntax::visit::Visitor;
 use syntax::ast::*;
 
-use std::float;
 use std::hashmap::{HashMap, HashSet};
 
 //
@@ -476,9 +475,9 @@ pub fn lit_to_const(lit: &lit) -> const_val {
       lit_int(n, _) => const_int(n),
       lit_uint(n, _) => const_uint(n),
       lit_int_unsuffixed(n) => const_int(n),
-      lit_float(n, _) => const_float(float::from_str(n).unwrap() as f64),
+      lit_float(n, _) => const_float(from_str::<float>(n).unwrap() as f64),
       lit_float_unsuffixed(n) =>
-        const_float(float::from_str(n).unwrap() as f64),
+        const_float(from_str::<float>(n).unwrap() as f64),
       lit_nil => const_int(0i64),
       lit_bool(b) => const_bool(b)
     }
index 62fbdc41b0e7046f34187a15e71b725ce7fd1d2d..d27bcde20649cf8fda14d52b1ebd5c928b0a526e 100644 (file)
@@ -324,15 +324,16 @@ fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result {
             return single_result(datumblock.to_result(bcx));
         }
         lit(ConstLit(lit_id)) => {
-            let llval = consts::get_const_val(bcx.ccx(), lit_id);
+            let (llval, _) = consts::get_const_val(bcx.ccx(), lit_id);
             return single_result(rslt(bcx, llval));
         }
         var(disr_val, repr) => {
             return adt::trans_case(bcx, repr, disr_val);
         }
         range(l1, l2) => {
-            return range_result(rslt(bcx, consts::const_expr(ccx, l1)),
-                                rslt(bcx, consts::const_expr(ccx, l2)));
+            let (l1, _) = consts::const_expr(ccx, l1);
+            let (l2, _) = consts::const_expr(ccx, l2);
+            return range_result(rslt(bcx, l1), rslt(bcx, l2));
         }
         vec_len(n, vec_len_eq, _) => {
             return single_result(rslt(bcx, C_int(ccx, n as int)));
index f0238e8f5c5501ee25fb5b9efba97ec386393c21..f7fcd8f908d714809109b70cdb803f127ace295a 100644 (file)
@@ -92,7 +92,7 @@
 
 pub use middle::trans::context::task_llcx;
 
-static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key;
+local_data_key!(task_local_insn_key: @~[&'static str])
 
 pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
     let opt = local_data::get(task_local_insn_key, |k| k.map_move(|k| *k));
@@ -109,7 +109,7 @@ pub struct _InsnCtxt { _x: () }
 
 #[unsafe_destructor]
 impl Drop for _InsnCtxt {
-    fn drop(&self) {
+    fn drop(&mut self) {
         do local_data::modify(task_local_insn_key) |c| {
             do c.map_move |ctx| {
                 let mut ctx = (*ctx).clone();
@@ -159,7 +159,7 @@ pub fn new(ccx: @mut CrateContext,
 
 #[unsafe_destructor]
 impl<'self> Drop for StatRecorder<'self> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         if self.ccx.sess.trans_stats() {
             let end = time::precise_time_ns();
             let elapsed = ((end - self.start) / 1_000_000) as uint;
@@ -174,6 +174,7 @@ fn drop(&self) {
     }
 }
 
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
 pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
     let llfn: ValueRef = do name.with_c_str |buf| {
         unsafe {
@@ -185,18 +186,12 @@ pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type)
     return llfn;
 }
 
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
 pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
     return decl_fn(llmod, name, lib::llvm::CCallConv, ty);
 }
 
-// Only use this if you are going to actually define the function. It's
-// not valid to simply declare a function as internal.
-pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
-    let llfn = decl_cdecl_fn(llmod, name, ty);
-    lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
-    return llfn;
-}
-
+// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
 pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
                      cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
     match externs.find_equiv(&name) {
@@ -205,7 +200,73 @@ pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
     }
     let f = decl_fn(llmod, name, cc, ty);
     externs.insert(name.to_owned(), f);
-    return f;
+    f
+}
+
+pub fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+                          name: &str) -> ValueRef {
+    match ccx.externs.find_equiv(&name) {
+        Some(n) => return *n,
+        None => ()
+    }
+    let f = decl_rust_fn(ccx, inputs, output, name);
+    ccx.externs.insert(name.to_owned(), f);
+    f
+}
+
+pub fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+                    name: &str) -> ValueRef {
+    let llfty = type_of_rust_fn(ccx, inputs, output);
+    let llfn = decl_cdecl_fn(ccx.llmod, name, llfty);
+
+    match ty::get(output).sty {
+        // `~` pointer return values never alias because ownership is transferred
+        ty::ty_uniq(*) |
+        ty::ty_evec(_, ty::vstore_uniq) => {
+            unsafe {
+                llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
+            }
+        }
+        _ => ()
+    }
+
+    let uses_outptr = type_of::return_uses_outptr(ccx.tcx, output);
+    let offset = if uses_outptr { 2 } else { 1 };
+
+    for (i, &arg_ty) in inputs.iter().enumerate() {
+        let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
+        match ty::get(arg_ty).sty {
+            // `~` pointer parameters never alias because ownership is transferred
+            ty::ty_uniq(*) |
+            ty::ty_evec(_, ty::vstore_uniq) |
+            ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
+                unsafe {
+                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
+                }
+            }
+            _ => ()
+        }
+    }
+
+    // The out pointer will never alias with any other pointers, as the object only exists at a
+    // language level after the call. It can also be tagged with SRet to indicate that it is
+    // guaranteed to point to a usable block of memory for the type.
+    if uses_outptr {
+        unsafe {
+            let outptr = llvm::LLVMGetParam(llfn, 0);
+            llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint);
+            llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint);
+        }
+    }
+
+    llfn
+}
+
+pub fn decl_internal_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+                             name: &str) -> ValueRef {
+    let llfn = decl_rust_fn(ccx, inputs, output, name);
+    lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
+    llfn
 }
 
 pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
@@ -809,33 +870,30 @@ pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
     C_null(Type::opaque_box(ccx).ptr_to())
 }
 
-pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t)
-    -> ValueRef {
+pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
     let name = csearch::get_symbol(ccx.sess.cstore, did);
     match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
-            // Currently llvm_calling_convention triggers unimpl/bug on
-            // Rust/RustIntrinsic, so those two are handled specially here.
-            let cconv = match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
-                Some(Rust) | Some(RustIntrinsic) => lib::llvm::CCallConv,
+            match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
+                Some(Rust) | Some(RustIntrinsic) => {
+                    get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name)
+                }
                 Some(*) | None => {
                     let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
-                    c.unwrap_or(lib::llvm::CCallConv)
+                    let cconv = c.unwrap_or(lib::llvm::CCallConv);
+                    let llty = type_of_fn_from_ty(ccx, t);
+                    get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty)
                 }
-            };
-            let llty = type_of_fn_from_ty(ccx, t);
-            return get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty);
+            }
         }
-        ty::ty_closure(_) => {
-            let llty = type_of_fn_from_ty(ccx, t);
-            return get_extern_fn(&mut ccx.externs, ccx.llmod, name,
-            lib::llvm::CCallConv, llty);
+        ty::ty_closure(ref f) => {
+            get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name)
         }
         _ => {
             let llty = type_of(ccx, t);
-            return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
+            get_extern_const(&mut ccx.externs, ccx.llmod, name, llty)
         }
-    };
+    }
 }
 
 pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
@@ -868,7 +926,8 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
                               llfn,
                               llargs,
                               normal_bcx.llbb,
-                              get_landing_pad(bcx));
+                              get_landing_pad(bcx),
+                              attributes);
         return (llresult, normal_bcx);
     } else {
         unsafe {
@@ -1707,8 +1766,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
 // field of the fn_ctxt with
 pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
                                  self_arg: self_arg,
-                                 args: &[ast::arg],
-                                 arg_tys: &[ty::t])
+                                 args: &[ast::arg])
                               -> ~[ValueRef] {
     let _icx = push_ctxt("create_llargs_for_fn_args");
 
@@ -1726,23 +1784,7 @@ pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
     // Return an array containing the ValueRefs that we get from
     // llvm::LLVMGetParam for each argument.
     do vec::from_fn(args.len()) |i| {
-        let arg_n = cx.arg_pos(i);
-        let arg_ty = arg_tys[i];
-        let llarg = unsafe {llvm::LLVMGetParam(cx.llfn, arg_n as c_uint) };
-
-        match ty::get(arg_ty).sty {
-            // `~` pointer parameters never alias because ownership is transferred
-            ty::ty_uniq(*) |
-            ty::ty_evec(_, ty::vstore_uniq) |
-            ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
-                unsafe {
-                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
-                }
-            }
-            _ => ()
-        }
-
-        llarg
+        unsafe { llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint) }
     }
 }
 
@@ -1896,8 +1938,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
 
     // Set up arguments to the function.
     let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
-    let raw_llargs = create_llargs_for_fn_args(fcx, self_arg,
-                                               decl.inputs, arg_tys);
+    let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
 
     // Set the fixed stack segment flag if necessary.
     if attr::contains_name(attributes, "fixed_stack_segment") {
@@ -1961,18 +2002,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
            param_substs.repr(ccx.tcx));
     let _icx = push_ctxt("trans_fn");
     let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
-
-    match ty::get(output_type).sty {
-        // `~` pointer return values never alias because ownership is transferred
-        ty::ty_uniq(*) |
-        ty::ty_evec(_, ty::vstore_uniq) => {
-            unsafe {
-                llvm::LLVMAddReturnAttribute(llfndecl, lib::llvm::NoAliasAttribute as c_uint);
-            }
-        }
-        _ => ()
-    }
-
     trans_closure(ccx,
                   path.clone(),
                   decl,
@@ -2120,7 +2149,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
 
     let arg_tys = ty::ty_fn_args(ctor_ty);
 
-    let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, arg_tys);
+    let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
 
     let bcx = fcx.entry_bcx.unwrap();
 
@@ -2298,10 +2327,28 @@ pub fn register_fn(ccx: @mut CrateContext,
                    node_id: ast::NodeId,
                    node_type: ty::t)
                    -> ValueRef {
-    let llfty = type_of_fn_from_ty(ccx, node_type);
-    register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
+    let f = match ty::get(node_type).sty {
+        ty::ty_bare_fn(ref f) => {
+            assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+            f
+        }
+        _ => fail!("expected bare rust fn or an intrinsic")
+    };
+
+    let llfn = decl_rust_fn(ccx, f.sig.inputs, f.sig.output, sym);
+    ccx.item_symbols.insert(node_id, sym);
+
+    // FIXME #4404 android JNI hacks
+    let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
+                      (*ccx.sess.building_library &&
+                       ccx.sess.targ_cfg.os == session::OsAndroid));
+    if is_entry {
+        create_entry_wrapper(ccx, sp, llfn);
+    }
+    llfn
 }
 
+// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
 pub fn register_fn_llvmty(ccx: @mut CrateContext,
                           sp: Span,
                           sym: ~str,
@@ -2341,38 +2388,12 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
     let et = ccx.sess.entry_type.unwrap();
     match et {
         session::EntryMain => {
-            let llfn = create_main(ccx, main_llfn);
-            create_entry_fn(ccx, llfn, true);
+            create_entry_fn(ccx, main_llfn, true);
         }
         session::EntryStart => create_entry_fn(ccx, main_llfn, false),
         session::EntryNone => {}    // Do nothing.
     }
 
-    fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
-        let nt = ty::mk_nil();
-        let llfty = type_of_rust_fn(ccx, [], nt);
-        let llfdecl = decl_fn(ccx.llmod, "_rust_main",
-                              lib::llvm::CCallConv, llfty);
-
-        let fcx = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
-
-        // the args vector built in create_entry_fn will need
-        // be updated if this assertion starts to fail.
-        assert!(!fcx.caller_expects_out_pointer);
-
-        let bcx = fcx.entry_bcx.unwrap();
-        // Call main.
-        let llenvarg = unsafe {
-            let env_arg = fcx.env_arg_pos();
-            llvm::LLVMGetParam(llfdecl, env_arg as c_uint)
-        };
-        let args = ~[llenvarg];
-        Call(bcx, main_llfn, args, []);
-
-        finish_fn(fcx, bcx);
-        return llfdecl;
-    }
-
     fn create_entry_fn(ccx: @mut CrateContext,
                        rust_main: ValueRef,
                        use_start_lang_item: bool) {
@@ -2494,12 +2515,26 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                     let sym = exported_name(ccx, my_path, ty, i.attrs);
 
                     let v = match i.node {
-                        ast::item_static(_, m, expr) => {
+                        ast::item_static(_, _, expr) => {
+                            // If this static came from an external crate, then
+                            // we need to get the symbol from csearch instead of
+                            // using the current crate's name/version
+                            // information in the hash of the symbol
+                            debug!("making %s", sym);
+                            let sym = match ccx.external_srcs.find(&i.id) {
+                                Some(&did) => {
+                                    debug!("but found in other crate...");
+                                    csearch::get_symbol(ccx.sess.cstore, did)
+                                }
+                                None => sym
+                            };
+
                             // We need the translated value here, because for enums the
                             // LLVM type is not fully determined by the Rust type.
-                            let v = consts::const_expr(ccx, expr);
+                            let (v, inlineable) = consts::const_expr(ccx, expr);
                             ccx.const_values.insert(id, v);
-                            exprt = (m == ast::MutMutable || i.vis == ast::public);
+                            let mut inlineable = inlineable;
+                            exprt = true;
 
                             unsafe {
                                 let llty = llvm::LLVMTypeOf(v);
@@ -2514,8 +2549,30 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                                     lib::llvm::SetUnnamedAddr(g, true);
                                     lib::llvm::SetLinkage(g,
                                         lib::llvm::InternalLinkage);
+
+                                    // This is a curious case where we must make
+                                    // all of these statics inlineable. If a
+                                    // global is tagged as
+                                    // address_insignificant, then LLVM won't
+                                    // coalesce globals unless they have an
+                                    // internal linkage type. This means that
+                                    // external crates cannot use this global.
+                                    // This is a problem for things like inner
+                                    // statics in generic functions, because the
+                                    // function will be inlined into another
+                                    // crate and then attempt to link to the
+                                    // static in the original crate, only to
+                                    // find that it's not there. On the other
+                                    // side of inlininig, the crates knows to
+                                    // not declare this static as
+                                    // available_externally (because it isn't)
+                                    inlineable = true;
                                 }
 
+                                if !inlineable {
+                                    debug!("%s not inlined", sym);
+                                    ccx.non_inlineable_statics.insert(id);
+                                }
                                 ccx.item_symbols.insert(i.id, sym);
                                 g
                             }
@@ -2577,7 +2634,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                             foreign::register_foreign_item_fn(ccx, abis, &path, ni)
                         }
                         ast::foreign_item_static(*) => {
-                            let ident = token::ident_to_str(&ni.ident);
+                            let ident = foreign::link_name(ccx, ni);
                             let g = do ident.with_c_str |buf| {
                                 unsafe {
                                     let ty = type_of(ccx, ty);
@@ -2950,6 +3007,7 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_
             reexports2: cx.exp_map2,
             item_symbols: item_symbols,
             discrim_symbols: discrim_symbols,
+            non_inlineable_statics: &cx.non_inlineable_statics,
             link_meta: link_meta,
             cstore: cx.sess.cstore,
             encode_inlined_item: ie,
index aabb389dde114b13d6fe22552a2e2e75d557c52f..4b03a2cac4b3ac09cc2a5c20ef246decbee915e9 100644 (file)
@@ -109,7 +109,8 @@ pub fn Invoke(cx: @mut Block,
               Fn: ValueRef,
               Args: &[ValueRef],
               Then: BasicBlockRef,
-              Catch: BasicBlockRef)
+              Catch: BasicBlockRef,
+              attributes: &[(uint, lib::llvm::Attribute)])
            -> ValueRef {
     if cx.unreachable {
         return C_null(Type::i8());
@@ -119,15 +120,7 @@ pub fn Invoke(cx: @mut Block,
     debug!("Invoke(%s with arguments (%s))",
            cx.val_to_str(Fn),
            Args.map(|a| cx.val_to_str(*a)).connect(", "));
-    B(cx).invoke(Fn, Args, Then, Catch)
-}
-
-pub fn FastInvoke(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
-                  Then: BasicBlockRef, Catch: BasicBlockRef) {
-    if cx.unreachable { return; }
-    check_not_terminated(cx);
-    terminate(cx, "FastInvoke");
-    B(cx).fast_invoke(Fn, Args, Then, Catch);
+    B(cx).invoke(Fn, Args, Then, Catch, attributes)
 }
 
 pub fn Unreachable(cx: @mut Block) {
index 85e45942b7981d7cfe4e62ac36f2f4b594106151..d7a4dbb3510feb5e707f0369cca934fd0df0f061 100644 (file)
@@ -154,30 +154,25 @@ pub fn invoke(&self,
                   llfn: ValueRef,
                   args: &[ValueRef],
                   then: BasicBlockRef,
-                  catch: BasicBlockRef)
+                  catch: BasicBlockRef,
+                  attributes: &[(uint, lib::llvm::Attribute)])
                   -> ValueRef {
         self.count_insn("invoke");
         unsafe {
-            llvm::LLVMBuildInvoke(self.llbuilder,
-                                  llfn,
-                                  vec::raw::to_ptr(args),
-                                  args.len() as c_uint,
-                                  then,
-                                  catch,
-                                  noname())
+            let v = llvm::LLVMBuildInvoke(self.llbuilder,
+                                          llfn,
+                                          vec::raw::to_ptr(args),
+                                          args.len() as c_uint,
+                                          then,
+                                          catch,
+                                          noname());
+            for &(idx, attr) in attributes.iter() {
+                llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+            }
+            v
         }
     }
 
-    pub fn fast_invoke(&self,
-                       llfn: ValueRef,
-                       args: &[ValueRef],
-                       then: BasicBlockRef,
-                       catch: BasicBlockRef) {
-        self.count_insn("fastinvoke");
-        let v = self.invoke(llfn, args, then, catch);
-        lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
-    }
-
     pub fn unreachable(&self) {
         self.count_insn("unreachable");
         unsafe {
index 45da026afd06ac5d1df8bd7e9ec78102f6e5973d..54c905a4c1651352ab9b90eae0c399e0e3c84be5 100644 (file)
@@ -20,7 +20,7 @@
 
 use back::abi;
 use driver::session;
-use lib::llvm::ValueRef;
+use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute};
 use lib::llvm::llvm;
 use metadata::csearch;
 use middle::trans::base;
@@ -706,8 +706,26 @@ pub fn trans_call_inner(in_cx: @mut Block,
                 _ => {}
             }
 
+            // A function pointer is called without the declaration available, so we have to apply
+            // any attributes with ABI implications directly to the call instruction. Right now, the
+            // only attribute we need to worry about is `sret`.
+            let mut attrs = ~[];
+            if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
+                attrs.push((1, StructRetAttribute));
+            }
+
+            // The `noalias` attribute on the return value is useful to a function ptr caller.
+            match ty::get(ret_ty).sty {
+                // `~` pointer return values never alias because ownership is transferred
+                ty::ty_uniq(*) |
+                ty::ty_evec(_, ty::vstore_uniq) => {
+                    attrs.push((0, NoAliasAttribute));
+                }
+                _ => ()
+            }
+
             // Invoke the actual rust fn and update bcx/llresult.
-            let (llret, b) = base::invoke(bcx, llfn, llargs, []);
+            let (llret, b) = base::invoke(bcx, llfn, llargs, attrs);
             bcx = b;
             llresult = llret;
 
index 690d7343489e299909091845e09a8cf9cfb47c47..605032dc20c8fa0609361a1e7b3fa61976239795 100644 (file)
@@ -381,8 +381,10 @@ pub fn trans_expr_fn(bcx: @mut Block,
 
     let ccx = bcx.ccx();
     let fty = node_id_type(bcx, outer_id);
-
-    let llfnty = type_of_fn_from_ty(ccx, fty);
+    let f = match ty::get(fty).sty {
+        ty::ty_closure(ref f) => f,
+        _ => fail!("expected closure")
+    };
 
     let sub_path = vec::append_one(bcx.fcx.path.clone(),
                                    path_name(special_idents::anon));
@@ -390,7 +392,7 @@ pub fn trans_expr_fn(bcx: @mut Block,
     let s = mangle_internal_name_by_path_and_seq(ccx,
                                                  sub_path.clone(),
                                                  "expr_fn");
-    let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
+    let llfn = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
 
     // set an inline hint for all closures
     set_inline_hint(llfn);
index b75b06f42b64986fec003a549512b26b1a65d976..b659a93f5f099d148c7715214a3519b627159041 100644 (file)
@@ -111,7 +111,7 @@ pub struct BuilderRef_res {
 }
 
 impl Drop for BuilderRef_res {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposeBuilder(self.B);
         }
index 78d2228ff041c4d8550140c1335957d808df4a88..a7a04627981a97d0cf0955fa9bebb9c286f1de52 100644 (file)
@@ -84,21 +84,21 @@ pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: Type) -> ValueRef {
 }
 
 pub fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr])
-    -> (ValueRef, ValueRef, Type) {
+    -> (ValueRef, ValueRef, Type, bool) {
     unsafe {
         let vec_ty = ty::expr_ty(cx.tcx, e);
         let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
         let llunitty = type_of::type_of(cx, unit_ty);
         let unit_sz = machine::llsize_of(cx, llunitty);
         let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz);
-        let vs = es.map(|e| const_expr(cx, *e));
+        let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
         // If the vector contains enums, an LLVM array won't work.
         let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
             C_struct(vs)
         } else {
             C_array(llunitty, vs)
         };
-        return (v, sz, llunitty);
+        return (v, sz, llunitty, inlineable.iter().fold(true, |a, &b| a && b));
     }
 }
 
@@ -157,7 +157,8 @@ fn const_deref(cx: &mut CrateContext, v: ValueRef, t: ty::t, explicit: bool)
     }
 }
 
-pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::DefId) -> ValueRef {
+pub fn get_const_val(cx: @mut CrateContext,
+                     mut def_id: ast::DefId) -> (ValueRef, bool) {
     let contains_key = cx.const_values.contains_key(&def_id.node);
     if !ast_util::is_local(def_id) || !contains_key {
         if !ast_util::is_local(def_id) {
@@ -172,11 +173,14 @@ pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::DefId) -> ValueRef
             _ => cx.tcx.sess.bug("expected a const to be an item")
         }
     }
-    cx.const_values.get_copy(&def_id.node)
+    (cx.const_values.get_copy(&def_id.node),
+     !cx.non_inlineable_statics.contains(&def_id.node))
 }
 
-pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
-    let mut llconst = const_expr_unadjusted(cx, e);
+pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> (ValueRef, bool) {
+    let (llconst, inlineable) = const_expr_unadjusted(cx, e);
+    let mut llconst = llconst;
+    let mut inlineable = inlineable;
     let ety = ty::expr_ty(cx.tcx, e);
     let adjustment = cx.tcx.adjustments.find_copy(&e.id);
     match adjustment {
@@ -204,7 +208,10 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
                     // Don't copy data to do a deref+ref.
                     let llptr = match maybe_ptr {
                         Some(ptr) => ptr,
-                        None => const_addr_of(cx, llconst)
+                        None => {
+                            inlineable = false;
+                            const_addr_of(cx, llconst)
+                        }
                     };
                     match *autoref {
                         ty::AutoUnsafe(m) |
@@ -250,17 +257,27 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
                          e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
                          csize, tsize));
     }
-    llconst
+    (llconst, inlineable)
 }
 
-fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
+// the bool returned is whether this expression can be inlined into other crates
+// if it's assigned to a static.
+fn const_expr_unadjusted(cx: @mut CrateContext,
+                         e: &ast::Expr) -> (ValueRef, bool) {
+    fn map_list(cx: @mut CrateContext,
+                exprs: &[@ast::Expr]) -> (~[ValueRef], bool) {
+        exprs.iter().map(|&e| const_expr(cx, e))
+             .fold((~[], true), |(L, all_inlineable), (val, inlineable)| {
+                    (vec::append_one(L, val), all_inlineable && inlineable)
+             })
+    }
     unsafe {
         let _icx = push_ctxt("const_expr");
         return match e.node {
-          ast::ExprLit(lit) => consts::const_lit(cx, e, *lit),
+          ast::ExprLit(lit) => (consts::const_lit(cx, e, *lit), true),
           ast::ExprBinary(_, b, e1, e2) => {
-            let te1 = const_expr(cx, e1);
-            let te2 = const_expr(cx, e2);
+            let (te1, _) = const_expr(cx, e1);
+            let (te2, _) = const_expr(cx, e2);
 
             let te2 = base::cast_shift_const_rhs(b, te1, te2);
 
@@ -269,7 +286,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
             let ty = ty::expr_ty(cx.tcx, e1);
             let is_float = ty::type_is_fp(ty);
             let signed = ty::type_is_signed(ty);
-            return match b {
+            return (match b {
               ast::BiAdd   => {
                 if is_float { llvm::LLVMConstFAdd(te1, te2) }
                 else        { llvm::LLVMConstAdd(te1, te2) }
@@ -338,13 +355,13 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                       else      { ConstICmp(IntUGT, te1, te2) }
                   }
               },
-            };
+            }, true)
           },
           ast::ExprUnary(_, u, e) => {
-            let te = const_expr(cx, e);
+            let (te, _) = const_expr(cx, e);
             let ty = ty::expr_ty(cx.tcx, e);
             let is_float = ty::type_is_fp(ty);
-            return match u {
+            return (match u {
               ast::UnBox(_)  |
               ast::UnUniq |
               ast::UnDeref  => {
@@ -367,21 +384,21 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 if is_float { llvm::LLVMConstFNeg(te) }
                 else        { llvm::LLVMConstNeg(te) }
               }
-            }
+            }, true)
           }
           ast::ExprField(base, field, _) => {
               let bt = ty::expr_ty_adjusted(cx.tcx, base);
               let brepr = adt::represent_type(cx, bt);
-              let bv = const_expr(cx, base);
+              let (bv, inlineable) = const_expr(cx, base);
               do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| {
                   let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
-                  adt::const_get_field(cx, brepr, bv, discr, ix)
+                  (adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
               }
           }
 
           ast::ExprIndex(_, base, index) => {
               let bt = ty::expr_ty_adjusted(cx.tcx, base);
-              let bv = const_expr(cx, base);
+              let (bv, inlineable) = const_expr(cx, base);
               let iv = match const_eval::eval_const_expr(cx.tcx, index) {
                   const_eval::const_int(i) => i as u64,
                   const_eval::const_uint(u) => u,
@@ -422,15 +439,15 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                   cx.sess.span_err(e.span,
                                    "const index-expr is out of bounds");
               }
-              const_get_elt(cx, arr, [iv as c_uint])
+              (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
           }
           ast::ExprCast(base, _) => {
             let ety = ty::expr_ty(cx.tcx, e);
             let llty = type_of::type_of(cx, ety);
             let basety = ty::expr_ty(cx.tcx, base);
-            let v = const_expr(cx, base);
-            match (expr::cast_type_kind(basety),
-                   expr::cast_type_kind(ety)) {
+            let (v, inlineable) = const_expr(cx, base);
+            return (match (expr::cast_type_kind(basety),
+                           expr::cast_type_kind(ety)) {
 
               (expr::cast_integral, expr::cast_integral) => {
                 let s = ty::type_is_signed(basety) as Bool;
@@ -476,17 +493,17 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 cx.sess.impossible_case(e.span,
                                         "bad combination of types for cast")
               }
-            }
+            }, inlineable)
           }
           ast::ExprAddrOf(ast::MutImmutable, sub) => {
-              let e = const_expr(cx, sub);
-              const_addr_of(cx, e)
+              let (e, _) = const_expr(cx, sub);
+              (const_addr_of(cx, e), false)
           }
           ast::ExprTup(ref es) => {
               let ety = ty::expr_ty(cx.tcx, e);
               let repr = adt::represent_type(cx, ety);
-              let vals = es.map(|&e| const_expr(cx, e));
-              adt::trans_const(cx, repr, 0, vals)
+              let (vals, inlineable) = map_list(cx, *es);
+              (adt::trans_const(cx, repr, 0, vals), inlineable)
           }
           ast::ExprStruct(_, ref fs, ref base_opt) => {
               let ety = ty::expr_ty(cx.tcx, e);
@@ -500,24 +517,29 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
 
               do expr::with_field_tys(tcx, ety, Some(e.id))
                   |discr, field_tys| {
-                  let cs: ~[ValueRef] = field_tys.iter().enumerate()
+                  let cs = field_tys.iter().enumerate()
                       .map(|(ix, &field_ty)| {
                       match fs.iter().find(|f| field_ty.ident.name == f.ident.name) {
                           Some(f) => const_expr(cx, (*f).expr),
                           None => {
                               match base_val {
-                                Some(bv) => adt::const_get_field(cx, repr, bv, discr, ix),
+                                Some((bv, inlineable)) => {
+                                    (adt::const_get_field(cx, repr, bv, discr, ix),
+                                     inlineable)
+                                }
                                 None => cx.tcx.sess.span_bug(e.span, "missing struct field")
                               }
                           }
                       }
-                  }).collect();
-                  adt::trans_const(cx, repr, discr, cs)
+                  }).to_owned_vec();
+                  let (cs, inlineable) = vec::unzip(cs.move_iter());
+                  (adt::trans_const(cx, repr, discr, cs),
+                   inlineable.iter().fold(true, |a, &b| a && b))
               }
           }
           ast::ExprVec(ref es, ast::MutImmutable) => {
-            let (v, _, _) = const_vec(cx, e, *es);
-            v
+            let (v, _, _, inlineable) = const_vec(cx, e, *es);
+            (v, inlineable)
           }
           ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
             match sub.node {
@@ -528,7 +550,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 }
               }
               ast::ExprVec(ref es, ast::MutImmutable) => {
-                let (cv, sz, llunitty) = const_vec(cx, e, *es);
+                let (cv, sz, llunitty, _) = const_vec(cx, e, *es);
                 let llty = val_ty(cv);
                 let gv = do "const".with_c_str |name| {
                     llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
@@ -537,7 +559,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 llvm::LLVMSetGlobalConstant(gv, True);
                 SetLinkage(gv, PrivateLinkage);
                 let p = const_ptrcast(cx, gv, llunitty);
-                C_struct([p, sz])
+                (C_struct([p, sz]), false)
               }
               _ => cx.sess.span_bug(e.span, "bad const-slice expr")
             }
@@ -551,13 +573,13 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 const_eval::const_uint(i) => i as uint,
                 _ => cx.sess.span_bug(count.span, "count must be integral const expression.")
             };
-            let vs = vec::from_elem(n, const_expr(cx, elem));
+            let vs = vec::from_elem(n, const_expr(cx, elem).first());
             let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
                 C_struct(vs)
             } else {
                 C_array(llunitty, vs)
             };
-            v
+            (v, true)
           }
           ast::ExprPath(ref pth) => {
             // Assert that there are no type parameters in this path.
@@ -568,10 +590,10 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 Some(&ast::DefFn(def_id, _purity)) => {
                     if !ast_util::is_local(def_id) {
                         let ty = csearch::get_type(cx.tcx, def_id).ty;
-                        base::trans_external_path(cx, def_id, ty)
+                        (base::trans_external_path(cx, def_id, ty), true)
                     } else {
                         assert!(ast_util::is_local(def_id));
-                        base::get_item_val(cx, def_id.node)
+                        (base::get_item_val(cx, def_id.node), true)
                     }
                 }
                 Some(&ast::DefStatic(def_id, false)) => {
@@ -583,12 +605,12 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                     let vinfo = ty::enum_variant_with_id(cx.tcx,
                                                          enum_did,
                                                          variant_did);
-                    adt::trans_const(cx, repr, vinfo.disr_val, [])
+                    (adt::trans_const(cx, repr, vinfo.disr_val, []), true)
                 }
                 Some(&ast::DefStruct(_)) => {
                     let ety = ty::expr_ty(cx.tcx, e);
                     let llty = type_of::type_of(cx, ety);
-                    C_null(llty)
+                    (C_null(llty), true)
                 }
                 _ => {
                     cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def")
@@ -601,8 +623,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                   Some(&ast::DefStruct(_)) => {
                       let ety = ty::expr_ty(cx.tcx, e);
                       let repr = adt::represent_type(cx, ety);
-                      let arg_vals = args.map(|a| const_expr(cx, *a));
-                      adt::trans_const(cx, repr, 0, arg_vals)
+                      let (arg_vals, inlineable) = map_list(cx, *args);
+                      (adt::trans_const(cx, repr, 0, arg_vals), inlineable)
                   }
                   Some(&ast::DefVariant(enum_did, variant_did, _)) => {
                       let ety = ty::expr_ty(cx.tcx, e);
@@ -610,13 +632,14 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                       let vinfo = ty::enum_variant_with_id(cx.tcx,
                                                            enum_did,
                                                            variant_did);
-                      let arg_vals = args.map(|a| const_expr(cx, *a));
-                      adt::trans_const(cx, repr, vinfo.disr_val, arg_vals)
+                      let (arg_vals, inlineable) = map_list(cx, *args);
+                      (adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
+                       inlineable)
                   }
                   _ => cx.sess.span_bug(e.span, "expected a struct or variant def")
               }
           }
-          ast::ExprParen(e) => { return const_expr(cx, e); }
+          ast::ExprParen(e) => { const_expr(cx, e) }
           _ => cx.sess.span_bug(e.span,
                   "bad constant expression type in consts::const_expr")
         };
index 6eb2fcf25fd3c289ff9113aa4c877ccd16099668..e342bcaf4faf7e6663c6b72d0393aad710c2cb6b 100644 (file)
@@ -61,6 +61,13 @@ pub struct CrateContext {
      finished_tydescs: bool,
      // Track mapping of external ids to local items imported for inlining
      external: HashMap<ast::DefId, Option<ast::NodeId>>,
+     // Backwards version of the `external` map (inlined items to where they
+     // came from)
+     external_srcs: HashMap<ast::NodeId, ast::DefId>,
+     // A set of static items which cannot be inlined into other crates. This
+     // will pevent in ii_item() structures from being encoded into the metadata
+     // that is generated
+     non_inlineable_statics: HashSet<ast::NodeId>,
      // Cache instances of monomorphized functions
      monomorphized: HashMap<mono_id, ValueRef>,
      monomorphizing: HashMap<ast::DefId, uint>,
@@ -189,6 +196,8 @@ pub fn new(sess: session::Session,
                   tydescs: HashMap::new(),
                   finished_tydescs: false,
                   external: HashMap::new(),
+                  external_srcs: HashMap::new(),
+                  non_inlineable_statics: HashSet::new(),
                   monomorphized: HashMap::new(),
                   monomorphizing: HashMap::new(),
                   type_use_cache: HashMap::new(),
@@ -273,12 +282,12 @@ pub fn offsetof_gep(&self,
 
 #[unsafe_destructor]
 impl Drop for CrateContext {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unset_task_llcx();
     }
 }
 
-static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
+local_data_key!(task_local_llcx_key: @ContextRef)
 
 pub fn task_llcx() -> ContextRef {
     let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k));
index b351fe91e6f1c859c644272ce71d66437b9e80d1..0a5578697583261f0fc5bb1fd75e235e36c6fa02 100644 (file)
 
 use back::abi;
 use back::link;
-use lib::llvm::{ValueRef, llvm, SetLinkage, ExternalLinkage, False};
+use lib::llvm::{ValueRef, llvm, SetLinkage, False};
 use lib;
 use metadata::csearch;
 use middle::trans::_match;
 use middle::trans::debuginfo;
 use middle::trans::machine;
 use middle::trans::meth;
+use middle::trans::inline;
 use middle::trans::tvec;
 use middle::trans::type_of;
 use middle::ty::struct_fields;
@@ -987,6 +988,15 @@ fn trans_def_lvalue(bcx: @mut Block,
             ast::DefStatic(did, _) => {
                 let const_ty = expr_ty(bcx, ref_expr);
 
+                fn get_did(ccx: @mut CrateContext, did: ast::DefId)
+                    -> ast::DefId {
+                    if did.crate != ast::LOCAL_CRATE {
+                        inline::maybe_instantiate_inline(ccx, did)
+                    } else {
+                        did
+                    }
+                }
+
                 fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
                            -> ValueRef {
                     // For external constants, we don't inline.
@@ -1018,7 +1028,6 @@ fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
                                                     llty.to_ref(),
                                                     buf)
                             };
-                            SetLinkage(llval, ExternalLinkage);
                             let extern_const_values = &mut bcx.ccx().extern_const_values;
                             extern_const_values.insert(did, llval);
                             llval
@@ -1026,6 +1035,7 @@ fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
                     }
                 }
 
+                let did = get_did(bcx.ccx(), did);
                 let val = get_val(bcx, did, const_ty);
                 DatumBlock {
                     bcx: bcx,
index 1ebe402bbb987838d3c41d9700c1db91680c36dc..b00d77d72ddb34650df328966483b8d4246e3e7b 100644 (file)
@@ -21,7 +21,6 @@
 use middle::trans::build::*;
 use middle::trans::builder::noname;
 use middle::trans::common::*;
-use middle::trans::llrepr::LlvmRepr;
 use middle::trans::type_of::*;
 use middle::trans::type_of;
 use middle::ty;
@@ -265,6 +264,9 @@ pub fn trans_native_call(bcx: @mut Block,
         }
     };
 
+    // A function pointer is called without the declaration available, so we have to apply
+    // any attributes with ABI implications directly to the call instruction. Right now, the
+    // only attribute we need to worry about is `sret`.
     let attrs;
     if fn_type.sret {
         attrs = &[(1, StructRetAttribute)];
@@ -406,13 +408,12 @@ fn build_rust_fn(ccx: @mut CrateContext,
                 special_idents::clownshoe_abi
             )));
 
-        // Compute the LLVM type that the function would have if it
-        // were just a normal Rust function. This will be the type of
-        // the wrappee fn.
-        let llty = match ty::get(t).sty {
+        // Compute the type that the function would have if it were just a
+        // normal Rust function. This will be the type of the wrappee fn.
+        let f = match ty::get(t).sty {
             ty::ty_bare_fn(ref f) => {
                 assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
-                type_of_rust_fn(ccx, f.sig.inputs, f.sig.output)
+                f
             }
             _ => {
                 ccx.sess.bug(fmt!("build_rust_fn: extern fn %s has ty %s, \
@@ -422,13 +423,12 @@ fn build_rust_fn(ccx: @mut CrateContext,
             }
         };
 
-        debug!("build_rust_fn: path=%s id=%? t=%s llty=%s",
+        debug!("build_rust_fn: path=%s id=%? t=%s",
                path.repr(tcx),
                id,
-               t.repr(tcx),
-               llty.llrepr(ccx));
+               t.repr(tcx));
 
-        let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
+        let llfndecl = base::decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, ps);
         base::trans_fn(ccx,
                        (*path).clone(),
                        decl,
@@ -500,7 +500,7 @@ unsafe fn build_wrap_fn(ccx: @mut CrateContext,
             // Rust expects to use an outpointer. If the foreign fn
             // also uses an outpointer, we can reuse it, but the types
             // may vary, so cast first to the Rust type. If the
-            // foriegn fn does NOT use an outpointer, we will have to
+            // foreign fn does NOT use an outpointer, we will have to
             // alloca some scratch space on the stack.
             match foreign_outptr {
                 Some(llforeign_outptr) => {
index cfc9c8a2e17cf3c1f2690f4e4642191c5b4e3b9d..8900b50b49df2e9aa92c74a3cb4100a29349e112 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
+use lib::llvm::{AvailableExternallyLinkage, SetLinkage};
 use metadata::csearch;
 use middle::astencode;
 use middle::trans::base::{push_ctxt, impl_self, no_self};
@@ -21,6 +21,7 @@
 use syntax::ast;
 use syntax::ast_map::path_name;
 use syntax::ast_util::local_def;
+use syntax::attr;
 
 pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
     -> ast::DefId {
@@ -53,16 +54,41 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
         }
         csearch::found(ast::ii_item(item)) => {
             ccx.external.insert(fn_id, Some(item.id));
+            ccx.external_srcs.insert(item.id, fn_id);
             ccx.stats.n_inlines += 1;
             trans_item(ccx, item);
+
+            // We're bringing an external global into this crate, but we don't
+            // want to create two copies of the global. If we do this, then if
+            // you take the address of the global in two separate crates you get
+            // two different addresses. This is bad for things like conditions,
+            // but it could possibly have other adverse side effects. We still
+            // want to achieve the optimizations related to this global,
+            // however, so we use the available_externally linkage which llvm
+            // provides
+            match item.node {
+                ast::item_static(*) => {
+                    let g = get_item_val(ccx, item.id);
+                    // see the comment in get_item_val() as to why this check is
+                    // performed here.
+                    if !attr::contains_name(item.attrs,
+                                            "address_insignificant") {
+                        SetLinkage(g, AvailableExternallyLinkage);
+                    }
+                }
+                _ => {}
+            }
+
             local_def(item.id)
         }
         csearch::found(ast::ii_foreign(item)) => {
           ccx.external.insert(fn_id, Some(item.id));
+          ccx.external_srcs.insert(item.id, fn_id);
           local_def(item.id)
         }
         csearch::found_parent(parent_id, ast::ii_item(item)) => {
           ccx.external.insert(parent_id, Some(item.id));
+          ccx.external_srcs.insert(item.id, parent_id);
           let mut my_id = 0;
           match item.node {
             ast::item_enum(_, _) => {
@@ -86,6 +112,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
         csearch::found(ast::ii_method(impl_did, is_provided, mth)) => {
           ccx.stats.n_inlines += 1;
           ccx.external.insert(fn_id, Some(mth.id));
+          ccx.external_srcs.insert(mth.id, fn_id);
           // If this is a default method, we can't look up the
           // impl type. But we aren't going to translate anyways, so don't.
           if is_provided { return local_def(mth.id); }
index 2bdff6c8567fea52cf4e3c14fb7e7026b866fa69..ef055a52468c89be55e964653bf7fe9cb7289f99 100644 (file)
 use lib::llvm::ValueRef;
 use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint};
 use middle::trans::base::{trans_enum_variant,push_ctxt};
-use middle::trans::base::{trans_fn, decl_internal_cdecl_fn};
+use middle::trans::base::{trans_fn, decl_internal_rust_fn};
 use middle::trans::base::{get_item_val, no_self};
 use middle::trans::base;
 use middle::trans::common::*;
 use middle::trans::datum;
 use middle::trans::machine;
 use middle::trans::meth;
-use middle::trans::type_of::type_of_fn_from_ty;
 use middle::trans::type_of;
 use middle::trans::type_use;
 use middle::trans::intrinsic;
@@ -177,7 +176,14 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
             ty::subst_tps(ccx.tcx, substs, None, llitem_ty)
         }
     };
-    let llfty = type_of_fn_from_ty(ccx, mono_ty);
+
+    let f = match ty::get(mono_ty).sty {
+        ty::ty_bare_fn(ref f) => {
+            assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+            f
+        }
+        _ => fail!("expected bare rust fn or an intrinsic")
+    };
 
     ccx.stats.n_monos += 1;
 
@@ -200,7 +206,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
     debug!("monomorphize_fn mangled to %s", s);
 
     let mk_lldecl = || {
-        let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
+        let lldecl = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
         ccx.monomorphized.insert(hash_id, lldecl);
         lldecl
     };
index 300fb64863ca8c0fad6b781b21d1562cc5e83855..23b87c63d6a2c5bb1ee02117eb586d42d484e5f3 100644 (file)
@@ -293,8 +293,7 @@ pub fn visit_ty(&mut self, t: ty::t) {
                                                                sub_path,
                                                                "get_disr");
 
-                let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
-                let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
+                let llfdecl = decl_internal_rust_fn(ccx, [opaqueptrty], ty::mk_int(), sym);
                 let fcx = new_fn_ctxt(ccx,
                                       ~[],
                                       llfdecl,
index adf11a9fa21205e8a934022cf193d247bed09a8e..8c3e198e5d6f495a0c32ab7af4290a3d09eddff7 100644 (file)
@@ -40,7 +40,7 @@
 use std::str;
 use std::task;
 use std::vec;
-use extra::getopts::{groups, opt_present};
+use extra::getopts::groups;
 use extra::getopts;
 use syntax::codemap;
 use syntax::diagnostic;
@@ -134,7 +134,7 @@ pub fn version(argv0: &str) {
 
 pub fn usage(argv0: &str) {
     let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
-    printfln!("%s\
+    printfln!("%s\n\
 Additional help:
     -W help             Print 'lint' options and default settings
     -Z help             Print internal options for debugging rustc\n",
@@ -204,39 +204,39 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
         &match getopts::groups::getopts(args, optgroups()) {
           Ok(m) => m,
           Err(f) => {
-            early_error(demitter, getopts::fail_str(f));
+            early_error(demitter, f.to_err_msg());
           }
         };
 
-    if opt_present(matches, "h") || opt_present(matches, "help") {
+    if matches.opt_present("h") || matches.opt_present("help") {
         usage(binary);
         return;
     }
 
     // Display the available lint options if "-W help" or only "-W" is given.
-    let lint_flags = vec::append(getopts::opt_strs(matches, "W"),
-                                 getopts::opt_strs(matches, "warn"));
+    let lint_flags = vec::append(matches.opt_strs("W"),
+                                 matches.opt_strs("warn"));
 
     let show_lint_options = lint_flags.iter().any(|x| x == &~"help") ||
-        (opt_present(matches, "W") && lint_flags.is_empty());
+        (matches.opt_present("W") && lint_flags.is_empty());
 
     if show_lint_options {
         describe_warnings();
         return;
     }
 
-    let r = getopts::opt_strs(matches, "Z");
+    let r = matches.opt_strs("Z");
     if r.iter().any(|x| x == &~"help") {
         describe_debug_flags();
         return;
     }
 
-    if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
+    if matches.opt_str("passes") == Some(~"list") {
         unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
         return;
     }
 
-    if opt_present(matches, "v") || opt_present(matches, "version") {
+    if matches.opt_present("v") || matches.opt_present("version") {
         version(binary);
         return;
     }
@@ -256,10 +256,10 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
 
     let sopts = build_session_options(binary, matches, demitter);
     let sess = build_session(sopts, demitter);
-    let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
-    let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
+    let odir = matches.opt_str("out-dir").map_move(|o| Path(o));
+    let ofile = matches.opt_str("o").map_move(|o| Path(o));
     let cfg = build_configuration(sess);
-    let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
+    let pretty = do matches.opt_default("pretty", "normal").map_move |a| {
         parse_pretty(sess, a)
     };
     match pretty {
@@ -269,7 +269,7 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
       }
       None::<PpMode> => {/* continue */ }
     }
-    let ls = opt_present(matches, "ls");
+    let ls = matches.opt_present("ls");
     if ls {
         match input {
           file_input(ref ifile) => {
@@ -342,7 +342,7 @@ struct finally {
         }
 
         impl Drop for finally {
-            fn drop(&self) { self.ch.send(done); }
+            fn drop(&mut self) { self.ch.send(done); }
         }
 
         let _finally = finally { ch: ch };
index eb9206a52b1257e9937efaa644f3928a5d4b0cac..46620319a8212742da584b09314fd36e2c2a392a 100644 (file)
@@ -40,7 +40,7 @@ pub struct _indenter {
 }
 
 impl Drop for _indenter {
-    fn drop(&self) { debug!("<<"); }
+    fn drop(&mut self) { debug!("<<"); }
 }
 
 pub fn _indenter(_i: ()) -> _indenter {
index ff6401456b6b9965d37616b3d870ce698544606a..71ece1788078266a67ef2e3137f79f87a38b80c3 100644 (file)
@@ -125,7 +125,7 @@ pub fn parse_config_(
             }
         }
         Err(f) => {
-            Err(getopts::fail_str(f))
+            Err(f.to_err_msg())
         }
     }
 }
@@ -139,7 +139,7 @@ fn config_from_opts(
     let config = default_config(input_crate);
     let result = result::Ok(config);
     let result = do result.and_then |config| {
-        let output_dir = getopts::opt_maybe_str(matches, opt_output_dir());
+        let output_dir = matches.opt_str(opt_output_dir());
         let output_dir = output_dir.map_move(|s| Path(s));
         result::Ok(Config {
             output_dir: output_dir.unwrap_or(config.output_dir.clone()),
@@ -147,7 +147,7 @@ fn config_from_opts(
         })
     };
     let result = do result.and_then |config| {
-        let output_format = getopts::opt_maybe_str(matches, opt_output_format());
+        let output_format = matches.opt_str(opt_output_format());
         do output_format.map_move_default(result::Ok(config.clone())) |output_format| {
             do parse_output_format(output_format).and_then |output_format| {
                 result::Ok(Config {
@@ -159,7 +159,7 @@ fn config_from_opts(
     };
     let result = do result.and_then |config| {
         let output_style =
-            getopts::opt_maybe_str(matches, opt_output_style());
+            matches.opt_str(opt_output_style());
         do output_style.map_move_default(result::Ok(config.clone())) |output_style| {
             do parse_output_style(output_style).and_then |output_style| {
                 result::Ok(Config {
@@ -171,7 +171,7 @@ fn config_from_opts(
     };
     let process_output = Cell::new(process_output);
     let result = do result.and_then |config| {
-        let pandoc_cmd = getopts::opt_maybe_str(matches, opt_pandoc_cmd());
+        let pandoc_cmd = matches.opt_str(opt_pandoc_cmd());
         let pandoc_cmd = maybe_find_pandoc(
             &config, pandoc_cmd, process_output.take());
         do pandoc_cmd.and_then |pandoc_cmd| {
index 3393133bc186603acdc5042935abc62521cb62ba..23c55488332ad77e277188b52d46d4c73fac4a2e 100644 (file)
@@ -127,7 +127,7 @@ struct Bored {
 }
 
 impl Drop for Bored {
-  fn drop(&self) { }
+  fn drop(&mut self) { }
 }
 
 /**
index 9208191e364cd347d500a61e18e05c2c963f6472..4deaa458f194fd059b2fbbd252a58719f1c6ab49 100644 (file)
@@ -60,7 +60,7 @@ struct LocalVariable {
 }
 
 type LocalCache = @mut HashMap<~str, @~[u8]>;
-static tls_key: local_data::Key<LocalCache> = &local_data::Key;
+local_data_key!(tls_key: LocalCache)
 
 impl Program {
     pub fn new() -> Program {
index 727bbcb30b4c51f6bf5a07430df1d5db126b311a..e1092458ffaae85e4a6f3d05a1282b89cfe72380 100644 (file)
@@ -12,6 +12,7 @@
 use crate::*;
 use package_id::*;
 use package_source::*;
+use target::*;
 use version::Version;
 use workcache_support::*;
 
@@ -63,56 +64,40 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
 pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
                  lib: Path) {
     let cx = default_context(sysroot);
-    let subroot = root.clone();
-    let subversion = version.clone();
-    let sublib = lib.clone();
-    do cx.workcache_context.with_prep(name) |prep| {
-        let pkg_src = PkgSrc {
-            workspace: subroot.clone(),
-            start_dir: subroot.push("src").push(name),
-            id: PkgId{ version: subversion.clone(), ..PkgId::new(name)},
-            libs: ~[mk_crate(sublib.clone())],
+    let pkg_src = PkgSrc {
+            workspace: root.clone(),
+            start_dir: root.push("src").push(name),
+            id: PkgId{ version: version, ..PkgId::new(name)},
+            // n.b. This assumes the package only has one crate
+            libs: ~[mk_crate(lib)],
             mains: ~[],
             tests: ~[],
             benchs: ~[]
         };
-        pkg_src.declare_inputs(prep);
-        let subcx = cx.clone();
-        let subsrc = pkg_src.clone();
-        do prep.exec |exec| {
-            subsrc.build(exec, &subcx.clone(), ~[]);
-        }
-    };
+    pkg_src.build(&cx, ~[]);
 }
 
 pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
                  main: Path) {
     let cx = default_context(sysroot);
-    let subroot = root.clone();
-    let submain = main.clone();
-    do cx.workcache_context.with_prep(name) |prep| {
-        let pkg_src = PkgSrc {
-            workspace: subroot.clone(),
-            start_dir: subroot.push("src").push(name),
-            id: PkgId{ version: version.clone(), ..PkgId::new(name)},
-            libs: ~[],
-            mains: ~[mk_crate(submain.clone())],
-            tests: ~[],
-            benchs: ~[]
-        };
-        pkg_src.declare_inputs(prep);
-        let subsrc = pkg_src.clone();
-        let subcx = cx.clone();
-        do prep.exec |exec| {
-            subsrc.clone().build(exec, &subcx.clone(), ~[]);
-        }
-    }
+    let pkg_src = PkgSrc {
+        workspace: root.clone(),
+        start_dir: root.push("src").push(name),
+        id: PkgId{ version: version, ..PkgId::new(name)},
+        libs: ~[],
+        // n.b. This assumes the package only has one crate
+        mains: ~[mk_crate(main)],
+        tests: ~[],
+        benchs: ~[]
+    };
+
+    pkg_src.build(&cx, ~[]);
 }
 
 pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
     let cx = default_context(sysroot);
     let pkgid = PkgId{ version: version, ..PkgId::new(name)};
-    cx.install(PkgSrc::new(workspace, false, pkgid));
+    cx.install(PkgSrc::new(workspace, false, pkgid), &Everything);
 }
 
 fn mk_crate(p: Path) -> Crate {
diff --git a/src/librustpkg/exit_codes.rs b/src/librustpkg/exit_codes.rs
new file mode 100644 (file)
index 0000000..484f6bd
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub static copy_failed_code: int = 65;
index bc2fcdd7fe9b2b19b30d71b5a69fb34afb3bab40..52b986cb6e7e6cad12a205dd360501958f201402 100644 (file)
@@ -108,6 +108,12 @@ pub fn prefixes_iter(&self) -> Prefixes {
         }
     }
 
+    // This is the workcache function name for the *installed*
+    // binaries for this package (as opposed to the built ones,
+    // which are per-crate).
+    pub fn install_tag(&self) -> ~str {
+        fmt!("install(%s)", self.to_str())
+    }
 }
 
 struct Prefixes {
index b5ded6f3fafab0d209c3fc6ec9bad6c914e53478..4bf647b011d9dbc3b7cf24ae872b6e0ec21439a8 100644 (file)
@@ -22,6 +22,7 @@
 use util::compile_crate;
 use workspace::is_workspace;
 use workcache_support;
+use workcache_support::crate_tag;
 use extra::workcache;
 
 // An enumeration of the unpacked source of a package workspace.
@@ -231,7 +232,7 @@ fn stem_matches(&self, p: &Path) -> bool {
         p.filestem().map_default(false, |p| { p == &self.id.short_name.as_slice() })
     }
 
-    fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
+    pub fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
         assert!(p.components.len() > prefix);
         let mut sub = Path("");
         for c in p.components.slice(prefix, p.components.len()).iter() {
@@ -286,7 +287,6 @@ pub fn find_crates(&mut self) {
 
     fn build_crates(&self,
                     ctx: &BuildContext,
-                    exec: &mut workcache::Exec,
                     destination_dir: &Path,
                     crates: &[Crate],
                     cfgs: &[~str],
@@ -297,25 +297,40 @@ fn build_crates(&self,
             let path_str = path.to_str();
             let cfgs = crate.cfgs + cfgs;
 
-            let result =
-                // compile_crate should return the path of the output artifact
-                compile_crate(ctx,
-                              exec,
-                              &self.id,
-                              &path,
-                              destination_dir,
-                              crate.flags,
-                              cfgs,
-                              false,
-                              what).to_str();
-            debug!("Result of compiling %s was %s", path_str, result);
+            do ctx.workcache_context.with_prep(crate_tag(&path)) |prep| {
+                debug!("Building crate %s, declaring it as an input", path.to_str());
+                prep.declare_input("file", path.to_str(),
+                                   workcache_support::digest_file_with_date(&path));
+                let subpath = path.clone();
+                let subcfgs = cfgs.clone();
+                let subpath_str = path_str.clone();
+                let subcx = ctx.clone();
+                let id = self.id.clone();
+                let sub_dir = destination_dir.clone();
+                let sub_flags = crate.flags.clone();
+                do prep.exec |exec| {
+                    let result = compile_crate(&subcx,
+                                               exec,
+                                               &id,
+                                               &subpath,
+                                               &sub_dir,
+                                               sub_flags,
+                                               subcfgs,
+                                               false,
+                                               what).to_str();
+                    debug!("Result of compiling %s was %s", subpath_str, result);
+                    result
+                }
+            };
         }
     }
 
     /// Declare all the crate files in the package source as inputs
+    /// (to the package)
     pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
         let to_do = ~[self.libs.clone(), self.mains.clone(),
                       self.tests.clone(), self.benchs.clone()];
+        debug!("In declare inputs, self = %s", self.to_str());
         for cs in to_do.iter() {
             for c in cs.iter() {
                 let path = self.start_dir.push_rel(&c.file).normalize();
@@ -330,7 +345,6 @@ pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
     // It would be better if build returned a Path, but then Path would have to derive
     // Encodable.
     pub fn build(&self,
-                 exec: &mut workcache::Exec,
                  build_context: &BuildContext,
                  cfgs: ~[~str]) -> ~str {
         use conditions::not_a_workspace::cond;
@@ -360,13 +374,23 @@ pub fn build(&self,
         let benchs = self.benchs.clone();
         debug!("Building libs in %s, destination = %s",
                destination_workspace.to_str(), destination_workspace.to_str());
-        self.build_crates(build_context, exec, &destination_workspace, libs, cfgs, Lib);
+        self.build_crates(build_context, &destination_workspace, libs, cfgs, Lib);
         debug!("Building mains");
-        self.build_crates(build_context, exec, &destination_workspace, mains, cfgs, Main);
+        self.build_crates(build_context, &destination_workspace, mains, cfgs, Main);
         debug!("Building tests");
-        self.build_crates(build_context, exec, &destination_workspace, tests, cfgs, Test);
+        self.build_crates(build_context, &destination_workspace, tests, cfgs, Test);
         debug!("Building benches");
-        self.build_crates(build_context, exec, &destination_workspace, benchs, cfgs, Bench);
+        self.build_crates(build_context, &destination_workspace, benchs, cfgs, Bench);
         destination_workspace.to_str()
     }
+
+    /// Debugging
+    pub fn dump_crates(&self) {
+        let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
+        for crate_set in crate_sets.iter() {
+            for c in crate_set.iter() {
+                debug!("Built crate: %s", c.file.to_str())
+            }
+        }
+    }
 }
index eef1dcabfd0efd1c397981401b58135cb65227b3..0187a8d189c3fd0aa64a19a4f85c097c18faccb2 100644 (file)
 extern mod rustc;
 extern mod syntax;
 
-use std::{io, os, result, run, str};
+use std::{io, os, result, run, str, task};
 pub use std::path::Path;
 
 use extra::workcache;
-use extra::arc::RWArc;
 use rustc::driver::{driver, session};
 use rustc::metadata::filesearch;
 use rustc::metadata::filesearch::rust_path;
                        LLVMAssemble, LLVMCompileBitcode};
 use package_id::PkgId;
 use package_source::PkgSrc;
-use workcache_support::{discover_outputs, digest_only_date};
+use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
+// use workcache_support::{discover_outputs, digest_only_date};
+use workcache_support::digest_only_date;
+use exit_codes::copy_failed_code;
 
 pub mod api;
 mod conditions;
 mod context;
 mod crate;
+mod exit_codes;
 mod installed_packages;
 mod messages;
 mod package_id;
@@ -172,40 +175,26 @@ fn hash(&self) -> ~str {
 pub trait CtxMethods {
     fn run(&self, cmd: &str, args: ~[~str]);
     fn do_cmd(&self, _cmd: &str, _pkgname: &str);
-    fn build_from_src(&self, pkg_src: PkgSrc);
     /// Returns the destination workspace
-    fn build(&self, exec: &mut workcache::Exec, pkg_src: PkgSrc) -> Path;
+    fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
     fn clean(&self, workspace: &Path, id: &PkgId);
     fn info(&self);
     /// Returns a pair. First component is a list of installed paths,
     /// second is a list of declared and discovered inputs
-    fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
+    fn install(&self, src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]);
     /// Returns a list of installed files
     fn install_no_build(&self,
                         source_workspace: &Path,
                         target_workspace: &Path,
-                        id: &PkgId) -> ~[Path];
+                        id: &PkgId) -> ~[~str];
     fn prefer(&self, _id: &str, _vers: Option<~str>);
     fn test(&self);
     fn uninstall(&self, _id: &str, _vers: Option<~str>);
     fn unprefer(&self, _id: &str, _vers: Option<~str>);
+    fn init(&self);
 }
 
 impl CtxMethods for BuildContext {
-    fn build_from_src(&self, pkg_src: PkgSrc) {
-        let tag = pkg_src.id.to_str();
-        debug!("package source = %s", pkg_src.to_str());
-        do self.workcache_context.with_prep(tag) |prep| {
-            let subsrc = pkg_src.clone();
-            let subself = self.clone();
-            declare_package_script_dependency(prep, &subsrc);
-            pkg_src.declare_inputs(prep);
-            do prep.exec |exec| {
-                subself.build(exec, subsrc.clone());
-            }
-        }
-    }
-
     fn run(&self, cmd: &str, args: ~[~str]) {
         match cmd {
             "build" => {
@@ -214,11 +203,13 @@ fn run(&self, cmd: &str, args: ~[~str]) {
                         None if self.context.use_rust_path_hack => {
                             let cwd = os::getcwd();
                             let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
-                            self.build_from_src(PkgSrc::new(cwd, true, pkgid));
+                            let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
+                            self.build(&mut pkg_src, &Everything);
                         }
                         None => { usage::build(); return; }
                         Some((ws, pkgid)) => {
-                            self.build_from_src(PkgSrc::new(ws, false, pkgid));
+                            let mut pkg_src = PkgSrc::new(ws, false, pkgid);
+                            self.build(&mut pkg_src, &Everything);
                         }
                     }
                 }
@@ -229,8 +220,8 @@ fn run(&self, cmd: &str, args: ~[~str]) {
                     do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
                         debug!("found pkg %s in workspace %s, trying to build",
                                pkgid.to_str(), workspace.to_str());
-                        let pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
-                        self.build_from_src(pkg_src);
+                        let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
+                        self.build(&mut pkg_src, &Everything);
                         true
                     };
                 }
@@ -270,12 +261,12 @@ fn run(&self, cmd: &str, args: ~[~str]) {
                             let cwd = os::getcwd();
                             let inferred_pkgid =
                                 PkgId::new(cwd.components[cwd.components.len() - 1]);
-                            self.install(PkgSrc::new(cwd, true, inferred_pkgid));
+                            self.install(PkgSrc::new(cwd, true, inferred_pkgid), &Everything);
                         }
                         None  => { usage::install(); return; }
                         Some((ws, pkgid))                => {
                             let pkg_src = PkgSrc::new(ws, false, pkgid);
-                            self.install(pkg_src);
+                            self.install(pkg_src, &Everything);
                       }
                   }
                 }
@@ -290,14 +281,14 @@ fn run(&self, cmd: &str, args: ~[~str]) {
                         let rp = rust_path();
                         assert!(!rp.is_empty());
                         let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
-                        self.install(src);
+                        self.install(src, &Everything);
                     }
                     else {
                         for workspace in workspaces.iter() {
                             let src = PkgSrc::new(workspace.clone(),
                                                   self.context.use_rust_path_hack,
                                                   pkgid.clone());
-                            self.install(src);
+                            self.install(src, &Everything);
                         };
                     }
                 }
@@ -319,6 +310,13 @@ fn run(&self, cmd: &str, args: ~[~str]) {
             "test" => {
                 self.test();
             }
+            "init" => {
+                if args.len() != 0 {
+                    return usage::init();
+                } else {
+                    self.init();
+                }
+            }
             "uninstall" => {
                 if args.len() < 1 {
                     return usage::uninstall();
@@ -358,7 +356,9 @@ fn do_cmd(&self, _cmd: &str, _pkgname: &str)  {
 
     /// Returns the destination workspace
     /// In the case of a custom build, we don't know, so we just return the source workspace
-    fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
+    /// what_to_build says: "Just build the lib.rs file in one subdirectory,
+    /// don't walk anything recursively." Or else, everything.
+    fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) -> Path {
         let workspace = pkg_src.workspace.clone();
         let pkgid = pkg_src.id.clone();
 
@@ -376,7 +376,7 @@ fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
             let default_ws = default_workspace();
             debug!("Calling build recursively with %? and %?", default_ws.to_str(),
                    pkgid.to_str());
-            return self.build(exec, PkgSrc::new(default_ws, false, pkgid.clone()));
+            return self.build(&mut PkgSrc::new(default_ws, false, pkgid.clone()), what_to_build);
         }
 
         // Is there custom build logic? If so, use it
@@ -387,12 +387,21 @@ fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
         let cfgs = match pkg_src.package_script_option() {
             Some(package_script_path) => {
                 let sysroot = self.sysroot_to_use();
-                let (cfgs, hook_result) = {
-                    let pscript = PkgScript::parse(@sysroot.clone(),
-                                                   package_script_path.clone(),
-                                                   &workspace.clone(),
-                                                   &pkgid);
-                    pscript.run_custom(exec, &sysroot)
+                let (cfgs, hook_result) =
+                    do self.workcache_context.with_prep(package_script_path.to_str()) |prep| {
+                    let sub_sysroot = sysroot.clone();
+                    let package_script_path_clone = package_script_path.clone();
+                    let sub_ws = workspace.clone();
+                    let sub_id = pkgid.clone();
+                    declare_package_script_dependency(prep, &*pkg_src);
+                    do prep.exec |exec| {
+                        let pscript = PkgScript::parse(@sub_sysroot.clone(),
+                                                       package_script_path_clone.clone(),
+                                                       &sub_ws,
+                                                       &sub_id);
+
+                        pscript.run_custom(exec, &sub_sysroot)
+                    }
                 };
                 debug!("Command return code = %?", hook_result);
                 if hook_result != 0 {
@@ -411,10 +420,31 @@ fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
         // If there was a package script, it should have finished
         // the build already. Otherwise...
         if !custom {
-            // Find crates inside the workspace
-            pkg_src.find_crates();
+            match what_to_build {
+                // Find crates inside the workspace
+                &Everything => pkg_src.find_crates(),
+                // Don't infer any crates -- just build the one that was requested
+                &JustOne(ref p) => {
+                    // We expect that p is relative to the package source's start directory,
+                    // so check that assumption
+                    debug!("JustOne: p = %s", p.to_str());
+                    assert!(os::path_exists(&pkg_src.start_dir.push_rel(p)));
+                    if is_lib(p) {
+                        PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
+                    } else if is_main(p) {
+                        PkgSrc::push_crate(&mut pkg_src.mains, 0, p);
+                    } else if is_test(p) {
+                        PkgSrc::push_crate(&mut pkg_src.tests, 0, p);
+                    } else if is_bench(p) {
+                        PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
+                    } else {
+                        warn(fmt!("Not building any crates for dependency %s", p.to_str()));
+                        return workspace.clone();
+                    }
+                }
+            }
             // Build it!
-            let rs_path = pkg_src.build(exec, self, cfgs);
+            let rs_path = pkg_src.build(self, cfgs);
             Path(rs_path)
         }
         else {
@@ -444,56 +474,54 @@ fn info(&self) {
         fail!("info not yet implemented");
     }
 
-    fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
-
-        let id = &pkg_src.id;
-
-        let installed_files = RWArc::new(~[]);
-        let inputs = RWArc::new(~[]);
-        // FIXME #7402: Use RUST_PATH to determine target dir
-        self.workcache_context.with_prep(id.to_str(), |p| pkg_src.declare_inputs(p));
-        do self.workcache_context.with_prep(id.to_str()) |prep| {
-            let sub_inputs = inputs.clone();
-            let sub_files  = installed_files.clone();
-            let subsrc = pkg_src.clone();
-            let subself = self.clone();
-            let id_str = id.to_str();
-            let sub_id = id.clone();
-            sub_inputs.write(|r| *r = prep.lookup_declared_inputs().map(|v|
-                                          { (~"file", (*v).clone()) }));
-            do prep.exec |exec| {
-                let destination_workspace = subself.build(exec, subsrc.clone()).to_str();
-                // See #7402: This still isn't quite right yet; we want to
-                // install to the first workspace in the RUST_PATH if there's
-                // a non-default RUST_PATH. This code installs to the same
-                // workspace the package was built in.
-                let actual_workspace = if path_util::user_set_rust_path() {
-                    default_workspace()
-                }
-                else {
-                    Path(destination_workspace)
-                };
-                debug!("install: destination workspace = %s, id = %s, installing to %s",
-                       destination_workspace, id_str, actual_workspace.to_str());
-                let result = subself.install_no_build(&Path(destination_workspace),
-                                                      &actual_workspace,
-                                                      &sub_id);
-                debug!("install: id = %s, about to call discover_outputs, %?",
-                       id_str, result.to_str());
-
-                discover_outputs(exec, result.clone());
-                sub_files.write(|r| { *r = result.clone(); });
-                sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
-                note(fmt!("Installed package %s to %s", id_str, actual_workspace.to_str()));
+    fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
+
+        let id = pkg_src.id.clone();
+
+        let mut installed_files = ~[];
+        let inputs = ~[];
+
+        // workcache only knows about *crates*. Building a package
+        // just means inferring all the crates in it, then building each one.
+        let destination_workspace = self.build(&mut pkg_src, what).to_str();
+
+        let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
+                      pkg_src.tests.clone(), pkg_src.benchs.clone()];
+        debug!("In declare inputs for %s", id.to_str());
+        for cs in to_do.iter() {
+            for c in cs.iter() {
+                let path = pkg_src.start_dir.push_rel(&c.file).normalize();
+                debug!("Recording input: %s", path.to_str());
+                installed_files.push(path);
             }
+        }
+        // See #7402: This still isn't quite right yet; we want to
+        // install to the first workspace in the RUST_PATH if there's
+        // a non-default RUST_PATH. This code installs to the same
+        // workspace the package was built in.
+        let actual_workspace = if path_util::user_set_rust_path() {
+            default_workspace()
+        }
+            else {
+            Path(destination_workspace)
         };
-        (installed_files.unwrap(), inputs.unwrap())
+        debug!("install: destination workspace = %s, id = %s, installing to %s",
+               destination_workspace, id.to_str(), actual_workspace.to_str());
+        let result = self.install_no_build(&Path(destination_workspace),
+                                           &actual_workspace,
+                                           &id).map(|s| Path(*s));
+        debug!("install: id = %s, about to call discover_outputs, %?",
+               id.to_str(), result.to_str());
+        installed_files = installed_files + result;
+        note(fmt!("Installed package %s to %s", id.to_str(), actual_workspace.to_str()));
+        (installed_files, inputs)
     }
 
+    // again, working around lack of Encodable for Path
     fn install_no_build(&self,
                         source_workspace: &Path,
                         target_workspace: &Path,
-                        id: &PkgId) -> ~[Path] {
+                        id: &PkgId) -> ~[~str] {
         use conditions::copy_failed::cond;
 
         // Now copy stuff into the install dirs
@@ -503,32 +531,59 @@ fn install_no_build(&self,
         let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
 
         debug!("target_exec = %s target_lib = %? \
-                maybe_executable = %? maybe_library = %?",
+               maybe_executable = %? maybe_library = %?",
                target_exec.to_str(), target_lib,
                maybe_executable, maybe_library);
 
-        let mut outputs = ~[];
-
-        for exec in maybe_executable.iter() {
-            debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
-            if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
-                 os::copy_file(exec, &target_exec)) {
-                cond.raise(((*exec).clone(), target_exec.clone()));
+        do self.workcache_context.with_prep(id.install_tag()) |prep| {
+            for ee in maybe_executable.iter() {
+                prep.declare_input("binary",
+                                   ee.to_str(),
+                                   workcache_support::digest_only_date(ee));
             }
-            outputs.push(target_exec.clone());
-        }
-        for lib in maybe_library.iter() {
-            let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \
-                                                didn't install it!", lib.to_str()));
-            let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib"));
-            debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
-            if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
-                 os::copy_file(lib, &target_lib)) {
-                cond.raise(((*lib).clone(), target_lib.clone()));
+            for ll in maybe_library.iter() {
+                prep.declare_input("binary",
+                                   ll.to_str(),
+                                   workcache_support::digest_only_date(ll));
+            }
+            let subex = maybe_executable.clone();
+            let sublib = maybe_library.clone();
+            let sub_target_ex = target_exec.clone();
+            let sub_target_lib = target_lib.clone();
+
+            do prep.exec |exe_thing| {
+                let mut outputs = ~[];
+
+                for exec in subex.iter() {
+                    debug!("Copying: %s -> %s", exec.to_str(), sub_target_ex.to_str());
+                    if !(os::mkdir_recursive(&sub_target_ex.dir_path(), U_RWX) &&
+                         os::copy_file(exec, &sub_target_ex)) {
+                        cond.raise(((*exec).clone(), sub_target_ex.clone()));
+                    }
+                    exe_thing.discover_output("binary",
+                        sub_target_ex.to_str(),
+                        workcache_support::digest_only_date(&sub_target_ex));
+                    outputs.push(sub_target_ex.to_str());
+                }
+                for lib in sublib.iter() {
+                    let target_lib = sub_target_lib
+                        .clone().expect(fmt!("I built %s but apparently \
+                                             didn't install it!", lib.to_str()));
+                    let target_lib = target_lib
+                        .pop().push(lib.filename().expect("weird target lib"));
+                    debug!("Copying: %s -> %s", lib.to_str(), sub_target_lib.to_str());
+                    if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
+                         os::copy_file(lib, &target_lib)) {
+                        cond.raise(((*lib).clone(), target_lib.clone()));
+                    }
+                    exe_thing.discover_output("binary",
+                                              target_lib.to_str(),
+                                              workcache_support::digest_only_date(&target_lib));
+                    outputs.push(target_lib.to_str());
+                }
+                outputs
             }
-            outputs.push(target_lib.clone());
         }
-        outputs
     }
 
     fn prefer(&self, _id: &str, _vers: Option<~str>)  {
@@ -540,6 +595,13 @@ fn test(&self)  {
         fail!("test not yet implemented");
     }
 
+    fn init(&self) {
+        os::mkdir_recursive(&Path("src"),   U_RWX);
+        os::mkdir_recursive(&Path("lib"),   U_RWX);
+        os::mkdir_recursive(&Path("bin"),   U_RWX);
+        os::mkdir_recursive(&Path("build"), U_RWX);
+    }
+
     fn uninstall(&self, _id: &str, _vers: Option<~str>)  {
         fail!("uninstall not yet implemented");
     }
@@ -579,53 +641,53 @@ pub fn main_args(args: &[~str]) {
     let matches = &match getopts::getopts(args, opts) {
         result::Ok(m) => m,
         result::Err(f) => {
-            error(fmt!("%s", getopts::fail_str(f)));
+            error(fmt!("%s", f.to_err_msg()));
 
             return;
         }
     };
-    let mut help = getopts::opt_present(matches, "h") ||
-                   getopts::opt_present(matches, "help");
-    let no_link = getopts::opt_present(matches, "no-link");
-    let no_trans = getopts::opt_present(matches, "no-trans");
-    let supplied_sysroot = getopts::opt_val(matches, "sysroot");
-    let generate_asm = getopts::opt_present(matches, "S") ||
-        getopts::opt_present(matches, "assembly");
-    let parse_only = getopts::opt_present(matches, "parse-only");
-    let pretty = getopts::opt_present(matches, "pretty");
-    let emit_llvm = getopts::opt_present(matches, "emit-llvm");
-
-    if getopts::opt_present(matches, "v") ||
-       getopts::opt_present(matches, "version") {
+    let mut help = matches.opt_present("h") ||
+                   matches.opt_present("help");
+    let no_link = matches.opt_present("no-link");
+    let no_trans = matches.opt_present("no-trans");
+    let supplied_sysroot = matches.opt_val("sysroot");
+    let generate_asm = matches.opt_present("S") ||
+        matches.opt_present("assembly");
+    let parse_only = matches.opt_present("parse-only");
+    let pretty = matches.opt_present("pretty");
+    let emit_llvm = matches.opt_present("emit-llvm");
+
+    if matches.opt_present("v") ||
+       matches.opt_present("version") {
         rustc::version(args[0]);
         return;
     }
 
-    let use_rust_path_hack = getopts::opt_present(matches, "r") ||
-                             getopts::opt_present(matches, "rust-path-hack");
+    let use_rust_path_hack = matches.opt_present("r") ||
+                             matches.opt_present("rust-path-hack");
 
-    let linker = getopts::opt_maybe_str(matches, "linker");
-    let link_args = getopts::opt_maybe_str(matches, "link-args");
-    let cfgs = getopts::opt_strs(matches, "cfg") + getopts::opt_strs(matches, "c");
+    let linker = matches.opt_str("linker");
+    let link_args = matches.opt_str("link-args");
+    let cfgs = matches.opt_strs("cfg") + matches.opt_strs("c");
     let mut user_supplied_opt_level = true;
-    let opt_level = match getopts::opt_maybe_str(matches, "opt-level") {
+    let opt_level = match matches.opt_str("opt-level") {
         Some(~"0") => session::No,
         Some(~"1") => session::Less,
         Some(~"2") => session::Default,
         Some(~"3") => session::Aggressive,
-        _ if getopts::opt_present(matches, "O") => session::Default,
+        _ if matches.opt_present("O") => session::Default,
         _ => {
             user_supplied_opt_level = false;
             session::No
         }
     };
 
-    let save_temps = getopts::opt_present(matches, "save-temps");
-    let target     = getopts::opt_maybe_str(matches, "target");
-    let target_cpu = getopts::opt_maybe_str(matches, "target-cpu");
+    let save_temps = matches.opt_present("save-temps");
+    let target     = matches.opt_str("target");
+    let target_cpu = matches.opt_str("target-cpu");
     let experimental_features = {
-        let strs = getopts::opt_strs(matches, "Z");
-        if getopts::opt_present(matches, "Z") {
+        let strs = matches.opt_strs("Z");
+        if matches.opt_present("Z") {
             Some(strs)
         }
         else {
@@ -688,6 +750,7 @@ pub fn main_args(args: &[~str]) {
                     ~"list"    => usage::list(),
                     ~"prefer" => usage::prefer(),
                     ~"test" => usage::test(),
+                    ~"init" => usage::init(),
                     ~"uninstall" => usage::uninstall(),
                     ~"unprefer" => usage::unprefer(),
                     _ => usage::general()
@@ -710,15 +773,27 @@ pub fn main_args(args: &[~str]) {
 
     debug!("Using sysroot: %s", sroot.to_str());
     debug!("Will store workcache in %s", default_workspace().to_str());
-    BuildContext {
-        context: Context {
-        cfgs: cfgs,
-        rustc_flags: rustc_flags,
-        use_rust_path_hack: use_rust_path_hack,
-        sysroot: sroot, // Currently, only tests override this
-    },
-        workcache_context: api::default_context(default_workspace()).workcache_context
-    }.run(*cmd, remaining_args)
+
+    let rm_args = remaining_args.clone();
+    let sub_cmd = cmd.clone();
+    // Wrap the rest in task::try in case of a condition failure in a task
+    let result = do task::try {
+        BuildContext {
+            context: Context {
+                cfgs: cfgs.clone(),
+                rustc_flags: rustc_flags.clone(),
+                use_rust_path_hack: use_rust_path_hack,
+                sysroot: sroot.clone(), // Currently, only tests override this
+            },
+            workcache_context: api::default_context(default_workspace()).workcache_context
+        }.run(sub_cmd, rm_args.clone())
+    };
+    // FIXME #9262: This is using the same error code for all errors,
+    // and at least one test case succeeds if rustpkg returns copy_failed_code,
+    // when actually, it might set the exit code for that even if a different
+    // unhandled condition got raised.
+    if result.is_err() { os::set_exit_status(copy_failed_code); }
+
 }
 
 /**
index 03c2f5a4fe42afa5ae5c2514cd461333aaae63ac..9d3ad1f39a74ac0cd6c9fece12a46e6be37cc48b 100644 (file)
@@ -16,8 +16,45 @@ pub enum OutputType { Main, Lib, Bench, Test }
 
 #[deriving(Eq)]
 pub enum Target {
-    // In-place build
+    /// In-place build
     Build,
-    // Install to bin/ or lib/ dir
+    /// Install to bin/ or lib/ dir
     Install
 }
+
+#[deriving(Eq, Clone)]
+pub enum WhatToBuild {
+    /// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
+    JustOne(Path),
+    /// Build everything
+    Everything
+}
+
+pub fn is_lib(p: &Path) -> bool {
+    file_is(p, "lib")
+}
+
+pub fn is_main(p: &Path) -> bool {
+    file_is(p, "main")
+}
+
+pub fn is_test(p: &Path) -> bool {
+    file_is(p, "test")
+}
+
+pub fn is_bench(p: &Path) -> bool {
+    file_is(p, "bench")
+}
+
+fn file_is(p: &Path, stem: &str) -> bool {
+    match p.filestem() {
+        Some(s) if s == stem => true,
+        _ => false
+    }
+}
+
+pub fn lib_name_of(p: &Path) -> Path {
+    p.push("lib.rs")
+}
+
+pub static lib_crate_filename: &'static str = "lib.rs";
index 83110e22ed55fa24112ba0b9b6b93db809730fd0..918cc366799780cfe23867d28bac01084a4094e2 100644 (file)
 use syntax::diagnostic;
 use target::*;
 use package_source::PkgSrc;
-
-/// Returns the last-modified date as an Option
-fn datestamp(p: &Path) -> Option<libc::time_t> {
-    p.stat().map(|stat| stat.st_mtime)
-}
+use util::datestamp;
 
 fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
     let context = workcache::Context::new(
@@ -224,18 +220,26 @@ fn rustpkg_exec() -> Path {
 }
 
 fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
-    command_line_test_with_env(args, cwd, None).expect("Command line test failed")
+    match command_line_test_with_env(args, cwd, None) {
+        Success(r) => r,
+        _ => fail!("Command line test failed")
+    }
 }
 
-fn command_line_test_partial(args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
+fn command_line_test_partial(args: &[~str], cwd: &Path) -> ProcessResult {
     command_line_test_with_env(args, cwd, None)
 }
 
+enum ProcessResult {
+    Success(ProcessOutput),
+    Fail(int) // exit code
+}
+
 /// Runs `rustpkg` (based on the directory that this executable was
 /// invoked from) with the given arguments, in the given working directory.
 /// Returns the process's output.
 fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
-    -> Option<ProcessOutput> {
+    -> ProcessResult {
     let cmd = rustpkg_exec().to_str();
     let env_str = match env {
         Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
@@ -266,10 +270,10 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
         debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
               cmd, args, output.status,
               str::from_utf8(output.output) + str::from_utf8(output.error));
-        None
+        Fail(output.status)
     }
     else {
-        Some(output)
+        Success(output)
     }
 }
 
@@ -410,8 +414,11 @@ fn command_line_test_output(args: &[~str]) -> ~[~str] {
 
 fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
     let mut result = ~[];
-    let p_output = command_line_test_with_env(args,
-        &os::getcwd(), Some(env)).expect("Command-line test failed");
+    let p_output = match command_line_test_with_env(args,
+        &os::getcwd(), Some(env)) {
+        Fail(_) => fail!("Command-line test failed"),
+        Success(r) => r
+    };
     let test_output = str::from_utf8(p_output.output);
     for s in test_output.split_iter('\n') {
         result.push(s.to_owned());
@@ -420,9 +427,9 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~
 }
 
 // assumes short_name and path are one and the same -- I should fix
-fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path {
-    debug!("lib_output_file_name: given %s and parent %s and short name %s",
-           workspace.to_str(), parent, short_name);
+fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
+    debug!("lib_output_file_name: given %s and short name %s",
+           workspace.to_str(), short_name);
     library_in_workspace(&Path(short_name),
                          short_name,
                          Build,
@@ -450,19 +457,18 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
 }
 
 /// Add a comment at the end
-fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
+fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) {
     use conditions::bad_path::cond;
     let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
-    let contents = os::list_dir_path(&pkg_src_dir);
     let mut maybe_p = None;
-    for p in contents.iter() {
-        if p.filetype() == Some(".rs") {
-            maybe_p = Some(p);
-            break;
-        }
+    let maybe_file = pkg_src_dir.push(filename);
+    debug!("Trying to frob %s -- %s", pkg_src_dir.to_str(), filename);
+    if os::path_exists(&maybe_file) {
+        maybe_p = Some(maybe_file);
     }
+    debug!("Frobbed? %?", maybe_p);
     match maybe_p {
-        Some(p) => {
+        Some(ref p) => {
             let w = io::file_writer(p, &[io::Append]);
             match w {
                 Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
@@ -499,7 +505,7 @@ fn test_install_valid() {
     debug!("temp_workspace = %s", temp_workspace.to_str());
     // should have test, bench, lib, and main
     let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
-    ctxt.install(src);
+    ctxt.install(src, &Everything);
     // Check that all files exist
     let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
     debug!("exec = %s", exec.to_str());
@@ -528,7 +534,7 @@ fn test_install_invalid() {
     // Uses task::try because of #9001
     let result = do task::try {
         let pkg_src = PkgSrc::new(temp_workspace.clone(), false, pkgid.clone());
-        ctxt.install(pkg_src);
+        ctxt.install(pkg_src, &Everything);
     };
     // Not the best test -- doesn't test that we failed in the right way.
     // Best we can do for now.
@@ -944,20 +950,23 @@ fn no_rebuilding_dep() {
     let dep_id = PkgId::new("bar");
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     command_line_test([~"build", ~"foo"], &workspace);
-    let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
-                                                  ".rust",
-                                                  "bar"));
-    let foo_date_1 = datestamp(&output_file_name(&workspace, ~"foo"));
+    let bar_lib = lib_output_file_name(&workspace, "bar");
+    let bar_date_1 = datestamp(&bar_lib);
+
+    frob_source_file(&workspace, &p_id, "main.rs");
+
+    // Now make `bar` read-only so that subsequent rebuilds of it will fail
+    assert!(chmod_read_only(&bar_lib));
+
+    match command_line_test_partial([~"build", ~"foo"], &workspace) {
+        Success(*) => (), // ok
+        Fail(status) if status == 65 => fail!("no_rebuilding_dep failed: it tried to rebuild bar"),
+        Fail(_) => fail!("no_rebuilding_dep failed for some other reason")
+    }
 
-    frob_source_file(&workspace, &p_id);
-    command_line_test([~"build", ~"foo"], &workspace);
     let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
-                                                  ".rust",
-                                                  "bar"));
-    let foo_date_2 = datestamp(&output_file_name(&workspace, ~"foo"));
+                                                   "bar"));
     assert_eq!(bar_date_1, bar_date_2);
-    assert!(foo_date_1 < foo_date_2);
-    assert!(foo_date_1 > bar_date_1);
 }
 
 #[test]
@@ -966,7 +975,7 @@ fn do_rebuild_dep_dates_change() {
     let dep_id = PkgId::new("bar");
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     command_line_test([~"build", ~"foo"], &workspace);
-    let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
+    let bar_lib_name = lib_output_file_name(&workspace, "bar");
     let bar_date = datestamp(&bar_lib_name);
     debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
     touch_source_file(&workspace, &dep_id);
@@ -982,11 +991,11 @@ fn do_rebuild_dep_only_contents_change() {
     let dep_id = PkgId::new("bar");
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     command_line_test([~"build", ~"foo"], &workspace);
-    let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
-    frob_source_file(&workspace, &dep_id);
+    let bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
+    frob_source_file(&workspace, &dep_id, "lib.rs");
     // should adjust the datestamp
     command_line_test([~"build", ~"foo"], &workspace);
-    let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+    let new_bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
     assert!(new_bar_date > bar_date);
 }
 
@@ -1308,7 +1317,6 @@ fn rust_path_hack_build_no_arg() {
 }
 
 #[test]
-#[ignore (reason = "#7402 not yet implemented")]
 fn rust_path_install_target() {
     let dir_for_path = mkdtemp(&os::tmpdir(),
         "source_workspace").expect("rust_path_install_target failed");
@@ -1463,10 +1471,13 @@ fn test_cfg_fail() {
     let workspace = create_local_package(&p_id);
     writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
                "#[cfg(quux)] fn main() {}");
-    assert!(command_line_test_partial([test_sysroot().to_str(),
+    match command_line_test_partial([test_sysroot().to_str(),
                        ~"build",
                        ~"foo"],
-                      &workspace).is_none());
+                      &workspace) {
+        Success(*) => fail!("test_cfg_fail failed"),
+        _          => ()
+    }
 }
 
 
@@ -1679,6 +1690,21 @@ fn test_target_specific_install_dir() {
     assert_executable_exists(&workspace, "foo");
 }
 
+#[test]
+fn test_dependencies_terminate() {
+ //   let a_id = PkgId::new("a");
+    let b_id = PkgId::new("b");
+//    let workspace = create_local_package_with_dep(&b_id, &a_id);
+    let workspace = create_local_package(&b_id);
+    let b_dir = workspace.push_many([~"src", ~"b-0.1"]);
+  //  writeFile(&b_dir.push("lib.rs"), "extern mod a; pub fn f() {}");
+    let b_subdir = b_dir.push("test");
+    assert!(os::mkdir_recursive(&b_subdir, U_RWX));
+    writeFile(&b_subdir.push("test.rs"),
+              "extern mod b; use b::f; #[test] fn g() { f() }");
+    command_line_test([~"install", ~"b"], &workspace);
+}
+
 /// Returns true if p exists and is executable
 fn is_executable(p: &Path) -> bool {
     use std::libc::consts::os::posix88::{S_IXUSR};
@@ -1688,3 +1714,25 @@ fn is_executable(p: &Path) -> bool {
         Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint
     }
 }
+
+#[cfg(target_os = "win32")]
+fn chmod_read_only(p: &Path) -> bool {
+    #[fixed_stack_segment];
+    unsafe {
+        do p.to_str().with_c_str |src_buf| {
+            libc::chmod(src_buf, libc::consts::os::posix88::S_IRUSR as c_int) == 0 as libc::c_int
+        }
+    }
+}
+
+#[cfg(not(target_os = "win32"))]
+fn chmod_read_only(p: &Path) -> bool {
+    #[fixed_stack_segment];
+    unsafe {
+        do p.to_str().with_c_str |src_buf| {
+            libc::chmod(src_buf,
+                        libc::consts::os::posix88::S_IRUSR as libc::mode_t) == 0
+                as libc::c_int
+        }
+    }
+}
index dae949541b3a185a3272a7d9ba74db586ecafb35..c0601818f3772793a6ea3820166291923ca1fd0e 100644 (file)
@@ -148,3 +148,10 @@ pub fn test() {
 Options:
     -c, --cfg      Pass a cfg flag to the package script");
 }
+
+pub fn init() {
+    io::println("rustpkg init name
+
+This makes a new workspace for working on a project named name.
+");
+}
index 71c4760f28d9e61dcb71c45e3435018697f84a9c..64f76dcdc605d25d9d51c5300ca3cdfaea07ea7d 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::libc;
 use std::os;
 use extra::workcache;
 use rustc::driver::{driver, session};
 use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
 use messages::error;
 
-pub use target::{OutputType, Main, Lib, Bench, Test};
+pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
 use workcache_support::{digest_file_with_date, digest_only_date};
 
 // It would be nice to have the list of commands in just one place -- for example,
 // you could update the match in rustpkg.rc but forget to update this list. I think
 // that should be fixed.
 static COMMANDS: &'static [&'static str] =
-    &["build", "clean", "do", "info", "install", "list", "prefer", "test", "uninstall",
+    &["build", "clean", "do", "info", "init", "install", "list", "prefer", "test", "uninstall",
       "unprefer"];
 
 
@@ -171,6 +172,8 @@ pub fn compile_input(context: &BuildContext,
     // not sure if we should support anything else
 
     let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path);
+    // Make the output directory if it doesn't exist already
+    assert!(os::mkdir_recursive(&out_dir, U_RWX));
 
     let binary = os::args()[0].to_managed();
 
@@ -220,7 +223,7 @@ pub fn compile_input(context: &BuildContext,
         optimize: if opt { session::Aggressive } else { session::No },
         test: what == Test || what == Bench,
         maybe_sysroot: Some(sysroot_to_use),
-        addl_lib_search_paths: @mut (~[out_dir.clone()]),
+        addl_lib_search_paths: @mut (~[]),
         output_type: output_type,
         .. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
     };
@@ -329,6 +332,9 @@ pub fn compile_crate_from_input(input: &Path,
     // Register dependency on the source file
     exec.discover_input("file", input.to_str(), digest_file_with_date(input));
 
+    debug!("Built %s, date = %?", outputs.out_filename.to_str(),
+           datestamp(&outputs.out_filename));
+
     Some(outputs.out_filename)
 }
 
@@ -409,7 +415,8 @@ pub fn find_and_install_dependencies(context: &BuildContext,
                             workspaces[0]
                         };
                         let (outputs_disc, inputs_disc) =
-                            context.install(PkgSrc::new(dep_workspace.clone(), false, pkg_id));
+                            context.install(PkgSrc::new(dep_workspace.clone(),
+                                false, pkg_id), &JustOne(Path(lib_crate_filename)));
                         debug!("Installed %s, returned %? dependencies and \
                                %? transitive dependencies",
                                lib_name, outputs_disc.len(), inputs_disc.len());
@@ -435,10 +442,11 @@ pub fn find_and_install_dependencies(context: &BuildContext,
                         debug!("Adding additional search path: %s", lib_name);
                         let installed_library =
                             installed_library_in_workspace(&Path(lib_name), &dep_workspace)
-                                .expect( fmt!("rustpkg failed to install dependency %s",
+                                .expect(fmt!("rustpkg failed to install dependency %s",
                                               lib_name));
                         let install_dir = installed_library.pop();
-                        debug!("Installed %s into %s", lib_name, install_dir.to_str());
+                        debug!("Installed %s into %s [%?]", lib_name, install_dir.to_str(),
+                               datestamp(&installed_library));
                         save(install_dir);
                     }
                 }}
@@ -449,37 +457,6 @@ pub fn find_and_install_dependencies(context: &BuildContext,
     };
 }
 
-#[cfg(windows)]
-pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    /* FIXME (#1768): Investigate how to do this on win32
-       Node wraps symlinks by having a .bat,
-       but that won't work with minGW. */
-
-    false
-}
-
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "android")]
-#[cfg(target_os = "freebsd")]
-#[cfg(target_os = "macos")]
-pub fn link_exe(src: &Path, dest: &Path) -> bool {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    use std::c_str::ToCStr;
-    use std::libc;
-
-    unsafe {
-        do src.with_c_str |src_buf| {
-            do dest.with_c_str |dest_buf| {
-                libc::link(src_buf, dest_buf) == 0 as libc::c_int &&
-                    libc::chmod(dest_buf, 755) == 0 as libc::c_int
-            }
-        }
-    }
-}
-
 pub fn mk_string_lit(s: @str) -> ast::lit {
     Spanned {
         node: ast::lit_str(s),
@@ -516,3 +493,12 @@ pub fn option_to_vec<T>(x: Option<T>) -> ~[T] {
 // tjc: cheesy
 fn debug_flags() -> ~[~str] { ~[] }
 // static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
+
+
+/// Returns the last-modified date as an Option
+pub fn datestamp(p: &Path) -> Option<libc::time_t> {
+    debug!("Scrutinizing datestamp for %s - does it exist? %?", p.to_str(), os::path_exists(p));
+    let out = p.stat().map(|stat| stat.st_mtime);
+    debug!("Date = %?", out);
+    out.map(|t| { *t as libc::time_t })
+}
index e2416782d987cd43a42e079eeecb902f06caa57c..daf35c988c823861f7237e86841ea6e0d9de0eef 100644 (file)
@@ -56,3 +56,8 @@ pub fn discover_outputs(e: &mut workcache::Exec, outputs: ~[Path]) {
         e.discover_output("binary", p.to_str(), digest_only_date(p));
     }
 }
+
+/// Returns the function name for building a crate
+pub fn crate_tag(p: &Path) -> ~str {
+    p.to_str() // implicitly, it's "build(p)"...
+}
index ce8e90e1a4324395f823a02201d7e223563b957c..42f511f722daba4323cd3cc6d9502b7294ea3974 100644 (file)
@@ -230,13 +230,16 @@ pub unsafe fn reserve<T>(v: &mut @[T], n: uint) {
     // Implementation detail. Shouldn't be public
     #[allow(missing_doc)]
     pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut Box<Vec<()>>, n: uint) {
-
+        // check for `uint` overflow
         unsafe {
-            let size_in_bytes = n * (*ty).size;
-            if size_in_bytes > (**ptr).data.alloc {
-                let total_size = size_in_bytes + sys::size_of::<Vec<()>>();
+            if n > (**ptr).data.alloc / (*ty).size {
+                let alloc = n * (*ty).size;
+                let total_size = alloc + sys::size_of::<Vec<()>>();
+                if alloc / (*ty).size != n || total_size < alloc {
+                    fail!("vector size is too large: %u", n);
+                }
                 (*ptr) = local_realloc(*ptr as *(), total_size) as *mut Box<Vec<()>>;
-                (**ptr).data.alloc = size_in_bytes;
+                (**ptr).data.alloc = alloc;
             }
         }
 
index 6c3d4c5f1fbeab4d82dec81c1543d7e4eeb74939..0626b3fc6183c5ff56044421788139c3dae4051e 100644 (file)
@@ -22,7 +22,7 @@ pub fn to_uint<T>(thing: &T) -> uint {
 /// Determine if two borrowed pointers point to the same thing.
 #[inline]
 pub fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool {
-    to_uint(thing) == to_uint(other)
+    (thing as *T) == (other as *T)
 }
 
 // Equality for region pointers
@@ -70,3 +70,17 @@ impl<'self, T: TotalEq> TotalEq for &'self T {
     #[inline]
     fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::ref_eq;
+
+    #[test]
+    fn test_ref_eq() {
+        let x = 1;
+        let y = 1;
+
+        assert!(ref_eq(&x, &x));
+        assert!(!ref_eq(&x, &y));
+    }
+}
index a2842efbf8a04dbeabd32582fdc131f4ed4fd071..67b5aff8466047cce860aa4cde4da2334fbe9df4 100644 (file)
@@ -30,9 +30,7 @@ pub enum NullByteResolution {
 
 condition! {
     // This should be &[u8] but there's a lifetime issue (#5370).
-    // NOTE: this super::NullByteResolution should be NullByteResolution
-    // Change this next time the snapshot is updated.
-    pub null_byte: (~[u8]) -> super::NullByteResolution;
+    pub null_byte: (~[u8]) -> NullByteResolution;
 }
 
 /// The representation of a C String.
@@ -127,7 +125,7 @@ pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
 }
 
 impl Drop for CString {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment]; #[inline(never)];
         if self.owns_buffer_ {
             unsafe {
index 911d883f88ac98c1f537b6c768ec306706c9a2ce..431fc27a202d32d4c2da13d8b5ebe62cb89176c3 100644 (file)
@@ -281,11 +281,11 @@ pub fn escape_unicode(c: char, f: &fn(char)) {
     // avoid calling str::to_str_radix because we don't really need to allocate
     // here.
     f('\\');
-    let pad = cond!(
-        (c <= '\xff')   { f('x'); 2 }
-        (c <= '\uffff') { f('u'); 4 }
-        _               { f('U'); 8 }
-    );
+    let pad = match () {
+        _ if c <= '\xff'    => { f('x'); 2 }
+        _ if c <= '\uffff'  => { f('u'); 4 }
+        _                   => { f('U'); 8 }
+    };
     for offset in range_step::<i32>(4 * (pad - 1), -1, -4) {
         unsafe {
             match ((c as i32) >> offset) & 0xf {
@@ -329,13 +329,13 @@ pub fn len_utf8_bytes(c: char) -> uint {
     static MAX_FOUR_B:  uint = 2097152u;
 
     let code = c as uint;
-    cond!(
-        (code < MAX_ONE_B)   { 1u }
-        (code < MAX_TWO_B)   { 2u }
-        (code < MAX_THREE_B) { 3u }
-        (code < MAX_FOUR_B)  { 4u }
-        _ { fail!("invalid character!") }
-    )
+    match () {
+        _ if code < MAX_ONE_B   => 1u,
+        _ if code < MAX_TWO_B   => 2u,
+        _ if code < MAX_THREE_B => 3u,
+        _ if code < MAX_FOUR_B  => 4u,
+        _                       => fail!("invalid character!"),
+    }
 }
 
 impl ToStr for char {
index 9cd2ad79d18902c64a2d6029be937c54a53ae1d4..954b8bd73300c5ede29899095ad86b85a015fb84 100644 (file)
@@ -87,7 +87,7 @@ struct Guard<'self, T, U> {
 
 #[unsafe_destructor]
 impl<'self, T, U> Drop for Guard<'self, T, U> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         debug!("Guard: popping handler from TLS");
         let curr = local_data::pop(self.cond.key);
         match curr {
index 2ca36de4f49cce83a79c69e1736c49027abfca25..890a53690d96a8574d55355b38ca945fc90b913b 100644 (file)
@@ -1021,7 +1021,7 @@ pub fn new(f: *libc::FILE) -> FILERes {
 }
 
 impl Drop for FILERes {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment]; #[inline(never)];
 
         unsafe {
@@ -1302,7 +1302,7 @@ pub fn new(fd: fd_t) -> FdRes {
 }
 
 impl Drop for FdRes {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment]; #[inline(never)];
 
         unsafe {
@@ -1832,7 +1832,7 @@ pub fn new(arg: Arg<t>) -> Res<t> {
 
     #[unsafe_destructor]
     impl<T> Drop for Res<T> {
-        fn drop(&self) {
+        fn drop(&mut self) {
             match self.arg.opt_level {
                 None => (),
                 Some(level) => {
index 790dc886c0497d94f010622fa53d78213ee8cf1e..a5a2def450e8a0f33dce48a034c86f4027f81b38 100644 (file)
@@ -294,7 +294,6 @@ pub mod posix88 {
                 pub type ssize_t = i32;
             }
             #[cfg(target_arch = "x86")]
-            #[cfg(target_arch = "mips")]
             pub mod posix01 {
                 use libc::types::os::arch::c95::{c_short, c_long, time_t};
                 use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t};
@@ -305,7 +304,6 @@ pub mod posix01 {
                 pub type blksize_t = i32;
                 pub type blkcnt_t = i32;
 
-                #[cfg(target_arch = "x86")]
                 pub struct stat {
                     st_dev: dev_t,
                     __pad1: c_short,
@@ -328,30 +326,6 @@ pub struct stat {
                     __unused4: c_long,
                     __unused5: c_long,
                 }
-
-                #[cfg(target_arch = "mips")]
-                pub struct stat {
-                    st_dev: c_ulong,
-                    st_pad1: [c_long, ..3],
-                    st_ino: ino_t,
-                    st_mode: mode_t,
-                    st_nlink: nlink_t,
-                    st_uid: uid_t,
-                    st_gid: gid_t,
-                    st_rdev: c_ulong,
-                    st_pad2: [c_long, ..2],
-                    st_size: off_t,
-                    st_pad3: c_long,
-                    st_atime: time_t,
-                    st_atime_nsec: c_long,
-                    st_mtime: time_t,
-                    st_mtime_nsec: c_long,
-                    st_ctime: time_t,
-                    st_ctime_nsec: c_long,
-                    st_blksize: blksize_t,
-                    st_blocks: blkcnt_t,
-                    st_pad5: [c_long, ..14],
-                }
             }
             #[cfg(target_arch = "arm")]
             pub mod posix01 {
@@ -385,6 +359,40 @@ pub struct stat {
                     st_ino: c_ulonglong
                 }
             }
+            #[cfg(target_arch = "mips")]
+            pub mod posix01 {
+                use libc::types::os::arch::c95::{c_long, c_ulong, time_t};
+                use libc::types::os::arch::posix88::{gid_t, ino_t};
+                use libc::types::os::arch::posix88::{mode_t, off_t};
+                use libc::types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u32;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i32;
+
+                pub struct stat {
+                    st_dev: c_ulong,
+                    st_pad1: [c_long, ..3],
+                    st_ino: ino_t,
+                    st_mode: mode_t,
+                    st_nlink: nlink_t,
+                    st_uid: uid_t,
+                    st_gid: gid_t,
+                    st_rdev: c_ulong,
+                    st_pad2: [c_long, ..2],
+                    st_size: off_t,
+                    st_pad3: c_long,
+                    st_atime: time_t,
+                    st_atime_nsec: c_long,
+                    st_mtime: time_t,
+                    st_mtime_nsec: c_long,
+                    st_ctime: time_t,
+                    st_ctime_nsec: c_long,
+                    st_blksize: blksize_t,
+                    st_blocks: blkcnt_t,
+                    st_pad5: [c_long, ..14],
+                }
+            }
             pub mod posix08 {}
             pub mod bsd44 {}
             pub mod extra {}
@@ -1633,6 +1641,111 @@ pub mod posix88 {
             pub static EPIPE : c_int = 32;
             pub static EDOM : c_int = 33;
             pub static ERANGE : c_int = 34;
+
+            pub static ENOMSG: c_int = 35;
+            pub static EIDRM: c_int = 36;
+            pub static ECHRNG: c_int = 37;
+            pub static EL2NSYNC: c_int = 38;
+            pub static EL3HLT: c_int = 39;
+            pub static EL3RST: c_int = 40;
+            pub static ELNRNG: c_int = 41;
+            pub static EUNATCH: c_int = 42;
+            pub static ENOCSI: c_int = 43;
+            pub static EL2HLT: c_int = 44;
+            pub static EDEADLK: c_int = 45;
+            pub static ENOLCK: c_int = 46;
+            pub static EBADE: c_int = 50;
+            pub static EBADR: c_int = 51;
+            pub static EXFULL: c_int = 52;
+            pub static ENOANO: c_int = 53;
+            pub static EBADRQC: c_int = 54;
+            pub static EBADSLT: c_int = 55;
+            pub static EDEADLOCK: c_int = 56;
+            pub static EBFONT: c_int = 59;
+            pub static ENOSTR: c_int = 60;
+            pub static ENODATA: c_int = 61;
+            pub static ETIME: c_int = 62;
+            pub static ENOSR: c_int = 63;
+            pub static ENONET: c_int = 64;
+            pub static ENOPKG: c_int = 65;
+            pub static EREMOTE: c_int = 66;
+            pub static ENOLINK: c_int = 67;
+            pub static EADV: c_int = 68;
+            pub static ESRMNT: c_int = 69;
+            pub static ECOMM: c_int = 70;
+            pub static EPROTO: c_int = 71;
+            pub static EDOTDOT: c_int = 73;
+            pub static EMULTIHOP: c_int = 74;
+            pub static EBADMSG: c_int = 77;
+            pub static ENAMETOOLONG: c_int = 78;
+            pub static EOVERFLOW: c_int = 79;
+            pub static ENOTUNIQ: c_int = 80;
+            pub static EBADFD: c_int = 81;
+            pub static EREMCHG: c_int = 82;
+            pub static ELIBACC: c_int = 83;
+            pub static ELIBBAD: c_int = 84;
+            pub static ELIBSCN: c_int = 95;
+            pub static ELIBMAX: c_int = 86;
+            pub static ELIBEXEC: c_int = 87;
+            pub static EILSEQ: c_int = 88;
+            pub static ENOSYS: c_int = 89;
+            pub static ELOOP: c_int = 90;
+            pub static ERESTART: c_int = 91;
+            pub static ESTRPIPE: c_int = 92;
+            pub static ENOTEMPTY: c_int = 93;
+            pub static EUSERS: c_int = 94;
+            pub static ENOTSOCK: c_int = 95;
+            pub static EDESTADDRREQ: c_int = 96;
+            pub static EMSGSIZE: c_int = 97;
+            pub static EPROTOTYPE: c_int = 98;
+            pub static ENOPROTOOPT: c_int = 99;
+            pub static EPROTONOSUPPORT: c_int = 120;
+            pub static ESOCKTNOSUPPORT: c_int = 121;
+            pub static EOPNOTSUPP: c_int = 122;
+            pub static EPFNOSUPPORT: c_int = 123;
+            pub static EAFNOSUPPORT: c_int = 124;
+            pub static EADDRINUSE: c_int = 125;
+            pub static EADDRNOTAVAIL: c_int = 126;
+            pub static ENETDOWN: c_int = 127;
+            pub static ENETUNREACH: c_int = 128;
+            pub static ENETRESET: c_int = 129;
+            pub static ECONNABORTED: c_int = 130;
+            pub static ECONNRESET: c_int = 131;
+            pub static ENOBUFS: c_int = 132;
+            pub static EISCONN: c_int = 133;
+            pub static ENOTCONN: c_int = 134;
+            pub static EUCLEAN: c_int = 135;
+            pub static ENOTNAM: c_int = 137;
+            pub static ENAVAIL: c_int = 138;
+            pub static EISNAM: c_int = 139;
+            pub static EREMOTEIO: c_int = 140;
+            pub static ESHUTDOWN: c_int = 143;
+            pub static ETOOMANYREFS: c_int = 144;
+            pub static ETIMEDOUT: c_int = 145;
+            pub static ECONNREFUSED: c_int = 146;
+            pub static EHOSTDOWN: c_int = 147;
+            pub static EHOSTUNREACH: c_int = 148;
+            pub static EWOULDBLOCK: c_int = EAGAIN;
+            pub static EALREADY: c_int = 149;
+            pub static EINPROGRESS: c_int = 150;
+            pub static ESTALE: c_int = 151;
+            pub static ECANCELED: c_int = 158;
+
+            pub static ENOMEDIUM: c_int = 159;
+            pub static EMEDIUMTYPE: c_int = 160;
+            pub static ENOKEY: c_int = 161;
+            pub static EKEYEXPIRED: c_int = 162;
+            pub static EKEYREVOKED: c_int = 163;
+            pub static EKEYREJECTED: c_int = 164;
+
+            pub static EOWNERDEAD: c_int = 165;
+            pub static ENOTRECOVERABLE: c_int = 166;
+
+            pub static ERFKILL: c_int = 167;
+
+            pub static EHWPOISON: c_int = 168;
+
+            pub static EDQUOT: c_int = 1133;
         }
         pub mod posix01 {
             use libc::types::os::arch::c95::c_int;
index b39b3102a343a3982d846d853e7d9b2d38c193a8..1a463a499cb41bedee4d31e88e58094bea708b08 100644 (file)
@@ -37,17 +37,6 @@ pub fn console_off() {
     rt::logging::console_off();
 }
 
-#[cfg(not(test), stage0)]
-#[lang="log_type"]
-#[allow(missing_doc)]
-pub fn log_type<T>(_level: u32, object: &T) {
-    use sys;
-
-    // XXX: Bad allocation
-    let msg = sys::log_str(object);
-    newsched_log_str(msg);
-}
-
 fn newsched_log_str(msg: ~str) {
     use rt::task::Task;
     use rt::local::Local;
index 0addcce3eb608657b6a50ae2c438cee6d8f946f1..2787e0286454de7aba0ca942e3cebb85406aeb18 100644 (file)
@@ -206,35 +206,35 @@ impl Orderable for f32 {
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn min(&self, other: &f32) -> f32 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self < *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self < *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn max(&self, other: &f32) -> f32 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self > *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self > *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns the number constrained within the range `mn <= self <= mx`.
     /// If any of the numbers are `NaN` then `NaN` is returned.
     #[inline]
     fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
-        cond!(
-            (self.is_NaN())   { *self }
-            (!(*self <= *mx)) { *mx   }
-            (!(*self >= *mn)) { *mn   }
-            _                 { *self }
-        )
+        match () {
+            _ if self.is_NaN()   => *self,
+            _ if !(*self <= *mx) => *mx,
+            _ if !(*self >= *mn) => *mn,
+            _                    => *self,
+        }
     }
 }
 
@@ -822,39 +822,6 @@ fn to_str_radix(&self, rdx: uint) -> ~str {
     }
 }
 
-///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently,  '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number.  Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<f32> {
-    strconv::from_str_common(num, 10u, true, true, true,
-                             strconv::ExpDec, false, false)
-}
-
 ///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
@@ -888,40 +855,65 @@ pub fn from_str_hex(num: &str) -> Option<f32> {
                              strconv::ExpBin, false, false)
 }
 
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
-    strconv::from_str_common(num, rdx, true, true, false,
-                             strconv::ExpNone, false, false)
-}
-
 impl FromStr for f32 {
+    ///
+    /// Convert a string in base 10 to a float.
+    /// Accepts a optional decimal exponent.
+    ///
+    /// This function accepts strings such as
+    ///
+    /// * '3.14'
+    /// * '+3.14', equivalent to '3.14'
+    /// * '-3.14'
+    /// * '2.5E10', or equivalently, '2.5e10'
+    /// * '2.5E-10'
+    /// * '.' (understood as 0)
+    /// * '5.'
+    /// * '.5', or, equivalently,  '0.5'
+    /// * '+inf', 'inf', '-inf', 'NaN'
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number.  Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
-    fn from_str(val: &str) -> Option<f32> { from_str(val) }
+    fn from_str(val: &str) -> Option<f32> {
+        strconv::from_str_common(val, 10u, true, true, true,
+                                 strconv::ExpDec, false, false)
+    }
 }
 
 impl num::FromStrRadix for f32 {
+    ///
+    /// Convert a string in an given base to a float.
+    ///
+    /// Due to possible conflicts, this function does **not** accept
+    /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+    /// does it recognize exponents of any kind.
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    /// * radix - The base to use. Must lie in the range [2 .. 36]
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number. Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
     fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
-        from_str_radix(val, rdx)
+        strconv::from_str_common(val, rdx, true, true, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
index b0675278238e4c0e8fe92751cdd48e06c5bc9dbd..afc22ec212b3ead98b062af3357e16afe05dc387 100644 (file)
@@ -229,35 +229,35 @@ impl Orderable for f64 {
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn min(&self, other: &f64) -> f64 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self < *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self < *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns `NaN` if either of the numbers are `NaN`.
     #[inline]
     fn max(&self, other: &f64) -> f64 {
-        cond!(
-            (self.is_NaN())  { *self  }
-            (other.is_NaN()) { *other }
-            (*self > *other) { *self  }
-            _                { *other }
-        )
+        match () {
+            _ if self.is_NaN()  => *self,
+            _ if other.is_NaN() => *other,
+            _ if *self > *other => *self,
+            _                   => *other,
+        }
     }
 
     /// Returns the number constrained within the range `mn <= self <= mx`.
     /// If any of the numbers are `NaN` then `NaN` is returned.
     #[inline]
     fn clamp(&self, mn: &f64, mx: &f64) -> f64 {
-        cond!(
-            (self.is_NaN())   { *self }
-            (!(*self <= *mx)) { *mx   }
-            (!(*self >= *mn)) { *mn   }
-            _                 { *self }
-        )
+        match () {
+            _ if self.is_NaN()   => *self,
+            _ if !(*self <= *mx) => *mx,
+            _ if !(*self >= *mn) => *mn,
+            _                    => *self,
+        }
     }
 }
 
@@ -869,39 +869,6 @@ fn to_str_radix(&self, rdx: uint) -> ~str {
     }
 }
 
-///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently,  '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number.  Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<f64> {
-    strconv::from_str_common(num, 10u, true, true, true,
-                             strconv::ExpDec, false, false)
-}
-
 ///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
@@ -935,40 +902,65 @@ pub fn from_str_hex(num: &str) -> Option<f64> {
                              strconv::ExpBin, false, false)
 }
 
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
-    strconv::from_str_common(num, rdx, true, true, false,
-                             strconv::ExpNone, false, false)
-}
-
 impl FromStr for f64 {
+    ///
+    /// Convert a string in base 10 to a float.
+    /// Accepts a optional decimal exponent.
+    ///
+    /// This function accepts strings such as
+    ///
+    /// * '3.14'
+    /// * '+3.14', equivalent to '3.14'
+    /// * '-3.14'
+    /// * '2.5E10', or equivalently, '2.5e10'
+    /// * '2.5E-10'
+    /// * '.' (understood as 0)
+    /// * '5.'
+    /// * '.5', or, equivalently,  '0.5'
+    /// * '+inf', 'inf', '-inf', 'NaN'
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number.  Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
-    fn from_str(val: &str) -> Option<f64> { from_str(val) }
+    fn from_str(val: &str) -> Option<f64> {
+        strconv::from_str_common(val, 10u, true, true, true,
+                                 strconv::ExpDec, false, false)
+    }
 }
 
 impl num::FromStrRadix for f64 {
+    ///
+    /// Convert a string in an given base to a float.
+    ///
+    /// Due to possible conflicts, this function does **not** accept
+    /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+    /// does it recognize exponents of any kind.
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    /// * radix - The base to use. Must lie in the range [2 .. 36]
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number. Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
     fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
-        from_str_radix(val, rdx)
+        strconv::from_str_common(val, rdx, true, true, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
index 3952f5478f7fdb956963edddae97a2fe71c3f2e2..b86422edc0356975f68f02614cbd8a9cf8c86887 100644 (file)
@@ -187,39 +187,6 @@ fn to_str_radix(&self, radix: uint) -> ~str {
     }
 }
 
-///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently,  '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number.  Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<float> {
-    strconv::from_str_common(num, 10u, true, true, true,
-                             strconv::ExpDec, false, false)
-}
-
 ///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
@@ -253,40 +220,65 @@ pub fn from_str_hex(num: &str) -> Option<float> {
                              strconv::ExpBin, false, false)
 }
 
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, radix: uint) -> Option<float> {
-    strconv::from_str_common(num, radix, true, true, false,
-                             strconv::ExpNone, false, false)
-}
-
 impl FromStr for float {
+    ///
+    /// Convert a string in base 10 to a float.
+    /// Accepts a optional decimal exponent.
+    ///
+    /// This function accepts strings such as
+    ///
+    /// * '3.14'
+    /// * '+3.14', equivalent to '3.14'
+    /// * '-3.14'
+    /// * '2.5E10', or equivalently, '2.5e10'
+    /// * '2.5E-10'
+    /// * '.' (understood as 0)
+    /// * '5.'
+    /// * '.5', or, equivalently,  '0.5'
+    /// * '+inf', 'inf', '-inf', 'NaN'
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number.  Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
-    fn from_str(val: &str) -> Option<float> { from_str(val) }
+    fn from_str(val: &str) -> Option<float> {
+        strconv::from_str_common(val, 10u, true, true, true,
+                                 strconv::ExpDec, false, false)
+    }
 }
 
 impl num::FromStrRadix for float {
+    ///
+    /// Convert a string in an given base to a float.
+    ///
+    /// Due to possible conflicts, this function does **not** accept
+    /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+    /// does it recognize exponents of any kind.
+    ///
+    /// Leading and trailing whitespace represent an error.
+    ///
+    /// # Arguments
+    ///
+    /// * num - A string
+    /// * radix - The base to use. Must lie in the range [2 .. 36]
+    ///
+    /// # Return value
+    ///
+    /// `none` if the string did not represent a valid number. Otherwise,
+    /// `Some(n)` where `n` is the floating-point number represented by `num`.
+    ///
     #[inline]
     fn from_str_radix(val: &str, radix: uint) -> Option<float> {
-        from_str_radix(val, radix)
+        strconv::from_str_common(val, radix, true, true, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
@@ -1316,49 +1308,49 @@ pub fn test_to_str_exact_do_decimal() {
 
     #[test]
     pub fn test_from_str() {
-        assert_eq!(from_str("3"), Some(3.));
-        assert_eq!(from_str("3.14"), Some(3.14));
-        assert_eq!(from_str("+3.14"), Some(3.14));
-        assert_eq!(from_str("-3.14"), Some(-3.14));
-        assert_eq!(from_str("2.5E10"), Some(25000000000.));
-        assert_eq!(from_str("2.5e10"), Some(25000000000.));
-        assert_eq!(from_str("25000000000.E-10"), Some(2.5));
-        assert_eq!(from_str("."), Some(0.));
-        assert_eq!(from_str(".e1"), Some(0.));
-        assert_eq!(from_str(".e-1"), Some(0.));
-        assert_eq!(from_str("5."), Some(5.));
-        assert_eq!(from_str(".5"), Some(0.5));
-        assert_eq!(from_str("0.5"), Some(0.5));
-        assert_eq!(from_str("-.5"), Some(-0.5));
-        assert_eq!(from_str("-5"), Some(-5.));
-        assert_eq!(from_str("inf"), Some(infinity));
-        assert_eq!(from_str("+inf"), Some(infinity));
-        assert_eq!(from_str("-inf"), Some(neg_infinity));
+        assert_eq!(from_str::<float>("3"), Some(3.));
+        assert_eq!(from_str::<float>("3.14"), Some(3.14));
+        assert_eq!(from_str::<float>("+3.14"), Some(3.14));
+        assert_eq!(from_str::<float>("-3.14"), Some(-3.14));
+        assert_eq!(from_str::<float>("2.5E10"), Some(25000000000.));
+        assert_eq!(from_str::<float>("2.5e10"), Some(25000000000.));
+        assert_eq!(from_str::<float>("25000000000.E-10"), Some(2.5));
+        assert_eq!(from_str::<float>("."), Some(0.));
+        assert_eq!(from_str::<float>(".e1"), Some(0.));
+        assert_eq!(from_str::<float>(".e-1"), Some(0.));
+        assert_eq!(from_str::<float>("5."), Some(5.));
+        assert_eq!(from_str::<float>(".5"), Some(0.5));
+        assert_eq!(from_str::<float>("0.5"), Some(0.5));
+        assert_eq!(from_str::<float>("-.5"), Some(-0.5));
+        assert_eq!(from_str::<float>("-5"), Some(-5.));
+        assert_eq!(from_str::<float>("inf"), Some(infinity));
+        assert_eq!(from_str::<float>("+inf"), Some(infinity));
+        assert_eq!(from_str::<float>("-inf"), Some(neg_infinity));
         // note: NaN != NaN, hence this slightly complex test
-        match from_str("NaN") {
+        match from_str::<float>("NaN") {
             Some(f) => assert!(f.is_NaN()),
             None => fail!()
         }
         // note: -0 == 0, hence these slightly more complex tests
-        match from_str("-0") {
+        match from_str::<float>("-0") {
             Some(v) if v.is_zero() => assert!(v.is_negative()),
             _ => fail!()
         }
-        match from_str("0") {
+        match from_str::<float>("0") {
             Some(v) if v.is_zero() => assert!(v.is_positive()),
             _ => fail!()
         }
 
-        assert!(from_str("").is_none());
-        assert!(from_str("x").is_none());
-        assert!(from_str(" ").is_none());
-        assert!(from_str("   ").is_none());
-        assert!(from_str("e").is_none());
-        assert!(from_str("E").is_none());
-        assert!(from_str("E1").is_none());
-        assert!(from_str("1e1e1").is_none());
-        assert!(from_str("1e1.1").is_none());
-        assert!(from_str("1e1-1").is_none());
+        assert!(from_str::<float>("").is_none());
+        assert!(from_str::<float>("x").is_none());
+        assert!(from_str::<float>(" ").is_none());
+        assert!(from_str::<float>("   ").is_none());
+        assert!(from_str::<float>("e").is_none());
+        assert!(from_str::<float>("E").is_none());
+        assert!(from_str::<float>("E1").is_none());
+        assert!(from_str::<float>("1e1e1").is_none());
+        assert!(from_str::<float>("1e1.1").is_none());
+        assert!(from_str::<float>("1e1-1").is_none());
     }
 
     #[test]
index dfdd6cf72f742970d69e1c74607e8f123e89eebf..38a4df270fc23cabfa2b56e1fa18d9b26917ea97 100644 (file)
@@ -101,7 +101,17 @@ pub fn next_power_of_two(n: uint) -> uint {
     let mut tmp: uint = n - 1u;
     let mut shift: uint = 1u;
     while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
-    return tmp + 1u;
+    tmp + 1u
+}
+
+/// Returns the smallest power of 2 greater than or equal to `n`
+#[inline]
+pub fn next_power_of_two_opt(n: uint) -> Option<uint> {
+    let halfbits: uint = sys::size_of::<uint>() * 4u;
+    let mut tmp: uint = n - 1u;
+    let mut shift: uint = 1u;
+    while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
+    tmp.checked_add(&1)
 }
 
 #[cfg(target_word_size = "32")]
index 0a9c912a6e2acbe0bbc142dd820190adafea86ec..7cd1be7ab740620ef9336144c6b084f6278cdfc1 100644 (file)
@@ -70,11 +70,11 @@ fn max(&self, other: &$T) -> $T {
     /// Returns the number constrained within the range `mn <= self <= mx`.
     #[inline]
     fn clamp(&self, mn: &$T, mx: &$T) -> $T {
-        cond!(
-            (*self > *mx) { *mx   }
-            (*self < *mn) { *mn   }
-            _             { *self }
-        )
+        match () {
+            _ if (*self > *mx) => *mx,
+            _ if (*self < *mn) => *mn,
+            _                  => *self,
+        }
     }
 }
 
index 756b4a10d3c9042ed7aa576b50edad859e515fce..1d4d827434b96518ba0e4de58eb311ae3afd401d 100644 (file)
@@ -14,7 +14,7 @@
 
 #[lang="drop"]
 pub trait Drop {
-    fn drop(&self);
+    fn drop(&mut self);
 }
 
 #[lang="add"]
@@ -95,7 +95,7 @@ struct HasDtor {
     }
 
     impl Drop for HasDtor {
-        fn drop(&self) {
+        fn drop(&mut self) {
         }
     }
 
@@ -105,4 +105,4 @@ fn alloc_obj_with_dtor(bh: &mut BenchHarness) {
             HasDtor { x : 10 };
         }
     }
-}
\ No newline at end of file
+}
index ce725257dfff03a4fefba00aa2df45b5172d15d5..9b6d0a77cd83b6945abd8d150d2ab3baa3e0b3ef 100644 (file)
@@ -573,7 +573,7 @@ struct R {
 
         #[unsafe_destructor]
         impl ::ops::Drop for R {
-           fn drop(&self) { *(self.i) += 1; }
+           fn drop(&mut self) { *(self.i) += 1; }
         }
 
         fn R(i: @mut int) -> R {
index 5269eca888af8c31c9ebf9cae452724a441a8f19..1dc1d1d677648c923f2a3233921f29e99e5dfd05 100644 (file)
@@ -148,18 +148,6 @@ pub fn as_utf16_p<T>(s: &str, f: &fn(*u16) -> T) -> T {
     }
 }
 
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
-    (fn $name:ident ()) => (
-        extern {
-            fn $name();
-        }
-    )
-)
-}
-
 /*
 Accessing environment variables is not generally threadsafe.
 Serialize access through a global lock.
@@ -196,16 +184,7 @@ unsafe fn get_env_pairs() -> ~[~str] {
             if (ch as uint == 0) {
                 fail!("os::env() failure getting env string from OS: %s", os::last_os_error());
             }
-            let mut curr_ptr: uint = ch as uint;
-            let mut result = ~[];
-            while(*(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
-                let env_pair = str::raw::from_c_str(
-                    curr_ptr as *libc::c_char);
-                result.push(env_pair);
-                curr_ptr +=
-                    libc::strlen(curr_ptr as *libc::c_char) as uint
-                    + 1;
-            }
+            let result = str::raw::from_c_multistring(ch as *libc::c_char, None);
             FreeEnvironmentStringsA(ch);
             result
         }
@@ -1135,18 +1114,19 @@ fn strerror() -> ~str {
         #[fixed_stack_segment]; #[inline(never)];
 
         use libc::types::os::arch::extra::DWORD;
-        use libc::types::os::arch::extra::LPSTR;
+        use libc::types::os::arch::extra::LPWSTR;
         use libc::types::os::arch::extra::LPVOID;
+        use libc::types::os::arch::extra::WCHAR;
 
         #[cfg(target_arch = "x86")]
         #[link_name = "kernel32"]
         #[abi = "stdcall"]
         extern "stdcall" {
-            fn FormatMessageA(flags: DWORD,
+            fn FormatMessageW(flags: DWORD,
                               lpSrc: LPVOID,
                               msgId: DWORD,
                               langId: DWORD,
-                              buf: LPSTR,
+                              buf: LPWSTR,
                               nsize: DWORD,
                               args: *c_void)
                               -> DWORD;
@@ -1155,11 +1135,11 @@ fn FormatMessageA(flags: DWORD,
         #[cfg(target_arch = "x86_64")]
         #[link_name = "kernel32"]
         extern {
-            fn FormatMessageA(flags: DWORD,
+            fn FormatMessageW(flags: DWORD,
                               lpSrc: LPVOID,
                               msgId: DWORD,
                               langId: DWORD,
-                              buf: LPSTR,
+                              buf: LPWSTR,
                               nsize: DWORD,
                               args: *c_void)
                               -> DWORD;
@@ -1173,11 +1153,11 @@ fn FormatMessageA(flags: DWORD,
         let langId = 0x0800 as DWORD;
         let err = errno() as DWORD;
 
-        let mut buf = [0 as c_char, ..TMPBUF_SZ];
+        let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
 
         unsafe {
             do buf.as_mut_buf |buf, len| {
-                let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+                let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
                                          FORMAT_MESSAGE_IGNORE_INSERTS,
                                          ptr::mut_null(),
                                          err,
@@ -1190,9 +1170,7 @@ fn FormatMessageA(flags: DWORD,
                 }
             }
 
-            do buf.as_imm_buf |buf, _len| {
-                str::raw::from_c_str(buf)
-            }
+            str::from_utf16(buf)
         }
     }
 
@@ -1482,7 +1460,7 @@ pub fn granularity() -> uint {
 
 #[cfg(unix)]
 impl Drop for MemoryMap {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment]; #[inline(never)];
 
         unsafe {
@@ -1608,7 +1586,7 @@ pub fn granularity() -> uint {
 
 #[cfg(windows)]
 impl Drop for MemoryMap {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment]; #[inline(never)];
 
         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
@@ -1669,7 +1647,7 @@ pub mod consts {
     pub use os::consts::arm::*;
 
     #[cfg(target_arch = "mips")]
-    use os::consts::mips::*;
+    pub use os::consts::mips::*;
 
     pub mod unix {
         pub static FAMILY: &'static str = "unix";
index 6e90e2a1070b59aea6aeb383f74262a666eb5ade..135acb106a17872227acfbd53cec62e3d4c93851 100644 (file)
 use cmp::Equiv;
 use iter::{range, Iterator};
 use option::{Option, Some, None};
-#[cfg(stage0)]
-use sys;
 use unstable::intrinsics;
 use util::swap;
 
 #[cfg(not(test))] use cmp::{Eq, Ord};
 
-/// Calculate the offset from a pointer. The count *must* be in bounds or
-/// otherwise the loads of this address are undefined.
-#[inline]
-#[cfg(stage0)]
-pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
-    (ptr as uint + (count as uint) * sys::size_of::<T>()) as *T
-}
-
-/// Calculate the offset from a mut pointer
-#[inline]
-#[cfg(stage0)]
-pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
-    (ptr as uint + (count as uint) * sys::size_of::<T>()) as *mut T
-}
-
 /// Calculate the offset from a pointer
 #[inline]
-#[cfg(not(stage0))]
 pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
     intrinsics::offset(ptr, count)
 }
@@ -48,7 +30,6 @@ pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
 /// Calculate the offset from a mut pointer. The count *must* be in bounds or
 /// otherwise the loads of this address are undefined.
 #[inline]
-#[cfg(not(stage0))]
 pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
     intrinsics::offset(ptr as *T, count) as *mut T
 }
@@ -383,17 +364,7 @@ unsafe fn offset(self, count: int) -> *mut T { mut_offset(self, count) }
 }
 
 // Equality for pointers
-#[cfg(stage0, not(test))]
-impl<T> Eq for *T {
-    #[inline]
-    fn eq(&self, other: &*T) -> bool {
-        (*self as uint) == (*other as uint)
-    }
-    #[inline]
-    fn ne(&self, other: &*T) -> bool { !self.eq(other) }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Eq for *T {
     #[inline]
     fn eq(&self, other: &*T) -> bool {
@@ -403,17 +374,7 @@ fn eq(&self, other: &*T) -> bool {
     fn ne(&self, other: &*T) -> bool { !self.eq(other) }
 }
 
-#[cfg(stage0, not(test))]
-impl<T> Eq for *mut T {
-    #[inline]
-    fn eq(&self, other: &*mut T) -> bool {
-        (*self as uint) == (*other as uint)
-    }
-    #[inline]
-    fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Eq for *mut T {
     #[inline]
     fn eq(&self, other: &*mut T) -> bool {
@@ -480,27 +441,7 @@ fn ne(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
 }
 
 // Comparison for pointers
-#[cfg(stage0, not(test))]
-impl<T> Ord for *T {
-    #[inline]
-    fn lt(&self, other: &*T) -> bool {
-        (*self as uint) < (*other as uint)
-    }
-    #[inline]
-    fn le(&self, other: &*T) -> bool {
-        (*self as uint) <= (*other as uint)
-    }
-    #[inline]
-    fn ge(&self, other: &*T) -> bool {
-        (*self as uint) >= (*other as uint)
-    }
-    #[inline]
-    fn gt(&self, other: &*T) -> bool {
-        (*self as uint) > (*other as uint)
-    }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Ord for *T {
     #[inline]
     fn lt(&self, other: &*T) -> bool {
@@ -520,27 +461,7 @@ fn gt(&self, other: &*T) -> bool {
     }
 }
 
-#[cfg(stage0, not(test))]
-impl<T> Ord for *mut T {
-    #[inline]
-    fn lt(&self, other: &*mut T) -> bool {
-        (*self as uint) < (*other as uint)
-    }
-    #[inline]
-    fn le(&self, other: &*mut T) -> bool {
-        (*self as uint) <= (*other as uint)
-    }
-    #[inline]
-    fn ge(&self, other: &*mut T) -> bool {
-        (*self as uint) >= (*other as uint)
-    }
-    #[inline]
-    fn gt(&self, other: &*mut T) -> bool {
-        (*self as uint) > (*other as uint)
-    }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 impl<T> Ord for *mut T {
     #[inline]
     fn lt(&self, other: &*mut T) -> bool {
index 1330096ee36a6f59fa475f0cb1a4ba57e0cc1b82..8ca247edb595823ef27d77805e315cbe2a8fe30b 100644 (file)
@@ -915,7 +915,7 @@ pub fn seed() -> ~[u8] {
 }
 
 // used to make space in TLS for a random number generator
-static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key;
+local_data_key!(tls_rng_state: @@mut IsaacRng)
 
 /**
  * Gives back a lazily initialized task-local random number generator,
diff --git a/src/libstd/reflect_stage0.rs b/src/libstd/reflect_stage0.rs
deleted file mode 100644 (file)
index 56e0f83..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-Runtime type reflection
-
-*/
-
-#[allow(missing_doc)];
-
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor};
-use libc::c_void;
-use sys;
-use unstable::raw;
-
-/**
- * Trait for visitor that wishes to reflect on data. To use this, create a
- * struct that encapsulates the set of pointers you wish to walk through a
- * data structure, and implement both `MovePtr` for it as well as `TyVisitor`;
- * then build a MovePtrAdaptor wrapped around your struct.
- */
-pub trait MovePtr {
-    fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void);
-    fn push_ptr(&self);
-    fn pop_ptr(&self);
-}
-
-/// Helper function for alignment calculation.
-#[inline]
-pub fn align(size: uint, align: uint) -> uint {
-    ((size + align) - 1u) & !(align - 1u)
-}
-
-/// Adaptor to wrap around visitors implementing MovePtr.
-pub struct MovePtrAdaptor<V> {
-    inner: V
-}
-pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> {
-    MovePtrAdaptor { inner: v }
-}
-
-impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> {
-    #[inline]
-    pub fn bump(&self, sz: uint) {
-        do self.inner.move_ptr() |p| {
-            ((p as uint) + sz) as *c_void
-        };
-    }
-
-    #[inline]
-    pub fn align(&self, a: uint) {
-        do self.inner.move_ptr() |p| {
-            align(p as uint, a) as *c_void
-        };
-    }
-
-    #[inline]
-    pub fn align_to<T>(&self) {
-        self.align(sys::min_align_of::<T>());
-    }
-
-    #[inline]
-    pub fn bump_past<T>(&self) {
-        self.bump(sys::size_of::<T>());
-    }
-}
-
-/// Abstract type-directed pointer-movement using the MovePtr trait
-impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
-    fn visit_bot(&self) -> bool {
-        self.align_to::<()>();
-        if ! self.inner.visit_bot() { return false; }
-        self.bump_past::<()>();
-        true
-    }
-
-    fn visit_nil(&self) -> bool {
-        self.align_to::<()>();
-        if ! self.inner.visit_nil() { return false; }
-        self.bump_past::<()>();
-        true
-    }
-
-    fn visit_bool(&self) -> bool {
-        self.align_to::<bool>();
-        if ! self.inner.visit_bool() { return false; }
-        self.bump_past::<bool>();
-        true
-    }
-
-    fn visit_int(&self) -> bool {
-        self.align_to::<int>();
-        if ! self.inner.visit_int() { return false; }
-        self.bump_past::<int>();
-        true
-    }
-
-    fn visit_i8(&self) -> bool {
-        self.align_to::<i8>();
-        if ! self.inner.visit_i8() { return false; }
-        self.bump_past::<i8>();
-        true
-    }
-
-    fn visit_i16(&self) -> bool {
-        self.align_to::<i16>();
-        if ! self.inner.visit_i16() { return false; }
-        self.bump_past::<i16>();
-        true
-    }
-
-    fn visit_i32(&self) -> bool {
-        self.align_to::<i32>();
-        if ! self.inner.visit_i32() { return false; }
-        self.bump_past::<i32>();
-        true
-    }
-
-    fn visit_i64(&self) -> bool {
-        self.align_to::<i64>();
-        if ! self.inner.visit_i64() { return false; }
-        self.bump_past::<i64>();
-        true
-    }
-
-    fn visit_uint(&self) -> bool {
-        self.align_to::<uint>();
-        if ! self.inner.visit_uint() { return false; }
-        self.bump_past::<uint>();
-        true
-    }
-
-    fn visit_u8(&self) -> bool {
-        self.align_to::<u8>();
-        if ! self.inner.visit_u8() { return false; }
-        self.bump_past::<u8>();
-        true
-    }
-
-    fn visit_u16(&self) -> bool {
-        self.align_to::<u16>();
-        if ! self.inner.visit_u16() { return false; }
-        self.bump_past::<u16>();
-        true
-    }
-
-    fn visit_u32(&self) -> bool {
-        self.align_to::<u32>();
-        if ! self.inner.visit_u32() { return false; }
-        self.bump_past::<u32>();
-        true
-    }
-
-    fn visit_u64(&self) -> bool {
-        self.align_to::<u64>();
-        if ! self.inner.visit_u64() { return false; }
-        self.bump_past::<u64>();
-        true
-    }
-
-    fn visit_float(&self) -> bool {
-        self.align_to::<float>();
-        if ! self.inner.visit_float() { return false; }
-        self.bump_past::<float>();
-        true
-    }
-
-    fn visit_f32(&self) -> bool {
-        self.align_to::<f32>();
-        if ! self.inner.visit_f32() { return false; }
-        self.bump_past::<f32>();
-        true
-    }
-
-    fn visit_f64(&self) -> bool {
-        self.align_to::<f64>();
-        if ! self.inner.visit_f64() { return false; }
-        self.bump_past::<f64>();
-        true
-    }
-
-    fn visit_char(&self) -> bool {
-        self.align_to::<char>();
-        if ! self.inner.visit_char() { return false; }
-        self.bump_past::<char>();
-        true
-    }
-
-    fn visit_estr_box(&self) -> bool {
-        self.align_to::<@str>();
-        if ! self.inner.visit_estr_box() { return false; }
-        self.bump_past::<@str>();
-        true
-    }
-
-    fn visit_estr_uniq(&self) -> bool {
-        self.align_to::<~str>();
-        if ! self.inner.visit_estr_uniq() { return false; }
-        self.bump_past::<~str>();
-        true
-    }
-
-    fn visit_estr_slice(&self) -> bool {
-        self.align_to::<&'static str>();
-        if ! self.inner.visit_estr_slice() { return false; }
-        self.bump_past::<&'static str>();
-        true
-    }
-
-    fn visit_estr_fixed(&self, n: uint,
-                        sz: uint,
-                        align: uint) -> bool {
-        self.align(align);
-        if ! self.inner.visit_estr_fixed(n, sz, align) { return false; }
-        self.bump(sz);
-        true
-    }
-
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<@u8>();
-        if ! self.inner.visit_box(mtbl, inner) { return false; }
-        self.bump_past::<@u8>();
-        true
-    }
-
-    fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~u8>();
-        if ! self.inner.visit_uniq(mtbl, inner) { return false; }
-        self.bump_past::<~u8>();
-        true
-    }
-
-    fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~u8>();
-        if ! self.inner.visit_uniq_managed(mtbl, inner) { return false; }
-        self.bump_past::<~u8>();
-        true
-    }
-
-    fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<*u8>();
-        if ! self.inner.visit_ptr(mtbl, inner) { return false; }
-        self.bump_past::<*u8>();
-        true
-    }
-
-    fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<&'static u8>();
-        if ! self.inner.visit_rptr(mtbl, inner) { return false; }
-        self.bump_past::<&'static u8>();
-        true
-    }
-
-    fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<raw::Vec<()>>();
-        if ! self.inner.visit_vec(mtbl, inner) { return false; }
-        true
-    }
-
-    fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~[u8]>();
-        if ! self.inner.visit_vec(mtbl, inner) { return false; }
-        self.bump_past::<~[u8]>();
-        true
-    }
-
-    fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<@[u8]>();
-        if ! self.inner.visit_evec_box(mtbl, inner) { return false; }
-        self.bump_past::<@[u8]>();
-        true
-    }
-
-    fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~[u8]>();
-        if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; }
-        self.bump_past::<~[u8]>();
-        true
-    }
-
-    fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<~[@u8]>();
-        if ! self.inner.visit_evec_uniq_managed(mtbl, inner) { return false; }
-        self.bump_past::<~[@u8]>();
-        true
-    }
-
-    fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.align_to::<&'static [u8]>();
-        if ! self.inner.visit_evec_slice(mtbl, inner) { return false; }
-        self.bump_past::<&'static [u8]>();
-        true
-    }
-
-    fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
-                        mtbl: uint, inner: *TyDesc) -> bool {
-        self.align(align);
-        if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) {
-            return false;
-        }
-        self.bump(sz);
-        true
-    }
-
-    fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_rec_field(&self, i: uint, name: &str,
-                       mtbl: uint, inner: *TyDesc) -> bool {
-        unsafe { self.align((*inner).align); }
-        if ! self.inner.visit_rec_field(i, name, mtbl, inner) {
-            return false;
-        }
-        unsafe { self.bump((*inner).size); }
-        true
-    }
-
-    fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint)
-                      -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_class(n_fields, sz, align) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_class_field(&self, i: uint, name: &str,
-                         mtbl: uint, inner: *TyDesc) -> bool {
-        unsafe { self.align((*inner).align); }
-        if ! self.inner.visit_class_field(i, name, mtbl, inner) {
-            return false;
-        }
-        unsafe { self.bump((*inner).size); }
-        true
-    }
-
-    fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
-                      -> bool {
-        if ! self.inner.visit_leave_class(n_fields, sz, align) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
-        unsafe { self.align((*inner).align); }
-        if ! self.inner.visit_tup_field(i, inner) { return false; }
-        unsafe { self.bump((*inner).size); }
-        true
-    }
-
-    fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
-        if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; }
-        true
-    }
-
-    fn visit_enter_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool {
-        if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) {
-            return false
-        }
-        true
-    }
-
-    fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool {
-        if ! self.inner.visit_fn_input(i, mode, inner) { return false; }
-        true
-    }
-
-    fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool {
-        if ! self.inner.visit_fn_output(retstyle, inner) { return false; }
-        true
-    }
-
-    fn visit_leave_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool {
-        if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enter_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint)
-                     -> bool {
-        self.align(align);
-        if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enter_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool {
-        if ! self.inner.visit_enter_enum_variant(variant, disr_val,
-                                                 n_fields, name) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
-        self.inner.push_ptr();
-        self.bump(offset);
-        if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
-        self.inner.pop_ptr();
-        true
-    }
-
-    fn visit_leave_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool {
-        if ! self.inner.visit_leave_enum_variant(variant, disr_val,
-                                                 n_fields, name) {
-            return false;
-        }
-        true
-    }
-
-    fn visit_leave_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint) -> bool {
-        if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) {
-            return false;
-        }
-        self.bump(sz);
-        true
-    }
-
-    fn visit_trait(&self) -> bool {
-        self.align_to::<@TyVisitor>();
-        if ! self.inner.visit_trait() { return false; }
-        self.bump_past::<@TyVisitor>();
-        true
-    }
-
-    fn visit_param(&self, i: uint) -> bool {
-        if ! self.inner.visit_param(i) { return false; }
-        true
-    }
-
-    fn visit_self(&self) -> bool {
-        self.align_to::<&'static u8>();
-        if ! self.inner.visit_self() { return false; }
-        self.align_to::<&'static u8>();
-        true
-    }
-
-    fn visit_type(&self) -> bool {
-        if ! self.inner.visit_type() { return false; }
-        true
-    }
-
-    fn visit_opaque_box(&self) -> bool {
-        self.align_to::<@u8>();
-        if ! self.inner.visit_opaque_box() { return false; }
-        self.bump_past::<@u8>();
-        true
-    }
-
-    fn visit_closure_ptr(&self, ck: uint) -> bool {
-        self.align_to::<@fn()>();
-        if ! self.inner.visit_closure_ptr(ck) { return false; }
-        self.bump_past::<@fn()>();
-        true
-    }
-}
diff --git a/src/libstd/repr_stage0.rs b/src/libstd/repr_stage0.rs
deleted file mode 100644 (file)
index cbce200..0000000
+++ /dev/null
@@ -1,626 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-More runtime type reflection
-
-*/
-
-#[allow(missing_doc)];
-
-use cast::transmute;
-use char;
-use container::Container;
-use io::{Writer, WriterUtil};
-use iter::Iterator;
-use libc::c_void;
-use option::{Some, None};
-use ptr;
-use reflect;
-use reflect::{MovePtr, align};
-use str::StrSlice;
-use to_str::ToStr;
-use vec::OwnedVector;
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
-use unstable::raw;
-
-#[cfg(test)] use io;
-
-/// Helpers
-
-trait EscapedCharWriter {
-    fn write_escaped_char(&self, ch: char);
-}
-
-impl EscapedCharWriter for @Writer {
-    fn write_escaped_char(&self, ch: char) {
-        match ch {
-            '\t' => self.write_str("\\t"),
-            '\r' => self.write_str("\\r"),
-            '\n' => self.write_str("\\n"),
-            '\\' => self.write_str("\\\\"),
-            '\'' => self.write_str("\\'"),
-            '"' => self.write_str("\\\""),
-            '\x20'..'\x7e' => self.write_char(ch),
-            _ => {
-                do char::escape_unicode(ch) |c| {
-                    self.write_char(c);
-                }
-            }
-        }
-    }
-}
-
-/// Representations
-
-trait Repr {
-    fn write_repr(&self, writer: @Writer);
-}
-
-impl Repr for () {
-    fn write_repr(&self, writer: @Writer) { writer.write_str("()"); }
-}
-
-impl Repr for bool {
-    fn write_repr(&self, writer: @Writer) {
-        writer.write_str(if *self { "true" } else { "false" })
-    }
-}
-
-macro_rules! int_repr(($ty:ident) => (impl Repr for $ty {
-    fn write_repr(&self, writer: @Writer) {
-        do ::$ty::to_str_bytes(*self, 10u) |bits| {
-            writer.write(bits);
-        }
-    }
-}))
-
-int_repr!(int)
-int_repr!(i8)
-int_repr!(i16)
-int_repr!(i32)
-int_repr!(i64)
-int_repr!(uint)
-int_repr!(u8)
-int_repr!(u16)
-int_repr!(u32)
-int_repr!(u64)
-
-macro_rules! num_repr(($ty:ident) => (impl Repr for $ty {
-    fn write_repr(&self, writer: @Writer) {
-        let s = self.to_str();
-        writer.write(s.as_bytes());
-    }
-}))
-
-num_repr!(float)
-num_repr!(f32)
-num_repr!(f64)
-
-// New implementation using reflect::MovePtr
-
-enum VariantState {
-    SearchingFor(int),
-    Matched,
-    AlreadyFound
-}
-
-pub struct ReprVisitor {
-    ptr: @mut *c_void,
-    ptr_stk: @mut ~[*c_void],
-    var_stk: @mut ~[VariantState],
-    writer: @Writer
-}
-pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
-    ReprVisitor {
-        ptr: @mut ptr,
-        ptr_stk: @mut ~[],
-        var_stk: @mut ~[],
-        writer: writer,
-    }
-}
-
-impl MovePtr for ReprVisitor {
-    #[inline]
-    fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
-        *self.ptr = adjustment(*self.ptr);
-    }
-    fn push_ptr(&self) {
-        self.ptr_stk.push(*self.ptr);
-    }
-    fn pop_ptr(&self) {
-        *self.ptr = self.ptr_stk.pop();
-    }
-}
-
-impl ReprVisitor {
-    // Various helpers for the TyVisitor impl
-
-    #[inline]
-    pub fn get<T>(&self, f: &fn(&T)) -> bool {
-        unsafe {
-            f(transmute::<*c_void,&T>(*self.ptr));
-        }
-        true
-    }
-
-    #[inline]
-    pub fn visit_inner(&self, inner: *TyDesc) -> bool {
-        self.visit_ptr_inner(*self.ptr, inner)
-    }
-
-    #[inline]
-    pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
-        unsafe {
-            let u = ReprVisitor(ptr, self.writer);
-            let v = reflect::MovePtrAdaptor(u);
-            visit_tydesc(inner, @v as @TyVisitor);
-            true
-        }
-    }
-
-    #[inline]
-    pub fn write<T:Repr>(&self) -> bool {
-        do self.get |v:&T| {
-            v.write_repr(self.writer);
-        }
-    }
-
-    pub fn write_escaped_slice(&self, slice: &str) {
-        self.writer.write_char('"');
-        for ch in slice.iter() {
-            self.writer.write_escaped_char(ch);
-        }
-        self.writer.write_char('"');
-    }
-
-    pub fn write_mut_qualifier(&self, mtbl: uint) {
-        if mtbl == 0 {
-            self.writer.write_str("mut ");
-        } else if mtbl == 1 {
-            // skip, this is ast::m_imm
-        } else {
-            assert_eq!(mtbl, 2);
-            self.writer.write_str("const ");
-        }
-    }
-
-    pub fn write_vec_range(&self,
-                           _mtbl: uint,
-                           ptr: *(),
-                           len: uint,
-                           inner: *TyDesc)
-                           -> bool {
-        let mut p = ptr as *u8;
-        let (sz, al) = unsafe { ((*inner).size, (*inner).align) };
-        self.writer.write_char('[');
-        let mut first = true;
-        let mut left = len;
-        // unit structs have 0 size, and don't loop forever.
-        let dec = if sz == 0 {1} else {sz};
-        while left > 0 {
-            if first {
-                first = false;
-            } else {
-                self.writer.write_str(", ");
-            }
-            self.visit_ptr_inner(p as *c_void, inner);
-            unsafe {
-                p = align(ptr::offset(p, sz as int) as uint, al) as *u8;
-            }
-            left -= dec;
-        }
-        self.writer.write_char(']');
-        true
-    }
-
-    pub fn write_unboxed_vec_repr(&self,
-                                  mtbl: uint,
-                                  v: &raw::Vec<()>,
-                                  inner: *TyDesc)
-                                  -> bool {
-        self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data),
-                             v.fill, inner)
-    }
-}
-
-impl TyVisitor for ReprVisitor {
-    fn visit_bot(&self) -> bool {
-        self.writer.write_str("!");
-        true
-    }
-    fn visit_nil(&self) -> bool { self.write::<()>() }
-    fn visit_bool(&self) -> bool { self.write::<bool>() }
-    fn visit_int(&self) -> bool { self.write::<int>() }
-    fn visit_i8(&self) -> bool { self.write::<i8>() }
-    fn visit_i16(&self) -> bool { self.write::<i16>() }
-    fn visit_i32(&self) -> bool { self.write::<i32>()  }
-    fn visit_i64(&self) -> bool { self.write::<i64>() }
-
-    fn visit_uint(&self) -> bool { self.write::<uint>() }
-    fn visit_u8(&self) -> bool { self.write::<u8>() }
-    fn visit_u16(&self) -> bool { self.write::<u16>() }
-    fn visit_u32(&self) -> bool { self.write::<u32>() }
-    fn visit_u64(&self) -> bool { self.write::<u64>() }
-
-    fn visit_float(&self) -> bool { self.write::<float>() }
-    fn visit_f32(&self) -> bool { self.write::<f32>() }
-    fn visit_f64(&self) -> bool { self.write::<f64>() }
-
-    fn visit_char(&self) -> bool {
-        do self.get::<char> |&ch| {
-            self.writer.write_char('\'');
-            self.writer.write_escaped_char(ch);
-            self.writer.write_char('\'');
-        }
-    }
-
-    fn visit_estr_box(&self) -> bool {
-        do self.get::<@str> |s| {
-            self.writer.write_char('@');
-            self.write_escaped_slice(*s);
-        }
-    }
-    fn visit_estr_uniq(&self) -> bool {
-        do self.get::<~str> |s| {
-            self.writer.write_char('~');
-            self.write_escaped_slice(*s);
-        }
-    }
-    fn visit_estr_slice(&self) -> bool {
-        do self.get::<&str> |s| {
-            self.write_escaped_slice(*s);
-        }
-    }
-
-    // Type no longer exists, vestigial function.
-    fn visit_estr_fixed(&self, _n: uint, _sz: uint,
-                        _align: uint) -> bool { fail!(); }
-
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('@');
-        self.write_mut_qualifier(mtbl);
-        do self.get::<&raw::Box<()>> |b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, inner);
-        }
-    }
-
-    fn visit_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('~');
-        do self.get::<*c_void> |b| {
-            self.visit_ptr_inner(*b, inner);
-        }
-    }
-
-    fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('~');
-        do self.get::<&raw::Box<()>> |b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, inner);
-        }
-    }
-
-    fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool {
-        do self.get::<*c_void> |p| {
-            self.writer.write_str(fmt!("(0x%x as *())",
-                                       *p as uint));
-        }
-    }
-
-    fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        self.writer.write_char('&');
-        self.write_mut_qualifier(mtbl);
-        do self.get::<*c_void> |p| {
-            self.visit_ptr_inner(*p, inner);
-        }
-    }
-
-    // Type no longer exists, vestigial function.
-    fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); }
-
-
-    fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<raw::Vec<()>> |b| {
-            self.write_unboxed_vec_repr(mtbl, b, inner);
-        }
-    }
-
-    fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<&raw::Box<raw::Vec<()>>> |b| {
-            self.writer.write_char('@');
-            self.write_mut_qualifier(mtbl);
-            self.write_unboxed_vec_repr(mtbl, &b.data, inner);
-        }
-    }
-
-    fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<&raw::Vec<()>> |b| {
-            self.writer.write_char('~');
-            self.write_unboxed_vec_repr(mtbl, *b, inner);
-        }
-    }
-
-    fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<&raw::Box<raw::Vec<()>>> |b| {
-            self.writer.write_char('~');
-            self.write_unboxed_vec_repr(mtbl, &b.data, inner);
-        }
-    }
-
-    fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<raw::Slice<()>> |s| {
-            self.writer.write_char('&');
-            self.write_vec_range(mtbl, s.data, s.len, inner);
-        }
-    }
-
-    fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint,
-                        mtbl: uint, inner: *TyDesc) -> bool {
-        do self.get::<()> |b| {
-            self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner);
-        }
-    }
-
-    fn visit_enter_rec(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('{');
-        true
-    }
-
-    fn visit_rec_field(&self, i: uint, name: &str,
-                       mtbl: uint, inner: *TyDesc) -> bool {
-        if i != 0 {
-            self.writer.write_str(", ");
-        }
-        self.write_mut_qualifier(mtbl);
-        self.writer.write_str(name);
-        self.writer.write_str(": ");
-        self.visit_inner(inner);
-        true
-    }
-
-    fn visit_leave_rec(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('}');
-        true
-    }
-
-    fn visit_enter_class(&self, _n_fields: uint,
-                         _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('{');
-        true
-    }
-    fn visit_class_field(&self, i: uint, name: &str,
-                         mtbl: uint, inner: *TyDesc) -> bool {
-        if i != 0 {
-            self.writer.write_str(", ");
-        }
-        self.write_mut_qualifier(mtbl);
-        self.writer.write_str(name);
-        self.writer.write_str(": ");
-        self.visit_inner(inner);
-        true
-    }
-    fn visit_leave_class(&self, _n_fields: uint,
-                         _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('}');
-        true
-    }
-
-    fn visit_enter_tup(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        self.writer.write_char('(');
-        true
-    }
-    fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
-        if i != 0 {
-            self.writer.write_str(", ");
-        }
-        self.visit_inner(inner);
-        true
-    }
-    fn visit_leave_tup(&self, _n_fields: uint,
-                       _sz: uint, _align: uint) -> bool {
-        if _n_fields == 1 {
-            self.writer.write_char(',');
-        }
-        self.writer.write_char(')');
-        true
-    }
-
-    fn visit_enter_enum(&self,
-                        _n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        _sz: uint,
-                        _align: uint) -> bool {
-        let var_stk: &mut ~[VariantState] = self.var_stk;
-        let disr = unsafe {
-            get_disr(transmute(*self.ptr))
-        };
-        var_stk.push(SearchingFor(disr));
-        true
-    }
-
-    fn visit_enter_enum_variant(&self, _variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool {
-        let mut write = false;
-        match self.var_stk.pop() {
-            SearchingFor(sought) => {
-                if disr_val == sought {
-                    self.var_stk.push(Matched);
-                    write = true;
-                } else {
-                    self.var_stk.push(SearchingFor(sought));
-                }
-            }
-            Matched | AlreadyFound => {
-                self.var_stk.push(AlreadyFound);
-            }
-        }
-
-        if write {
-            self.writer.write_str(name);
-            if n_fields > 0 {
-                self.writer.write_char('(');
-            }
-        }
-        true
-    }
-
-    fn visit_enum_variant_field(&self,
-                                i: uint,
-                                _offset: uint,
-                                inner: *TyDesc)
-                                -> bool {
-        match self.var_stk[self.var_stk.len() - 1] {
-            Matched => {
-                if i != 0 {
-                    self.writer.write_str(", ");
-                }
-                if ! self.visit_inner(inner) {
-                    return false;
-                }
-            }
-            _ => ()
-        }
-        true
-    }
-
-    fn visit_leave_enum_variant(&self, _variant: uint,
-                                _disr_val: int,
-                                n_fields: uint,
-                                _name: &str) -> bool {
-        match self.var_stk[self.var_stk.len() - 1] {
-            Matched => {
-                if n_fields > 0 {
-                    self.writer.write_char(')');
-                }
-            }
-            _ => ()
-        }
-        true
-    }
-
-    fn visit_leave_enum(&self,
-                        _n_variants: uint,
-                        _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        _sz: uint,
-                        _align: uint)
-                        -> bool {
-        let var_stk: &mut ~[VariantState] = self.var_stk;
-        match var_stk.pop() {
-            SearchingFor(*) => fail!("enum value matched no variant"),
-            _ => true
-        }
-    }
-
-    fn visit_enter_fn(&self, _purity: uint, _proto: uint,
-                      _n_inputs: uint, _retstyle: uint) -> bool { true }
-    fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
-        true
-    }
-    fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
-        true
-    }
-    fn visit_leave_fn(&self, _purity: uint, _proto: uint,
-                      _n_inputs: uint, _retstyle: uint) -> bool { true }
-
-
-    fn visit_trait(&self) -> bool { true }
-    fn visit_param(&self, _i: uint) -> bool { true }
-    fn visit_self(&self) -> bool { true }
-    fn visit_type(&self) -> bool { true }
-
-    fn visit_opaque_box(&self) -> bool {
-        self.writer.write_char('@');
-        do self.get::<&raw::Box<()>> |b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
-            self.visit_ptr_inner(p, b.type_desc);
-        }
-    }
-
-    fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
-}
-
-pub fn write_repr<T>(writer: @Writer, object: &T) {
-    unsafe {
-        let ptr = ptr::to_unsafe_ptr(object) as *c_void;
-        let tydesc = get_tydesc::<T>();
-        let u = ReprVisitor(ptr, writer);
-        let v = reflect::MovePtrAdaptor(u);
-        visit_tydesc(tydesc, @v as @TyVisitor)
-    }
-}
-
-#[cfg(test)]
-struct P {a: int, b: float}
-
-#[test]
-fn test_repr() {
-
-    fn exact_test<T>(t: &T, e:&str) {
-        let s : &str = io::with_str_writer(|w| write_repr(w, t));
-        if s != e {
-            error!("expected '%s', got '%s'",
-                   e, s);
-        }
-        assert_eq!(s, e);
-    }
-
-    exact_test(&10, "10");
-    exact_test(&true, "true");
-    exact_test(&false, "false");
-    exact_test(&1.234, "1.234");
-    exact_test(&(&"hello"), "\"hello\"");
-    exact_test(&(@"hello"), "@\"hello\"");
-    exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\"");
-
-    exact_test(&(@10), "@10");
-    exact_test(&(@mut 10), "@10"); // FIXME: #4210: incorrect
-    exact_test(&((@mut 10, 2)), "(@mut 10, 2)");
-    exact_test(&(~10), "~10");
-    exact_test(&(&10), "&10");
-    let mut x = 10;
-    exact_test(&(&mut x), "&mut 10");
-    exact_test(&(@mut [1, 2]), "@mut [1, 2]");
-
-    exact_test(&(1,), "(1,)");
-    exact_test(&(@[1,2,3,4,5,6,7,8]),
-               "@[1, 2, 3, 4, 5, 6, 7, 8]");
-    exact_test(&(@[1u8,2u8,3u8,4u8]),
-               "@[1, 2, 3, 4]");
-    exact_test(&(@["hi", "there"]),
-               "@[\"hi\", \"there\"]");
-    exact_test(&(~["hi", "there"]),
-               "~[\"hi\", \"there\"]");
-    exact_test(&(&["hi", "there"]),
-               "&[\"hi\", \"there\"]");
-    exact_test(&(P{a:10, b:1.234}),
-               "{a: 10, b: 1.234}");
-    exact_test(&(@P{a:10, b:1.234}),
-               "@{a: 10, b: 1.234}");
-    exact_test(&(~P{a:10, b:1.234}),
-               "~{a: 10, b: 1.234}");
-    exact_test(&(10_u8, ~"hello"),
-               "(10, ~\"hello\")");
-    exact_test(&(10_u16, ~"hello"),
-               "(10, ~\"hello\")");
-    exact_test(&(10_u32, ~"hello"),
-               "(10, ~\"hello\")");
-    exact_test(&(10_u64, ~"hello"),
-               "(10, ~\"hello\")");
-
-    struct Foo;
-    exact_test(&(~[Foo, Foo, Foo]), "~[{}, {}, {}]");
-}
index afa8d3261fc46ec32b08ebc6bb4a1ebb9078e4da..d8317c34f506b108f4eca35c2bb120b6de67d1b4 100644 (file)
@@ -117,18 +117,6 @@ unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> ~[~str] {
         }
     }
 
-    #[cfg(stage0)]
-    mod macro_hack {
-    #[macro_escape];
-    macro_rules! externfn(
-        (fn $name:ident () $(-> $ret_ty:ty),*) => (
-            extern {
-                fn $name() $(-> $ret_ty),*;
-            }
-        )
-    )
-    }
-
     externfn!(fn rust_take_global_args_lock())
     externfn!(fn rust_drop_global_args_lock())
     externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
index 4f5f26513b4c6fcf558cd52ab22bbac382a7f2d3..a8cd9bd66d7de36a0536324f6d91e75fcb2ec96b 100644 (file)
@@ -363,7 +363,7 @@ fn peek(&self) -> bool {
 
 #[unsafe_destructor]
 impl<T> Drop for ChanOne<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         if self.suppress_finalize { return }
 
         unsafe {
@@ -391,7 +391,7 @@ fn drop(&self) {
 
 #[unsafe_destructor]
 impl<T> Drop for PortOne<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         if self.suppress_finalize { return }
 
         unsafe {
index 579e581d87e0957cbed13f9204d85d6d3ecc0623..7988f640687bdd8d0f3272307a39e71b2b3f9950 100644 (file)
@@ -126,7 +126,7 @@ fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R {
 
 /// Wraps a Writer and buffers output to it
 ///
-/// NOTE: `BufferedWriter` will NOT flush its buffer when dropped.
+/// Note that `BufferedWriter` will NOT flush its buffer when dropped.
 pub struct BufferedWriter<W> {
     priv inner: W,
     priv buf: ~[u8],
@@ -204,7 +204,7 @@ fn eof(&mut self) -> bool {
 
 /// Wraps a Stream and buffers input and output to and from it
 ///
-/// NOTE: `BufferedStream` will NOT flush its output buffer when dropped.
+/// Note that `BufferedStream` will NOT flush its output buffer when dropped.
 // FIXME #9155 this should be a newtype struct
 pub struct BufferedStream<S> {
     priv inner: BufferedReader<InternalBufferedWriter<S>>
index e221f0ee94de72b10047cb1a686d59772358627b..1c48d6e7f1e1305ab569a57cb210554d2eb6d03b 100644 (file)
@@ -303,7 +303,7 @@ fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) {
             let start_len = buf.len();
             let mut total_read = 0;
 
-            buf.reserve_at_least(start_len + len);
+            buf.reserve_additional(len);
             vec::raw::set_len(buf, start_len + len);
 
             do (|| {
index 3bc0e74c7822a6565627396c29c9068dec7b0eda..a884961fd1e0de77d2155988ee3cdaabc19bbd1a 100644 (file)
@@ -8,17 +8,87 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*! Synchronous File I/O
+
+This module provides a set of functions and traits for working
+with regular files & directories on a filesystem.
+
+At the top-level of the module are a set of freestanding functions,
+associated with various filesystem operations. They all operate
+on a `PathLike` object.
+
+All operations in this module, including those as part of `FileStream` et al
+block the task during execution. Most will raise `std::rt::io::{io_error,read_error}`
+conditions in the event of failure.
+
+Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When
+`use`'d alongside a value whose type implements them (A `std::path::Path` impl is
+a part of this module), they expose a set of functions for operations against
+a given file location, depending on whether the path already exists. Whenever
+possible, the `{FileInfo, DirectoryInfo}` preserve the same semantics as their
+free function counterparts.
+*/
+
 use prelude::*;
 use super::support::PathLike;
 use super::{Reader, Writer, Seek};
-use super::{SeekSet, SeekCur, SeekEnd, SeekStyle};
+use super::{SeekStyle,SeekSet, SeekCur, SeekEnd,
+            Open, Read, Write, Create, ReadWrite};
 use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject};
 use rt::io::{io_error, read_error, EndOfFile,
-             FileMode, FileAccess, Open, Read, Create, ReadWrite};
+            FileMode, FileAccess, FileStat, IoError,
+            PathAlreadyExists, PathDoesntExist,
+            MismatchedFileTypeForOperation, ignore_io_error};
 use rt::local::Local;
-use rt::test::*;
+use option::{Some, None};
+use path::Path;
+use super::super::test::*;
 
 /// Open a file for reading/writing, as indicated by `path`.
+///
+/// # Example
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::support::PathLike;
+///     use std::rt::io::file::open;
+///     use std::rt::io::{FileMode, FileAccess};
+///
+///     let p = &Path("/some/file/path.txt");
+///
+///     do io_error::cond.trap(|_| {
+///         // hoo-boy...
+///     }).inside {
+///         let stream = match open(p, Create, ReadWrite) {
+///             Some(s) => s,
+///             None => fail!("whoops! I'm sure this raised, anyways..");
+///         }
+///         // do some stuff with that stream
+///
+///         // the file stream will be closed at the end of this block
+///     }
+///     // ..
+///
+/// `FileMode` and `FileAccess` provide information about the permissions
+/// context in which a given stream is created. More information about them
+/// can be found in `std::rt::io`'s docs.
+///
+/// Note that, with this function, a `FileStream` is returned regardless of
+/// the access-limitations indicated by `FileAccess` (e.g. calling `write` on a
+/// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at runtime). If you
+/// desire a more-correctly-constrained interface to files, use the
+/// `{open_stream, open_reader, open_writer}` methods that are a part of `FileInfo`
+///
+/// # Errors
+///
+/// This function will raise an `io_error` condition under a number of different circumstances,
+/// to include but not limited to:
+///
+/// * Opening a file that already exists with `FileMode` of `Create` or vice versa (e.g.
+///   opening a non-existant file with `FileMode` or `Open`)
+/// * Attempting to open a file with a `FileAccess` that the user lacks permissions
+///   for
+/// * Filesystem-level errors (full disk, etc)
 pub fn open<P: PathLike>(path: &P,
                          mode: FileMode,
                          access: FileAccess
@@ -39,8 +109,28 @@ pub fn open<P: PathLike>(path: &P,
     }
 }
 
-/// Unlink (remove) a file from the filesystem, as indicated
-/// by `path`.
+/// Unlink a file from the underlying filesystem.
+///
+/// # Example
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::support::PathLike;
+///     use std::rt::io::file::unlink;
+///
+///     let p = &Path("/some/file/path.txt");
+///     unlink(p);
+///     // if we made it here without failing, then the
+///     // unlink operation was successful
+///
+/// Note that, just because an unlink call was successful, it is not
+/// guaranteed that a file is immediately deleted (e.g. depending on
+/// platform, other open file descriptors may prevent immediate removal)
+///
+/// # Errors
+///
+/// This function will raise an `io_error` condition if the user lacks permissions to
+/// remove the file or if some other filesystem-level error occurs
 pub fn unlink<P: PathLike>(path: &P) {
     let unlink_result = unsafe {
         let io: *mut IoFactoryObject = Local::unsafe_borrow();
@@ -54,26 +144,231 @@ pub fn unlink<P: PathLike>(path: &P) {
     }
 }
 
-/// Abstraction representing *positional* access to a file. In this case,
-/// *positional* refers to it keeping an encounter *cursor* of where in the
-/// file a subsequent `read` or `write` will begin from. Users of a `FileStream`
-/// can `seek` to move the cursor to a given location *within the bounds of the
-/// file* and can ask to have the `FileStream` `tell` them the location, in
-/// bytes, of the cursor.
+/// Create a new, empty directory at the provided path
+///
+/// # Example
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::support::PathLike;
+///     use std::rt::io::file::mkdir;
+///
+///     let p = &Path("/some/dir");
+///     mkdir(p);
+///     // If we got here, our directory exists! Horray!
+///
+/// # Errors
+///
+/// This call will raise an `io_error` condition if the user lacks permissions to make a
+/// new directory at the provided path, or if the directory already exists
+pub fn mkdir<P: PathLike>(path: &P) {
+    let mkdir_result = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).fs_mkdir(path)
+    };
+    match mkdir_result {
+        Ok(_) => (),
+        Err(ioerr) => {
+            io_error::cond.raise(ioerr);
+        }
+    }
+}
+
+/// Remove an existing, empty directory
+///
+/// # Example
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::support::PathLike;
+///     use std::rt::io::file::rmdir;
+///
+///     let p = &Path("/some/dir");
+///     rmdir(p);
+///     // good riddance, you mean ol' directory
+///
+/// # Errors
+///
+/// This call will raise an `io_error` condition if the user lacks permissions to remove the
+/// directory at the provided path, or if the directory isn't empty
+pub fn rmdir<P: PathLike>(path: &P) {
+    let rmdir_result = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).fs_rmdir(path)
+    };
+    match rmdir_result {
+        Ok(_) => (),
+        Err(ioerr) => {
+            io_error::cond.raise(ioerr);
+        }
+    }
+}
+
+/// Get information on the file, directory, etc at the provided path
+///
+/// Given a `rt::io::support::PathLike`, query the file system to get
+/// information about a file, directory, etc.
+///
+/// Returns a `Some(std::rt::io::PathInfo)` on success
+///
+/// # Example
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::support::PathLike;
+///     use std::rt::io::file::stat;
+///
+///     let p = &Path("/some/file/path.txt");
+///
+///     do io_error::cond.trap(|_| {
+///         // hoo-boy...
+///     }).inside {
+///         let info = match stat(p) {
+///             Some(s) => s,
+///             None => fail!("whoops! I'm sure this raised, anyways..");
+///         }
+///         if stat.is_file {
+///             // just imagine the possibilities ...
+///         }
+///
+///         // the file stream will be closed at the end of this block
+///     }
+///     // ..
+///
+/// # Errors
+///
+/// This call will raise an `io_error` condition if the user lacks the requisite
+/// permissions to perform a `stat` call on the given path or if there is no
+/// entry in the filesystem at the provided path.
+pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
+    let open_result = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).fs_stat(path)
+    };
+    match open_result {
+        Ok(p) => {
+            Some(p)
+        },
+        Err(ioerr) => {
+            io_error::cond.raise(ioerr);
+            None
+        }
+    }
+}
+
+/// Retrieve a vector containing all entries within a provided directory
+///
+/// # Example
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::support::PathLike;
+///     use std::rt::io::file::readdir;
+///
+///     fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
+///         if dir.is_dir() {
+///             let contents = dir.readdir();
+///             for entry in contents.iter() {
+///                 if entry.is_dir() { visit_dirs(entry, cb); }
+///                 else { cb(entry); }
+///             }
+///         }
+///         else { fail!("nope"); }
+///     }
+///
+/// # Errors
+///
+/// Will raise an `io_error` condition if the provided `path` doesn't exist,
+/// the process lacks permissions to view the contents or if the `path` points
+/// at a non-directory file
+pub fn readdir<P: PathLike>(path: &P) -> Option<~[Path]> {
+    let readdir_result = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).fs_readdir(path, 0)
+    };
+    match readdir_result {
+        Ok(p) => {
+            Some(p)
+        },
+        Err(ioerr) => {
+            io_error::cond.raise(ioerr);
+            None
+        }
+    }
+}
+
+/// Constrained version of `FileStream` that only exposes read-specific operations.
 ///
-/// This abstraction is roughly modeled on the access workflow as represented
-/// by `open(2)`, `read(2)`, `write(2)` and friends.
+/// Can be retreived via `FileInfo.open_reader()`.
+pub struct FileReader { priv stream: FileStream }
+
+/// a `std::rt::io::Reader` trait impl for file I/O.
+impl Reader for FileReader {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        self.stream.read(buf)
+    }
+
+    fn eof(&mut self) -> bool {
+        self.stream.eof()
+    }
+}
+
+/// a `std::rt::io::Seek` trait impl for file I/O.
+impl Seek for FileReader {
+    fn tell(&self) -> u64 {
+        self.stream.tell()
+    }
+
+    fn seek(&mut self, pos: i64, style: SeekStyle) {
+        self.stream.seek(pos, style);
+    }
+}
+
+/// Constrained version of `FileStream` that only exposes write-specific operations.
 ///
-/// The `open` and `unlink` static methods are provided to manage creation/removal
-/// of files. All other methods operatin on an instance of `FileStream`.
+/// Can be retreived via `FileInfo.open_writer()`.
+pub struct FileWriter { priv stream: FileStream }
+
+/// a `std::rt::io::Writer` trait impl for file I/O.
+impl Writer for FileWriter {
+    fn write(&mut self, buf: &[u8]) {
+        self.stream.write(buf);
+    }
+
+    fn flush(&mut self) {
+        self.stream.flush();
+    }
+}
+
+/// a `std::rt::io::Seek` trait impl for file I/O.
+impl Seek for FileWriter {
+    fn tell(&self) -> u64 {
+        self.stream.tell()
+    }
+
+    fn seek(&mut self, pos: i64, style: SeekStyle) {
+        self.stream.seek(pos, style);
+    }
+}
+
+/// Unconstrained file access type that exposes read and write operations
+///
+/// Can be retreived via `file::open()` and `FileInfo.open_stream()`.
+///
+/// # Errors
+///
+/// This type will raise an io_error condition if operations are attempted against
+/// it for which its underlying file descriptor was not configured at creation
+/// time, via the `FileAccess` parameter to `file::open()`.
+///
+/// For this reason, it is best to use the access-constrained wrappers that are
+/// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`.
 pub struct FileStream {
     fd: ~RtioFileStream,
     last_nread: int,
 }
 
-impl FileStream {
-}
-
+/// a `std::rt::io::Reader` trait impl for file I/O.
 impl Reader for FileStream {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
         match self.fd.read(buf) {
@@ -99,6 +394,7 @@ fn eof(&mut self) -> bool {
     }
 }
 
+/// a `std::rt::io::Writer` trait impl for file I/O.
 impl Writer for FileStream {
     fn write(&mut self, buf: &[u8]) {
         match self.fd.write(buf) {
@@ -119,6 +415,7 @@ fn flush(&mut self) {
     }
 }
 
+/// a `std::rt::io:Seek` trait impl for file I/O.
 impl Seek for FileStream {
     fn tell(&self) -> u64 {
         let res = self.fd.tell();
@@ -145,6 +442,242 @@ fn seek(&mut self, pos: i64, style: SeekStyle) {
     }
 }
 
+/// Shared functionality between `FileInfo` and `DirectoryInfo`
+pub trait FileSystemInfo {
+    /// Get the filesystem path that this instance points at,
+    /// whether it is valid or not. In this way, it can be used to
+    /// to specify a path of a non-existent file which it
+    /// later creates
+    fn get_path<'a>(&'a self) -> &'a Path;
+
+    /// Get information on the file, directory, etc at the provided path
+    ///
+    /// Consult the `file::stat` documentation for more info.
+    ///
+    /// This call preserves identical runtime/error semantics with `file::stat`
+    fn stat(&self) -> Option<FileStat> {
+        stat(self.get_path())
+    }
+
+    /// Boolean value indicator whether the underlying file exists on the filesystem
+    ///
+    /// # Errors
+    ///
+    /// Will not raise a condition
+    fn exists(&self) -> bool {
+        match ignore_io_error(|| self.stat()) {
+            Some(_) => true,
+            None => false
+        }
+    }
+
+}
+
+/// Represents a file, whose underlying path may or may not be valid
+///
+/// # Example
+///
+/// * Check if a file exists, reading from it if so
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::file::{FileInfo, FileReader};
+///
+///     let f = &Path("/some/file/path.txt");
+///     if f.exists() {
+///         let reader = f.open_reader(Open);
+///         let mut mem = [0u8, 8*64000];
+///         reader.read(mem);
+///         // ...
+///     }
+///
+/// * Is the given path a file?
+///
+///    let f = get_file_path_from_wherever();
+///    match f.is_file() {
+///        true => doing_something_with_a_file(f),
+///        _ => {}
+///    }
+pub trait FileInfo : FileSystemInfo {
+    /// Whether the underlying implemention (be it a file path,
+    /// or something else) points at a "regular file" on the FS. Will return
+    /// false for paths to non-existent locations or directories or
+    /// other non-regular files (named pipes, etc).
+    ///
+    /// # Errors
+    ///
+    /// Will not raise a condition
+    fn is_file(&self) -> bool {
+        match ignore_io_error(|| self.stat()) {
+            Some(s) => s.is_file,
+            None => false
+        }
+    }
+
+    /// Attempts to open a regular file for reading/writing based
+    /// on provided inputs
+    ///
+    /// See `file::open` for more information on runtime semantics and error conditions
+    fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option<FileStream> {
+        match ignore_io_error(|| self.stat()) {
+            Some(s) => match s.is_file {
+                true => open(self.get_path(), mode, access),
+                false => None
+            },
+            None => open(self.get_path(), mode, access)
+        }
+    }
+
+    /// Attempts to open a regular file in read-only mode, based
+    /// on provided inputs
+    ///
+    /// See `file::open` for more information on runtime semantics and error conditions
+    fn open_reader(&self, mode: FileMode) -> Option<FileReader> {
+        match self.open_stream(mode, Read) {
+            Some(s) => Some(FileReader { stream: s}),
+            None => None
+        }
+    }
+
+    /// Attempts to open a regular file in write-only mode, based
+    /// on provided inputs
+    ///
+    /// See `file::open` for more information on runtime semantics and error conditions
+    fn open_writer(&self, mode: FileMode) -> Option<FileWriter> {
+        match self.open_stream(mode, Write) {
+            Some(s) => Some(FileWriter { stream: s}),
+            None => None
+        }
+    }
+
+    /// Attempt to remove a file from the filesystem
+    ///
+    /// See `file::unlink` for more information on runtime semantics and error conditions
+    fn unlink(&self) {
+        unlink(self.get_path());
+    }
+}
+
+/// `FileSystemInfo` implementation for `Path`s
+impl FileSystemInfo for Path {
+    fn get_path<'a>(&'a self) -> &'a Path { self }
+}
+
+/// `FileInfo` implementation for `Path`s
+impl FileInfo for Path { }
+
+/// Represents a directory, whose underlying path may or may not be valid
+///
+/// # Example
+///
+/// * Check if a directory exists, `mkdir`'ing it if not
+///
+///     use std;
+///     use std::path::Path;
+///     use std::rt::io::file::{DirectoryInfo};
+///
+///     let dir = &Path("/some/dir");
+///     if !dir.exists() {
+///         dir.mkdir();
+///     }
+///
+/// * Is the given path a directory? If so, iterate on its contents
+///
+///     fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
+///         if dir.is_dir() {
+///             let contents = dir.readdir();
+///             for entry in contents.iter() {
+///                 if entry.is_dir() { visit_dirs(entry, cb); }
+///                 else { cb(entry); }
+///             }
+///         }
+///         else { fail!("nope"); }
+///     }
+trait DirectoryInfo : FileSystemInfo {
+    /// Whether the underlying implemention (be it a file path,
+    /// or something else) is pointing at a directory in the underlying FS.
+    /// Will return false for paths to non-existent locations or if the item is
+    /// not a directory (eg files, named pipes, links, etc)
+    ///
+    /// # Errors
+    ///
+    /// Will not raise a condition
+    fn is_dir(&self) -> bool {
+        match ignore_io_error(|| self.stat()) {
+            Some(s) => s.is_dir,
+            None => false
+        }
+    }
+
+    /// Create a directory at the location pointed to by the
+    /// type underlying the given `DirectoryInfo`.
+    ///
+    /// # Errors
+    ///
+    /// This method will raise a `PathAlreadyExists` kind of `io_error` condition
+    /// if the provided path exists
+    ///
+    /// See `file::mkdir` for more information on runtime semantics and error conditions
+    fn mkdir(&self) {
+        match ignore_io_error(|| self.stat()) {
+            Some(_) => {
+                io_error::cond.raise(IoError {
+                    kind: PathAlreadyExists,
+                    desc: "Path already exists",
+                    detail:
+                        Some(fmt!("%s already exists; can't mkdir it", self.get_path().to_str()))
+                })
+            },
+            None => mkdir(self.get_path())
+        }
+    }
+
+    /// Remove a directory at the given location.
+    ///
+    /// # Errors
+    ///
+    /// This method will raise a `PathDoesntExist` kind of `io_error` condition
+    /// if the provided path exists. It will raise a `MismatchedFileTypeForOperation`
+    /// kind of `io_error` condition if the provided path points at any
+    /// non-directory file type
+    ///
+    /// See `file::rmdir` for more information on runtime semantics and error conditions
+    fn rmdir(&self) {
+        match ignore_io_error(|| self.stat()) {
+            Some(s) => {
+                match s.is_dir {
+                    true => rmdir(self.get_path()),
+                    false => {
+                        let ioerr = IoError {
+                            kind: MismatchedFileTypeForOperation,
+                            desc: "Cannot do rmdir() on a non-directory",
+                            detail: Some(fmt!(
+                                "%s is a non-directory; can't rmdir it",
+                                self.get_path().to_str()))
+                        };
+                        io_error::cond.raise(ioerr);
+                    }
+                }
+            },
+            None =>
+                io_error::cond.raise(IoError {
+                    kind: PathDoesntExist,
+                    desc: "Path doesn't exist",
+                    detail: Some(fmt!("%s doesn't exist; can't rmdir it", self.get_path().to_str()))
+                })
+        }
+    }
+
+    // Get a collection of all entries at the given
+    // directory
+    fn readdir(&self) -> Option<~[Path]> {
+        readdir(self.get_path())
+    }
+}
+
+/// `DirectoryInfo` impl for `path::Path`
+impl DirectoryInfo for Path { }
+
 fn file_test_smoke_test_impl() {
     do run_in_mt_newsched_task {
         let message = "it's alright. have a good time";
@@ -168,7 +701,6 @@ fn file_test_smoke_test_impl() {
 }
 
 #[test]
-#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_smoke_test() {
     file_test_smoke_test_impl();
 }
@@ -236,7 +768,6 @@ 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();
 }
@@ -268,14 +799,13 @@ fn file_test_io_seeking_impl() {
         assert!(tell_pos_post_read == message.len() as u64);
     }
 }
+
 #[test]
-#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_seek_and_tell_smoke_test() {
     file_test_io_seeking_impl();
 }
 
 fn file_test_io_seek_and_write_impl() {
-    use io;
     do run_in_mt_newsched_task {
         use str;
         let initial_msg =   "food-is-yummy";
@@ -296,12 +826,11 @@ fn file_test_io_seek_and_write_impl() {
         }
         unlink(filename);
         let read_str = str::from_utf8(read_mem);
-        io::println(fmt!("read_str: '%?' final_msg: '%?'", read_str, final_msg));
         assert!(read_str == final_msg.to_owned());
     }
 }
+
 #[test]
-#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_seek_and_write() {
     file_test_io_seek_and_write_impl();
 }
@@ -340,8 +869,116 @@ fn file_test_io_seek_shakedown_impl() {
         unlink(filename);
     }
 }
+
 #[test]
-#[ignore(cfg(windows))] // FIXME #8810
 fn file_test_io_seek_shakedown() {
     file_test_io_seek_shakedown_impl();
 }
+
+#[test]
+fn file_test_stat_is_correct_on_is_file() {
+    do run_in_mt_newsched_task {
+        let filename = &Path("./tmp/file_stat_correct_on_is_file.txt");
+        {
+            let mut fs = open(filename, Create, ReadWrite).unwrap();
+            let msg = "hw";
+            fs.write(msg.as_bytes());
+        }
+        let stat_res = match stat(filename) {
+            Some(s) => s,
+            None => fail!("shouldn't happen")
+        };
+        assert!(stat_res.is_file);
+        unlink(filename);
+    }
+}
+
+#[test]
+fn file_test_stat_is_correct_on_is_dir() {
+    do run_in_mt_newsched_task {
+        let filename = &Path("./tmp/file_stat_correct_on_is_dir");
+        mkdir(filename);
+        let stat_res = match stat(filename) {
+            Some(s) => s,
+            None => fail!("shouldn't happen")
+        };
+        assert!(stat_res.is_dir);
+        rmdir(filename);
+    }
+}
+
+#[test]
+fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+    do run_in_mt_newsched_task {
+        let dir = &Path("./tmp/fileinfo_false_on_dir");
+        mkdir(dir);
+        assert!(dir.is_file() == false);
+        rmdir(dir);
+    }
+}
+
+#[test]
+fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+    do run_in_mt_newsched_task {
+        let file = &Path("./tmp/fileinfo_check_exists_b_and_a.txt");
+        {
+            let msg = "foo".as_bytes();
+            let mut w = file.open_writer(Create);
+            w.write(msg);
+        }
+        assert!(file.exists());
+        file.unlink();
+        assert!(!file.exists());
+    }
+}
+
+#[test]
+fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+    do run_in_mt_newsched_task {
+        let dir = &Path("./tmp/before_and_after_dir");
+        assert!(!dir.exists());
+        dir.mkdir();
+        assert!(dir.exists());
+        assert!(dir.is_dir());
+        dir.rmdir();
+        assert!(!dir.exists());
+    }
+}
+
+#[test]
+fn file_test_directoryinfo_readdir() {
+    use str;
+    do run_in_mt_newsched_task {
+        let dir = &Path("./tmp/di_readdir");
+        dir.mkdir();
+        let prefix = "foo";
+        for n in range(0,3) {
+            let f = dir.push(fmt!("%d.txt", n));
+            let mut w = f.open_writer(Create);
+            let msg_str = (prefix + n.to_str().to_owned()).to_owned();
+            let msg = msg_str.as_bytes();
+            w.write(msg);
+        }
+        match dir.readdir() {
+            Some(files) => {
+                let mut mem = [0u8, .. 4];
+                for f in files.iter() {
+                    {
+                        let n = f.filestem();
+                        let mut r = f.open_reader(Open);
+                        r.read(mem);
+                        let read_str = str::from_utf8(mem);
+                        let expected = match n {
+                            Some(n) => prefix+n,
+                            None => fail!("really shouldn't happen..")
+                        };
+                        assert!(expected == read_str);
+                    }
+                    f.unlink();
+                }
+            },
+            None => fail!("shouldn't happen")
+        }
+        dir.rmdir();
+    }
+}
\ No newline at end of file
index 59ca5d5775980db4843f58e45f6e377c13be9cc4..6b405b0948a0fba6a5a523078bd591f5c6686e02 100644 (file)
 use prelude::*;
 use to_str::ToStr;
 use str::{StrSlice, OwnedStr};
+use path::Path;
 
 // Reexports
 pub use self::stdio::stdin;
 pub use self::net::tcp::TcpListener;
 pub use self::net::tcp::TcpStream;
 pub use self::net::udp::UdpStream;
+pub use self::pipe::PipeStream;
+pub use self::pipe::UnboundPipeStream;
+pub use self::process::Process;
 
 // Some extension traits that all Readers and Writers get.
 pub use self::extensions::ReaderUtil;
 /// Synchronous, non-blocking file I/O.
 pub mod file;
 
+/// Synchronous, in-memory I/O.
+pub mod pipe;
+
+/// Child process management.
+pub mod process;
+
 /// Synchronous, non-blocking network I/O.
 pub mod net;
 
@@ -357,7 +367,10 @@ pub enum IoErrorKind {
     Closed,
     ConnectionRefused,
     ConnectionReset,
-    BrokenPipe
+    BrokenPipe,
+    PathAlreadyExists,
+    PathDoesntExist,
+    MismatchedFileTypeForOperation
 }
 
 // FIXME: #8242 implementing manually because deriving doesn't work for some reason
@@ -373,7 +386,10 @@ fn to_str(&self) -> ~str {
             Closed => ~"Closed",
             ConnectionRefused => ~"ConnectionRefused",
             ConnectionReset => ~"ConnectionReset",
-            BrokenPipe => ~"BrokenPipe"
+            BrokenPipe => ~"BrokenPipe",
+            PathAlreadyExists => ~"PathAlreadyExists",
+            PathDoesntExist => ~"PathDoesntExist",
+            MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation"
         }
     }
 }
@@ -381,17 +397,25 @@ fn to_str(&self) -> ~str {
 // XXX: Can't put doc comments on macros
 // Raised by `I/O` operations on error.
 condition! {
-    // NOTE: this super::IoError should be IoError
-    // Change this next time the snapshot is updated.
-    pub io_error: super::IoError -> ();
+    pub io_error: IoError -> ();
 }
 
 // XXX: Can't put doc comments on macros
 // Raised by `read` on error
 condition! {
-    // NOTE: this super::IoError should be IoError
-    // Change this next time the snapshot it updated.
-    pub read_error: super::IoError -> ();
+    pub read_error: IoError -> ();
+}
+
+/// Helper for wrapper calls where you want to
+/// ignore any io_errors that might be raised
+pub fn ignore_io_error<T>(cb: &fn() -> T) -> T {
+    do io_error::cond.trap(|_| {
+        // just swallow the error.. downstream users
+        // who can make a decision based on a None result
+        // won't care
+    }).inside {
+        cb()
+    }
 }
 
 pub trait Reader {
@@ -596,3 +620,22 @@ pub enum FileAccess {
     Write,
     ReadWrite
 }
+
+pub struct FileStat {
+    /// A `Path` object containing information about the `PathInfo`'s location
+    path: Path,
+    /// `true` if the file pointed at by the `PathInfo` is a regular file
+    is_file: bool,
+    /// `true` if the file pointed at by the `PathInfo` is a directory
+    is_dir: bool,
+    /// The file pointed at by the `PathInfo`'s size in bytes
+    size: u64,
+    /// The file pointed at by the `PathInfo`'s creation time
+    created: u64,
+    /// The file pointed at by the `PathInfo`'s last-modification time in
+    /// platform-dependent msecs
+    modified: u64,
+    /// The file pointed at by the `PathInfo`'s last-accessd time (e.g. read) in
+    /// platform-dependent msecs
+    accessed: u64,
+}
index be8a051a0664d94165479a007d31cb1b95cdc19b..55abc4ab135860f9447b7b94bed40e7ef4818bf9 100644 (file)
@@ -178,12 +178,17 @@ fn bind_error() {
     }
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME #8811
     fn connect_error() {
         do run_in_mt_newsched_task {
             let mut called = false;
             do io_error::cond.trap(|e| {
-                assert_eq!(e.kind, ConnectionRefused);
+                let expected_error = if cfg!(unix) {
+                    ConnectionRefused
+                } else {
+                    // On Win32, opening port 1 gives WSAEADDRNOTAVAIL error.
+                    OtherIoError
+                };
+                assert_eq!(e.kind, expected_error);
                 called = true;
             }).inside {
                 let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs
new file mode 100644 (file)
index 0000000..7e6c59f
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Synchronous, in-memory pipes.
+//!
+//! Currently these aren't particularly useful, there only exists bindings
+//! enough so that pipes can be created to child processes.
+
+use prelude::*;
+use super::{Reader, Writer};
+use rt::io::{io_error, read_error, EndOfFile};
+use rt::local::Local;
+use rt::rtio::{RtioPipe, RtioPipeObject, IoFactoryObject, IoFactory};
+use rt::rtio::RtioUnboundPipeObject;
+
+pub struct PipeStream(RtioPipeObject);
+pub struct UnboundPipeStream(~RtioUnboundPipeObject);
+
+impl PipeStream {
+    /// Creates a new pipe initialized, but not bound to any particular
+    /// source/destination
+    pub fn new() -> Option<UnboundPipeStream> {
+        let pipe = unsafe {
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
+            (*io).pipe_init(false)
+        };
+        match pipe {
+            Ok(p) => Some(UnboundPipeStream(p)),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+
+    pub fn bind(inner: RtioPipeObject) -> PipeStream {
+        PipeStream(inner)
+    }
+}
+
+impl Reader for PipeStream {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        match (**self).read(buf) {
+            Ok(read) => Some(read),
+            Err(ioerr) => {
+                // EOF is indicated by returning None
+                if ioerr.kind != EndOfFile {
+                    read_error::cond.raise(ioerr);
+                }
+                return None;
+            }
+        }
+    }
+
+    fn eof(&mut self) -> bool { fail!() }
+}
+
+impl Writer for PipeStream {
+    fn write(&mut self, buf: &[u8]) {
+        match (**self).write(buf) {
+            Ok(_) => (),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+            }
+        }
+    }
+
+    fn flush(&mut self) { fail!() }
+}
diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs
new file mode 100644 (file)
index 0000000..e92b0d3
--- /dev/null
@@ -0,0 +1,278 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Bindings for executing child processes
+
+use prelude::*;
+
+use libc;
+use rt::io;
+use rt::io::io_error;
+use rt::local::Local;
+use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};
+
+pub struct Process {
+    priv handle: ~RtioProcessObject,
+    io: ~[Option<io::PipeStream>],
+}
+
+/// This configuration describes how a new process should be spawned. This is
+/// translated to libuv's own configuration
+pub struct ProcessConfig<'self> {
+    /// Path to the program to run
+    program: &'self str,
+
+    /// Arguments to pass to the program (doesn't include the program itself)
+    args: &'self [~str],
+
+    /// Optional environment to specify for the program. If this is None, then
+    /// it will inherit the current process's environment.
+    env: Option<&'self [(~str, ~str)]>,
+
+    /// Optional working directory for the new process. If this is None, then
+    /// the current directory of the running process is inherited.
+    cwd: Option<&'self str>,
+
+    /// Any number of streams/file descriptors/pipes may be attached to this
+    /// process. This list enumerates the file descriptors and such for the
+    /// process to be spawned, and the file descriptors inherited will start at
+    /// 0 and go to the length of this array.
+    ///
+    /// Standard file descriptors are:
+    ///
+    ///     0 - stdin
+    ///     1 - stdout
+    ///     2 - stderr
+    io: ~[StdioContainer]
+}
+
+/// Describes what to do with a standard io stream for a child process.
+pub enum StdioContainer {
+    /// This stream will be ignored. This is the equivalent of attaching the
+    /// stream to `/dev/null`
+    Ignored,
+
+    /// The specified file descriptor is inherited for the stream which it is
+    /// specified for.
+    InheritFd(libc::c_int),
+
+    // XXX: these two shouldn't have libuv-specific implementation details
+
+    /// The specified libuv stream is inherited for the corresponding file
+    /// descriptor it is assigned to.
+    // XXX: this needs to be thought out more.
+    //InheritStream(uv::net::StreamWatcher),
+
+    /// Creates a pipe for the specified file descriptor which will be directed
+    /// into the previously-initialized pipe passed in.
+    ///
+    /// The first boolean argument is whether the pipe is readable, and the
+    /// second is whether it is writable. These properties are from the view of
+    /// the *child* process, not the parent process.
+    CreatePipe(io::UnboundPipeStream,
+               bool /* readable */,
+               bool /* writable */),
+}
+
+impl Process {
+    /// Creates a new pipe initialized, but not bound to any particular
+    /// source/destination
+    pub fn new(config: ProcessConfig) -> Option<Process> {
+        let process = unsafe {
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
+            (*io).spawn(config)
+        };
+        match process {
+            Ok((p, io)) => Some(Process{
+                handle: p,
+                io: io.move_iter().map(|p|
+                    p.map_move(|p| io::PipeStream::bind(p))
+                ).collect()
+            }),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+
+    /// Returns the process id of this child process
+    pub fn id(&self) -> libc::pid_t { self.handle.id() }
+
+    /// Sends the specified signal to the child process, returning whether the
+    /// signal could be delivered or not.
+    ///
+    /// Note that this is purely a wrapper around libuv's `uv_process_kill`
+    /// function.
+    ///
+    /// If the signal delivery fails, then the `io_error` condition is raised on
+    pub fn signal(&mut self, signal: int) {
+        match self.handle.kill(signal) {
+            Ok(()) => {}
+            Err(err) => {
+                io_error::cond.raise(err)
+            }
+        }
+    }
+
+    /// Wait for the child to exit completely, returning the status that it
+    /// exited with. This function will continue to have the same return value
+    /// after it has been called at least once.
+    pub fn wait(&mut self) -> int { self.handle.wait() }
+}
+
+impl Drop for Process {
+    fn drop(&mut self) {
+        // Close all I/O before exiting to ensure that the child doesn't wait
+        // forever to print some text or something similar.
+        for _ in range(0, self.io.len()) {
+            self.io.pop();
+        }
+
+        self.wait();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+    use super::*;
+
+    use rt::io::{Reader, Writer};
+    use rt::io::pipe::*;
+    use str;
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn smoke() {
+        let io = ~[];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"true"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert_eq!(p.wait(), 0);
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn smoke_failure() {
+        let io = ~[];
+        let args = ProcessConfig {
+            program: "if-this-is-a-binary-then-the-world-has-ended",
+            args: [],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert!(p.wait() != 0);
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn exit_reported_right() {
+        let io = ~[];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"exit 1"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert_eq!(p.wait(), 1);
+    }
+
+    fn read_all(input: &mut Reader) -> ~str {
+        let mut ret = ~"";
+        let mut buf = [0, ..1024];
+        loop {
+            match input.read(buf) {
+                None | Some(0) => { break }
+                Some(n) => { ret = ret + str::from_utf8(buf.slice_to(n)); }
+            }
+        }
+        return ret;
+    }
+
+    fn run_output(args: ProcessConfig) -> ~str {
+        let p = Process::new(args);
+        assert!(p.is_some());
+        let mut p = p.unwrap();
+        assert!(p.io[0].is_none());
+        assert!(p.io[1].is_some());
+        let ret = read_all(p.io[1].get_mut_ref() as &mut Reader);
+        assert_eq!(p.wait(), 0);
+        return ret;
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn stdout_works() {
+        let pipe = PipeStream::new().unwrap();
+        let io = ~[Ignored, CreatePipe(pipe, false, true)];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"echo foobar"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        assert_eq!(run_output(args), ~"foobar\n");
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn set_cwd_works() {
+        let pipe = PipeStream::new().unwrap();
+        let io = ~[Ignored, CreatePipe(pipe, false, true)];
+        let cwd = Some("/");
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"pwd"],
+            env: None,
+            cwd: cwd,
+            io: io,
+        };
+        assert_eq!(run_output(args), ~"/\n");
+    }
+
+    #[test]
+    #[cfg(unix, not(android))]
+    fn stdin_works() {
+        let input = PipeStream::new().unwrap();
+        let output = PipeStream::new().unwrap();
+        let io = ~[CreatePipe(input, true, false),
+                   CreatePipe(output, false, true)];
+        let args = ProcessConfig {
+            program: "/bin/sh",
+            args: [~"-c", ~"read line; echo $line"],
+            env: None,
+            cwd: None,
+            io: io,
+        };
+        let mut p = Process::new(args).expect("didn't create a proces?!");
+        p.io[0].get_mut_ref().write("foobar".as_bytes());
+        p.io[0] = None; // close stdin;
+        let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
+        assert_eq!(p.wait(), 0);
+        assert_eq!(out, ~"foobar\n");
+    }
+}
index afbff77f9883226e03e4985eb696c06de631e2a1..59db8194963bb401205bb564d20a115db6fa7d5f 100644 (file)
@@ -33,9 +33,8 @@ mod test {
     use super::PathLike;
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME #8812
     fn path_like_smoke_test() {
-        let expected = "/home";
+        let expected = if cfg!(unix) { "/home" } else { "C:\\" };
         let path = Path(expected);
         path.path_as_str(|p| assert!(p == expected));
         path.path_as_str(|p| assert!(p == expected));
index e6003fb1a4449d77f9be472a3984101900be7630..92dc62490ed1b1479bb46093cce62898c9501ea2 100644 (file)
@@ -235,7 +235,7 @@ pub struct Death {
 impl Drop for KillFlag {
     // Letting a KillFlag with a task inside get dropped would leak the task.
     // We could free it here, but the task should get awoken by hand somehow.
-    fn drop(&self) {
+    fn drop(&mut self) {
         match self.load(Relaxed) {
             KILL_RUNNING | KILL_KILLED => { },
             _ => rtabort!("can't drop kill flag with a blocked task inside!"),
@@ -685,7 +685,7 @@ pub fn assert_may_sleep(&self) {
 }
 
 impl Drop for Death {
-    fn drop(&self) {
+    fn drop(&mut self) {
         // Mustn't be in an atomic or unkillable section at task death.
         rtassert!(self.unkillable == 0);
         rtassert!(self.wont_sleep == 0);
index 12ec19a1ecc67af345c332a072da5055da186c87..9d0a0e0ac25d122d2333d171974b6d3dc984af61 100644 (file)
@@ -78,7 +78,7 @@ pub fn free(&mut self, box: *OpaqueBox) {
 
 impl Drop for LocalHeap {
     #[fixed_stack_segment] #[inline(never)]
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             rust_delete_boxed_region(self.boxed_region);
             rust_delete_memory_region(self.memory_region);
index 53f62786b629dc17cfe714e538fd77f30b6046ad..6df857b8d551716ddb812dc81fa75ed81383be1d 100644 (file)
@@ -198,18 +198,6 @@ pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn())
     return exit_code;
 }
 
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
-    (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
-        extern {
-            fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
-        }
-    )
-)
-}
-
 /// One-time runtime initialization.
 ///
 /// Initializes global state, including frobbing
index 18a5dd4a1145d1fc287665d8aa98380134a7097d..2ba00c3a2fbaced49417a4d7e37a1237d3b658ca 100644 (file)
@@ -74,21 +74,18 @@ pub fn refcount(&self) -> uint {
 
 #[unsafe_destructor]
 impl<T> Drop for RC<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         assert!(self.refcount() > 0);
 
         unsafe {
-            // FIXME(#4330) Need self by value to get mutability.
-            let this: &mut RC<T> = cast::transmute_mut(self);
-
-            match *this.get_mut_state() {
+            match *self.get_mut_state() {
                 (ref mut count, _) => {
                     *count = *count - 1
                 }
             }
 
-            if this.refcount() == 0 {
-                let _: ~(uint, T) = cast::transmute(this.p);
+            if self.refcount() == 0 {
+                let _: ~(uint, T) = cast::transmute(self.p);
             }
         }
     }
index c9c402baaf0fa1d979149faffb9629c714e2db13..ca521c792dc732e9e25cf9db564cf5c72a922143 100644 (file)
@@ -8,17 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use libc;
 use option::*;
 use result::*;
 use libc::c_int;
 
 use rt::io::IoError;
+use super::io::process::ProcessConfig;
 use super::io::net::ip::{IpAddr, SocketAddr};
 use rt::uv::uvio;
 use path::Path;
 use super::io::support::PathLike;
 use super::io::{SeekStyle};
-use super::io::{FileMode, FileAccess};
+use super::io::{FileMode, FileAccess, FileStat};
 
 // XXX: ~object doesn't work currently so these are some placeholder
 // types to use instead
@@ -31,6 +33,9 @@
 pub type RtioUdpSocketObject = uvio::UvUdpSocket;
 pub type RtioTimerObject = uvio::UvTimer;
 pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
+pub type RtioPipeObject = uvio::UvPipeStream;
+pub type RtioUnboundPipeObject = uvio::UvUnboundPipe;
+pub type RtioProcessObject = uvio::UvProcess;
 
 pub trait EventLoop {
     fn run(&mut self);
@@ -74,6 +79,14 @@ 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 get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>;
+    fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError>;
+    fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
+    fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
+    fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
+        Result<~[Path], IoError>;
+    fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError>;
+    fn spawn(&mut self, config: ProcessConfig)
+            -> Result<(~RtioProcessObject, ~[Option<RtioPipeObject>]), IoError>;
 }
 
 pub trait RtioTcpListener : RtioSocket {
@@ -130,3 +143,14 @@ pub trait RtioFileStream {
     fn tell(&self) -> Result<u64, IoError>;
     fn flush(&mut self) -> Result<(), IoError>;
 }
+
+pub trait RtioProcess {
+    fn id(&self) -> libc::pid_t;
+    fn kill(&mut self, signal: int) -> Result<(), IoError>;
+    fn wait(&mut self) -> int;
+}
+
+pub trait RtioPipe {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
+}
index bcf9ae4a2a8410037d2f0e80ec48e8e4b62c3dba..854fdadfb00d24c9e2bafba96ac04fc56117bb51 100644 (file)
@@ -1200,15 +1200,15 @@ fn start_closure_dtor() {
             struct S { field: () }
 
             impl Drop for S {
-                fn drop(&self) {
-                        let _foo = @0;
+                fn drop(&mut self) {
+                    let _foo = @0;
                 }
             }
 
             let s = S { field: () };
 
             do spawntask {
-                        let _ss = &s;
+                let _ss = &s;
             }
         }
     }
index da70659acec2edfe577607b7a54b1fa1152cad27..fddee5882b9acf6c8dcdf8da54574ce52fde7c03 100644 (file)
@@ -53,7 +53,7 @@ pub fn end(&self) -> *uint {
 }
 
 impl Drop for StackSegment {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment]; #[inline(never)];
 
         unsafe {
index da81aab0f7849eb6bfd5742629af46168b383219..09bd89ec94a181c36cb1ea9235d999e6d1f5792f 100644 (file)
@@ -328,7 +328,7 @@ pub fn on_appropriate_sched() -> bool {
 }
 
 impl Drop for Task {
-    fn drop(&self) {
+    fn drop(&mut self) {
         rtdebug!("called drop for a task: %u", borrow::to_uint(self));
         rtassert!(self.destroyed)
     }
@@ -444,17 +444,10 @@ pub fn try(&mut self, f: &fn()) {
         }
 
         extern {
-            #[cfg(not(stage0))]
             #[rust_stack]
             fn rust_try(f: extern "C" fn(*c_void, *c_void),
                         code: *c_void,
                         data: *c_void) -> uintptr_t;
-
-            #[cfg(stage0)]
-            #[rust_stack]
-            fn rust_try(f: *u8,
-                        code: *c_void,
-                        data: *c_void) -> uintptr_t;
         }
     }
 
@@ -490,10 +483,10 @@ fn local_heap() {
     fn tls() {
         use local_data;
         do run_in_newsched_task() {
-            static key: local_data::Key<@~str> = &local_data::Key;
+            local_data_key!(key: @~str)
             local_data::set(key, @~"data");
             assert!(*local_data::get(key, |k| k.map_move(|k| *k)).unwrap() == ~"data");
-            static key2: local_data::Key<@~str> = &local_data::Key;
+            local_data_key!(key2: @~str)
             local_data::set(key2, @~"data");
             assert!(*local_data::get(key2, |k| k.map_move(|k| *k)).unwrap() == ~"data");
         }
index 61db08f4813ef5da516cd1d8ecc335cb43fc9a3d..8b64fda21364a2ca9a40fef1b22bb1bbf858399a 100644 (file)
@@ -46,7 +46,7 @@ pub fn join(self) {
 }
 
 impl Drop for Thread {
-    fn drop(&self) {
+    fn drop(&mut self) {
         #[fixed_stack_segment]; #[inline(never)];
 
         assert!(self.joined);
index 45a5fce3f1e8aa0e33575244b98897eb3f73a4f8..ada558036cfeae2419768e52878eb73a9ead533b 100644 (file)
@@ -17,6 +17,7 @@
 use rt::uv::uvll::*;
 use super::super::io::support::PathLike;
 use cast::transmute;
+use libc;
 use libc::{c_int};
 use option::{None, Some, Option};
 
 impl Request for FsRequest;
 
 pub struct RequestData {
-    complete_cb: Option<FsCallback>,
-    raw_fd: Option<c_int>
+    complete_cb: Option<FsCallback>
 }
 
 impl FsRequest {
-    pub fn new(cb: Option<FsCallback>) -> FsRequest {
+    pub fn new() -> FsRequest {
         let fs_req = unsafe { malloc_req(UV_FS) };
         assert!(fs_req.is_not_null());
         let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
-        fs_req.install_req_data(cb);
         fs_req
     }
 
-    fn open_common<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int,
-               cb: Option<FsCallback>) -> int {
-        let complete_cb_ptr = match cb {
-            Some(_) => compl_cb as *u8,
-            None => 0 as *u8
+    pub fn open<P: PathLike>(self, loop_: &Loop, path: &P, flags: int, mode: int,
+               cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
         };
-        let is_sync = cb.is_none();
-        let req = FsRequest::new(cb);
-        let result = path.path_as_str(|p| {
+        path.path_as_str(|p| {
             p.to_c_str().with_ref(|p| unsafe {
             uvll::fs_open(loop_.native_handle(),
-                          req.native_handle(), p, flags, mode, complete_cb_ptr) as int
+                          self.native_handle(), p, flags, mode, complete_cb_ptr)
             })
         });
-        if is_sync { req.cleanup_and_delete(); }
-        result
     }
-    pub fn open<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int,
-               cb: FsCallback) {
-        FsRequest::open_common(loop_, path, flags, mode, Some(cb));
+
+    pub fn open_sync<P: PathLike>(self, loop_: &Loop, path: &P,
+                                  flags: int, mode: int) -> Result<c_int, UvError> {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(None)
+        };
+        let result = path.path_as_str(|p| {
+            p.to_c_str().with_ref(|p| unsafe {
+            uvll::fs_open(loop_.native_handle(),
+                    self.native_handle(), p, flags, mode, complete_cb_ptr)
+            })
+        });
+        self.sync_cleanup(result)
     }
 
-    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)
+    pub fn unlink<P: PathLike>(self, loop_: &Loop, path: &P, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        path.path_as_str(|p| {
+            p.to_c_str().with_ref(|p| unsafe {
+                uvll::fs_unlink(loop_.native_handle(),
+                              self.native_handle(), p, complete_cb_ptr)
+            })
+        });
     }
 
-    fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) -> int {
-        let complete_cb_ptr = match cb {
-            Some(_) => compl_cb as *u8,
-            None => 0 as *u8
+    pub fn unlink_sync<P: PathLike>(self, loop_: &Loop, path: &P)
+      -> Result<c_int, UvError> {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(None)
         };
-        let is_sync = cb.is_none();
-        let req = FsRequest::new(cb);
         let result = path.path_as_str(|p| {
             p.to_c_str().with_ref(|p| unsafe {
                 uvll::fs_unlink(loop_.native_handle(),
-                              req.native_handle(), p, complete_cb_ptr) as int
+                              self.native_handle(), p, complete_cb_ptr)
             })
         });
-        if is_sync { req.cleanup_and_delete(); }
-        result
+        self.sync_cleanup(result)
+    }
+
+    pub fn stat<P: PathLike>(self, loop_: &Loop, path: &P, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        path.path_as_str(|p| {
+            p.to_c_str().with_ref(|p| unsafe {
+                uvll::fs_stat(loop_.native_handle(),
+                              self.native_handle(), p, complete_cb_ptr)
+            })
+        });
+    }
+
+    pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        let base_ptr = buf.base as *c_void;
+        let len = buf.len as uint;
+        unsafe {
+            uvll::fs_write(loop_.native_handle(), self.native_handle(),
+                           fd, base_ptr,
+                           len, offset, complete_cb_ptr)
+        };
     }
-    pub fn unlink<P: PathLike>(loop_: &Loop, path: &P, cb: FsCallback) {
-        let result = FsRequest::unlink_common(loop_, path, Some(cb));
-        sync_cleanup(result);
+    pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
+          -> Result<c_int, UvError> {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(None)
+        };
+        let base_ptr = buf.base as *c_void;
+        let len = buf.len as uint;
+        let result = unsafe {
+            uvll::fs_write(loop_.native_handle(), self.native_handle(),
+                           fd, base_ptr,
+                           len, offset, complete_cb_ptr)
+        };
+        self.sync_cleanup(result)
+    }
+
+    pub fn read(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        let buf_ptr = buf.base as *c_void;
+        let len = buf.len as uint;
+        unsafe {
+            uvll::fs_read(loop_.native_handle(), self.native_handle(),
+                           fd, buf_ptr,
+                           len, offset, complete_cb_ptr)
+        };
     }
-    pub fn unlink_sync<P: PathLike>(loop_: &Loop, path: &P) -> Result<int, UvError> {
-        let result = FsRequest::unlink_common(loop_, path, None);
-        sync_cleanup(result)
+    pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
+          -> Result<c_int, UvError> {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(None)
+        };
+        let buf_ptr = buf.base as *c_void;
+        let len = buf.len as uint;
+        let result = unsafe {
+            uvll::fs_read(loop_.native_handle(), self.native_handle(),
+                           fd, buf_ptr,
+                           len, offset, complete_cb_ptr)
+        };
+        self.sync_cleanup(result)
     }
 
-    pub fn install_req_data(&self, cb: Option<FsCallback>) {
+    pub fn close(self, loop_: &Loop, fd: c_int, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        unsafe {
+            uvll::fs_close(loop_.native_handle(), self.native_handle(),
+                           fd, complete_cb_ptr)
+        };
+    }
+    pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result<c_int, UvError> {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(None)
+        };
+        let result = unsafe {
+            uvll::fs_close(loop_.native_handle(), self.native_handle(),
+                           fd, complete_cb_ptr)
+        };
+        self.sync_cleanup(result)
+    }
+
+    pub fn mkdir<P: PathLike>(self, loop_: &Loop, path: &P, mode: int, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        path.path_as_str(|p| {
+            p.to_c_str().with_ref(|p| unsafe {
+            uvll::fs_mkdir(loop_.native_handle(),
+                          self.native_handle(), p, mode, complete_cb_ptr)
+            })
+        });
+    }
+
+    pub fn rmdir<P: PathLike>(self, loop_: &Loop, path: &P, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        path.path_as_str(|p| {
+            p.to_c_str().with_ref(|p| unsafe {
+            uvll::fs_rmdir(loop_.native_handle(),
+                          self.native_handle(), p, complete_cb_ptr)
+            })
+        });
+    }
+
+    pub fn readdir<P: PathLike>(self, loop_: &Loop, path: &P,
+                                flags: c_int, cb: FsCallback) {
+        let complete_cb_ptr = {
+            let mut me = self;
+            me.req_boilerplate(Some(cb))
+        };
+        path.path_as_str(|p| {
+            p.to_c_str().with_ref(|p| unsafe {
+            uvll::fs_readdir(loop_.native_handle(),
+                          self.native_handle(), p, flags, complete_cb_ptr)
+            })
+        });
+    }
+
+    // accessors/utility funcs
+    fn sync_cleanup(self, result: c_int)
+          -> Result<c_int, UvError> {
+        self.cleanup_and_delete();
+        match status_to_maybe_uv_error(result as i32) {
+            Some(err) => Err(err),
+            None => Ok(result)
+        }
+    }
+    fn req_boilerplate(&mut self, cb: Option<FsCallback>) -> *u8 {
+        let result = match cb {
+            Some(_) => {
+                compl_cb as *u8
+            },
+            None => 0 as *u8
+        };
+        self.install_req_data(cb);
+        result
+    }
+    pub fn install_req_data(&mut self, cb: Option<FsCallback>) {
         let fs_req = (self.native_handle()) as *uvll::uv_write_t;
         let data = ~RequestData {
-            complete_cb: cb,
-            raw_fd: None
+            complete_cb: cb
         };
         unsafe {
             let data = transmute::<~RequestData, *c_void>(data);
@@ -106,7 +260,7 @@ fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
         unsafe {
             let data = uvll::get_data_for_req((self.native_handle()));
             let data = transmute::<&*c_void, &mut ~RequestData>(&data);
-            return &mut **data;
+            &mut **data
         }
     }
 
@@ -120,6 +274,42 @@ pub fn get_loop(&self) -> Loop {
         unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
     }
 
+    pub fn get_stat(&self) -> uv_stat_t {
+        let stat = uv_stat_t::new();
+        unsafe { uvll::populate_stat(self.native_handle(), &stat); }
+        stat
+    }
+
+    pub fn get_ptr(&self) -> *libc::c_void {
+        unsafe {
+            uvll::get_ptr_from_fs_req(self.native_handle())
+        }
+    }
+
+    pub fn get_paths(&mut self) -> ~[~str] {
+        use str;
+        let ptr = self.get_ptr();
+        match self.get_result() {
+            n if (n <= 0) => {
+                ~[]
+            },
+            n => {
+                let n_len = n as uint;
+                // we pass in the len that uv tells us is there
+                // for the entries and we don't continue past that..
+                // it appears that sometimes the multistring isn't
+                // correctly delimited and we stray into garbage memory?
+                // in any case, passing Some(n_len) fixes it and ensures
+                // good results
+                let raw_path_strs = unsafe {
+                    str::raw::from_c_multistring(ptr as *libc::c_char, Some(n_len)) };
+                let raw_len = raw_path_strs.len();
+                assert_eq!(raw_len, n_len);
+                raw_path_strs
+            }
+        }
+    }
+
     fn cleanup_and_delete(self) {
         unsafe {
             let data = uvll::get_data_for_req(self.native_handle());
@@ -148,97 +338,6 @@ fn sync_cleanup(result: int)
     }
 }
 
-pub struct FileDescriptor(c_int);
-
-impl FileDescriptor {
-    fn new(fd: c_int) -> FileDescriptor {
-        FileDescriptor(fd)
-    }
-
-
-    pub fn from_open_req(req: &mut FsRequest) -> FileDescriptor {
-        FileDescriptor::new(req.get_result())
-    }
-
-    // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write
-    fn write_common(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: Option<FsCallback>)
-          -> int {
-        let complete_cb_ptr = match cb {
-            Some(_) => compl_cb as *u8,
-            None => 0 as *u8
-        };
-        let is_sync = cb.is_none();
-        let mut req = FsRequest::new(cb);
-        let base_ptr = buf.base as *c_void;
-        let len = buf.len as uint;
-        req.get_req_data().raw_fd = Some(self.native_handle());
-        let result = unsafe {
-            uvll::fs_write(loop_.native_handle(), req.native_handle(),
-                           self.native_handle(), base_ptr,
-                           len, offset, complete_cb_ptr) as int
-        };
-        if is_sync { req.cleanup_and_delete(); }
-        result
-    }
-    pub fn write(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
-        self.write_common(loop_, buf, offset, Some(cb));
-    }
-    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)
-    }
-
-    fn read_common(&mut self, loop_: &Loop, buf: Buf,
-                   offset: i64, cb: Option<FsCallback>)
-          -> int {
-        let complete_cb_ptr = match cb {
-            Some(_) => compl_cb as *u8,
-            None => 0 as *u8
-        };
-        let is_sync = cb.is_none();
-        let mut req = FsRequest::new(cb);
-        req.get_req_data().raw_fd = Some(self.native_handle());
-        let buf_ptr = buf.base as *c_void;
-        let result = unsafe {
-            uvll::fs_read(loop_.native_handle(), req.native_handle(),
-                           self.native_handle(), buf_ptr,
-                           buf.len as uint, offset, complete_cb_ptr) as int
-        };
-        if is_sync { req.cleanup_and_delete(); }
-        result
-    }
-    pub fn read(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
-        self.read_common(loop_, buf, offset, Some(cb));
-    }
-    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)
-    }
-
-    fn close_common(self, loop_: &Loop, cb: Option<FsCallback>) -> int {
-        let complete_cb_ptr = match cb {
-            Some(_) => compl_cb as *u8,
-            None => 0 as *u8
-        };
-        let is_sync = cb.is_none();
-        let req = FsRequest::new(cb);
-        let result = unsafe {
-            uvll::fs_close(loop_.native_handle(), req.native_handle(),
-                           self.native_handle(), complete_cb_ptr) as int
-        };
-        if is_sync { req.cleanup_and_delete(); }
-        result
-    }
-    pub fn close(self, loop_: &Loop, cb: FsCallback) {
-        self.close_common(loop_, Some(cb));
-    }
-    pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
-        let result = self.close_common(loop_, None);
-        sync_cleanup(result)
-    }
-}
 extern fn compl_cb(req: *uv_fs_t) {
     let mut req: FsRequest = NativeHandle::from_native_handle(req);
     // pull the user cb out of the req data
@@ -261,15 +360,7 @@ pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
     req.cleanup_and_delete();
 }
 
-impl NativeHandle<c_int> for FileDescriptor {
-    fn from_native_handle(handle: c_int) -> FileDescriptor {
-        FileDescriptor(handle)
-    }
-    fn native_handle(&self) -> c_int {
-        match self { &FileDescriptor(ptr) => ptr }
-    }
-}
-
+#[cfg(test)]
 mod test {
     use super::*;
     //use rt::test::*;
@@ -279,11 +370,11 @@ mod test {
     use unstable::run_in_bare_thread;
     use path::Path;
     use rt::uv::{Loop, Buf, slice_to_uv_buf};
-    use libc::{O_CREAT, O_RDWR, O_RDONLY,
-               S_IWUSR, S_IRUSR}; //NOTE: need defs for S_**GRP|S_**OTH in libc:: ...
-               //S_IRGRP, S_IROTH};
+    use libc::{c_int, O_CREAT, O_RDWR, O_RDONLY,
+               S_IWUSR, S_IRUSR};
 
-    fn file_test_full_simple_impl() {
+    #[test]
+    fn file_test_full_simple() {
         do run_in_bare_thread {
             let mut loop_ = Loop::new();
             let create_flags = O_RDWR | O_CREAT;
@@ -302,25 +393,27 @@ fn file_test_full_simple_impl() {
             let read_buf = slice_to_uv_buf(read_mem);
             let read_buf_ptr: *Buf = &read_buf;
             let p = Path(path_str);
-            do FsRequest::open(&loop_, &p, create_flags as int, mode as int)
+            let open_req = FsRequest::new();
+            do open_req.open(&loop_, &p, create_flags as int, mode as int)
             |req, uverr| {
                 assert!(uverr.is_none());
-                let mut fd = FileDescriptor::from_open_req(req);
-                let raw_fd = fd.native_handle();
+                let fd = req.get_result();
                 let buf = unsafe { *write_buf_ptr };
-                do fd.write(&req.get_loop(), buf, -1) |req, uverr| {
-                    let fd = FileDescriptor(raw_fd);
-                    do fd.close(&req.get_loop()) |req, _| {
-                        let loop_ = req.get_loop();
+                let write_req = FsRequest::new();
+                do write_req.write(&req.get_loop(), fd, buf, -1) |req, uverr| {
+                    let close_req = FsRequest::new();
+                    do close_req.close(&req.get_loop(), fd) |req, _| {
                         assert!(uverr.is_none());
-                        do FsRequest::open(&loop_, &Path(path_str), read_flags as int,0)
+                        let loop_ = req.get_loop();
+                        let open_req = FsRequest::new();
+                        do open_req.open(&loop_, &Path(path_str), read_flags as int,0)
                             |req, uverr| {
                             assert!(uverr.is_none());
                             let loop_ = req.get_loop();
-                            let mut fd = FileDescriptor::from_open_req(req);
-                            let raw_fd = fd.native_handle();
+                            let fd = req.get_result();
                             let read_buf = unsafe { *read_buf_ptr };
-                            do fd.read(&loop_, read_buf, 0) |req, uverr| {
+                            let read_req = FsRequest::new();
+                            do read_req.read(&loop_, fd, read_buf, 0) |req, uverr| {
                                 assert!(uverr.is_none());
                                 let loop_ = req.get_loop();
                                 // we know nread >=0 because uverr is none..
@@ -334,15 +427,17 @@ fn file_test_full_simple_impl() {
                                                 read_buf.base, nread))
                                     };
                                     assert!(read_str == ~"hello");
-                                    do FileDescriptor(raw_fd).close(&loop_) |req,uverr| {
+                                    let close_req = FsRequest::new();
+                                    do close_req.close(&loop_, fd) |req,uverr| {
                                         assert!(uverr.is_none());
                                         let loop_ = &req.get_loop();
-                                        do FsRequest::unlink(loop_, &Path(path_str))
+                                        let unlink_req = FsRequest::new();
+                                        do unlink_req.unlink(loop_, &Path(path_str))
                                         |_,uverr| {
                                             assert!(uverr.is_none());
                                         };
                                     };
-                                }
+                                };
                             };
                         };
                     };
@@ -352,7 +447,9 @@ fn file_test_full_simple_impl() {
             loop_.close();
         }
     }
-    fn file_test_full_simple_impl_sync() {
+
+    #[test]
+    fn file_test_full_simple_sync() {
         do run_in_bare_thread {
             // setup
             let mut loop_ = Loop::new();
@@ -368,26 +465,31 @@ fn file_test_full_simple_impl_sync() {
             let write_val = "hello".as_bytes().to_owned();
             let write_buf = slice_to_uv_buf(write_val);
             // open/create
-            let result = FsRequest::open_sync(&loop_, &Path(path_str),
+            let open_req = FsRequest::new();
+            let result = open_req.open_sync(&loop_, &Path(path_str),
                                                    create_flags as int, mode as int);
             assert!(result.is_ok());
-            let mut fd = FileDescriptor(result.unwrap() as i32);
+            let fd = result.unwrap();
             // write
-            let result = fd.write_sync(&loop_, write_buf, -1);
+            let write_req = FsRequest::new();
+            let result = write_req.write_sync(&loop_, fd, write_buf, -1);
             assert!(result.is_ok());
             // close
-            let result = fd.close_sync(&loop_);
+            let close_req = FsRequest::new();
+            let result = close_req.close_sync(&loop_, fd);
             assert!(result.is_ok());
             // re-open
-            let result = FsRequest::open_sync(&loop_, &Path(path_str),
+            let open_req = FsRequest::new();
+            let result = open_req.open_sync(&loop_, &Path(path_str),
                                                    read_flags as int,0);
             assert!(result.is_ok());
             let len = 1028;
-            let mut fd = FileDescriptor(result.unwrap() as i32);
+            let fd = result.unwrap();
             // read
             let read_mem: ~[u8] = vec::from_elem(len, 0u8);
             let buf = slice_to_uv_buf(read_mem);
-            let result = fd.read_sync(&loop_, buf, 0);
+            let read_req = FsRequest::new();
+            let result = read_req.read_sync(&loop_, fd, buf, 0);
             assert!(result.is_ok());
             let nread = result.unwrap();
             // nread == 0 would be EOF.. we know it's >= zero because otherwise
@@ -397,33 +499,23 @@ fn file_test_full_simple_impl_sync() {
                     read_mem.slice(0, nread as uint));
                 assert!(read_str == ~"hello");
                 // close
-                let result = fd.close_sync(&loop_);
+                let close_req = FsRequest::new();
+                let result = close_req.close_sync(&loop_, fd);
                 assert!(result.is_ok());
                 // unlink
-                let result = FsRequest::unlink_sync(&loop_, &Path(path_str));
+                let unlink_req = FsRequest::new();
+                let result = unlink_req.unlink_sync(&loop_, &Path(path_str));
                 assert!(result.is_ok());
             } else { fail!("nread was 0.. wudn't expectin' that."); }
             loop_.close();
         }
     }
 
-    #[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();
-    }
-
     fn naive_print(loop_: &Loop, input: &str) {
-        let mut stdout = FileDescriptor(STDOUT_FILENO);
         let write_val = input.as_bytes();
         let write_buf = slice_to_uv_buf(write_val);
-        stdout.write_sync(loop_, write_buf, -1);
+        let write_req = FsRequest::new();
+        write_req.write_sync(loop_, STDOUT_FILENO, write_buf, -1);
     }
 
     #[test]
@@ -435,4 +527,130 @@ fn file_test_write_to_stdout() {
             loop_.close();
         };
     }
+    #[test]
+    fn file_test_stat_simple() {
+        do run_in_bare_thread {
+            let mut loop_ = Loop::new();
+            let path = "./tmp/file_test_stat_simple.txt";
+            let create_flags = O_RDWR |
+                O_CREAT;
+            let mode = S_IWUSR |
+                S_IRUSR;
+            let write_val = "hello".as_bytes().to_owned();
+            let write_buf  = slice_to_uv_buf(write_val);
+            let write_buf_ptr: *Buf = &write_buf;
+            let open_req = FsRequest::new();
+            do open_req.open(&loop_, &path, create_flags as int, mode as int)
+            |req, uverr| {
+                assert!(uverr.is_none());
+                let fd = req.get_result();
+                let buf = unsafe { *write_buf_ptr };
+                let write_req = FsRequest::new();
+                do write_req.write(&req.get_loop(), fd, buf, 0) |req, uverr| {
+                    assert!(uverr.is_none());
+                    let loop_ = req.get_loop();
+                    let stat_req = FsRequest::new();
+                    do stat_req.stat(&loop_, &path) |req, uverr| {
+                        assert!(uverr.is_none());
+                        let loop_ = req.get_loop();
+                        let stat = req.get_stat();
+                        let sz: uint = stat.st_size as uint;
+                        assert!(sz > 0);
+                        let close_req = FsRequest::new();
+                        do close_req.close(&loop_, fd) |req, uverr| {
+                            assert!(uverr.is_none());
+                            let loop_ = req.get_loop();
+                            let unlink_req = FsRequest::new();
+                            do unlink_req.unlink(&loop_, &path) |req,uverr| {
+                                assert!(uverr.is_none());
+                                let loop_ = req.get_loop();
+                                let stat_req = FsRequest::new();
+                                do stat_req.stat(&loop_, &path) |_, uverr| {
+                                    // should cause an error because the
+                                    // file doesn't exist anymore
+                                    assert!(uverr.is_some());
+                                };
+                            };
+                        };
+                    };
+                };
+            };
+            loop_.run();
+            loop_.close();
+        }
+    }
+
+    #[test]
+    fn file_test_mk_rm_dir() {
+        do run_in_bare_thread {
+            let mut loop_ = Loop::new();
+            let path = "./tmp/mk_rm_dir";
+            let mode = S_IWUSR |
+                S_IRUSR;
+            let mkdir_req = FsRequest::new();
+            do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| {
+                assert!(uverr.is_none());
+                let loop_ = req.get_loop();
+                let stat_req = FsRequest::new();
+                do stat_req.stat(&loop_, &path) |req, uverr| {
+                    assert!(uverr.is_none());
+                    let loop_ = req.get_loop();
+                    let stat = req.get_stat();
+                    naive_print(&loop_, fmt!("%?", stat));
+                    assert!(stat.is_dir());
+                    let rmdir_req = FsRequest::new();
+                    do rmdir_req.rmdir(&loop_, &path) |req,uverr| {
+                        assert!(uverr.is_none());
+                        let loop_ = req.get_loop();
+                        let stat_req = FsRequest::new();
+                        do stat_req.stat(&loop_, &path) |req, uverr| {
+                            assert!(uverr.is_some());
+                        }
+                    }
+                }
+            }
+            loop_.run();
+            loop_.close();
+        }
+    }
+    #[test]
+    fn file_test_mkdir_chokes_on_double_create() {
+        do run_in_bare_thread {
+            let mut loop_ = Loop::new();
+            let path = "./tmp/double_create_dir";
+            let mode = S_IWUSR |
+                S_IRUSR;
+            let mkdir_req = FsRequest::new();
+            do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| {
+                assert!(uverr.is_none());
+                let loop_ = req.get_loop();
+                let mkdir_req = FsRequest::new();
+                do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| {
+                    assert!(uverr.is_some());
+                    let loop_ = req.get_loop();
+                    let stat = req.get_stat();
+                    let rmdir_req = FsRequest::new();
+                    do rmdir_req.rmdir(&loop_, &path) |req,uverr| {
+                        assert!(uverr.is_none());
+                        let loop_ = req.get_loop();
+                    }
+                }
+            }
+            loop_.run();
+            loop_.close();
+        }
+    }
+    #[test]
+    fn file_test_rmdir_chokes_on_nonexistant_path() {
+        do run_in_bare_thread {
+            let mut loop_ = Loop::new();
+            let path = "./tmp/never_existed_dir";
+            let rmdir_req = FsRequest::new();
+            do rmdir_req.rmdir(&loop_, &path) |req,uverr| {
+                assert!(uverr.is_some());
+            }
+            loop_.run();
+            loop_.close();
+        }
+    }
 }
index 451d454d2d822262c4279ca94f379cb8f0e29b98..95b2059d5381ddfa2fb3178b38d76719c9a8fdd3 100644 (file)
@@ -58,6 +58,8 @@
 pub use self::idle::IdleWatcher;
 pub use self::timer::TimerWatcher;
 pub use self::async::AsyncWatcher;
+pub use self::process::Process;
+pub use self::pipe::Pipe;
 
 /// The implementation of `rtio` for libuv
 pub mod uvio;
@@ -71,6 +73,8 @@
 pub mod timer;
 pub mod async;
 pub mod addrinfo;
+pub mod process;
+pub mod pipe;
 
 /// XXX: Loop(*handle) is buggy with destructors. Normal structs
 /// with dtors may not be destructured, but tuple structs can,
@@ -127,6 +131,8 @@ 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>);
@@ -145,7 +151,8 @@ struct WatcherData {
     timer_cb: Option<TimerCallback>,
     async_cb: Option<AsyncCallback>,
     udp_recv_cb: Option<UdpReceiveCallback>,
-    udp_send_cb: Option<UdpSendCallback>
+    udp_send_cb: Option<UdpSendCallback>,
+    exit_cb: Option<ExitCallback>,
 }
 
 pub trait WatcherInterop {
@@ -177,7 +184,8 @@ fn install_watcher_data(&mut self) {
                 timer_cb: None,
                 async_cb: None,
                 udp_recv_cb: None,
-                udp_send_cb: None
+                udp_send_cb: None,
+                exit_cb: None,
             };
             let data = transmute::<~WatcherData, *c_void>(data);
             uvll::set_data_for_uv_handle(self.native_handle(), data);
diff --git a/src/libstd/rt/uv/pipe.rs b/src/libstd/rt/uv/pipe.rs
new file mode 100644 (file)
index 0000000..1147c73
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+use libc;
+
+use rt::uv;
+use rt::uv::net;
+use rt::uv::uvll;
+
+pub struct Pipe(*uvll::uv_pipe_t);
+
+impl uv::Watcher for Pipe {}
+
+impl Pipe {
+    pub fn new(loop_: &uv::Loop, ipc: bool) -> Pipe {
+        unsafe {
+            let handle = uvll::malloc_handle(uvll::UV_NAMED_PIPE);
+            assert!(handle.is_not_null());
+            let ipc = ipc as libc::c_int;
+            assert_eq!(uvll::pipe_init(loop_.native_handle(), handle, ipc), 0);
+            let mut ret: Pipe =
+                    uv::NativeHandle::from_native_handle(handle);
+            ret.install_watcher_data();
+            ret
+        }
+    }
+
+    pub fn as_stream(&self) -> net::StreamWatcher {
+        net::StreamWatcher(**self as *uvll::uv_stream_t)
+    }
+
+    pub fn close(self, cb: uv::NullCallback) {
+        {
+            let mut this = self;
+            let data = this.get_watcher_data();
+            assert!(data.close_cb.is_none());
+            data.close_cb = Some(cb);
+        }
+
+        unsafe { uvll::close(self.native_handle(), close_cb); }
+
+        extern fn close_cb(handle: *uvll::uv_pipe_t) {
+            let mut process: Pipe = uv::NativeHandle::from_native_handle(handle);
+            process.get_watcher_data().close_cb.take_unwrap()();
+            process.drop_watcher_data();
+            unsafe { uvll::free_handle(handle as *libc::c_void) }
+        }
+    }
+}
+
+impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe {
+    fn from_native_handle(handle: *uvll::uv_pipe_t) -> Pipe {
+        Pipe(handle)
+    }
+    fn native_handle(&self) -> *uvll::uv_pipe_t {
+        match self { &Pipe(ptr) => ptr }
+    }
+}
diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs
new file mode 100644 (file)
index 0000000..ccfa1ff
--- /dev/null
@@ -0,0 +1,219 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+use cell::Cell;
+use libc;
+use ptr;
+use util;
+use vec;
+
+use rt::io::process::*;
+use rt::uv;
+use rt::uv::uvio::UvPipeStream;
+use rt::uv::uvll;
+
+/// A process wraps the handle of the underlying uv_process_t.
+pub struct Process(*uvll::uv_process_t);
+
+impl uv::Watcher for Process {}
+
+impl Process {
+    /// Creates a new process, ready to spawn inside an event loop
+    pub fn new() -> Process {
+        let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
+        assert!(handle.is_not_null());
+        let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
+        ret.install_watcher_data();
+        return ret;
+    }
+
+    /// Spawn a new process inside the specified event loop.
+    ///
+    /// The `config` variable will be passed down to libuv, and the `exit_cb`
+    /// will be run only once, when the process exits.
+    ///
+    /// Returns either the corresponding process object or an error which
+    /// occurred.
+    pub fn spawn(&mut self, loop_: &uv::Loop, mut config: ProcessConfig,
+                 exit_cb: uv::ExitCallback)
+                    -> Result<~[Option<UvPipeStream>], uv::UvError>
+    {
+        let cwd = config.cwd.map_move(|s| s.to_c_str());
+
+        extern fn on_exit(p: *uvll::uv_process_t,
+                          exit_status: libc::c_int,
+                          term_signal: libc::c_int) {
+            let mut p: Process = uv::NativeHandle::from_native_handle(p);
+            let err = match exit_status {
+                0 => None,
+                _ => uv::status_to_maybe_uv_error(-1)
+            };
+            p.get_watcher_data().exit_cb.take_unwrap()(p,
+                                                       exit_status as int,
+                                                       term_signal as int,
+                                                       err);
+        }
+
+        let io = util::replace(&mut config.io, ~[]);
+        let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(io.len());
+        let mut ret_io = vec::with_capacity(io.len());
+        unsafe {
+            vec::raw::set_len(&mut stdio, io.len());
+            for (slot, other) in stdio.iter().zip(io.move_iter()) {
+                let io = set_stdio(slot as *uvll::uv_stdio_container_t, other);
+                ret_io.push(io);
+            }
+        }
+
+        let exit_cb = Cell::new(exit_cb);
+        let ret_io = Cell::new(ret_io);
+        do with_argv(config.program, config.args) |argv| {
+            do with_env(config.env) |envp| {
+                let options = uvll::uv_process_options_t {
+                    exit_cb: on_exit,
+                    file: unsafe { *argv },
+                    args: argv,
+                    env: envp,
+                    cwd: match cwd {
+                        Some(ref cwd) => cwd.with_ref(|p| p),
+                        None => ptr::null(),
+                    },
+                    flags: 0,
+                    stdio_count: stdio.len() as libc::c_int,
+                    stdio: stdio.as_imm_buf(|p, _| p),
+                    uid: 0,
+                    gid: 0,
+                };
+
+                match unsafe {
+                    uvll::spawn(loop_.native_handle(), **self, options)
+                } {
+                    0 => {
+                        (*self).get_watcher_data().exit_cb = Some(exit_cb.take());
+                        Ok(ret_io.take())
+                    }
+                    err => Err(uv::UvError(err))
+                }
+            }
+        }
+    }
+
+    /// Sends a signal to this process.
+    ///
+    /// This is a wrapper around `uv_process_kill`
+    pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
+        match unsafe {
+            uvll::process_kill(self.native_handle(), signum as libc::c_int)
+        } {
+            0 => Ok(()),
+            err => Err(uv::UvError(err))
+        }
+    }
+
+    /// Returns the process id of a spawned process
+    pub fn pid(&self) -> libc::pid_t {
+        unsafe { uvll::process_pid(**self) as libc::pid_t }
+    }
+
+    /// Closes this handle, invoking the specified callback once closed
+    pub fn close(self, cb: uv::NullCallback) {
+        {
+            let mut this = self;
+            let data = this.get_watcher_data();
+            assert!(data.close_cb.is_none());
+            data.close_cb = Some(cb);
+        }
+
+        unsafe { uvll::close(self.native_handle(), close_cb); }
+
+        extern fn close_cb(handle: *uvll::uv_process_t) {
+            let mut process: Process = uv::NativeHandle::from_native_handle(handle);
+            process.get_watcher_data().close_cb.take_unwrap()();
+            process.drop_watcher_data();
+            unsafe { uvll::free_handle(handle as *libc::c_void) }
+        }
+    }
+}
+
+unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
+                    io: StdioContainer) -> Option<UvPipeStream> {
+    match io {
+        Ignored => {
+            uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE);
+            None
+        }
+        InheritFd(fd) => {
+            uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
+            uvll::set_stdio_container_fd(dst, fd);
+            None
+        }
+        CreatePipe(pipe, readable, writable) => {
+            let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
+            if readable {
+                flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
+            }
+            if writable {
+                flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
+            }
+            let handle = pipe.pipe.as_stream().native_handle();
+            uvll::set_stdio_container_flags(dst, flags);
+            uvll::set_stdio_container_stream(dst, handle);
+            Some(pipe.bind())
+        }
+    }
+}
+
+/// Converts the program and arguments to the argv array expected by libuv
+fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
+    // First, allocation space to put all the C-strings (we need to have
+    // ownership of them somewhere
+    let mut c_strs = vec::with_capacity(args.len() + 1);
+    c_strs.push(prog.to_c_str());
+    for arg in args.iter() {
+        c_strs.push(arg.to_c_str());
+    }
+
+    // Next, create the char** array
+    let mut c_args = vec::with_capacity(c_strs.len() + 1);
+    for s in c_strs.iter() {
+        c_args.push(s.with_ref(|p| p));
+    }
+    c_args.push(ptr::null());
+    c_args.as_imm_buf(|buf, _| f(buf))
+}
+
+/// Converts the environment to the env array expected by libuv
+fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
+    let env = match env {
+        Some(s) => s,
+        None => { return f(ptr::null()); }
+    };
+    // As with argv, create some temporary storage and then the actual array
+    let mut envp = vec::with_capacity(env.len());
+    for &(ref key, ref value) in env.iter() {
+        envp.push(fmt!("%s=%s", *key, *value).to_c_str());
+    }
+    let mut c_envp = vec::with_capacity(envp.len() + 1);
+    for s in envp.iter() {
+        c_envp.push(s.with_ref(|p| p));
+    }
+    c_envp.push(ptr::null());
+    c_envp.as_imm_buf(|buf, _| f(buf))
+}
+
+impl uv::NativeHandle<*uvll::uv_process_t> for Process {
+    fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
+        Process(handle)
+    }
+    fn native_handle(&self) -> *uvll::uv_process_t {
+        match self { &Process(ptr) => ptr }
+    }
+}
index e8af0c749a04dbfc49a9175792bf9136105a2cbd..ed6e16c8fdb09046b0cbb4966a1cb37744735fa4 100644 (file)
@@ -13,7 +13,7 @@
 use cast;
 use cell::Cell;
 use clone::Clone;
-use libc::{c_int, c_uint, c_void};
+use libc::{c_int, c_uint, c_void, pid_t};
 use ops::Drop;
 use option::*;
 use ptr;
@@ -22,6 +22,8 @@
 use rt::io::IoError;
 use rt::io::net::ip::{SocketAddr, IpAddr};
 use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd};
+use rt::io::process::ProcessConfig;
+use rt::kill::BlockedTask;
 use rt::local::Local;
 use rt::rtio::*;
 use rt::sched::{Scheduler, SchedHandle};
 use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs};
 use rt::uv::addrinfo::GetAddrInfoRequest;
 use unstable::sync::Exclusive;
+use path::Path;
 use super::super::io::support::PathLike;
 use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY,
-          S_IRUSR, S_IWUSR};
+          S_IRUSR, S_IWUSR, S_IRWXU};
 use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
-            CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite};
+             CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite,
+             FileStat};
 use task;
 
 #[cfg(test)] use container::Container;
@@ -187,12 +191,8 @@ pub fn new() -> UvEventLoop {
 }
 
 impl Drop for UvEventLoop {
-    fn drop(&self) {
-        // XXX: Need mutable finalizer
-        let this = unsafe {
-            transmute::<&UvEventLoop, &mut UvEventLoop>(self)
-        };
-        this.uvio.uv_loop().close();
+    fn drop(&mut self) {
+        self.uvio.uv_loop().close();
     }
 }
 
@@ -351,7 +351,7 @@ fn fire(&mut self) { self.async.send() }
 }
 
 impl Drop for UvRemoteCallback {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             let this: &mut UvRemoteCallback = cast::transmute_mut(self);
             do this.exit_flag.with |should_exit| {
@@ -411,6 +411,36 @@ pub fn uv_loop<'a>(&'a mut self) -> &'a mut Loop {
     }
 }
 
+/// Helper for a variety of simple uv_fs_* functions that
+/// have no ret val
+fn uv_fs_helper<P: PathLike>(loop_: &mut Loop, path: &P,
+                             cb: ~fn(&mut FsRequest, &mut Loop, &P,
+                                     ~fn(&FsRequest, Option<UvError>)))
+        -> Result<(), IoError> {
+    let result_cell = Cell::new_empty();
+    let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+    let path_cell = Cell::new(path);
+    do task::unkillable { // FIXME(#8674)
+        let scheduler: ~Scheduler = Local::take();
+        let mut new_req = FsRequest::new();
+        do scheduler.deschedule_running_task_and_then |_, task| {
+            let task_cell = Cell::new(task);
+            let path = path_cell.take();
+            do cb(&mut new_req, loop_, path) |_, err| {
+                let res = match err {
+                    None => Ok(()),
+                    Some(err) => Err(uv_error_to_io_error(err))
+                };
+                unsafe { (*result_cell_ptr).put_back(res); }
+                let scheduler: ~Scheduler = Local::take();
+                scheduler.resume_blocked_task_immediately(task_cell.take());
+            };
+        }
+    }
+    assert!(!result_cell.is_empty());
+    return result_cell.take();
+}
+
 impl IoFactory for UvIoFactory {
     // Connect to an address and return a new stream
     // NB: This blocks the task waiting on the connection.
@@ -516,7 +546,6 @@ fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError> {
 
     fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream {
         let loop_ = Loop {handle: self.uv_loop().native_handle()};
-        let fd = file::FileDescriptor(fd);
         let home = get_handle_to_current_scheduler!();
         ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream
     }
@@ -547,15 +576,16 @@ fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
         let path_cell = Cell::new(path);
         do task::unkillable { // FIXME(#8674)
             let scheduler: ~Scheduler = Local::take();
+            let open_req = file::FsRequest::new();
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
                 let path = path_cell.take();
-                do file::FsRequest::open(self.uv_loop(), path, flags as int, create_mode as int)
+                do open_req.open(self.uv_loop(), path, flags as int, create_mode as int)
                       |req,err| {
                     if err.is_none() {
                         let loop_ = Loop {handle: req.get_loop().native_handle()};
                         let home = get_handle_to_current_scheduler!();
-                        let fd = file::FileDescriptor(req.get_result());
+                        let fd = req.get_result() as c_int;
                         let fs = ~UvFileStream::new(
                             loop_, fd, true, home) as ~RtioFileStream;
                         let res = Ok(fs);
@@ -570,31 +600,56 @@ fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
                     }
                 };
             };
-        }
+        };
         assert!(!result_cell.is_empty());
         return result_cell.take();
     }
 
     fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+        do uv_fs_helper(self.uv_loop(), path) |unlink_req, l, p, cb| {
+            do unlink_req.unlink(l, p) |req, err| {
+                cb(req, err)
+            };
+        }
+    }
+    fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError> {
+        use str::StrSlice;
         let result_cell = Cell::new_empty();
-        let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+        let result_cell_ptr: *Cell<Result<FileStat,
+                                           IoError>> = &result_cell;
         let path_cell = Cell::new(path);
         do task::unkillable { // FIXME(#8674)
             let scheduler: ~Scheduler = Local::take();
+            let stat_req = file::FsRequest::new();
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
                 let path = path_cell.take();
-                do file::FsRequest::unlink(self.uv_loop(), path) |_, err| {
+                let path_str = path.path_as_str(|p| p.to_owned());
+                do stat_req.stat(self.uv_loop(), path)
+                      |req,err| {
                     let res = match err {
-                        None => Ok(()),
-                        Some(err) => Err(uv_error_to_io_error(err))
+                        None => {
+                            let stat = req.get_stat();
+                            Ok(FileStat {
+                                path: Path(path_str),
+                                is_file: stat.is_file(),
+                                is_dir: stat.is_dir(),
+                                size: stat.st_size,
+                                created: stat.st_ctim.tv_sec as u64,
+                                modified: stat.st_mtim.tv_sec as u64,
+                                accessed: stat.st_atim.tv_sec as u64
+                            })
+                        },
+                        Some(e) => {
+                            Err(uv_error_to_io_error(e))
+                        }
                     };
                     unsafe { (*result_cell_ptr).put_back(res); }
                     let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 };
             };
-        }
+        };
         assert!(!result_cell.is_empty());
         return result_cell.take();
     }
@@ -629,6 +684,117 @@ fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> {
         assert!(!result_cell.is_empty());
         return result_cell.take();
     }
+    fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+        let mode = S_IRWXU as int;
+        do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| {
+            do mkdir_req.mkdir(l, p, mode as int) |req, err| {
+                cb(req, err)
+            };
+        }
+    }
+    fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+        do uv_fs_helper(self.uv_loop(), path) |rmdir_req, l, p, cb| {
+            do rmdir_req.rmdir(l, p) |req, err| {
+                cb(req, err)
+            };
+        }
+    }
+    fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
+        Result<~[Path], IoError> {
+        use str::StrSlice;
+        let result_cell = Cell::new_empty();
+        let result_cell_ptr: *Cell<Result<~[Path],
+                                           IoError>> = &result_cell;
+        let path_cell = Cell::new(path);
+        do task::unkillable { // FIXME(#8674)
+            let scheduler: ~Scheduler = Local::take();
+            let stat_req = file::FsRequest::new();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task_cell = Cell::new(task);
+                let path = path_cell.take();
+                let path_str = path.path_as_str(|p| p.to_owned());
+                do stat_req.readdir(self.uv_loop(), path, flags)
+                      |req,err| {
+                    let res = match err {
+                        None => {
+                            let rel_paths = req.get_paths();
+                            let mut paths = ~[];
+                            for r in rel_paths.iter() {
+                                paths.push(Path(path_str+"/"+*r));
+                            }
+                            Ok(paths)
+                        },
+                        Some(e) => {
+                            Err(uv_error_to_io_error(e))
+                        }
+                    };
+                    unsafe { (*result_cell_ptr).put_back(res); }
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task_cell.take());
+                };
+            };
+        };
+        assert!(!result_cell.is_empty());
+        return result_cell.take();
+    }
+
+    fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError> {
+        let home = get_handle_to_current_scheduler!();
+        Ok(~UvUnboundPipe { pipe: Pipe::new(self.uv_loop(), ipc), home: home })
+    }
+
+    fn spawn(&mut self, config: ProcessConfig)
+            -> Result<(~RtioProcessObject, ~[Option<RtioPipeObject>]), IoError>
+    {
+        // Sadly, we must create the UvProcess before we actually call uv_spawn
+        // so that the exit_cb can close over it and notify it when the process
+        // has exited.
+        let mut ret = ~UvProcess {
+            process: Process::new(),
+            home: None,
+            exit_status: None,
+            term_signal: None,
+            exit_error: None,
+            descheduled: None,
+        };
+        let ret_ptr = unsafe {
+            *cast::transmute::<&~UvProcess, &*mut UvProcess>(&ret)
+        };
+
+        // The purpose of this exit callback is to record the data about the
+        // exit and then wake up the task which may be waiting for the process
+        // to exit. This is all performed in the current io-loop, and the
+        // implementation of UvProcess ensures that reading these fields always
+        // occurs on the current io-loop.
+        let exit_cb: ExitCallback = |_, exit_status, term_signal, error| {
+            unsafe {
+                assert!((*ret_ptr).exit_status.is_none());
+                (*ret_ptr).exit_status = Some(exit_status);
+                (*ret_ptr).term_signal = Some(term_signal);
+                (*ret_ptr).exit_error = error;
+                match (*ret_ptr).descheduled.take() {
+                    Some(task) => {
+                        let scheduler: ~Scheduler = Local::take();
+                        scheduler.resume_blocked_task_immediately(task);
+                    }
+                    None => {}
+                }
+            }
+        };
+
+        match ret.process.spawn(self.uv_loop(), config, exit_cb) {
+            Ok(io) => {
+                // Only now do we actually get a handle to this scheduler.
+                ret.home = Some(get_handle_to_current_scheduler!());
+                Ok((ret, io))
+            }
+            Err(uverr) => {
+                // We still need to close the process handle we created, but
+                // that's taken care for us in the destructor of UvProcess
+                Err(uv_error_to_io_error(uverr))
+            }
+        }
+    }
 }
 
 pub struct UvTcpListener {
@@ -647,10 +813,8 @@ fn new(watcher: TcpWatcher, home: SchedHandle) -> UvTcpListener {
 }
 
 impl Drop for UvTcpListener {
-    fn drop(&self) {
-        // XXX need mutable finalizer
-        let self_ = unsafe { transmute::<&UvTcpListener, &mut UvTcpListener>(self) };
-        do self_.home_for_io_with_sched |self_, scheduler| {
+    fn drop(&mut self) {
+        do self.home_for_io_with_sched |self_, scheduler| {
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task = Cell::new(task);
                 do self_.watcher.as_stream().close {
@@ -752,6 +916,126 @@ fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
     }
 }
 
+fn read_stream(mut watcher: StreamWatcher,
+               scheduler: ~Scheduler,
+               buf: &mut [u8]) -> Result<uint, IoError> {
+    let result_cell = Cell::new_empty();
+    let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
+
+    let buf_ptr: *&mut [u8] = &buf;
+    do scheduler.deschedule_running_task_and_then |_sched, task| {
+        let task_cell = Cell::new(task);
+        // XXX: We shouldn't reallocate these callbacks every
+        // call to read
+        let alloc: AllocCallback = |_| unsafe {
+            slice_to_uv_buf(*buf_ptr)
+        };
+        do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
+
+            // Stop reading so that no read callbacks are
+            // triggered before the user calls `read` again.
+            // XXX: Is there a performance impact to calling
+            // stop here?
+            watcher.read_stop();
+
+            let result = if status.is_none() {
+                assert!(nread >= 0);
+                Ok(nread as uint)
+            } else {
+                Err(uv_error_to_io_error(status.unwrap()))
+            };
+
+            unsafe { (*result_cell_ptr).put_back(result); }
+
+            let scheduler: ~Scheduler = Local::take();
+            scheduler.resume_blocked_task_immediately(task_cell.take());
+        }
+    }
+
+    assert!(!result_cell.is_empty());
+    result_cell.take()
+}
+
+fn write_stream(mut watcher: StreamWatcher,
+                scheduler: ~Scheduler,
+                buf: &[u8]) -> Result<(), IoError> {
+    let result_cell = Cell::new_empty();
+    let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+    let buf_ptr: *&[u8] = &buf;
+    do scheduler.deschedule_running_task_and_then |_, task| {
+        let task_cell = Cell::new(task);
+        let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
+        do watcher.write(buf) |_watcher, status| {
+            let result = if status.is_none() {
+                Ok(())
+            } else {
+                Err(uv_error_to_io_error(status.unwrap()))
+            };
+
+            unsafe { (*result_cell_ptr).put_back(result); }
+
+            let scheduler: ~Scheduler = Local::take();
+            scheduler.resume_blocked_task_immediately(task_cell.take());
+        }
+    }
+
+    assert!(!result_cell.is_empty());
+    result_cell.take()
+}
+
+pub struct UvUnboundPipe {
+    pipe: Pipe,
+    home: SchedHandle,
+}
+
+impl HomingIO for UvUnboundPipe {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvUnboundPipe {
+    fn drop(&mut self) {
+        do self.home_for_io |self_| {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task_cell = Cell::new(task);
+                do self_.pipe.close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task_cell.take());
+                }
+            }
+        }
+    }
+}
+
+impl UvUnboundPipe {
+    pub unsafe fn bind(~self) -> UvPipeStream {
+        UvPipeStream { inner: self }
+    }
+}
+
+pub struct UvPipeStream {
+    priv inner: ~UvUnboundPipe,
+}
+
+impl UvPipeStream {
+    pub fn new(inner: ~UvUnboundPipe) -> UvPipeStream {
+        UvPipeStream { inner: inner }
+    }
+}
+
+impl RtioPipe for UvPipeStream {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
+        do self.inner.home_for_io_with_sched |self_, scheduler| {
+            read_stream(self_.pipe.as_stream(), scheduler, buf)
+        }
+    }
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+        do self.inner.home_for_io_with_sched |self_, scheduler| {
+            write_stream(self_.pipe.as_stream(), scheduler, buf)
+        }
+    }
+}
+
 pub struct UvTcpStream {
     watcher: TcpWatcher,
     home: SchedHandle,
@@ -762,10 +1046,8 @@ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
 }
 
 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| {
+    fn drop(&mut self) {
+        do self.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 {
@@ -788,70 +1070,13 @@ fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
 impl RtioTcpStream for UvTcpStream {
     fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
         do self.home_for_io_with_sched |self_, scheduler| {
-            let result_cell = Cell::new_empty();
-            let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
-
-            let buf_ptr: *&mut [u8] = &buf;
-            do scheduler.deschedule_running_task_and_then |_sched, task| {
-                let task_cell = Cell::new(task);
-                // XXX: We shouldn't reallocate these callbacks every
-                // call to read
-                let alloc: AllocCallback = |_| unsafe {
-                    slice_to_uv_buf(*buf_ptr)
-                };
-                let mut watcher = self_.watcher.as_stream();
-                do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
-
-                    // Stop reading so that no read callbacks are
-                    // triggered before the user calls `read` again.
-                    // XXX: Is there a performance impact to calling
-                    // stop here?
-                    watcher.read_stop();
-
-                    let result = if status.is_none() {
-                        assert!(nread >= 0);
-                        Ok(nread as uint)
-                    } else {
-                        Err(uv_error_to_io_error(status.unwrap()))
-                    };
-
-                    unsafe { (*result_cell_ptr).put_back(result); }
-
-                    let scheduler: ~Scheduler = Local::take();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                }
-            }
-
-            assert!(!result_cell.is_empty());
-            result_cell.take()
+            read_stream(self_.watcher.as_stream(), scheduler, buf)
         }
     }
 
     fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
         do self.home_for_io_with_sched |self_, scheduler| {
-            let result_cell = Cell::new_empty();
-            let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
-            let buf_ptr: *&[u8] = &buf;
-            do scheduler.deschedule_running_task_and_then |_, task| {
-                let task_cell = Cell::new(task);
-                let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
-                let mut watcher = self_.watcher.as_stream();
-                do watcher.write(buf) |_watcher, status| {
-                    let result = if status.is_none() {
-                        Ok(())
-                    } else {
-                        Err(uv_error_to_io_error(status.unwrap()))
-                    };
-
-                    unsafe { (*result_cell_ptr).put_back(result); }
-
-                    let scheduler: ~Scheduler = Local::take();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                }
-            }
-
-            assert!(!result_cell.is_empty());
-            result_cell.take()
+            write_stream(self_.watcher.as_stream(), scheduler, buf)
         }
     }
 
@@ -921,10 +1146,8 @@ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
 }
 
 impl Drop for UvUdpSocket {
-    fn drop(&self) {
-        // XXX need mutable finalizer
-        let this = unsafe { transmute::<&UvUdpSocket, &mut UvUdpSocket>(self) };
-        do this.home_for_io_with_sched |self_, scheduler| {
+    fn drop(&mut self) {
+        do self.home_for_io_with_sched |self_, scheduler| {
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
                 do self_.watcher.close {
@@ -1139,9 +1362,8 @@ fn new(w: timer::TimerWatcher, home: SchedHandle) -> UvTimer {
 }
 
 impl Drop for UvTimer {
-    fn drop(&self) {
-        let self_ = unsafe { transmute::<&UvTimer, &mut UvTimer>(self) };
-        do self_.home_for_io_with_sched |self_, scheduler| {
+    fn drop(&mut self) {
+        do self.home_for_io_with_sched |self_, scheduler| {
             rtdebug!("closing UvTimer");
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
@@ -1173,7 +1395,7 @@ fn sleep(&mut self, msecs: u64) {
 
 pub struct UvFileStream {
     loop_: Loop,
-    fd: file::FileDescriptor,
+    fd: c_int,
     close_on_drop: bool,
     home: SchedHandle
 }
@@ -1183,7 +1405,7 @@ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
 }
 
 impl UvFileStream {
-    fn new(loop_: Loop, fd: file::FileDescriptor, close_on_drop: bool,
+    fn new(loop_: Loop, fd: c_int, close_on_drop: bool,
            home: SchedHandle) -> UvFileStream {
         UvFileStream {
             loop_: loop_,
@@ -1200,7 +1422,8 @@ fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError> {
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
                 let task_cell = Cell::new(task);
-                do self_.fd.read(&self_.loop_, buf, offset) |req, uverr| {
+                let read_req = file::FsRequest::new();
+                do read_req.read(&self_.loop_, self_.fd, buf, offset) |req, uverr| {
                     let res = match uverr  {
                         None => Ok(req.get_result() as int),
                         Some(err) => Err(uv_error_to_io_error(err))
@@ -1221,7 +1444,8 @@ fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> {
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
                 let task_cell = Cell::new(task);
-                do self_.fd.write(&self_.loop_, buf, offset) |_, uverr| {
+                let write_req = file::FsRequest::new();
+                do write_req.write(&self_.loop_, self_.fd, buf, offset) |_, uverr| {
                     let res = match uverr  {
                         None => Ok(()),
                         Some(err) => Err(uv_error_to_io_error(err))
@@ -1238,7 +1462,7 @@ fn seek_common(&mut self, pos: i64, whence: c_int) ->
         Result<u64, IoError>{
         #[fixed_stack_segment]; #[inline(never)];
         unsafe {
-            match lseek((*self.fd), pos as off_t, whence) {
+            match lseek(self.fd, pos as off_t, whence) {
                 -1 => {
                     Err(IoError {
                         kind: OtherIoError,
@@ -1253,13 +1477,13 @@ fn seek_common(&mut self, pos: i64, whence: c_int) ->
 }
 
 impl Drop for UvFileStream {
-    fn drop(&self) {
-        let self_ = unsafe { transmute::<&UvFileStream, &mut UvFileStream>(self) };
+    fn drop(&mut self) {
         if self.close_on_drop {
-            do self_.home_for_io_with_sched |self_, scheduler| {
+            do self.home_for_io_with_sched |self_, scheduler| {
                 do scheduler.deschedule_running_task_and_then |_, task| {
                     let task_cell = Cell::new(task);
-                    do self_.fd.close(&self.loop_) |_,_| {
+                    let close_req = file::FsRequest::new();
+                    do close_req.close(&self_.loop_, self_.fd) |_,_| {
                         let scheduler: ~Scheduler = Local::take();
                         scheduler.resume_blocked_task_immediately(task_cell.take());
                     };
@@ -1302,6 +1526,86 @@ 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(&mut self) {
+        let close = |self_: &mut UvProcess| {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task = Cell::new(task);
+                do self_.process.close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task.take());
+                }
+            }
+        };
+
+        // If home is none, then this process never actually successfully
+        // spawned, so there's no need to switch event loops
+        if self.home.is_none() {
+            close(self)
+        } else {
+            self.home_for_io(close)
+        }
+    }
+}
+
+impl RtioProcess for UvProcess {
+    fn id(&self) -> pid_t {
+        self.process.pid()
+    }
+
+    fn kill(&mut self, signal: int) -> Result<(), IoError> {
+        do self.home_for_io |self_| {
+            match self_.process.kill(signal) {
+                Ok(()) => Ok(()),
+                Err(uverr) => Err(uv_error_to_io_error(uverr))
+            }
+        }
+    }
+
+    fn wait(&mut self) -> int {
+        // Make sure (on the home scheduler) that we have an exit status listed
+        do self.home_for_io |self_| {
+            match self_.exit_status {
+                Some(*) => {}
+                None => {
+                    // If there's no exit code previously listed, then the
+                    // process's exit callback has yet to be invoked. We just
+                    // need to deschedule ourselves and wait to be reawoken.
+                    let scheduler: ~Scheduler = Local::take();
+                    do scheduler.deschedule_running_task_and_then |_, task| {
+                        assert!(self_.descheduled.is_none());
+                        self_.descheduled = Some(task);
+                    }
+                    assert!(self_.exit_status.is_some());
+                }
+            }
+        }
+
+        self.exit_status.unwrap()
+    }
+}
+
 #[test]
 fn test_simple_io_no_connect() {
     do run_in_mt_newsched_task {
@@ -1740,7 +2044,6 @@ fn test_read_read_read() {
 }
 
 #[test]
-#[ignore(cfg(windows))] // FIXME #8816
 fn test_udp_twice() {
     do run_in_mt_newsched_task {
         let server_addr = next_test_ip4();
@@ -1892,7 +2195,6 @@ fn file_test_uvio_full_simple_impl() {
 }
 
 #[test]
-#[ignore(cfg(windows))] // FIXME #8816
 fn file_test_uvio_full_simple() {
     do run_in_mt_newsched_task {
         file_test_uvio_full_simple_impl();
index 5bf04110abf45c19b0971d0db1d3238d429418b1..790bf53a291d9b526c41df6d0682cfc1a673d142 100644 (file)
@@ -31,7 +31,6 @@
 
 use c_str::ToCStr;
 use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t};
-#[cfg(not(stage0))]
 use libc::ssize_t;
 use libc::{malloc, free};
 use libc;
@@ -67,6 +66,19 @@ pub mod errors {
     pub static EPIPE: c_int = -libc::EPIPE;
 }
 
+pub static PROCESS_SETUID: c_int = 1 << 0;
+pub static PROCESS_SETGID: c_int = 1 << 1;
+pub static PROCESS_WINDOWS_VERBATIM_ARGUMENTS: c_int = 1 << 2;
+pub static PROCESS_DETACHED: c_int = 1 << 3;
+pub static PROCESS_WINDOWS_HIDE: c_int = 1 << 4;
+
+pub static STDIO_IGNORE: c_int = 0x00;
+pub static STDIO_CREATE_PIPE: c_int = 0x01;
+pub static STDIO_INHERIT_FD: c_int = 0x02;
+pub static STDIO_INHERIT_STREAM: c_int = 0x04;
+pub static STDIO_READABLE_PIPE: c_int = 0x10;
+pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
+
 // see libuv/include/uv-unix.h
 #[cfg(unix)]
 pub struct uv_buf_t {
@@ -81,6 +93,26 @@ pub struct uv_buf_t {
     base: *u8,
 }
 
+pub struct uv_process_options_t {
+    exit_cb: uv_exit_cb,
+    file: *libc::c_char,
+    args: **libc::c_char,
+    env: **libc::c_char,
+    cwd: *libc::c_char,
+    flags: libc::c_uint,
+    stdio_count: libc::c_int,
+    stdio: *uv_stdio_container_t,
+    uid: uv_uid_t,
+    gid: uv_gid_t,
+}
+
+// These fields are private because they must be interfaced with through the
+// functions below.
+pub struct uv_stdio_container_t {
+    priv flags: libc::c_int,
+    priv stream: *uv_stream_t,
+}
+
 pub type uv_handle_t = c_void;
 pub type uv_loop_t = c_void;
 pub type uv_idle_t = c_void;
@@ -95,77 +127,95 @@ pub struct uv_buf_t {
 pub type uv_fs_t = c_void;
 pub type uv_udp_send_t = c_void;
 pub type uv_getaddrinfo_t = c_void;
+pub type uv_process_t = c_void;
+pub type uv_pipe_t = c_void;
+
+pub struct uv_timespec_t {
+    tv_sec: libc::c_long,
+    tv_nsec: libc::c_long
+}
+
+pub struct uv_stat_t {
+    st_dev: libc::uint64_t,
+    st_mode: libc::uint64_t,
+    st_nlink: libc::uint64_t,
+    st_uid: libc::uint64_t,
+    st_gid: libc::uint64_t,
+    st_rdev: libc::uint64_t,
+    st_ino: libc::uint64_t,
+    st_size: libc::uint64_t,
+    st_blksize: libc::uint64_t,
+    st_blocks: libc::uint64_t,
+    st_flags: libc::uint64_t,
+    st_gen: libc::uint64_t,
+    st_atim: uv_timespec_t,
+    st_mtim: uv_timespec_t,
+    st_ctim: uv_timespec_t,
+    st_birthtim: uv_timespec_t
+}
+
+impl uv_stat_t {
+    pub fn new() -> uv_stat_t {
+        uv_stat_t {
+            st_dev: 0,
+            st_mode: 0,
+            st_nlink: 0,
+            st_uid: 0,
+            st_gid: 0,
+            st_rdev: 0,
+            st_ino: 0,
+            st_size: 0,
+            st_blksize: 0,
+            st_blocks: 0,
+            st_flags: 0,
+            st_gen: 0,
+            st_atim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
+            st_mtim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
+            st_ctim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
+            st_birthtim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 }
+        }
+    }
+    pub fn is_file(&self) -> bool {
+        ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFREG as libc::uint64_t
+    }
+    pub fn is_dir(&self) -> bool {
+        ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFDIR as libc::uint64_t
+    }
+}
 
-#[cfg(stage0)]
-pub type uv_idle_cb = *u8;
-#[cfg(stage0)]
-pub type uv_alloc_cb = *u8;
-#[cfg(stage0)]
-pub type uv_read_cb = *u8;
-#[cfg(stage0)]
-pub type uv_udp_send_cb = *u8;
-#[cfg(stage0)]
-pub type uv_udp_recv_cb = *u8;
-#[cfg(stage0)]
-pub type uv_close_cb = *u8;
-#[cfg(stage0)]
-pub type uv_walk_cb = *u8;
-#[cfg(stage0)]
-pub type uv_async_cb = *u8;
-#[cfg(stage0)]
-pub type uv_connect_cb = *u8;
-#[cfg(stage0)]
-pub type uv_connection_cb = *u8;
-#[cfg(stage0)]
-pub type uv_timer_cb = *u8;
-#[cfg(stage0)]
-pub type uv_write_cb = *u8;
-#[cfg(stage0)]
-pub type uv_getaddrinfo_cb = *u8;
-
-#[cfg(not(stage0))]
 pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
                                     status: c_int);
-#[cfg(not(stage0))]
 pub type uv_alloc_cb = extern "C" fn(stream: *uv_stream_t,
                                      suggested_size: size_t) -> uv_buf_t;
-#[cfg(not(stage0))]
 pub type uv_read_cb = extern "C" fn(stream: *uv_stream_t,
                                     nread: ssize_t,
                                     buf: uv_buf_t);
-#[cfg(not(stage0))]
 pub type uv_udp_send_cb = extern "C" fn(req: *uv_udp_send_t,
                                         status: c_int);
-#[cfg(not(stage0))]
 pub type uv_udp_recv_cb = extern "C" fn(handle: *uv_udp_t,
                                         nread: ssize_t,
                                         buf: uv_buf_t,
                                         addr: *sockaddr,
                                         flags: c_uint);
-#[cfg(not(stage0))]
 pub type uv_close_cb = extern "C" fn(handle: *uv_handle_t);
-#[cfg(not(stage0))]
 pub type uv_walk_cb = extern "C" fn(handle: *uv_handle_t,
                                     arg: *c_void);
-#[cfg(not(stage0))]
 pub type uv_async_cb = extern "C" fn(handle: *uv_async_t,
                                      status: c_int);
-#[cfg(not(stage0))]
 pub type uv_connect_cb = extern "C" fn(handle: *uv_connect_t,
                                        status: c_int);
-#[cfg(not(stage0))]
 pub type uv_connection_cb = extern "C" fn(handle: *uv_connection_t,
                                           status: c_int);
-#[cfg(not(stage0))]
 pub type uv_timer_cb = extern "C" fn(handle: *uv_timer_t,
                                      status: c_int);
-#[cfg(not(stage0))]
 pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
                                      status: c_int);
-#[cfg(not(stage0))]
 pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t,
                                            status: c_int,
                                            res: *addrinfo);
+pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t,
+                                    exit_status: c_int,
+                                    term_signal: c_int);
 
 pub type sockaddr = c_void;
 pub type sockaddr_in = c_void;
@@ -214,6 +264,11 @@ pub struct addrinfo {
     ai_next: *addrinfo
 }
 
+#[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
+#[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
+#[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
+#[cfg(windows)] pub type uv_gid_t = libc::c_uchar;
+
 #[deriving(Eq)]
 pub enum uv_handle_type {
     UV_UNKNOWN_HANDLE,
@@ -237,6 +292,7 @@ pub enum uv_handle_type {
     UV_HANDLE_TYPE_MAX
 }
 
+#[cfg(unix)]
 #[deriving(Eq)]
 pub enum uv_req_type {
     UV_UNKNOWN_REQ,
@@ -251,6 +307,31 @@ pub enum uv_req_type {
     UV_REQ_TYPE_MAX
 }
 
+// uv_req_type may have additional fields defined by UV_REQ_TYPE_PRIVATE.
+// See UV_REQ_TYPE_PRIVATE at libuv/include/uv-win.h
+#[cfg(windows)]
+#[deriving(Eq)]
+pub enum uv_req_type {
+    UV_UNKNOWN_REQ,
+    UV_REQ,
+    UV_CONNECT,
+    UV_WRITE,
+    UV_SHUTDOWN,
+    UV_UDP_SEND,
+    UV_FS,
+    UV_WORK,
+    UV_GETADDRINFO,
+    UV_ACCEPT,
+    UV_FS_EVENT_REQ,
+    UV_POLL_REQ,
+    UV_PROCESS_EXIT,
+    UV_READ,
+    UV_UDP_RECV,
+    UV_WAKEUP,
+    UV_SIGNAL_REQ,
+    UV_REQ_TYPE_MAX
+}
+
 #[deriving(Eq)]
 pub enum uv_membership {
     UV_LEAVE_GROUP,
@@ -298,10 +379,8 @@ fn handle_sanity_check() {
 }
 
 #[test]
-#[ignore(cfg(windows))] // FIXME #8817
-#[fixed_stack_segment]
-#[inline(never)]
 fn request_sanity_check() {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
     }
@@ -712,18 +791,95 @@ pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int,
 
     rust_uv_fs_close(loop_ptr, req, fd, cb)
 }
+pub unsafe fn fs_stat(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_fs_stat(loop_ptr, req, path, cb)
+}
+pub unsafe fn fs_fstat(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_fs_fstat(loop_ptr, req, fd, cb)
+}
+pub unsafe fn fs_mkdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, mode: int,
+                cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_fs_mkdir(loop_ptr, req, path, mode as c_int, cb)
+}
+pub unsafe fn fs_rmdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
+                cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_fs_rmdir(loop_ptr, req, path, cb)
+}
+pub unsafe fn fs_readdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
+                flags: c_int, cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_fs_readdir(loop_ptr, req, path, flags, cb)
+}
+pub unsafe fn populate_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t) {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_populate_uv_stat(req_in, stat_out)
+}
 pub unsafe fn fs_req_cleanup(req: *uv_fs_t) {
     #[fixed_stack_segment]; #[inline(never)];
 
     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)];
 
     rust_uv_get_result_from_fs_req(req)
 }
+pub unsafe fn get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_get_ptr_from_fs_req(req)
+}
 pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
     #[fixed_stack_segment]; #[inline(never)];
 
@@ -904,8 +1060,18 @@ fn rust_uv_fs_read(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
                        buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
     fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
                         cb: *u8) -> c_int;
+    fn rust_uv_fs_stat(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int;
+    fn rust_uv_fs_fstat(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int;
+    fn rust_uv_fs_mkdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
+                        mode: c_int, cb: *u8) -> c_int;
+    fn rust_uv_fs_rmdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
+                        cb: *u8) -> c_int;
+    fn rust_uv_fs_readdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
+                        flags: c_int, cb: *u8) -> c_int;
     fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
+    fn rust_uv_populate_uv_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t);
     fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
+    fn rust_uv_get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void;
     fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
     fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t;
 
@@ -925,4 +1091,13 @@ fn rust_uv_getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t,
                            node: *c_char, service: *c_char,
                            hints: *addrinfo) -> c_int;
     fn rust_uv_freeaddrinfo(ai: *addrinfo);
+    fn rust_uv_spawn(loop_ptr: *c_void, outptr: *uv_process_t,
+                     options: uv_process_options_t) -> c_int;
+    fn rust_uv_process_kill(p: *uv_process_t, signum: c_int) -> c_int;
+    fn rust_uv_process_pid(p: *uv_process_t) -> c_int;
+    fn rust_set_stdio_container_flags(c: *uv_stdio_container_t, flags: c_int);
+    fn rust_set_stdio_container_fd(c: *uv_stdio_container_t, fd: c_int);
+    fn rust_set_stdio_container_stream(c: *uv_stdio_container_t,
+                                       stream: *uv_stream_t);
+    fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int;
 }
index 0fe9236253d2ebca0e32da402973ec8b37566cad..362eab17fe70acffa8886547584a1f24451bfac9 100644 (file)
@@ -436,12 +436,9 @@ fn killpid(pid: pid_t, force: bool) {
 }
 
 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();
+    fn drop(&mut self) {
+        self.finish();
+        self.close_outputs();
         free_handle(self.handle);
     }
 }
@@ -646,15 +643,28 @@ fn spawn_process_os(prog: &str, args: &[~str],
     use libc::funcs::bsd44::getdtablesize;
 
     mod rustrt {
-        use libc::c_void;
-
         #[abi = "cdecl"]
         extern {
             pub fn rust_unset_sigprocmask();
-            pub fn rust_set_environ(envp: *c_void);
         }
     }
 
+    #[cfg(windows)]
+    unsafe fn set_environ(_envp: *c_void) {}
+    #[cfg(target_os = "macos")]
+    unsafe fn set_environ(envp: *c_void) {
+        externfn!(fn _NSGetEnviron() -> *mut *c_void);
+
+        *_NSGetEnviron() = envp;
+    }
+    #[cfg(not(target_os = "macos"), not(windows))]
+    unsafe fn set_environ(envp: *c_void) {
+        extern {
+            static mut environ: *c_void;
+        }
+        environ = envp;
+    }
+
     unsafe {
 
         let pid = fork();
@@ -688,7 +698,7 @@ mod rustrt {
 
         do with_envp(env) |envp| {
             if !envp.is_null() {
-                rustrt::rust_set_environ(envp);
+                set_environ(envp);
             }
             do with_argv(prog, args) |argv| {
                 execvp(*argv, argv);
@@ -739,8 +749,6 @@ fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
             let mut tmps = vec::with_capacity(env.len());
 
             for pair in env.iter() {
-                // Use of match here is just to workaround limitations
-                // in the stage0 irrefutable pattern impl.
                 let kv = fmt!("%s=%s", pair.first(), pair.second());
                 tmps.push(kv.to_c_str());
             }
index 05433c4705983b9545f33f6d5a19a2b92e2fe237..e9d5dd416ade329609e1152541185f9dda4f2afd 100644 (file)
@@ -179,14 +179,8 @@ 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;
index ccb39c605eb062bd3c4c9ea60fda544483a81dfc..9707d592a2e8524f387ea122f78ec725559398dc 100644 (file)
@@ -22,8 +22,7 @@
 use char::Char;
 use clone::{Clone, DeepClone};
 use container::{Container, Mutable};
-use num::Times;
-use iter::{Iterator, FromIterator, Extendable};
+use iter::{Iterator, FromIterator, Extendable, range};
 use iter::{Filter, AdditiveIterator, Map};
 use iter::{Invert, DoubleEndedIterator, ExactSize};
 use libc;
@@ -33,7 +32,6 @@
 use ptr::RawPtr;
 use to_str::ToStr;
 use uint;
-use unstable::raw::{Repr, Slice};
 use vec;
 use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
 use default::Default;
@@ -185,23 +183,15 @@ impl<'self, S: Str> StrVector for &'self [S] {
     fn concat(&self) -> ~str {
         if self.is_empty() { return ~""; }
 
+        // `len` calculation may overflow but push_str but will check boundaries
         let len = self.iter().map(|s| s.as_slice().len()).sum();
 
-        let mut s = with_capacity(len);
+        let mut result = with_capacity(len);
 
-        unsafe {
-            do s.as_mut_buf |buf, _| {
-                let mut buf = buf;
-                for ss in self.iter() {
-                    do ss.as_slice().as_imm_buf |ssbuf, sslen| {
-                        ptr::copy_memory(buf, ssbuf, sslen);
-                        buf = buf.offset(sslen as int);
-                    }
-                }
-            }
-            raw::set_len(&mut s, len);
+        for s in self.iter() {
+            result.push_str(s.as_slice())
         }
-        s
+        result
     }
 
     /// Concatenate a vector of strings, placing a given separator between each.
@@ -212,34 +202,21 @@ fn connect(&self, sep: &str) -> ~str {
         if sep.is_empty() { return self.concat(); }
 
         // this is wrong without the guarantee that `self` is non-empty
+        // `len` calculation may overflow but push_str but will check boundaries
         let len = sep.len() * (self.len() - 1)
             + self.iter().map(|s| s.as_slice().len()).sum();
-        let mut s = ~"";
+        let mut result = with_capacity(len);
         let mut first = true;
 
-        s.reserve(len);
-
-        unsafe {
-            do s.as_mut_buf |buf, _| {
-                do sep.as_imm_buf |sepbuf, seplen| {
-                    let mut buf = buf;
-                    for ss in self.iter() {
-                        do ss.as_slice().as_imm_buf |ssbuf, sslen| {
-                            if first {
-                                first = false;
-                            } else {
-                                ptr::copy_memory(buf, sepbuf, seplen);
-                                buf = buf.offset(seplen as int);
-                            }
-                            ptr::copy_memory(buf, ssbuf, sslen);
-                            buf = buf.offset(sslen as int);
-                        }
-                    }
-                }
+        for s in self.iter() {
+            if first {
+                first = false;
+            } else {
+                result.push_str(sep);
             }
-            raw::set_len(&mut s, len);
+            result.push_str(s.as_slice());
         }
-        s
+        result
     }
 }
 
@@ -961,7 +938,7 @@ macro_rules! utf8_acc_cont_byte(
 
 /// Unsafe operations
 pub mod raw {
-    use option::Some;
+    use option::{Option, Some};
     use cast;
     use libc;
     use ptr;
@@ -1064,21 +1041,22 @@ pub unsafe fn slice_unchecked<'a>(s: &'a str, begin: uint, end: uint) -> &'a str
         }
     }
 
-    /// Appends a byte to a string. (Not UTF-8 safe).
+    /// Appends a byte to a string.
+    /// The caller must preserve the valid UTF-8 property.
     #[inline]
     pub unsafe fn push_byte(s: &mut ~str, b: u8) {
-        let v: &mut ~[u8] = cast::transmute(s);
-        v.push(b);
+        as_owned_vec(s).push(b)
     }
 
-    /// Appends a vector of bytes to a string. (Not UTF-8 safe).
-    unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
-        let new_len = s.len() + bytes.len();
-        s.reserve_at_least(new_len);
-        for byte in bytes.iter() { push_byte(&mut *s, *byte); }
+    /// Appends a vector of bytes to a string.
+    /// The caller must preserve the valid UTF-8 property.
+    #[inline]
+    pub unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
+        vec::bytes::push_bytes(as_owned_vec(s), bytes);
     }
 
-    /// Removes the last byte from a string and returns it. (Not UTF-8 safe).
+    /// Removes the last byte from a string and returns it.
+    /// The caller must preserve the valid UTF-8 property.
     pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
         let len = s.len();
         assert!((len > 0u));
@@ -1087,7 +1065,8 @@ pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
         return b;
     }
 
-    /// Removes the first byte from a string and returns it. (Not UTF-8 safe).
+    /// Removes the first byte from a string and returns it.
+    /// The caller must preserve the valid UTF-8 property.
     pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
         let len = s.len();
         assert!((len > 0u));
@@ -1096,6 +1075,13 @@ pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
         return b;
     }
 
+    /// Access the str in its vector representation.
+    /// The caller must preserve the valid UTF-8 property when modifying.
+    #[inline]
+    pub unsafe fn as_owned_vec<'a>(s: &'a mut ~str) -> &'a mut ~[u8] {
+        cast::transmute(s)
+    }
+
     /// Sets the length of a string
     ///
     /// This will explicitly set the size of the string, without actually
@@ -1103,8 +1089,35 @@ pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
     /// the string is actually the specified size.
     #[inline]
     pub unsafe fn set_len(s: &mut ~str, new_len: uint) {
-        let v: &mut ~[u8] = cast::transmute(s);
-        vec::raw::set_len(v, new_len)
+        vec::raw::set_len(as_owned_vec(s), new_len)
+    }
+
+    /// Parses a C "multistring", eg windows env values or
+    /// the req->ptr result in a uv_fs_readdir() call.
+    /// Optionally, a `count` can be passed in, limiting the
+    /// parsing to only being done `count`-times.
+    #[inline]
+    pub unsafe fn from_c_multistring(buf: *libc::c_char, count: Option<uint>) -> ~[~str] {
+        #[fixed_stack_segment]; #[inline(never)];
+
+        let mut curr_ptr: uint = buf as uint;
+        let mut result = ~[];
+        let mut ctr = 0;
+        let (limited_count, limit) = match count {
+            Some(limit) => (true, limit),
+            None => (false, 0)
+        };
+        while(((limited_count && ctr < limit) || !limited_count)
+              && *(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
+            let env_pair = from_c_str(
+                curr_ptr as *libc::c_char);
+            result.push(env_pair);
+            curr_ptr +=
+                libc::strlen(curr_ptr as *libc::c_char) as uint
+                + 1;
+            ctr += 1;
+        }
+        result
     }
 
     /// Sets the length of a string
@@ -1122,6 +1135,25 @@ fn test_from_buf_len() {
         }
     }
 
+    #[test]
+    fn test_str_multistring_parsing() {
+        use option::None;
+        unsafe {
+            let input = bytes!("zero", "\x00", "one", "\x00", "\x00");
+            let ptr = vec::raw::to_ptr(input);
+            let mut result = from_c_multistring(ptr as *libc::c_char, None);
+            assert!(result.len() == 2);
+            let mut ctr = 0;
+            for x in result.iter() {
+                match ctr {
+                    0 => assert_eq!(x, &~"zero"),
+                    1 => assert_eq!(x, &~"one"),
+                    _ => fail!("shouldn't happen!")
+                }
+                ctr += 1;
+            }
+        }
+    }
 }
 
 /*
@@ -2061,22 +2093,11 @@ fn find_str(&self, needle: &str) -> Option<uint> {
 
     /// Given a string, make a new string with repeated copies of it.
     fn repeat(&self, nn: uint) -> ~str {
-        do self.as_imm_buf |buf, len| {
-            let mut ret = with_capacity(nn * len);
-
-            unsafe {
-                do ret.as_mut_buf |rbuf, _len| {
-                    let mut rbuf = rbuf;
-
-                    do nn.times {
-                        ptr::copy_memory(rbuf, buf, len);
-                        rbuf = rbuf.offset(len as int);
-                    }
-                }
-                raw::set_len(&mut ret, nn * len);
-            }
-            ret
+        let mut ret = with_capacity(nn * self.len());
+        for _ in range(0, nn) {
+            ret.push_str(*self);
         }
+        ret
     }
 
     /// Retrieves the first character from a string slice and returns
@@ -2199,36 +2220,16 @@ impl OwnedStr for ~str {
     /// Appends a string slice to the back of a string, without overallocating
     #[inline]
     fn push_str_no_overallocate(&mut self, rhs: &str) {
-        unsafe {
-            let llen = self.len();
-            let rlen = rhs.len();
-            self.reserve(llen + rlen);
-            do self.as_imm_buf |lbuf, _llen| {
-                do rhs.as_imm_buf |rbuf, _rlen| {
-                    let dst = ptr::offset(lbuf, llen as int);
-                    let dst = cast::transmute_mut_unsafe(dst);
-                    ptr::copy_memory(dst, rbuf, rlen);
-                }
-            }
-            raw::set_len(self, llen + rlen);
-        }
+        let new_cap = self.len() + rhs.len();
+        self.reserve(new_cap);
+        self.push_str(rhs);
     }
 
     /// Appends a string slice to the back of a string
     #[inline]
     fn push_str(&mut self, rhs: &str) {
         unsafe {
-            let llen = self.len();
-            let rlen = rhs.len();
-            self.reserve_at_least(llen + rlen);
-            do self.as_imm_buf |lbuf, _llen| {
-                do rhs.as_imm_buf |rbuf, _rlen| {
-                    let dst = ptr::offset(lbuf, llen as int);
-                    let dst = cast::transmute_mut_unsafe(dst);
-                    ptr::copy_memory(dst, rbuf, rlen);
-                }
-            }
-            raw::set_len(self, llen + rlen);
+            raw::push_bytes(self, rhs.as_bytes());
         }
     }
 
@@ -2236,17 +2237,18 @@ fn push_str(&mut self, rhs: &str) {
     #[inline]
     fn push_char(&mut self, c: char) {
         let cur_len = self.len();
-        self.reserve_at_least(cur_len + 4); // may use up to 4 bytes
-
-        // Attempt to not use an intermediate buffer by just pushing bytes
-        // directly onto this string.
+        // may use up to 4 bytes.
         unsafe {
-            let v = self.repr();
-            let len = c.encode_utf8(cast::transmute(Slice {
-                data: ((&(*v).data) as *u8).offset(cur_len as int),
-                len: 4,
-            }));
-            raw::set_len(self, cur_len + len);
+            raw::as_owned_vec(self).reserve_additional(4);
+
+            // Attempt to not use an intermediate buffer by just pushing bytes
+            // directly onto this string.
+            let used = do self.as_mut_buf |buf, _| {
+                do vec::raw::mut_buf_as_slice(buf.offset(cur_len as int), 4) |slc| {
+                    c.encode_utf8(slc)
+                }
+            };
+            raw::set_len(self, cur_len + used);
         }
     }
 
@@ -2306,8 +2308,7 @@ fn append(self, rhs: &str) -> ~str {
     #[inline]
     fn reserve(&mut self, n: uint) {
         unsafe {
-            let v: &mut ~[u8] = cast::transmute(self);
-            (*v).reserve(n);
+            raw::as_owned_vec(self).reserve(n)
         }
     }
 
@@ -2329,7 +2330,7 @@ fn reserve(&mut self, n: uint) {
     /// * n - The number of bytes to reserve space for
     #[inline]
     fn reserve_at_least(&mut self, n: uint) {
-        self.reserve(uint::next_power_of_two(n))
+        self.reserve(uint::next_power_of_two_opt(n).unwrap_or(n))
     }
 
     /// Returns the number of single-byte characters the string can hold without
@@ -2359,8 +2360,9 @@ fn into_bytes(self) -> ~[u8] {
 
     #[inline]
     fn as_mut_buf<T>(&mut self, f: &fn(*mut u8, uint) -> T) -> T {
-        let v: &mut ~[u8] = unsafe { cast::transmute(self) };
-        v.as_mut_buf(f)
+        unsafe {
+            raw::as_owned_vec(self).as_mut_buf(f)
+        }
     }
 }
 
@@ -3912,4 +3914,23 @@ fn bench_with_capacity(bh: &mut BenchHarness) {
             with_capacity(100);
         }
     }
+
+    #[bench]
+    fn bench_push_str(bh: &mut BenchHarness) {
+        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+        do bh.iter {
+            let mut r = ~"";
+            r.push_str(s);
+        }
+    }
+
+    #[bench]
+    fn bench_connect(bh: &mut BenchHarness) {
+        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+        let sep = "→";
+        let v = [s, s, s, s, s, s, s, s, s, s];
+        do bh.iter {
+            assert_eq!(v.connect(sep).len(), s.len() * 10 + sep.len() * 9);
+        }
+    }
 }
index 3d35de0f898153b9e731c709af138eec2b28b6e0..c315c3f9dfc5e1f87257e83e6ebbe29bf43517df 100644 (file)
@@ -14,8 +14,6 @@
 
 use c_str::ToCStr;
 use cast;
-#[cfg(stage0)]
-use io;
 use libc;
 use libc::{c_char, size_t};
 use repr;
@@ -92,7 +90,6 @@ pub fn refcount<T>(t: @T) -> uint {
     }
 }
 
-#[cfg(not(stage0))]
 pub fn log_str<T>(t: &T) -> ~str {
     use rt::io;
     use rt::io::Decorator;
@@ -101,12 +98,6 @@ pub fn log_str<T>(t: &T) -> ~str {
     repr::write_repr(&mut result as &mut io::Writer, t);
     str::from_utf8_owned(result.inner())
 }
-#[cfg(stage0)]
-pub fn log_str<T>(t: &T) -> ~str {
-    do io::with_str_writer |w| {
-        repr::write_repr(w, t)
-    }
-}
 
 /// Trait for initiating task failure.
 pub trait FailWithCause {
index c3a3dc56ce2330de23a04374d359a7de753b0148..58cea8d7d0ecb3b03fbe1f72bd772dd9ae3e68bb 100644 (file)
@@ -319,40 +319,35 @@ pub struct Taskgroup {
 
 impl Drop for Taskgroup {
     // Runs on task exit.
-    fn drop(&self) {
-        unsafe {
-            // FIXME(#4330) Need self by value to get mutability.
-            let this: &mut Taskgroup = transmute(self);
-
-            // If we are failing, the whole taskgroup needs to die.
-            do RuntimeGlue::with_task_handle_and_failing |me, failing| {
-                if failing {
-                    for x in this.notifier.mut_iter() {
-                        x.failed = true;
-                    }
-                    // Take everybody down with us. After this point, every
-                    // other task in the group will see 'tg' as none, which
-                    // indicates the whole taskgroup is failing (and forbids
-                    // new spawns from succeeding).
-                    let tg = do access_group(&self.tasks) |tg| { tg.take() };
-                    // It's safe to send kill signals outside the lock, because
-                    // we have a refcount on all kill-handles in the group.
-                    kill_taskgroup(tg, me);
-                } else {
-                    // Remove ourselves from the group(s).
-                    do access_group(&self.tasks) |tg| {
-                        leave_taskgroup(tg, me, true);
-                    }
+    fn drop(&mut self) {
+        // If we are failing, the whole taskgroup needs to die.
+        do RuntimeGlue::with_task_handle_and_failing |me, failing| {
+            if failing {
+                for x in self.notifier.mut_iter() {
+                    x.failed = true;
+                }
+                // Take everybody down with us. After this point, every
+                // other task in the group will see 'tg' as none, which
+                // indicates the whole taskgroup is failing (and forbids
+                // new spawns from succeeding).
+                let tg = do access_group(&self.tasks) |tg| { tg.take() };
+                // It's safe to send kill signals outside the lock, because
+                // we have a refcount on all kill-handles in the group.
+                kill_taskgroup(tg, me);
+            } else {
+                // Remove ourselves from the group(s).
+                do access_group(&self.tasks) |tg| {
+                    leave_taskgroup(tg, me, true);
                 }
-                // It doesn't matter whether this happens before or after dealing
-                // with our own taskgroup, so long as both happen before we die.
-                // We remove ourself from every ancestor we can, so no cleanup; no
-                // break.
-                do each_ancestor(&mut this.ancestors, |_| {}) |ancestor_group| {
-                    leave_taskgroup(ancestor_group, me, false);
-                    true
-                };
             }
+            // It doesn't matter whether this happens before or after dealing
+            // with our own taskgroup, so long as both happen before we die.
+            // We remove ourself from every ancestor we can, so no cleanup; no
+            // break.
+            do each_ancestor(&mut self.ancestors, |_| {}) |ancestor_group| {
+                leave_taskgroup(ancestor_group, me, false);
+                true
+            };
         }
     }
 }
@@ -377,7 +372,7 @@ struct AutoNotify {
 }
 
 impl Drop for AutoNotify {
-    fn drop(&self) {
+    fn drop(&mut self) {
         let result = if self.failed { Failure } else { Success };
         self.notify_chan.send(result);
     }
index f9380e7ad1241fd2f6bf7c3bc9c99d51218a2e9b..e8835462a80e28afd804c9612c355f9d1ac6fce7 100644 (file)
@@ -338,14 +338,8 @@ pub fn is_empty(&mut self, order: Ordering) -> bool {
 
 #[unsafe_destructor]
 impl<T> Drop for AtomicOption<T> {
-    fn drop(&self) {
-        // This will ensure that the contained data is
-        // destroyed, unless it's null.
-        unsafe {
-            // FIXME(#4330) Need self by value to get mutability.
-            let this : &mut AtomicOption<T> = cast::transmute(self);
-            let _ = this.take(SeqCst);
-        }
+    fn drop(&mut self) {
+        let _ = self.take(SeqCst);
     }
 }
 
index d8a07eeb8b7d3d1ff7b15179b04336624d67d12d..4c92d9c2e362c5272edbaf4e3e2bb399db614140 100644 (file)
@@ -26,7 +26,7 @@
 pub struct DynamicLibrary { priv handle: *libc::c_void }
 
 impl Drop for DynamicLibrary {
-    fn drop(&self) {
+    fn drop(&mut self) {
         match do dl::check_for_errors_in {
             unsafe {
                 dl::close(self.handle)
index 42820aaaa959d562e33b88a1b897b1c1e792ef26..6833ca6d7cfef6f2ee086ff3d54a90896332a14a 100644 (file)
@@ -64,7 +64,7 @@ struct Finallyalizer<'self> {
 
 #[unsafe_destructor]
 impl<'self> Drop for Finallyalizer<'self> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         (self.dtor)();
     }
 }
index c3791d18b384657d5dadcee6ed981c4cf459eaa1..349739a5ea63dfc976fee078764815bead29de83 100644 (file)
@@ -76,103 +76,7 @@ pub struct TyDesc {
 pub enum Opaque { }
 
 #[lang="ty_visitor"]
-#[cfg(not(test), stage0)]
-pub trait TyVisitor {
-    fn visit_bot(&self) -> bool;
-    fn visit_nil(&self) -> bool;
-    fn visit_bool(&self) -> bool;
-
-    fn visit_int(&self) -> bool;
-    fn visit_i8(&self) -> bool;
-    fn visit_i16(&self) -> bool;
-    fn visit_i32(&self) -> bool;
-    fn visit_i64(&self) -> bool;
-
-    fn visit_uint(&self) -> bool;
-    fn visit_u8(&self) -> bool;
-    fn visit_u16(&self) -> bool;
-    fn visit_u32(&self) -> bool;
-    fn visit_u64(&self) -> bool;
-
-    fn visit_float(&self) -> bool;
-    fn visit_f32(&self) -> bool;
-    fn visit_f64(&self) -> bool;
-
-    fn visit_char(&self) -> bool;
-
-    fn visit_estr_box(&self) -> bool;
-    fn visit_estr_uniq(&self) -> bool;
-    fn visit_estr_slice(&self) -> bool;
-    fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool;
-
-    fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool;
-
-    fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
-                        mtbl: uint, inner: *TyDesc) -> bool;
-
-    fn visit_enter_rec(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-    fn visit_rec_field(&self, i: uint, name: &str,
-                       mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_rec(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-
-    fn visit_enter_class(&self, n_fields: uint,
-                         sz: uint, align: uint) -> bool;
-    fn visit_class_field(&self, i: uint, name: &str,
-                         mtbl: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_class(&self, n_fields: uint,
-                         sz: uint, align: uint) -> bool;
-
-    fn visit_enter_tup(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-    fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_tup(&self, n_fields: uint,
-                       sz: uint, align: uint) -> bool;
-
-    fn visit_enter_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint) -> bool;
-    fn visit_enter_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool;
-    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_enum_variant(&self, variant: uint,
-                                disr_val: int,
-                                n_fields: uint,
-                                name: &str) -> bool;
-    fn visit_leave_enum(&self, n_variants: uint,
-                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
-                        sz: uint, align: uint) -> bool;
-
-    fn visit_enter_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool;
-    fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool;
-    fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool;
-    fn visit_leave_fn(&self, purity: uint, proto: uint,
-                      n_inputs: uint, retstyle: uint) -> bool;
-
-    fn visit_trait(&self) -> bool;
-    fn visit_param(&self, i: uint) -> bool;
-    fn visit_self(&self) -> bool;
-    fn visit_type(&self) -> bool;
-    fn visit_opaque_box(&self) -> bool;
-    fn visit_closure_ptr(&self, ck: uint) -> bool;
-}
-
-#[lang="ty_visitor"]
-#[cfg(not(test), not(stage0))]
+#[cfg(not(test))]
 pub trait TyVisitor {
     fn visit_bot(&mut self) -> bool;
     fn visit_nil(&mut self) -> bool;
@@ -424,9 +328,6 @@ fn visit_leave_fn(&mut 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));
index 26313323291e5e8d4bef786dec5d989cc6942971..c2ef2300fc261673ef7c49ff7b15a3b35ddcf13a 100644 (file)
@@ -220,7 +220,7 @@ fn clone(&self) -> UnsafeArc<T> {
 
 #[unsafe_destructor]
 impl<T> Drop for UnsafeArc<T>{
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             // Happens when destructing an unwrapper's handle and from `#[unsafe_no_drop_flag]`
             if self.data.is_null() {
@@ -308,7 +308,7 @@ pub struct LittleLock {
 }
 
 impl Drop for LittleLock {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             rust_destroy_little_lock(self.l);
         }
@@ -411,23 +411,6 @@ pub fn unwrap(self) -> T {
     }
 }
 
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
-    (fn $name:ident () $(-> $ret_ty:ty),*) => (
-        extern {
-            fn $name() $(-> $ret_ty),*;
-        }
-    );
-    (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
-        extern {
-            fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
-        }
-    )
-)
-}
-
 externfn!(fn rust_create_little_lock() -> rust_little_lock)
 externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
 externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
index 5085f337d4bba216103ddf9f17c1505dca509123..e8bcceb85fa689ed9574281cab1e752722f0c45b 100644 (file)
@@ -88,7 +88,7 @@ pub fn new() -> NonCopyable { NonCopyable }
 }
 
 impl Drop for NonCopyable {
-    fn drop(&self) { }
+    fn drop(&mut self) { }
 }
 
 /// A type with no inhabitants
@@ -188,7 +188,7 @@ fn test_noncopyable() {
         struct Foo { five: int }
 
         impl Drop for Foo {
-            fn drop(&self) {
+            fn drop(&mut self) {
                 assert_eq!(self.five, 5);
                 unsafe {
                     did_run = true;
index 47c3a07961444b90a20af13de4b8cb0533fcaa27..9fc0eaf72b14d044de5d1fd8a0df90293de97d8e 100644 (file)
@@ -1245,6 +1245,7 @@ pub trait OwnedVector<T> {
 
     fn reserve(&mut self, n: uint);
     fn reserve_at_least(&mut self, n: uint);
+    fn reserve_additional(&mut self, n: uint);
     fn capacity(&self) -> uint;
     fn shrink_to_fit(&mut self);
 
@@ -1300,6 +1301,11 @@ fn move_rev_iter(self) -> MoveRevIterator<T> {
      * # Arguments
      *
      * * n - The number of elements to reserve space for
+     *
+     * # Failure
+     *
+     * This method always succeeds in reserving space for `n` elements, or it does
+     * not return.
      */
     fn reserve(&mut self, n: uint) {
         // Only make the (slow) call into the runtime if we have to
@@ -1340,7 +1346,26 @@ fn reserve(&mut self, n: uint) {
      */
     #[inline]
     fn reserve_at_least(&mut self, n: uint) {
-        self.reserve(uint::next_power_of_two(n));
+        self.reserve(uint::next_power_of_two_opt(n).unwrap_or(n));
+    }
+
+    /**
+     * Reserves capacity for at least `n` additional elements in the given vector.
+     *
+     * # Failure
+     *
+     * Fails if the new required capacity overflows uint.
+     *
+     * May also fail if `reserve` fails.
+     */
+    #[inline]
+    fn reserve_additional(&mut self, n: uint) {
+        if self.capacity() - self.len() < n {
+            match self.len().checked_add(&n) {
+                None => fail!("vec::reserve_additional: `uint` overflow"),
+                Some(new_cap) => self.reserve_at_least(new_cap)
+            }
+        }
     }
 
     /// Returns the number of elements the vector can hold without reallocating.
@@ -1376,8 +1401,7 @@ fn push(&mut self, t: T) {
                 let repr: **Box<Vec<()>> = cast::transmute(&mut *self);
                 let fill = (**repr).data.fill;
                 if (**repr).data.alloc <= fill {
-                    let new_len = self.len() + 1;
-                    self.reserve_at_least(new_len);
+                    self.reserve_additional(1);
                 }
 
                 push_fast(self, t);
@@ -1385,8 +1409,7 @@ fn push(&mut self, t: T) {
                 let repr: **Vec<()> = cast::transmute(&mut *self);
                 let fill = (**repr).fill;
                 if (**repr).alloc <= fill {
-                    let new_len = self.len() + 1;
-                    self.reserve_at_least(new_len);
+                    self.reserve_additional(1);
                 }
 
                 push_fast(self, t);
@@ -1432,7 +1455,7 @@ fn push_all_move(&mut self, mut rhs: ~[T]) {
         let self_len = self.len();
         let rhs_len = rhs.len();
         let new_len = self_len + rhs_len;
-        self.reserve_at_least(new_len);
+        self.reserve_additional(rhs.len());
         unsafe { // Note: infallible.
             let self_p = vec::raw::to_mut_ptr(*self);
             let rhs_p = vec::raw::to_ptr(rhs);
@@ -2221,6 +2244,23 @@ pub fn copy_memory(dst: &mut [u8], src: &[u8], count: uint) {
         // Bound checks are done at vec::raw::copy_memory.
         unsafe { vec::raw::copy_memory(dst, src, count) }
     }
+
+    /**
+     * Allocate space in `dst` and append the data in `src`.
+     */
+    #[inline]
+    pub fn push_bytes(dst: &mut ~[u8], src: &[u8]) {
+        let old_len = dst.len();
+        dst.reserve_additional(src.len());
+        unsafe {
+            do dst.as_mut_buf |p_dst, len_dst| {
+                do src.as_imm_buf |p_src, len_src| {
+                    ptr::copy_memory(p_dst.offset(len_dst as int), p_src, len_src)
+                }
+            }
+            vec::raw::set_len(dst, old_len + src.len());
+        }
+    }
 }
 
 impl<A: Clone> Clone for ~[A] {
@@ -3619,6 +3659,14 @@ fn test_overflow_does_not_cause_segfault() {
         v.push(2);
     }
 
+    #[test]
+    #[should_fail]
+    fn test_overflow_does_not_cause_segfault_managed() {
+        let mut v = ~[@1];
+        v.reserve(-1);
+        v.push(@2);
+    }
+
     #[test]
     fn test_mut_split() {
         let mut values = [1u8,2,3,4,5];
index cbc6b604bb7c0e3e683878133ac7f66e8b783339..f0f86911f5050be8c43ebe1ea4f9d644e5fa52c1 100644 (file)
@@ -804,7 +804,7 @@ pub fn new_sctable_internal() -> SCTable {
 
 // fetch the SCTable from TLS, create one if it doesn't yet exist.
 pub fn get_sctable() -> @mut SCTable {
-    static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
+    local_data_key!(sctable_key: @@mut SCTable)
     match local_data::get(sctable_key, |k| k.map_move(|k| *k)) {
         None => {
             let new_table = @@mut new_sctable_internal();
@@ -841,7 +841,7 @@ pub fn mtwt_resolve(id : Ident) -> Name {
 // okay, I admit, putting this in TLS is not so nice:
 // fetch the SCTable from TLS, create one if it doesn't yet exist.
 pub fn get_resolve_table() -> @mut ResolveTable {
-    static resolve_table_key: local_data::Key<@@mut ResolveTable> = &local_data::Key;
+    local_data_key!(resolve_table_key: @@mut ResolveTable)
     match local_data::get(resolve_table_key, |k| k.map(|&k| *k)) {
         None => {
             let new_table = @@mut HashMap::new();
index 536267a2235c050e0ea37e5c1733bae697277b61..5e9714ca5b2de33c90c7ca89ba1a9a27a74097e9 100644 (file)
@@ -187,7 +187,7 @@ fn diagnosticcolor(lvl: level) -> term::color::Color {
 }
 
 fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
-    static tls_terminal: local_data::Key<@Option<term::Terminal>> = &local_data::Key;
+    local_data_key!(tls_terminal: @Option<term::Terminal>)
 
     let stderr = io::stderr();
 
index 6cb5a93a3131bf46610223cae636e244bd28b917..889c2a5976eb358e73864716a0fa027dadd45b26 100644 (file)
@@ -644,25 +644,11 @@ fn lambda(&self, span: Span, ids: ~[ast::Ident], blk: ast::Block) -> @ast::Expr
 
         self.expr(span, ast::ExprFnBlock(fn_decl, blk))
     }
-    #[cfg(stage0)]
-    fn lambda0(&self, _span: Span, blk: ast::Block) -> @ast::Expr {
-        let ext_cx = *self;
-        let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
-        quote_expr!(|| $blk_e )
-    }
-    #[cfg(not(stage0))]
     fn lambda0(&self, _span: Span, blk: ast::Block) -> @ast::Expr {
         let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
         quote_expr!(*self, || $blk_e )
     }
 
-    #[cfg(stage0)]
-    fn lambda1(&self, _span: Span, blk: ast::Block, ident: ast::Ident) -> @ast::Expr {
-        let ext_cx = *self;
-        let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
-        quote_expr!(|$ident| $blk_e )
-    }
-    #[cfg(not(stage0))]
     fn lambda1(&self, _span: Span, blk: ast::Block, ident: ast::Ident) -> @ast::Expr {
         let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
         quote_expr!(*self, |$ident| $blk_e )
index cac311b008825533a8df02abbe77fabe5a49630b..b27fcb6c9b9f7c641a25aa11203558843b876aa7 100644 (file)
@@ -30,43 +30,43 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> bas
                 // string literal, push each byte to vector expression
                 ast::lit_str(s) => {
                     for byte in s.byte_iter() {
-                        bytes.push(cx.expr_u8(sp, byte));
+                        bytes.push(cx.expr_u8(expr.span, byte));
                     }
                 }
 
                 // u8 literal, push to vector expression
                 ast::lit_uint(v, ast::ty_u8) => {
                     if v > 0xFF {
-                        cx.span_err(sp, "Too large u8 literal in bytes!")
+                        cx.span_err(expr.span, "Too large u8 literal in bytes!")
                     } else {
-                        bytes.push(cx.expr_u8(sp, v as u8));
+                        bytes.push(cx.expr_u8(expr.span, v as u8));
                     }
                 }
 
                 // integer literal, push to vector expression
                 ast::lit_int_unsuffixed(v) => {
                     if v > 0xFF {
-                        cx.span_err(sp, "Too large integer literal in bytes!")
+                        cx.span_err(expr.span, "Too large integer literal in bytes!")
                     } else if v < 0 {
-                        cx.span_err(sp, "Negative integer literal in bytes!")
+                        cx.span_err(expr.span, "Negative integer literal in bytes!")
                     } else {
-                        bytes.push(cx.expr_u8(sp, v as u8));
+                        bytes.push(cx.expr_u8(expr.span, v as u8));
                     }
                 }
 
                 // char literal, push to vector expression
                 ast::lit_char(v) => {
                     if char::from_u32(v).unwrap().is_ascii() {
-                        bytes.push(cx.expr_u8(sp, v as u8));
+                        bytes.push(cx.expr_u8(expr.span, v as u8));
                     } else {
-                        cx.span_err(sp, "Non-ascii char literal in bytes!")
+                        cx.span_err(expr.span, "Non-ascii char literal in bytes!")
                     }
                 }
 
-                _ => cx.span_err(sp, "Unsupported literal in bytes!")
+                _ => cx.span_err(expr.span, "Unsupported literal in bytes!")
             },
 
-            _ => cx.span_err(sp, "Non-literal in bytes!")
+            _ => cx.span_err(expr.span, "Non-literal in bytes!")
         }
     }
 
index ac8a7d513dd5d5e19c7d9af7d3f88e7a629666f2..e97af9cbfb143db6da01824c21d684c7124c966f 100644 (file)
 
 use std::os;
 
-#[cfg(stage0)]
-pub fn expand_option_env(ext_cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
-    -> base::MacResult {
-    let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!");
-
-    let e = match os::getenv(var) {
-      None => quote_expr!(::std::option::None::<&'static str>),
-      Some(s) => quote_expr!(::std::option::Some($s))
-    };
-    MRExpr(e)
-}
-#[cfg(not(stage0))]
 pub fn expand_option_env(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
     -> base::MacResult {
     let var = get_single_str_from_tts(cx, sp, tts, "option_env!");
index ac094c27a8119780debbf58de5afefbd413d7dd4..0bee789542099e93f8bb65530201fbfac7cc487b 100644 (file)
@@ -863,9 +863,7 @@ pub mod $c {
 
                 use super::*;
 
-                static key: ::std::local_data::Key<
-                    @::std::condition::Handler<$input, $out>> =
-                    &::std::local_data::Key;
+                local_data_key!(key: @::std::condition::Handler<$input, $out>)
 
                 pub static cond :
                     ::std::condition::Condition<$input,$out> =
@@ -884,9 +882,7 @@ mod $c {
 
                 use super::*;
 
-                static key: ::std::local_data::Key<
-                    @::std::condition::Handler<$input, $out>> =
-                    &::std::local_data::Key;
+                local_data_key!(key: @::std::condition::Handler<$input, $out>)
 
                 pub static cond :
                     ::std::condition::Condition<$input,$out> =
@@ -898,42 +894,6 @@ mod $c {
         }
     )
 
-    //
-    // A scheme-style conditional that helps to improve code clarity in some instances when
-    // the `if`, `else if`, and `else` keywords obscure predicates undesirably.
-    //
-    // # Example
-    //
-    // ~~~
-    // let clamped =
-    //     if x > mx { mx }
-    //     else if x < mn { mn }
-    //     else { x };
-    // ~~~
-    //
-    // Using `cond!`, the above could be written as:
-    //
-    // ~~~
-    // let clamped = cond!(
-    //     (x > mx) { mx }
-    //     (x < mn) { mn }
-    //     _        { x  }
-    // );
-    // ~~~
-    //
-    // The optional default case is denoted by `_`.
-    //
-    macro_rules! cond (
-        ( $(($pred:expr) $body:block)+ _ $default:block ) => (
-            $(if $pred $body else)+
-            $default
-        );
-        // for if the default case was ommitted
-        ( $(($pred:expr) $body:block)+ ) => (
-            $(if $pred $body)else+
-        );
-    )
-
     // NOTE(acrichto): start removing this after the next snapshot
     macro_rules! printf (
         ($arg:expr) => (
@@ -975,8 +935,6 @@ macro_rules! println (
         ($($arg:tt)*) => (::std::io::println(format!($($arg)*)))
     )
 
-    // NOTE: use this after a snapshot lands to abstract the details
-    // of the TLS interface.
     macro_rules! local_data_key (
         ($name:ident: $ty:ty) => (
             static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
index 9f4e55b1a92cef6258d983a922d1bea669aca24e..cace4648df2527ed57204a92ad929ccd1fd29276 100644 (file)
@@ -76,6 +76,7 @@ fn parse_args(&mut self, sp: Span,
                 self.ecx.span_err(sp, "expected token: `,`");
                 return (extra, None);
             }
+            if *p.token == token::EOF { break } // accept trailing commas
             if named || (token::is_ident(p.token) &&
                          p.look_ahead(1, |t| *t == token::EQ)) {
                 named = true;
index c267a673fcedfababfb57c1f2cbeb7a0a75e42b2..0bc9e6192743654c0d1a912d65339951159ad9e7 100644 (file)
@@ -699,6 +699,7 @@ fn binop(rdr: @mut StringReader, op: token::binop) -> token::Token {
               '\\' => { c2 = '\\'; }
               '\'' => { c2 = '\''; }
               '"' => { c2 = '"'; }
+              '0' => { c2 = '\x00'; }
               'x' => { c2 = scan_numeric_escape(rdr, 2u); }
               'u' => { c2 = scan_numeric_escape(rdr, 4u); }
               'U' => { c2 = scan_numeric_escape(rdr, 8u); }
@@ -738,6 +739,7 @@ fn binop(rdr: @mut StringReader, op: token::binop) -> token::Token {
                   '\'' => accum_str.push_char('\''),
                   '"' => accum_str.push_char('"'),
                   '\n' => consume_whitespace(rdr),
+                  '0' => accum_str.push_char('\x00'),
                   'x' => {
                     accum_str.push_char(scan_numeric_escape(rdr, 2u));
                   }
index f7c76fee1809307380e6fb3cfa2115c215e52028..9645dab4e8b7b847c72c00b8296d03fa8cdaab73 100644 (file)
@@ -398,30 +398,130 @@ fn sp (a: uint, b: uint) -> Span {
     #[test] fn string_to_tts_1 () {
         let (tts,_ps) = string_to_tts_and_sess(@"fn a (b : int) { b; }");
         assert_eq!(to_json_str(@tts),
-                   ~"[\
-                [\"tt_tok\",null,[\"IDENT\",\"fn\",false]],\
-                [\"tt_tok\",null,[\"IDENT\",\"a\",false]],\
-                [\
-                    \"tt_delim\",\
-                    [\
-                        [\"tt_tok\",null,\"LPAREN\"],\
-                        [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
-                        [\"tt_tok\",null,\"COLON\"],\
-                        [\"tt_tok\",null,[\"IDENT\",\"int\",false]],\
-                        [\"tt_tok\",null,\"RPAREN\"]\
+        ~"[\
+    {\
+        \"variant\":\"tt_tok\",\
+        \"fields\":[\
+            null,\
+            {\
+                \"variant\":\"IDENT\",\
+                \"fields\":[\
+                    \"fn\",\
+                    false\
+                ]\
+            }\
+        ]\
+    },\
+    {\
+        \"variant\":\"tt_tok\",\
+        \"fields\":[\
+            null,\
+            {\
+                \"variant\":\"IDENT\",\
+                \"fields\":[\
+                    \"a\",\
+                    false\
+                ]\
+            }\
+        ]\
+    },\
+    {\
+        \"variant\":\"tt_delim\",\
+        \"fields\":[\
+            [\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        \"LPAREN\"\
                     ]\
-                ],\
-                [\
-                    \"tt_delim\",\
-                    [\
-                        [\"tt_tok\",null,\"LBRACE\"],\
-                        [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
-                        [\"tt_tok\",null,\"SEMI\"],\
-                        [\"tt_tok\",null,\"RBRACE\"]\
+                },\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        {\
+                            \"variant\":\"IDENT\",\
+                            \"fields\":[\
+                                \"b\",\
+                                false\
+                            ]\
+                        }\
                     ]\
-                ]\
-            ]"
-                  );
+                },\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        \"COLON\"\
+                    ]\
+                },\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        {\
+                            \"variant\":\"IDENT\",\
+                            \"fields\":[\
+                                \"int\",\
+                                false\
+                            ]\
+                        }\
+                    ]\
+                },\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        \"RPAREN\"\
+                    ]\
+                }\
+            ]\
+        ]\
+    },\
+    {\
+        \"variant\":\"tt_delim\",\
+        \"fields\":[\
+            [\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        \"LBRACE\"\
+                    ]\
+                },\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        {\
+                            \"variant\":\"IDENT\",\
+                            \"fields\":[\
+                                \"b\",\
+                                false\
+                            ]\
+                        }\
+                    ]\
+                },\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        \"SEMI\"\
+                    ]\
+                },\
+                {\
+                    \"variant\":\"tt_tok\",\
+                    \"fields\":[\
+                        null,\
+                        \"RBRACE\"\
+                    ]\
+                }\
+            ]\
+        ]\
+    }\
+]"
+        );
     }
 
     #[test] fn ret_expr() {
index f05452bb6c504d584ece8c54484ecf5e0fa80940..4aad5c24d0f3d8e07e3355f38bd32d4908d844a1 100644 (file)
@@ -341,7 +341,7 @@ pub struct Parser {
 #[unsafe_destructor]
 impl Drop for Parser {
     /* do not copy the parser; its state is tied to outside state */
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn is_plain_ident_or_underscore(t: &token::Token) -> bool {
index fa00b536837c5b212a37a5233c94257cfc10875f..a8df737e49fcf7db6a727b17a5b44291ef7d360a 100644 (file)
@@ -490,8 +490,7 @@ fn mk_fresh_ident_interner() -> @ident_interner {
 // if an interner exists in TLS, return it. Otherwise, prepare a
 // fresh one.
 pub fn get_ident_interner() -> @ident_interner {
-    static key: local_data::Key<@@::parse::token::ident_interner> =
-        &local_data::Key;
+    local_data_key!(key: @@::parse::token::ident_interner)
     match local_data::get(key, |k| k.map_move(|k| *k)) {
         Some(interner) => *interner,
         None => {
index af2a49770828b5c219049f64e2ec28fad41ed83b..615f33013736fc566c5d4f89d38dba2ec87d7f8c 100644 (file)
@@ -243,7 +243,7 @@ pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer {
  * the entire buffered window, but can't output anything until the size is >=
  * 0 (sizes are set to negative while they're pending calculation).
  *
- * So SCAN takeks input and buffers tokens and pending calculations, while
+ * So SCAN takes input and buffers tokens and pending calculations, while
  * PRINT gobbles up completed calculations and tokens from the buffer. The
  * theory is that the two can never get more than 3N tokens apart, because
  * once there's "obviously" too much data to fit on a line, in a size
index ec84cbda97360392abce5a27964b7940a2f2894a..b5868cbc63db09a0b16135f4b9c9be3eba91e193 100644 (file)
@@ -1535,15 +1535,15 @@ fn print_path_(s: @ps,
 
         print_ident(s, segment.identifier);
 
-        if segment.lifetime.is_some() || !segment.types.is_empty() {
-            // If this is the last segment, print the bounds.
-            if i == path.segments.len() - 1 {
-                match *opt_bounds {
-                    None => {}
-                    Some(ref bounds) => print_bounds(s, bounds, true),
-                }
+        // If this is the last segment, print the bounds.
+        if i == path.segments.len() - 1 {
+            match *opt_bounds {
+                None => {}
+                Some(ref bounds) => print_bounds(s, bounds, true),
             }
+        }
 
+        if segment.lifetime.is_some() || !segment.types.is_empty() {
             if colons_before_params {
                 word(s.s, "::")
             }
index 4b718303f2cb0f7da78d4da0f7783bb7e6f13b0f..8877b082588284a063508a283efd81db6bb66d8b 100644 (file)
@@ -643,6 +643,29 @@ rust_valgrind_stack_deregister(unsigned int id) {
   VALGRIND_STACK_DEREGISTER(id);
 }
 
+#if defined(__WIN32__)
+
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+    // empty stub for windows to keep linker happy
+}
+
+#else
+
+#include <signal.h>
+#include <unistd.h>
+
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+    // this can't be safely converted to rust code because the
+    // representation of sigset_t is platform-dependent
+    sigset_t sset;
+    sigemptyset(&sset);
+    sigprocmask(SIG_SETMASK, &sset, NULL);
+}
+
+#endif
+
 //
 // Local Variables:
 // mode: C++
diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp
deleted file mode 100644 (file)
index 25cbaf8..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-#include "rust_globals.h"
-
-#ifdef __APPLE__
-#include <crt_externs.h>
-#endif
-
-#if defined(__WIN32__)
-
-extern "C" CDECL void
-rust_unset_sigprocmask() {
-    // empty stub for windows to keep linker happy
-}
-
-extern "C" CDECL void
-rust_set_environ(void* envp) {
-    // empty stub for windows to keep linker happy
-}
-
-#elif defined(__GNUC__)
-
-#include <signal.h>
-#include <unistd.h>
-
-#ifdef __FreeBSD__
-extern char **environ;
-#endif
-
-extern "C" CDECL void
-rust_unset_sigprocmask() {
-    // this can't be safely converted to rust code because the
-    // representation of sigset_t is platform-dependent
-    sigset_t sset;
-    sigemptyset(&sset);
-    sigprocmask(SIG_SETMASK, &sset, NULL);
-}
-
-extern "C" CDECL void
-rust_set_environ(void* envp) {
-    // FIXME: this could actually be converted to rust (see issue #2674)
-#ifdef __APPLE__
-    *_NSGetEnviron() = (char **) envp;
-#else
-    environ = (char **) envp;
-#endif
-}
-
-#else
-#error "Platform not supported."
-#endif
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
-// End:
-//
index bfdf0e67a9b81f8616d7873edf9b0d8d4f7a543c..3e9b8ba136eaa05e31537fd48a800eba46328e3e 100644 (file)
@@ -542,6 +542,10 @@ extern "C" int
 rust_uv_get_result_from_fs_req(uv_fs_t* req) {
   return req->result;
 }
+extern "C" void*
+rust_uv_get_ptr_from_fs_req(uv_fs_t* req) {
+  return req->ptr;
+}
 extern "C" uv_loop_t*
 rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
   return req->loop;
@@ -551,3 +555,85 @@ extern "C" uv_loop_t*
 rust_uv_get_loop_from_getaddrinfo_req(uv_getaddrinfo_t* req) {
   return req->loop;
 }
+
+extern "C" int
+rust_uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+  return uv_fs_stat(loop, req, path, cb);
+}
+extern "C" int
+rust_uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+  return uv_fs_fstat(loop, req, file, cb);
+}
+
+extern "C" void
+rust_uv_populate_uv_stat(uv_fs_t* req_in, uv_stat_t* stat_out) {
+  stat_out->st_dev = req_in->statbuf.st_dev;
+  stat_out->st_mode = req_in->statbuf.st_mode;
+  stat_out->st_nlink = req_in->statbuf.st_nlink;
+  stat_out->st_uid = req_in->statbuf.st_uid;
+  stat_out->st_gid = req_in->statbuf.st_gid;
+  stat_out->st_rdev = req_in->statbuf.st_rdev;
+  stat_out->st_ino = req_in->statbuf.st_ino;
+  stat_out->st_size = req_in->statbuf.st_size;
+  stat_out->st_blksize = req_in->statbuf.st_blksize;
+  stat_out->st_blocks = req_in->statbuf.st_blocks;
+  stat_out->st_flags = req_in->statbuf.st_flags;
+  stat_out->st_gen = req_in->statbuf.st_gen;
+  stat_out->st_atim.tv_sec = req_in->statbuf.st_atim.tv_sec;
+  stat_out->st_atim.tv_nsec = req_in->statbuf.st_atim.tv_nsec;
+  stat_out->st_mtim.tv_sec = req_in->statbuf.st_mtim.tv_sec;
+  stat_out->st_mtim.tv_nsec = req_in->statbuf.st_mtim.tv_nsec;
+  stat_out->st_ctim.tv_sec = req_in->statbuf.st_ctim.tv_sec;
+  stat_out->st_ctim.tv_nsec = req_in->statbuf.st_ctim.tv_nsec;
+  stat_out->st_birthtim.tv_sec = req_in->statbuf.st_birthtim.tv_sec;
+  stat_out->st_birthtim.tv_nsec = req_in->statbuf.st_birthtim.tv_nsec;
+}
+
+extern "C" int
+rust_uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) {
+  return uv_fs_mkdir(loop, req, path, mode, cb);
+}
+extern "C" int
+rust_uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+  return uv_fs_rmdir(loop, req, path, cb);
+}
+
+extern "C" int
+rust_uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) {
+  return uv_fs_readdir(loop, req, path, flags, cb);
+}
+
+extern "C" int
+rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) {
+  return uv_spawn(loop, p, options);
+}
+
+extern "C" int
+rust_uv_process_kill(uv_process_t *p, int signum) {
+  return uv_process_kill(p, signum);
+}
+
+extern "C" void
+rust_set_stdio_container_flags(uv_stdio_container_t *c, int flags) {
+  c->flags = (uv_stdio_flags) flags;
+}
+
+extern "C" void
+rust_set_stdio_container_fd(uv_stdio_container_t *c, int fd) {
+  c->data.fd = fd;
+}
+
+extern "C" void
+rust_set_stdio_container_stream(uv_stdio_container_t *c, uv_stream_t *stream) {
+  c->data.stream = stream;
+}
+
+extern "C" int
+rust_uv_process_pid(uv_process_t* p) {
+  return p->pid;
+}
+
+extern "C" int
+rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) {
+  return uv_pipe_init(loop, p, ipc);
+}
index 4cbee0dcbd0688b0d2403aed4f3cf5396b89191d..7a9149187d8c711792a01e290eb26f02d734d6a2 100644 (file)
@@ -25,7 +25,6 @@ rust_list_dir_wfd_fp_buf
 rust_log_console_on
 rust_log_console_off
 rust_should_log_console
-rust_set_environ
 rust_unset_sigprocmask
 rust_env_pairs
 upcall_rust_personality
@@ -113,8 +112,15 @@ rust_uv_fs_write
 rust_uv_fs_read
 rust_uv_fs_close
 rust_uv_get_result_from_fs_req
+rust_uv_get_ptr_from_fs_req
 rust_uv_get_loop_from_fs_req
+rust_uv_fs_stat
+rust_uv_fs_fstat
 rust_uv_fs_req_cleanup
+rust_uv_populate_uv_stat
+rust_uv_fs_mkdir
+rust_uv_fs_rmdir
+rust_uv_fs_readdir
 rust_dbg_lock_create
 rust_dbg_lock_destroy
 rust_dbg_lock_lock
@@ -191,3 +197,10 @@ rust_drop_linenoise_lock
 rust_get_test_int
 rust_get_task
 rust_uv_get_loop_from_getaddrinfo_req
+rust_uv_spawn
+rust_uv_process_kill
+rust_set_stdio_container_flags
+rust_set_stdio_container_fd
+rust_set_stdio_container_stream
+rust_uv_process_pid
+rust_uv_pipe_init
index 1bfb8e28393973a90ed0c9e11bd07ab61fc08d74..65aa070ce6e9487fd6e6e6af67a5652c635ece4e 100644 (file)
@@ -1043,27 +1043,3 @@ fn resolve_type(t: &Type) -> Type {
         ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::NameValue;
-
-    #[test]
-    fn test_doc_collapsing() {
-        assert_eq!(collapse_docs(~"// Foo\n//Bar\n // Baz\n"), ~"Foo\nBar\nBaz");
-        assert_eq!(collapse_docs(~"* Foo\n *  Bar\n *Baz\n"), ~"Foo\n Bar\nBaz");
-        assert_eq!(collapse_docs(~"* Short desc\n *\n * Bar\n *Baz\n"), ~"Short desc\n\nBar\nBaz");
-        assert_eq!(collapse_docs(~" * Foo"), ~"Foo");
-        assert_eq!(collapse_docs(~"\n *\n *\n * Foo"), ~"Foo");
-    }
-
-    fn collapse_docs(input: ~str) -> ~str {
-        let attrs = ~[NameValue(~"doc", input)];
-        let attrs_clean = super::collapse_docs(attrs);
-
-        match attrs_clean[0] {
-            NameValue(~"doc", s) => s,
-            _ => (fail!("dude where's my doc?"))
-        }
-    }
-}
diff --git a/src/rustdoc_ng/lib.rs b/src/rustdoc_ng/lib.rs
deleted file mode 100644 (file)
index 75453aa..0000000
+++ /dev/null
@@ -1,37 +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.
-
-#[link(name = "rustdoc_ng",
-       vers = "0.1.0",
-       uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6")];
-#[desc = "rustdoc, the Rust documentation extractor"];
-#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
-
-#[deny(warnings)];
-
-extern mod syntax;
-extern mod rustc;
-
-extern mod extra;
-
-use extra::serialize::Encodable;
-
-pub mod core;
-pub mod doctree;
-pub mod clean;
-pub mod visit_ast;
-pub mod fold;
-pub mod plugins;
-pub mod passes;
-
-pub static SCHEMA_VERSION: &'static str = "0.8.0";
-
-pub static ctxtkey: std::local_data::Key<@core::DocContext> = &std::local_data::Key;
diff --git a/src/rustdoc_ng/main.rs b/src/rustdoc_ng/main.rs
deleted file mode 100644 (file)
index aad6404..0000000
+++ /dev/null
@@ -1,104 +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.
-
-#[link(name = "rustdoc_ng",
-       vers = "0.1.0",
-       uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6")];
-#[desc = "rustdoc, the Rust documentation extractor"];
-#[license = "MIT/ASL2"];
-#[crate_type = "bin"];
-
-extern mod extra;
-extern mod rustdoc_ng;
-
-use rustdoc_ng::*;
-use std::cell::Cell;
-
-use extra::serialize::Encodable;
-
-fn main() {
-    use extra::getopts::*;
-    use extra::getopts::groups::*;
-
-    let args = std::os::args();
-    let opts = ~[
-        optmulti("L", "library-path", "directory to add to crate search path", "DIR"),
-        optmulti("p", "plugin", "plugin to load and run", "NAME"),
-        optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
-        // auxillary pass (defaults to hidden_strip
-        optmulti("a", "pass", "auxillary pass to run", "NAME"),
-        optflag("n", "no-defult-passes", "do not run the default passes"),
-        optflag("h", "help", "show this help message"),
-    ];
-
-    let matches = getopts(args.tail(), opts).unwrap();
-
-    if opt_present(&matches, "h") || opt_present(&matches, "help") {
-        println(usage(args[0], opts));
-        return;
-    }
-
-    let libs = Cell::new(opt_strs(&matches, "L").map(|s| Path(*s)));
-
-    let mut passes = if opt_present(&matches, "n") {
-        ~[]
-    } else {
-        ~[~"collapse-docs", ~"clean-comments", ~"collapse-privacy" ]
-    };
-
-    opt_strs(&matches, "a").map(|x| passes.push(x.clone()));
-
-    if matches.free.len() != 1 {
-        println(usage(args[0], opts));
-        return;
-    }
-
-    let cr = Cell::new(Path(matches.free[0]));
-
-    let crate = std::task::try(|| {let cr = cr.take(); core::run_core(libs.take(), &cr)}).unwrap();
-
-    // { "schema": version, "crate": { parsed crate ... }, "plugins": { output of plugins ... }}
-    let mut json = ~extra::treemap::TreeMap::new();
-    json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
-
-    let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
-
-    for pass in passes.iter() {
-        pm.add_plugin(match pass.as_slice() {
-            "strip-hidden" => passes::strip_hidden,
-            "clean-comments" => passes::clean_comments,
-            "collapse-docs" => passes::collapse_docs,
-            "collapse-privacy" => passes::collapse_privacy,
-            s => { error!("unknown pass %s, skipping", s); passes::noop },
-        })
-    }
-
-    for pname in opt_strs(&matches, "p").move_iter() {
-        pm.load_plugin(pname);
-    }
-
-    let (crate, res) = pm.run_plugins(crate);
-    let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
-
-    // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
-    // straight to the Rust JSON representation.
-    let crate_json_str = do std::io::with_str_writer |w| {
-        crate.encode(&mut extra::json::Encoder(w));
-    };
-    let crate_json = match extra::json::from_str(crate_json_str) {
-        Ok(j) => j,
-        Err(_) => fail!("Rust generated JSON is invalid??")
-    };
-
-    json.insert(~"crate", crate_json);
-    json.insert(~"plugins", extra::json::Object(plugins_json));
-
-    println(extra::json::Object(json).to_str());
-}
diff --git a/src/rustdoc_ng/rustdoc_ng.rs b/src/rustdoc_ng/rustdoc_ng.rs
new file mode 100644 (file)
index 0000000..a4e3bc5
--- /dev/null
@@ -0,0 +1,122 @@
+// 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.
+
+#[link(name = "rustdoc_ng",
+       vers = "0.8-pre",
+       uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6",
+       url = "https://github.com/mozilla/rust/tree/master/src/rustdoc_ng")];
+
+#[desc = "rustdoc, the Rust documentation extractor"];
+#[license = "MIT/ASL2"];
+#[crate_type = "lib"];
+
+extern mod syntax;
+extern mod rustc;
+extern mod extra;
+
+use extra::serialize::Encodable;
+use std::cell::Cell;
+
+pub mod core;
+pub mod doctree;
+pub mod clean;
+pub mod visit_ast;
+pub mod fold;
+pub mod plugins;
+pub mod passes;
+
+pub static SCHEMA_VERSION: &'static str = "0.8.0";
+
+local_data_key!(pub ctxtkey: @core::DocContext)
+
+pub fn main() {
+    main_args(std::os::args());
+}
+
+pub fn main_args(args: &[~str]) {
+    use extra::getopts::groups::*;
+
+    let opts = ~[
+        optmulti("L", "library-path", "directory to add to crate search path", "DIR"),
+        optmulti("p", "plugin", "plugin to load and run", "NAME"),
+        optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
+        // auxillary pass (defaults to hidden_strip
+        optmulti("a", "pass", "auxillary pass to run", "NAME"),
+        optflag("n", "no-defult-passes", "do not run the default passes"),
+        optflag("h", "help", "show this help message"),
+    ];
+
+    let matches = getopts(args.tail(), opts).unwrap();
+
+    if matches.opt_present("h") || matches.opt_present("help") {
+        println(usage(args[0], opts));
+        return;
+    }
+
+    let libs = Cell::new(matches.opt_strs("L").map(|s| Path(*s)));
+
+    let mut passes = if matches.opt_present("n") {
+        ~[]
+    } else {
+        ~[~"collapse-docs", ~"clean-comments", ~"collapse-privacy" ]
+    };
+
+    matches.opt_strs("a").map(|x| passes.push(x.clone()));
+
+    if matches.free.len() != 1 {
+        println(usage(args[0], opts));
+        return;
+    }
+
+    let cr = Cell::new(Path(matches.free[0]));
+
+    let crate = do std::task::try {
+        let cr = cr.take();
+        core::run_core(libs.take(), &cr)
+    }.unwrap();
+
+    // { "schema": version, "crate": { parsed crate ... }, "plugins": { output of plugins ... }}
+    let mut json = ~extra::treemap::TreeMap::new();
+    json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
+
+    let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
+
+    for pass in passes.iter() {
+        pm.add_plugin(match pass.as_slice() {
+            "strip-hidden" => passes::strip_hidden,
+            "clean-comments" => passes::clean_comments,
+            "collapse-docs" => passes::collapse_docs,
+            "collapse-privacy" => passes::collapse_privacy,
+            s => { error!("unknown pass %s, skipping", s); passes::noop },
+        })
+    }
+
+    for pname in matches.opt_strs("p").move_iter() {
+        pm.load_plugin(pname);
+    }
+
+    let (crate, res) = pm.run_plugins(crate);
+    let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
+
+    // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
+    // straight to the Rust JSON representation.
+    let crate_json_str = do std::io::with_str_writer |w| {
+        crate.encode(&mut extra::json::Encoder(w));
+    };
+    let crate_json = match extra::json::from_str(crate_json_str) {
+        Ok(j) => j,
+        Err(_) => fail!("Rust generated JSON is invalid??")
+    };
+
+    json.insert(~"crate", crate_json);
+    json.insert(~"plugins", extra::json::Object(plugins_json));
+
+    println(extra::json::Object(json).to_str());
+}
index ad170d9173f71b6909fcecd0713a8b209cec546d..705cf50632a6acc74a5d661037f29df38a93698e 100644 (file)
@@ -1,3 +1,11 @@
+S 2013-09-17 cbd1eef
+  freebsd-x86_64 9166867a8859076343cb3e57da918b5c0eea720b
+  linux-i386 38347b579312ff30c36d257a1161660eb0ae8422
+  linux-x86_64 0c169bba5d6729d0c0f096d61d9274fb082b4b34
+  macos-i386 1eb229510dd12b91800674566b8dad401a3f80d3
+  macos-x86_64 1c5d8e29b9671af93963e1b5fa9fcca081124a39
+  winnt-i386 56baa04a1f02235ebc5a75be05aa65fdc822a4e6
+
 S 2013-08-14 e7b5729
   freebsd-x86_64 9de0b5583a5c4413f9e77df7071498385e936dd2
   linux-i386 29119a9072f74c639c2bad998edc40e582da540e
index cbdd6b56b7da49564b4da1c1f3680e2ccaa44570..8ed65628f54f9277ef5d90fee629b5aa9033ca36 100644 (file)
@@ -21,7 +21,7 @@ struct arc_destruct<T> {
 
 #[unsafe_destructor]
 impl<T:Freeze> Drop for arc_destruct<T> {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn arc_destruct<T:Freeze>(data: int) -> arc_destruct<T> {
@@ -43,7 +43,7 @@ struct context_res {
 }
 
 impl Drop for context_res {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn context_res() -> context_res {
index 9c9b3d9f243404ed95d6c538316a553a7269546e..f9bbfa7ecce07ede44f88770e50ec79f029a9e89 100644 (file)
@@ -19,7 +19,7 @@ pub struct socket_handle {
     }
 
     impl Drop for socket_handle {
-        fn drop(&self) {
+        fn drop(&mut self) {
             /* c::close(self.sockfd); */
         }
     }
diff --git a/src/test/auxiliary/issue-4208-cc.rs b/src/test/auxiliary/issue-4208-cc.rs
new file mode 100644 (file)
index 0000000..26db69f
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+#[link(name = "numeric",
+       vers = "0.1")];
+#[crate_type = "lib"];
+
+pub trait Trig<T> {
+    fn sin(&self) -> T;
+}
+
+pub fn sin<T:Trig<R>, R>(theta: &T) -> R { theta.sin() }
+
+pub trait Angle<T>: Trig<T> {}
index ec5d8baf25900a4d13d6108f4095ce881db2203c..b311ee35674672fe5f22f323ddf98a5c0b2bed7a 100644 (file)
@@ -16,7 +16,7 @@ pub struct rsrc {
 }
 
 impl Drop for rsrc {
-    fn drop(&self) {
+    fn drop(&mut self) {
         foo(self.x);
     }
 }
index f45b80715953ef847c24208f00c2873c5f673c16..fe403a56a4be6524f9ad3bce538560f8f19091f7 100644 (file)
@@ -15,7 +15,7 @@ pub struct S {
 }
 
 impl Drop for S {
-    fn drop(&self) {
+    fn drop(&mut self) {
         println("goodbye");
     }
 }
diff --git a/src/test/auxiliary/xcrate_address_insignificant.rs b/src/test/auxiliary/xcrate_address_insignificant.rs
new file mode 100644 (file)
index 0000000..08e3eff
--- /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.
+
+pub fn foo<T>() -> int {
+    #[address_insignificant]
+    static a: int = 3;
+    a
+}
+
+pub fn bar() -> int {
+    foo::<int>()
+}
index 3a05462d856da20c25c56543abbaa85026b19e9d..f0df2b1e71edebff076623cce8d1208cb876325b 100644 (file)
 
 pub static global: int = 3;
 
+static global0: int = 4;
+pub static global2: &'static int = &global0;
+
 pub fn verify_same(a: &'static int) {
     let a = a as *int as uint;
     let b = &global as *int as uint;
     assert_eq!(a, b);
 }
 
+pub fn verify_same2(a: &'static int) {
+    let a = a as *int as uint;
+    let b = global2 as *int as uint;
+    assert_eq!(a, b);
+}
+
 condition!{ pub test: int -> (); }
 
 pub fn raise() {
index 7029ca2a49296969920d7cb804a0a077e93971a2..0896682b32225b5df486d0b92cae6c197458dc77 100644 (file)
@@ -64,7 +64,7 @@ fn parse_opts(argv: ~[~str]) -> Config {
 
     match getopts::getopts(opt_args, opts) {
       Ok(ref m) => {
-          return Config {stress: getopts::opt_present(m, "stress")}
+          return Config {stress: m.opt_present("stress")}
       }
       Err(_) => { fail!(); }
     }
index 9718a12c83f13e373fbe01de716703d9360e071c..f383f7a101fcca9cb8d0a35ada3c35124828889a 100644 (file)
@@ -58,7 +58,7 @@ struct r {
 
 #[unsafe_destructor]
 impl Drop for r {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn r(l: @nillist) -> r {
index 6353d7c6581b175ebfc2f3321777c983acc76c50..3d1cca46085dbf06f8d9f95a890360b85d309391 100644 (file)
@@ -11,7 +11,7 @@
 struct X { x: () }
 
 impl Drop for X {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("destructor runs");
     }
 }
index 6ea5f85797f188c79b053520486c69caa8d0e6e4..a1803a621a53fc2996f4ddea13508ddcc58a5d0d 100644 (file)
@@ -11,7 +11,7 @@
 struct X { x: (), }
 
 impl Drop for X {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("destructor runs");
     }
 }
index 8f0642896f1e2ed9ecb1ac90e853f4c2453967c9..34a9c0b8fc26d01fdcdbcc6ead782b013377ef62 100644 (file)
@@ -11,7 +11,7 @@
 struct X { x: (), }
 
 impl Drop for X {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("destructor runs");
     }
 }
index 859bf7bd26d9cbd3002c463387e9c3c05bd2c289..2aa3379993b7abaf195f247baa57c9707d592a04 100644 (file)
@@ -11,7 +11,7 @@
 struct X { x: (), }
 
 impl Drop for X {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("destructor runs");
     }
 }
index a1243dd01d9f7e8c26323d35e7c91103ad9871c1..7143ce0252b733c4b5683f3d2453fe753d16a317 100644 (file)
@@ -11,7 +11,7 @@
 struct X { x: (), }
 
 impl Drop for X {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("destructor runs");
     }
 }
index c9b627f55f80362a08c65f8c4262fa2960a21bf5..df42244fd0fc8cfc669210999594c309f2f577e4 100644 (file)
@@ -13,7 +13,7 @@
 struct r;
 
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         true
     }
 }
index 98099360f3c71f404c06c39cb0fc27f42aa9e8a1..1c725a0dd0e036ba6f6e6823c90ded1e54f5da89 100644 (file)
@@ -14,7 +14,7 @@ struct defer<'self> {
 
 #[unsafe_destructor]
 impl<'self> Drop for defer<'self> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             error!("%?", self.x);
         }
index 4407329f49775876f027132e63bfc287da426620..ade9ce9568f958a5b758c6a8abefcd3576cac1c8 100644 (file)
@@ -1,6 +1,6 @@
 struct S {f:~str}
 impl Drop for S {
-    fn drop(&self) { println(self.f); }
+    fn drop(&mut self) { println(self.f); }
 }
 
 fn move_in_match() {
index 400a4f07951fc120480feb44822f252465edb123..1a0fc9e3b3b4d7eb6c4d8136c01c42a40cc915a2 100644 (file)
@@ -1,6 +1,6 @@
 struct S(~str);
 impl Drop for S {
-    fn drop(&self) { println(**self); }
+    fn drop(&mut self) { println(**self); }
 }
 
 fn move_in_match() {
index a90b04b79adc19c10621b040f9bc9d16c36346c7..c5f5861de825d778395d9a6d85b9f090af2edb4d 100644 (file)
@@ -13,7 +13,7 @@ struct foo {
 }
 
 impl Drop for foo {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn foo(i:int) -> foo {
index 4652aa0d3f12518c43d938dcdeceb5bfeda929ff..2a4d46941b9771312b1f37dd2f60821d4573c7b1 100644 (file)
@@ -13,7 +13,7 @@ struct X {
 }
 
 impl Drop for X {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("value: %s", self.x);
     }
 }
index 748114a4f12f6f99b3c35bda8b1e9237f325bd32..ecb02c4307d3e1427a14952577eb827e5e755118 100644 (file)
@@ -13,7 +13,7 @@ struct X {
 }
 
 impl Drop for X {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("value: %s", self.x);
     }
 }
index 2eb58d49612318859552fb38566831f6c24f0c51..e65d5966b277a7541df0c0dc3bb03ecb75d5ef3f 100644 (file)
@@ -12,7 +12,7 @@
 
 impl Drop for Foo {   //~ ERROR the Drop trait may only be implemented
 //~^ ERROR cannot provide an extension implementation
-    fn drop(&self) {
+    fn drop(&mut self) {
         println("kaboom");
     }
 }
index 5ffc9ea08eda7b48f93322045dff27c621109fb7..4a34f9c42be4032f04654e8ce33a3568903fc69a 100644 (file)
@@ -13,7 +13,7 @@ struct Foo {
 }
 
 impl Drop for Foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         println("kaboom");
     }
 }
index ace31183d76a0a1f14d31a3a68ba460c55359075..2a5c260910b6f25b9cc32d445584af97a6f1771c 100644 (file)
@@ -17,7 +17,7 @@ trait Bar : Drop {
 }
 
 impl Drop for Foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         println("kaboom");
     }
 }
index dd881790ba880430aabc75495fe9e93da0e6b9c2..02db789519596d6bdad7fa0731d5d470b353157c 100644 (file)
@@ -17,7 +17,7 @@
 struct A { y: Arc<int>, x: Arc<int> }
 
 impl Drop for A {
-    fn drop(&self) { println(fmt!("x=%?", self.x.get())); }
+    fn drop(&mut self) { println(fmt!("x=%?", self.x.get())); }
 }
 fn main() {
     let a = A { y: Arc::new(1), x: Arc::new(2) };
index cb0b8afbf8ba4454f4bf688c4d6468e675145b20..5822b35c74ec64e3b1e5d5357294531a8b1bc693 100644 (file)
@@ -18,7 +18,7 @@ struct foo {
 
 #[unsafe_destructor]
 impl Drop for foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             println("Goodbye, World!");
             *self.x += 1;
index 95cb5c6475c187bd75b30c4e1fb0d2044d36de25..bf00dc139d0f594ce248cfc4af7b74024a27be48 100644 (file)
@@ -13,7 +13,7 @@ struct C {
 }
 
 impl Drop for C {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("dropping: %?", self.x);
     }
 }
index 8eb110e6ce9b33282605e97d2848e9bb4a2fdc7e..5be0a1e708babe6a4a6976e9087206b78595a6dc 100644 (file)
@@ -15,7 +15,7 @@ struct foo {
     }
 
     impl<T> Drop for foo<T> {
-        fn drop(&self) {}
+        fn drop(&mut self) {}
     }
 }
 fn main() { }
index 07adc3d81e5f3a8a8324bf9d36d0814ef6c139c7..7ab7aeea85cadb86cc2f0001edd306bb16ed7ed5 100644 (file)
@@ -3,7 +3,7 @@ struct Foo {
 }
 
 impl Drop for Foo { //~ ERROR cannot implement a destructor on a structure that does not satisfy Send
-    fn drop(&self) {
+    fn drop(&mut self) {
         *self.f = 10;
     }
 }
index 5f0d4bc60ac01b41db7bb5e7fafa29965ba588d8..e7b897ad9068383d6d0393235eda562ae8cb6348 100644 (file)
@@ -20,7 +20,7 @@ struct foo {
 
     #[unsafe_destructor]
     impl Drop for foo {
-        fn drop(&self) {}
+        fn drop(&mut self) {}
     }
 
     fn foo(x: Port<()>) -> foo {
index e64d5b67ab76893678ff75fe959f09febc5f0649..9d057998c790d73579736569725f2e199d71e388 100644 (file)
@@ -15,7 +15,7 @@ struct bar {
 }
 
 impl Drop for bar {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn bar(x:int) -> bar {
index ccbe265000df28186ceaa6e64d3dbeddc816b04b..822c6812116346fa4ae6e27d112d785af71ef915 100644 (file)
@@ -14,7 +14,7 @@ struct r {
 
 #[unsafe_destructor]
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             *(self.i) = *(self.i) + 1;
         }
index c997ce2a2815280a3e65f2d654627fb13adb8300..ab3f8496eaf26352446158e06ab43a841a571b23 100644 (file)
@@ -17,7 +17,7 @@ struct Foo {
 }
 
 impl Drop for Foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         println("Goodbye!");
     }
 }
index ace0f516eef03b5cfbedfe8e9893c3522f885f77..a9a7966ebeb9858eb5cff2debfaf6b6f75d9e874 100644 (file)
@@ -17,7 +17,7 @@ struct Bar {
 }
 
 impl Drop for Bar {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 impl Foo for Bar {
index 0218899bf2ed5a99efde3d4dc43b5d7e13386c6a..50bb074fc7ac7f09cbffb441a2e10a6ed7d19e7b 100644 (file)
@@ -13,7 +13,7 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn main() {
index bee36ea8293457f956de275bee85c56d03997c39..0fcbc847850bebe7b640e6250516a57f6bc56f56 100644 (file)
@@ -14,7 +14,7 @@ struct r {
 
 #[unsafe_destructor]
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             *(self.i) = *(self.i) + 1;
         }
index 0622c028c631bb116bcbe6bc36104b2f75973780..5440e1e2728c5991857664331afe7b75a003c31f 100644 (file)
@@ -3,7 +3,7 @@ struct S {
 }
 
 impl Drop for S {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 impl S {
index 2d59e490e0d7b21140dd38952cee9fb96c1f1df7..e7441a2c9681800e59747f79b3e856ca19b93806 100644 (file)
@@ -17,7 +17,7 @@ struct r {
 fn r(i:int) -> r { r { i: i } }
 
 impl Drop for r {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn main() {
index e996b249d369ee434dde633dc902264120579ee9..47c9bd469d4098685fa4c6f35683eacfa822c6ea 100644 (file)
@@ -42,7 +42,7 @@ struct StructWithDestructor {
 }
 
 impl Drop for StructWithDestructor {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn main() {
index d3e27c85b745af044589d162c3551803dcf0c65d..a21c98b9d1b82a6d6bee165cdf10088333417d67 100644 (file)
@@ -78,7 +78,7 @@ struct StructWithDrop {
 }
 
 impl Drop for StructWithDrop {
-    fn drop(&self) {()}
+    fn drop(&mut self) {()}
 }
 
 fn main() {
index 47e4a26ab4ba29d892c518161256aba0a9263155..f684a60b68805c05a815e8bbdd4325ba0214e142 100644 (file)
@@ -49,7 +49,7 @@ struct Packed {
 }
 
 impl Drop for Packed {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 #[packed]
@@ -74,7 +74,7 @@ struct Unpacked {
 }
 
 impl Drop for Unpacked {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 #[packed]
@@ -94,7 +94,7 @@ struct PackedInPackedWithDrop {
 }
 
 impl Drop for PackedInPackedWithDrop {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 struct PackedInUnpackedWithDrop {
@@ -105,7 +105,7 @@ struct PackedInUnpackedWithDrop {
 }
 
 impl Drop for PackedInUnpackedWithDrop {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 #[packed]
@@ -117,7 +117,7 @@ struct UnpackedInPackedWithDrop {
 }
 
 impl Drop for UnpackedInPackedWithDrop {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 struct DeeplyNested {
index 8994a582b58fc7cabd337939d60a6037e1a1aac7..18c5994fe2a8c6d1cde26c985f5737c569256e8c 100644 (file)
@@ -37,7 +37,7 @@ struct WithDestructor {
 }
 
 impl Drop for WithDestructor {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 struct NoDestructorGuarded {
@@ -55,7 +55,7 @@ struct NestedInner {
 }
 
 impl Drop for NestedInner {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 struct NestedOuter {
diff --git a/src/test/pretty/path-type-bounds.rs b/src/test/pretty/path-type-bounds.rs
new file mode 100644 (file)
index 0000000..a62fbde
--- /dev/null
@@ -0,0 +1,13 @@
+// pp-exact
+
+trait Tr { }
+impl Tr for int;
+
+fn foo(x: ~Tr: Freeze) -> ~Tr: Freeze { x }
+
+fn main() {
+    let x: ~Tr: Freeze;
+
+    ~1 as ~Tr: Freeze;
+}
+
index 3e78fd1f7db5bb9544cd3311acab6ec4472e4323..451105b0c529e5ed93df0888a4aacc98ffef2cd2 100644 (file)
@@ -15,7 +15,7 @@ struct R {
 }
 
 impl Drop for R {
-    fn drop(&self) {
+    fn drop(&mut self) {
         let _y = R { b: self.b };
     }
 }
index bf03695855e4a51f16a092f61495d6c84e1a10b5..5ac3092640038ae3f4d78a85c81ac2d87041fee3 100644 (file)
@@ -45,7 +45,7 @@ struct and_then_get_big_again {
 }
 
 impl Drop for and_then_get_big_again {
-    fn drop(&self) {
+    fn drop(&mut self) {
         fn getbig(i: int) {
             if i != 0 {
                 getbig(i - 1);
index 4a8586fd19f35e107e6729ca333c0cad2138a95e..e6f219710b37bc0b5a43089c3ef224b3aebe0f8f 100644 (file)
@@ -31,7 +31,7 @@ struct and_then_get_big_again {
 }
 
 impl Drop for and_then_get_big_again {
-    fn drop(&self) {
+    fn drop(&mut self) {
         fn getbig(i: int) {
             if i != 0 {
                 getbig(i - 1);
index b6fe25bc7a2ed1e8fac1be8368462cf1c3f8b4ee..02a65e91d04456e0890d25a7f2f08f6bd3bcb0cd 100644 (file)
@@ -31,7 +31,7 @@ struct and_then_get_big_again {
 }
 
 impl Drop for and_then_get_big_again {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn and_then_get_big_again(x:int) -> and_then_get_big_again {
index d78dedfa39dc011f32096cde33f863eaaf02ccf9..01f745850906eb1f9391ff8e9774363e7bb535af 100644 (file)
@@ -21,7 +21,7 @@ struct r {
 // failed has no effect and the process exits with the
 // runtime's exit code
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         os::set_exit_status(50);
     }
 }
index 04dea449172da60bce8f612e062c3f2d88befe67..62d25915431a92127461349178b70e3bcd36c620 100644 (file)
@@ -24,7 +24,7 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             if !*(self.recursed) {
                 *(self.recursed) = true;
index 7f022d5761c238c3f9e16796d34cabb00d04cc09..c8a3e77a18c46f09d3d27a46ed09417e420083c1 100644 (file)
@@ -21,7 +21,7 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             let _v2: ~int = cast::transmute(self.v);
         }
index d695caf7b5f974c7e85b55f8e6ba26d9cdb2c2be..6526455b8e2e073a6694271d4feb6bed9b7b48cf 100644 (file)
@@ -15,7 +15,7 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) { fail!("squirrel") }
+    fn drop(&mut self) { fail!("squirrel") }
 }
 
 fn r(i: int) -> r { r { i: i } }
index 6ebb4a742c43c8aeea7fabb793f7b780ec8704ac..67e1d0e8f92ac5752c85bb6bb781cdad20e00838 100644 (file)
@@ -16,7 +16,7 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) { fail!("wombat") }
+    fn drop(&mut self) { fail!("wombat") }
 }
 
 fn r(i: int) -> r { r { i: i } }
index 2de9d4cec77efe3eca0d0422a283849f7b9cbe06..231f6e7b7d579f840b46561821611aff1d08f362 100644 (file)
@@ -19,7 +19,7 @@ fn faily_box(i: @int) -> faily_box { faily_box { i: i } }
 
 #[unsafe_destructor]
 impl Drop for faily_box {
-    fn drop(&self) {
+    fn drop(&mut self) {
         fail!("quux");
     }
 }
index 87c476d781e7eb409b93d12cc7a93402d7caf004..e5470a1cff472ae28c77024a2a903f069f077582 100644 (file)
@@ -17,7 +17,7 @@ struct Test<T> {
 
 #[unsafe_destructor]
 impl<T> Drop for Test<T> {
-    fn drop(&self) { }
+    fn drop(&mut self) { }
 }
 
 fn main() {
index c52371de54af05f7342c33ec08a23f8d4cfe926b..2ab0f4262fb5c9d8d0e1ad011f85448c88386788 100644 (file)
@@ -13,7 +13,7 @@ struct noncopyable {
 }
 
 impl Drop for noncopyable {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("dropped");
     }
 }
index 108ae023e12ab76ce2097c8da17f4f38d43dc82a..2165f73c3bf4ce3da2595532635a1992c279111d 100644 (file)
@@ -16,7 +16,7 @@ struct cat {
 
 impl Drop for cat {
     #[cat_dropper]
-    fn drop(&self) { error!("%s landed on hir feet" , self . name); }
+    fn drop(&mut self) { error!("%s landed on hir feet" , self . name); }
 }
 
 
index 02279677276f2e7d4674702b3d6ac19f10e41df8..30cafff0388c57cd822141ade391be12429f8ab5 100644 (file)
@@ -17,7 +17,7 @@ impl Drop for cat {
     /**
        Actually, cats don't always land on their feet when you drop them.
     */
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("%s landed on hir feet", self.name);
     }
 }
index c294670faa3d9591f605b283eee9f5921bcb429f..8ee382eaa38f949435cd99ce8b57a21a85c96acc 100644 (file)
@@ -14,7 +14,7 @@ struct cat {
 }
 
 impl Drop for cat {
-    fn drop(&self) {
+    fn drop(&mut self) {
         (self.done)(self.meows);
     }
 }
diff --git a/src/test/run-pass/cond-macro-no-default.rs b/src/test/run-pass/cond-macro-no-default.rs
deleted file mode 100644 (file)
index 8bd1a77..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn clamp<T:Ord + Signed>(x: T, mn: T, mx: T) -> T {
-    cond!(
-        (x > mx) { return mx; }
-        (x < mn) { return mn; }
-    )
-    return x;
-}
-
-fn main() {
-    assert_eq!(clamp(1, 2, 4), 2);
-    assert_eq!(clamp(8, 2, 4), 4);
-    assert_eq!(clamp(3, 2, 4), 3);
-}
diff --git a/src/test/run-pass/cond-macro.rs b/src/test/run-pass/cond-macro.rs
deleted file mode 100644 (file)
index 61a51b6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn clamp<T:Ord + Signed>(x: T, mn: T, mx: T) -> T {
-    cond!(
-        (x > mx) { mx }
-        (x < mn) { mn }
-        _        { x  }
-    )
-}
-
-fn main() {
-    assert_eq!(clamp(1, 2, 4), 2);
-    assert_eq!(clamp(8, 2, 4), 4);
-    assert_eq!(clamp(3, 2, 4), 3);
-}
index cb5a5294acf92d9cf0dc876f33a8b67de09247b3..39453af83c3815013eaeac873eb97759c9481687 100644 (file)
@@ -14,7 +14,7 @@ struct S<T> {
 
 #[unsafe_destructor]
 impl<T> ::std::ops::Drop for S<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         println("bye");
     }
 }
index 35d59770d12e81e6bd8a18aee697d005e97a5af6..e36379295c419e2f4b103596b418fd115884aa91 100644 (file)
@@ -13,7 +13,7 @@ struct Foo {
 }
 
 impl Drop for Foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         println("bye");
     }
 }
index 1937c366831ffc795de87530dcb49eefd1790b34..ed9871b5edb2d025f89f7c38f1147d12e58dea4f 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // Test that we ignore modes when calling extern functions.
+// xfail-fast #9205
 
 #[deriving(Eq)]
 struct TwoU64s {
index b543099b3b8f8f4990ecc508ef8d1ff20f9680d2..772970ce8a3376ced5c8aa7018eb6d0847364807 100644 (file)
@@ -14,6 +14,7 @@
 // xfail-fast This works standalone on windows but not with check-fast.
 // possibly because there is another test that uses this extern fn but gives it
 // a different signature
+// xfail-fast #9205
 
 #[deriving(Eq)]
 struct TwoU64s {
index 4dc31d715260b2707ffbd34521f941c198e31433..7fcbe3670fc0a3ce313eb16982613688e59de9ff 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// xfail-fast #9205
+
 struct TwoU64s {
     one: u64, two: u64
 }
index cebd29100703616c6665c5ecaf2ea85000f43f41..d1964b5d94b82db4f08a3dbc25c65bae5585916b 100644 (file)
@@ -20,8 +20,8 @@ pub fn main() {
 
     match getopts(args, opts) {
         Ok(ref m)  =>
-            assert!(!opt_present(m, "b")),
-        Err(ref f) => fail!(fail_str((*f).clone()))
+            assert!(!m.opt_present("b")),
+        Err(ref f) => fail!((*f).clone().to_err_msg())
     };
 
 }
index 351bad193da2dfc85249039f122df30e7a2241c2..6ca21c6c5a198b6df1a15fe04f3ea48f29c8c878 100644 (file)
@@ -243,6 +243,10 @@ pub fn main() {
     }
 
     test_format_args();
+
+    // test that trailing commas are acceptable
+    format!("{}", "test",);
+    format!("{foo}", foo="test",);
 }
 
 // Basic test to make sure that we can invoke the `write!` macro with an
index 0b5e58526f6343e576dd6a9364cc5462c8d67059..fb6204866dfdf6612ec59e2589646c219b3d17f1 100644 (file)
@@ -19,7 +19,7 @@ struct Box { x: r }
 
 #[unsafe_destructor]
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *(self.i) = *(self.i) + 1;
     }
 }
index 0f9f1102aeac7aa74116e419a60262102610788c..c12325e6ff52ebec38f9b43e211e8f99d5cd11a6 100644 (file)
@@ -14,7 +14,7 @@ struct socket {
 }
 
 impl Drop for socket {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 impl socket {
index 44ace16fb95ea5d62d23331f98800db0042efee1..1fce8e5ce4996692dc012946e62c863657c984c6 100644 (file)
@@ -16,7 +16,7 @@ struct Font {
 }
 
 impl Drop for Font {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn Font() -> Font {
index edfae096407b6f77d7e1da4bc5ccdd13feb515f9..19f0843efd82c81d85742672bdc3862238e88172 100644 (file)
@@ -161,7 +161,7 @@ pub struct send_packet<T> {
 
     #[unsafe_destructor]
     impl<T:Send> Drop for send_packet<T> {
-        fn drop(&self) {
+        fn drop(&mut self) {
             unsafe {
                 if self.p != None {
                     let self_p: &mut Option<*packet<T>> =
@@ -191,7 +191,7 @@ pub struct recv_packet<T> {
 
     #[unsafe_destructor]
     impl<T:Send> Drop for recv_packet<T> {
-        fn drop(&self) {
+        fn drop(&mut self) {
             unsafe {
                 if self.p != None {
                     let self_p: &mut Option<*packet<T>> =
index b44d50921a5ea4b55076a3f8f9d426b313c019c2..3be634c1e58f8007d2b3d8453a17c67fa062996b 100644 (file)
@@ -15,7 +15,7 @@ struct defer {
 
 #[unsafe_destructor]
 impl Drop for defer {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *self.b = true;
     }
 }
index 902b2f69d614a1f4f3dd04b03ad0a87b4af3d8d8..8999ffd5f7f09df325e38ad349647784c08ce6a4 100644 (file)
@@ -15,7 +15,7 @@ struct defer {
 
 #[unsafe_destructor]
 impl Drop for defer {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *self.b = true;
     }
 }
index a80a079b69514071568bca13b9bfb5219a9408b7..f325756d3687651261bfa18245797e54041636a0 100644 (file)
@@ -19,7 +19,7 @@ struct Kitty {
 }
 
 impl Drop for Kitty {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 #[cfg(target_arch = "x86_64")]
index dce6d8f0bf1048fceac61d174f7cda304864456d..9c44a7cfcc3073f50044d038aa353ab6d937fa7c 100644 (file)
@@ -11,7 +11,7 @@
 struct thing { x: int, }
 
 impl Drop for thing {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn thing() -> thing {
index 3c4c4889ba2f81c6a6f1c100a7ad405797dea275..9040d5b5fb5f98ee11136d4b5677590c66ce7d03 100644 (file)
@@ -57,7 +57,7 @@ struct AsciiArt {
 }
 
 impl Drop for AsciiArt {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 // It's common to define a constructor sort of function to create struct instances.
diff --git a/src/test/run-pass/issue-4208.rs b/src/test/run-pass/issue-4208.rs
new file mode 100644 (file)
index 0000000..e8b633c
--- /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:issue-4208-cc.rs
+// xfail-fast - Windows hates cross-crate tests
+
+extern mod numeric;
+use numeric::*;
+
+fn foo<T, A:Angle<T>>(theta: A) -> T { sin(&theta) }
+
+fn main() {}
index de1f630a245b876a92dcc12976904a196fc60d95..121757fb5904655bac08600cbb7f36c1f4982f3e 100644 (file)
@@ -26,7 +26,7 @@ fn call(&self) {
 }
 
 impl<T: X> Drop for Z<T> {
-    fn drop(&self) {
+    fn drop(&mut self) {
         self.x.call(); // Adding this statement causes an ICE.
     }
 }
index c1ea98283b15cd678a22d5794eafdc78b2cea67c..8451d281aa0abae1df328c95e480effd795a49b9 100644 (file)
@@ -15,7 +15,7 @@
 struct NonCopyable(*c_void);
 
 impl Drop for NonCopyable {
-    fn drop(&self) {
+    fn drop(&mut self) {
         let p = **self;
         let _v = unsafe { transmute::<*c_void, ~int>(p) };
     }
diff --git a/src/test/run-pass/issue-5008-borrowed-traitobject-method-call.rs b/src/test/run-pass/issue-5008-borrowed-traitobject-method-call.rs
new file mode 100644 (file)
index 0000000..ce9bb72
--- /dev/null
@@ -0,0 +1,43 @@
+// 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.
+
+/*
+
+#5008 cast to &Trait causes code to segfault on method call
+
+It fixes itself if the &Trait is changed to @Trait.
+*/
+
+trait Debuggable {
+    fn debug_name(&self) -> ~str;
+}
+
+#[deriving(Clone)]
+struct Thing {
+name: ~str,
+}
+
+impl Thing {
+    fn new() -> Thing { Thing { name: ~"dummy" } }
+}
+
+impl Debuggable for Thing {
+    fn debug_name(&self) -> ~str { self.name.clone() }
+}
+
+fn print_name(x: &Debuggable)
+{
+    println(fmt!("debug_name = %s", x.debug_name()));
+}
+
+fn main() {
+    let thing = Thing::new();
+    print_name(&thing as &Debuggable);
+}
index 29fc0744305849a27c29572ef80f0cc6dc21f849..f57482b67e049bc1b321d588d830f40ddc91d111 100644 (file)
@@ -12,7 +12,7 @@
 struct A { x: uint }
 
 impl Drop for A {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn main() {}
\ No newline at end of file
index 5cda0690029810c1c3826942df09b317191459a7..6e0b6101d37484b004388cc392a9191a51ad1a8f 100644 (file)
@@ -10,7 +10,7 @@
 struct A { x: uint }
 
 impl Drop for A {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn main() {
index 4b1d274c40df9af68bc439843479be239b3b907d..b9429fc63fd28e5ebf32c7b72e2d73a35a420c4a 100644 (file)
@@ -10,7 +10,7 @@
 struct A { x: uint }
 
 impl Drop for A {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn main() {
diff --git a/src/test/run-pass/issue-7519-match-unit-in-arg.rs b/src/test/run-pass/issue-7519-match-unit-in-arg.rs
new file mode 100644 (file)
index 0000000..ba84dd4
--- /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.
+
+/*
+#7519 ICE pattern matching unit in function argument
+*/
+
+fn foo(():()) { }
+
+fn main() {
+    foo(());
+}
diff --git a/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs b/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs
new file mode 100644 (file)
index 0000000..2f2b736
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+/*
+
+#7673 Polymorphically creating traits barely works
+
+*/
+
+fn main() {}
+
+trait A {}
+impl<T: 'static> A for T {}
+
+fn owned1<T: 'static>(a: T) { ~a as ~A:; } /* note `:` */
+fn owned2<T: 'static>(a: ~T) { a as ~A:; }
+fn owned3<T: 'static>(a: ~T) { ~a as ~A:; }
+
+fn managed1<T: 'static>(a: T) { @a as @A; }
+fn managed2<T: 'static>(a: @T) { a as @A; }
+fn managed3<T: 'static>(a: @T) { @a as @A; }
diff --git a/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs b/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs
new file mode 100644 (file)
index 0000000..be68d50
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+/*
+
+#8171 Self is not recognised as implementing kinds in default method implementations
+
+*/
+
+fn require_send<T: Send>(_: T){}
+
+trait TragicallySelfIsNotSend: Send {
+    fn x(self) {
+        require_send(self);
+    }
+}
+
+fn main(){}
index a68aaeb38a2972281a705f933cbcb8870f0c7672..4c4f19d51664e556a3b5272d3ddef47305530e77 100644 (file)
@@ -14,7 +14,7 @@ struct r {
 
 #[unsafe_destructor]
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *(self.b) += 1;
     }
 }
diff --git a/src/test/run-pass/nested-enum-same-names.rs b/src/test/run-pass/nested-enum-same-names.rs
new file mode 100644 (file)
index 0000000..7d9b744
--- /dev/null
@@ -0,0 +1,49 @@
+// 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.
+
+/*
+
+#7770 ICE with sibling methods containing same-name-enum containing
+ same-name-member
+
+If you have two methods in an impl block, each containing an enum
+(with the same name), each containing at least one value with the same
+name, rustc gives the same LLVM symbol for the two of them and fails,
+as it does not include the method name in the symbol name.
+
+*/
+
+pub struct Foo;
+impl Foo {
+    pub fn foo() {
+        enum Panic { Common };
+    }
+    pub fn bar() {
+        enum Panic { Common };
+    }
+}
+
+/*
+#2074 duplicate symbols with enum in boxed closure
+*/
+
+fn foo() {
+    let one: @fn() -> uint = || {
+        enum r { a }
+        a as uint
+    };
+    let two: @fn() -> uint = || {
+        enum r { a }
+        a as uint
+    };
+    one(); two();
+}
+
+fn main() {}
index b917bf0810b2d6da4dcadd5d9a673ae87e76f5a4..578f80f1ca51edd0d02bb58e67ca0a6bd4e28323 100644 (file)
@@ -14,7 +14,7 @@
 
 #[unsafe_destructor]
 impl Drop for Foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         ***self = 23;
     }
 }
index b58c8738295da925923dba8c2c9c40ce5cacae97..37b9b5fe068379e8963708895017a2ae5ad3eec1 100644 (file)
@@ -5,7 +5,7 @@
 
 impl Drop for Fd {
     #[fixed_stack_segment] #[inline(never)]
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             libc::close(**self);
         }
diff --git a/src/test/run-pass/nul-characters.rs b/src/test/run-pass/nul-characters.rs
new file mode 100644 (file)
index 0000000..2a301d0
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main()
+{
+    let all_nuls1 = "\0\x00\u0000\U00000000";
+    let all_nuls2 = "\U00000000\u0000\x00\0";
+    let all_nuls3 = "\u0000\U00000000\x00\0";
+    let all_nuls4 = "\x00\u0000\0\U00000000";
+
+    // sizes for two should suffice
+    assert_eq!(all_nuls1.len(), 4); 
+    assert_eq!(all_nuls2.len(), 4);
+
+    // string equality should pass between the strings
+    assert_eq!(all_nuls1, all_nuls2);
+    assert_eq!(all_nuls2, all_nuls3);
+    assert_eq!(all_nuls3, all_nuls4);
+    
+    // all extracted characters in all_nuls are equivalent to each other
+    for c1 in all_nuls1.iter()
+    {
+        for c2 in all_nuls1.iter()
+        {
+            assert_eq!(c1,c2);
+        }
+    }
+    
+    // testing equality between explicit character literals
+    assert_eq!('\0', '\x00');
+    assert_eq!('\u0000', '\x00');
+    assert_eq!('\u0000', '\U00000000');
+
+    // NUL characters should make a difference
+    assert!("Hello World" != "Hello \0World");
+    assert!("Hello World" != "Hello World\0");
+}
index a469e4b86ebcd27c8a76143aac9f5ebd526ca27a..66cd7f2b55f7499e5ee58e6152fef537e3ac638e 100644 (file)
@@ -15,7 +15,7 @@ struct dtor {
 
 #[unsafe_destructor]
 impl Drop for dtor {
-    fn drop(&self) {
+    fn drop(&mut self) {
         // abuse access to shared mutable state to write this code
         *self.x -= 1;
     }
index 0f6aaeb3861d4385f9a9e0faa30d10943f4e5ac3..dd5450de62fdb4280d49af78bc9a99bb7bebdef9 100644 (file)
@@ -14,7 +14,7 @@ struct r {
 
 #[unsafe_destructor]
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *(self.i) += 1;
     }
 }
index db73aac2eae4e1c2e6cef315f501a9630aae7041..a5354fd01cd83083703788805a383d2085b671c1 100644 (file)
@@ -17,10 +17,10 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             info!("r's dtor: self = %x, self.v = %x, self.v's value = %x",
-              cast::transmute::<*r, uint>(self),
+              cast::transmute::<*mut r, uint>(self),
               cast::transmute::<**int, uint>(&(self.v)),
               cast::transmute::<*int, uint>(self.v));
             let _v2: ~int = cast::transmute(self.v);
index 0cfd3a93e53506a1ed6df0a914d61d8462532033..45ee6ce802149d0662857497331b4dfcda42b84e 100644 (file)
@@ -23,7 +23,7 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             let _v2: ~int = cast::transmute(self.v.c);
         }
index 1e0d8447aeb5521b5473b4e6c2b1766d288c4145..0435f0bdcfd8b00cfce8cb8303efb498a569e227 100644 (file)
@@ -27,7 +27,7 @@ struct R {
 }
 
 impl Drop for R {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             let _v2: ~int = cast::transmute(self.v.c);
             // let _v3: ~int = cast::transmute_copy(self.x);
index 08d56a930d26238697f1ffafa6182a0d0e7469fd..d92cfb5b9a54fd64034d2200b6540f3b29c69f79 100644 (file)
@@ -14,7 +14,7 @@ struct shrinky_pointer {
 
 #[unsafe_destructor]
 impl Drop for shrinky_pointer {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!(~"Hello!"); **(self.i) -= 1;
     }
 }
index 5fdda9dc0790900cfffb72fbb6666a41010befe0..d59f79eb2f1bda671e0d2341c041ce3f0202a018 100644 (file)
@@ -20,7 +20,7 @@ struct close_res {
 
 #[unsafe_destructor]
 impl Drop for close_res {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *(self.i) = false;
     }
 }
index e3435fd547b189f7eb48521b7ca8759405ae99e2..81e2d0a8ac8ca834e8dc6ec694c3b5ed8942fc61 100644 (file)
@@ -15,7 +15,7 @@ struct test {
 }
 
 impl Drop for test {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn test(f: int) -> test {
index 2fc6833242f28cdbb992c881ab9a2793074757a2..f983830936a1f482b37807c4c26abfa0c9d140f1 100644 (file)
@@ -13,7 +13,7 @@ struct foo {
 }
 
 impl Drop for foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("%s", self.x);
     }
 }
index 3f63902eb3193f298888d9510a58567720bc8f68..a1f5a2392b152e6fafa3f3f76e4931945a934183 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// xfail-fast #9205
+
 pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
 pub struct Floats { a: f64, b: u8, c: f64 }
 
index 84b031157656f0ddd5aadba7765a1f1c7e94e247..10116e569467cc344e65ea7a5e7401ea5dcaf1ce 100644 (file)
@@ -24,7 +24,7 @@ struct notify {
 
 #[unsafe_destructor]
 impl Drop for notify {
-    fn drop(&self) {
+    fn drop(&mut self) {
         unsafe {
             error!("notify: task=%? v=%x unwinding=%b b=%b",
                    0,
index 4d6efc9772ce096a49b10ce0586863fd5b29b794..a1cb0063322dc601760e685fedbca6d298a00c7b 100644 (file)
@@ -19,7 +19,7 @@ struct r {
 }
 
 impl Drop for r {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn r(i:int) -> r {
index 7b604bb7857c9455fd97a75427209f2874dbb96a..6ba3866bb6d43c9b9ffe1bf3d998b32a7c3a54b2 100644 (file)
@@ -14,7 +14,7 @@ struct r {
 
 #[unsafe_destructor]
 impl Drop for r {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *(self.i) = *(self.i) + 1;
     }
 }
index 41b971d64d023089ff76f66057955901bb508bb7..b8ca66e89793a15c379c329b85a5fc285a06ffea 100644 (file)
@@ -16,7 +16,7 @@
 struct Foo;
 
 impl Drop for Foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         fail!("This failure should happen.");
     }
 }
index bde90e3726ed3d7fdc45bcbf4d3fdf96cbbaf30a..f1d5009fe88944f78819c8fd4c6a006fad78f310 100644 (file)
@@ -20,7 +20,7 @@ struct complainer {
 }
 
 impl Drop for complainer {
-    fn drop(&self) {
+    fn drop(&mut self) {
         error!("About to send!");
         self.c.send(true);
         error!("Sent!");
index 4d550d9e4b2f49505eddb6f20b2be2e28e937899..5b0cd17eea05eca5e735173399d79ebf51f4940a 100644 (file)
@@ -18,7 +18,7 @@ struct complainer {
 
 #[unsafe_destructor]
 impl Drop for complainer {
-    fn drop(&self) {}
+    fn drop(&mut self) {}
 }
 
 fn complainer(c: @int) -> complainer {
index 85293405695e6a14570227dd8380b469005836c5..2a4bd2a8cf9a615848e41c0d943797cb679f8f1b 100644 (file)
@@ -15,7 +15,7 @@ struct foo {
 
 #[unsafe_destructor]
 impl Drop for foo {
-    fn drop(&self) {
+    fn drop(&mut self) {
         *self.x += 1;
     }
 }
diff --git a/src/test/run-pass/xcrate-address-insignificant.rs b/src/test/run-pass/xcrate-address-insignificant.rs
new file mode 100644 (file)
index 0000000..1bf3763
--- /dev/null
@@ -0,0 +1,18 @@
+// 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.
+
+// xfail-fast windows doesn't like aux-build
+// aux-build:xcrate_address_insignificant.rs
+
+extern mod foo(name = "xcrate_address_insignificant");
+
+fn main() {
+    assert_eq!(foo::foo::<float>(), foo::bar());
+}
index 059a6f75ac82e2cbbdc92dc96bc64bb826dc0f36..7eb4adfd0675755a456d106406787d5a42389a52 100644 (file)
@@ -17,6 +17,7 @@
 
 pub fn main() {
     other::verify_same(&other::global);
+    other::verify_same2(other::global2);
 
     // Previously this fail'd because there were two addresses that were being
     // used when declaring constants.