]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #8718 : bblum/rust/typeof, r=pcwalton
authorbors <bors@rust-lang.org>
Wed, 28 Aug 2013 22:30:38 +0000 (15:30 -0700)
committerbors <bors@rust-lang.org>
Wed, 28 Aug 2013 22:30:38 +0000 (15:30 -0700)
r? anybody

396 files changed:
.gitattributes
.gitmodules
Makefile.in
doc/rust.md
doc/tutorial-tasks.md
doc/tutorial.md
mk/rt.mk
mk/tests.mk
src/compiletest/common.rs
src/compiletest/compiletest.rs
src/compiletest/procsrv.rs
src/compiletest/runtest.rs
src/etc/emacs/rust-mode.el
src/etc/generate-keyword-tests.py [new file with mode: 0755]
src/etc/x86.supp
src/libextra/arc.rs
src/libextra/crypto/cryptoutil.rs
src/libextra/dlist.rs
src/libextra/flate.rs
src/libextra/getopts.rs
src/libextra/json.rs
src/libextra/num/bigint.rs
src/libextra/num/rational.rs
src/libextra/priority_queue.rs
src/libextra/ringbuf.rs
src/libextra/stats.rs
src/libextra/sync.rs
src/libextra/test.rs
src/libextra/time.rs
src/libextra/treemap.rs
src/libextra/uuid.rs
src/librustc/back/arm.rs
src/librustc/back/link.rs
src/librustc/back/mips.rs
src/librustc/back/passes.rs [deleted file]
src/librustc/back/x86.rs
src/librustc/back/x86_64.rs
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/front/std_inject.rs
src/librustc/front/test.rs
src/librustc/lib/llvm.rs
src/librustc/metadata/common.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/csearch.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/metadata/filesearch.rs
src/librustc/metadata/loader.rs
src/librustc/metadata/tydecode.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/astencode.rs
src/librustc/middle/borrowck/check_loans.rs
src/librustc/middle/borrowck/gather_loans/gather_moves.rs
src/librustc/middle/borrowck/gather_loans/lifetime.rs
src/librustc/middle/borrowck/gather_loans/mod.rs
src/librustc/middle/borrowck/gather_loans/restrictions.rs
src/librustc/middle/borrowck/mod.rs
src/librustc/middle/check_const.rs
src/librustc/middle/lint.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/moves.rs
src/librustc/middle/privacy.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve.rs
src/librustc/middle/stack_check.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/adt.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/context.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/meth.rs
src/librustc/middle/trans/monomorphize.rs
src/librustc/middle/trans/reflect.rs
src/librustc/middle/trans/type_use.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/collect.rs
src/librustc/middle/typeck/infer/glb.rs
src/librustc/middle/typeck/infer/lub.rs
src/librustc/middle/typeck/infer/sub.rs
src/librustc/rustc.rs
src/librustc/util/ppaux.rs
src/librustdoc/markdown_writer.rs
src/librustpkg/path_util.rs
src/librustpkg/rustpkg.rs
src/librustpkg/search.rs
src/librustpkg/source_control.rs
src/librustpkg/tests.rs
src/librustpkg/util.rs
src/librustpkg/version.rs
src/librustpkg/workspace.rs
src/libstd/at_vec.rs
src/libstd/c_str.rs
src/libstd/cast.rs
src/libstd/cell.rs
src/libstd/cleanup.rs
src/libstd/default.rs [new file with mode: 0644]
src/libstd/fmt/mod.rs
src/libstd/hash.rs
src/libstd/hashmap.rs
src/libstd/io.rs
src/libstd/iterator.rs
src/libstd/libc.rs
src/libstd/local_data.rs
src/libstd/logging.rs
src/libstd/macros.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/num/float.rs
src/libstd/num/int_macros.rs
src/libstd/num/num.rs
src/libstd/num/uint_macros.rs
src/libstd/option.rs
src/libstd/os.rs
src/libstd/prelude.rs
src/libstd/ptr.rs
src/libstd/reflect.rs
src/libstd/repr.rs
src/libstd/rt/borrowck.rs
src/libstd/rt/comm.rs
src/libstd/rt/context.rs
src/libstd/rt/io/extensions.rs
src/libstd/rt/io/file.rs
src/libstd/rt/io/mod.rs
src/libstd/rt/io/net/ip.rs
src/libstd/rt/io/net/tcp.rs
src/libstd/rt/io/net/udp.rs
src/libstd/rt/io/pipe.rs [new file with mode: 0644]
src/libstd/rt/io/timer.rs
src/libstd/rt/kill.rs
src/libstd/rt/local.rs
src/libstd/rt/local_heap.rs
src/libstd/rt/local_ptr.rs
src/libstd/rt/message_queue.rs
src/libstd/rt/metrics.rs [deleted file]
src/libstd/rt/mod.rs
src/libstd/rt/rtio.rs
src/libstd/rt/sched.rs
src/libstd/rt/select.rs
src/libstd/rt/sleeper_list.rs
src/libstd/rt/stack.rs
src/libstd/rt/task.rs
src/libstd/rt/thread_local_storage.rs
src/libstd/rt/tube.rs
src/libstd/rt/util.rs
src/libstd/rt/uv/async.rs
src/libstd/rt/uv/file.rs
src/libstd/rt/uv/idle.rs
src/libstd/rt/uv/mod.rs
src/libstd/rt/uv/net.rs
src/libstd/rt/uv/pipe.rs [new file with mode: 0644]
src/libstd/rt/uv/process.rs [new file with mode: 0644]
src/libstd/rt/uv/timer.rs
src/libstd/rt/uv/uvio.rs
src/libstd/rt/uv/uvll.rs
src/libstd/run.rs
src/libstd/select.rs
src/libstd/std.rs
src/libstd/str.rs
src/libstd/sys.rs
src/libstd/task/local_data_priv.rs [deleted file]
src/libstd/task/mod.rs
src/libstd/task/spawn.rs
src/libstd/to_bytes.rs
src/libstd/tuple.rs
src/libstd/unit.rs
src/libstd/unstable/atomics.rs
src/libstd/unstable/dynamic_lib.rs
src/libstd/unstable/intrinsics.rs
src/libstd/unstable/lang.rs
src/libstd/unstable/raw.rs
src/libstd/unstable/sync.rs
src/libstd/util.rs
src/libstd/vec.rs
src/libsyntax/ast.rs
src/libsyntax/ast_util.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/concat_idents.rs
src/libsyntax/ext/deriving/rand.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/ifmt.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/fold.rs
src/libsyntax/oldvisit.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/obsolete.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/libuv
src/rt/arch/x86_64/_context.S
src/rt/arch/x86_64/ccall.S
src/rt/arch/x86_64/morestack.S
src/rt/arch/x86_64/regs.h
src/rt/arch/x86_64/sp.h
src/rt/memory_region.cpp
src/rt/memory_region.h
src/rt/rust_abi.cpp [deleted file]
src/rt/rust_abi.h [deleted file]
src/rt/rust_builtin.cpp
src/rt/rust_exchange_alloc.cpp [deleted file]
src/rt/rust_exchange_alloc.h [deleted file]
src/rt/rust_gc_metadata.cpp [deleted file]
src/rt/rust_gc_metadata.h [deleted file]
src/rt/rust_test_helpers.cpp
src/rt/rust_upcall.cpp
src/rt/rust_util.cpp [deleted file]
src/rt/rust_util.h
src/rt/rust_uv.cpp
src/rt/rustrt.def.in
src/rt/sync/sync.h [deleted file]
src/rt/sync/timer.cpp [deleted file]
src/rt/sync/timer.h [deleted file]
src/rt/util/indexed_list.h [deleted file]
src/rt/vg/valgrind.h
src/rustllvm/PassWrapper.cpp
src/rustllvm/RustWrapper.cpp
src/rustllvm/rustllvm.def.in
src/rustllvm/rustllvm.h
src/test/bench/core-map.rs
src/test/bench/core-set.rs
src/test/compile-fail/attrs-after-extern-mod.rs
src/test/compile-fail/bad-mid-path-type-params.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-alias-mut-base-ptr.rs [deleted file]
src/test/compile-fail/borrowck-assign-to-andmut-in-aliasable-loc.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs
src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs
src/test/compile-fail/borrowck-lend-flow.rs
src/test/compile-fail/borrowck-loan-vec-content.rs
src/test/compile-fail/borrowck-pat-by-value-binding.rs [deleted file]
src/test/compile-fail/borrowck-pat-enum.rs [deleted file]
src/test/compile-fail/borrowck-uniq-via-lend.rs
src/test/compile-fail/borrowck-uniq-via-ref.rs [deleted file]
src/test/compile-fail/fn-variance-3.rs
src/test/compile-fail/ifmt-bad-arg.rs
src/test/compile-fail/ifmt-bad-plural.rs
src/test/compile-fail/ifmt-bad-select.rs
src/test/compile-fail/ifmt-unimpl.rs
src/test/compile-fail/ifmt-unknown-trait.rs
src/test/compile-fail/issue-3969.rs [deleted file]
src/test/compile-fail/issue-4096.rs [deleted file]
src/test/compile-fail/keyword-as-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-break-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-do-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-else-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-enum-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-extern-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-false-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-fn-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-for-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-if-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-impl-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-let-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-loop-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-match-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-mod-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-mut-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-priv-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-pub-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-ref-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-return-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-self-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-static-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-struct-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-super-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-trait-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-true-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-type-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-unsafe-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-use-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/keyword-while-as-identifier.rs [new file with mode: 0644]
src/test/compile-fail/map-types.rs
src/test/compile-fail/mutable-huh-ptr-assign.rs [deleted file]
src/test/compile-fail/prim-with-args.rs
src/test/compile-fail/private-variant-xc.rs
src/test/compile-fail/regions-bounds.rs
src/test/compile-fail/resolve-inconsistent-binding-mode.rs
src/test/compile-fail/static-method-privacy.rs
src/test/compile-fail/xc-private-method.rs
src/test/debug-info/basic-types.rs
src/test/debug-info/borrowed-basic.rs
src/test/debug-info/borrowed-c-style-enum.rs
src/test/debug-info/borrowed-enum.rs
src/test/debug-info/borrowed-managed-basic.rs
src/test/debug-info/borrowed-struct.rs
src/test/debug-info/borrowed-tuple.rs
src/test/debug-info/borrowed-unique-basic.rs
src/test/debug-info/box.rs
src/test/debug-info/boxed-struct.rs
src/test/debug-info/boxed-vec.rs
src/test/debug-info/c-style-enum-in-composite.rs
src/test/debug-info/c-style-enum.rs
src/test/debug-info/closure-in-generic-function.rs
src/test/debug-info/destructured-fn-argument.rs
src/test/debug-info/destructured-local.rs
src/test/debug-info/evec-in-struct.rs
src/test/debug-info/function-arguments.rs
src/test/debug-info/generic-function.rs
src/test/debug-info/generic-functions-nested.rs
src/test/debug-info/generic-method-on-generic-struct.rs
src/test/debug-info/generic-static-method-on-struct-and-enum.rs
src/test/debug-info/generic-struct-style-enum.rs
src/test/debug-info/generic-struct.rs
src/test/debug-info/generic-trait-generic-static-default-method.rs
src/test/debug-info/generic-tuple-style-enum.rs
src/test/debug-info/lexical-scope-in-for-loop.rs
src/test/debug-info/lexical-scope-in-if.rs
src/test/debug-info/lexical-scope-in-managed-closure.rs
src/test/debug-info/lexical-scope-in-match.rs
src/test/debug-info/lexical-scope-in-parameterless-closure.rs
src/test/debug-info/lexical-scope-in-stack-closure.rs
src/test/debug-info/lexical-scope-in-unconditional-loop.rs
src/test/debug-info/lexical-scope-in-unique-closure.rs
src/test/debug-info/lexical-scope-in-while.rs
src/test/debug-info/lexical-scope-with-macro.rs
src/test/debug-info/lexical-scopes-in-block-expression.rs
src/test/debug-info/managed-enum.rs
src/test/debug-info/managed-pointer-within-unique-vec.rs
src/test/debug-info/managed-pointer-within-unique.rs
src/test/debug-info/method-on-enum.rs
src/test/debug-info/method-on-generic-struct.rs
src/test/debug-info/method-on-struct.rs
src/test/debug-info/method-on-trait.rs
src/test/debug-info/method-on-tuple-struct.rs
src/test/debug-info/multiple-functions-equal-var-names.rs
src/test/debug-info/multiple-functions.rs
src/test/debug-info/name-shadowing-and-scope-nesting.rs
src/test/debug-info/nil-enum.rs
src/test/debug-info/option-like-enum.rs
src/test/debug-info/packed-struct-with-destructor.rs
src/test/debug-info/packed-struct.rs
src/test/debug-info/self-in-default-method.rs
src/test/debug-info/self-in-generic-default-method.rs
src/test/debug-info/shadowed-argument.rs
src/test/debug-info/shadowed-variable.rs
src/test/debug-info/simple-lexical-scope.rs
src/test/debug-info/simple-struct.rs
src/test/debug-info/simple-tuple.rs
src/test/debug-info/static-method-on-struct-and-enum.rs
src/test/debug-info/struct-in-enum.rs
src/test/debug-info/struct-in-struct.rs
src/test/debug-info/struct-style-enum.rs
src/test/debug-info/struct-with-destructor.rs
src/test/debug-info/trait-generic-static-default-method.rs
src/test/debug-info/tuple-in-struct.rs
src/test/debug-info/tuple-in-tuple.rs
src/test/debug-info/tuple-struct.rs
src/test/debug-info/tuple-style-enum.rs
src/test/debug-info/unique-enum.rs
src/test/debug-info/vec-slices.rs
src/test/debug-info/vec.rs
src/test/run-pass/auto-ref-slice-plus-ref.rs
src/test/run-pass/autoderef-and-borrow-method-receiver.rs
src/test/run-pass/borrowck-pat-enum.rs [new file with mode: 0644]
src/test/run-pass/borrowck-uniq-via-ref.rs [new file with mode: 0644]
src/test/run-pass/class-impl-very-parameterized-trait.rs
src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs
src/test/run-pass/const-vec-syntax.rs
src/test/run-pass/core-run-destroy.rs
src/test/run-pass/deriving-meta-multiple.rs
src/test/run-pass/deriving-meta.rs
src/test/run-pass/deriving-zero.rs
src/test/run-pass/enum-discrim-width-stuff.rs [new file with mode: 0644]
src/test/run-pass/fixed_length_vec_glue.rs
src/test/run-pass/float-nan.rs
src/test/run-pass/ifmt.rs
src/test/run-pass/issue-3026.rs
src/test/run-pass/issue-5783.rs [new file with mode: 0644]
src/test/run-pass/issue-6898.rs
src/test/run-pass/log-knows-the-names-of-variants-in-std.rs
src/test/run-pass/log-knows-the-names-of-variants.rs
src/test/run-pass/mid-path-type-params.rs [new file with mode: 0644]
src/test/run-pass/objects-owned-object-borrowed-method-header.rs
src/test/run-pass/option_addition.rs [deleted file]
src/test/run-pass/rec-align-u32.rs
src/test/run-pass/rec-align-u64.rs
src/test/run-pass/reflect-visit-data.rs
src/test/run-pass/reflect-visit-type.rs
src/test/run-pass/static-mut-foreign.rs
src/test/run-pass/struct-return.rs
src/test/run-pass/tag-align-shape.rs
src/test/run-pass/trait-bounds-in-arc.rs
src/test/run-pass/trait-default-method-xc.rs
src/test/run-pass/trait-static-method-overwriting.rs

index 22d42a82a3b83108883e23a72f310b6b902f1b09..10505d47e6c5d6d092d1b2fa619760df8055bc1a 100644 (file)
@@ -8,3 +8,6 @@ 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 88ead6e608d5c4ee00212451f47c281d09d00846..fa979b6d868ef4bebdcc7a79891e4f61e27ce328 100644 (file)
@@ -4,5 +4,5 @@
        branch = master
 [submodule "src/libuv"]
        path = src/libuv
-       url = https://github.com/brson/libuv.git
+       url = https://github.com/alexcrichton/libuv.git
        branch = master
index a9a41a073d03366291a404187213a417cd608de6..0575f48c4c467d7695119ccd9a4afea7aa6dba71 100644 (file)
@@ -96,7 +96,8 @@ ifdef CFG_DISABLE_OPTIMIZE
   $(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
   CFG_RUSTC_FLAGS +=
 else
-  CFG_RUSTC_FLAGS += -O
+  # The rtopt cfg turns off runtime sanity checks
+  CFG_RUSTC_FLAGS += -O --cfg rtopt
 endif
 
 ifdef CFG_ENABLE_DEBUG
index 7ac0527e47dcd1dcae5ebf2ed6edc5dd706bd110..08c04c6c8887e9c046c0b9991073385eecbe187c 100644 (file)
@@ -2230,7 +2230,7 @@ Some examples of call expressions:
 # fn add(x: int, y: int) -> int { 0 }
 
 let x: int = add(1, 2);
-let pi = FromStr::from_str::<f32>("3.14");
+let pi: Option<f32> = FromStr::from_str("3.14");
 ~~~~
 
 ### Lambda expressions
index d190c332e6633ade92d1a9ac944aef034caca1db..18f35cf39a8a24895f1067949f41216c3a403a0d 100644 (file)
@@ -113,21 +113,6 @@ do spawn {
 }
 ~~~
 
-By default, the scheduler multiplexes tasks across the available cores, running
-in parallel. Thus, on a multicore machine, running the following code
-should interleave the output in vaguely random order.
-
-~~~
-# use std::io::print;
-# use std::task::spawn;
-
-for child_task_number in range(0, 20) {
-    do spawn {
-       print(fmt!("I am child number %d\n", child_task_number));
-    }
-}
-~~~
-
 ## Communication
 
 Now that we have spawned a new task, it would be nice if we could
index 958c15737615a3bbed9117d2a0a492a65709aaef..7614e8482377c458cde8fe2c38dd9bb059a5a387 100644 (file)
@@ -1864,7 +1864,7 @@ so you could not apply `head` to a type
 that does not implement `Clone`.
 
 While most traits can be defined and implemented by user code,
-two traits are automatically derived and implemented
+three traits are automatically derived and implemented
 for all applicable types by the compiler,
 and may not be overridden:
 
@@ -1877,6 +1877,12 @@ These are types that do not contain anything intrinsically mutable.
 Intrinsically mutable values include `@mut`
 and `Cell` in the standard library.
 
+* `'static` - Non-borrowed types.
+These are types that do not contain any data whose lifetime is bound to
+a particular stack frame. These are types that do not contain any
+borrowed pointers, or types where the only contained borrowed pointers
+have the `'static` lifetime.
+
 > ***Note:*** These two traits were referred to as 'kinds' in earlier
 > iterations of the language, and often still are.
 
@@ -2135,6 +2141,30 @@ select the method to call at runtime.
 
 This usage of traits is similar to Java interfaces.
 
+By default, each of the three storage classes for traits enforce a
+particular set of built-in kinds that their contents must fulfill in
+order to be packaged up in a trait object of that storage class.
+
+* The contents of owned traits (`~Trait`) must fulfill the `Send` bound.
+* The contents of managed traits (`@Trait`) must fulfill the `'static` bound.
+* The contents of borrowed traits (`&Trait`) are not constrained by any bound.
+
+Consequently, the trait objects themselves automatically fulfill their
+respective kind bounds. However, this default behavior can be overridden by
+specifying a list of bounds on the trait type, for example, by writing `~Trait:`
+(which indicates that the contents of the owned trait need not fulfill any
+bounds), or by writing `~Trait:Send+Freeze`, which indicates that in addition
+to fulfilling `Send`, contents must also fulfill `Freeze`, and as a consequence,
+the trait itself fulfills `Freeze`.
+
+* `~Trait:Send` is equivalent to `~Trait`.
+* `@Trait:'static` is equivalent to `@Trait`.
+* `&Trait:` is equivalent to `&Trait`.
+
+Builtin kind bounds can also be specified on closure types in the same way (for
+example, by writing `fn:Freeze()`), and the default behaviours are the same as
+for traits of the same storage class.
+
 ## Trait inheritance
 
 We can write a trait declaration that _inherits_ from other traits, called _supertraits_.
@@ -2221,237 +2251,665 @@ The full list of derivable traits is `Eq`, `TotalEq`, `Ord`,
 `TotalOrd`, `Encodable` `Decodable`, `Clone`, `DeepClone`,
 `IterBytes`, `Rand`, `Zero`, and `ToStr`.
 
-# Modules and crates
+# Crates and the module system
+
+Rust's module system is very powerful, but because of that also somewhat complex.
+Nevertheless, this section will try to explain every important aspect of it.
+
+## Crates
+
+In order to speak about the module system, we first need to define the medium it exists in:
 
-The Rust namespace is arranged in a hierarchy of modules. Each source
-(.rs) file represents a single module and may in turn contain
-additional modules.
+Let's say you've written a program or a library, compiled it, and got the resulting binary.
+In Rust, the content of all source code that the compiler directly had to compile in order to end up with
+that binary is collectively called a 'crate'.
 
+For example, for a simple hello world program your crate only consists of this code:
+
+~~~~
+// main.rs
+fn main() {
+    println("Hello world!");
+}
 ~~~~
+
+A crate is also the unit of independent compilation in Rust: `rustc` always compiles a single crate at a time,
+from which it produces either a library or an executable.
+
+Note that merely using an already compiled library in your code does not make it part of your crate.
+
+## The module hierarchy
+
+For every crate, all the code in it is arranged in a hierarchy of modules starting with a single
+root module. That root module is called the 'crate root'.
+
+All modules in a crate below the crate root are declared with the `mod` keyword:
+
+~~~~
+// This is the crate root
+
 mod farm {
-    pub fn chicken() -> &str { "cluck cluck" }
-    pub fn cow() -> &str { "mooo" }
+    // This is the body of module 'farm' declared in the crate root.
+
+    fn chicken() { println("cluck cluck"); }
+    fn cow() { println("mooo"); }
+
+    mod barn {
+        // Body of module 'barn'
+
+        fn hay() { println("..."); }
+    }
 }
 
 fn main() {
-    println(farm::chicken());
+    println("Hello farm!");
 }
 ~~~~
 
-The contents of modules can be imported into the current scope
-with the `use` keyword, optionally giving it an alias. `use`
-may appear at the beginning of crates, `mod`s, `fn`s, and other
-blocks.
+As you can see, your module hierarchy is now three modules deep: There is the crate root, which contains your `main()`
+function, and the module `farm`. The module `farm` also contains two functions and a third module `barn`,
+which contains a function `hay`.
 
-~~~
-# mod farm { pub fn chicken() { } }
-# fn main() {
-// Bring `chicken` into scope
-use farm::chicken;
+(In case you already stumbled over `extern mod`: It isn't directly related to a bare `mod`, we'll get to it later. )
+
+## Paths and visibility
+
+We've now defined a nice module hierarchy. But how do we access the items in it from our `main` function?
+One way to do it is to simply fully qualifying it:
 
-fn chicken_farmer() {
-    // The same, but name it `my_chicken`
-    use my_chicken = farm::chicken;
-    ...
-# my_chicken();
+~~~~ {.xfail-test}
+mod farm {
+    fn chicken() { println("cluck cluck"); }
+    // ...
 }
-# chicken();
-# }
-~~~
 
-These farm animal functions have a new keyword, `pub`, attached to
-them. The `pub` keyword modifies an item's visibility, making it
-visible outside its containing module. An expression with `::`, like
-`farm::chicken`, can name an item outside of its containing
-module. Items, such as those declared with `fn`, `struct`, `enum`,
-`type`, or `static`, are module-private by default.
+fn main() {
+    println("Hello chicken!");
+
+    ::farm::chicken(); // Won't compile yet, see further down
+}
+~~~~
+
+The `::farm::chicken` construct is what we call a 'path'.
+
+Because it's starting with a `::`, it's also a 'global path',
+which qualifies an item by its full path in the module hierarchy
+relative to the crate root.
+
+If the path were to start with a regular identifier, like `farm::chicken`, it would be
+a 'local path' instead. We'll get to them later.
+
+Now, if you actually tried to compile this code example, you'll notice
+that you get a `unresolved name: 'farm::chicken'` error. That's because per default,
+items (`fn`, `struct`, `static`, `mod`, ...) are only visible inside the module
+they are defined in.
+
+To make them visible outside their containing modules, you need to mark them _public_ with `pub`:
+
+~~~~
+mod farm {
+    pub fn chicken() { println("cluck cluck"); }
+    pub fn cow() { println("mooo"); }
+    // ...
+}
+
+fn main() {
+    println("Hello chicken!");
+    ::farm::chicken(); // This compiles now
+}
+~~~~
 
 Visibility restrictions in Rust exist only at module boundaries. This
 is quite different from most object-oriented languages that also
 enforce restrictions on objects themselves. That's not to say that
 Rust doesn't support encapsulation: both struct fields and methods can
 be private. But this encapsulation is at the module level, not the
-struct level. Note that fields and methods are _public_ by default.
+struct level.
+
+For convenience, fields are _public_ by default, and can be made _private_ with the `priv` keyword:
 
 ~~~
-pub mod farm {
+mod farm {
 # pub type Chicken = int;
-# type Cow = int;
 # struct Human(int);
 # impl Human { fn rest(&self) { } }
-# pub fn make_me_a_farm() -> Farm { Farm { chickens: ~[], cows: ~[], farmer: Human(0) } }
+# pub fn make_me_a_farm() -> Farm { Farm { chickens: ~[], farmer: Human(0) } }
     pub struct Farm {
         priv chickens: ~[Chicken],
-        priv cows: ~[Cow],
         farmer: Human
     }
 
     impl Farm {
         fn feed_chickens(&self) { ... }
-        fn feed_cows(&self) { ... }
         pub fn add_chicken(&self, c: Chicken) { ... }
     }
 
     pub fn feed_animals(farm: &Farm) {
         farm.feed_chickens();
-        farm.feed_cows();
     }
 }
 
 fn main() {
-     let f = make_me_a_farm();
-     f.add_chicken(make_me_a_chicken());
-     farm::feed_animals(&f);
-     f.farmer.rest();
+    let f = make_me_a_farm();
+    f.add_chicken(make_me_a_chicken());
+    farm::feed_animals(&f);
+    f.farmer.rest();
+
+    // This wouldn't compile because both are private:
+    // f.feed_chickens();
+    // let chicken_counter = f.chickens.len();
 }
 # fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() }
 # fn make_me_a_chicken() -> farm::Chicken { 0 }
 ~~~
 
-## Crates
+> ***Note:*** Visibility rules are currently buggy and not fully defined, you might have to add or remove `pub` along a path until it works.
 
-The unit of independent compilation in Rust is the crate: rustc
-compiles a single crate at a time, from which it produces either a
-library or an executable.
-
-When compiling a single `.rs` source file, the file acts as the whole crate.
-You can compile it with the `--lib` compiler switch to create a shared
-library, or without, provided that your file contains a `fn main`
-somewhere, to create an executable.
-
-Larger crates typically span multiple files and are, by convention,
-compiled from a source file with the `.rc` extension, called a *crate file*.
-The crate file extension distinguishes source files that represent
-crates from those that do not, but otherwise source files and crate files are identical.
-
-A typical crate file declares attributes associated with the crate that
-may affect how the compiler processes the source.
-Crate attributes specify metadata used for locating and linking crates,
-the type of crate (library or executable),
-and control warning and error behavior,
-among other things.
-Crate files additionally declare the external crates they depend on
-as well as any modules loaded from other files.
-
-~~~~ { .xfail-test }
-// Crate linkage metadata
-#[link(name = "farm", vers = "2.5", author = "mjh")];
+## Files and modules
 
-// Make a library ("bin" is the default)
-#[crate_type = "lib"];
+One important aspect about Rusts module system is that source files are not important:
+You define a module hierarchy, populate it with all your definitions, define visibility,
+maybe put in a `fn main()`, and that's it: No need to think about source files.
 
-// Turn on a warning
-#[warn(non_camel_case_types)]
+The only file that's relevant is the one that contains the body of your crate root,
+and it's only relevant because you have to pass that file to `rustc` to compile your crate.
 
-// Link to the standard library
-extern mod std;
+And in principle, that's all you need: You can write any Rust program as one giant source file that contains your
+crate root and everything below it in `mod ... { ... }` declarations.
+
+However, in practice you usually want to split you code up into multiple source files to make it more manageable.
+In order to do that, Rust allows you to move the body of any module into it's own source file, which works like this:
 
-// Load some modules from other files
-mod cow;
-mod chicken;
-mod horse;
+If you declare a module without its body, like `mod foo;`, the compiler will look for the
+files `foo.rs` and `foo/mod.rs`. If it finds either, it uses the content of that file as the body of the module.
+If it finds both, that's a compile error.
+
+So, if we want to move the content of `mod farm` into it's own file, it would look like this:
+
+~~~~ {.ignore}
+// main.rs - contains body of the crate root
+mod farm; // Compiler will look for 'farm.rs' and 'farm/mod.rs'
 
 fn main() {
-    ...
+    println("Hello farm!");
+    ::farm::cow();
 }
 ~~~~
 
-Compiling this file will cause `rustc` to look for files named
-`cow.rs`, `chicken.rs`, and `horse.rs` in the same directory as the
-`.rc` file, compile them all together, and, based on the presence of
-the `crate_type = "lib"` attribute, output a shared library or an
-executable. (If the line `#[crate_type = "lib"];` was omitted,
-`rustc` would create an executable.)
+~~~~
+// farm.rs - contains body of module 'farm' in the crate root
+pub fn chicken() { println("cluck cluck"); }
+pub fn cow() { println("mooo"); }
+
+pub mod barn {
+    pub fn hay() { println("..."); }
+}
+# fn main() { }
+~~~~
 
-The `#[link(...)]` attribute provides meta information about the
-module, which other crates can use to load the right module. More
-about that later.
+So, in short `mod foo;` is just syntactic sugar for `mod foo { /* include content of foo.rs or foo/mod.rs here */ }`.
 
-To have a nested directory structure for your source files, you can
-nest mods:
+This also means that having two or more identical `mod foo;` somewhere
+in your crate hierarchy is generally a bad idea,
+just like copy-and-paste-ing a module into two or more places is one.
+Both will result in duplicate and mutually incompatible definitions.
 
-~~~~ {.ignore}
-mod poultry {
-    mod chicken;
-    mod turkey;
+The directory the compiler looks in for those two files is determined by starting with
+the same directory as the source file that contains the `mod foo;` declaration, and concatenating to that a
+path equivalent to the relative path of all nested `mod { ... }` declarations the `mod foo;` is contained in, if any.
+
+For example, given a file with this module body:
+
+~~~ {.ignore}
+// src/main.rs
+mod plants;
+mod fungi;
+mod animals {
+    mod fish;
+    mod mammals {
+        mod humans;
+    }
+}
+~~~
+
+The compiler would then try all these files:
+
+~~~ {.notrust}
+src/plants.rs
+src/plants/mod.rs
+
+src/fungi.rs
+src/fungi/mod.rs
+
+src/animals/fish.rs
+src/animals/fish/mod.rs
+
+src/animals/mammals/humans.rs
+src/animals/mammals/humans/mod.rs
+~~~
+
+These rules per default result in any directory structure mirroring
+the crates's module hierarchy, and allow you to have both small modules that only need
+to consist of one source file, and big modules that group the source files of submodules together.
+
+If you need to circumvent those defaults, you can also overwrite the path a `mod foo;` would take:
+
+~~~ {.ignore}
+#[path="../../area51/classified.rs"]
+mod alien;
+~~~
+
+## Importing names into the local scope
+
+Always referring to definitions in other modules with their global
+path gets old really fast, so Rust has a way to import
+them into the local scope of your module: `use`-statements.
+
+They work like this: At the beginning of any module body, `fn` body, or any other block
+you can write a list of `use`-statements, consisting of the keyword `use` and a __global path__ to an item
+without the `::` prefix. For example, this imports `cow` into the local scope:
+
+~~~
+use farm::cow;
+# mod farm { pub fn cow() { println("I'm a hidden ninja cow!") } }
+# fn main() { cow() }
+~~~
+
+The path you give to `use` is per default global, meaning relative to the crate root,
+no matter how deep the module hierarchy is, or whether the module body it's written in
+is contained in its own file (remember: files are irrelevant).
+
+This is different to other languages, where you often only find a single import construct that combines the semantic
+of `mod foo;` and `use`-statements, and which tend to work relative to the source file or use an absolute file path
+- Rubys `require` or C/C++'s `#include` come to mind.
+
+However, it's also possible to import things relative to the module of the `use`-statement:
+Adding a `super::` in front of the path will start in the parent module,
+while adding a `self::` prefix will start in the current module:
+
+~~~
+# mod workaround {
+# pub fn some_parent_item(){ println("...") }
+# mod foo {
+use super::some_parent_item;
+use self::some_child_module::some_item;
+# pub fn bar() { some_parent_item(); some_item() }
+# pub mod some_child_module { pub fn some_item() {} }
+# }
+# }
+~~~
+
+Again - relative to the module, not to the file.
+
+Imports are also shadowed by local definitions:
+For each name you mention in a module/block, `rust`
+will first look at all items that are defined locally,
+and only if that results in no match look at items you brought in
+scope with corresponding `use` statements.
+
+~~~ {.ignore}
+# // XXX: Allow unused import in doc test
+use farm::cow;
+// ...
+# mod farm { pub fn cow() { println("Hidden ninja cow is hidden.") } }
+fn cow() { println("Mooo!") }
+
+fn main() {
+    cow() // resolves to the locally defined cow() function
 }
+~~~
+
+To make this behavior more obvious, the rule has been made that `use`-statement always need to be written
+before any declaration, like in the example above. This is a purely artificial rule introduced
+because people always assumed they shadowed each other based on order, despite the fact that all items in rust are
+mutually recursive, order independent definitions.
+
+One odd consequence of that rule is that `use` statements also go in front of any `mod` declaration,
+even if they refer to things inside them:
+
+~~~
+use farm::cow;
+mod farm {
+    pub fn cow() { println("Moooooo?") }
+}
+
+fn main() { cow() }
+~~~
+
+This is what our `farm` example looks like with `use` statements:
+
 ~~~~
+use farm::chicken;
+use farm::cow;
+use farm::barn;
 
-The compiler will now look for `poultry/chicken.rs` and
-`poultry/turkey.rs`, and export their content in `poultry::chicken`
-and `poultry::turkey`. You can also provide a `poultry.rs` to add
-content to the `poultry` module itself.
+mod farm {
+    pub fn chicken() { println("cluck cluck"); }
+    pub fn cow() { println("mooo"); }
 
-## Using other crates
+    pub mod barn {
+        pub fn hay() { println("..."); }
+    }
+}
 
-The `extern mod` directive lets you use a crate (once it's been
-compiled into a library) from inside another crate. `extern mod` can
-appear at the top of a crate file or at the top of modules. It will
-cause the compiler to look in the library search path (which you can
-extend with the `-L` switch) for a compiled Rust library with the
-right name, then add a module with that crate's name into the local
-scope.
+fn main() {
+    println("Hello farm!");
 
-For example, `extern mod std` links the [standard library].
+    // Can now refer to those names directly:
+    chicken();
+    cow();
+    barn::hay();
+}
+~~~~
 
-[standard library]: std/index.html
+And here an example with multiple files:
+~~~{.ignore}
+// a.rs - crate root
+use b::foo;
+mod b;
+fn main() { foo(); }
+~~~
+~~~{.ignore}
+// b.rs
+use b::c::bar;
+pub mod c;
+pub fn foo() { bar(); }
+~~~
+~~~
+// c.rs
+pub fn bar() { println("Baz!"); }
+~~~
+
+There also exist two short forms for importing multiple names at once:
+
+1. Explicit mention multiple names as the last element of an `use` path:
+~~~
+use farm::{chicken, cow};
+# mod farm {
+#     pub fn cow() { println("Did I already mention how hidden and ninja I am?") }
+#     pub fn chicken() { println("I'm Bat-chicken, guardian of the hidden tutorial code.") }
+# }
+# fn main() { cow(); chicken() }
+~~~
+
+2. Import everything in a module with a wildcard:
+~~~
+use farm::*;
+# mod farm {
+#     pub fn cow() { println("Bat-chicken? What a stupid name!") }
+#     pub fn chicken() { println("Says the 'hidden ninja' cow.") }
+# }
+# fn main() { cow(); chicken() }
+~~~
+
+However, that's not all. You can also rename an item while you're bringing it into scope:
+
+~~~
+use egg_layer = farm::chicken;
+# mod farm { pub fn chicken() { println("Laying eggs is fun!")  } }
+// ...
+
+fn main() {
+    egg_layer();
+}
+~~~
+
+In general, `use` creates an local alias:
+An alternate path and a possibly different name to access the same item,
+whiteout touching the original, and with both being interchangeable.
+
+## Reexporting names
+
+It is also possible to reexport items to be accessible under your module.
+
+For that, you write `pub use`:
+
+~~~
+mod farm {
+    pub use self::barn::hay;
+
+    pub fn chicken() { println("cluck cluck"); }
+    pub fn cow() { println("mooo"); }
+
+    mod barn {
+        pub fn hay() { println("..."); }
+    }
+}
+
+fn main() {
+    farm::chicken();
+    farm::cow();
+    farm::hay();
+}
+~~~
+
+Just like in normal `use` statements, the exported names
+merely represent an alias to the same thing and can also be renamed.
+
+The above example also demonstrate what you can use `pub use` for:
+The nested `barn` module is private, but the `pub use` allows users
+of the module `farm` to access a function from `barn` without needing
+to know that `barn` exists.
+
+In other words, you can use them to decouple an public api from their internal implementation.
+
+## Using libraries
+
+So far we've only talked about how to define and structure your own crate.
+
+However, most code out there will want to use preexisting libraries,
+as there really is no reason to start from scratch each time you start a new project.
+
+In Rust terminology, we need a way to refer to other crates.
+
+For that, Rust offers you the `extern mod` declaration:
+
+~~~
+extern mod extra;
+// extra ships with Rust, you'll find more details further down.
+
+fn main() {
+    // The rational number '1/2':
+    let one_half = ::extra::rational::Ratio::new(1, 2);
+}
+~~~
+
+Despite its name, `extern mod` is a distinct construct from regular `mod` declarations:
+A statement of the form `extern mod foo;` will cause `rustc` to search for the crate `foo`,
+and if it finds a matching binary it lets you use it from inside your crate.
+
+The effect it has on your module hierarchy mirrors aspects of both `mod` and `use`:
+
+- Like `mod`, it causes `rustc` to actually emit code:
+  The linkage information the binary needs to use the library `foo`.
+
+- But like `use`, all `extern mod` statements that refer to the same library are interchangeable,
+  as each one really just presents an alias to an external module (the crate root of the library your linking against).
+
+Remember how `use`-statements have to go before local declarations because the latter shadows the former?
+Well, `extern mod` statements also have their own rules in that regard:
+Both `use` and local declarations can shadow them, so the rule is that `extern mod` has to go in front
+of both `use` and local declarations.
+
+Which can result in something like this:
+
+~~~
+extern mod extra;
+
+use farm::dog;
+use extra::rational::Ratio;
+
+mod farm {
+    pub fn dog() { println("woof"); }
+}
+
+fn main() {
+    farm::dog();
+    let a_third = Ratio::new(1, 3);
+}
+~~~
+
+It's a bit weird, but it's the result of shadowing rules that have been set that way because
+they model most closely what people expect to shadow.
+
+## Package ids
+
+If you use `extern mod`, per default `rustc` will look for libraries in the the library search path (which you can
+extend with the `-L` switch).
+
+However, Rust also ships with rustpkg, a package manager that is able to automatically download and build
+libraries if you use it for building your crate. How it works is explained [here][rustpkg],
+but for this tutorial it's only important to know that you can optionally annotate an
+`extern mod` statement with an package id that rustpkg can use to identify it:
+
+~~~ {.ignore}
+extern mod rust = "github.com/mozilla/rust"; // pretend Rust is an simple library
+~~~
 
-When a comma-separated list of name/value pairs appears after `extern
-mod`, the compiler front-end matches these pairs against the
-attributes provided in the `link` attribute of the crate file. The
-front-end will only select this crate for use if the actual pairs
-match the declared attributes. You can provide a `name` value to
-override the name used to search for the crate.
+[rustpkg]: rustpkg.html
 
-Our example crate declared this set of `link` attributes:
+## Crate metadata and settings
+
+For every crate you can define a number of metadata items, such as link name, version or author.
+You can also toggle settings that have crate-global consequences. Both mechanism
+work by providing attributes in the crate root.
+
+For example, Rust uniquely identifies crates by their link metadate, which includes
+the link name and the version. It also hashes the filename and the symbols in a binary
+based on the link metadata, allowing you to use two different versions of the same library in a crate
+without conflict.
+
+Therefor, if you plan to compile your crate as a library, you should annotate it with that information:
 
 ~~~~
-#[link(name = "farm", vers = "2.5", author = "mjh")];
+// lib.rs
+
+# #[crate_type = "lib"];
+// Crate linkage metadata
+#[link(name = "farm", vers = "2.5")];
+
+// ...
+# pub fn farm() {}
 ~~~~
 
-Which you can then link with any (or all) of the following:
+You can also in turn require in a `extern mod` statement that certain link metadata items match some criteria.
+For that, Rust currently parses a comma-separated list of name/value pairs that appear after
+it, and ensures that they match the attributes provided in the `link` attribute of a crate file.
+This enables you to, eg, pick a a crate based on it's version number, or to link an library under an
+different name. For example, this two mod statements would both accept and select the crate define above:
 
 ~~~~ {.xfail-test}
-extern mod farm;
-extern mod my_farm (name = "farm", vers = "2.5");
-extern mod my_auxiliary_farm (name = "farm", author = "mjh");
+extern mod farm(vers = "2.5");
+extern mod my_farm(name = "farm", vers = "2.5");
 ~~~~
 
-If any of the requested metadata do not match, then the crate
-will not be compiled successfully.
+Other crate settings and metadata include things like enabling/disabling certain errors or warnings,
+or setting the crate type (library or executable) explicitly:
+
+~~~~
+// lib.rs
+// ...
+
+// This crate is a library ("bin" is the default)
+#[crate_type = "lib"];
+
+// Turn on a warning
+#[warn(non_camel_case_types)]
+# pub fn farm() {}
+~~~~
+
+If you're compiling your crate with `rustpkg`,
+link annotations will not be necessary, because they get
+inferred by `rustpkg` based on the Package id and naming conventions.
+
+
+> ***Note:*** The rules regarding link metadata, both as attributes and on `extern mod`,
+              as well as their interaction with `rustpkg`
+              are currently not clearly defined and will likely change in the future.
 
 ## A minimal example
 
-Now for something that you can actually compile yourself, we have
-these two files:
+Now for something that you can actually compile yourself.
+
+We define two crates, and use one of them as a library in the other.
 
 ~~~~
 // world.rs
-#[link(name = "world", vers = "1.0")];
-pub fn explore() -> &str { "world" }
+#[link(name = "world", vers = "0.42")];
+pub fn explore() -> &'static str { "world" }
 ~~~~
 
 ~~~~ {.xfail-test}
 // main.rs
 extern mod world;
-fn main() { println(~"hello " + world::explore()); }
+fn main() { println("hello " + world::explore()); }
 ~~~~
 
 Now compile and run like this (adjust to your platform if necessary):
 
 ~~~~ {.notrust}
-> rustc --lib world.rs  # compiles libworld-94839cbfe144198-1.0.so
+> rustc --lib world.rs  # compiles libworld-<HASH>-0.42.so
 > rustc main.rs -L .    # compiles main
 > ./main
 "hello world"
 ~~~~
 
-Notice that the library produced contains the version in the filename
-as well as an inscrutable string of alphanumerics. These are both
-part of Rust's library versioning scheme. The alphanumerics are
-a hash representing the crate metadata.
+Notice that the library produced contains the version in the file name
+as well as an inscrutable string of alphanumerics. As explained in the previous paragraph,
+these are both part of Rust's library versioning scheme. The alphanumerics are
+a hash representing the crates link metadata.
+
+## The standard library and the prelude
+
+While reading the examples in this tutorial, you might have asked yourself where all
+those magical predefined items like `println()` are coming from.
+
+The truth is, there's nothing magical about them: They are all defined normally
+in the `std` library, which is a crate that ships with Rust.
+
+The only magical thing that happens is that `rustc` automatically inserts this line into your crate root:
+
+~~~ {.ignore}
+extern mod std;
+~~~
+
+As well as this line into every module body:
+
+~~~ {.ignore}
+use std::prelude::*;
+~~~
+
+The role of the `prelude` module is to re-exports common definitions from `std`.
+
+This allows you to use common types and functions like `Option<T>` or `println`
+without needing to import them. And if you need something from `std` that's not in the prelude,
+you just have to import it with an `use` statement.
+
+For example, it re-exports `println` which is defined in `std::io::println`:
 
-## The standard library
+~~~
+use puts = std::io::println;
+
+fn main() {
+    println("println is imported per default.");
+    puts("Doesn't hinder you from importing it under an different name yourself.");
+    ::std::io::println("Or from not using the automatic import.");
+}
+~~~
+
+Both auto-insertions can be disabled with an attribute if necessary:
+
+~~~
+// In the crate root:
+#[no_std];
+~~~
+
+~~~
+// In any module:
+#[no_implicit_prelude];
+~~~
+
+## The standard library in detail
 
 The Rust standard library provides runtime features required by the language,
 including the task scheduler and memory allocators, as well as library
@@ -2469,24 +2927,9 @@ I/O abstractions ([`io`]), [containers] like [`hashmap`],
 common traits ([`kinds`], [`ops`], [`cmp`], [`num`],
 [`to_str`], [`clone`]), and complete bindings to the C standard library ([`libc`]).
 
-### Standard Library injection and the Rust prelude
-
-`std` is imported at the topmost level of every crate by default, as
-if the first line of each crate was
-
-    extern mod std;
-
-This means that the contents of std can be accessed from from any context
-with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`,
-etc.
-
-Additionally, `std` contains a `prelude` module that reexports many of the
-most common standard modules, types and traits. The contents of the prelude are
-imported into every *module* by default.  Implicitly, all modules behave as if
-they contained the following prologue:
-
-    use std::prelude::*;
+The full documentation for `std` can be found here: [standard library].
 
+[standard library]: std/index.html
 [`std`]: std/index.html
 [`bool`]: std/bool.html
 [tuples]: std/tuple.html
@@ -2513,6 +2956,18 @@ they contained the following prologue:
 [`clone`]: std/clone.html
 [`libc`]: std/libc.html
 
+## The extra library
+
+Rust also ships with the [extra library], an accumulation of
+useful things, that are however not important enough
+to deserve a place in the standard library.
+You can use them by linking to `extra` with an `extern mod extra;`.
+
+[extra library]: extra/index.html
+
+Right now `extra` contains those definitions directly, but in the future it will likely just
+re-export a bunch of 'officially blessed' crates that get managed with `rustpkg`.
+
 # What next?
 
 Now that you know the essentials, check out any of the additional
@@ -2523,8 +2978,9 @@ tutorials on individual topics.
 * [Macros][macros]
 * [The foreign function interface][ffi]
 * [Containers and iterators](tutorial-container.html)
+* [Error-handling and Conditions](tutorial-conditions.html)
 
-There is further documentation on the [wiki].
+There is further documentation on the [wiki], however those tend to be even more out of date as this document.
 
 [borrow]: tutorial-borrowed-ptr.html
 [tasks]: tutorial-tasks.html
index f2a33bb13817e3ab6f4342055d3f0a7402c1ddf1..823dfd94c1a65af4e11abfa2cd9c916290b31195 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -63,7 +63,6 @@ endif
 endif
 
 RUNTIME_CXXS_$(1)_$(2) := \
-              rt/sync/timer.cpp \
               rt/sync/lock_and_signal.cpp \
               rt/sync/rust_thread.cpp \
               rt/rust_builtin.cpp \
@@ -72,13 +71,9 @@ RUNTIME_CXXS_$(1)_$(2) := \
               rt/rust_upcall.cpp \
               rt/rust_uv.cpp \
               rt/rust_crate_map.cpp \
-              rt/rust_gc_metadata.cpp \
-              rt/rust_util.cpp \
               rt/rust_log.cpp \
-              rt/rust_exchange_alloc.cpp \
               rt/isaac/randport.cpp \
               rt/miniz.cpp \
-              rt/rust_abi.cpp \
               rt/memory_region.cpp \
               rt/boxed_region.cpp \
               rt/arch/$$(HOST_$(1))/context.cpp \
@@ -168,34 +163,49 @@ LIBUV_DEPS := $$(wildcard \
               $$(S)src/libuv/*/*/*/*)
 endif
 
+LIBUV_GYP := $$(S)src/libuv/build/gyp
+LIBUV_MAKEFILE_$(1)_$(2) := $$(CFG_BUILD_DIR)rt/$(1)/stage$(2)/libuv/Makefile
+LIBUV_NO_LOAD = run-benchmarks.target.mk run-tests.target.mk \
+               uv_dtrace_header.target.mk uv_dtrace_provider.target.mk
+
+$$(LIBUV_MAKEFILE_$(1)_$(2)): $$(LIBUV_GYP)
+       (cd $(S)src/libuv/ && \
+        $$(CFG_PYTHON) ./gyp_uv -f make -Dtarget_arch=$$(HOST_$(1)) -D ninja \
+          -Goutput_dir=$$(@D) --generator-output $$(@D))
+
 # XXX: Shouldn't need platform-specific conditions here
 ifdef CFG_WINDOWSY_$(1)
 $$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
-       $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
-               builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
-               OS=mingw \
+       $$(Q)rm -f $$(S)src/libuv/libuv.a
+       $$(Q)$$(MAKE) -C $$(S)src/libuv -f Makefile.mingw \
+               CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
+               AR="$$(AR_$(1))" \
                V=$$(VERBOSE)
+       $$(Q)cp $$(S)src/libuv/libuv.a $$@
 else ifeq ($(OSTYPE_$(1)), linux-androideabi)
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
-       $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
+       $$(Q)$$(MAKE) -C $$(@D) \
                CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
                LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
                CC="$$(CC_$(1))" \
                CXX="$$(CXX_$(1))" \
                AR="$$(AR_$(1))" \
-               BUILDTYPE=Release \
-               builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
                host=android OS=linux \
+               builddir="." \
+               BUILDTYPE=Release \
+               NO_LOAD="$$(LIBUV_NO_LOAD)" \
                V=$$(VERBOSE)
 else
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
-       $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
+       $$(Q)$$(MAKE) -C $$(@D) \
                CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
                LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
                CC="$$(CC_$(1))" \
                CXX="$$(CXX_$(1))" \
                AR="$$(AR_$(1))" \
-               builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
+               builddir="." \
+               BUILDTYPE=Release \
+               NO_LOAD="$$(LIBUV_NO_LOAD)" \
                V=$$(VERBOSE)
 endif
 
@@ -259,3 +269,7 @@ endef
 $(foreach stage,$(STAGES), \
        $(foreach target,$(CFG_TARGET_TRIPLES), \
         $(eval $(call DEF_RUNTIME_TARGETS,$(target),$(stage)))))
+
+$(LIBUV_GYP):
+       mkdir -p $(S)src/libuv/build
+       git clone https://git.chromium.org/external/gyp.git $(S)src/libuv/build/gyp
index a5afdf4775b76b548aa849b0169ab0951f0bea64..67b2a26c3af44c50113424eb778810b3c590664b 100644 (file)
@@ -73,16 +73,24 @@ TEST_RATCHET_NOISE_PERCENT=10.0
 
 # Whether to ratchet or merely save benchmarks
 ifdef CFG_RATCHET_BENCH
-CRATE_TEST_BENCH_ARGS=\
+CRATE_TEST_EXTRA_ARGS=\
   --test $(TEST_BENCH) \
   --ratchet-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) \
   --ratchet-noise-percent $(TEST_RATCHET_NOISE_PERCENT)
 else
-CRATE_TEST_BENCH_ARGS=\
+CRATE_TEST_EXTRA_ARGS=\
   --test $(TEST_BENCH) \
   --save-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4))
 endif
 
+# If we're sharding the testsuite between parallel testers,
+# pass this argument along to the compiletest and crate test
+# invocations.
+ifdef TEST_SHARD
+  CTEST_TESTARGS += --test-shard=$(TEST_SHARD)
+  CRATE_TEST_EXTRA_ARGS += --test-shard=$(TEST_SHARD)
+endif
+
 define DEF_TARGET_COMMANDS
 
 ifdef CFG_UNIXY_$(1)
@@ -401,7 +409,7 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
        @$$(call E, run: $$<)
        $$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(2),$(3)) $$(TESTARGS)      \
        --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
-       $$(call CRATE_TEST_BENCH_ARGS,$(1),$(2),$(3),$(4)) \
+       $$(call CRATE_TEST_EXTRA_ARGS,$(1),$(2),$(3),$(4)) \
        && touch $$@
 endef
 
@@ -415,7 +423,7 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
        @$(CFG_ADB) shell '(cd $(CFG_ADB_TEST_DIR); LD_LIBRARY_PATH=. \
                ./$$(notdir $$<) \
                --logfile $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log \
-               $$(call CRATE_TEST_BENCH_ARGS,$(1),$(2),$(3),$(4)))' \
+               $$(call CRATE_TEST_EXTRA_ARGS,$(1),$(2),$(3),$(4)))' \
                > tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp
        @cat tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp
        @touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
index bc5741de2b98f5723e83450a415dc7d940c36d0d..3ae3600cf88c6a41759e1571b25a625f2fd163f8 100644 (file)
@@ -68,6 +68,11 @@ pub struct config {
     // Percent change in metrics to consider noise
     ratchet_noise_percent: Option<f64>,
 
+    // "Shard" of the testsuite to run: this has the form of
+    // two numbers (a,b), and causes only those tests with
+    // positional order equal to a mod b to run.
+    test_shard: Option<(uint,uint)>,
+
     // A command line to prefix program execution with,
     // for running under valgrind
     runtool: Option<~str>,
index 4262aba9a85946c2f30ee8dc6bdfa4be5dc75d5e..8de79749b54f3f57053fd9db1c59709addeb7e14 100644 (file)
@@ -75,6 +75,7 @@ pub fn parse_config(args: ~[~str]) -> config {
           optopt("", "target", "the target to build for", "TARGET"),
           optopt("", "adb-path", "path to the android debugger", "PATH"),
           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
+          optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
           optflag("h", "help", "show this message"),
          ];
 
@@ -148,6 +149,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
                     ~"") { true }
                 else { false }
             } else { false },
+        test_shard: test::opt_shard(getopts::opt_maybe_str(matches, "test-shard")),
         verbose: getopts::opt_present(matches, "verbose")
     }
 }
@@ -172,6 +174,10 @@ pub fn log_config(config: &config) {
     logv(c, fmt!("adb_path: %s", config.adb_path));
     logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
     logv(c, fmt!("adb_device_status: %b", config.adb_device_status));
+    match config.test_shard {
+        None => logv(c, ~"test_shard: (all)"),
+        Some((a,b)) => logv(c, fmt!("test_shard: %u.%u", a, b))
+    }
     logv(c, fmt!("verbose: %b", config.verbose));
     logv(c, fmt!("\n"));
 }
@@ -234,6 +240,7 @@ pub fn test_opts(config: &config) -> test::TestOpts {
         ratchet_metrics: config.ratchet_metrics.clone(),
         ratchet_noise_percent: config.ratchet_noise_percent.clone(),
         save_metrics: config.save_metrics.clone(),
+        test_shard: config.test_shard.clone()
     }
 }
 
index 45e4f756d7a15752a7e3d3e7ed672ac2547c8296..74627829c60ff52b2f37c4e03d6a6582c654edf3 100644 (file)
@@ -54,10 +54,10 @@ pub fn run(lib_path: &str,
         in_fd: None,
         out_fd: None,
         err_fd: None
-    });
+    }).unwrap();
 
     for input in input.iter() {
-        proc.input().write_str(*input);
+        proc.input().write(input.as_bytes());
     }
     let output = proc.finish_with_output();
 
index a31efe26c1a5f2f1330ddc59f17db62531b1c44e..16de4f8e82233dbdbd1b1c5c4c54d1981cfacc6e 100644 (file)
 use util;
 use util::logv;
 
-use std::cell::Cell;
 use std::io;
 use std::os;
 use std::str;
-use std::task::{spawn_sched, SingleThreaded};
 use std::vec;
-use std::unstable::running_on_valgrind;
 
 use extra::test::MetricMap;
 
 pub fn run(config: config, testfile: ~str) {
-    let config = Cell::new(config);
-    let testfile = Cell::new(testfile);
-    // FIXME #6436: Creating another thread to run the test because this
-    // is going to call waitpid. The new scheduler has some strange
-    // interaction between the blocking tasks and 'friend' schedulers
-    // that destroys parallelism if we let normal schedulers block.
-    // It should be possible to remove this spawn once std::run is
-    // rewritten to be non-blocking.
-    //
-    // We do _not_ create another thread if we're running on V because
-    // it serializes all threads anyways.
-    if running_on_valgrind() {
-        let config = config.take();
-        let testfile = testfile.take();
-        let mut _mm = MetricMap::new();
-        run_metrics(config, testfile, &mut _mm);
-    } else {
-        do spawn_sched(SingleThreaded) {
-            let config = config.take();
-            let testfile = testfile.take();
-            let mut _mm = MetricMap::new();
-            run_metrics(config, testfile, &mut _mm);
-        }
-    }
+    let mut _mm = MetricMap::new();
+    run_metrics(config, testfile, &mut _mm);
 }
 
 pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
@@ -282,7 +257,9 @@ fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) {
     }
 
     // write debugger script
-    let script_str = cmds.append("\nquit\n");
+    let script_str = [~"set charset UTF-8",
+                      cmds,
+                      ~"quit\n"].connect("\n");
     debug!("script_str = %s", script_str);
     dump_output_file(config, testfile, script_str, "debugger.script");
 
index ecb223f896c37f668901c0a9c228f9451626c742..4bb0c4040306b18a350a27108833bb5708d39184 100644 (file)
@@ -225,4 +225,27 @@ The initializer is `DEFAULT-TAB-WIDTH'.")
 
 (provide 'rust-mode)
 
+;; Issue #6887: Rather than inheriting the 'gnu compilation error
+;; regexp (which is broken on a few edge cases), add our own 'rust
+;; compilation error regexp and use it instead.
+(defvar rustc-compilation-regexps
+  (let ((file "\\([^\n]+\\)")
+        (start-line "\\([0-9]+\\)")
+        (start-col  "\\([0-9]+\\)")
+        (end-line   "\\([0-9]+\\)")
+        (end-col    "\\([0-9]+\\)")
+        (error-or-warning "\\(?:[Ee]rror\\|\\([Ww]arning\\)\\)"))
+    (let ((re (concat "^" file ":" start-line ":" start-col
+                      ": " end-line ":" end-col
+                      " \\(?:[Ee]rror\\|\\([Ww]arning\\)\\):")))
+      (cons re '(1 (2 . 4) (3 . 5) (6)))))
+  "Specifications for matching errors in rustc invocations.
+See `compilation-error-regexp-alist for help on their format.")
+
+(eval-after-load 'compile
+  '(progn
+     (add-to-list 'compilation-error-regexp-alist-alist
+                  (cons 'rustc rustc-compilation-regexps))
+     (add-to-list 'compilation-error-regexp-alist 'rustc)))
+
 ;;; rust-mode.el ends here
diff --git a/src/etc/generate-keyword-tests.py b/src/etc/generate-keyword-tests.py
new file mode 100755 (executable)
index 0000000..5b82755
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# xfail-license
+# Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+"""
+This script takes a list of keywords and generates a testcase, that checks
+if using the keyword as identifier fails, for every keyword. The generate
+test files are set read-only.
+Test for https://github.com/mozilla/rust/issues/2275
+
+sample usage: src/etc/generate-keyword-tests.py as break
+"""
+
+import sys
+import os
+import datetime
+import stat
+
+
+template = """// Copyright %d The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py %s'
+
+fn main() {
+    let %s = "foo"; //~ error: ident
+}
+"""
+
+test_dir = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '../test/compile-fail')
+)
+
+for kw in sys.argv[1:]:
+    test_file = os.path.join(test_dir, 'keyword-%s-as-identifier.rs' % kw)
+
+    # set write permission if file exists, so it can be changed
+    if os.path.exists(test_file):
+        os.chmod(test_file, stat.S_IWUSR)
+
+    with open(test_file, 'wt') as f:
+        f.write(template % (datetime.datetime.now().year, kw, kw))
+
+    # mark file read-only
+    os.chmod(test_file, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
index e6064ff4f72d2852bca25bbfc525772f59882e8b..a5a239aef58102dc2437a402735ea53b838f234c 100644 (file)
    fun:uv__platform_loop_init
    fun:uv__loop_init
    fun:uv_loop_new
-   fun:rust_uv_loop_new__c_stack_shim
    ...
 }
\ No newline at end of file
index 1df69945a6057aaee0088b2311ae65c4b414071f..792fb7f9ca7214c91ed30ce7d5148942f7dd2563 100644 (file)
@@ -44,7 +44,7 @@
 use sync::{Mutex, RWLock};
 
 use std::cast;
-use std::unstable::sync::UnsafeAtomicRcBox;
+use std::unstable::sync::UnsafeArc;
 use std::task;
 use std::borrow;
 
@@ -108,7 +108,7 @@ pub fn broadcast_on(&self, condvar_id: uint) -> uint {
  ****************************************************************************/
 
 /// An atomically reference counted wrapper for shared immutable state.
-pub struct Arc<T> { priv x: UnsafeAtomicRcBox<T> }
+pub struct Arc<T> { priv x: UnsafeArc<T> }
 
 
 /**
@@ -118,7 +118,7 @@ pub struct Arc<T> { priv x: UnsafeAtomicRcBox<T> }
 impl<T:Freeze+Send> Arc<T> {
     /// Create an atomically reference counted wrapper.
     pub fn new(data: T) -> Arc<T> {
-        Arc { x: UnsafeAtomicRcBox::new(data) }
+        Arc { x: UnsafeArc::new(data) }
     }
 
     pub fn get<'a>(&'a self) -> &'a T {
@@ -160,7 +160,7 @@ fn clone(&self) -> Arc<T> {
 #[doc(hidden)]
 struct MutexArcInner<T> { priv lock: Mutex, priv failed: bool, priv data: T }
 /// An Arc with mutable data protected by a blocking mutex.
-struct MutexArc<T> { priv x: UnsafeAtomicRcBox<MutexArcInner<T>> }
+struct MutexArc<T> { priv x: UnsafeArc<MutexArcInner<T>> }
 
 
 impl<T:Send> Clone for MutexArc<T> {
@@ -187,7 +187,7 @@ pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
             lock: Mutex::new_with_condvars(num_condvars),
             failed: false, data: user_data
         };
-        MutexArc { x: UnsafeAtomicRcBox::new(data) }
+        MutexArc { x: UnsafeArc::new(data) }
     }
 
     /**
@@ -309,7 +309,7 @@ struct RWArcInner<T> { priv lock: RWLock, priv failed: bool, priv data: T }
  */
 #[no_freeze]
 struct RWArc<T> {
-    priv x: UnsafeAtomicRcBox<RWArcInner<T>>,
+    priv x: UnsafeArc<RWArcInner<T>>,
 }
 
 impl<T:Freeze + Send> Clone for RWArc<T> {
@@ -335,7 +335,7 @@ pub fn new_with_condvars(user_data: T, num_condvars: uint) -> RWArc<T> {
             lock: RWLock::new_with_condvars(num_condvars),
             failed: false, data: user_data
         };
-        RWArc { x: UnsafeAtomicRcBox::new(data), }
+        RWArc { x: UnsafeArc::new(data), }
     }
 
     /**
index d4d43558110b15482df457b55ca22d40f0dc0119..9516517d9f7bebdc361378b5ae77b6aa8dcb62a8 100644 (file)
@@ -420,6 +420,7 @@ fn test_add_bytes_to_bits_tuple_overflow() {
     #[test]
     #[should_fail]
     fn test_add_bytes_to_bits_tuple_overflow2() {
-        add_bytes_to_bits_tuple::<u64>((Bounded::max_value::<u64>() - 1, 0), 0x8000000000000000);
+        let value: u64 = Bounded::max_value();
+        add_bytes_to_bits_tuple::<u64>((value - 1, 0), 0x8000000000000000);
     }
 }
index 076e86dd5b04095e1988089e1bfcb353437b7e57..8e641073637853e103c1c08e29f0fa465a21cf04 100644 (file)
@@ -661,7 +661,7 @@ mod tests {
 
     #[test]
     fn test_basic() {
-        let mut m = DList::new::<~int>();
+        let mut m: DList<~int> = DList::new();
         assert_eq!(m.pop_front(), None);
         assert_eq!(m.pop_back(), None);
         assert_eq!(m.pop_front(), None);
@@ -768,7 +768,7 @@ fn test_prepend() {
 
     #[test]
     fn test_rotate() {
-        let mut n = DList::new::<int>();
+        let mut n: DList<int> = DList::new();
         n.rotate_backward(); check_links(&n);
         assert_eq!(n.len(), 0);
         n.rotate_forward(); check_links(&n);
@@ -1033,7 +1033,7 @@ fn test_fuzz() {
 
     #[cfg(test)]
     fn fuzz_test(sz: int) {
-        let mut m = DList::new::<int>();
+        let mut m: DList<int> = DList::new();
         let mut v = ~[];
         for i in range(0, sz) {
             check_links(&m);
@@ -1078,7 +1078,7 @@ fn bench_collect_into(b: &mut test::BenchHarness) {
 
     #[bench]
     fn bench_push_front(b: &mut test::BenchHarness) {
-        let mut m = DList::new::<int>();
+        let mut m: DList<int> = DList::new();
         do b.iter {
             m.push_front(0);
         }
@@ -1086,7 +1086,7 @@ fn bench_push_front(b: &mut test::BenchHarness) {
 
     #[bench]
     fn bench_push_back(b: &mut test::BenchHarness) {
-        let mut m = DList::new::<int>();
+        let mut m: DList<int> = DList::new();
         do b.iter {
             m.push_back(0);
         }
@@ -1094,7 +1094,7 @@ fn bench_push_back(b: &mut test::BenchHarness) {
 
     #[bench]
     fn bench_push_back_pop_back(b: &mut test::BenchHarness) {
-        let mut m = DList::new::<int>();
+        let mut m: DList<int> = DList::new();
         do b.iter {
             m.push_back(0);
             m.pop_back();
@@ -1103,7 +1103,7 @@ fn bench_push_back_pop_back(b: &mut test::BenchHarness) {
 
     #[bench]
     fn bench_push_front_pop_front(b: &mut test::BenchHarness) {
-        let mut m = DList::new::<int>();
+        let mut m: DList<int> = DList::new();
         do b.iter {
             m.push_front(0);
             m.pop_front();
@@ -1112,7 +1112,7 @@ fn bench_push_front_pop_front(b: &mut test::BenchHarness) {
 
     #[bench]
     fn bench_rotate_forward(b: &mut test::BenchHarness) {
-        let mut m = DList::new::<int>();
+        let mut m: DList<int> = DList::new();
         m.push_front(0);
         m.push_front(1);
         do b.iter {
@@ -1122,7 +1122,7 @@ fn bench_rotate_forward(b: &mut test::BenchHarness) {
 
     #[bench]
     fn bench_rotate_backward(b: &mut test::BenchHarness) {
-        let mut m = DList::new::<int>();
+        let mut m: DList<int> = DList::new();
         m.push_front(0);
         m.push_front(1);
         do b.iter {
index 530885001292c51d77d5b0df33ba1cb21c42d452..65d4f79c640249e01008fd71e39b37f75cbf9998 100644 (file)
@@ -25,13 +25,13 @@ pub mod rustrt {
 
     #[link_name = "rustrt"]
     extern {
-        pub fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
+        pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
                                           src_buf_len: size_t,
                                           pout_len: *mut size_t,
                                           flags: c_int)
                                           -> *c_void;
 
-        pub fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
+        pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
                                             src_buf_len: size_t,
                                             pout_len: *mut size_t,
                                             flags: c_int)
index 000520fe41e6e5200a4d1aea90ebe62d4c300565..a21d9dc605f40ccc18afa5650cf97a6233c1ae18 100644 (file)
@@ -689,9 +689,9 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
                 }
             }
 
-            // FIXME: #5516
+            // FIXME: #5516 should be graphemes not codepoints
             // here we just need to indent the start of the description
-            let rowlen = row.len();
+            let rowlen = row.char_len();
             if rowlen < 24 {
                 do (24 - rowlen).times {
                     row.push_char(' ')
@@ -707,14 +707,14 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
                 desc_normalized_whitespace.push_char(' ');
             }
 
-            // FIXME: #5516
+            // FIXME: #5516 should be graphemes not codepoints
             let mut desc_rows = ~[];
             do each_split_within(desc_normalized_whitespace, 54) |substr| {
                 desc_rows.push(substr.to_owned());
                 true
             };
 
-            // FIXME: #5516
+            // FIXME: #5516 should be graphemes not codepoints
             // wrapped description
             row.push_str(desc_rows.connect(desc_sep));
 
@@ -798,7 +798,7 @@ enum LengthLimit {
             cont
         };
 
-        ss.iter().enumerate().advance(|x| machine(x));
+        ss.char_offset_iter().advance(|x| machine(x));
 
         // Let the automaton 'run out' by supplying trailing whitespace
         while cont && match state { B | C => true, A => false } {
@@ -1580,4 +1580,31 @@ fn test_groups_usage_description_wrapping() {
         debug!("generated: <<%s>>", usage);
         assert!(usage == expected)
     }
+
+    #[test]
+    fn test_groups_usage_description_multibyte_handling() {
+        let optgroups = ~[
+            groups::optflag("k", "k\u2013w\u2013",
+                "The word kiwi is normally spelled with two i's"),
+            groups::optflag("a", "apple",
+                "This \u201Cdescription\u201D has some characters that could \
+confuse the line wrapping; an apple costs 0.51€ in some parts of Europe."),
+        ];
+
+        let expected =
+~"Usage: fruits
+
+Options:
+    -k --k–w–           The word kiwi is normally spelled with two i's
+    -a --apple          This “description” has some characters that could
+                        confuse the line wrapping; an apple costs 0.51€ in
+                        some parts of Europe.
+";
+
+        let usage = groups::usage("Usage: fruits", optgroups);
+
+        debug!("expected: <<%s>>", expected);
+        debug!("generated: <<%s>>", usage);
+        assert!(usage == expected)
+    }
 }
index 2287384b53a0e153385dd1fceac5477662d52f41..a13836d87bd74f88462813e4decfa28341a9e653 100644 (file)
@@ -459,26 +459,24 @@ fn encode(&self, e: &mut E) {
     }
 }
 
-/// Encodes a json value into a io::writer
-pub fn to_writer(wr: @io::Writer, json: &Json) {
-    let mut encoder = Encoder(wr);
-    json.encode(&mut encoder)
-}
-
-/// Encodes a json value into a string
-pub fn to_str(json: &Json) -> ~str {
-    io::with_str_writer(|wr| to_writer(wr, json))
-}
+impl Json{
+    /// Encodes a json value into a io::writer.  Uses a single line.
+    pub fn to_writer(&self, wr: @io::Writer) {
+        let mut encoder = Encoder(wr);
+        self.encode(&mut encoder)
+    }
 
-/// Encodes a json value into a io::writer
-pub fn to_pretty_writer(wr: @io::Writer, json: &Json) {
-    let mut encoder = PrettyEncoder(wr);
-    json.encode(&mut encoder)
-}
+    /// Encodes a json value into a io::writer.
+    /// Pretty-prints in a more readable format.
+    pub fn to_pretty_writer(&self, wr: @io::Writer) {
+        let mut encoder = PrettyEncoder(wr);
+        self.encode(&mut encoder)
+    }
 
-/// Encodes a json value into a string
-pub fn to_pretty_str(json: &Json) -> ~str {
-    io::with_str_writer(|wr| to_pretty_writer(wr, json))
+    /// Encodes a json value into a string
+    pub fn to_pretty_str(&self) -> ~str {
+        io::with_str_writer(|wr| self.to_pretty_writer(wr))
+    }
 }
 
 pub struct Parser<T> {
@@ -1307,7 +1305,10 @@ fn to_json(&self) -> Json {
 }
 
 impl to_str::ToStr for Json {
-    fn to_str(&self) -> ~str { to_str(self) }
+    /// Encodes a json value into a string
+    fn to_str(&self) -> ~str {
+      io::with_str_writer(|wr| self.to_writer(wr))
+    }
 }
 
 impl to_str::ToStr for Error {
@@ -1358,69 +1359,67 @@ fn mk_object(items: &[(~str, Json)]) -> Json {
 
     #[test]
     fn test_write_null() {
-        assert_eq!(to_str(&Null), ~"null");
-        assert_eq!(to_pretty_str(&Null), ~"null");
+        assert_eq!(Null.to_str(), ~"null");
+        assert_eq!(Null.to_pretty_str(), ~"null");
     }
 
 
     #[test]
     fn test_write_number() {
-        assert_eq!(to_str(&Number(3f)), ~"3");
-        assert_eq!(to_pretty_str(&Number(3f)), ~"3");
+        assert_eq!(Number(3f).to_str(), ~"3");
+        assert_eq!(Number(3f).to_pretty_str(), ~"3");
 
-        assert_eq!(to_str(&Number(3.1f)), ~"3.1");
-        assert_eq!(to_pretty_str(&Number(3.1f)), ~"3.1");
+        assert_eq!(Number(3.1f).to_str(), ~"3.1");
+        assert_eq!(Number(3.1f).to_pretty_str(), ~"3.1");
 
-        assert_eq!(to_str(&Number(-1.5f)), ~"-1.5");
-        assert_eq!(to_pretty_str(&Number(-1.5f)), ~"-1.5");
+        assert_eq!(Number(-1.5f).to_str(), ~"-1.5");
+        assert_eq!(Number(-1.5f).to_pretty_str(), ~"-1.5");
 
-        assert_eq!(to_str(&Number(0.5f)), ~"0.5");
-        assert_eq!(to_pretty_str(&Number(0.5f)), ~"0.5");
+        assert_eq!(Number(0.5f).to_str(), ~"0.5");
+        assert_eq!(Number(0.5f).to_pretty_str(), ~"0.5");
     }
 
     #[test]
     fn test_write_str() {
-        assert_eq!(to_str(&String(~"")), ~"\"\"");
-        assert_eq!(to_pretty_str(&String(~"")), ~"\"\"");
+        assert_eq!(String(~"").to_str(), ~"\"\"");
+        assert_eq!(String(~"").to_pretty_str(), ~"\"\"");
 
-        assert_eq!(to_str(&String(~"foo")), ~"\"foo\"");
-        assert_eq!(to_pretty_str(&String(~"foo")), ~"\"foo\"");
+        assert_eq!(String(~"foo").to_str(), ~"\"foo\"");
+        assert_eq!(String(~"foo").to_pretty_str(), ~"\"foo\"");
     }
 
     #[test]
     fn test_write_bool() {
-        assert_eq!(to_str(&Boolean(true)), ~"true");
-        assert_eq!(to_pretty_str(&Boolean(true)), ~"true");
+        assert_eq!(Boolean(true).to_str(), ~"true");
+        assert_eq!(Boolean(true).to_pretty_str(), ~"true");
 
-        assert_eq!(to_str(&Boolean(false)), ~"false");
-        assert_eq!(to_pretty_str(&Boolean(false)), ~"false");
+        assert_eq!(Boolean(false).to_str(), ~"false");
+        assert_eq!(Boolean(false).to_pretty_str(), ~"false");
     }
 
     #[test]
     fn test_write_list() {
-        assert_eq!(to_str(&List(~[])), ~"[]");
-        assert_eq!(to_pretty_str(&List(~[])), ~"[]");
+        assert_eq!(List(~[]).to_str(), ~"[]");
+        assert_eq!(List(~[]).to_pretty_str(), ~"[]");
 
-        assert_eq!(to_str(&List(~[Boolean(true)])), ~"[true]");
+        assert_eq!(List(~[Boolean(true)]).to_str(), ~"[true]");
         assert_eq!(
-            to_pretty_str(&List(~[Boolean(true)])),
+            List(~[Boolean(true)]).to_pretty_str(),
             ~"\
             [\n  \
                 true\n\
             ]"
         );
 
-        assert_eq!(to_str(&List(~[
+        let longTestList = List(~[
             Boolean(false),
             Null,
-            List(~[String(~"foo\nbar"), Number(3.5f)])
-        ])), ~"[false,null,[\"foo\\nbar\",3.5]]");
+            List(~[String(~"foo\nbar"), Number(3.5f)])]);
+
+        assert_eq!(longTestList.to_str(),
+            ~"[false,null,[\"foo\\nbar\",3.5]]");
         assert_eq!(
-            to_pretty_str(&List(~[
-                Boolean(false),
-                Null,
-                List(~[String(~"foo\nbar"), Number(3.5f)])
-            ])),
+            longTestList.to_pretty_str(),
             ~"\
             [\n  \
                 false,\n  \
@@ -1435,28 +1434,30 @@ fn test_write_list() {
 
     #[test]
     fn test_write_object() {
-        assert_eq!(to_str(&mk_object([])), ~"{}");
-        assert_eq!(to_pretty_str(&mk_object([])), ~"{}");
+        assert_eq!(mk_object([]).to_str(), ~"{}");
+        assert_eq!(mk_object([]).to_pretty_str(), ~"{}");
 
         assert_eq!(
-            to_str(&mk_object([(~"a", Boolean(true))])),
+            mk_object([(~"a", Boolean(true))]).to_str(),
             ~"{\"a\":true}"
         );
         assert_eq!(
-            to_pretty_str(&mk_object([(~"a", Boolean(true))])),
+            mk_object([(~"a", Boolean(true))]).to_pretty_str(),
             ~"\
             {\n  \
                 \"a\": true\n\
             }"
         );
 
-        assert_eq!(
-            to_str(&mk_object([
+        let complexObj = mk_object([
                 (~"b", List(~[
                     mk_object([(~"c", String(~"\x0c\r"))]),
                     mk_object([(~"d", String(~""))])
                 ]))
-            ])),
+            ]);
+
+        assert_eq!(
+            complexObj.to_str(),
             ~"{\
                 \"b\":[\
                     {\"c\":\"\\f\\r\"},\
@@ -1465,12 +1466,7 @@ fn test_write_object() {
             }"
         );
         assert_eq!(
-            to_pretty_str(&mk_object([
-                (~"b", List(~[
-                    mk_object([(~"c", String(~"\x0c\r"))]),
-                    mk_object([(~"d", String(~""))])
-                ]))
-            ])),
+            complexObj.to_pretty_str(),
             ~"\
             {\n  \
                 \"b\": [\n    \
@@ -1494,8 +1490,8 @@ fn test_write_object() {
 
         // We can't compare the strings directly because the object fields be
         // printed in a different order.
-        assert_eq!(a.clone(), from_str(to_str(&a)).unwrap());
-        assert_eq!(a.clone(), from_str(to_pretty_str(&a)).unwrap());
+        assert_eq!(a.clone(), from_str(a.to_str()).unwrap());
+        assert_eq!(a.clone(), from_str(a.to_pretty_str()).unwrap());
     }
 
     #[test]
index c86c4dd07ed2f2034da4c13ddcf2ea4d7aa78b27..5fd9690d9b0b32dbe0b5d94611e1d4f24db6a506 100644 (file)
@@ -32,9 +32,7 @@
 
 A BigDigit is half the size of machine word size.
 */
-#[cfg(target_arch = "x86")]
-#[cfg(target_arch = "arm")]
-#[cfg(target_arch = "mips")]
+#[cfg(target_word_size = "32")]
 pub type BigDigit = u16;
 
 /**
@@ -42,7 +40,7 @@
 
 A BigDigit is half the size of machine word size.
 */
-#[cfg(target_arch = "x86_64")]
+#[cfg(target_word_size = "64")]
 pub type BigDigit = u32;
 
 pub static ZERO_BIG_DIGIT: BigDigit = 0;
 pub mod BigDigit {
     use bigint::BigDigit;
 
-    #[cfg(target_arch = "x86")]
-    #[cfg(target_arch = "arm")]
-    #[cfg(target_arch = "mips")]
+    #[cfg(target_word_size = "32")]
     pub static bits: uint = 16;
 
-    #[cfg(target_arch = "x86_64")]
+    #[cfg(target_word_size = "64")]
     pub static bits: uint = 32;
 
     pub static base: uint = 1 << bits;
     static hi_mask: uint = (-1 as uint) << bits;
     static lo_mask: uint = (-1 as uint) >> bits;
 
-
+    #[inline]
     fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit }
-
+    #[inline]
     fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit }
 
     /// Split one machine sized unsigned integer into two BigDigits.
-
+    #[inline]
     pub fn from_uint(n: uint) -> (BigDigit, BigDigit) {
         (get_hi(n), get_lo(n))
     }
 
     /// Join two BigDigits into one machine sized unsigned integer
-
+    #[inline]
     pub fn to_uint(hi: BigDigit, lo: BigDigit) -> uint {
         (lo as uint) | ((hi as uint) << bits)
     }
@@ -92,40 +88,26 @@ pub struct BigUint {
 }
 
 impl Eq for BigUint {
-
+    #[inline]
     fn eq(&self, other: &BigUint) -> bool { self.equals(other) }
-
-    fn ne(&self, other: &BigUint) -> bool { !self.equals(other) }
 }
 
 impl TotalEq for BigUint {
-
+    #[inline]
     fn equals(&self, other: &BigUint) -> bool {
         match self.cmp(other) { Equal => true, _ => false }
     }
 }
 
 impl Ord for BigUint {
-
+    #[inline]
     fn lt(&self, other: &BigUint) -> bool {
         match self.cmp(other) { Less => true, _ => false}
     }
-
-    fn le(&self, other: &BigUint) -> bool {
-        match self.cmp(other) { Less | Equal => true, _ => false }
-    }
-
-    fn ge(&self, other: &BigUint) -> bool {
-        match self.cmp(other) { Greater | Equal => true, _ => false }
-    }
-
-    fn gt(&self, other: &BigUint) -> bool {
-        match self.cmp(other) { Greater => true, _ => false }
-    }
 }
 
 impl TotalOrd for BigUint {
-
+    #[inline]
     fn cmp(&self, other: &BigUint) -> Ordering {
         let (s_len, o_len) = (self.data.len(), other.data.len());
         if s_len < o_len { return Less; }
@@ -140,12 +122,12 @@ fn cmp(&self, other: &BigUint) -> Ordering {
 }
 
 impl ToStr for BigUint {
-
+    #[inline]
     fn to_str(&self) -> ~str { self.to_str_radix(10) }
 }
 
 impl FromStr for BigUint {
-
+    #[inline]
     fn from_str(s: &str) -> Option<BigUint> {
         FromStrRadix::from_str_radix(s, 10)
     }
@@ -154,17 +136,17 @@ fn from_str(s: &str) -> Option<BigUint> {
 impl Num for BigUint {}
 
 impl Orderable for BigUint {
-
+    #[inline]
     fn min(&self, other: &BigUint) -> BigUint {
         if self < other { self.clone() } else { other.clone() }
     }
 
-
+    #[inline]
     fn max(&self, other: &BigUint) -> BigUint {
         if self > other { self.clone() } else { other.clone() }
     }
 
-
+    #[inline]
     fn clamp(&self, mn: &BigUint, mx: &BigUint) -> BigUint {
         if self > mx { mx.clone() } else
         if self < mn { mn.clone() } else { self.clone() }
@@ -172,7 +154,7 @@ fn clamp(&self, mn: &BigUint, mx: &BigUint) -> BigUint {
 }
 
 impl Shl<uint, BigUint> for BigUint {
-
+    #[inline]
     fn shl(&self, rhs: &uint) -> BigUint {
         let n_unit = *rhs / BigDigit::bits;
         let n_bits = *rhs % BigDigit::bits;
@@ -181,7 +163,7 @@ fn shl(&self, rhs: &uint) -> BigUint {
 }
 
 impl Shr<uint, BigUint> for BigUint {
-
+    #[inline]
     fn shr(&self, rhs: &uint) -> BigUint {
         let n_unit = *rhs / BigDigit::bits;
         let n_bits = *rhs % BigDigit::bits;
@@ -190,22 +172,21 @@ fn shr(&self, rhs: &uint) -> BigUint {
 }
 
 impl Zero for BigUint {
-
+    #[inline]
     fn zero() -> BigUint { BigUint::new(~[]) }
 
-
+    #[inline]
     fn is_zero(&self) -> bool { self.data.is_empty() }
 }
 
 impl One for BigUint {
-
+    #[inline]
     fn one() -> BigUint { BigUint::new(~[1]) }
 }
 
 impl Unsigned for BigUint {}
 
 impl Add<BigUint, BigUint> for BigUint {
-
     fn add(&self, other: &BigUint) -> BigUint {
         let new_len = num::max(self.data.len(), other.data.len());
 
@@ -225,7 +206,6 @@ fn add(&self, other: &BigUint) -> BigUint {
 }
 
 impl Sub<BigUint, BigUint> for BigUint {
-
     fn sub(&self, other: &BigUint) -> BigUint {
         let new_len = num::max(self.data.len(), other.data.len());
 
@@ -298,14 +278,14 @@ fn mul_digit(a: &BigUint, n: BigDigit) -> BigUint {
             return BigUint::new(prod);
         }
 
-
+        #[inline]
         fn cut_at(a: &BigUint, n: uint) -> (BigUint, BigUint) {
             let mid = num::min(a.data.len(), n);
             return (BigUint::from_slice(a.data.slice(mid, a.data.len())),
                     BigUint::from_slice(a.data.slice(0, mid)));
         }
 
-
+        #[inline]
         fn sub_sign(a: BigUint, b: BigUint) -> (Ordering, BigUint) {
             match a.cmp(&b) {
                 Less    => (Less,    b - a),
@@ -317,7 +297,7 @@ fn sub_sign(a: BigUint, b: BigUint) -> (Ordering, BigUint) {
 }
 
 impl Div<BigUint, BigUint> for BigUint {
-
+    #[inline]
     fn div(&self, other: &BigUint) -> BigUint {
         let (q, _) = self.div_rem(other);
         return q;
@@ -325,7 +305,7 @@ fn div(&self, other: &BigUint) -> BigUint {
 }
 
 impl Rem<BigUint, BigUint> for BigUint {
-
+    #[inline]
     fn rem(&self, other: &BigUint) -> BigUint {
         let (_, r) = self.div_rem(other);
         return r;
@@ -333,29 +313,28 @@ fn rem(&self, other: &BigUint) -> BigUint {
 }
 
 impl Neg<BigUint> for BigUint {
-
+    #[inline]
     fn neg(&self) -> BigUint { fail!() }
 }
 
 impl Integer for BigUint {
-
+    #[inline]
     fn div_rem(&self, other: &BigUint) -> (BigUint, BigUint) {
         self.div_mod_floor(other)
     }
 
-
+    #[inline]
     fn div_floor(&self, other: &BigUint) -> BigUint {
         let (d, _) = self.div_mod_floor(other);
         return d;
     }
 
-
+    #[inline]
     fn mod_floor(&self, other: &BigUint) -> BigUint {
         let (_, m) = self.div_mod_floor(other);
         return m;
     }
 
-
     fn div_mod_floor(&self, other: &BigUint) -> (BigUint, BigUint) {
         if other.is_zero() { fail!() }
         if self.is_zero() { return (Zero::zero(), Zero::zero()); }
@@ -380,7 +359,7 @@ fn div_mod_floor(&self, other: &BigUint) -> (BigUint, BigUint) {
 
         fn div_mod_floor_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) {
             let mut m = a;
-            let mut d = Zero::zero::<BigUint>();
+            let mut d: BigUint = Zero::zero();
             let mut n = 1;
             while m >= b {
                 let (d0, d_unit, b_unit) = div_estimate(&m, &b, n);
@@ -432,8 +411,9 @@ fn div_estimate(a: &BigUint, b: &BigUint, n: uint)
             if shift == 0 {
                 return (BigUint::new(d), One::one(), (*b).clone());
             }
+            let one: BigUint = One::one();
             return (BigUint::from_slice(d).shl_unit(shift),
-                    One::one::<BigUint>().shl_unit(shift),
+                    one.shl_unit(shift),
                     b.shl_unit(shift));
         }
     }
@@ -443,7 +423,7 @@ fn div_estimate(a: &BigUint, b: &BigUint, n: uint)
      *
      * The result is always positive
      */
-
+    #[inline]
     fn gcd(&self, other: &BigUint) -> BigUint {
         // Use Euclid's algorithm
         let mut m = (*self).clone();
@@ -459,15 +439,15 @@ fn gcd(&self, other: &BigUint) -> BigUint {
     /**
      * Calculates the Lowest Common Multiple (LCM) of the number and `other`
      */
-
+    #[inline]
     fn lcm(&self, other: &BigUint) -> BigUint { ((*self * *other) / self.gcd(other)) }
 
     /// Returns `true` if the number can be divided by `other` without leaving a remainder
-
+    #[inline]
     fn is_multiple_of(&self, other: &BigUint) -> bool { (*self % *other).is_zero() }
 
     /// Returns `true` if the number is divisible by `2`
-
+    #[inline]
     fn is_even(&self) -> bool {
         // Considering only the last digit.
         if self.data.is_empty() {
@@ -478,24 +458,23 @@ fn is_even(&self) -> bool {
     }
 
     /// Returns `true` if the number is not divisible by `2`
-
+    #[inline]
     fn is_odd(&self) -> bool { !self.is_even() }
 }
 
 impl IntConvertible for BigUint {
-
+    #[inline]
     fn to_int(&self) -> int {
         num::min(self.to_uint(), int::max_value as uint) as int
     }
 
-
+    #[inline]
     fn from_int(n: int) -> BigUint {
         if (n < 0) { Zero::zero() } else { BigUint::from_uint(n as uint) }
     }
 }
 
 impl ToStrRadix for BigUint {
-
     fn to_str_radix(&self, radix: uint) -> ~str {
         assert!(1 < radix && radix <= 16);
         let (base, max_len) = get_radix_base(radix);
@@ -504,7 +483,6 @@ fn to_str_radix(&self, radix: uint) -> ~str {
         }
         return fill_concat(convert_base((*self).clone(), base), radix, max_len);
 
-
         fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] {
             let divider    = BigUint::from_uint(base);
             let mut result = ~[];
@@ -520,7 +498,6 @@ fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] {
             return result;
         }
 
-
         fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str {
             if v.is_empty() { return ~"0" }
             let mut s = str::with_capacity(v.len() * l);
@@ -536,7 +513,7 @@ fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str {
 
 impl FromStrRadix for BigUint {
     /// Creates and initializes an BigUint.
-
+    #[inline]
     fn from_str_radix(s: &str, radix: uint)
         -> Option<BigUint> {
         BigUint::parse_bytes(s.as_bytes(), radix)
@@ -545,7 +522,7 @@ fn from_str_radix(s: &str, radix: uint)
 
 impl BigUint {
     /// Creates and initializes an BigUint.
-
+    #[inline]
     pub fn new(v: ~[BigDigit]) -> BigUint {
         // omit trailing zeros
         let new_len = v.rposition(|n| *n != 0).map_move_default(0, |p| p + 1);
@@ -557,7 +534,7 @@ pub fn new(v: ~[BigDigit]) -> BigUint {
     }
 
     /// Creates and initializes an BigUint.
-
+    #[inline]
     pub fn from_uint(n: uint) -> BigUint {
         match BigDigit::from_uint(n) {
             (0,  0)  => Zero::zero(),
@@ -567,13 +544,12 @@ pub fn from_uint(n: uint) -> BigUint {
     }
 
     /// Creates and initializes an BigUint.
-
+    #[inline]
     pub fn from_slice(slice: &[BigDigit]) -> BigUint {
         return BigUint::new(slice.to_owned());
     }
 
     /// Creates and initializes an BigUint.
-
     pub fn parse_bytes(buf: &[u8], radix: uint)
         -> Option<BigUint> {
         let (base, unit_len) = get_radix_base(radix);
@@ -603,6 +579,7 @@ pub fn parse_bytes(buf: &[u8], radix: uint)
 
     /// Converts this big integer into a uint, returning the uint::max_value if
     /// it's too large to fit in a uint.
+    #[inline]
     pub fn to_uint(&self) -> uint {
         match self.data.len() {
             0 => 0,
@@ -612,7 +589,7 @@ pub fn to_uint(&self) -> uint {
         }
     }
 
-
+    #[inline]
     fn shl_unit(&self, n_unit: uint) -> BigUint {
         if n_unit == 0 || self.is_zero() { return (*self).clone(); }
 
@@ -620,7 +597,7 @@ fn shl_unit(&self, n_unit: uint) -> BigUint {
                             + self.data);
     }
 
-
+    #[inline]
     fn shl_bits(&self, n_bits: uint) -> BigUint {
         if n_bits == 0 || self.is_zero() { return (*self).clone(); }
 
@@ -636,7 +613,7 @@ fn shl_bits(&self, n_bits: uint) -> BigUint {
         return BigUint::new(shifted);
     }
 
-
+    #[inline]
     fn shr_unit(&self, n_unit: uint) -> BigUint {
         if n_unit == 0 { return (*self).clone(); }
         if self.data.len() < n_unit { return Zero::zero(); }
@@ -645,7 +622,7 @@ fn shr_unit(&self, n_unit: uint) -> BigUint {
         );
     }
 
-
+    #[inline]
     fn shr_bits(&self, n_bits: uint) -> BigUint {
         if n_bits == 0 || self.data.is_empty() { return (*self).clone(); }
 
@@ -659,8 +636,8 @@ fn shr_bits(&self, n_bits: uint) -> BigUint {
     }
 }
 
-#[cfg(target_arch = "x86_64")]
-
+#[cfg(target_word_size = "64")]
+#[inline]
 fn get_radix_base(radix: uint) -> (uint, uint) {
     assert!(1 < radix && radix <= 16);
     match radix {
@@ -683,10 +660,8 @@ fn get_radix_base(radix: uint) -> (uint, uint) {
     }
 }
 
-#[cfg(target_arch = "arm")]
-#[cfg(target_arch = "x86")]
-#[cfg(target_arch = "mips")]
-
+#[cfg(target_word_size = "32")]
+#[inline]
 fn get_radix_base(radix: uint) -> (uint, uint) {
     assert!(1 < radix && radix <= 16);
     match radix {
@@ -714,31 +689,18 @@ fn get_radix_base(radix: uint) -> (uint, uint) {
 pub enum Sign { Minus, Zero, Plus }
 
 impl Ord for Sign {
-
+    #[inline]
     fn lt(&self, other: &Sign) -> bool {
         match self.cmp(other) { Less => true, _ => false}
     }
-
-    fn le(&self, other: &Sign) -> bool {
-        match self.cmp(other) { Less | Equal => true, _ => false }
-    }
-
-    fn ge(&self, other: &Sign) -> bool {
-        match self.cmp(other) { Greater | Equal => true, _ => false }
-    }
-
-    fn gt(&self, other: &Sign) -> bool {
-        match self.cmp(other) { Greater => true, _ => false }
-    }
 }
 
 impl TotalEq for Sign {
-    fn equals(&self, other: &Sign) -> bool {
-        *self == *other
-    }
+    #[inline]
+    fn equals(&self, other: &Sign) -> bool { *self == *other }
 }
 impl TotalOrd for Sign {
-
+    #[inline]
     fn cmp(&self, other: &Sign) -> Ordering {
         match (*self, *other) {
           (Minus, Minus) | (Zero,  Zero) | (Plus, Plus) => Equal,
@@ -750,7 +712,7 @@ fn cmp(&self, other: &Sign) -> Ordering {
 
 impl Neg<Sign> for Sign {
     /// Negate Sign value.
-
+    #[inline]
     fn neg(&self) -> Sign {
         match *self {
           Minus => Plus,
@@ -768,40 +730,26 @@ pub struct BigInt {
 }
 
 impl Eq for BigInt {
-
+    #[inline]
     fn eq(&self, other: &BigInt) -> bool { self.equals(other) }
-
-    fn ne(&self, other: &BigInt) -> bool { !self.equals(other) }
 }
 
 impl TotalEq for BigInt {
-
+    #[inline]
     fn equals(&self, other: &BigInt) -> bool {
         match self.cmp(other) { Equal => true, _ => false }
     }
 }
 
 impl Ord for BigInt {
-
+    #[inline]
     fn lt(&self, other: &BigInt) -> bool {
         match self.cmp(other) { Less => true, _ => false}
     }
-
-    fn le(&self, other: &BigInt) -> bool {
-        match self.cmp(other) { Less | Equal => true, _ => false }
-    }
-
-    fn ge(&self, other: &BigInt) -> bool {
-        match self.cmp(other) { Greater | Equal => true, _ => false }
-    }
-
-    fn gt(&self, other: &BigInt) -> bool {
-        match self.cmp(other) { Greater => true, _ => false }
-    }
 }
 
 impl TotalOrd for BigInt {
-
+    #[inline]
     fn cmp(&self, other: &BigInt) -> Ordering {
         let scmp = self.sign.cmp(&other.sign);
         if scmp != Equal { return scmp; }
@@ -815,12 +763,12 @@ fn cmp(&self, other: &BigInt) -> Ordering {
 }
 
 impl ToStr for BigInt {
-
+    #[inline]
     fn to_str(&self) -> ~str { self.to_str_radix(10) }
 }
 
 impl FromStr for BigInt {
-
+    #[inline]
     fn from_str(s: &str) -> Option<BigInt> {
         FromStrRadix::from_str_radix(s, 10)
     }
@@ -829,17 +777,17 @@ fn from_str(s: &str) -> Option<BigInt> {
 impl Num for BigInt {}
 
 impl Orderable for BigInt {
-
+    #[inline]
     fn min(&self, other: &BigInt) -> BigInt {
         if self < other { self.clone() } else { other.clone() }
     }
 
-
+    #[inline]
     fn max(&self, other: &BigInt) -> BigInt {
         if self > other { self.clone() } else { other.clone() }
     }
 
-
+    #[inline]
     fn clamp(&self, mn: &BigInt, mx: &BigInt) -> BigInt {
         if self > mx { mx.clone() } else
         if self < mn { mn.clone() } else { self.clone() }
@@ -847,38 +795,38 @@ fn clamp(&self, mn: &BigInt, mx: &BigInt) -> BigInt {
 }
 
 impl Shl<uint, BigInt> for BigInt {
-
+    #[inline]
     fn shl(&self, rhs: &uint) -> BigInt {
         BigInt::from_biguint(self.sign, self.data << *rhs)
     }
 }
 
 impl Shr<uint, BigInt> for BigInt {
-
+    #[inline]
     fn shr(&self, rhs: &uint) -> BigInt {
         BigInt::from_biguint(self.sign, self.data >> *rhs)
     }
 }
 
 impl Zero for BigInt {
-
+    #[inline]
     fn zero() -> BigInt {
         BigInt::from_biguint(Zero, Zero::zero())
     }
 
-
+    #[inline]
     fn is_zero(&self) -> bool { self.sign == Zero }
 }
 
 impl One for BigInt {
-
+    #[inline]
     fn one() -> BigInt {
         BigInt::from_biguint(Plus, One::one())
     }
 }
 
 impl Signed for BigInt {
-
+    #[inline]
     fn abs(&self) -> BigInt {
         match self.sign {
             Plus | Zero => self.clone(),
@@ -886,12 +834,12 @@ fn abs(&self) -> BigInt {
         }
     }
 
-
+    #[inline]
     fn abs_sub(&self, other: &BigInt) -> BigInt {
         if *self <= *other { Zero::zero() } else { *self - *other }
     }
 
-
+    #[inline]
     fn signum(&self) -> BigInt {
         match self.sign {
             Plus  => BigInt::from_biguint(Plus, One::one()),
@@ -900,15 +848,15 @@ fn signum(&self) -> BigInt {
         }
     }
 
-
+    #[inline]
     fn is_positive(&self) -> bool { self.sign == Plus }
 
-
+    #[inline]
     fn is_negative(&self) -> bool { self.sign == Minus }
 }
 
 impl Add<BigInt, BigInt> for BigInt {
-
+    #[inline]
     fn add(&self, other: &BigInt) -> BigInt {
         match (self.sign, other.sign) {
             (Zero, _)      => other.clone(),
@@ -923,7 +871,7 @@ fn add(&self, other: &BigInt) -> BigInt {
 }
 
 impl Sub<BigInt, BigInt> for BigInt {
-
+    #[inline]
     fn sub(&self, other: &BigInt) -> BigInt {
         match (self.sign, other.sign) {
             (Zero, _)    => -other,
@@ -941,7 +889,7 @@ fn sub(&self, other: &BigInt) -> BigInt {
 }
 
 impl Mul<BigInt, BigInt> for BigInt {
-
+    #[inline]
     fn mul(&self, other: &BigInt) -> BigInt {
         match (self.sign, other.sign) {
             (Zero, _)     | (_,     Zero)  => Zero::zero(),
@@ -956,7 +904,7 @@ fn mul(&self, other: &BigInt) -> BigInt {
 }
 
 impl Div<BigInt, BigInt> for BigInt {
-
+    #[inline]
     fn div(&self, other: &BigInt) -> BigInt {
         let (q, _) = self.div_rem(other);
         return q;
@@ -964,7 +912,7 @@ fn div(&self, other: &BigInt) -> BigInt {
 }
 
 impl Rem<BigInt, BigInt> for BigInt {
-
+    #[inline]
     fn rem(&self, other: &BigInt) -> BigInt {
         let (_, r) = self.div_rem(other);
         return r;
@@ -972,14 +920,14 @@ fn rem(&self, other: &BigInt) -> BigInt {
 }
 
 impl Neg<BigInt> for BigInt {
-
+    #[inline]
     fn neg(&self) -> BigInt {
         BigInt::from_biguint(self.sign.neg(), self.data.clone())
     }
 }
 
 impl Integer for BigInt {
-
+    #[inline]
     fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) {
         // r.sign == self.sign
         let (d_ui, r_ui) = self.data.div_mod_floor(&other.data);
@@ -994,19 +942,18 @@ fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) {
         }
     }
 
-
+    #[inline]
     fn div_floor(&self, other: &BigInt) -> BigInt {
         let (d, _) = self.div_mod_floor(other);
         return d;
     }
 
-
+    #[inline]
     fn mod_floor(&self, other: &BigInt) -> BigInt {
         let (_, m) = self.div_mod_floor(other);
         return m;
     }
 
-
     fn div_mod_floor(&self, other: &BigInt) -> (BigInt, BigInt) {
         // m.sign == other.sign
         let (d_ui, m_ui) = self.data.div_rem(&other.data);
@@ -1034,7 +981,7 @@ fn div_mod_floor(&self, other: &BigInt) -> (BigInt, BigInt) {
      *
      * The result is always positive
      */
-
+    #[inline]
     fn gcd(&self, other: &BigInt) -> BigInt {
         BigInt::from_biguint(Plus, self.data.gcd(&other.data))
     }
@@ -1042,26 +989,26 @@ fn gcd(&self, other: &BigInt) -> BigInt {
     /**
      * Calculates the Lowest Common Multiple (LCM) of the number and `other`
      */
-
+    #[inline]
     fn lcm(&self, other: &BigInt) -> BigInt {
         BigInt::from_biguint(Plus, self.data.lcm(&other.data))
     }
 
     /// Returns `true` if the number can be divided by `other` without leaving a remainder
-
+    #[inline]
     fn is_multiple_of(&self, other: &BigInt) -> bool { self.data.is_multiple_of(&other.data) }
 
     /// Returns `true` if the number is divisible by `2`
-
+    #[inline]
     fn is_even(&self) -> bool { self.data.is_even() }
 
     /// Returns `true` if the number is not divisible by `2`
-
+    #[inline]
     fn is_odd(&self) -> bool { self.data.is_odd() }
 }
 
 impl IntConvertible for BigInt {
-
+    #[inline]
     fn to_int(&self) -> int {
         match self.sign {
             Plus  => num::min(self.to_uint(), int::max_value as uint) as int,
@@ -1071,7 +1018,7 @@ fn to_int(&self) -> int {
         }
     }
 
-
+    #[inline]
     fn from_int(n: int) -> BigInt {
         if n > 0 {
            return BigInt::from_biguint(Plus,  BigUint::from_uint(n as uint));
@@ -1086,7 +1033,7 @@ fn from_int(n: int) -> BigInt {
 }
 
 impl ToStrRadix for BigInt {
-
+    #[inline]
     fn to_str_radix(&self, radix: uint) -> ~str {
         match self.sign {
             Plus  => self.data.to_str_radix(radix),
@@ -1098,21 +1045,21 @@ fn to_str_radix(&self, radix: uint) -> ~str {
 
 impl FromStrRadix for BigInt {
     /// Creates and initializes an BigInt.
-
-    fn from_str_radix(s: &str, radix: uint)
-        -> Option<BigInt> {
+    #[inline]
+    fn from_str_radix(s: &str, radix: uint) -> Option<BigInt> {
         BigInt::parse_bytes(s.as_bytes(), radix)
     }
 }
 
 impl BigInt {
     /// Creates and initializes an BigInt.
+    #[inline]
     pub fn new(sign: Sign, v: ~[BigDigit]) -> BigInt {
         BigInt::from_biguint(sign, BigUint::new(v))
     }
 
     /// Creates and initializes an BigInt.
-
+    #[inline]
     pub fn from_biguint(sign: Sign, data: BigUint) -> BigInt {
         if sign == Zero || data.is_zero() {
             return BigInt { sign: Zero, data: Zero::zero() };
@@ -1121,20 +1068,19 @@ pub fn from_biguint(sign: Sign, data: BigUint) -> BigInt {
     }
 
     /// Creates and initializes an BigInt.
-
+    #[inline]
     pub fn from_uint(n: uint) -> BigInt {
         if n == 0 { return Zero::zero(); }
         return BigInt::from_biguint(Plus, BigUint::from_uint(n));
     }
 
     /// Creates and initializes an BigInt.
-
+    #[inline]
     pub fn from_slice(sign: Sign, slice: &[BigDigit]) -> BigInt {
         BigInt::from_biguint(sign, BigUint::from_slice(slice))
     }
 
     /// Creates and initializes an BigInt.
-
     pub fn parse_bytes(buf: &[u8], radix: uint)
         -> Option<BigInt> {
         if buf.is_empty() { return None; }
@@ -1148,6 +1094,7 @@ pub fn parse_bytes(buf: &[u8], radix: uint)
             .map_move(|bu| BigInt::from_biguint(sign, bu));
     }
 
+    #[inline]
     pub fn to_uint(&self) -> uint {
         match self.sign {
             Plus  => self.data.to_uint(),
@@ -1221,89 +1168,79 @@ fn test_cmp() {
 
     #[test]
     fn test_shl() {
-        fn check(v: ~[BigDigit], shift: uint, ans: ~[BigDigit]) {
-            assert_eq!(BigUint::new(v) << shift, BigUint::new(ans));
-        }
-
-        check(~[], 3, ~[]);
-        check(~[1, 1, 1], 3, ~[1 << 3, 1 << 3, 1 << 3]);
-        check(~[1 << (BigDigit::bits - 2)], 2, ~[0, 1]);
-        check(~[1 << (BigDigit::bits - 2)], 3, ~[0, 2]);
-        check(~[1 << (BigDigit::bits - 2)], 3 + BigDigit::bits, ~[0, 0, 2]);
-
-        test_shl_bits();
-
-        #[cfg(target_arch = "x86_64")]
-        fn test_shl_bits() {
-            check(~[0x7654_3210, 0xfedc_ba98,
-                    0x7654_3210, 0xfedc_ba98], 4,
-                  ~[0x6543_2100, 0xedcb_a987,
-                    0x6543_210f, 0xedcb_a987, 0xf]);
-            check(~[0x2222_1111, 0x4444_3333,
-                    0x6666_5555, 0x8888_7777], 16,
-                  ~[0x1111_0000, 0x3333_2222,
-                    0x5555_4444, 0x7777_6666, 0x8888]);
-        }
-
-        #[cfg(target_arch = "arm")]
-        #[cfg(target_arch = "x86")]
-        #[cfg(target_arch = "mips")]
-        fn test_shl_bits() {
-            check(~[0x3210, 0x7654, 0xba98, 0xfedc,
-                    0x3210, 0x7654, 0xba98, 0xfedc], 4,
-                  ~[0x2100, 0x6543, 0xa987, 0xedcb,
-                    0x210f, 0x6543, 0xa987, 0xedcb, 0xf]);
-            check(~[0x1111, 0x2222, 0x3333, 0x4444,
-                    0x5555, 0x6666, 0x7777, 0x8888], 16,
-                  ~[0x0000, 0x1111, 0x2222, 0x3333,
-                    0x4444, 0x5555, 0x6666, 0x7777, 0x8888]);
-        }
-
+        fn check(s: &str, shift: uint, ans: &str) {
+            let opt_biguint: Option<BigUint> = FromStrRadix::from_str_radix(s, 16);
+            let bu = (opt_biguint.unwrap() << shift).to_str_radix(16);
+            assert_eq!(bu.as_slice(), ans);
+        }
+
+        check("0", 3, "0");
+        check("1", 3, "8");
+
+        check("1" + "0000" + "0000" + "0000" + "0001" + "0000" + "0000" + "0000" + "0001", 3,
+              "8" + "0000" + "0000" + "0000" + "0008" + "0000" + "0000" + "0000" + "0008");
+        check("1" + "0000" + "0001" + "0000" + "0001", 2,
+              "4" + "0000" + "0004" + "0000" + "0004");
+        check("1" + "0001" + "0001", 1,
+              "2" + "0002" + "0002");
+
+        check(""  + "4000" + "0000" + "0000" + "0000", 3,
+              "2" + "0000" + "0000" + "0000" + "0000");
+        check(""  + "4000" + "0000", 2,
+              "1" + "0000" + "0000");
+        check(""  + "4000", 2,
+              "1" + "0000");
+
+        check(""  + "4000" + "0000" + "0000" + "0000", 67,
+              "2" + "0000" + "0000" + "0000" + "0000" + "0000" + "0000" + "0000" + "0000");
+        check(""  + "4000" + "0000", 35,
+              "2" + "0000" + "0000" + "0000" + "0000");
+        check(""  + "4000", 19,
+              "2" + "0000" + "0000");
+
+        check(""  + "fedc" + "ba98" + "7654" + "3210" + "fedc" + "ba98" + "7654" + "3210", 4,
+              "f" + "edcb" + "a987" + "6543" + "210f" + "edcb" + "a987" + "6543" + "2100");
+        check("88887777666655554444333322221111", 16,
+              "888877776666555544443333222211110000");
     }
 
     #[test]
-    #[ignore(cfg(target_arch = "x86"))]
-    #[ignore(cfg(target_arch = "arm"))]
-    #[ignore(cfg(target_arch = "mips"))]
     fn test_shr() {
-        fn check(v: ~[BigDigit], shift: uint, ans: ~[BigDigit]) {
-            assert_eq!(BigUint::new(v) >> shift, BigUint::new(ans));
-        }
-
-        check(~[], 3, ~[]);
-        check(~[1, 1, 1], 3,
-              ~[1 << (BigDigit::bits - 3), 1 << (BigDigit::bits - 3)]);
-        check(~[1 << 2], 2, ~[1]);
-        check(~[1, 2], 3, ~[1 << (BigDigit::bits - 2)]);
-        check(~[1, 1, 2], 3 + BigDigit::bits, ~[1 << (BigDigit::bits - 2)]);
-        check(~[0, 1], 1, ~[0x80000000]);
-        test_shr_bits();
-
-        #[cfg(target_arch = "x86_64")]
-        fn test_shr_bits() {
-            check(~[0x6543_2100, 0xedcb_a987,
-                    0x6543_210f, 0xedcb_a987, 0xf], 4,
-                  ~[0x7654_3210, 0xfedc_ba98,
-                    0x7654_3210, 0xfedc_ba98]);
-            check(~[0x1111_0000, 0x3333_2222,
-                    0x5555_4444, 0x7777_6666, 0x8888], 16,
-                  ~[0x2222_1111, 0x4444_3333,
-                    0x6666_5555, 0x8888_7777]);
-        }
-
-        #[cfg(target_arch = "arm")]
-        #[cfg(target_arch = "x86")]
-        #[cfg(target_arch = "mips")]
-        fn test_shr_bits() {
-            check(~[0x2100, 0x6543, 0xa987, 0xedcb,
-                    0x210f, 0x6543, 0xa987, 0xedcb, 0xf], 4,
-                  ~[0x3210, 0x7654, 0xba98, 0xfedc,
-                    0x3210, 0x7654, 0xba98, 0xfedc]);
-            check(~[0x0000, 0x1111, 0x2222, 0x3333,
-                    0x4444, 0x5555, 0x6666, 0x7777, 0x8888], 16,
-                  ~[0x1111, 0x2222, 0x3333, 0x4444,
-                    0x5555, 0x6666, 0x7777, 0x8888]);
-        }
+        fn check(s: &str, shift: uint, ans: &str) {
+            let opt_biguint: Option<BigUint> =
+                FromStrRadix::from_str_radix(s, 16);
+            let bu = (opt_biguint.unwrap() >> shift).to_str_radix(16);
+            assert_eq!(bu.as_slice(), ans);
+        }
+
+        check("0", 3, "0");
+        check("f", 3, "1");
+
+        check("1" + "0000" + "0000" + "0000" + "0001" + "0000" + "0000" + "0000" + "0001", 3,
+              ""  + "2000" + "0000" + "0000" + "0000" + "2000" + "0000" + "0000" + "0000");
+        check("1" + "0000" + "0001" + "0000" + "0001", 2,
+              ""  + "4000" + "0000" + "4000" + "0000");
+        check("1" + "0001" + "0001", 1,
+              ""  + "8000" + "8000");
+
+        check("2" + "0000" + "0000" + "0000" + "0001" + "0000" + "0000" + "0000" + "0001", 67,
+              ""  + "4000" + "0000" + "0000" + "0000");
+        check("2" + "0000" + "0001" + "0000" + "0001", 35,
+              ""  + "4000" + "0000");
+        check("2" + "0001" + "0001", 19,
+              ""  + "4000");
+
+        check("1" + "0000" + "0000" + "0000" + "0000", 1,
+              ""  + "8000" + "0000" + "0000" + "0000");
+        check("1" + "0000" + "0000", 1,
+              ""  + "8000" + "0000");
+        check("1" + "0000", 1,
+              ""  + "8000");
+        check("f" + "edcb" + "a987" + "6543" + "210f" + "edcb" + "a987" + "6543" + "2100", 4,
+              ""  + "fedc" + "ba98" + "7654" + "3210" + "fedc" + "ba98" + "7654" + "3210");
+
+        check("888877776666555544443333222211110000", 16,
+              "88887777666655554444333322221111");
     }
 
     #[test]
@@ -1510,11 +1447,18 @@ fn check(a: uint, b: uint, c: uint) {
 
     #[test]
     fn test_is_even() {
-        assert!(FromStr::from_str::<BigUint>("1").unwrap().is_odd());
-        assert!(FromStr::from_str::<BigUint>("2").unwrap().is_even());
-        assert!(FromStr::from_str::<BigUint>("1000").unwrap().is_even());
-        assert!(FromStr::from_str::<BigUint>("1000000000000000000000").unwrap().is_even());
-        assert!(FromStr::from_str::<BigUint>("1000000000000000000001").unwrap().is_odd());
+        let one: Option<BigUint> = FromStr::from_str("1");
+        let two: Option<BigUint> = FromStr::from_str("2");
+        let thousand: Option<BigUint> = FromStr::from_str("1000");
+        let big: Option<BigUint> =
+            FromStr::from_str("1000000000000000000000");
+        let bigger: Option<BigUint> =
+            FromStr::from_str("1000000000000000000001");
+        assert!(one.unwrap().is_odd());
+        assert!(two.unwrap().is_even());
+        assert!(thousand.unwrap().is_even());
+        assert!(big.unwrap().is_even());
+        assert!(bigger.unwrap().is_odd());
         assert!((BigUint::from_uint(1) << 64).is_even());
         assert!(((BigUint::from_uint(1) << 64) + BigUint::from_uint(1)).is_odd());
     }
@@ -1599,15 +1543,19 @@ fn test_from_str_radix() {
             }
         }
 
-        assert_eq!(FromStrRadix::from_str_radix::<BigUint>("Z", 10), None);
-        assert_eq!(FromStrRadix::from_str_radix::<BigUint>("_", 2), None);
-        assert_eq!(FromStrRadix::from_str_radix::<BigUint>("-1", 10), None);
+        let zed: Option<BigUint> = FromStrRadix::from_str_radix("Z", 10);
+        assert_eq!(zed, None);
+        let blank: Option<BigUint> = FromStrRadix::from_str_radix("_", 2);
+        assert_eq!(blank, None);
+        let minus_one: Option<BigUint> = FromStrRadix::from_str_radix("-1",
+                                                                      10);
+        assert_eq!(minus_one, None);
     }
 
     #[test]
     fn test_factor() {
         fn factor(n: uint) -> BigUint {
-            let mut f= One::one::<BigUint>();
+            let mut f: BigUint = One::one();
             for i in range(2, n + 1) {
                 // FIXME(#6102): Assignment operator for BigInt causes ICE
                 // f *= BigUint::from_uint(i);
@@ -1633,7 +1581,6 @@ fn check(n: uint, s: &str) {
 
 #[cfg(test)]
 mod bigint_tests {
-
     use super::*;
 
     use std::cmp::{Less, Equal, Greater};
@@ -2005,17 +1952,24 @@ fn check(a: int, b: int, c: int) {
 
     #[test]
     fn test_abs_sub() {
-        assert_eq!((-One::one::<BigInt>()).abs_sub(&One::one()), Zero::zero());
-        assert_eq!(One::one::<BigInt>().abs_sub(&One::one()), Zero::zero());
-        assert_eq!(One::one::<BigInt>().abs_sub(&Zero::zero()), One::one());
-        assert_eq!(One::one::<BigInt>().abs_sub(&-One::one::<BigInt>()),
-                   IntConvertible::from_int(2));
+        let zero: BigInt = Zero::zero();
+        let one: BigInt = One::one();
+        assert_eq!((-one).abs_sub(&one), zero);
+        let one: BigInt = One::one();
+        let zero: BigInt = Zero::zero();
+        assert_eq!(one.abs_sub(&one), zero);
+        let one: BigInt = One::one();
+        let zero: BigInt = Zero::zero();
+        assert_eq!(one.abs_sub(&zero), one);
+        let one: BigInt = One::one();
+        assert_eq!(one.abs_sub(&-one), IntConvertible::from_int(2));
     }
 
     #[test]
     fn test_to_str_radix() {
         fn check(n: int, ans: &str) {
-            assert!(ans == IntConvertible::from_int::<BigInt>(n).to_str_radix(10));
+            let n: BigInt = IntConvertible::from_int(n);
+            assert!(ans == n.to_str_radix(10));
         }
         check(10, "10");
         check(1, "1");
@@ -2028,7 +1982,10 @@ fn check(n: int, ans: &str) {
     #[test]
     fn test_from_str_radix() {
         fn check(s: &str, ans: Option<int>) {
-            let ans = ans.map_move(|n| IntConvertible::from_int::<BigInt>(n));
+            let ans = ans.map_move(|n| {
+                let x: BigInt = IntConvertible::from_int(n);
+                x
+            });
             assert_eq!(FromStrRadix::from_str_radix(s, 10), ans);
         }
         check("10", Some(10));
@@ -2046,6 +2003,51 @@ fn test_neg() {
             BigInt::new(Minus, ~[1, 1, 1]));
         assert!(-BigInt::new(Minus, ~[1, 1, 1]) ==
             BigInt::new(Plus,  ~[1, 1, 1]));
-        assert_eq!(-Zero::zero::<BigInt>(), Zero::zero::<BigInt>());
+        let zero: BigInt = Zero::zero();
+        assert_eq!(-zero, zero);
+    }
+}
+
+#[cfg(test)]
+mod bench {
+    use super::*;
+    use std::{iterator, util};
+    use std::num::{Zero, One};
+    use extra::test::BenchHarness;
+
+    fn factorial(n: uint) -> BigUint {
+        let mut f: BigUint = One::one();
+        for i in iterator::range_inclusive(1, n) {
+            f = f * BigUint::from_uint(i);
+        }
+        f
+    }
+
+    fn fib(n: uint) -> BigUint {
+        let mut f0: BigUint = Zero::zero();
+        let mut f1: BigUint = One::one();
+        for _ in range(0, n) {
+            let f2 = f0 + f1;
+            f0 = util::replace(&mut f1, f2);
+        }
+        f0
+    }
+
+    #[bench]
+    fn factorial_100(bh: &mut BenchHarness) {
+        do bh.iter { factorial(100);  }
+    }
+
+    #[bench]
+    fn fib_100(bh: &mut BenchHarness) {
+        do bh.iter { fib(100); }
+    }
+
+    #[bench]
+    fn to_str(bh: &mut BenchHarness) {
+        let fac = factorial(100);
+        let fib = fib(100);
+        do bh.iter { fac.to_str(); }
+        do bh.iter { fib.to_str(); }
     }
 }
index 60dd36a3b886e1c90688b423645e5bbfb3b7f1c0..41e9a488bf8ae8fa74149502dbe2f35eface48b0 100644 (file)
@@ -269,9 +269,13 @@ impl<T: FromStr + Clone + Integer + Ord>
     /// Parses `numer/denom`.
     fn from_str(s: &str) -> Option<Ratio<T>> {
         let split: ~[&str] = s.splitn_iter('/', 1).collect();
-        if split.len() < 2 { return None; }
-        do FromStr::from_str::<T>(split[0]).chain |a| {
-            do FromStr::from_str::<T>(split[1]).chain |b| {
+        if split.len() < 2 {
+            return None
+        }
+        let a_option: Option<T> = FromStr::from_str(split[0]);
+        do a_option.chain |a| {
+            let b_option: Option<T> = FromStr::from_str(split[1]);
+            do b_option.chain |b| {
                 Some(Ratio::new(a.clone(), b.clone()))
             }
         }
@@ -282,10 +286,15 @@ impl<T: FromStrRadix + Clone + Integer + Ord>
     /// Parses `numer/denom` where the numbers are in base `radix`.
     fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
         let split: ~[&str] = s.splitn_iter('/', 1).collect();
-        if split.len() < 2 { None }
-        else {
-            do FromStrRadix::from_str_radix::<T>(split[0], radix).chain |a| {
-                do FromStrRadix::from_str_radix::<T>(split[1], radix).chain |b| {
+        if split.len() < 2 {
+            None
+        } else {
+            let a_option: Option<T> = FromStrRadix::from_str_radix(split[0],
+                                                                   radix);
+            do a_option.chain |a| {
+                let b_option: Option<T> =
+                    FromStrRadix::from_str_radix(split[1], radix);
+                do b_option.chain |b| {
                     Some(Ratio::new(a.clone(), b.clone()))
                 }
             }
@@ -496,7 +505,8 @@ fn test(r: Rational, s: ~str) {
     #[test]
     fn test_from_str_fail() {
         fn test(s: &str) {
-            assert_eq!(FromStr::from_str::<Rational>(s), None);
+            let rational: Option<Rational> = FromStr::from_str(s);
+            assert_eq!(rational, None);
         }
 
         let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];
@@ -536,7 +546,8 @@ fn test16(r: Rational, s: ~str) { test(r, s, 16) }
     #[test]
     fn test_from_str_radix_fail() {
         fn test(s: &str) {
-            assert_eq!(FromStrRadix::from_str_radix::<Rational>(s, 3), None);
+            let radix: Option<Rational> = FromStrRadix::from_str_radix(s, 3);
+            assert_eq!(radix, None);
         }
 
         let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"];
index a9341a8075d416a69206d23ff8e7700beb26df3e..b085981aabba1cb6244130d3be44d1912f436452 100644 (file)
@@ -338,27 +338,36 @@ fn test_to_vec() {
 
     #[test]
     #[should_fail]
-    fn test_empty_pop() { let mut heap = PriorityQueue::new::<int>(); heap.pop(); }
+    fn test_empty_pop() {
+        let mut heap: PriorityQueue<int> = PriorityQueue::new();
+        heap.pop();
+    }
 
     #[test]
     fn test_empty_maybe_pop() {
-        let mut heap = PriorityQueue::new::<int>();
+        let mut heap: PriorityQueue<int> = PriorityQueue::new();
         assert!(heap.maybe_pop().is_none());
     }
 
     #[test]
     #[should_fail]
-    fn test_empty_top() { let empty = PriorityQueue::new::<int>(); empty.top(); }
+    fn test_empty_top() {
+        let empty: PriorityQueue<int> = PriorityQueue::new();
+        empty.top();
+    }
 
     #[test]
     fn test_empty_maybe_top() {
-        let empty = PriorityQueue::new::<int>();
+        let empty: PriorityQueue<int> = PriorityQueue::new();
         assert!(empty.maybe_top().is_none());
     }
 
     #[test]
     #[should_fail]
-    fn test_empty_replace() { let mut heap = PriorityQueue::new(); heap.replace(5); }
+    fn test_empty_replace() {
+        let mut heap: PriorityQueue<int> = PriorityQueue::new();
+        heap.replace(5);
+    }
 
     #[test]
     fn test_from_iter() {
index a38cb580c50578aa066e9f4ff6e83d37d335d324..4f2755374af02779354b9ea0a1ffd270e4a4999e 100644 (file)
@@ -483,7 +483,7 @@ fn test_push_front_grow() {
     #[bench]
     fn bench_new(b: &mut test::BenchHarness) {
         do b.iter {
-            let _ = RingBuf::new::<u64>();
+            let _: RingBuf<u64> = RingBuf::new();
         }
     }
 
index 0cea4c1ac6c015f597309cba8168697bba9f00b6..2b6c53b3c86159987533f8a26f7586d7cb19d22b 100644 (file)
@@ -368,7 +368,7 @@ pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) {
 /// Returns a HashMap with the number of occurrences of every element in the
 /// sequence that the iterator exposes.
 pub fn freq_count<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
-    let mut map = hashmap::HashMap::new::<U, uint>();
+    let mut map: hashmap::HashMap<U,uint> = hashmap::HashMap::new();
     for elem in iter {
         map.insert_or_update_with(elem, 1, |_, count| *count += 1);
     }
index afb4cf3943abae035a6cba94d2cd3f8d791f0e27..d8c2f0223b7f853f382e8d0bc152e0de0eb212a9 100644 (file)
@@ -21,7 +21,7 @@
 use std::comm::SendDeferred;
 use std::comm::{GenericPort, Peekable};
 use std::task;
-use std::unstable::sync::{Exclusive, UnsafeAtomicRcBox};
+use std::unstable::sync::{Exclusive, UnsafeArc};
 use std::unstable::atomics;
 use std::unstable::finally::Finally;
 use std::util;
@@ -135,9 +135,7 @@ pub fn access<U>(&self, blk: &fn() -> U) -> U {
         do task::unkillable {
             do (|| {
                 self.acquire();
-                unsafe {
-                    do task::rekillable { blk() }
-                }
+                do task::rekillable { blk() }
             }).finally {
                 self.release();
             }
@@ -234,10 +232,8 @@ pub fn wait_on(&self, condvar_id: uint) {
                 // signaller already sent -- I mean 'unconditionally' in contrast
                 // with acquire().)
                 do (|| {
-                    unsafe {
-                        do task::rekillable {
-                            let _ = WaitEnd.take_unwrap().recv();
-                        }
+                    do task::rekillable {
+                        let _ = WaitEnd.take_unwrap().recv();
                     }
                 }).finally {
                     // Reacquire the condvar. Note this is back in the unkillable
@@ -448,7 +444,7 @@ struct RWLockInner {
 pub struct RWLock {
     priv order_lock:  Semaphore,
     priv access_lock: Sem<~[WaitQueue]>,
-    priv state:       UnsafeAtomicRcBox<RWLockInner>,
+    priv state:       UnsafeArc<RWLockInner>,
 }
 
 impl RWLock {
@@ -460,7 +456,7 @@ pub fn new() -> RWLock { RWLock::new_with_condvars(1) }
     * Similar to mutex_with_condvars.
     */
     pub fn new_with_condvars(num_condvars: uint) -> RWLock {
-        let state = UnsafeAtomicRcBox::new(RWLockInner {
+        let state = UnsafeArc::new(RWLockInner {
             read_mode:  false,
             read_count: atomics::AtomicUint::new(0),
         });
@@ -516,14 +512,12 @@ pub fn read<U>(&self, blk: &fn() -> U) -> U {
      * 'write' from other tasks will run concurrently with this one.
      */
     pub fn write<U>(&self, blk: &fn() -> U) -> U {
-        unsafe {
-            do task::unkillable {
-                (&self.order_lock).acquire();
-                do (&self.access_lock).access {
-                    (&self.order_lock).release();
-                    do task::rekillable {
-                        blk()
-                    }
+        do task::unkillable {
+            (&self.order_lock).acquire();
+            do (&self.access_lock).access {
+                (&self.order_lock).release();
+                do task::rekillable {
+                    blk()
                 }
             }
         }
@@ -562,16 +556,14 @@ pub fn write_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U {
         // which can't happen until T2 finishes the downgrade-read entirely.
         // The astute reader will also note that making waking writers use the
         // order_lock is better for not starving readers.
-        unsafe {
-            do task::unkillable {
-                (&self.order_lock).acquire();
-                do (&self.access_lock).access_cond |cond| {
-                    (&self.order_lock).release();
-                    do task::rekillable {
-                        let opt_lock = Just(&self.order_lock);
-                        blk(&Condvar { sem: cond.sem, order: opt_lock,
-                                       token: NonCopyable::new() })
-                    }
+        do task::unkillable {
+            (&self.order_lock).acquire();
+            do (&self.access_lock).access_cond |cond| {
+                (&self.order_lock).release();
+                do task::rekillable {
+                    let opt_lock = Just(&self.order_lock);
+                    blk(&Condvar { sem: cond.sem, order: opt_lock,
+                                   token: NonCopyable::new() })
                 }
             }
         }
@@ -606,10 +598,8 @@ pub fn write_downgrade<U>(&self, blk: &fn(v: RWLockWriteMode) -> U) -> U {
             (&self.access_lock).acquire();
             (&self.order_lock).release();
             do (|| {
-                unsafe {
-                    do task::rekillable {
-                        blk(RWLockWriteMode { lock: self, token: NonCopyable::new() })
-                    }
+                do task::rekillable {
+                    blk(RWLockWriteMode { lock: self, token: NonCopyable::new() })
                 }
             }).finally {
                 let writer_or_last_reader;
index d940e8bb4734d208427e7413956ed67f84f6d401..ccade8f19bebc456104c316f15726333364555ac 100644 (file)
@@ -38,6 +38,7 @@
 use std::to_str::ToStr;
 use std::f64;
 use std::os;
+use std::uint;
 
 
 // The name of a test. By convention this follows the rules for rust
@@ -164,6 +165,7 @@ pub struct TestOpts {
     ratchet_metrics: Option<Path>,
     ratchet_noise_percent: Option<f64>,
     save_metrics: Option<Path>,
+    test_shard: Option<(uint,uint)>,
     logfile: Option<Path>
 }
 
@@ -184,7 +186,9 @@ fn optgroups() -> ~[getopts::groups::OptGroup] {
                      "Tests within N% of the recorded metrics will be \
                       considered as passing", "PERCENTAGE"),
       groups::optopt("", "logfile", "Write logs to the specified file instead \
-                          of stdout", "PATH")]
+                          of stdout", "PATH"),
+      groups::optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite",
+                     "A.B")]
 }
 
 fn usage(binary: &str, helpstr: &str) -> ! {
@@ -255,6 +259,9 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
     let save_metrics = getopts::opt_maybe_str(&matches, "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 = opt_shard(test_shard);
+
     let test_opts = TestOpts {
         filter: filter,
         run_ignored: run_ignored,
@@ -263,12 +270,29 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
         ratchet_metrics: ratchet_metrics,
         ratchet_noise_percent: ratchet_noise_percent,
         save_metrics: save_metrics,
+        test_shard: test_shard,
         logfile: logfile
     };
 
     either::Left(test_opts)
 }
 
+pub fn opt_shard(maybestr: Option<~str>) -> Option<(uint,uint)> {
+    match maybestr {
+        None => None,
+        Some(s) => {
+            match s.split_iter('.').to_owned_vec() {
+                [a, b] => match (uint::from_str(a), uint::from_str(b)) {
+                    (Some(a), Some(b)) => Some((a,b)),
+                    _ => None
+                },
+                _ => None
+            }
+        }
+    }
+}
+
+
 #[deriving(Clone, Eq)]
 pub struct BenchSamples {
     ns_iter_summ: stats::Summary,
@@ -772,7 +796,15 @@ fn lteq(t1: &TestDescAndFn, t2: &TestDescAndFn) -> bool {
     }
     sort::quick_sort(filtered, lteq);
 
-    filtered
+    // Shard the remaining tests, if sharding requested.
+    match opts.test_shard {
+        None => filtered,
+        Some((a,b)) =>
+            filtered.move_iter().enumerate()
+            .filter(|&(i,_)| i % b == a)
+            .map(|(_,t)| t)
+            .to_owned_vec()
+    }
 }
 
 struct TestFuture {
@@ -875,7 +907,7 @@ pub fn load(p: &Path) -> MetricMap {
     /// Write MetricDiff to a file.
     pub fn save(&self, p: &Path) {
         let f = io::file_writer(p, [io::Create, io::Truncate]).unwrap();
-        json::to_pretty_writer(f, &self.to_json());
+        self.to_json().to_pretty_writer(f);
     }
 
     /// Compare against another MetricMap. Optionally compare all
@@ -1234,6 +1266,7 @@ fn dummy() {}
             ratchet_noise_percent: None,
             ratchet_metrics: None,
             save_metrics: None,
+            test_shard: None
         };
 
         let tests = ~[
@@ -1272,6 +1305,7 @@ pub fn sort_tests() {
             ratchet_noise_percent: None,
             ratchet_metrics: None,
             save_metrics: None,
+            test_shard: None
         };
 
         let names =
index 257d941e4afff6d3db6c579555179e265013e8b3..6119170f13057f75e5fe8ea63f425b4a24e9ba60 100644 (file)
@@ -121,6 +121,9 @@ pub struct Tm {
 }
 
 pub fn empty_tm() -> Tm {
+    // 64 is the max size of the timezone buffer allocated on windows
+    // in rust_localtime. In glibc the max timezone size is supposedly 3.
+    let zone = str::with_capacity(64);
     Tm {
         tm_sec: 0_i32,
         tm_min: 0_i32,
@@ -132,7 +135,7 @@ pub fn empty_tm() -> Tm {
         tm_yday: 0_i32,
         tm_isdst: 0_i32,
         tm_gmtoff: 0_i32,
-        tm_zone: ~"",
+        tm_zone: zone,
         tm_nsec: 0_i32,
     }
 }
index 118754ec02830a1d5b6a3fee9e7f3e6e99a02125..307de43a067f0e5a1cccb5d363240af83a1cb0d9 100644 (file)
@@ -879,7 +879,8 @@ mod test_treemap {
 
     #[test]
     fn find_empty() {
-        let m = TreeMap::new::<int, int>(); assert!(m.find(&5) == None);
+        let m: TreeMap<int,int> = TreeMap::new();
+        assert!(m.find(&5) == None);
     }
 
     #[test]
@@ -1006,7 +1007,7 @@ fn check_structure<K: TotalOrd, V>(map: &TreeMap<K, V>) {
 
     #[test]
     fn test_rand_int() {
-        let mut map = TreeMap::new::<int, int>();
+        let mut map: TreeMap<int,int> = TreeMap::new();
         let mut ctrl = ~[];
 
         check_equal(ctrl, &map);
index 1a99de127a8d143ce3b815baf1621408b3ab9c0f..3159d8a8f3c63d12a894d92d27788f8602cfecc2 100644 (file)
@@ -787,7 +787,7 @@ pub fn uuid_to_str(bh: &mut BenchHarness) {
     pub fn parse_str(bh: &mut BenchHarness) {
         let s = "urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4";
         do bh.iter {
-            let u = Uuid::parse_string(s);
+            Uuid::parse_string(s);
         }
     }
 }
index fc59df8d2489497b00b3000569bd6b5b69870c9e..94f4adb590ab2c8bdc8336dbaf5b0e04cda7f894 100644 (file)
@@ -13,7 +13,7 @@
 use driver::session;
 use metadata::loader::meta_section_name;
 
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
@@ -61,13 +61,7 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t {
           }
         },
 
-        target_triple: match target_os {
-          session::os_macos => ~"arm-apple-darwin",
-          session::os_win32 => ~"arm-pc-mingw32",
-          session::os_linux => ~"arm-unknown-linux-gnueabihf",
-          session::os_android => ~"arm-linux-androideabi",
-          session::os_freebsd => ~"arm-unknown-freebsd"
-        },
+        target_triple: target_triple,
 
         cc_args: ~[~"-marm"]
     };
index db61042b9ff9893649da8ca5819c47c7028e6df1..ccebf88ec38b64bb69a982e54260f9aafcdc9f44 100644 (file)
@@ -27,7 +27,6 @@
 use std::hash::Streaming;
 use std::hash;
 use std::io;
-use std::libc::{c_int, c_uint};
 use std::os::consts::{macos, freebsd, linux, android, win32};
 use std::os;
 use std::ptr;
@@ -67,37 +66,19 @@ pub fn llvm_err(sess: Session, msg: ~str) -> ! {
     }
 }
 
-pub fn WriteOutputFile(sess: Session,
-        PM: lib::llvm::PassManagerRef, M: ModuleRef,
-        Triple: &str,
-        Cpu: &str,
-        Feature: &str,
+pub fn WriteOutputFile(
+        sess: Session,
+        Target: lib::llvm::TargetMachineRef,
+        PM: lib::llvm::PassManagerRef,
+        M: ModuleRef,
         Output: &str,
-        // FIXME: When #2334 is fixed, change
-        // c_uint to FileType
-        FileType: c_uint,
-        OptLevel: c_int,
-        EnableSegmentedStacks: bool) {
+        FileType: lib::llvm::FileType) {
     unsafe {
-        do Triple.with_c_str |Triple| {
-            do Cpu.with_c_str |Cpu| {
-                do Feature.with_c_str |Feature| {
-                    do Output.with_c_str |Output| {
-                        let result = llvm::LLVMRustWriteOutputFile(
-                                PM,
-                                M,
-                                Triple,
-                                Cpu,
-                                Feature,
-                                Output,
-                                FileType,
-                                OptLevel,
-                                EnableSegmentedStacks);
-                        if (!result) {
-                            llvm_err(sess, ~"Could not write output");
-                        }
-                    }
-                }
+        do Output.with_c_str |Output| {
+            let result = llvm::LLVMRustWriteOutputFile(
+                    Target, PM, M, Output, FileType);
+            if !result {
+                llvm_err(sess, ~"Could not write output");
             }
         }
     }
@@ -231,25 +212,15 @@ pub mod write {
     use driver::session::Session;
     use driver::session;
     use lib::llvm::llvm;
-    use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
-    use lib::llvm::{ContextRef};
+    use lib::llvm::{ModuleRef, ContextRef};
     use lib;
 
-    use back::passes;
-
     use std::c_str::ToCStr;
-    use std::libc::{c_int, c_uint};
+    use std::libc::c_uint;
     use std::path::Path;
     use std::run;
     use std::str;
 
-    pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
-        match ot {
-            output_type_assembly | output_type_object | output_type_exe => true,
-            _ => false
-        }
-    }
-
     pub fn run_passes(sess: Session,
                       llcx: ContextRef,
                       llmod: ModuleRef,
@@ -258,163 +229,178 @@ pub fn run_passes(sess: Session,
         unsafe {
             llvm::LLVMInitializePasses();
 
-            let opts = sess.opts;
-            if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
-            let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
-            let pm = mk_pass_manager();
-            llvm::LLVMAddTargetData(td.lltd, pm.llpm);
-
-            // Generate a pre-optimization intermediate file if -save-temps
-            // was specified.
-            if opts.save_temps {
-                match output_type {
-                  output_type_bitcode => {
-                    if opts.optimize != session::No {
-                        let filename = output.with_filetype("no-opt.bc");
-                        do filename.with_c_str |buf| {
-                            llvm::LLVMWriteBitcodeToFile(llmod, buf);
-                        }
-                    }
-                  }
-                  _ => {
-                    let filename = output.with_filetype("bc");
-                    do filename.with_c_str |buf| {
-                        llvm::LLVMWriteBitcodeToFile(llmod, buf);
-                    }
-                  }
+            // Only initialize the platforms supported by Rust here, because
+            // using --llvm-root will have multiple platforms that rustllvm
+            // doesn't actually link to and it's pointless to put target info
+            // into the registry that Rust can not generate machine code for.
+            llvm::LLVMInitializeX86TargetInfo();
+            llvm::LLVMInitializeX86Target();
+            llvm::LLVMInitializeX86TargetMC();
+            llvm::LLVMInitializeX86AsmPrinter();
+            llvm::LLVMInitializeX86AsmParser();
+
+            llvm::LLVMInitializeARMTargetInfo();
+            llvm::LLVMInitializeARMTarget();
+            llvm::LLVMInitializeARMTargetMC();
+            llvm::LLVMInitializeARMAsmPrinter();
+            llvm::LLVMInitializeARMAsmParser();
+
+            llvm::LLVMInitializeMipsTargetInfo();
+            llvm::LLVMInitializeMipsTarget();
+            llvm::LLVMInitializeMipsTargetMC();
+            llvm::LLVMInitializeMipsAsmPrinter();
+            llvm::LLVMInitializeMipsAsmParser();
+
+            if sess.opts.save_temps {
+                do output.with_filetype("no-opt.bc").with_c_str |buf| {
+                    llvm::LLVMWriteBitcodeToFile(llmod, buf);
                 }
             }
 
-            let mut mpm = passes::PassManager::new(td.lltd);
-
-            if !sess.no_verify() {
-                mpm.add_pass_from_name("verify");
-            }
+            // Copy what clan does by turning on loop vectorization at O2 and
+            // slp vectorization at O3
+            let vectorize_loop = !sess.no_vectorize_loops() &&
+                                 (sess.opts.optimize == session::Default ||
+                                  sess.opts.optimize == session::Aggressive);
+            let vectorize_slp = !sess.no_vectorize_slp() &&
+                                sess.opts.optimize == session::Aggressive;
+            llvm::LLVMRustSetLLVMOptions(sess.print_llvm_passes(),
+                                         vectorize_loop,
+                                         vectorize_slp,
+                                         sess.time_llvm_passes());
+
+            let OptLevel = match sess.opts.optimize {
+              session::No => lib::llvm::CodeGenLevelNone,
+              session::Less => lib::llvm::CodeGenLevelLess,
+              session::Default => lib::llvm::CodeGenLevelDefault,
+              session::Aggressive => lib::llvm::CodeGenLevelAggressive,
+            };
 
-            let passes = if sess.opts.custom_passes.len() > 0 {
-                sess.opts.custom_passes.clone()
-            } else {
-                if sess.lint_llvm() {
-                    mpm.add_pass_from_name("lint");
+            let tm = do sess.targ_cfg.target_strs.target_triple.with_c_str |T| {
+                do sess.opts.target_cpu.with_c_str |CPU| {
+                    do sess.opts.target_feature.with_c_str |Features| {
+                        llvm::LLVMRustCreateTargetMachine(
+                            T, CPU, Features,
+                            lib::llvm::CodeModelDefault,
+                            lib::llvm::RelocPIC,
+                            OptLevel,
+                            true
+                        )
+                    }
                 }
-                passes::create_standard_passes(opts.optimize)
             };
 
+            // Create the two optimizing pass managers. These mirror what clang
+            // does, and are by populated by LLVM's default PassManagerBuilder.
+            // Each manager has a different set of passes, but they also share
+            // some common passes. Each one is initialized with the analyis
+            // passes the target requires, and then further passes are added.
+            let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
+            let mpm = llvm::LLVMCreatePassManager();
+            llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
+            llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+
+            // If we're verifying or linting, add them to the function pass
+            // manager.
+            let addpass = |pass: &str| {
+                do pass.with_c_str |s| { llvm::LLVMRustAddPass(fpm, s) }
+            };
+            if !sess.no_verify() { assert!(addpass("verify")); }
+            if sess.lint_llvm()  { assert!(addpass("lint"));   }
+
+            // Create the PassManagerBuilder for LLVM. We configure it with
+            // reasonable defaults and prepare it to actually populate the pass
+            // manager.
+            let builder = llvm::LLVMPassManagerBuilderCreate();
+            match sess.opts.optimize {
+                session::No => {
+                    // Don't add lifetime intrinsics add O0
+                    llvm::LLVMRustAddAlwaysInlinePass(builder, false);
+                }
+                // numeric values copied from clang
+                session::Less => {
+                    llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+                                                                        225);
+                }
+                session::Default | session::Aggressive => {
+                    llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+                                                                        275);
+                }
+            }
+            llvm::LLVMPassManagerBuilderSetOptLevel(builder, OptLevel as c_uint);
+            llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
+
+            // Use the builder to populate the function/module pass managers.
+            llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
+            llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
+            llvm::LLVMPassManagerBuilderDispose(builder);
+
+            for pass in sess.opts.custom_passes.iter() {
+                do pass.with_c_str |s| {
+                    if !llvm::LLVMRustAddPass(mpm, s) {
+                        sess.warn(fmt!("Unknown pass %s, ignoring", *pass));
+                    }
+                }
+            }
+
+            // Finally, run the actual optimization passes
+            llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
+            llvm::LLVMRunPassManager(mpm, llmod);
 
-            debug!("Passes: %?", passes);
-            passes::populate_pass_manager(sess, &mut mpm, passes);
+            // Deallocate managers that we're now done with
+            llvm::LLVMDisposePassManager(fpm);
+            llvm::LLVMDisposePassManager(mpm);
 
-            debug!("Running Module Optimization Pass");
-            mpm.run(llmod);
+            if sess.opts.save_temps {
+                do output.with_filetype("bc").with_c_str |buf| {
+                    llvm::LLVMWriteBitcodeToFile(llmod, buf);
+                }
+            }
 
-            if opts.jit {
+            if sess.opts.jit {
                 // If we are using JIT, go ahead and create and execute the
-                // engine now.  JIT execution takes ownership of the module and
-                // context, so don't dispose and return.
+                // engine now. JIT execution takes ownership of the module and
+                // context, so don't dispose
                 jit::exec(sess, llcx, llmod, true);
+            } else {
+                // Create a codegen-specific pass manager to emit the actual
+                // assembly or object files. This may not end up getting used,
+                // but we make it anyway for good measure.
+                let cpm = llvm::LLVMCreatePassManager();
+                llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
+                llvm::LLVMRustAddLibraryInfo(cpm, llmod);
 
-                if sess.time_llvm_passes() {
-                    llvm::LLVMRustPrintPassTimings();
-                }
-                return;
-            } else if is_object_or_assembly_or_exe(output_type) {
-                let LLVMOptNone       = 0 as c_int; // -O0
-                let LLVMOptLess       = 1 as c_int; // -O1
-                let LLVMOptDefault    = 2 as c_int; // -O2, -Os
-                let LLVMOptAggressive = 3 as c_int; // -O3
-
-                let CodeGenOptLevel = match opts.optimize {
-                  session::No => LLVMOptNone,
-                  session::Less => LLVMOptLess,
-                  session::Default => LLVMOptDefault,
-                  session::Aggressive => LLVMOptAggressive
-                };
-
-                let FileType = match output_type {
-                    output_type_object | output_type_exe => lib::llvm::ObjectFile,
-                    _ => lib::llvm::AssemblyFile
-                };
-
-                // Write optimized bitcode if --save-temps was on.
-
-                if opts.save_temps {
-                    // Always output the bitcode file with --save-temps
-
-                    let filename = output.with_filetype("opt.bc");
-                    do filename.with_c_str |buf| {
-                        llvm::LLVMWriteBitcodeToFile(llmod, buf)
-                    };
-                    // Save the assembly file if -S is used
-                    if output_type == output_type_assembly {
-                        WriteOutputFile(
-                            sess,
-                            pm.llpm,
-                            llmod,
-                            sess.targ_cfg.target_strs.target_triple,
-                            opts.target_cpu,
-                            opts.target_feature,
-                            output.to_str(),
-                            lib::llvm::AssemblyFile as c_uint,
-                            CodeGenOptLevel,
-                            true);
+                match output_type {
+                    output_type_none => {}
+                    output_type_bitcode => {
+                        do output.with_c_str |buf| {
+                            llvm::LLVMWriteBitcodeToFile(llmod, buf);
+                        }
                     }
-
-                    // Save the object file for -c or --save-temps alone
-                    // This .o is needed when an exe is built
-                    if output_type == output_type_object ||
-                           output_type == output_type_exe {
-                        WriteOutputFile(
-                            sess,
-                            pm.llpm,
-                            llmod,
-                            sess.targ_cfg.target_strs.target_triple,
-                            opts.target_cpu,
-                            opts.target_feature,
-                            output.to_str(),
-                            lib::llvm::ObjectFile as c_uint,
-                            CodeGenOptLevel,
-                            true);
+                    output_type_llvm_assembly => {
+                        do output.with_c_str |output| {
+                            llvm::LLVMRustPrintModule(cpm, llmod, output)
+                        }
+                    }
+                    output_type_assembly => {
+                        WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
+                                        lib::llvm::AssemblyFile);
+                    }
+                    output_type_exe | output_type_object => {
+                        WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
+                                        lib::llvm::ObjectFile);
                     }
-                } else {
-                    // If we aren't saving temps then just output the file
-                    // type corresponding to the '-c' or '-S' flag used
-                    WriteOutputFile(
-                        sess,
-                        pm.llpm,
-                        llmod,
-                        sess.targ_cfg.target_strs.target_triple,
-                        opts.target_cpu,
-                        opts.target_feature,
-                        output.to_str(),
-                        FileType as c_uint,
-                        CodeGenOptLevel,
-                        true);
                 }
-                // Clean up and return
 
-                llvm::LLVMDisposeModule(llmod);
-                llvm::LLVMContextDispose(llcx);
-                if sess.time_llvm_passes() {
-                    llvm::LLVMRustPrintPassTimings();
-                }
-                return;
+                llvm::LLVMDisposePassManager(cpm);
             }
 
-            if output_type == output_type_llvm_assembly {
-                // Given options "-S --emit-llvm": output LLVM assembly
-                do output.with_c_str |buf_o| {
-                    llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o);
-                }
-            } else {
-                // If only a bitcode file is asked for by using the
-                // '--emit-llvm' flag, then output it here
-                do output.with_c_str |buf| {
-                    llvm::LLVMWriteBitcodeToFile(llmod, buf);
-                }
+            llvm::LLVMRustDisposeTargetMachine(tm);
+            // the jit takes ownership of these two items
+            if !sess.opts.jit {
+                llvm::LLVMDisposeModule(llmod);
+                llvm::LLVMContextDispose(llcx);
             }
-
-            llvm::LLVMDisposeModule(llmod);
-            llvm::LLVMContextDispose(llcx);
             if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
         }
     }
index 3409db5aabe3f9cb2cfb90dcb07dbfc6689f9859..e19b3c78623a61ed681fbdfc512ec1401c759b93 100644 (file)
@@ -13,7 +13,7 @@
 use driver::session::sess_os_to_meta_os;
 use metadata::loader::meta_section_name;
 
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
@@ -61,13 +61,7 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t {
           }
         },
 
-        target_triple: match target_os {
-          session::os_macos => ~"mips-apple-darwin",
-          session::os_win32 => ~"mips-pc-mingw32",
-          session::os_linux => ~"mips-unknown-linux-gnu",
-          session::os_android => ~"mips-unknown-android-gnu",
-          session::os_freebsd => ~"mips-unknown-freebsd"
-        },
+        target_triple: target_triple,
 
         cc_args: ~[]
     };
diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs
deleted file mode 100644 (file)
index bb5ddc1..0000000
+++ /dev/null
@@ -1,349 +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.
-
-use std::c_str::ToCStr;
-use std::io;
-
-use driver::session::{OptLevel, No, Less, Aggressive};
-use driver::session::{Session};
-use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
-use lib::llvm::llvm;
-use lib;
-
-pub struct PassManager {
-    priv llpm: PassManagerRef
-}
-
-impl Drop for PassManager {
-    fn drop(&self) {
-        unsafe {
-            llvm::LLVMDisposePassManager(self.llpm);
-        }
-    }
-}
-
-impl PassManager {
-    pub fn new(td: TargetDataRef) -> PassManager {
-        unsafe {
-            let pm = PassManager {
-                llpm: llvm::LLVMCreatePassManager()
-            };
-            llvm::LLVMAddTargetData(td, pm.llpm);
-
-            return pm;
-        }
-    }
-
-    pub fn add_pass(&mut self, pass:PassRef) {
-        unsafe {
-            llvm::LLVMAddPass(self.llpm, pass);
-        }
-    }
-
-    pub fn add_pass_from_name(&mut self, name:&str) {
-        let pass = create_pass(name).unwrap();
-        self.add_pass(pass);
-    }
-
-    pub fn run(&self, md:ModuleRef) -> bool {
-        unsafe {
-            llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
-        }
-    }
-}
-
-pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
-    let mut passes = ~[];
-
-    // mostly identical to clang 3.3, all differences are documented with comments
-
-    if level != No {
-        passes.push(~"targetlibinfo");
-        passes.push(~"no-aa");
-        // "tbaa" omitted, we don't emit clang-style type-based alias analysis information
-        passes.push(~"basicaa");
-        passes.push(~"globalopt");
-        passes.push(~"ipsccp");
-        passes.push(~"deadargelim");
-        passes.push(~"instcombine");
-        passes.push(~"simplifycfg");
-    }
-
-    passes.push(~"basiccg");
-
-    if level != No {
-        passes.push(~"prune-eh");
-    }
-
-    passes.push(~"inline-cost");
-
-    if level == No || level == Less {
-        passes.push(~"always-inline");
-    } else {
-        passes.push(~"inline");
-    }
-
-    if level != No {
-        passes.push(~"functionattrs");
-        if level == Aggressive {
-            passes.push(~"argpromotion");
-        }
-        passes.push(~"sroa");
-        passes.push(~"domtree");
-        passes.push(~"early-cse");
-        passes.push(~"lazy-value-info");
-        passes.push(~"jump-threading");
-        passes.push(~"correlated-propagation");
-        passes.push(~"simplifycfg");
-        passes.push(~"instcombine");
-        passes.push(~"tailcallelim");
-        passes.push(~"simplifycfg");
-        passes.push(~"reassociate");
-        passes.push(~"domtree");
-        passes.push(~"loops");
-        passes.push(~"loop-simplify");
-        passes.push(~"lcssa");
-        passes.push(~"loop-rotate");
-        passes.push(~"licm");
-        passes.push(~"lcssa");
-        passes.push(~"loop-unswitch");
-        passes.push(~"instcombine");
-        passes.push(~"scalar-evolution");
-        passes.push(~"loop-simplify");
-        passes.push(~"lcssa");
-        passes.push(~"indvars");
-        passes.push(~"loop-idiom");
-        passes.push(~"loop-deletion");
-        if level == Aggressive {
-            passes.push(~"loop-simplify");
-            passes.push(~"lcssa");
-            passes.push(~"loop-vectorize");
-            passes.push(~"loop-simplify");
-            passes.push(~"lcssa");
-            passes.push(~"scalar-evolution");
-            passes.push(~"loop-simplify");
-            passes.push(~"lcssa");
-        }
-        if level != Less {
-            passes.push(~"loop-unroll");
-            passes.push(~"memdep");
-            passes.push(~"gvn");
-        }
-        passes.push(~"memdep");
-        passes.push(~"memcpyopt");
-        passes.push(~"sccp");
-        passes.push(~"instcombine");
-        passes.push(~"lazy-value-info");
-        passes.push(~"jump-threading");
-        passes.push(~"correlated-propagation");
-        passes.push(~"domtree");
-        passes.push(~"memdep");
-        passes.push(~"dse");
-        passes.push(~"adce");
-        passes.push(~"simplifycfg");
-        passes.push(~"instcombine");
-        // clang does `strip-dead-prototypes` here, since it does not emit them
-    }
-
-    // rustc emits dead prototypes, so always ask LLVM to strip them
-    passes.push(~"strip-dead-prototypes");
-
-    if level != Less {
-        passes.push(~"globaldce");
-        passes.push(~"constmerge");
-    }
-
-    passes
-}
-
-pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
-    for nm in pass_list.iter() {
-        match create_pass(*nm) {
-            Some(p) => pm.add_pass(p),
-            None    => sess.warn(fmt!("Unknown pass %s", *nm))
-        }
-    }
-}
-
-pub fn create_pass(name:&str) -> Option<PassRef> {
-    do name.with_c_str |s| {
-        unsafe {
-            let p = llvm::LLVMCreatePass(s);
-            if p.is_null() {
-                None
-            } else {
-                Some(p)
-            }
-        }
-    }
-}
-
-pub fn list_passes() {
-    io::println("\nAvailable Passes:");
-
-    io::println("\nAnalysis Passes:");
-    for &(name, desc) in analysis_passes.iter() {
-        printfln!("    %-30s -- %s", name, desc);
-    }
-    io::println("\nTransformation Passes:");
-    for &(name, desc) in transform_passes.iter() {
-        printfln!("    %-30s -- %s", name, desc);
-    }
-    io::println("\nUtility Passes:");
-    for &(name, desc) in utility_passes.iter() {
-        printfln!("    %-30s -- %s", name, desc);
-    }
-}
-
-/** Analysis Passes */
-pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
-    ("aa-eval",                         "Exhausive Alias Analysis Precision Evaluator"),
-    ("asan",                            "AddressSanitizer"),
-    ("basicaa",                         "Basic Alias Analysis"),
-    ("basiccg",                         "Basic CallGraph Construction"),
-    ("block-freq",                      "Block Frequency Analysis"),
-    ("cost-model",                      "Cost Model Analysis"),
-    ("count-aa",                        "Count Alias Analysis Query Responses"),
-    ("da",                              "Dependence Analysis"),
-    ("debug-aa",                        "AA Use Debugger"),
-    ("domfrontier",                     "Dominance Frontier Construction"),
-    ("domtree",                         "Dominator Tree Construction"),
-    ("globalsmodref-aa",                "Simple mod/ref analysis for globals"),
-    ("instcount",                       "Count the various types of Instructions"),
-    ("intervals",                       "Interval Partition Construction"),
-    ("iv-users",                        "Induction Variable Users"),
-    ("lazy-value-info",                 "Lazy Value Information Analysis"),
-    ("libcall-aa",                      "LibCall Alias Analysis"),
-    ("lint",                            "Statically lint-check LLVM IR"),
-    ("loops",                           "Natural Loop Information"),
-    ("memdep",                          "Memory Dependence Analysis"),
-    ("module-debuginfo",                "Decodes module-level debug info"),
-    ("profile-estimator",               "Estimate profiling information"),
-    ("profile-loader",                  "Load profile information from llvmprof.out"),
-    ("profile-verifier",                "Verify profiling information"),
-    ("regions",                         "Detect single entry single exit regions"),
-    ("scalar-evolution",                "Scalar Evolution Analysis"),
-    ("scev-aa",                         "Scalar Evolution-based Alias Analysis"),
-    ("tbaa",                            "Type-Based Alias Analysis"),
-    ("tsan",                            "ThreadSanitizer"),
-];
-
-/** Transformation Passes */
-pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
-    ("adce",                            "Aggressive Dead Code Elimination"),
-    ("always-inline",                   "Inliner for #[inline] functions"),
-    ("argpromotion",                    "Promote 'by reference' arguments to scalars"),
-    ("bb-vectorize",                    "Basic-Block Vectorization"),
-    ("block-placement",                 "Profile Guided Basic Block Placement"),
-    ("bounds-checking",                 "Run-time bounds checking"),
-    ("break-crit-edges",                "Break critical edges in CFG"),
-    ("codegenprepare",                  "Optimize for code generation"),
-    ("constmerge",                      "Merge Duplicate Global Constants"),
-    ("constprop",                       "Simple constant propagation"),
-    ("correlated-propagation",          "Value Propagation"),
-    ("da",                              "Data Layout"),
-    ("dce",                             "Dead Code Elimination"),
-    ("deadargelim",                     "Dead Argument Elimination"),
-    ("die",                             "Dead Instruction Elimination"),
-    ("dse",                             "Dead Store Elimination"),
-    ("early-cse",                       "Early CSE"),
-    ("functionattrs",                   "Deduce function attributes"),
-    ("globaldce",                       "Dead Global Elimination"),
-    ("globalopt",                       "Global Variable Optimizer"),
-    ("gvn",                             "Global Value Numbering"),
-    ("indvars",                         "Canonicalize Induction Variables"),
-    ("inline",                          "Function Integration/Inlining"),
-    ("insert-edge-profiling",           "Insert instrumentation for edge profiling"),
-    ("insert-gcov-profiling",           "Insert instrumentation for GCOV profiling"),
-    ("insert-optimal-edge-profiling",   "Insert optimal instrumentation for edge profiling"),
-    ("instcombine",                     "Combine redundant instructions"),
-    ("instsimplify",                    "Remove redundant instructions"),
-    ("ipconstprop",                     "Interprocedural constant propagation"),
-    ("ipsccp",                          "Interprocedural Sparse Conditional Constant Propagation"),
-    ("jump-threading",                  "Jump Threading"),
-    ("lcssa",                           "Loop-Closed SSA Form Pass"),
-    ("licm",                            "Loop Invariant Code Motion"),
-    ("loop-deletion",                   "Delete dead loops"),
-    ("loop-extract",                    "Extract loops into new functions"),
-    ("loop-extract-single",             "Extract at most one loop into a new function"),
-    ("loop-idiom",                      "Recognise loop idioms"),
-    ("loop-instsimplify",               "Simplify instructions in loops"),
-    ("loop-reduce",                     "Loop Strength Reduction"),
-    ("loop-rotate",                     "Rotate Loops"),
-    ("loop-simplify",                   "Canonicalize natural loops"),
-    ("loop-unroll",                     "Unroll loops"),
-    ("loop-unswitch",                   "Unswitch loops"),
-    ("loop-vectorize",                  "Loop Vectorization"),
-    ("lower-expect",                    "Lower 'expect' Intrinsics"),
-    ("mem2reg",                         "Promote Memory to Register"),
-    ("memcpyopt",                       "MemCpy Optimization"),
-    ("mergefunc",                       "Merge Functions"),
-    ("mergereturn",                     "Unify function exit nodes"),
-    ("partial-inliner",                 "Partial Inliner"),
-    ("prune-eh",                        "Remove unused exception handling info"),
-    ("reassociate",                     "Reassociate expressions"),
-    ("reg2mem",                         "Demote all values to stack slots"),
-    ("scalarrepl",                      "Scalar Replacement of Aggregates (DT)"),
-    ("scalarrepl-ssa",                  "Scalar Replacement of Aggregates (SSAUp)"),
-    ("sccp",                            "Sparse Conditional Constant Propagation"),
-    ("simplifycfg",                     "Simplify the CFG"),
-    ("sink",                            "Code sinking"),
-    ("strip",                           "Strip all symbols from a module"),
-    ("strip-dead-debug-info",           "Strip debug info for unused symbols"),
-    ("strip-dead-prototypes",           "Strip Unused Function Prototypes"),
-    ("strip-debug-declare",             "Strip all llvm.dbg.declare intrinsics"),
-    ("strip-nondebug",                  "Strip all symbols, except dbg symbols, from a module"),
-    ("sroa",                            "Scalar Replacement of Aggregates"),
-    ("tailcallelim",                    "Tail Call Elimination"),
-];
-
-/** Utility Passes */
-static utility_passes : &'static [(&'static str, &'static str)] = &'static [
-    ("instnamer",                       "Assign names to anonymous instructions"),
-    ("verify",                          "Module Verifier"),
-];
-
-#[test]
-fn passes_exist() {
-    let mut failed = ~[];
-    unsafe { llvm::LLVMInitializePasses(); }
-    for &(name,_) in analysis_passes.iter() {
-        let pass = create_pass(name);
-        if !pass.is_some() {
-            failed.push(name);
-        } else {
-            unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
-        }
-    }
-    for &(name,_) in transform_passes.iter() {
-        let pass = create_pass(name);
-        if !pass.is_some() {
-            failed.push(name);
-        } else {
-            unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
-        }
-    }
-    for &(name,_) in utility_passes.iter() {
-        let pass = create_pass(name);
-        if !pass.is_some() {
-            failed.push(name);
-        } else {
-            unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
-        }
-    }
-
-    if failed.len() > 0 {
-        io::println("Some passes don't exist:");
-        for &n in failed.iter() {
-            printfln!("    %s", n);
-        }
-        fail!();
-    }
-}
index c5dbbf8f028dba1b9ffd5703ca44f3b7437546d4..968c5ba161b1de1cf64393be5db7d2b626af8aef 100644 (file)
@@ -14,7 +14,7 @@
 use driver::session;
 use metadata::loader::meta_section_name;
 
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
@@ -44,13 +44,7 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t {
           }
         },
 
-        target_triple: match target_os {
-          session::os_macos => ~"i686-apple-darwin",
-          session::os_win32 => ~"i686-pc-mingw32",
-          session::os_linux => ~"i686-unknown-linux-gnu",
-          session::os_android => ~"i686-unknown-android-gnu",
-          session::os_freebsd => ~"i686-unknown-freebsd"
-        },
+        target_triple: target_triple,
 
         cc_args: ~[~"-m32"]
     };
index 42420094e1767926a4a2988e351a1c9d701891fc..87aad7a108cebbf5e3c55d1b0c8f1eca1a651c62 100644 (file)
@@ -14,7 +14,7 @@
 use driver::session;
 use metadata::loader::meta_section_name;
 
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
@@ -52,13 +52,7 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t {
           }
         },
 
-        target_triple: match target_os {
-          session::os_macos => ~"x86_64-apple-darwin",
-          session::os_win32 => ~"x86_64-pc-mingw32",
-          session::os_linux => ~"x86_64-unknown-linux-gnu",
-          session::os_android => ~"x86_64-unknown-android-gnu",
-          session::os_freebsd => ~"x86_64-unknown-freebsd",
-        },
+        target_triple: target_triple,
 
         cc_args: ~[~"-m64"]
     };
index ca3247db669cb3210cdca66084d6f50258888076..003840b85a16744b063e9fe57bf8c4785be398cf 100644 (file)
@@ -570,11 +570,12 @@ pub fn build_target_config(sopts: @session::options,
       abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
       abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
     };
+    let target_triple = sopts.target_triple.clone();
     let target_strs = match arch {
-      abi::X86 => x86::get_target_strs(os),
-      abi::X86_64 => x86_64::get_target_strs(os),
-      abi::Arm => arm::get_target_strs(os),
-      abi::Mips => mips::get_target_strs(os)
+      abi::X86 => x86::get_target_strs(target_triple, os),
+      abi::X86_64 => x86_64::get_target_strs(target_triple, os),
+      abi::Arm => arm::get_target_strs(target_triple, os),
+      abi::Mips => mips::get_target_strs(target_triple, os)
     };
     let target_cfg = @session::config {
         os: os,
@@ -847,8 +848,9 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] {
   optopt("", "opt-level",
                         "Optimize with possible levels 0-3", "LEVEL"),
   optopt("", "passes", "Comma or space separated list of pass names to use. \
-                        Overrides the default passes for optimization levels,\n\
-                        a value of \"list\" will list the available passes.", "NAMES"),
+                        Appends to the default list of passes to run for the \
+                        specified current optimization level. A value of \
+                        \"list\" will list all of the available passes", "NAMES"),
   optopt( "",  "out-dir",
                         "Write output to compiler-chosen filename
                           in <dir>", "DIR"),
index 50b29ff16be1a5a456be92758cc2477a24b63af8..912fc606f0a344d6e126c4f39c561002c0970b81 100644 (file)
@@ -76,6 +76,9 @@ pub struct config {
 pub static no_debug_borrows:        uint = 1 << 24;
 pub static lint_llvm:               uint = 1 << 25;
 pub static once_fns:                uint = 1 << 26;
+pub static print_llvm_passes:       uint = 1 << 27;
+pub static no_vectorize_loops:      uint = 1 << 28;
+pub static no_vectorize_slp:        uint = 1 << 29;
 
 pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
     ~[(~"verbose", ~"in general, enable more debug printouts", verbose),
@@ -120,6 +123,15 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
      (~"once-fns",
       ~"Allow 'once fn' closures to deinitialize captured variables",
       once_fns),
+     (~"print-llvm-passes",
+      ~"Prints the llvm optimization passes being run",
+      print_llvm_passes),
+     (~"no-vectorize-loops",
+      ~"Don't run the loop vectorization optimization passes",
+      no_vectorize_loops),
+     (~"no-vectorize-slp",
+      ~"Don't run LLVM's SLP vectorization passes",
+      no_vectorize_slp),
     ]
 }
 
@@ -305,6 +317,15 @@ pub fn debug_borrows(@self) -> bool {
         self.opts.optimize == No && !self.debugging_opt(no_debug_borrows)
     }
     pub fn once_fns(@self) -> bool { self.debugging_opt(once_fns) }
+    pub fn print_llvm_passes(@self) -> bool {
+        self.debugging_opt(print_llvm_passes)
+    }
+    pub fn no_vectorize_loops(@self) -> bool {
+        self.debugging_opt(no_vectorize_loops)
+    }
+    pub fn no_vectorize_slp(@self) -> bool {
+        self.debugging_opt(no_vectorize_slp)
+    }
 
     // pointless function, now...
     pub fn str_of(@self, id: ast::ident) -> @str {
index 2a61ea28e0c6b3452c6118b4faf403e4db10cbc6..429a1c35b3421f7d6b786e34d93de89eff735414 100644 (file)
@@ -17,6 +17,7 @@
 use syntax::codemap::dummy_sp;
 use syntax::codemap;
 use syntax::fold;
+use syntax::opt_vec;
 
 static STD_VERSION: &'static str = "0.8-pre";
 
@@ -90,12 +91,18 @@ fn spanned<T>(x: T) -> codemap::spanned<T> {
             let prelude_path = ast::Path {
                 span: dummy_sp(),
                 global: false,
-                idents: ~[
-                    sess.ident_of("std"),
-                    sess.ident_of("prelude")
+                segments: ~[
+                    ast::PathSegment {
+                        identifier: sess.ident_of("std"),
+                        lifetime: None,
+                        types: opt_vec::Empty,
+                    },
+                    ast::PathSegment {
+                        identifier: sess.ident_of("prelude"),
+                        lifetime: None,
+                        types: opt_vec::Empty,
+                    },
                 ],
-                rp: None,
-                types: ~[]
             };
 
             let vp = @spanned(ast::view_path_glob(prelude_path, n2));
index 0aacd4c5063db28a3c8eea9a972cb04b237acba4..a341db75393d3d1bf0ec6f08f5e098be300bd16d 100644 (file)
 
 use std::vec;
 use syntax::ast_util::*;
+use syntax::attr::AttrMetaMethods;
 use syntax::attr;
 use syntax::codemap::{dummy_sp, span, ExpnInfo, NameAndSpan};
 use syntax::codemap;
 use syntax::ext::base::ExtCtxt;
 use syntax::fold;
+use syntax::opt_vec;
 use syntax::print::pprust;
 use syntax::{ast, ast_util};
-use syntax::attr::AttrMetaMethods;
 
 type node_id_gen = @fn() -> ast::NodeId;
 
@@ -383,19 +384,27 @@ fn nospan<T>(t: T) -> codemap::spanned<T> {
 }
 
 fn path_node(ids: ~[ast::ident]) -> ast::Path {
-    ast::Path { span: dummy_sp(),
-                global: false,
-                idents: ids,
-                rp: None,
-                types: ~[] }
+    ast::Path {
+        span: dummy_sp(),
+        global: false,
+        segments: ids.move_iter().map(|identifier| ast::PathSegment {
+            identifier: identifier,
+            lifetime: None,
+            types: opt_vec::Empty,
+        }).collect()
+    }
 }
 
 fn path_node_global(ids: ~[ast::ident]) -> ast::Path {
-    ast::Path { span: dummy_sp(),
-                 global: true,
-                 idents: ids,
-                 rp: None,
-                 types: ~[] }
+    ast::Path {
+        span: dummy_sp(),
+        global: true,
+        segments: ids.move_iter().map(|identifier| ast::PathSegment {
+            identifier: identifier,
+            lifetime: None,
+            types: opt_vec::Empty,
+        }).collect()
+    }
 }
 
 #[cfg(stage0)]
index 60f8a1773fc84a59b1514bbcfcce11778f73278a..220b082fab1cf986fd7fa8318a3f853b1d50d4f5 100644 (file)
@@ -170,7 +170,6 @@ pub enum AtomicOrdering {
     SequentiallyConsistent = 7
 }
 
-// FIXME: Not used right now, but will be once #2334 is fixed
 // Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h)
 pub enum FileType {
     AssemblyFile = 0,
@@ -192,6 +191,29 @@ pub enum AsmDialect {
     AD_Intel = 1
 }
 
+pub enum CodeGenOptLevel {
+    CodeGenLevelNone = 0,
+    CodeGenLevelLess = 1,
+    CodeGenLevelDefault = 2,
+    CodeGenLevelAggressive = 3,
+}
+
+pub enum RelocMode {
+    RelocDefault = 0,
+    RelocStatic = 1,
+    RelocPIC = 2,
+    RelocDynamicNoPic = 3,
+}
+
+pub enum CodeGenModel {
+    CodeModelDefault = 0,
+    CodeModelJITDefault = 1,
+    CodeModelSmall = 2,
+    CodeModelKernel = 3,
+    CodeModelMedium = 4,
+    CodeModelLarge = 5,
+}
+
 // Opaque pointer types
 pub enum Module_opaque {}
 pub type ModuleRef = *Module_opaque;
@@ -223,6 +245,8 @@ pub enum SectionIterator_opaque {}
 pub type SectionIteratorRef = *SectionIterator_opaque;
 pub enum Pass_opaque {}
 pub type PassRef = *Pass_opaque;
+pub enum TargetMachine_opaque {}
+pub type TargetMachineRef = *TargetMachine_opaque;
 
 pub mod debuginfo {
     use super::{ValueRef};
@@ -266,7 +290,8 @@ pub mod llvm {
     use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef};
     use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef};
     use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef};
-    use super::{ValueRef, PassRef};
+    use super::{ValueRef, TargetMachineRef, FileType};
+    use super::{CodeGenModel, RelocMode, CodeGenOptLevel};
     use super::debuginfo::*;
     use std::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong};
 
@@ -1614,6 +1639,7 @@ pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef)
         /** Creates a pass manager. */
         #[fast_ffi]
         pub fn LLVMCreatePassManager() -> PassManagerRef;
+
         /** Creates a function-by-function pass manager */
         #[fast_ffi]
         pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef)
@@ -1643,15 +1669,6 @@ pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef)
         #[fast_ffi]
         pub fn LLVMInitializePasses();
 
-        #[fast_ffi]
-        pub fn LLVMAddPass(PM: PassManagerRef, P: PassRef);
-
-        #[fast_ffi]
-        pub fn LLVMCreatePass(PassName: *c_char) -> PassRef;
-
-        #[fast_ffi]
-        pub fn LLVMDestroyPass(P: PassRef);
-
         /** Adds a verification pass. */
         #[fast_ffi]
         pub fn LLVMAddVerifierPass(PM: PassManagerRef);
@@ -1808,20 +1825,6 @@ pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef,
         pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *c_char)
             -> MemoryBufferRef;
 
-        #[fast_ffi]
-        pub fn LLVMRustWriteOutputFile(PM: PassManagerRef,
-                                       M: ModuleRef,
-                                       Triple: *c_char,
-                                       Cpu: *c_char,
-                                       Feature: *c_char,
-                                       Output: *c_char,
-                                       // FIXME: When #2334 is fixed,
-                                       // change c_uint to FileType
-                                       FileType: c_uint,
-                                       OptLevel: c_int,
-                                       EnableSegmentedStacks: bool)
-                                       -> bool;
-
         /** Returns a string describing the last error caused by an LLVMRust*
             call. */
         #[fast_ffi]
@@ -1842,24 +1845,6 @@ pub fn LLVMRustBuildJIT(MM: *(),
                                 EnableSegmentedStacks: bool)
                                 -> ExecutionEngineRef;
 
-        /** Parses the bitcode in the given memory buffer. */
-        #[fast_ffi]
-        pub fn LLVMRustParseBitcode(MemBuf: MemoryBufferRef) -> ModuleRef;
-
-        /** Parses LLVM asm in the given file */
-        #[fast_ffi]
-        pub fn LLVMRustParseAssemblyFile(Filename: *c_char, C: ContextRef)
-                                         -> ModuleRef;
-
-        #[fast_ffi]
-        pub fn LLVMRustAddPrintModulePass(PM: PassManagerRef,
-                                          M: ModuleRef,
-                                          Output: *c_char);
-
-        /** Turn on LLVM pass-timing. */
-        #[fast_ffi]
-        pub fn LLVMRustEnableTimePasses();
-
         /// Print the pass timings since static dtors aren't picking them up.
         #[fast_ffi]
         pub fn LLVMRustPrintPassTimings();
@@ -2097,6 +2082,55 @@ pub fn LLVMDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef,
                                                         LineNo: c_uint,
                                                         ColumnNo: c_uint)
                                                         -> ValueRef;
+
+        pub fn LLVMInitializeX86TargetInfo();
+        pub fn LLVMInitializeX86Target();
+        pub fn LLVMInitializeX86TargetMC();
+        pub fn LLVMInitializeX86AsmPrinter();
+        pub fn LLVMInitializeX86AsmParser();
+        pub fn LLVMInitializeARMTargetInfo();
+        pub fn LLVMInitializeARMTarget();
+        pub fn LLVMInitializeARMTargetMC();
+        pub fn LLVMInitializeARMAsmPrinter();
+        pub fn LLVMInitializeARMAsmParser();
+        pub fn LLVMInitializeMipsTargetInfo();
+        pub fn LLVMInitializeMipsTarget();
+        pub fn LLVMInitializeMipsTargetMC();
+        pub fn LLVMInitializeMipsAsmPrinter();
+        pub fn LLVMInitializeMipsAsmParser();
+
+        pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: *c_char) -> bool;
+        pub fn LLVMRustCreateTargetMachine(Triple: *c_char,
+                                           CPU: *c_char,
+                                           Features: *c_char,
+                                           Model: CodeGenModel,
+                                           Reloc: RelocMode,
+                                           Level: CodeGenOptLevel,
+                                           EnableSegstk: bool) -> TargetMachineRef;
+        pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef);
+        pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef,
+                                         PM: PassManagerRef,
+                                         M: ModuleRef);
+        pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
+                                             M: ModuleRef);
+        pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef);
+        pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
+        pub fn LLVMRustWriteOutputFile(T: TargetMachineRef,
+                                       PM: PassManagerRef,
+                                       M: ModuleRef,
+                                       Output: *c_char,
+                                       FileType: FileType) -> bool;
+        pub fn LLVMRustPrintModule(PM: PassManagerRef,
+                                   M: ModuleRef,
+                                   Output: *c_char);
+        pub fn LLVMRustSetLLVMOptions(PrintPasses: bool,
+                                      VectorizeLoops: bool,
+                                      VectorizeSLP: bool,
+                                      TimePasses: bool);
+        pub fn LLVMRustPrintPasses();
+        pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *c_char);
+        pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef,
+                                           AddLifetimes: bool);
     }
 }
 
@@ -2244,7 +2278,6 @@ pub fn val_to_str(&self, val: ValueRef) -> ~str {
     }
 }
 
-
 /* Memory-managed interface to target data. */
 
 pub struct target_data_res {
index f2d8b68faa6f3b7a655e5e6637830c5a0bb6e58a..8af535865941f0a9da58577e2b2bcae6b71ee308 100644 (file)
@@ -182,6 +182,12 @@ pub fn from_uint(value : uint) -> Option<astencode_tag> {
 pub static tag_item_method_provided_source: uint = 0x81;
 pub static tag_item_impl_vtables: uint = 0x82;
 
+pub static tag_impls: uint = 0x83;
+pub static tag_impls_impl: uint = 0x84;
+
+pub static tag_items_data_item_inherent_impl: uint = 0x85;
+pub static tag_items_data_item_extension_impl: uint = 0x86;
+
 pub struct LinkMeta {
     name: @str,
     vers: @str,
index c8c4a396c87af99c0041f1274fcd3acf92b353c7..942d5f1373d733e78eb1c384027952d5d3093019 100644 (file)
@@ -25,7 +25,7 @@
 use syntax::diagnostic::span_handler;
 use syntax::parse::token;
 use syntax::parse::token::ident_interner;
-use syntax::oldvisit;
+use syntax::visit;
 
 // Traverses an AST, reading all the information about use'd crates and extern
 // libraries necessary for later resolving, typechecking, linking, etc.
@@ -46,17 +46,25 @@ pub fn read_crates(diag: @mut span_handler,
         next_crate_num: 1,
         intr: intr
     };
-    let v =
-        oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
-            visit_view_item: |a| visit_view_item(e, a),
-            visit_item: |a| visit_item(e, a),
-            .. *oldvisit::default_simple_visitor()});
+    let mut v = ReadCrateVisitor{ e:e };
     visit_crate(e, crate);
-    oldvisit::visit_crate(crate, ((), v));
+    visit::walk_crate(&mut v, crate, ());
     dump_crates(*e.crate_cache);
     warn_if_multiple_versions(e, diag, *e.crate_cache);
 }
 
+struct ReadCrateVisitor { e:@mut Env }
+impl visit::Visitor<()> for ReadCrateVisitor {
+    fn visit_view_item(&mut self, a:&ast::view_item, _:()) {
+        visit_view_item(self.e, a);
+        visit::walk_view_item(self, a, ());
+    }
+    fn visit_item(&mut self, a:@ast::item, _:()) {
+        visit_item(self.e, a);
+        visit::walk_item(self, a, ());
+    }
+}
+
 #[deriving(Clone)]
 struct cache_entry {
     cnum: int,
index 317b9cf6ce34f7c82abe9594403f448905d1ce1f..3ad69ff4da03dd53d77ae160eddc2e25efd4a4c0 100644 (file)
@@ -49,16 +49,34 @@ pub fn each_lang_item(cstore: @mut cstore::CStore,
     decoder::each_lang_item(crate_data, f)
 }
 
-/// Iterates over all the paths in the given crate.
-pub fn each_path(cstore: @mut cstore::CStore,
-                 cnum: ast::CrateNum,
-                 f: &fn(&str, decoder::def_like, ast::visibility) -> bool)
-                 -> bool {
+/// Iterates over each child of the given item.
+pub fn each_child_of_item(cstore: @mut cstore::CStore,
+                          def_id: ast::def_id,
+                          callback: &fn(decoder::def_like, ast::ident)) {
+    let crate_data = cstore::get_crate_data(cstore, def_id.crate);
+    let get_crate_data: decoder::GetCrateDataCb = |cnum| {
+        cstore::get_crate_data(cstore, cnum)
+    };
+    decoder::each_child_of_item(cstore.intr,
+                                crate_data,
+                                def_id.node,
+                                get_crate_data,
+                                callback)
+}
+
+/// Iterates over each top-level crate item.
+pub fn each_top_level_item_of_crate(cstore: @mut cstore::CStore,
+                                    cnum: ast::CrateNum,
+                                    callback: &fn(decoder::def_like,
+                                                  ast::ident)) {
     let crate_data = cstore::get_crate_data(cstore, cnum);
     let get_crate_data: decoder::GetCrateDataCb = |cnum| {
         cstore::get_crate_data(cstore, cnum)
     };
-    decoder::each_path(cstore.intr, crate_data, get_crate_data, f)
+    decoder::each_top_level_item_of_crate(cstore.intr,
+                                          crate_data,
+                                          get_crate_data,
+                                          callback)
 }
 
 pub fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path {
@@ -246,3 +264,36 @@ pub fn get_link_args_for_crate(cstore: @mut cstore::CStore,
     let cdata = cstore::get_crate_data(cstore, crate_num);
     decoder::get_link_args_for_crate(cdata)
 }
+
+pub fn each_impl(cstore: @mut cstore::CStore,
+                 crate_num: ast::CrateNum,
+                 callback: &fn(ast::def_id)) {
+    let cdata = cstore::get_crate_data(cstore, crate_num);
+    decoder::each_impl(cdata, callback)
+}
+
+pub fn each_implementation_for_type(cstore: @mut cstore::CStore,
+                                    def_id: ast::def_id,
+                                    callback: &fn(ast::def_id)) {
+    let cdata = cstore::get_crate_data(cstore, def_id.crate);
+    decoder::each_implementation_for_type(cdata, def_id.node, callback)
+}
+
+pub fn each_implementation_for_trait(cstore: @mut cstore::CStore,
+                                     def_id: ast::def_id,
+                                     callback: &fn(ast::def_id)) {
+    let cdata = cstore::get_crate_data(cstore, def_id.crate);
+    decoder::each_implementation_for_trait(cdata, def_id.node, callback)
+}
+
+/// If the given def ID describes a method belonging to a trait (either a
+/// default method or an implementation of a trait method), returns the ID of
+/// the trait that the method belongs to. Otherwise, returns `None`.
+pub fn get_trait_of_method(cstore: @mut cstore::CStore,
+                           def_id: ast::def_id,
+                           tcx: ty::ctxt)
+                           -> Option<ast::def_id> {
+    let cdata = cstore::get_crate_data(cstore, def_id.crate);
+    decoder::get_trait_of_method(cdata, def_id.node, tcx)
+}
+
index 9eb09806bc07dc0ea6e12bae27951225772564a3..215f41f3fd647457daf38639ed39f95a1c253119 100644 (file)
 use metadata::tydecode::{parse_ty_data, parse_def_id,
                          parse_type_param_def_data,
                          parse_bare_fn_ty_data, parse_trait_ref_data};
+use middle::ty::{ImplContainer, TraitContainer};
 use middle::ty;
 use middle::typeck;
 use middle::astencode::vtable_decoder_helpers;
 
 
-use std::hash::HashUtil;
-use std::uint;
+use std::u64;
 use std::io::WriterUtil;
 use std::io;
 use std::option;
@@ -39,7 +39,7 @@
 use syntax::attr;
 use syntax::parse::token::{ident_interner, special_idents};
 use syntax::print::pprust;
-use syntax::{ast, ast_util};
+use syntax::ast;
 use syntax::codemap;
 use syntax::parse::token;
 
@@ -207,9 +207,9 @@ fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) -> bool {
     reader::tagged_docs(d, tag_items_data_item_reexport, f)
 }
 
-fn variant_disr_val(d: ebml::Doc) -> Option<uint> {
+fn variant_disr_val(d: ebml::Doc) -> Option<ty::Disr> {
     do reader::maybe_get_doc(d, tag_disr_val).chain |val_doc| {
-        do reader::with_doc_data(val_doc) |data| { uint::parse_bytes(data, 10u) }
+        do reader::with_doc_data(val_doc) |data| { u64::parse_bytes(data, 10u) }
     }
 }
 
@@ -335,15 +335,19 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::CrateNum)
             let purity = if fam == UnsafeStaticMethod { ast::unsafe_fn } else
                 { ast::impure_fn };
             // def_static_method carries an optional field of its enclosing
-            // *trait*, but not an inclosing Impl (if this is an inherent
-            // static method). So we need to detect whether this is in
-            // a trait or not, which we do through the mildly hacky
-            // way of checking whether there is a trait_method_sort.
-            let trait_did_opt = if reader::maybe_get_doc(
+            // trait or enclosing impl (if this is an inherent static method).
+            // So we need to detect whether this is in a trait or not, which
+            // we do through the mildly hacky way of checking whether there is
+            // a trait_method_sort.
+            let provenance = if reader::maybe_get_doc(
                   item, tag_item_trait_method_sort).is_some() {
-                Some(item_reqd_and_translated_parent_item(cnum, item))
-            } else { None };
-            dl_def(ast::def_static_method(did, trait_did_opt, purity))
+                ast::FromTrait(item_reqd_and_translated_parent_item(cnum,
+                                                                    item))
+            } else {
+                ast::FromImpl(item_reqd_and_translated_parent_item(cnum,
+                                                                   item))
+            };
+            dl_def(ast::def_static_method(did, provenance, purity))
         }
         Type | ForeignType => dl_def(ast::def_ty(did)),
         Mod => dl_def(ast::def_mod(did)),
@@ -698,33 +702,164 @@ fn each_child_of_module_or_crate(&mut self, item_doc: ebml::Doc) -> bool {
     }
 }
 
-/// Iterates over all the paths in the given crate.
-pub fn each_path(intr: @ident_interner,
-                 cdata: cmd,
-                 get_crate_data: GetCrateDataCb,
-                 f: &fn(&str, def_like, ast::visibility) -> bool)
-                 -> bool {
-    // FIXME #4572: This function needs to be nuked, as it's impossible to
-    // make fast. It's the source of most of the performance problems when
-    // compiling small crates.
+fn each_child_of_item_or_crate(intr: @ident_interner,
+                               cdata: cmd,
+                               item_doc: ebml::Doc,
+                               get_crate_data: GetCrateDataCb,
+                               callback: &fn(def_like, ast::ident)) {
+    // Iterate over all children.
+    let _ = do reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| {
+        let child_def_id = reader::with_doc_data(child_info_doc,
+                                                 parse_def_id);
+        let child_def_id = translate_def_id(cdata, child_def_id);
+
+        // This item may be in yet another crate if it was the child of a
+        // reexport.
+        let other_crates_items = if child_def_id.crate == cdata.cnum {
+            reader::get_doc(reader::Doc(cdata.data), tag_items)
+        } else {
+            let crate_data = get_crate_data(child_def_id.crate);
+            reader::get_doc(reader::Doc(crate_data.data), tag_items)
+        };
+
+        // Get the item.
+        match maybe_find_item(child_def_id.node, other_crates_items) {
+            None => {}
+            Some(child_item_doc) => {
+                // Hand off the item to the callback.
+                let child_name = item_name(intr, child_item_doc);
+                let def_like = item_to_def_like(child_item_doc,
+                                                child_def_id,
+                                                cdata.cnum);
+                callback(def_like, child_name);
+
+            }
+        }
+
+        true
+    };
+
+    // As a special case, iterate over all static methods of
+    // associated implementations too. This is a bit of a botch.
+    // --pcwalton
+    let _ = do reader::tagged_docs(item_doc,
+                                   tag_items_data_item_inherent_impl)
+            |inherent_impl_def_id_doc| {
+        let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc,
+                                               cdata);
+        let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
+        match maybe_find_item(inherent_impl_def_id.node, items) {
+            None => {}
+            Some(inherent_impl_doc) => {
+                let _ = do reader::tagged_docs(inherent_impl_doc,
+                                               tag_item_impl_method)
+                        |impl_method_def_id_doc| {
+                    let impl_method_def_id =
+                        reader::with_doc_data(impl_method_def_id_doc,
+                                              parse_def_id);
+                    let impl_method_def_id =
+                        translate_def_id(cdata, impl_method_def_id);
+                    match maybe_find_item(impl_method_def_id.node, items) {
+                        None => {}
+                        Some(impl_method_doc) => {
+                            match item_family(impl_method_doc) {
+                                StaticMethod | UnsafeStaticMethod => {
+                                    // Hand off the static method
+                                    // to the callback.
+                                    let static_method_name =
+                                        item_name(intr, impl_method_doc);
+                                    let static_method_def_like =
+                                        item_to_def_like(impl_method_doc,
+                                                         impl_method_def_id,
+                                                         cdata.cnum);
+                                    callback(static_method_def_like,
+                                             static_method_name);
+                                }
+                                _ => {}
+                            }
+                        }
+                    }
+
+                    true
+                };
+            }
+        }
+
+        true
+    };
+
+    // Iterate over all reexports.
+    let _ = do each_reexport(item_doc) |reexport_doc| {
+        let def_id_doc = reader::get_doc(reexport_doc,
+                                         tag_items_data_item_reexport_def_id);
+        let child_def_id = reader::with_doc_data(def_id_doc,
+                                                 parse_def_id);
+        let child_def_id = translate_def_id(cdata, child_def_id);
+
+        let name_doc = reader::get_doc(reexport_doc,
+                                       tag_items_data_item_reexport_name);
+        let name = name_doc.as_str_slice();
+
+        // This reexport may be in yet another crate.
+        let other_crates_items = if child_def_id.crate == cdata.cnum {
+            reader::get_doc(reader::Doc(cdata.data), tag_items)
+        } else {
+            let crate_data = get_crate_data(child_def_id.crate);
+            reader::get_doc(reader::Doc(crate_data.data), tag_items)
+        };
+
+        // Get the item.
+        match maybe_find_item(child_def_id.node, other_crates_items) {
+            None => {}
+            Some(child_item_doc) => {
+                // Hand off the item to the callback.
+                let def_like = item_to_def_like(child_item_doc,
+                                                child_def_id,
+                                                cdata.cnum);
+                callback(def_like, token::str_to_ident(name));
+            }
+        }
+
+        true
+    };
+}
+
+/// Iterates over each child of the given item.
+pub fn each_child_of_item(intr: @ident_interner,
+                          cdata: cmd,
+                          id: ast::NodeId,
+                          get_crate_data: GetCrateDataCb,
+                          callback: &fn(def_like, ast::ident)) {
+    // Find the item.
+    let root_doc = reader::Doc(cdata.data);
+    let items = reader::get_doc(root_doc, tag_items);
+    let item_doc = match maybe_find_item(id, items) {
+        None => return,
+        Some(item_doc) => item_doc,
+    };
 
+    each_child_of_item_or_crate(intr,
+                                cdata,
+                                item_doc,
+                                get_crate_data,
+                                callback)
+}
+
+/// Iterates over all the top-level crate items.
+pub fn each_top_level_item_of_crate(intr: @ident_interner,
+                                    cdata: cmd,
+                                    get_crate_data: GetCrateDataCb,
+                                    callback: &fn(def_like, ast::ident)) {
     let root_doc = reader::Doc(cdata.data);
     let misc_info_doc = reader::get_doc(root_doc, tag_misc_info);
     let crate_items_doc = reader::get_doc(misc_info_doc,
                                           tag_misc_info_crate_items);
 
-    let mut path_builder = ~"";
-
-    let mut context = EachItemContext {
-        intr: intr,
-        cdata: cdata,
-        get_crate_data: get_crate_data,
-        path_builder: &mut path_builder,
-        callback: f,
-    };
-
-    // Iterate over all top-level crate items.
-    context.each_child_of_module_or_crate(crate_items_doc)
+    each_child_of_item_or_crate(intr,
+                                cdata,
+                                crate_items_doc,
+                                get_crate_data,
+                                callback)
 }
 
 pub fn get_item_path(cdata: cmd, id: ast::NodeId) -> ast_map::path {
@@ -804,12 +939,9 @@ pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
 fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ {
     fn get_mutability(ch: u8) -> ast::mutability {
         match ch as char {
-            'i' => { ast::m_imm }
-            'm' => { ast::m_mutbl }
-            'c' => { ast::m_const }
-            _ => {
-                fail!("unknown mutability character: `%c`", ch as char)
-            }
+            'i' => ast::m_imm,
+            'm' => ast::m_mutbl,
+            _ => fail!("unknown mutability character: `%c`", ch as char),
         }
     }
 
@@ -876,8 +1008,15 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
 {
     let method_doc = lookup_item(id, cdata.data);
     let def_id = item_def_id(method_doc, cdata);
+
     let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
                                                             method_doc);
+    let container_doc = lookup_item(container_id.node, cdata.data);
+    let container = match item_family(container_doc) {
+        Trait => TraitContainer(container_id),
+        _ => ImplContainer(container_id),
+    };
+
     let name = item_name(intr, method_doc);
     let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
                                              tag_item_method_tps);
@@ -898,7 +1037,7 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
         explicit_self,
         vis,
         def_id,
-        container_id,
+        container,
         provided_source
     )
 }
@@ -1267,21 +1406,6 @@ pub fn get_crate_vers(data: @~[u8]) -> @str {
     }
 }
 
-fn iter_crate_items(intr: @ident_interner, cdata: cmd,
-                    get_crate_data: GetCrateDataCb,
-                    proc: &fn(path: &str, ast::def_id)) {
-    do each_path(intr, cdata, get_crate_data) |path_string, def_like, _| {
-        match def_like {
-            dl_impl(*) | dl_field => {}
-            dl_def(def) => {
-                proc(path_string,
-                     ast_util::def_id_of_def(def))
-            }
-        }
-        true
-    };
-}
-
 pub fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8],
                            out: @io::Writer) {
     let hash = get_crate_hash(bytes);
@@ -1315,3 +1439,59 @@ pub fn get_link_args_for_crate(cdata: cmd) -> ~[~str] {
     };
     result
 }
+
+pub fn each_impl(cdata: cmd, callback: &fn(ast::def_id)) {
+    let impls_doc = reader::get_doc(reader::Doc(cdata.data), tag_impls);
+    let _ = do reader::tagged_docs(impls_doc, tag_impls_impl) |impl_doc| {
+        callback(item_def_id(impl_doc, cdata));
+        true
+    };
+}
+
+pub fn each_implementation_for_type(cdata: cmd,
+                                    id: ast::NodeId,
+                                    callback: &fn(ast::def_id)) {
+    let item_doc = lookup_item(id, cdata.data);
+    do reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl)
+            |impl_doc| {
+        let implementation_def_id = item_def_id(impl_doc, cdata);
+        callback(implementation_def_id);
+        true
+    };
+}
+
+pub fn each_implementation_for_trait(cdata: cmd,
+                                     id: ast::NodeId,
+                                     callback: &fn(ast::def_id)) {
+    let item_doc = lookup_item(id, cdata.data);
+
+    let _ = do reader::tagged_docs(item_doc,
+                                   tag_items_data_item_extension_impl)
+            |impl_doc| {
+        let implementation_def_id = item_def_id(impl_doc, cdata);
+        callback(implementation_def_id);
+        true
+    };
+}
+
+pub fn get_trait_of_method(cdata: cmd, id: ast::NodeId, tcx: ty::ctxt)
+                           -> Option<ast::def_id> {
+    let item_doc = lookup_item(id, cdata.data);
+    let parent_item_id = match item_parent_item(item_doc) {
+        None => return None,
+        Some(item_id) => item_id,
+    };
+    let parent_item_id = translate_def_id(cdata, parent_item_id);
+    let parent_item_doc = lookup_item(parent_item_id.node, cdata.data);
+    match item_family(parent_item_doc) {
+        Trait => Some(item_def_id(parent_item_doc, cdata)),
+        Impl => {
+            do reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref).map
+                    |_| {
+                item_trait_ref(parent_item_doc, tcx, cdata).def_id
+            }
+        }
+        _ => None
+    }
+}
+
index dbed508348d03297de14364ec2e9316a6f854fda..aad9dd33d8df03a16230f1e9a21534d852b180c3 100644 (file)
@@ -21,7 +21,6 @@
 use middle::astencode;
 use middle;
 
-use std::hash::HashUtil;
 use std::hashmap::{HashMap, HashSet};
 use std::io;
 use std::str;
@@ -39,6 +38,7 @@
 use syntax::diagnostic::span_handler;
 use syntax::parse::token::special_idents;
 use syntax::ast_util;
+use syntax::visit::Visitor;
 use syntax::visit;
 use syntax::parse::token;
 use syntax;
@@ -72,6 +72,7 @@ struct Stats {
     dep_bytes: uint,
     lang_item_bytes: uint,
     link_args_bytes: uint,
+    impl_bytes: uint,
     misc_bytes: uint,
     item_bytes: uint,
     index_bytes: uint,
@@ -292,7 +293,7 @@ fn encode_symbol(ecx: &EncodeContext,
 
 fn encode_disr_val(_: &EncodeContext,
                    ebml_w: &mut writer::Encoder,
-                   disr_val: uint) {
+                   disr_val: ty::Disr) {
     ebml_w.start_tag(tag_disr_val);
     let s = disr_val.to_str();
     ebml_w.writer.write(s.as_bytes());
@@ -511,8 +512,12 @@ fn encode_reexports(ecx: &EncodeContext,
         Some(ref exports) => {
             debug!("(encoding info for module) found reexports for %d", id);
             for exp in exports.iter() {
-                debug!("(encoding info for module) reexport '%s' for %d",
-                       exp.name, id);
+                debug!("(encoding info for module) reexport '%s' (%d/%d) for \
+                        %d",
+                       exp.name,
+                       exp.def_id.crate,
+                       exp.def_id.node,
+                       id);
                 ebml_w.start_tag(tag_items_data_item_reexport);
                 ebml_w.start_tag(tag_items_data_item_reexport_def_id);
                 ebml_w.wr_str(def_to_str(exp.def_id));
@@ -635,15 +640,8 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic
     fn encode_mutability(ebml_w: &writer::Encoder,
                          m: ast::mutability) {
         match m {
-            m_imm => {
-                ebml_w.writer.write(&[ 'i' as u8 ]);
-            }
-            m_mutbl => {
-                ebml_w.writer.write(&[ 'm' as u8 ]);
-            }
-            m_const => {
-                ebml_w.writer.write(&[ 'c' as u8 ]);
-            }
+            m_imm => ebml_w.writer.write(&[ 'i' as u8 ]),
+            m_mutbl => ebml_w.writer.write(&[ 'm' as u8 ]),
         }
     }
 }
@@ -804,6 +802,38 @@ fn should_inline(attrs: &[Attribute]) -> bool {
     }
 }
 
+// Encodes the inherent implementations of a structure, enumeration, or trait.
+fn encode_inherent_implementations(ecx: &EncodeContext,
+                                   ebml_w: &mut writer::Encoder,
+                                   def_id: def_id) {
+    match ecx.tcx.inherent_impls.find(&def_id) {
+        None => {}
+        Some(&implementations) => {
+            for implementation in implementations.iter() {
+                ebml_w.start_tag(tag_items_data_item_inherent_impl);
+                encode_def_id(ebml_w, implementation.did);
+                ebml_w.end_tag();
+            }
+        }
+    }
+}
+
+// Encodes the implementations of a trait defined in this crate.
+fn encode_extension_implementations(ecx: &EncodeContext,
+                                    ebml_w: &mut writer::Encoder,
+                                    trait_def_id: def_id) {
+    match ecx.tcx.trait_impls.find(&trait_def_id) {
+        None => {}
+        Some(&implementations) => {
+            for implementation in implementations.iter() {
+                ebml_w.start_tag(tag_items_data_item_extension_impl);
+                encode_def_id(ebml_w, implementation.did);
+                ebml_w.end_tag();
+            }
+        }
+    }
+}
+
 fn encode_info_for_item(ecx: &EncodeContext,
                         ebml_w: &mut writer::Encoder,
                         item: @item,
@@ -907,6 +937,10 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
         (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
         encode_region_param(ecx, ebml_w, item);
+
+        // Encode inherent implementations for this enumeration.
+        encode_inherent_implementations(ecx, ebml_w, def_id);
+
         ebml_w.end_tag();
 
         encode_enum_variant_info(ecx,
@@ -959,6 +993,9 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
             }
         }
 
+        // Encode inherent implementations for this structure.
+        encode_inherent_implementations(ecx, ebml_w, def_id);
+
         /* Each class has its own index -- encode it */
         let bkts = create_index(idx);
         encode_index(ebml_w, bkts, write_i64);
@@ -995,7 +1032,8 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
         encode_name(ecx, ebml_w, item.ident);
         encode_attributes(ebml_w, item.attrs);
         match ty.node {
-            ast::ty_path(ref path, ref bounds, _) if path.idents.len() == 1 => {
+            ast::ty_path(ref path, ref bounds, _) if path.segments
+                                                         .len() == 1 => {
                 assert!(bounds.is_none());
                 encode_impl_type_basename(ecx, ebml_w,
                                           ast_util::path_to_ident(path));
@@ -1073,6 +1111,10 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
             let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
             encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref);
         }
+
+        // Encode the implementations of this trait.
+        encode_extension_implementations(ecx, ebml_w, def_id);
+
         ebml_w.end_tag();
 
         // Now output the method info for each method.
@@ -1134,6 +1176,9 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
 
             ebml_w.end_tag();
         }
+
+        // Encode inherent implementations for this trait.
+        encode_inherent_implementations(ecx, ebml_w, def_id);
       }
       item_mac(*) => fail!("item macros unimplemented")
     }
@@ -1227,7 +1272,10 @@ struct EncodeVisitor {
 }
 
 impl visit::Visitor<()> for EncodeVisitor {
-    fn visit_expr(&mut self, ex:@expr, _:()) { my_visit_expr(ex); }
+    fn visit_expr(&mut self, ex:@expr, _:()) {
+        visit::walk_expr(self, ex, ());
+        my_visit_expr(ex);
+    }
     fn visit_item(&mut self, i:@item, _:()) {
         visit::walk_item(self, i, ());
         my_visit_item(i,
@@ -1516,6 +1564,60 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) {
     ebml_w.end_tag();
 }
 
+struct ImplVisitor<'self> {
+    ecx: &'self EncodeContext<'self>,
+    ebml_w: &'self mut writer::Encoder,
+}
+
+impl<'self> Visitor<()> for ImplVisitor<'self> {
+    fn visit_item(&mut self, item: @item, _: ()) {
+        match item.node {
+            item_impl(_, Some(ref trait_ref), _, _) => {
+                let def_map = self.ecx.tcx.def_map;
+                let trait_def = def_map.get_copy(&trait_ref.ref_id);
+                let def_id = ast_util::def_id_of_def(trait_def);
+
+                // Load eagerly if this is an implementation of the Drop trait
+                // or if the trait is not defined in this crate.
+                if def_id == self.ecx.tcx.lang_items.drop_trait().unwrap() ||
+                        def_id.crate != LOCAL_CRATE {
+                    self.ebml_w.start_tag(tag_impls_impl);
+                    encode_def_id(self.ebml_w, local_def(item.id));
+                    self.ebml_w.end_tag();
+                }
+            }
+            _ => {}
+        }
+        visit::walk_item(self, item, ());
+    }
+}
+
+/// Encodes implementations that are eagerly loaded.
+///
+/// None of this is necessary in theory; we can load all implementations
+/// lazily. However, in two cases the optimizations to lazily load
+/// implementations are not yet implemented. These two cases, which require us
+/// to load implementations eagerly, are:
+///
+/// * Destructors (implementations of the Drop trait).
+///
+/// * Implementations of traits not defined in this crate.
+fn encode_impls(ecx: &EncodeContext,
+                crate: &Crate,
+                ebml_w: &mut writer::Encoder) {
+    ebml_w.start_tag(tag_impls);
+
+    {
+        let mut visitor = ImplVisitor {
+            ecx: ecx,
+            ebml_w: ebml_w,
+        };
+        visit::walk_crate(&mut visitor, crate, ());
+    }
+
+    ebml_w.end_tag();
+}
+
 fn encode_misc_info(ecx: &EncodeContext,
                     crate: &Crate,
                     ebml_w: &mut writer::Encoder) {
@@ -1580,6 +1682,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         dep_bytes: 0,
         lang_item_bytes: 0,
         link_args_bytes: 0,
+        impl_bytes: 0,
         misc_bytes: 0,
         item_bytes: 0,
         index_bytes: 0,
@@ -1638,6 +1741,11 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
     encode_link_args(&ecx, &mut ebml_w);
     ecx.stats.link_args_bytes = *wr.pos - i;
 
+    // Encode the def IDs of impls, for coherence checking.
+    i = *wr.pos;
+    encode_impls(&ecx, crate, &mut ebml_w);
+    ecx.stats.impl_bytes = *wr.pos - i;
+
     // Encode miscellaneous info.
     i = *wr.pos;
     encode_misc_info(&ecx, crate, &mut ebml_w);
@@ -1670,6 +1778,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         printfln!("       dep bytes: %u", ecx.stats.dep_bytes);
         printfln!(" lang item bytes: %u", ecx.stats.lang_item_bytes);
         printfln!(" link args bytes: %u", ecx.stats.link_args_bytes);
+        printfln!("      impl bytes: %u", ecx.stats.impl_bytes);
         printfln!("      misc bytes: %u", ecx.stats.misc_bytes);
         printfln!("      item bytes: %u", ecx.stats.item_bytes);
         printfln!("     index bytes: %u", ecx.stats.index_bytes);
index 33d517f3981bb4f2f03d67b8a3ca7238311a83af..757c53354a24f20f1d05d9e9475f60e0a80115ae 100644 (file)
 use std::os;
 use std::hashmap::HashSet;
 
+pub enum FileMatch { FileMatches, FileDoesntMatch }
+
 // A module for searching for libraries
 // FIXME (#2658): I'm not happy how this module turned out. Should
 // probably just be folded into cstore.
 
 /// Functions with type `pick` take a parent directory as well as
 /// a file found in that directory.
-pub type pick<'self, T> = &'self fn(path: &Path) -> Option<T>;
+pub type pick<'self> = &'self fn(path: &Path) -> FileMatch;
 
 pub fn pick_file(file: Path, path: &Path) -> Option<Path> {
     if path.file_path() == file {
@@ -31,7 +33,7 @@ pub fn pick_file(file: Path, path: &Path) -> Option<Path> {
 
 pub trait FileSearch {
     fn sysroot(&self) -> @Path;
-    fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool;
+    fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch);
     fn get_target_lib_path(&self) -> Path;
     fn get_target_lib_file_path(&self, file: &Path) -> Path;
 }
@@ -47,13 +49,17 @@ struct FileSearchImpl {
     }
     impl FileSearch for FileSearchImpl {
         fn sysroot(&self) -> @Path { self.sysroot }
-        fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool {
+        fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch) {
             let mut visited_dirs = HashSet::new();
+            let mut found = false;
 
             debug!("filesearch: searching additional lib search paths [%?]",
                    self.addl_lib_search_paths.len());
             for path in self.addl_lib_search_paths.iter() {
-                f(path);
+                match f(path) {
+                    FileMatches => found = true,
+                    FileDoesntMatch => ()
+                }
                 visited_dirs.insert(path.to_str());
             }
 
@@ -61,20 +67,33 @@ fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool {
             let tlib_path = make_target_lib_path(self.sysroot,
                                         self.target_triple);
             if !visited_dirs.contains(&tlib_path.to_str()) {
-                if !f(&tlib_path) {
-                    return false;
+                match f(&tlib_path) {
+                    FileMatches => found = true,
+                    FileDoesntMatch => ()
                 }
             }
             visited_dirs.insert(tlib_path.to_str());
             // Try RUST_PATH
-            let rustpath = rust_path();
-            for path in rustpath.iter() {
+            if !found {
+                let rustpath = rust_path();
+                for path in rustpath.iter() {
+                    debug!("is %s in visited_dirs? %?",
+                            path.push("lib").to_str(),
+                            visited_dirs.contains(&path.push("lib").to_str()));
+
                     if !visited_dirs.contains(&path.push("lib").to_str()) {
-                        f(&path.push("lib"));
                         visited_dirs.insert(path.push("lib").to_str());
+                        // Don't keep searching the RUST_PATH if one match turns up --
+                        // if we did, we'd get a "multiple matching crates" error
+                        match f(&path.push("lib")) {
+                           FileMatches => {
+                               break;
+                           }
+                           FileDoesntMatch => ()
+                        }
                     }
+                }
             }
-            true
         }
         fn get_target_lib_path(&self) -> Path {
             make_target_lib_path(self.sysroot, self.target_triple)
@@ -93,28 +112,26 @@ fn get_target_lib_file_path(&self, file: &Path) -> Path {
     } as @FileSearch
 }
 
-pub fn search<T>(filesearch: @FileSearch, pick: pick<T>) -> Option<T> {
-    let mut rslt = None;
+pub fn search(filesearch: @FileSearch, pick: pick) {
     do filesearch.for_each_lib_search_path() |lib_search_path| {
         debug!("searching %s", lib_search_path.to_str());
         let r = os::list_dir_path(lib_search_path);
+        let mut rslt = FileDoesntMatch;
         for path in r.iter() {
             debug!("testing %s", path.to_str());
             let maybe_picked = pick(path);
             match maybe_picked {
-                Some(_) => {
+                FileMatches => {
                     debug!("picked %s", path.to_str());
-                    rslt = maybe_picked;
-                    break;
+                    rslt = FileMatches;
                 }
-                None => {
+                FileDoesntMatch => {
                     debug!("rejected %s", path.to_str());
                 }
             }
         }
-        rslt.is_none()
+        rslt
     };
-    return rslt;
 }
 
 pub fn relative_target_lib_path(target_triple: &str) -> Path {
index d0060931a6607eca54c753346ff492fbf8146d20..fbf6e3fcff8a70820a55e8f89cf9a168ce02dc17 100644 (file)
@@ -14,7 +14,7 @@
 use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
 use metadata::decoder;
 use metadata::encoder;
-use metadata::filesearch::FileSearch;
+use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch};
 use metadata::filesearch;
 use syntax::codemap::span;
 use syntax::diagnostic::span_handler;
@@ -92,10 +92,10 @@ fn find_library_crate_aux(
     // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
     let prefix = fmt!("%s%s-", prefix, crate_name);
     let mut matches = ~[];
-    filesearch::search(filesearch, |path| -> Option<()> {
+    filesearch::search(filesearch, |path| -> FileMatch {
       let path_str = path.filename();
       match path_str {
-          None => None,
+          None => FileDoesntMatch,
           Some(path_str) =>
               if path_str.starts_with(prefix) && path_str.ends_with(suffix) {
                   debug!("%s is a candidate", path.to_str());
@@ -104,20 +104,20 @@ fn find_library_crate_aux(
                           if !crate_matches(cvec, cx.metas, cx.hash) {
                               debug!("skipping %s, metadata doesn't match",
                                   path.to_str());
-                              None
+                              FileDoesntMatch
                           } else {
                               debug!("found %s with matching metadata", path.to_str());
                               matches.push((path.to_str(), cvec));
-                              None
+                              FileMatches
                           },
                       _ => {
                           debug!("could not load metadata for %s", path.to_str());
-                          None
+                          FileDoesntMatch
                       }
                   }
                }
                else {
-                   None
+                   FileDoesntMatch
                }
       }
     });
index 89b30e46ac06d1a5f00c5ad70ea507db90ccd216..f5bad88b1ca66eb3a7df4927c3b25247ca7f1e31 100644 (file)
@@ -138,12 +138,20 @@ fn parse_path(st: &mut PState) -> @ast::Path {
           ':' => { next(st); next(st); }
           c => {
             if c == '(' {
-                return @ast::Path { span: dummy_sp(),
-                                    global: false,
-                                    idents: idents,
-                                    rp: None,
-                                    types: ~[] };
-            } else { idents.push(parse_ident_(st, is_last)); }
+                return @ast::Path {
+                    span: dummy_sp(),
+                    global: false,
+                    segments: idents.move_iter().map(|identifier| {
+                        ast::PathSegment {
+                            identifier: identifier,
+                            lifetime: None,
+                            types: opt_vec::Empty,
+                        }
+                    }).collect()
+                };
+            } else {
+                idents.push(parse_ident_(st, is_last));
+            }
           }
         }
     };
@@ -417,7 +425,6 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
 fn parse_mutability(st: &mut PState) -> ast::mutability {
     match peek(st) {
       'm' => { next(st); ast::m_mutbl }
-      '?' => { next(st); ast::m_const }
       _ => { ast::m_imm }
     }
 }
index 5611808cc6d982225d6a7357f667633ea266b104..d00928dd3db74232da80f73a8df73150f12d41ab 100644 (file)
@@ -99,7 +99,6 @@ fn enc_mutability(w: @io::Writer, mt: ast::mutability) {
     match mt {
       m_imm => (),
       m_mutbl => w.write_char('m'),
-      m_const => w.write_char('?')
     }
 }
 
index a22daac90b5517e7c30fb48ef77850a7f6cb54a3..d6b22381192d26c676aabf5a61149cf8ada94fd8 100644 (file)
@@ -374,16 +374,23 @@ impl tr for ast::def {
     fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def {
         match *self {
           ast::def_fn(did, p) => ast::def_fn(did.tr(xcx), p),
-          ast::def_static_method(did, did2_opt, p) => {
+          ast::def_static_method(did, wrapped_did2, p) => {
             ast::def_static_method(did.tr(xcx),
-                                   did2_opt.map(|did2| did2.tr(xcx)),
+                                   match wrapped_did2 {
+                                    ast::FromTrait(did2) => {
+                                        ast::FromTrait(did2.tr(xcx))
+                                    }
+                                    ast::FromImpl(did2) => {
+                                        ast::FromImpl(did2.tr(xcx))
+                                    }
+                                   },
                                    p)
           }
           ast::def_method(did0, did1) => {
             ast::def_method(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
           }
           ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) }
-          ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
+          ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
           ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
           ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
           ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) }
index 0fa7750afa7aadc2367740dc6f6fa2190ef687ee..485a0aefe98294e5128dfc07406b59616da33617 100644 (file)
 use middle::borrowck::*;
 use middle::moves;
 use middle::ty;
-use syntax::ast::{m_mutbl, m_imm, m_const};
+use syntax::ast::{m_imm, m_mutbl};
 use syntax::ast;
 use syntax::ast_util;
 use syntax::codemap::span;
-use syntax::visit;
 use syntax::visit::Visitor;
+use syntax::visit;
 use util::ppaux::Repr;
 
 #[deriving(Clone)]
@@ -86,6 +86,44 @@ enum MoveError {
 }
 
 impl<'self> CheckLoanCtxt<'self> {
+    fn check_by_move_capture(&self,
+                             closure_id: ast::NodeId,
+                             cap_var: &moves::CaptureVar,
+                             move_path: @LoanPath) {
+        let move_err = self.analyze_move_out_from(closure_id, move_path);
+        match move_err {
+            MoveOk => {}
+            MoveWhileBorrowed(loan_path, loan_span) => {
+                self.bccx.span_err(
+                    cap_var.span,
+                    fmt!("cannot move `%s` into closure \
+                          because it is borrowed",
+                         self.bccx.loan_path_to_str(move_path)));
+                self.bccx.span_note(
+                    loan_span,
+                    fmt!("borrow of `%s` occurs here",
+                         self.bccx.loan_path_to_str(loan_path)));
+            }
+        }
+    }
+
+    fn check_captured_variables(&self, closure_id: ast::NodeId, span: span) {
+        let cap_vars = self.bccx.capture_map.get(&closure_id);
+        for cap_var in cap_vars.iter() {
+            let var_id = ast_util::def_id_of_def(cap_var.def).node;
+            let var_path = @LpVar(var_id);
+            self.check_if_path_is_moved(closure_id, span,
+                                        MovedInCapture, var_path);
+            match cap_var.mode {
+                moves::CapRef | moves::CapCopy => {}
+                moves::CapMove => {
+                    self.check_by_move_capture(closure_id, cap_var, var_path);
+                }
+            }
+        }
+        return;
+    }
+
     pub fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
 
     pub fn each_issued_loan(&self,
@@ -220,9 +258,9 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self,
 
         // Restrictions that would cause the new loan to be illegal:
         let illegal_if = match loan2.mutbl {
-            m_mutbl => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM,
-            m_imm =>   RESTR_ALIAS | RESTR_FREEZE,
-            m_const => RESTR_ALIAS,
+            MutableMutability   => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM,
+            ImmutableMutability => RESTR_ALIAS | RESTR_FREEZE,
+            ConstMutability     => RESTR_ALIAS,
         };
         debug!("illegal_if=%?", illegal_if);
 
@@ -231,7 +269,7 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self,
             if restr.loan_path != loan2.loan_path { loop; }
 
             match (new_loan.mutbl, old_loan.mutbl) {
-                (m_mutbl, m_mutbl) => {
+                (MutableMutability, MutableMutability) => {
                     self.bccx.span_err(
                         new_loan.span,
                         fmt!("cannot borrow `%s` as mutable \
@@ -367,7 +405,6 @@ fn mark_variable_as_used_mut(this: &CheckLoanCtxt,
 
                     mc::cat_rvalue(*) |
                     mc::cat_static_item |
-                    mc::cat_implicit_self |
                     mc::cat_copied_upvar(*) |
                     mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
                     mc::cat_deref(_, _, mc::gc_ptr(*)) |
@@ -406,15 +443,7 @@ fn check_for_aliasable_mutable_writes(this: &CheckLoanCtxt,
                 mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => {
                     // Statically prohibit writes to `&mut` when aliasable
 
-                    match b.freely_aliasable() {
-                        None => {}
-                        Some(cause) => {
-                            this.bccx.report_aliasability_violation(
-                                expr.span,
-                                MutabilityViolation,
-                                cause);
-                        }
-                    }
+                    check_for_aliasability_violation(this, expr, b);
                 }
 
                 mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => {
@@ -434,6 +463,50 @@ fn check_for_aliasable_mutable_writes(this: &CheckLoanCtxt,
             return true; // no errors reported
         }
 
+        fn check_for_aliasability_violation(this: &CheckLoanCtxt,
+                                            expr: @ast::expr,
+                                            cmt: mc::cmt) -> bool {
+            let mut cmt = cmt;
+
+            loop {
+                match cmt.cat {
+                    mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) |
+                    mc::cat_downcast(b) |
+                    mc::cat_stack_upvar(b) |
+                    mc::cat_deref(b, _, mc::uniq_ptr) |
+                    mc::cat_interior(b, _) |
+                    mc::cat_discr(b, _) => {
+                        // Aliasability depends on base cmt
+                        cmt = b;
+                    }
+
+                    mc::cat_copied_upvar(_) |
+                    mc::cat_rvalue(*) |
+                    mc::cat_local(*) |
+                    mc::cat_arg(_) |
+                    mc::cat_self(*) |
+                    mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
+                    mc::cat_static_item(*) |
+                    mc::cat_deref(_, _, mc::gc_ptr(_)) |
+                    mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) => {
+                        // Aliasability is independent of base cmt
+                        match cmt.freely_aliasable() {
+                            None => {
+                                return true;
+                            }
+                            Some(cause) => {
+                                this.bccx.report_aliasability_violation(
+                                    expr.span,
+                                    MutabilityViolation,
+                                    cause);
+                                return false;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
         fn check_for_assignment_to_restricted_or_frozen_location(
             this: &CheckLoanCtxt,
             expr: @ast::expr,
@@ -511,6 +584,12 @@ fn check_for_assignment_to_restricted_or_frozen_location(
             // path, and check that the super path was not lent out as
             // mutable or immutable (a const loan is ok).
             //
+            // Mutability of a path can be dependent on the super path
+            // in two ways. First, it might be inherited mutability.
+            // Second, the pointee of an `&mut` pointer can only be
+            // mutated if it is found in an unaliased location, so we
+            // have to check that the owner location is not borrowed.
+            //
             // Note that we are *not* checking for any and all
             // restrictions.  We are only interested in the pointers
             // that the user created, whereas we add restrictions for
@@ -528,16 +607,18 @@ fn check_for_assignment_to_restricted_or_frozen_location(
             let mut loan_path = loan_path;
             loop {
                 match *loan_path {
-                    // Peel back one layer if `loan_path` has
-                    // inherited mutability
-                    LpExtend(lp_base, mc::McInherited, _) => {
+                    // Peel back one layer if, for `loan_path` to be
+                    // mutable, `lp_base` must be mutable. This occurs
+                    // with inherited mutability and with `&mut`
+                    // pointers.
+                    LpExtend(lp_base, mc::McInherited, _) |
+                    LpExtend(lp_base, _, LpDeref(mc::region_ptr(ast::m_mutbl, _))) => {
                         loan_path = lp_base;
                     }
 
                     // Otherwise stop iterating
                     LpExtend(_, mc::McDeclared, _) |
                     LpExtend(_, mc::McImmutable, _) |
-                    LpExtend(_, mc::McReadOnly, _) |
                     LpVar(_) => {
                         return true;
                     }
@@ -545,8 +626,11 @@ fn check_for_assignment_to_restricted_or_frozen_location(
 
                 // Check for a non-const loan of `loan_path`
                 let cont = do this.each_in_scope_loan(expr.id) |loan| {
-                    if loan.loan_path == loan_path && loan.mutbl != m_const {
-                        this.report_illegal_mutation(expr, full_loan_path, loan);
+                    if loan.loan_path == loan_path &&
+                            loan.mutbl != ConstMutability {
+                        this.report_illegal_mutation(expr,
+                                                     full_loan_path,
+                                                     loan);
                         false
                     } else {
                         true
@@ -780,3 +864,4 @@ fn check_loans_in_block<'a>(vt: &mut CheckLoanVisitor,
     visit::walk_block(vt, blk, this);
     this.check_for_conflicting_loans(blk.id);
 }
+
index 24a6e5b6e0b2b230cf4c5348c24466fa3e2606a7..d6f9d1db7df8830220d1b321f8366b2c63638709 100644 (file)
@@ -100,7 +100,6 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt,
                                cmt0: mc::cmt,
                                cmt: mc::cmt) -> bool {
     match cmt.cat {
-        mc::cat_implicit_self(*) |
         mc::cat_deref(_, _, mc::region_ptr(*)) |
         mc::cat_deref(_, _, mc::gc_ptr(*)) |
         mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
index b315a7a2e72908a677671cd90f6492f79cc1f295..e76d11c269b2b21461c489aae232ca14135a8b77 100644 (file)
@@ -15,7 +15,7 @@
 use middle::borrowck::*;
 use mc = middle::mem_categorization;
 use middle::ty;
-use syntax::ast::{m_const, m_imm, m_mutbl};
+use syntax::ast::{m_imm, m_mutbl};
 use syntax::ast;
 use syntax::codemap::span;
 use util::ppaux::{note_and_explain_region};
@@ -26,7 +26,7 @@ pub fn guarantee_lifetime(bccx: @BorrowckCtxt,
                           span: span,
                           cmt: mc::cmt,
                           loan_region: ty::Region,
-                          loan_mutbl: ast::mutability) {
+                          loan_mutbl: LoanMutability) {
     debug!("guarantee_lifetime(cmt=%s, loan_region=%s)",
            cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
     let ctxt = GuaranteeLifetimeContext {bccx: bccx,
@@ -54,7 +54,7 @@ struct GuaranteeLifetimeContext {
 
     span: span,
     loan_region: ty::Region,
-    loan_mutbl: ast::mutability,
+    loan_mutbl: LoanMutability,
     cmt_original: mc::cmt
 }
 
@@ -68,7 +68,6 @@ fn check(&self, cmt: mc::cmt, discr_scope: Option<ast::NodeId>) {
 
         match cmt.cat {
             mc::cat_rvalue(*) |
-            mc::cat_implicit_self |
             mc::cat_copied_upvar(*) |                  // L-Local
             mc::cat_local(*) |                         // L-Local
             mc::cat_arg(*) |                           // L-Local
@@ -236,11 +235,11 @@ fn check_root(&self,
         // we need to dynamically mark it to prevent incompatible
         // borrows from happening later.
         let opt_dyna = match ptr_mutbl {
-            m_imm | m_const => None,
+            m_imm => None,
             m_mutbl => {
                 match self.loan_mutbl {
-                    m_mutbl => Some(DynaMut),
-                    m_imm | m_const => Some(DynaImm)
+                    MutableMutability => Some(DynaMut),
+                    ImmutableMutability | ConstMutability => Some(DynaImm)
                 }
             }
         };
@@ -301,7 +300,6 @@ fn is_moved(&self, cmt: mc::cmt) -> bool {
             }
             mc::cat_rvalue(*) |
             mc::cat_static_item |
-            mc::cat_implicit_self |
             mc::cat_copied_upvar(*) |
             mc::cat_deref(*) => {
                 false
@@ -328,7 +326,6 @@ fn scope(&self, cmt: mc::cmt) -> ty::Region {
             mc::cat_rvalue(cleanup_scope_id) => {
                 ty::re_scope(cleanup_scope_id)
             }
-            mc::cat_implicit_self |
             mc::cat_copied_upvar(_) => {
                 ty::re_scope(self.item_scope_id)
             }
index 6d2a4fcc9f31a8498afdc4ca9dd59ad1cdf11b87..dbe5214e0eb50013cfc0873f239a4ccaabc18345 100644 (file)
@@ -26,7 +26,6 @@
 use util::common::indenter;
 use util::ppaux::{Repr};
 
-use syntax::ast::{m_const, m_imm, m_mutbl};
 use syntax::ast;
 use syntax::ast_util::id_range;
 use syntax::codemap::span;
@@ -237,7 +236,11 @@ fn gather_loans_in_expr(v: &mut GatherLoanVisitor,
         // make sure that the thing we are pointing out stays valid
         // for the lifetime `scope_r` of the resulting ptr:
         let scope_r = ty_region(tcx, ex.span, ty::expr_ty(tcx, ex));
-        this.guarantee_valid(ex.id, ex.span, base_cmt, mutbl, scope_r);
+        this.guarantee_valid(ex.id,
+                             ex.span,
+                             base_cmt,
+                             LoanMutability::from_ast_mutability(mutbl),
+                             scope_r);
         visit::walk_expr(v, ex, this);
       }
 
@@ -278,7 +281,11 @@ fn gather_loans_in_expr(v: &mut GatherLoanVisitor,
           // adjustments).
           let scope_r = ty::re_scope(ex.id);
           let arg_cmt = this.bccx.cat_expr(arg);
-          this.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r);
+          this.guarantee_valid(arg.id,
+                               arg.span,
+                               arg_cmt,
+                               ImmutableMutability,
+                               scope_r);
           visit::walk_expr(v, ex, this);
       }
 
@@ -357,18 +364,22 @@ pub fn guarantee_adjustments(&mut self,
 
                 match *autoref {
                     ty::AutoPtr(r, m) => {
+                        let loan_mutability =
+                            LoanMutability::from_ast_mutability(m);
                         self.guarantee_valid(expr.id,
                                              expr.span,
                                              cmt,
-                                             m,
+                                             loan_mutability,
                                              r)
                     }
                     ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
                         let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1);
+                        let loan_mutability =
+                            LoanMutability::from_ast_mutability(m);
                         self.guarantee_valid(expr.id,
                                              expr.span,
                                              cmt_index,
-                                             m,
+                                             loan_mutability,
                                              r)
                     }
                     ty::AutoBorrowFn(r) => {
@@ -376,15 +387,17 @@ pub fn guarantee_adjustments(&mut self,
                         self.guarantee_valid(expr.id,
                                              expr.span,
                                              cmt_deref,
-                                             m_imm,
+                                             ImmutableMutability,
                                              r)
                     }
                     ty::AutoBorrowObj(r, m) => {
                         let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0);
+                        let loan_mutability =
+                            LoanMutability::from_ast_mutability(m);
                         self.guarantee_valid(expr.id,
                                              expr.span,
                                              cmt_deref,
-                                             m,
+                                             loan_mutability,
                                              r)
                     }
                     ty::AutoUnsafe(_) => {}
@@ -402,7 +415,7 @@ pub fn guarantee_valid(&mut self,
                            borrow_id: ast::NodeId,
                            borrow_span: span,
                            cmt: mc::cmt,
-                           req_mutbl: ast::mutability,
+                           req_mutbl: LoanMutability,
                            loan_region: ty::Region) {
         debug!("guarantee_valid(borrow_id=%?, cmt=%s, \
                 req_mutbl=%?, loan_region=%?)",
@@ -473,7 +486,7 @@ pub fn guarantee_valid(&mut self,
                 let kill_scope = self.compute_kill_scope(loan_scope, loan_path);
                 debug!("kill_scope = %?", kill_scope);
 
-                if req_mutbl == m_mutbl {
+                if req_mutbl == MutableMutability {
                     self.mark_loan_path_as_mutated(loan_path);
                 }
 
@@ -516,7 +529,7 @@ pub fn guarantee_valid(&mut self,
             //        index: all_loans.len(),
             //        loan_path: loan_path,
             //        cmt: cmt,
-            //        mutbl: m_const,
+            //        mutbl: ConstMutability,
             //        gen_scope: borrow_id,
             //        kill_scope: kill_scope,
             //        span: borrow_span,
@@ -527,29 +540,20 @@ pub fn guarantee_valid(&mut self,
         fn check_mutability(bccx: @BorrowckCtxt,
                             borrow_span: span,
                             cmt: mc::cmt,
-                            req_mutbl: ast::mutability) {
+                            req_mutbl: LoanMutability) {
             //! Implements the M-* rules in doc.rs.
 
             match req_mutbl {
-                m_const => {
+                ConstMutability => {
                     // Data of any mutability can be lent as const.
                 }
 
-                m_imm => {
-                    match cmt.mutbl {
-                        mc::McImmutable | mc::McDeclared | mc::McInherited => {
-                            // both imm and mut data can be lent as imm;
-                            // for mutable data, this is a freeze
-                        }
-                        mc::McReadOnly => {
-                            bccx.report(BckError {span: borrow_span,
-                                                  cmt: cmt,
-                                                  code: err_mutbl(req_mutbl)});
-                        }
-                    }
+                ImmutableMutability => {
+                    // both imm and mut data can be lent as imm;
+                    // for mutable data, this is a freeze
                 }
 
-                m_mutbl => {
+                MutableMutability => {
                     // Only mutable data can be lent as mutable.
                     if !cmt.mutbl.is_mutable() {
                         bccx.report(BckError {span: borrow_span,
@@ -561,12 +565,14 @@ fn check_mutability(bccx: @BorrowckCtxt,
         }
     }
 
-    pub fn restriction_set(&self, req_mutbl: ast::mutability)
+    pub fn restriction_set(&self, req_mutbl: LoanMutability)
                            -> RestrictionSet {
         match req_mutbl {
-            m_const => RESTR_EMPTY,
-            m_imm   => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM,
-            m_mutbl => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE
+            ConstMutability => RESTR_EMPTY,
+            ImmutableMutability => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM,
+            MutableMutability => {
+                RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE
+            }
         }
     }
 
@@ -582,8 +588,8 @@ pub fn mark_loan_path_as_mutated(&self, loan_path: @LoanPath) {
                 self.mark_loan_path_as_mutated(base);
             }
             LpExtend(_, mc::McDeclared, _) |
-            LpExtend(_, mc::McImmutable, _) |
-            LpExtend(_, mc::McReadOnly, _) => {
+            LpExtend(_, mc::McImmutable, _) => {
+                // Nothing to do.
             }
         }
     }
@@ -701,8 +707,13 @@ fn gather_pat(&mut self,
                             }
                         }
                     };
-                    self.guarantee_valid(pat.id, pat.span,
-                                         cmt_discr, mutbl, scope_r);
+                    let loan_mutability =
+                        LoanMutability::from_ast_mutability(mutbl);
+                    self.guarantee_valid(pat.id,
+                                         pat.span,
+                                         cmt_discr,
+                                         loan_mutability,
+                                         scope_r);
                   }
                   ast::bind_infer => {
                       // No borrows here, but there may be moves
@@ -725,6 +736,8 @@ fn gather_pat(&mut self,
                       self.vec_slice_info(slice_pat, slice_ty);
                   let mcx = self.bccx.mc_ctxt();
                   let cmt_index = mcx.cat_index(slice_pat, cmt, 0);
+                  let slice_loan_mutability =
+                    LoanMutability::from_ast_mutability(slice_mutbl);
 
                   // Note: We declare here that the borrow occurs upon
                   // entering the `[...]` pattern. This implies that
@@ -743,8 +756,11 @@ fn gather_pat(&mut self,
                   // trans do the right thing, and it would only work
                   // for `~` vectors. It seems simpler to just require
                   // that people call `vec.pop()` or `vec.unshift()`.
-                  self.guarantee_valid(pat.id, pat.span,
-                                       cmt_index, slice_mutbl, slice_r);
+                  self.guarantee_valid(pat.id,
+                                       pat.span,
+                                       cmt_index,
+                                       slice_loan_mutability,
+                                       slice_r);
               }
 
               _ => {}
index 46bb23e400ee59df4759812ca9fa233d29c40cba..26c2cff189c46b00923a7ff94d666170926768eb 100644 (file)
@@ -15,7 +15,7 @@
 use middle::borrowck::*;
 use mc = middle::mem_categorization;
 use middle::ty;
-use syntax::ast::{m_const, m_imm, m_mutbl};
+use syntax::ast::{m_imm, m_mutbl};
 use syntax::codemap::span;
 
 pub enum RestrictionResult {
@@ -101,7 +101,7 @@ fn restrict(&self,
                 self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
             }
 
-            mc::cat_deref(cmt_base, _, mc::uniq_ptr) => {
+            mc::cat_deref(cmt_base, _, pk @ mc::uniq_ptr) => {
                 // R-Deref-Send-Pointer
                 //
                 // When we borrow the interior of an owned pointer, we
@@ -110,26 +110,18 @@ fn restrict(&self,
                 let result = self.restrict(
                     cmt_base,
                     restrictions | RESTR_MUTATE | RESTR_CLAIM);
-                self.extend(result, cmt.mutbl, LpDeref, restrictions)
+                self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
             }
 
             mc::cat_copied_upvar(*) | // FIXME(#2152) allow mutation of upvars
             mc::cat_static_item(*) |
-            mc::cat_implicit_self(*) |
             mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) |
             mc::cat_deref(_, _, mc::gc_ptr(m_imm)) => {
                 // R-Deref-Imm-Borrowed
                 Safe
             }
 
-            mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
-            mc::cat_deref(_, _, mc::gc_ptr(m_const)) => {
-                // R-Deref-Freeze-Borrowed
-                self.check_no_mutability_control(cmt, restrictions);
-                Safe
-            }
-
-            mc::cat_deref(cmt_base, _, mc::gc_ptr(m_mutbl)) => {
+            mc::cat_deref(cmt_base, _, pk @ mc::gc_ptr(m_mutbl)) => {
                 // R-Deref-Managed-Borrowed
                 //
                 // Technically, no restrictions are *necessary* here.
@@ -170,14 +162,14 @@ fn restrict(&self,
                 match opt_loan_path(cmt_base) {
                     None => Safe,
                     Some(lp_base) => {
-                        let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref);
+                        let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref(pk));
                         SafeIf(lp, ~[Restriction {loan_path: lp,
                                                   set: restrictions}])
                     }
                 }
             }
 
-            mc::cat_deref(cmt_base, _, mc::region_ptr(m_mutbl, _)) => {
+            mc::cat_deref(cmt_base, _, pk @ mc::region_ptr(m_mutbl, _)) => {
                 // Because an `&mut` pointer does not inherit its
                 // mutability, we can only prevent mutation or prevent
                 // freezing if it is not aliased. Therefore, in such
@@ -187,7 +179,7 @@ fn restrict(&self,
                     let result = self.restrict(
                         cmt_base,
                         RESTR_ALIAS | RESTR_MUTATE | RESTR_CLAIM);
-                    self.extend(result, cmt.mutbl, LpDeref, restrictions)
+                    self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
                 } else {
                     // R-Deref-Mut-Borrowed-2
                     Safe
index 95eae32922b7f7afe7a35969aab1a83796aa5004..7113af3fbc2464a8f55c7f6526aea344fbfa3000 100644 (file)
@@ -241,12 +241,39 @@ pub enum PartialTotal {
 ///////////////////////////////////////////////////////////////////////////
 // Loans and loan paths
 
+#[deriving(Clone, Eq)]
+pub enum LoanMutability {
+    ImmutableMutability,
+    ConstMutability,
+    MutableMutability,
+}
+
+impl LoanMutability {
+    pub fn from_ast_mutability(ast_mutability: ast::mutability)
+                               -> LoanMutability {
+        match ast_mutability {
+            ast::m_imm => ImmutableMutability,
+            ast::m_mutbl => MutableMutability,
+        }
+    }
+}
+
+impl ToStr for LoanMutability {
+    fn to_str(&self) -> ~str {
+        match *self {
+            ImmutableMutability => ~"immutable",
+            ConstMutability => ~"read-only",
+            MutableMutability => ~"mutable",
+        }
+    }
+}
+
 /// Record of a loan that was issued.
 pub struct Loan {
     index: uint,
     loan_path: @LoanPath,
     cmt: mc::cmt,
-    mutbl: ast::mutability,
+    mutbl: LoanMutability,
     restrictions: ~[Restriction],
     gen_scope: ast::NodeId,
     kill_scope: ast::NodeId,
@@ -261,7 +288,7 @@ pub enum LoanPath {
 
 #[deriving(Eq, IterBytes)]
 pub enum LoanPathElem {
-    LpDeref,                     // `*LV` in doc.rs
+    LpDeref(mc::PointerKind),    // `*LV` in doc.rs
     LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
 }
 
@@ -284,8 +311,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
     match cmt.cat {
         mc::cat_rvalue(*) |
         mc::cat_static_item |
-        mc::cat_copied_upvar(_) |
-        mc::cat_implicit_self => {
+        mc::cat_copied_upvar(_) => {
             None
         }
 
@@ -295,9 +321,9 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
             Some(@LpVar(id))
         }
 
-        mc::cat_deref(cmt_base, _, _) => {
+        mc::cat_deref(cmt_base, _, pk) => {
             do opt_loan_path(cmt_base).map_move |lp| {
-                @LpExtend(lp, cmt.mutbl, LpDeref)
+                @LpExtend(lp, cmt.mutbl, LpDeref(pk))
             }
         }
 
@@ -418,7 +444,7 @@ fn to_str(&self) -> ~str {
 // Errors that can occur
 #[deriving(Eq)]
 pub enum bckerr_code {
-    err_mutbl(ast::mutability),
+    err_mutbl(LoanMutability),
     err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
     err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
     err_freeze_aliasable_const
@@ -728,7 +754,7 @@ pub fn append_loan_path_to_str_from_interior(&self,
                                                  loan_path: &LoanPath,
                                                  out: &mut ~str) {
         match *loan_path {
-            LpExtend(_, _, LpDeref) => {
+            LpExtend(_, _, LpDeref(_)) => {
                 out.push_char('(');
                 self.append_loan_path_to_str(loan_path, out);
                 out.push_char(')');
@@ -776,7 +802,7 @@ pub fn append_loan_path_to_str(&self,
                 out.push_str("[]");
             }
 
-            LpExtend(lp_base, _, LpDeref) => {
+            LpExtend(lp_base, _, LpDeref(_)) => {
                 out.push_char('*');
                 self.append_loan_path_to_str(lp_base, out);
             }
@@ -795,17 +821,14 @@ pub fn cmt_to_str(&self, cmt: mc::cmt) -> ~str {
         mc.cmt_to_str(cmt)
     }
 
-    pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
-        let mc = &mc::mem_categorization_ctxt {tcx: self.tcx,
-                                               method_map: self.method_map};
-        mc.mut_to_str(mutbl)
+    pub fn mut_to_str(&self, mutbl: LoanMutability) -> ~str {
+        mutbl.to_str()
     }
 
     pub fn mut_to_keyword(&self, mutbl: ast::mutability) -> &'static str {
         match mutbl {
             ast::m_imm => "",
-            ast::m_const => "const",
-            ast::m_mutbl => "mut"
+            ast::m_mutbl => "mut",
         }
     }
 }
@@ -854,7 +877,7 @@ fn repr(&self, tcx: ty::ctxt) -> ~str {
                 fmt!("$(%?)", id)
             }
 
-            &LpExtend(lp, _, LpDeref) => {
+            &LpExtend(lp, _, LpDeref(_)) => {
                 fmt!("%s.*", lp.repr(tcx))
             }
 
index 0530ffd30b4f0841f663f74faab5a4977560e626..fc779f73060a0c80e9a8123a08bbfd4ad891932d 100644 (file)
@@ -141,7 +141,7 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
             // to handle on-demand instantiation of functions via
             // foo::<bar> in a const. Currently that is only done on
             // a path in trans::callee that only works in block contexts.
-            if pth.types.len() != 0 {
+            if !pth.segments.iter().all(|segment| segment.types.is_empty()) {
                 sess.span_err(
                     e.span, "paths in constants may only refer to \
                              items without type parameters");
index eb42724e800384892da559f32881132235a5d47c..5a2e3a4b760f742ade80c897364e37ad8c2dd39c 100644 (file)
@@ -56,7 +56,7 @@
  * lint attributes.
  *
  * At each node of the ast which can modify lint attributes, all known lint
- * passes are also applied.  Each lint pass is an oldvisit::vt<()> structure.
+ * passes are also applied.  Each lint pass is a visit::Visitor implementator.
  * The visitors are constructed via the lint_*() functions below. There are
  * also some lint checks which operate directly on ast nodes (such as
  * @ast::item), and those are organized as check_item_*(). Each visitor added
@@ -508,7 +508,7 @@ fn with_lint_attrs(@mut self, attrs: &[ast::Attribute], f: &fn()) {
         }
     }
 
-    fn add_oldvisit_lint(&mut self, v: @mut OuterLint) {
+    fn add_old_lint(&mut self, v: @mut OuterLint) {
         self.visitors.push(OldVisitor(v, v.inner_variant()));
     }
 
@@ -547,7 +547,7 @@ fn process(@mut self, n: AttributedNode) {
                     }
                 }
             }
-            // Can't use oldvisit::visit_method_helper because the
+            // Can't use visit::walk_method_helper because the
             // item_stopping_visitor has overridden visit_fn(&fk_method(... ))
             // to be a no-op, so manually invoke visit_fn.
             Method(m) => {
@@ -1450,14 +1450,14 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::Crate) {
     }
 
     // Register each of the lint passes with the context
-    cx.add_oldvisit_lint(lint_while_true());
-    cx.add_oldvisit_lint(lint_path_statement());
-    cx.add_oldvisit_lint(lint_heap());
-    cx.add_oldvisit_lint(lint_type_limits());
-    cx.add_oldvisit_lint(lint_unused_unsafe());
-    cx.add_oldvisit_lint(lint_unused_mut());
-    cx.add_oldvisit_lint(lint_unnecessary_allocations());
-    cx.add_oldvisit_lint(lint_missing_doc());
+    cx.add_old_lint(lint_while_true());
+    cx.add_old_lint(lint_path_statement());
+    cx.add_old_lint(lint_heap());
+    cx.add_old_lint(lint_type_limits());
+    cx.add_old_lint(lint_unused_unsafe());
+    cx.add_old_lint(lint_unused_mut());
+    cx.add_old_lint(lint_unnecessary_allocations());
+    cx.add_old_lint(lint_missing_doc());
     cx.add_lint(lint_session(cx));
 
     // Actually perform the lint checks (iterating the ast)
index 283724447f831fab8fadc2b5adfca1fb0ae96cbf..3f1e409e170cde03b53c3f31a1cae27bccb341d3 100644 (file)
 use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
 use util::common::indenter;
 
-use syntax::ast::{m_imm, m_const, m_mutbl};
+use syntax::ast::{m_imm, m_mutbl};
 use syntax::ast;
 use syntax::codemap::span;
 use syntax::print::pprust;
 
 #[deriving(Eq)]
 pub enum categorization {
-    cat_rvalue(ast::NodeId),          // temporary val, argument is its scope
+    cat_rvalue(ast::NodeId),           // temporary val, argument is its scope
     cat_static_item,
-    cat_implicit_self,
     cat_copied_upvar(CopiedUpvar),     // upvar copied into @fn or ~fn env
     cat_stack_upvar(cmt),              // by ref upvar from &fn
-    cat_local(ast::NodeId),           // local variable
-    cat_arg(ast::NodeId),             // formal argument
-    cat_deref(cmt, uint, ptr_kind),    // deref of a ptr
+    cat_local(ast::NodeId),            // local variable
+    cat_arg(ast::NodeId),              // formal argument
+    cat_deref(cmt, uint, PointerKind), // deref of a ptr
     cat_interior(cmt, InteriorKind),   // something interior: field, tuple, etc
     cat_downcast(cmt),                 // selects a particular enum variant (*)
-    cat_discr(cmt, ast::NodeId),      // match discriminant (see preserve())
-    cat_self(ast::NodeId),            // explicit `self`
+    cat_discr(cmt, ast::NodeId),       // match discriminant (see preserve())
+    cat_self(ast::NodeId),             // explicit `self`
 
     // (*) downcast is only required if the enum has more than one variant
 }
@@ -82,8 +81,8 @@ pub struct CopiedUpvar {
 }
 
 // different kinds of pointers:
-#[deriving(Eq)]
-pub enum ptr_kind {
+#[deriving(Eq, IterBytes)]
+pub enum PointerKind {
     uniq_ptr,
     gc_ptr(ast::mutability),
     region_ptr(ast::mutability, ty::Region),
@@ -114,7 +113,6 @@ pub enum ElementKind {
 #[deriving(Eq, IterBytes)]
 pub enum MutabilityCategory {
     McImmutable, // Immutable.
-    McReadOnly,  // Read-only (`const`)
     McDeclared,  // Directly declared as mutable.
     McInherited  // Inherited from the fact that owner is mutable.
 }
@@ -147,7 +145,7 @@ pub struct cmt_ {
 // We pun on *T to mean both actual deref of a ptr as well
 // as accessing of components:
 pub enum deref_kind {
-    deref_ptr(ptr_kind),
+    deref_ptr(PointerKind),
     deref_interior(InteriorKind),
 }
 
@@ -298,7 +296,6 @@ impl MutabilityCategory {
     pub fn from_mutbl(m: ast::mutability) -> MutabilityCategory {
         match m {
             m_imm => McImmutable,
-            m_const => McReadOnly,
             m_mutbl => McDeclared
         }
     }
@@ -306,7 +303,6 @@ pub fn from_mutbl(m: ast::mutability) -> MutabilityCategory {
     pub fn inherit(&self) -> MutabilityCategory {
         match *self {
             McImmutable => McImmutable,
-            McReadOnly => McReadOnly,
             McDeclared => McInherited,
             McInherited => McInherited
         }
@@ -314,7 +310,7 @@ pub fn inherit(&self) -> MutabilityCategory {
 
     pub fn is_mutable(&self) -> bool {
         match *self {
-            McImmutable | McReadOnly => false,
+            McImmutable => false,
             McDeclared | McInherited => true
         }
     }
@@ -322,7 +318,7 @@ pub fn is_mutable(&self) -> bool {
     pub fn is_immutable(&self) -> bool {
         match *self {
             McImmutable => true,
-            McReadOnly | McDeclared | McInherited => false
+            McDeclared | McInherited => false
         }
     }
 
@@ -330,7 +326,6 @@ pub fn to_user_str(&self) -> &'static str {
         match *self {
             McDeclared | McInherited => "mutable",
             McImmutable => "immutable",
-            McReadOnly => "const"
         }
     }
 }
@@ -493,17 +488,11 @@ pub fn cat_def(&self,
             }
           }
 
-          ast::def_self(self_id, is_implicit) => {
-            let cat = if is_implicit {
-                cat_implicit_self
-            } else {
-                cat_self(self_id)
-            };
-
+          ast::def_self(self_id) => {
             @cmt_ {
                 id:id,
                 span:span,
-                cat:cat,
+                cat:cat_self(self_id),
                 mutbl: McImmutable,
                 ty:expr_ty
             }
@@ -617,7 +606,6 @@ pub fn inherited_mutability(&self,
                                 -> MutabilityCategory {
         match interior_m {
             m_imm => base_m.inherit(),
-            m_const => McReadOnly,
             m_mutbl => McDeclared
         }
     }
@@ -1006,7 +994,6 @@ pub fn cat_pattern(&self,
     pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
         match mutbl {
           m_mutbl => ~"mutable",
-          m_const => ~"const",
           m_imm => ~"immutable"
         }
     }
@@ -1016,9 +1003,6 @@ pub fn cmt_to_str(&self, cmt: cmt) -> ~str {
           cat_static_item => {
               ~"static item"
           }
-          cat_implicit_self => {
-              ~"self reference"
-          }
           cat_copied_upvar(_) => {
               ~"captured outer variable in a heap closure"
           }
@@ -1121,7 +1105,6 @@ pub fn guarantor(@self) -> cmt {
         match self.cat {
             cat_rvalue(*) |
             cat_static_item |
-            cat_implicit_self |
             cat_copied_upvar(*) |
             cat_local(*) |
             cat_self(*) |
@@ -1146,9 +1129,10 @@ pub fn is_freely_aliasable(&self) -> bool {
     }
 
     pub fn freely_aliasable(&self) -> Option<AliasableReason> {
-        //! True if this lvalue resides in an area that is
-        //! freely aliasable, meaning that rustc cannot track
-        //! the alias//es with precision.
+        /*!
+         * Returns `Some(_)` if this lvalue represents a freely aliasable
+         * pointer type.
+         */
 
         // Maybe non-obvious: copied upvars can only be considered
         // non-aliasable in once closures, since any other kind can be
@@ -1166,8 +1150,7 @@ pub fn freely_aliasable(&self) -> Option<AliasableReason> {
             }
 
             cat_copied_upvar(CopiedUpvar {onceness: ast::Many, _}) |
-            cat_static_item(*) |
-            cat_implicit_self(*) => {
+            cat_static_item(*) => {
                 Some(AliasableOther)
             }
 
@@ -1175,17 +1158,16 @@ pub fn freely_aliasable(&self) -> Option<AliasableReason> {
                 Some(AliasableManaged(m))
             }
 
-            cat_deref(_, _, region_ptr(m @ m_const, _)) |
             cat_deref(_, _, region_ptr(m @ m_imm, _)) => {
                 Some(AliasableBorrowed(m))
             }
 
-            cat_downcast(b) |
-            cat_stack_upvar(b) |
-            cat_deref(b, _, uniq_ptr) |
-            cat_interior(b, _) |
-            cat_discr(b, _) => {
-                b.freely_aliasable()
+            cat_downcast(*) |
+            cat_stack_upvar(*) |
+            cat_deref(_, _, uniq_ptr) |
+            cat_interior(*) |
+            cat_discr(*) => {
+                None
             }
         }
     }
@@ -1205,7 +1187,6 @@ impl Repr for categorization {
     fn repr(&self, tcx: ty::ctxt) -> ~str {
         match *self {
             cat_static_item |
-            cat_implicit_self |
             cat_rvalue(*) |
             cat_copied_upvar(*) |
             cat_local(*) |
@@ -1233,7 +1214,7 @@ fn repr(&self, tcx: ty::ctxt) -> ~str {
     }
 }
 
-pub fn ptr_sigil(ptr: ptr_kind) -> ~str {
+pub fn ptr_sigil(ptr: PointerKind) -> ~str {
     match ptr {
         uniq_ptr => ~"~",
         gc_ptr(_) => ~"@",
index 0c553843cd1b2dd713eaec618d30ea25da345679..9f55e5e3509bcde0319aabc9f7fe12e8f06f7aef 100644 (file)
@@ -139,8 +139,8 @@ struct Foo { a: int, b: ~int }
 use std::hashmap::{HashSet, HashMap};
 use syntax::ast::*;
 use syntax::ast_util;
-use syntax::oldvisit;
-use syntax::oldvisit::vt;
+use syntax::visit;
+use syntax::visit::Visitor;
 use syntax::codemap::span;
 
 #[deriving(Encodable, Decodable)]
@@ -190,16 +190,26 @@ enum UseMode {
     Read         // Read no matter what the type.
 }
 
+struct ComputeModesVisitor;
+
+impl visit::Visitor<VisitContext> for ComputeModesVisitor {
+    fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&fn_decl,
+                b:&Block, s:span, n:NodeId, e:VisitContext) {
+        compute_modes_for_fn(*self, fk, fd, b, s, n, e);
+    }
+    fn visit_expr(&mut self, ex:@expr, e:VisitContext) {
+        compute_modes_for_expr(*self, ex, e);
+    }
+    fn visit_local(&mut self, l:@Local, e:VisitContext) {
+        compute_modes_for_local(*self, l, e);
+    }
+}
+
 pub fn compute_moves(tcx: ty::ctxt,
                      method_map: method_map,
                      crate: &Crate) -> MoveMaps
 {
-    let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
-        visit_fn: compute_modes_for_fn,
-        visit_expr: compute_modes_for_expr,
-        visit_local: compute_modes_for_local,
-        .. *oldvisit::default_visitor()
-    });
+    let mut visitor = ComputeModesVisitor;
     let visit_cx = VisitContext {
         tcx: tcx,
         method_map: method_map,
@@ -209,7 +219,7 @@ pub fn compute_moves(tcx: ty::ctxt,
             moved_variables_set: @mut HashSet::new()
         }
     };
-    oldvisit::visit_crate(crate, (visit_cx, visitor));
+    visit::walk_crate(&mut visitor, crate, visit_cx);
     return visit_cx.move_maps;
 }
 
@@ -218,7 +228,7 @@ pub fn moved_variable_node_id_from_def(def: def) -> Option<NodeId> {
       def_binding(nid, _) |
       def_arg(nid, _) |
       def_local(nid, _) |
-      def_self(nid, _) => Some(nid),
+      def_self(nid) => Some(nid),
 
       _ => None
     }
@@ -227,43 +237,44 @@ pub fn moved_variable_node_id_from_def(def: def) -> Option<NodeId> {
 ///////////////////////////////////////////////////////////////////////////
 // Expressions
 
-fn compute_modes_for_local<'a>(local: @Local,
-                               (cx, v): (VisitContext,
-                                         vt<VisitContext>)) {
+fn compute_modes_for_local<'a>(v: ComputeModesVisitor,
+                               local: @Local,
+                               cx: VisitContext) {
     cx.use_pat(local.pat);
     for &init in local.init.iter() {
         cx.use_expr(init, Read, v);
     }
 }
 
-fn compute_modes_for_fn(fk: &oldvisit::fn_kind,
+fn compute_modes_for_fn(v: ComputeModesVisitor,
+                        fk: &visit::fn_kind,
                         decl: &fn_decl,
                         body: &Block,
                         span: span,
                         id: NodeId,
-                        (cx, v): (VisitContext,
-                                  vt<VisitContext>)) {
+                        cx: VisitContext) {
+    let mut v = v;
     for a in decl.inputs.iter() {
         cx.use_pat(a.pat);
     }
-    oldvisit::visit_fn(fk, decl, body, span, id, (cx, v));
+    visit::walk_fn(&mut v, fk, decl, body, span, id, cx);
 }
 
-fn compute_modes_for_expr(expr: @expr,
-                          (cx, v): (VisitContext,
-                                    vt<VisitContext>))
+fn compute_modes_for_expr(v: ComputeModesVisitor,
+                          expr: @expr,
+                          cx: VisitContext)
 {
     cx.consume_expr(expr, v);
 }
 
 impl VisitContext {
-    pub fn consume_exprs(&self, exprs: &[@expr], visitor: vt<VisitContext>) {
+    pub fn consume_exprs(&self, exprs: &[@expr], visitor: ComputeModesVisitor) {
         for expr in exprs.iter() {
             self.consume_expr(*expr, visitor);
         }
     }
 
-    pub fn consume_expr(&self, expr: @expr, visitor: vt<VisitContext>) {
+    pub fn consume_expr(&self, expr: @expr, visitor: ComputeModesVisitor) {
         /*!
          * Indicates that the value of `expr` will be consumed,
          * meaning either copied or moved depending on its type.
@@ -281,7 +292,7 @@ pub fn consume_expr(&self, expr: @expr, visitor: vt<VisitContext>) {
         };
     }
 
-    pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
+    pub fn consume_block(&self, blk: &Block, visitor: ComputeModesVisitor) {
         /*!
          * Indicates that the value of `blk` will be consumed,
          * meaning either copied or moved depending on its type.
@@ -290,7 +301,8 @@ pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
         debug!("consume_block(blk.id=%?)", blk.id);
 
         for stmt in blk.stmts.iter() {
-            (visitor.visit_stmt)(*stmt, (*self, visitor));
+            let mut v = visitor;
+            v.visit_stmt(*stmt, *self);
         }
 
         for tail_expr in blk.expr.iter() {
@@ -301,7 +313,7 @@ pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
     pub fn use_expr(&self,
                     expr: @expr,
                     expr_mode: UseMode,
-                    visitor: vt<VisitContext>) {
+                    visitor: ComputeModesVisitor) {
         /*!
          * Indicates that `expr` is used with a given mode.  This will
          * in turn trigger calls to the subcomponents of `expr`.
@@ -570,7 +582,7 @@ pub fn use_overloaded_operator(&self,
                                    expr: &expr,
                                    receiver_expr: @expr,
                                    arg_exprs: &[@expr],
-                                   visitor: vt<VisitContext>)
+                                   visitor: ComputeModesVisitor)
                                    -> bool {
         if !self.method_map.contains_key(&expr.id) {
             return false;
@@ -587,7 +599,7 @@ pub fn use_overloaded_operator(&self,
         return true;
     }
 
-    pub fn consume_arm(&self, arm: &arm, visitor: vt<VisitContext>) {
+    pub fn consume_arm(&self, arm: &arm, visitor: ComputeModesVisitor) {
         for pat in arm.pats.iter() {
             self.use_pat(*pat);
         }
@@ -630,21 +642,21 @@ pub fn use_pat(&self, pat: @pat) {
 
     pub fn use_receiver(&self,
                         receiver_expr: @expr,
-                        visitor: vt<VisitContext>) {
+                        visitor: ComputeModesVisitor) {
         self.use_fn_arg(receiver_expr, visitor);
     }
 
     pub fn use_fn_args(&self,
                        _: NodeId,
                        arg_exprs: &[@expr],
-                       visitor: vt<VisitContext>) {
+                       visitor: ComputeModesVisitor) {
         //! Uses the argument expressions.
         for arg_expr in arg_exprs.iter() {
             self.use_fn_arg(*arg_expr, visitor);
         }
     }
 
-    pub fn use_fn_arg(&self, arg_expr: @expr, visitor: vt<VisitContext>) {
+    pub fn use_fn_arg(&self, arg_expr: @expr, visitor: ComputeModesVisitor) {
         //! Uses the argument.
         self.consume_expr(arg_expr, visitor)
     }
index 222bef641d2247f8f71d021de716c8a1b7ccbc76..ccb62252e5d88ee0f26b283bffe62d2eed5ff588 100644 (file)
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// A pass that checks to make sure private fields and methods aren't used
-// outside their scopes.
-
+//! A pass that checks to make sure private fields and methods aren't used
+//! outside their scopes.
 
 use metadata::csearch;
 use middle::ty::{ty_struct, ty_enum};
@@ -226,7 +225,7 @@ fn check_method_common(&mut self, span: span, method_id: def_id, name: &ident) {
 
         if method_id.crate == LOCAL_CRATE {
             let is_private = self.method_is_private(span, method_id.node);
-            let container_id = ty::method(self.tcx, method_id).container_id;
+            let container_id = ty::method(self.tcx, method_id).container_id();
             if is_private &&
                     (container_id.crate != LOCAL_CRATE ||
                      !self.privileged_items.iter().any(|x| x == &(container_id.node))) {
@@ -251,7 +250,9 @@ fn check_path(&mut self, span: span, def: def, path: &Path) {
         match def {
             def_static_method(method_id, _, _) => {
                 debug!("found static method def, checking it");
-                self.check_method_common(span, method_id, path.idents.last())
+                self.check_method_common(span,
+                                         method_id,
+                                         &path.segments.last().identifier)
             }
             def_fn(def_id, _) => {
                 if def_id.crate == LOCAL_CRATE {
@@ -259,13 +260,19 @@ fn check_path(&mut self, span: span, def: def, path: &Path) {
                             !self.privileged_items.iter().any(|x| x == &def_id.node) {
                         self.tcx.sess.span_err(span,
                                           fmt!("function `%s` is private",
-                                               token::ident_to_str(path.idents.last())));
+                                               token::ident_to_str(
+                                                &path.segments
+                                                     .last()
+                                                     .identifier)));
                     }
                 } else if csearch::get_item_visibility(self.tcx.sess.cstore,
                                                        def_id) != public {
                     self.tcx.sess.span_err(span,
                                       fmt!("function `%s` is private",
-                                           token::ident_to_str(path.idents.last())));
+                                           token::ident_to_str(
+                                                &path.segments
+                                                     .last()
+                                                     .identifier)));
                 }
             }
             _ => {}
index ddd22a0add4c66ac300fc935389e30f327740991..d6b6a948a57155db396145e565ff43fbc381eb93 100644 (file)
@@ -827,7 +827,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
           Some(&ast::def_trait(did)) |
           Some(&ast::def_struct(did)) => {
             if did.crate == ast::LOCAL_CRATE {
-                if cx.region_is_relevant(&path.rp) {
+                if cx.region_is_relevant(&path.segments.last().lifetime) {
                     cx.add_dep(did.node);
                 }
             } else {
@@ -837,7 +837,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
                   Some(variance) => {
                     debug!("reference to external, rp'd type %s",
                            pprust::ty_to_str(ty, sess.intr()));
-                    if cx.region_is_relevant(&path.rp) {
+                    if cx.region_is_relevant(&path.segments.last().lifetime) {
                         let rv = cx.add_variance(variance);
                         cx.add_rp(cx.item_id, rv)
                     }
@@ -860,7 +860,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
       ast::ty_path(ref path, _, _) => {
         // type parameters are---for now, anyway---always invariant
         do cx.with_ambient_variance(rv_invariant) {
-            for tp in path.types.iter() {
+            for tp in path.segments.iter().flat_map(|s| s.types.iter()) {
                 visitor.visit_ty(tp, cx);
             }
         }
index 0dee86e2a196cd07b85e40aca6c8cff4f3a53675..2989f1047298ccace23c91427c3adab797062ffb 100644 (file)
 
 
 use driver::session::Session;
-use metadata::csearch::{each_path, get_trait_method_def_ids};
+use metadata::csearch::get_trait_method_def_ids;
 use metadata::csearch::get_method_name_and_explicit_self;
 use metadata::csearch::get_static_methods_if_impl;
 use metadata::csearch::{get_type_name_if_impl, get_struct_fields};
+use metadata::csearch;
 use metadata::cstore::find_extern_mod_stmt_cnum;
 use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
 use middle::lang_items::LanguageItems;
@@ -55,6 +56,12 @@ pub struct binding_info {
 // Trait method resolution
 pub type TraitMap = HashMap<NodeId,@mut ~[def_id]>;
 
+// A summary of the generics on a trait.
+struct TraitGenerics {
+    has_lifetime: bool,
+    type_parameter_count: uint,
+}
+
 // This is the replacement export map. It maps a module to all of the exports
 // within.
 pub type ExportMap2 = @mut HashMap<NodeId, ~[Export2]>;
@@ -125,7 +132,7 @@ pub enum Mutability {
 
 pub enum SelfBinding {
     NoSelfBinding,
-    HasSelfBinding(NodeId, bool /* is implicit */)
+    HasSelfBinding(NodeId)
 }
 
 struct ResolveVisitor {
@@ -464,12 +471,18 @@ pub struct Module {
 
     // The index of the import we're resolving.
     resolved_import_count: uint,
+
+    // Whether this module is populated. If not populated, any attempt to
+    // access the children must be preceded with a
+    // `populate_module_if_necessary` call.
+    populated: bool,
 }
 
 pub fn Module(parent_link: ParentLink,
               def_id: Option<def_id>,
-              kind: ModuleKind)
-           -> Module {
+              kind: ModuleKind,
+              external: bool)
+              -> Module {
     Module {
         parent_link: parent_link,
         def_id: def_id,
@@ -480,7 +493,8 @@ pub fn Module(parent_link: ParentLink,
         anonymous_children: @mut HashMap::new(),
         import_resolutions: @mut HashMap::new(),
         glob_count: 0,
-        resolved_import_count: 0
+        resolved_import_count: 0,
+        populated: !external,
     }
 }
 
@@ -527,9 +541,10 @@ pub fn define_module(@mut self,
                          parent_link: ParentLink,
                          def_id: Option<def_id>,
                          kind: ModuleKind,
+                         external: bool,
                          sp: span) {
         // Merges the module with the existing type def or creates a new one.
-        let module_ = @mut Module(parent_link, def_id, kind);
+        let module_ = @mut Module(parent_link, def_id, kind, external);
         match self.type_def {
             None => {
                 self.type_def = Some(TypeNsDef {
@@ -556,10 +571,11 @@ pub fn set_module_kind(@mut self,
                            parent_link: ParentLink,
                            def_id: Option<def_id>,
                            kind: ModuleKind,
+                           external: bool,
                            _sp: span) {
         match self.type_def {
             None => {
-                let module = @mut Module(parent_link, def_id, kind);
+                let module = @mut Module(parent_link, def_id, kind, external);
                 self.type_def = Some(TypeNsDef {
                     privacy: privacy,
                     module_def: Some(module),
@@ -570,7 +586,10 @@ pub fn set_module_kind(@mut self,
             Some(type_def) => {
                 match type_def.module_def {
                     None => {
-                        let module = @mut Module(parent_link, def_id, kind);
+                        let module = @mut Module(parent_link,
+                                                 def_id,
+                                                 kind,
+                                                 external);
                         self.type_def = Some(TypeNsDef {
                             privacy: privacy,
                             module_def: Some(module),
@@ -792,6 +811,7 @@ pub fn Resolver(session: Session,
                              NoParentLink,
                              Some(def_id { crate: 0, node: 0 }),
                              NormalModuleKind,
+                             false,
                              crate.span);
 
     let current_module = graph_root.get_module();
@@ -1157,6 +1177,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                                             parent_link,
                                             Some(def_id),
                                             NormalModuleKind,
+                                            false,
                                             sp);
 
                 let new_parent =
@@ -1179,6 +1200,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                                                     parent_link,
                                                     Some(def_id),
                                                     ExternModuleKind,
+                                                    false,
                                                     sp);
 
                         ModuleReducedGraphParent(name_bindings.get_module())
@@ -1277,7 +1299,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                     &Ty {
                         node: ty_path(ref path, _, _),
                         _
-                    } if path.idents.len() == 1 => {
+                    } if path.segments.len() == 1 => {
                         let name = path_to_ident(path);
 
                         let new_parent = match parent.children.find(&name) {
@@ -1303,6 +1325,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                                                             parent_link,
                                                             Some(def_id),
                                                             ImplModuleKind,
+                                                            false,
                                                             sp);
 
                                 ModuleReducedGraphParent(
@@ -1321,9 +1344,12 @@ pub fn build_reduced_graph_for_item(@mut self,
                                                method.span);
                             let def = match method.explicit_self.node {
                                 sty_static => {
-                                    // Static methods become `def_fn`s.
-                                    def_fn(local_def(method.id),
-                                           method.purity)
+                                    // Static methods become
+                                    // `def_static_method`s.
+                                    def_static_method(local_def(method.id),
+                                                      FromImpl(local_def(
+                                                        item.id)),
+                                                      method.purity)
                                 }
                                 _ => {
                                     // Non-static methods become
@@ -1357,6 +1383,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                                             parent_link,
                                             Some(local_def(item.id)),
                                             TraitModuleKind,
+                                            false,
                                             sp);
                 let module_parent = ModuleReducedGraphParent(name_bindings.
                                                              get_module());
@@ -1373,7 +1400,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                         sty_static => {
                             // Static methods become `def_static_method`s.
                             def_static_method(local_def(ty_m.id),
-                                              Some(local_def(item.id)),
+                                              FromTrait(local_def(item.id)),
                                               ty_m.purity)
                         }
                         _ => {
@@ -1476,20 +1503,22 @@ pub fn build_reduced_graph_for_view_item(@mut self,
                     let mut module_path = ~[];
                     match view_path.node {
                         view_path_simple(_, ref full_path, _) => {
-                            let path_len = full_path.idents.len();
+                            let path_len = full_path.segments.len();
                             assert!(path_len != 0);
 
-                            for (i, ident) in full_path.idents.iter().enumerate() {
+                            for (i, segment) in full_path.segments
+                                                         .iter()
+                                                         .enumerate() {
                                 if i != path_len - 1 {
-                                    module_path.push(*ident);
+                                    module_path.push(segment.identifier)
                                 }
                             }
                         }
 
                         view_path_glob(ref module_ident_path, _) |
                         view_path_list(ref module_ident_path, _, _) => {
-                            for ident in module_ident_path.idents.iter() {
-                                module_path.push(*ident);
+                            for segment in module_ident_path.segments.iter() {
+                                module_path.push(segment.identifier)
                             }
                         }
                     }
@@ -1498,7 +1527,8 @@ pub fn build_reduced_graph_for_view_item(@mut self,
                     let module_ = self.get_module_from_parent(parent);
                     match view_path.node {
                         view_path_simple(binding, ref full_path, id) => {
-                            let source_ident = *full_path.idents.last();
+                            let source_ident =
+                                full_path.segments.last().identifier;
                             let subclass = @SingleImport(binding,
                                                          source_ident);
                             self.build_import_directive(privacy,
@@ -1543,7 +1573,8 @@ pub fn build_reduced_graph_for_view_item(@mut self,
                             (self.get_module_from_parent(parent), name);
                         let external_module = @mut Module(parent_link,
                                                           Some(def_id),
-                                                          NormalModuleKind);
+                                                          NormalModuleKind,
+                                                          false);
 
                         parent.external_module_children.insert(
                             name,
@@ -1607,7 +1638,8 @@ pub fn build_reduced_graph_for_block(@mut self,
             let new_module = @mut Module(
                 BlockParentLink(parent_module, block_id),
                 None,
-                AnonymousModuleKind);
+                AnonymousModuleKind,
+                false);
             parent_module.anonymous_children.insert(block_id, new_module);
             new_parent = ModuleReducedGraphParent(new_module);
         } else {
@@ -1617,23 +1649,22 @@ pub fn build_reduced_graph_for_block(@mut self,
         visit::walk_block(visitor, block, new_parent);
     }
 
-    pub fn handle_external_def(@mut self,
-                               def: def,
-                               visibility: ast::visibility,
-                               modules: &mut HashMap<def_id, @mut Module>,
-                               child_name_bindings: @mut NameBindings,
-                               final_ident: &str,
-                               ident: ident,
-                               new_parent: ReducedGraphParent) {
+    fn handle_external_def(@mut self,
+                           def: def,
+                           visibility: ast::visibility,
+                           child_name_bindings: @mut NameBindings,
+                           final_ident: &str,
+                           ident: ident,
+                           new_parent: ReducedGraphParent) {
         let privacy = visibility_to_privacy(visibility);
         match def {
-          def_mod(def_id) | def_foreign_mod(def_id) => {
+          def_mod(def_id) | def_foreign_mod(def_id) | def_struct(def_id) |
+          def_ty(def_id) => {
             match child_name_bindings.type_def {
               Some(TypeNsDef { module_def: Some(module_def), _ }) => {
                 debug!("(building reduced graph for external crate) \
                         already created module");
                 module_def.def_id = Some(def_id);
-                modules.insert(def_id, module_def);
               }
               Some(_) | None => {
                 debug!("(building reduced graph for \
@@ -1641,45 +1672,20 @@ pub fn handle_external_def(@mut self,
                         %s", final_ident);
                 let parent_link = self.get_parent_link(new_parent, ident);
 
-                // FIXME (#5074): this should be a match on find
-                if !modules.contains_key(&def_id) {
-                    child_name_bindings.define_module(privacy,
-                                                      parent_link,
-                                                      Some(def_id),
-                                                      NormalModuleKind,
-                                                      dummy_sp());
-                    modules.insert(def_id,
-                                   child_name_bindings.get_module());
-                } else {
-                    let existing_module = *modules.get(&def_id);
-
-                    // Create an import resolution to avoid creating cycles in
-                    // the module graph.
-
-                    let resolution = @mut ImportResolution(Public, 0);
-                    resolution.outstanding_references = 0;
-
-                    match existing_module.parent_link {
-                      NoParentLink |
-                      BlockParentLink(*) => {
-                        fail!("can't happen");
-                      }
-                      ModuleParentLink(parent_module, ident) => {
-                        let name_bindings = parent_module.children.get(
-                            &ident);
-                        resolution.type_target =
-                            Some(Target(parent_module, *name_bindings));
-                      }
-                    }
-
-                    debug!("(building reduced graph for external crate) \
-                            ... creating import resolution");
-
-                    new_parent.import_resolutions.insert(ident, resolution);
-                }
+                child_name_bindings.define_module(privacy,
+                                                  parent_link,
+                                                  Some(def_id),
+                                                  NormalModuleKind,
+                                                  true,
+                                                  dummy_sp());
               }
             }
           }
+          _ => {}
+        }
+
+        match def {
+          def_mod(_) | def_foreign_mod(_) => {}
           def_variant(*) => {
             debug!("(building reduced graph for external crate) building \
                     variant %s",
@@ -1691,7 +1697,7 @@ pub fn handle_external_def(@mut self,
           }
           def_fn(*) | def_static_method(*) | def_static(*) => {
             debug!("(building reduced graph for external \
-                    crate) building value %s", final_ident);
+                    crate) building value (fn/static) %s", final_ident);
             child_name_bindings.define_value(privacy, def, dummy_sp());
           }
           def_trait(def_id) => {
@@ -1737,6 +1743,7 @@ trait method '%s'",
                                                   parent_link,
                                                   Some(def_id),
                                                   TraitModuleKind,
+                                                  true,
                                                   dummy_sp())
           }
           def_ty(_) => {
@@ -1767,184 +1774,183 @@ trait method '%s'",
         }
     }
 
-    /**
-     * Builds the reduced graph rooted at the 'use' directive for an external
-     * crate.
-     */
-    pub fn build_reduced_graph_for_external_crate(@mut self,
-                                                  root: @mut Module) {
-        let mut modules = HashMap::new();
-
-        // Create all the items reachable by paths.
-        do each_path(self.session.cstore, root.def_id.unwrap().crate)
-                |path_string, def_like, visibility| {
-
-            debug!("(building reduced graph for external crate) found path \
-                        entry: %s (%?)",
-                    path_string, def_like);
-
-            let mut pieces: ~[&str] = path_string.split_str_iter("::").collect();
-            let final_ident_str = pieces.pop();
-            let final_ident = self.session.ident_of(final_ident_str);
-
-            // Find the module we need, creating modules along the way if we
-            // need to.
-
-            let mut current_module = root;
-            for ident_str in pieces.iter() {
-                let ident = self.session.ident_of(*ident_str);
-                // Create or reuse a graph node for the child.
-                let (child_name_bindings, new_parent) =
-                    self.add_child(ident,
-                                   ModuleReducedGraphParent(current_module),
-                                   OverwriteDuplicates,
-                                   dummy_sp());
-
-                // Define or reuse the module node.
-                match child_name_bindings.type_def {
-                    None => {
-                        debug!("(building reduced graph for external crate) \
-                                autovivifying missing type def %s",
-                                *ident_str);
-                        let parent_link = self.get_parent_link(new_parent,
-                                                               ident);
-                        child_name_bindings.define_module(Public,
-                                                          parent_link,
-                                                          None,
-                                                          NormalModuleKind,
-                                                          dummy_sp());
+    /// Builds the reduced graph for a single item in an external crate.
+    fn build_reduced_graph_for_external_crate_def(@mut self,
+                                                  root: @mut Module,
+                                                  def_like: def_like,
+                                                  ident: ident) {
+        match def_like {
+            dl_def(def) => {
+                // Add the new child item, if necessary.
+                match def {
+                    def_foreign_mod(def_id) => {
+                        // Foreign modules have no names. Recur and populate
+                        // eagerly.
+                        do csearch::each_child_of_item(self.session.cstore,
+                                                       def_id)
+                                |def_like, child_ident| {
+                            self.build_reduced_graph_for_external_crate_def(
+                                root,
+                                def_like,
+                                child_ident)
+                        }
                     }
-                    Some(type_ns_def)
-                            if type_ns_def.module_def.is_none() => {
-                        debug!("(building reduced graph for external crate) \
-                                autovivifying missing module def %s",
-                                *ident_str);
-                        let parent_link = self.get_parent_link(new_parent,
-                                                               ident);
-                        child_name_bindings.define_module(Public,
-                                                          parent_link,
-                                                          None,
-                                                          NormalModuleKind,
-                                                          dummy_sp());
+                    _ => {
+                        let (child_name_bindings, new_parent) =
+                            self.add_child(ident,
+                                           ModuleReducedGraphParent(root),
+                                           OverwriteDuplicates,
+                                           dummy_sp());
+
+                        self.handle_external_def(def,
+                                                 public,
+                                                 child_name_bindings,
+                                                 self.session.str_of(ident),
+                                                 ident,
+                                                 new_parent);
                     }
-                    _ => {} // Fall through.
-                }
-
-                current_module = child_name_bindings.get_module();
-            }
-
-            match def_like {
-                dl_def(def) => {
-                    // Add the new child item.
-                    let (child_name_bindings, new_parent) =
-                        self.add_child(final_ident,
-                                       ModuleReducedGraphParent(
-                                            current_module),
-                                       OverwriteDuplicates,
-                                       dummy_sp());
-
-                    self.handle_external_def(def,
-                                             visibility,
-                                             &mut modules,
-                                             child_name_bindings,
-                                             self.session.str_of(
-                                                 final_ident),
-                                             final_ident,
-                                             new_parent);
-                }
-                dl_impl(def) => {
-                    // We only process static methods of impls here.
-                    match get_type_name_if_impl(self.session.cstore, def) {
-                        None => {}
-                        Some(final_ident) => {
-                            let static_methods_opt =
-                                get_static_methods_if_impl(
-                                    self.session.cstore, def);
-                            match static_methods_opt {
-                                Some(ref static_methods) if
-                                    static_methods.len() >= 1 => {
-                                    debug!("(building reduced graph for \
-                                            external crate) processing \
-                                            static methods for type name %s",
-                                            self.session.str_of(
-                                                final_ident));
-
-                                    let (child_name_bindings, new_parent) =
-                                        self.add_child(final_ident,
-                                            ModuleReducedGraphParent(
-                                                            current_module),
-                                            OverwriteDuplicates,
-                                            dummy_sp());
-
-                                    // Process the static methods. First,
-                                    // create the module.
-                                    let type_module;
-                                    match child_name_bindings.type_def {
-                                        Some(TypeNsDef {
-                                            module_def: Some(module_def),
-                                            _
-                                        }) => {
-                                            // We already have a module. This
-                                            // is OK.
-                                            type_module = module_def;
-
-                                            // Mark it as an impl module if
-                                            // necessary.
-                                            type_module.kind = ImplModuleKind;
-                                        }
-                                        Some(_) | None => {
-                                            let parent_link =
-                                                self.get_parent_link(
-                                                    new_parent, final_ident);
-                                            child_name_bindings.define_module(
-                                                Public,
-                                                parent_link,
-                                                Some(def),
-                                                ImplModuleKind,
-                                                dummy_sp());
-                                            type_module =
-                                                child_name_bindings.
-                                                    get_module();
-                                        }
+                }
+            }
+            dl_impl(def) => {
+                // We only process static methods of impls here.
+                match get_type_name_if_impl(self.session.cstore, def) {
+                    None => {}
+                    Some(final_ident) => {
+                        let static_methods_opt =
+                            get_static_methods_if_impl(self.session.cstore,
+                                                       def);
+                        match static_methods_opt {
+                            Some(ref static_methods) if
+                                static_methods.len() >= 1 => {
+                                debug!("(building reduced graph for \
+                                        external crate) processing \
+                                        static methods for type name %s",
+                                        self.session.str_of(
+                                            final_ident));
+
+                                let (child_name_bindings, new_parent) =
+                                    self.add_child(
+                                        final_ident,
+                                        ModuleReducedGraphParent(root),
+                                        OverwriteDuplicates,
+                                        dummy_sp());
+
+                                // Process the static methods. First,
+                                // create the module.
+                                let type_module;
+                                match child_name_bindings.type_def {
+                                    Some(TypeNsDef {
+                                        module_def: Some(module_def),
+                                        _
+                                    }) => {
+                                        // We already have a module. This
+                                        // is OK.
+                                        type_module = module_def;
+
+                                        // Mark it as an impl module if
+                                        // necessary.
+                                        type_module.kind = ImplModuleKind;
                                     }
-
-                                    // Add each static method to the module.
-                                    let new_parent = ModuleReducedGraphParent(
-                                        type_module);
-                                    for static_method_info in static_methods.iter() {
-                                        let ident = static_method_info.ident;
-                                        debug!("(building reduced graph for \
-                                                 external crate) creating \
-                                                 static method '%s'",
-                                               self.session.str_of(ident));
-
-                                        let (method_name_bindings, _) =
-                                            self.add_child(
-                                                ident,
-                                                new_parent,
-                                                OverwriteDuplicates,
-                                                dummy_sp());
-                                        let def = def_fn(
-                                            static_method_info.def_id,
-                                            static_method_info.purity);
-                                        method_name_bindings.define_value(
-                                            Public, def, dummy_sp());
+                                    Some(_) | None => {
+                                        let parent_link =
+                                            self.get_parent_link(new_parent,
+                                                                 final_ident);
+                                        child_name_bindings.define_module(
+                                            Public,
+                                            parent_link,
+                                            Some(def),
+                                            ImplModuleKind,
+                                            true,
+                                            dummy_sp());
+                                        type_module =
+                                            child_name_bindings.
+                                                get_module();
                                     }
                                 }
 
-                                // Otherwise, do nothing.
-                                Some(_) | None => {}
+                                // Add each static method to the module.
+                                let new_parent =
+                                    ModuleReducedGraphParent(type_module);
+                                for static_method_info in
+                                        static_methods.iter() {
+                                    let ident = static_method_info.ident;
+                                    debug!("(building reduced graph for \
+                                             external crate) creating \
+                                             static method '%s'",
+                                           self.session.str_of(ident));
+
+                                    let (method_name_bindings, _) =
+                                        self.add_child(ident,
+                                                       new_parent,
+                                                       OverwriteDuplicates,
+                                                       dummy_sp());
+                                    let def = def_fn(
+                                        static_method_info.def_id,
+                                        static_method_info.purity);
+                                    method_name_bindings.define_value(
+                                        Public,
+                                        def,
+                                        dummy_sp());
+                                }
                             }
+
+                            // Otherwise, do nothing.
+                            Some(_) | None => {}
                         }
                     }
                 }
-                dl_field => {
-                    debug!("(building reduced graph for external crate) \
-                            ignoring field");
-                }
             }
-            true
+            dl_field => {
+                debug!("(building reduced graph for external crate) \
+                        ignoring field");
+            }
+        }
+    }
+
+    /// Builds the reduced graph rooted at the given external module.
+    fn populate_external_module(@mut self, module: @mut Module) {
+        debug!("(populating external module) attempting to populate %s",
+               self.module_to_str(module));
+
+        let def_id = match module.def_id {
+            None => {
+                debug!("(populating external module) ... no def ID!");
+                return
+            }
+            Some(def_id) => def_id,
         };
+
+        do csearch::each_child_of_item(self.session.cstore, def_id)
+                |def_like, child_ident| {
+            debug!("(populating external module) ... found ident: %s",
+                   token::ident_to_str(&child_ident));
+            self.build_reduced_graph_for_external_crate_def(module,
+                                                            def_like,
+                                                            child_ident)
+        }
+        module.populated = true
+    }
+
+    /// Ensures that the reduced graph rooted at the given external module
+    /// is built, building it if it is not.
+    fn populate_module_if_necessary(@mut self, module: @mut Module) {
+        if !module.populated {
+            self.populate_external_module(module)
+        }
+        assert!(module.populated)
+    }
+
+    /// Builds the reduced graph rooted at the 'use' directive for an external
+    /// crate.
+    pub fn build_reduced_graph_for_external_crate(@mut self,
+                                                  root: @mut Module) {
+        do csearch::each_top_level_item_of_crate(self.session.cstore,
+                                                 root.def_id.unwrap().crate)
+                |def_like, ident| {
+            self.build_reduced_graph_for_external_crate_def(root,
+                                                            def_like,
+                                                            ident)
+        }
     }
 
     /// Creates and adds an import directive to the given module.
@@ -2043,6 +2049,7 @@ pub fn resolve_imports_for_module_subtree(@mut self,
                self.module_to_str(module_));
         self.resolve_imports_for_module(module_);
 
+        self.populate_module_if_necessary(module_);
         for (_, &child_node) in module_.children.iter() {
             match child_node.get_module_if_available() {
                 None => {
@@ -2109,6 +2116,14 @@ pub fn idents_to_str(@mut self, idents: &[ident]) -> ~str {
         return result;
     }
 
+    fn path_idents_to_str(@mut self, path: &Path) -> ~str {
+        let identifiers: ~[ast::ident] = path.segments
+                                             .iter()
+                                             .map(|seg| seg.identifier)
+                                             .collect();
+        self.idents_to_str(identifiers)
+    }
+
     pub fn import_directive_subclass_to_str(@mut self,
                                             subclass: ImportDirectiveSubclass)
                                             -> @str {
@@ -2260,6 +2275,7 @@ pub fn resolve_single_import(@mut self,
         let mut type_result = UnknownResult;
 
         // Search for direct children of the containing module.
+        self.populate_module_if_necessary(containing_module);
         match containing_module.children.find(&source) {
             None => {
                 // Continue.
@@ -2578,6 +2594,7 @@ pub fn resolve_glob_import(@mut self,
         };
 
         // Add all children from the containing module.
+        self.populate_module_if_necessary(containing_module);
         for (&ident, name_bindings) in containing_module.children.iter() {
             merge_import_resolution(ident, *name_bindings);
         }
@@ -2811,6 +2828,7 @@ pub fn resolve_item_in_lexical_scope(@mut self,
 
         // The current module node is handled specially. First, check for
         // its immediate children.
+        self.populate_module_if_necessary(module_);
         match module_.children.find(&name) {
             Some(name_bindings)
                     if name_bindings.defined_in_namespace(namespace) => {
@@ -3065,6 +3083,7 @@ pub fn resolve_name_in_module(@mut self,
                self.module_to_str(module_));
 
         // First, check the direct children of the module.
+        self.populate_module_if_necessary(module_);
         match module_.children.find(&name) {
             Some(name_bindings)
                     if name_bindings.defined_in_namespace(namespace) => {
@@ -3154,6 +3173,7 @@ pub fn report_unresolved_imports(@mut self, module_: @mut Module) {
         }
 
         // Descend into children and anonymous children.
+        self.populate_module_if_necessary(module_);
         for (_, &child_node) in module_.children.iter() {
             match child_node.get_module_if_available() {
                 None => {
@@ -3212,6 +3232,7 @@ pub fn record_exports_for_module_subtree(@mut self,
         }
 
         self.record_exports_for_module(module_);
+        self.populate_module_if_necessary(module_);
 
         for (_, &child_name_bindings) in module_.children.iter() {
             match child_name_bindings.get_module_if_available() {
@@ -3325,6 +3346,7 @@ pub fn with_scope(@mut self, name: Option<ident>, f: &fn()) {
                 // Nothing to do.
             }
             Some(name) => {
+                self.populate_module_if_necessary(orig_module);
                 match orig_module.children.find(&name) {
                     None => {
                         debug!("!!! (with scope) didn't find `%s` in `%s`",
@@ -3771,9 +3793,8 @@ pub fn resolve_function(@mut self,
                 NoSelfBinding => {
                     // Nothing to do.
                 }
-                HasSelfBinding(self_node_id, is_implicit) => {
-                    let def_like = dl_def(def_self(self_node_id,
-                                                   is_implicit));
+                HasSelfBinding(self_node_id) => {
+                    let def_like = dl_def(def_self(self_node_id));
                     *function_value_rib.self_binding = Some(def_like);
                 }
             }
@@ -3842,8 +3863,7 @@ pub fn resolve_trait_reference(@mut self,
                                    reference_type: TraitReferenceType) {
         match self.resolve_path(id, &trait_reference.path, TypeNS, true, visitor) {
             None => {
-                let path_str = self.idents_to_str(trait_reference.path.idents);
-
+                let path_str = self.path_idents_to_str(&trait_reference.path);
                 let usage_str = match reference_type {
                     TraitBoundingTypeParameter => "bound type parameter with",
                     TraitImplementation        => "implement",
@@ -3865,7 +3885,7 @@ pub fn resolve_struct(@mut self,
                           generics: &Generics,
                           fields: &[@struct_field],
                           visitor: &mut ResolveVisitor) {
-        let mut ident_map = HashMap::new::<ast::ident, @struct_field>();
+        let mut ident_map: HashMap<ast::ident,@struct_field> = HashMap::new();
         for &field in fields.iter() {
             match field.node.kind {
                 named_field(ident, _) => {
@@ -3917,7 +3937,7 @@ pub fn resolve_method(@mut self,
         // we only have self ty if it is a non static method
         let self_binding = match method.explicit_self.node {
           sty_static => { NoSelfBinding }
-          _ => { HasSelfBinding(method.self_id, false) }
+          _ => { HasSelfBinding(method.self_id) }
         };
 
         self.resolve_function(rib_kind,
@@ -4142,8 +4162,8 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
                 let mut result_def = None;
 
                 // First, check to see whether the name is a primitive type.
-                if path.idents.len() == 1 {
-                    let name = *path.idents.last();
+                if path.segments.len() == 1 {
+                    let name = path.segments.last().identifier;
 
                     match self.primitive_type_table
                             .primitive_types
@@ -4152,6 +4172,22 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
                         Some(&primitive_type) => {
                             result_def =
                                 Some(def_prim_ty(primitive_type));
+
+                            if path.segments
+                                   .iter()
+                                   .any(|s| s.lifetime.is_some()) {
+                                self.session.span_err(path.span,
+                                                      "lifetime parameters \
+                                                       are not allowed on \
+                                                       this type")
+                            } else if path.segments
+                                          .iter()
+                                          .any(|s| s.types.len() > 0) {
+                                self.session.span_err(path.span,
+                                                      "type parameters are \
+                                                       not allowed on this \
+                                                       type")
+                            }
                         }
                         None => {
                             // Continue.
@@ -4161,12 +4197,17 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
 
                 match result_def {
                     None => {
-                        match self.resolve_path(ty.id, path, TypeNS, true, visitor) {
+                        match self.resolve_path(ty.id,
+                                                path,
+                                                TypeNS,
+                                                true,
+                                                visitor) {
                             Some(def) => {
                                 debug!("(resolving type) resolved `%s` to \
                                         type %?",
-                                       self.session.str_of(
-                                            *path.idents.last()),
+                                       self.session.str_of(path.segments
+                                                               .last()
+                                                               .identifier),
                                        def);
                                 result_def = Some(def);
                             }
@@ -4175,9 +4216,7 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
                             }
                         }
                     }
-                    Some(_) => {
-                        // Continue.
-                    }
+                    Some(_) => {}   // Continue.
                 }
 
                 match result_def {
@@ -4185,14 +4224,15 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
                         // Write the result into the def map.
                         debug!("(resolving type) writing resolution for `%s` \
                                 (id %d)",
-                               self.idents_to_str(path.idents),
+                               self.path_idents_to_str(path),
                                path_id);
                         self.record_def(path_id, def);
                     }
                     None => {
                         self.resolve_error
-                            (ty.span, fmt!("use of undeclared type name `%s`",
-                                           self.idents_to_str(path.idents)));
+                            (ty.span,
+                             fmt!("use of undeclared type name `%s`",
+                                  self.path_idents_to_str(path)))
                     }
                 }
 
@@ -4231,7 +4271,7 @@ pub fn resolve_pattern(@mut self,
         do walk_pat(pattern) |pattern| {
             match pattern.node {
                 pat_ident(binding_mode, ref path, _)
-                        if !path.global && path.idents.len() == 1 => {
+                        if !path.global && path.segments.len() == 1 => {
 
                     // The meaning of pat_ident with no type parameters
                     // depends on whether an enum variant or unit-like struct
@@ -4242,7 +4282,7 @@ pub fn resolve_pattern(@mut self,
                     // such a value is simply disallowed (since it's rarely
                     // what you want).
 
-                    let ident = path.idents[0];
+                    let ident = path.segments[0].identifier;
 
                     match self.resolve_bare_identifier_pattern(ident) {
                         FoundStructOrEnumVariant(def)
@@ -4352,7 +4392,9 @@ struct in scope",
                     }
 
                     // Check the types in the path pattern.
-                    for ty in path.types.iter() {
+                    for ty in path.segments
+                                  .iter()
+                                  .flat_map(|seg| seg.types.iter()) {
                         self.resolve_type(ty, visitor);
                     }
                 }
@@ -4376,7 +4418,7 @@ struct in scope",
                                 path.span,
                                 fmt!("`%s` is not an enum variant or constant",
                                      self.session.str_of(
-                                         *path.idents.last())));
+                                         path.segments.last().identifier)))
                         }
                         None => {
                             self.resolve_error(path.span,
@@ -4385,7 +4427,9 @@ struct in scope",
                     }
 
                     // Check the types in the path pattern.
-                    for ty in path.types.iter() {
+                    for ty in path.segments
+                                  .iter()
+                                  .flat_map(|s| s.types.iter()) {
                         self.resolve_type(ty, visitor);
                     }
                 }
@@ -4403,8 +4447,10 @@ struct in scope",
                             self.resolve_error(
                                 path.span,
                                 fmt!("`%s` is not an enum variant, struct or const",
-                                     self.session.str_of(
-                                         *path.idents.last())));
+                                     self.session
+                                         .str_of(path.segments
+                                                     .last()
+                                                     .identifier)));
                         }
                         None => {
                             self.resolve_error(path.span,
@@ -4414,7 +4460,9 @@ struct in scope",
                     }
 
                     // Check the types in the path pattern.
-                    for ty in path.types.iter() {
+                    for ty in path.segments
+                                  .iter()
+                                  .flat_map(|s| s.types.iter()) {
                         self.resolve_type(ty, visitor);
                     }
                 }
@@ -4449,7 +4497,7 @@ struct in scope",
                             self.resolve_error(
                                 path.span,
                                 fmt!("`%s` does not name a structure",
-                                     self.idents_to_str(path.idents)));
+                                     self.path_idents_to_str(path)));
                         }
                     }
                 }
@@ -4511,7 +4559,7 @@ pub fn resolve_path(@mut self,
                         visitor: &mut ResolveVisitor)
                         -> Option<def> {
         // First, resolve the types.
-        for ty in path.types.iter() {
+        for ty in path.segments.iter().flat_map(|s| s.types.iter()) {
             self.resolve_type(ty, visitor);
         }
 
@@ -4521,20 +4569,27 @@ pub fn resolve_path(@mut self,
                                                     namespace);
         }
 
-        let unqualified_def = self.resolve_identifier(
-            *path.idents.last(), namespace, check_ribs, path.span);
+        let unqualified_def = self.resolve_identifier(path.segments
+                                                          .last()
+                                                          .identifier,
+                                                      namespace,
+                                                      check_ribs,
+                                                      path.span);
 
-        if path.idents.len() > 1 {
-            let def = self.resolve_module_relative_path(
-                path, self.xray_context, namespace);
+        if path.segments.len() > 1 {
+            let def = self.resolve_module_relative_path(path,
+                                                        self.xray_context,
+                                                        namespace);
             match (def, unqualified_def) {
                 (Some(d), Some(ud)) if d == ud => {
                     self.session.add_lint(unnecessary_qualification,
-                                          id, path.span,
+                                          id,
+                                          path.span,
                                           ~"unnecessary qualification");
                 }
                 _ => ()
             }
+
             return def;
         }
 
@@ -4572,6 +4627,7 @@ pub fn resolve_definition_of_name_in_module(@mut self,
                                                 xray: XrayFlag)
                                                 -> NameDefinition {
         // First, search children.
+        self.populate_module_if_necessary(containing_module);
         match containing_module.children.find(&name) {
             Some(child_name_bindings) => {
                 match (child_name_bindings.def_for_namespace(namespace),
@@ -4641,12 +4697,12 @@ pub fn resolve_definition_of_name_in_module(@mut self,
 
     pub fn intern_module_part_of_path(@mut self, path: &Path) -> ~[ident] {
         let mut module_path_idents = ~[];
-        for (index, ident) in path.idents.iter().enumerate() {
-            if index == path.idents.len() - 1 {
+        for (index, segment) in path.segments.iter().enumerate() {
+            if index == path.segments.len() - 1 {
                 break;
             }
 
-            module_path_idents.push(*ident);
+            module_path_idents.push(segment.identifier);
         }
 
         return module_path_idents;
@@ -4682,7 +4738,7 @@ pub fn resolve_module_relative_path(@mut self,
             }
         }
 
-        let name = *path.idents.last();
+        let name = path.segments.last().identifier;
         let def = match self.resolve_definition_of_name_in_module(containing_module,
                                                         name,
                                                         namespace,
@@ -4750,7 +4806,7 @@ pub fn resolve_crate_relative_path(@mut self,
             }
         }
 
-        let name = *path.idents.last();
+        let name = path.segments.last().identifier;
         match self.resolve_definition_of_name_in_module(containing_module,
                                                         name,
                                                         namespace,
@@ -4970,7 +5026,7 @@ pub fn resolve_expr(@mut self, expr: @expr, visitor: &mut ResolveVisitor) {
                     Some(def) => {
                         // Write the result into the def map.
                         debug!("(resolving expr) resolved `%s`",
-                               self.idents_to_str(path.idents));
+                               self.path_idents_to_str(path));
 
                         // First-class methods are not supported yet; error
                         // out here.
@@ -4990,8 +5046,7 @@ pub fn resolve_expr(@mut self, expr: @expr, visitor: &mut ResolveVisitor) {
                         self.record_def(expr.id, def);
                     }
                     None => {
-                        let wrong_name = self.idents_to_str(
-                            path.idents);
+                        let wrong_name = self.path_idents_to_str(path);
                         if self.name_exists_in_scope_struct(wrong_name) {
                             self.resolve_error(expr.span,
                                         fmt!("unresolved name `%s`. \
@@ -5067,7 +5122,7 @@ pub fn resolve_expr(@mut self, expr: @expr, visitor: &mut ResolveVisitor) {
                         self.resolve_error(
                             path.span,
                             fmt!("`%s` does not name a structure",
-                                 self.idents_to_str(path.idents)));
+                                 self.path_idents_to_str(path)));
                     }
                 }
 
@@ -5237,7 +5292,9 @@ pub fn search_for_traits_containing_method(@mut self, name: ident)
                 }
 
                 // Look for trait children.
-                for (_, &child_name_bindings) in search_module.children.iter() {
+                self.populate_module_if_necessary(search_module);
+                for (_, &child_name_bindings) in
+                        search_module.children.iter() {
                     match child_name_bindings.def_for_namespace(TypeNS) {
                         Some(def) => {
                             match def {
@@ -5436,6 +5493,7 @@ pub fn dump_module(@mut self, module_: @mut Module) {
         debug!("Dump of module `%s`:", self.module_to_str(module_));
 
         debug!("Children:");
+        self.populate_module_if_necessary(module_);
         for (&name, _) in module_.children.iter() {
             debug!("* %s", self.session.str_of(name));
         }
index 8837a9461edf4792bf0988af8c28ccc9fa38123e..4266b051c687598bd206dfa317a668c9bbaa585c 100644 (file)
@@ -22,7 +22,8 @@
 use syntax::ast_map;
 use syntax::attr;
 use syntax::codemap::span;
-use visit = syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
 use util::ppaux::Repr;
 
 #[deriving(Clone)]
@@ -31,44 +32,56 @@ struct Context {
     safe_stack: bool
 }
 
+struct StackCheckVisitor;
+
+impl Visitor<Context> for StackCheckVisitor {
+    fn visit_item(&mut self, i:@ast::item, e:Context) {
+        stack_check_item(*self, i, e);
+    }
+    fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+                b:&ast::Block, s:span, n:ast::NodeId, e:Context) {
+        stack_check_fn(*self, fk, fd, b, s, n, e);
+    }
+    fn visit_expr(&mut self, ex:@ast::expr, e:Context) {
+        stack_check_expr(*self, ex, e);
+    }
+}
+
 pub fn stack_check_crate(tcx: ty::ctxt,
                          crate: &ast::Crate) {
     let new_cx = Context {
         tcx: tcx,
         safe_stack: false
     };
-    let visitor = visit::mk_vt(@visit::Visitor {
-        visit_item: stack_check_item,
-        visit_fn: stack_check_fn,
-        visit_expr: stack_check_expr,
-        ..*visit::default_visitor()
-    });
-    visit::visit_crate(crate, (new_cx, visitor));
+    let mut visitor = StackCheckVisitor;
+    visit::walk_crate(&mut visitor, crate, new_cx);
 }
 
-fn stack_check_item(item: @ast::item,
-                    (in_cx, v): (Context, visit::vt<Context>)) {
+fn stack_check_item(v: StackCheckVisitor,
+                    item: @ast::item,
+                    in_cx: Context) {
+    let mut v = v;
     match item.node {
         ast::item_fn(_, ast::extern_fn, _, _, _) => {
             // an extern fn is already being called from C code...
             let new_cx = Context {safe_stack: true, ..in_cx};
-            visit::visit_item(item, (new_cx, v));
+            visit::walk_item(&mut v, item, new_cx);
         }
         ast::item_fn(*) => {
             let safe_stack = fixed_stack_segment(item.attrs);
             let new_cx = Context {safe_stack: safe_stack, ..in_cx};
-            visit::visit_item(item, (new_cx, v));
+            visit::walk_item(&mut v, item, new_cx);
         }
         ast::item_impl(_, _, _, ref methods) => {
             // visit_method() would make this nicer
             for &method in methods.iter() {
                 let safe_stack = fixed_stack_segment(method.attrs);
                 let new_cx = Context {safe_stack: safe_stack, ..in_cx};
-                visit::visit_method_helper(method, (new_cx, v));
+                visit::walk_method_helper(&mut v, method, new_cx);
             }
         }
         _ => {
-            visit::visit_item(item, (in_cx, v));
+            visit::walk_item(&mut v, item, in_cx);
         }
     }
 
@@ -77,12 +90,13 @@ fn fixed_stack_segment(attrs: &[ast::Attribute]) -> bool {
     }
 }
 
-fn stack_check_fn<'a>(fk: &visit::fn_kind,
+fn stack_check_fn<'a>(v: StackCheckVisitor,
+                      fk: &visit::fn_kind,
                       decl: &ast::fn_decl,
                       body: &ast::Block,
                       sp: span,
                       id: ast::NodeId,
-                      (in_cx, v): (Context, visit::vt<Context>)) {
+                      in_cx: Context) {
     let safe_stack = match *fk {
         visit::fk_method(*) | visit::fk_item_fn(*) => {
             in_cx.safe_stack // see stack_check_item above
@@ -102,11 +116,13 @@ fn stack_check_fn<'a>(fk: &visit::fn_kind,
     };
     let new_cx = Context {safe_stack: safe_stack, ..in_cx};
     debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
-    visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
+    let mut v = v;
+    visit::walk_fn(&mut v, fk, decl, body, sp, id, new_cx);
 }
 
-fn stack_check_expr<'a>(expr: @ast::expr,
-                        (cx, v): (Context, visit::vt<Context>)) {
+fn stack_check_expr<'a>(v: StackCheckVisitor,
+                        expr: @ast::expr,
+                        cx: Context) {
     debug!("stack_check_expr(safe_stack=%b, expr=%s)",
            cx.safe_stack, expr.repr(cx.tcx));
     if !cx.safe_stack {
@@ -126,7 +142,8 @@ fn stack_check_expr<'a>(expr: @ast::expr,
             _ => {}
         }
     }
-    visit::visit_expr(expr, (cx, v));
+    let mut v = v;
+    visit::walk_expr(&mut v, expr, cx);
 }
 
 fn call_to_extern_fn(cx: Context, callee: @ast::expr) {
index 1eeafeacc6f05a75b395d59360ec0c572d0e94c4..9a92d91ab5041032f0fdbcecdaada1abbba29a39 100644 (file)
@@ -245,7 +245,7 @@ pub enum VecLenOpt {
 // range)
 enum Opt {
     lit(Lit),
-    var(/* disr val */ uint, @adt::Repr),
+    var(ty::Disr, @adt::Repr),
     range(@ast::expr, @ast::expr),
     vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
 }
@@ -992,7 +992,7 @@ struct ExtractedBlock {
 
 fn extract_variant_args(bcx: @mut Block,
                             repr: &adt::Repr,
-                            disr_val: uint,
+                            disr_val: ty::Disr,
                             val: ValueRef)
     -> ExtractedBlock {
     let _icx = push_ctxt("match::extract_variant_args");
index a00cfa2912380a771e7b14066cc47e65e7ee5009..5c255ad081811e85185549417eee9a35d4082ad3 100644 (file)
@@ -55,6 +55,7 @@
 use middle::trans::machine;
 use middle::trans::type_of;
 use middle::ty;
+use middle::ty::Disr;
 use syntax::ast;
 use util::ppaux::ty_to_str;
 
@@ -64,7 +65,7 @@
 /// Representations.
 pub enum Repr {
     /// C-like enums; basically an int.
-    CEnum(uint, uint), // discriminant range
+    CEnum(Disr, Disr), // discriminant range
     /**
      * Single-case variants, and structs/tuples/records.
      *
@@ -89,7 +90,7 @@ pub enum Repr {
      * is represented such that `None` is a null pointer and `Some` is the
      * identity function.
      */
-    NullablePointer{ nonnull: Struct, nndiscr: uint, ptrfield: uint,
+    NullablePointer{ nonnull: Struct, nndiscr: Disr, ptrfield: uint,
                      nullfields: ~[ty::t] }
 }
 
@@ -140,7 +141,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
             return Univariant(mk_struct(cx, ftys, packed), dtor)
         }
         ty::ty_enum(def_id, ref substs) => {
-            struct Case { discr: uint, tys: ~[ty::t] };
+            struct Case { discr: Disr, tys: ~[ty::t] };
             impl Case {
                 fn is_zerolen(&self, cx: &mut CrateContext) -> bool {
                     mk_struct(cx, self.tys, false).size == 0
@@ -177,7 +178,7 @@ fn find_ptr(&self) -> Option<uint> {
             // Since there's at least one
             // non-empty body, explicit discriminants should have
             // been rejected by a checker before this point.
-            if !cases.iter().enumerate().all(|(i,c)| c.discr == i) {
+            if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as Disr)) {
                 cx.sess.bug(fmt!("non-C-like enum %s with specified \
                                   discriminants",
                                  ty::item_path_str(cx.tcx, def_id)))
@@ -305,8 +306,8 @@ pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef)
     -> ValueRef {
     match *r {
         CEnum(min, max) => load_discr(bcx, scrutinee, min, max),
-        Univariant(*) => C_uint(bcx.ccx(), 0),
-        General(ref cases) => load_discr(bcx, scrutinee, 0, cases.len() - 1),
+        Univariant(*) => C_disr(bcx.ccx(), 0),
+        General(ref cases) => load_discr(bcx, scrutinee, 0, (cases.len() - 1) as Disr),
         NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
             ZExt(bcx, nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee),
                  Type::enum_discrim(bcx.ccx()))
@@ -314,7 +315,7 @@ pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef)
     }
 }
 
-fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: uint, ptrfield: uint,
+fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint,
                      scrutinee: ValueRef) -> ValueRef {
     let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
     let llptr = Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield]));
@@ -323,7 +324,7 @@ fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: uint, ptrfield:
 }
 
 /// Helper for cases where the discriminant is simply loaded.
-fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: uint, max: uint)
+fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: Disr, max: Disr)
     -> ValueRef {
     let ptr = GEPi(bcx, scrutinee, [0, 0]);
     if max + 1 == min {
@@ -347,16 +348,16 @@ fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: uint, max: uint)
  *
  * This should ideally be less tightly tied to `_match`.
  */
-pub fn trans_case(bcx: @mut Block, r: &Repr, discr: uint) -> _match::opt_result {
+pub fn trans_case(bcx: @mut Block, r: &Repr, discr: Disr) -> _match::opt_result {
     match *r {
         CEnum(*) => {
-            _match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr)))
+            _match::single_result(rslt(bcx, C_disr(bcx.ccx(), discr)))
         }
         Univariant(*) => {
             bcx.ccx().sess.bug("no cases for univariants or structs")
         }
         General(*) => {
-            _match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr)))
+            _match::single_result(rslt(bcx, C_disr(bcx.ccx(), discr)))
         }
         NullablePointer{ _ } => {
             assert!(discr == 0 || discr == 1);
@@ -370,11 +371,11 @@ pub fn trans_case(bcx: @mut Block, r: &Repr, discr: uint) -> _match::opt_result
  * representation.  The fields, if any, should then be initialized via
  * `trans_field_ptr`.
  */
-pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint) {
+pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: Disr) {
     match *r {
         CEnum(min, max) => {
             assert!(min <= discr && discr <= max);
-            Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
+            Store(bcx, C_disr(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
         }
         Univariant(ref st, true) => {
             assert_eq!(discr, 0);
@@ -385,7 +386,7 @@ pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint) {
             assert_eq!(discr, 0);
         }
         General(*) => {
-            Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
+            Store(bcx, C_disr(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
         }
         NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
             if discr != nndiscr {
@@ -401,7 +402,7 @@ pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint) {
  * The number of fields in a given case; for use when obtaining this
  * information from the type or definition is less convenient.
  */
-pub fn num_args(r: &Repr, discr: uint) -> uint {
+pub fn num_args(r: &Repr, discr: Disr) -> uint {
     match *r {
         CEnum(*) => 0,
         Univariant(ref st, dtor) => {
@@ -416,7 +417,7 @@ pub fn num_args(r: &Repr, discr: uint) -> uint {
 }
 
 /// Access a field, at a point when the value's case is known.
-pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint,
+pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: Disr,
                        ix: uint) -> ValueRef {
     // Note: if this ever needs to generate conditionals (e.g., if we
     // decide to do some kind of cdr-coding-like non-unique repr
@@ -494,13 +495,13 @@ pub fn trans_drop_flag_ptr(bcx: @mut Block, r: &Repr, val: ValueRef) -> ValueRef
  * this could be changed in the future to avoid allocating unnecessary
  * space after values of shorter-than-maximum cases.
  */
-pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: uint,
+pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: Disr,
                    vals: &[ValueRef]) -> ValueRef {
     match *r {
         CEnum(min, max) => {
             assert_eq!(vals.len(), 0);
             assert!(min <= discr && discr <= max);
-            C_uint(ccx, discr)
+            C_disr(ccx, discr)
         }
         Univariant(ref st, _dro) => {
             assert_eq!(discr, 0);
@@ -509,7 +510,7 @@ pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: uint,
         General(ref cases) => {
             let case = &cases[discr];
             let max_sz = cases.iter().map(|x| x.size).max().unwrap();
-            let discr_ty = C_uint(ccx, discr);
+            let discr_ty = C_disr(ccx, discr);
             let contents = build_const_struct(ccx, case,
                                               ~[discr_ty] + vals);
             C_struct(contents + &[padding(max_sz - case.size)])
@@ -581,15 +582,15 @@ fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
 
 /// Get the discriminant of a constant value.  (Not currently used.)
 pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef)
-    -> uint {
+    -> Disr {
     match *r {
-        CEnum(*) => const_to_uint(val) as uint,
+        CEnum(*) => const_to_uint(val) as Disr,
         Univariant(*) => 0,
-        General(*) => const_to_uint(const_get_elt(ccx, val, [0])) as uint,
+        General(*) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr,
         NullablePointer{ nndiscr, ptrfield, _ } => {
             if is_null(const_struct_field(ccx, val, ptrfield)) {
                 /* subtraction as uint is ok because nndiscr is either 0 or 1 */
-                (1 - nndiscr) as uint
+                (1 - nndiscr) as Disr
             } else {
                 nndiscr
             }
@@ -605,7 +606,7 @@ pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef)
  * raw LLVM-level structs and arrays.)
  */
 pub fn const_get_field(ccx: &mut CrateContext, r: &Repr, val: ValueRef,
-                       _discr: uint, ix: uint) -> ValueRef {
+                       _discr: Disr, ix: uint) -> ValueRef {
     match *r {
         CEnum(*) => ccx.sess.bug("element access in C-like enum const"),
         Univariant(*) => const_struct_field(ccx, val, ix),
@@ -644,3 +645,7 @@ pub fn is_newtypeish(r: &Repr) -> bool {
         _ => false
     }
 }
+
+fn C_disr(cx: &CrateContext, i: Disr) -> ValueRef {
+    return C_integral(cx.int_type, i, false);
+}
index 5e4c58b9321acdb079392811d2479c978f19540b..e8186477877f423e019be698ce7719047c721add 100644 (file)
@@ -1710,7 +1710,8 @@ 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])
+                                 args: &[ast::arg],
+                                 arg_tys: &[ty::t])
                               -> ~[ValueRef] {
     let _icx = push_ctxt("create_llargs_for_fn_args");
 
@@ -1727,26 +1728,31 @@ 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.
-    vec::from_fn(args.len(), |i| {
-        unsafe {
-            let arg_n = cx.arg_pos(i);
-            let arg = &args[i];
-            let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
-
-            // FIXME #7260: aliasing should be determined by monomorphized ty::t
-            match arg.ty.node {
-                // `~` pointers never alias other parameters, because ownership was transferred
-                ast::ty_uniq(_) => {
-                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
+    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 {
+            // `~` pointers never alias other parameters, because
+            // ownership was 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);
                 }
-                // FIXME: #6785: `&mut` can only alias `&const` and `@mut`, we should check for
-                // those in the other parameters and then mark it as `noalias` if there aren't any
-                _ => {}
             }
-
-            llarg
+            // FIXME: #6785: `&mut` can only alias `&const` and
+            // `@mut`, we should check for those in the other
+            // parameters and then mark it as `noalias` if there
+            // aren't any
+            _ => {}
         }
-    })
+
+        llarg
+    }
 }
 
 pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
@@ -1881,7 +1887,6 @@ pub fn trans_closure(ccx: @mut CrateContext,
     debug!("trans_closure(..., param_substs=%s)",
            param_substs.repr(ccx.tcx));
 
-    // Set up arguments to the function.
     let fcx = new_fn_ctxt_w_id(ccx,
                                path,
                                llfndecl,
@@ -1892,21 +1897,23 @@ pub fn trans_closure(ccx: @mut CrateContext,
                                body.info(),
                                Some(body.span));
 
-    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") {
-        set_no_inline(fcx.llfn);
-        set_fixed_stack_segment(fcx.llfn);
-    }
-
     // Create the first basic block in the function and keep a handle on it to
     //  pass to finish_fn later.
     let bcx_top = fcx.entry_bcx.unwrap();
     let mut bcx = bcx_top;
     let block_ty = node_id_type(bcx, body.id);
 
+    // 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);
+
+    // Set the fixed stack segment flag if necessary.
+    if attr::contains_name(attributes, "fixed_stack_segment") {
+        set_no_inline(fcx.llfn);
+        set_fixed_stack_segment(fcx.llfn);
+    }
+
     bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, raw_llargs, arg_tys);
 
     maybe_load_env(fcx);
@@ -2007,7 +2014,7 @@ pub fn trans_enum_variant(ccx: @mut CrateContext,
                           _enum_id: ast::NodeId,
                           variant: &ast::variant,
                           args: &[ast::variant_arg],
-                          disr: uint,
+                          disr: ty::Disr,
                           param_substs: Option<@param_substs>,
                           llfndecl: ValueRef) {
     let _icx = push_ctxt("trans_enum_variant");
@@ -2056,7 +2063,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
     ccx: @mut CrateContext,
     ctor_id: ast::NodeId,
     args: &[A],
-    disr: uint,
+    disr: ty::Disr,
     param_substs: Option<@param_substs>,
     llfndecl: ValueRef)
 {
@@ -2108,10 +2115,11 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
                                None,
                                None);
 
-    let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
+    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 bcx = fcx.entry_bcx.unwrap();
-    let arg_tys = ty::ty_fn_args(ctor_ty);
 
     insert_synthetic_type_entries(bcx, fn_args, arg_tys);
     let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
@@ -2358,15 +2366,12 @@ fn create_entry_fn(ccx: @mut CrateContext,
                                &ccx.int_type);
 
         // FIXME #4404 android JNI hacks
-        let llfn = if *ccx.sess.building_library {
-            decl_cdecl_fn(ccx.llmod, "amain", llfty)
+        let main_name = if *ccx.sess.building_library {
+            "amain"
         } else {
-            let main_name = match ccx.sess.targ_cfg.os {
-                session::os_win32 => ~"WinMain@16",
-                _ => ~"main",
-            };
-            decl_cdecl_fn(ccx.llmod, main_name, llfty)
+            "main"
         };
+        let llfn = decl_cdecl_fn(ccx.llmod, main_name, llfty);
         let llbb = do "top".with_c_str |buf| {
             unsafe {
                 llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
index e72a568cba0d6fd10739e241c5735b200f63fb29..9502e02c27945c687d59d48b1366e58aeff9a386 100644 (file)
@@ -117,10 +117,13 @@ fn fn_callee(bcx: @mut Block, fd: FnData) -> Callee {
 
     fn trans_def(bcx: @mut Block, def: ast::def, ref_expr: @ast::expr) -> Callee {
         match def {
-            ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
+            ast::def_fn(did, _) |
+            ast::def_static_method(did, ast::FromImpl(_), _) => {
                 fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
             }
-            ast::def_static_method(impl_did, Some(trait_did), _) => {
+            ast::def_static_method(impl_did,
+                                   ast::FromTrait(trait_did),
+                                   _) => {
                 fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
                                                                 trait_did,
                                                                 ref_expr.id))
@@ -280,6 +283,14 @@ pub fn trans_fn_ref_with_vtables(
                               self_ty: None,
                               tps: /*bad*/ type_params.to_owned() };
 
+    // Load the info for the appropriate trait if necessary.
+    match ty::trait_of_method(tcx, def_id) {
+        None => {}
+        Some(trait_id) => {
+            ty::populate_implementations_for_trait_if_necessary(tcx, trait_id)
+        }
+    }
+
     // We need to do a bunch of special handling for default methods.
     // We need to modify the def_id and our substs in order to monomorphize
     // the function.
@@ -300,7 +311,7 @@ pub fn trans_fn_ref_with_vtables(
             // So, what we need to do is find this substitution and
             // compose it with the one we already have.
 
-            let impl_id = ty::method(tcx, def_id).container_id;
+            let impl_id = ty::method(tcx, def_id).container_id();
             let method = ty::method(tcx, source_id);
             let trait_ref = ty::impl_trait_ref(tcx, impl_id)
                 .expect("could not find trait_ref for impl with \
index 87d26fa5ba07c6f7b4be346e0a25166583f08159..0dfce6f42c32970d0cc7cd6d837819c0609a1171 100644 (file)
@@ -453,7 +453,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef {
               (expr::cast_enum, expr::cast_float)  => {
                 let repr = adt::represent_type(cx, basety);
                 let discr = adt::const_get_discrim(cx, repr, v);
-                let iv = C_uint(cx, discr);
+                let iv = C_integral(cx.int_type, discr, false);
                 let ety_cast = expr::cast_type_kind(ety);
                 match ety_cast {
                     expr::cast_integral => {
@@ -559,7 +559,9 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef {
             v
           }
           ast::expr_path(ref pth) => {
-            assert_eq!(pth.types.len(), 0);
+            // Assert that there are no type parameters in this path.
+            assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
+
             let tcx = cx.tcx;
             match tcx.def_map.find(&e.id) {
                 Some(&ast::def_fn(def_id, _purity)) => {
index 1318ef2c8958db24cc07975df24b20df018846fe..9f99a0c92e534b12d77e56decf1aa87fc5df230f 100644 (file)
@@ -137,7 +137,7 @@ pub fn new(sess: session::Session,
                 llvm::LLVMSetDataLayout(llmod, buf)
             };
             do targ_triple.with_c_str |buf| {
-                llvm::LLVMSetTarget(llmod, buf)
+                llvm::LLVMRustSetNormalizedTarget(llmod, buf)
             };
             let targ_cfg = sess.targ_cfg;
 
index ab4fc8ed6d331b1129e957634fab907e4aaaaeea..7c81bfbda6512f209149fb3bc3a7c691a96eafa0 100644 (file)
@@ -825,11 +825,13 @@ fn trans_def_datum_unadjusted(bcx: @mut Block,
     let _icx = push_ctxt("trans_def_datum_unadjusted");
 
     let fn_data = match def {
-        ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
+        ast::def_fn(did, _) |
+        ast::def_static_method(did, ast::FromImpl(_), _) => {
             callee::trans_fn_ref(bcx, did, ref_expr.id)
         }
-        ast::def_static_method(impl_did, Some(trait_did), _) => {
-            meth::trans_static_method_callee(bcx, impl_did,
+        ast::def_static_method(impl_did, ast::FromTrait(trait_did), _) => {
+            meth::trans_static_method_callee(bcx,
+                                             impl_did,
                                              trait_did,
                                              ref_expr.id)
         }
@@ -1066,7 +1068,7 @@ pub fn trans_local_var(bcx: @mut Block, def: ast::def) -> Datum {
         ast::def_local(nid, _) | ast::def_binding(nid, _) => {
             take_local(bcx, bcx.fcx.lllocals, nid)
         }
-        ast::def_self(nid, _) => {
+        ast::def_self(nid) => {
             let self_info: ValSelfData = match bcx.fcx.llself {
                 Some(ref self_info) => *self_info,
                 None => {
@@ -1118,7 +1120,7 @@ fn take_local(bcx: @mut Block,
 pub fn with_field_tys<R>(tcx: ty::ctxt,
                          ty: ty::t,
                          node_id_opt: Option<ast::NodeId>,
-                         op: &fn(uint, (&[ty::field])) -> R) -> R {
+                         op: &fn(ty::Disr, (&[ty::field])) -> R) -> R {
     match ty::get(ty).sty {
         ty::ty_struct(did, ref substs) => {
             op(0, struct_fields(tcx, did, substs))
@@ -1235,7 +1237,7 @@ struct StructBaseInfo {
  * - `optbase` contains information on the base struct (if any) from
  * which remaining fields are copied; see comments on `StructBaseInfo`.
  */
-fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: uint,
+fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: ty::Disr,
              fields: &[(uint, @ast::expr)],
              optbase: Option<StructBaseInfo>,
              dest: Dest) -> @mut Block {
index c0534b89f79adfeb8db5ae4c97a3a856002b70f4..717dfbb67845396e7561dea48bd44fa6b07125b9 100644 (file)
@@ -176,6 +176,10 @@ pub fn trans_method_callee(bcx: @mut Block,
         }) => {
             match bcx.fcx.param_substs {
                 Some(substs) => {
+                    ty::populate_implementations_for_trait_if_necessary(
+                        bcx.tcx(),
+                        trait_id);
+
                     let vtbl = find_vtable(bcx.tcx(), substs,
                                            p, b);
                     trans_monomorphized_callee(bcx, callee_id, this, mentry,
@@ -210,6 +214,8 @@ pub fn trans_static_method_callee(bcx: @mut Block,
            callee_id);
     let _indenter = indenter();
 
+    ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id);
+
     // When we translate a static fn defined in a trait like:
     //
     //   trait<T1...Tn> Trait {
@@ -575,6 +581,8 @@ fn emit_vtable_methods(bcx: @mut Block,
                                     make a vtable for a type impl!")
     };
 
+    ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id);
+
     let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
     do trait_method_def_ids.map |method_def_id| {
         let ident = ty::method(tcx, *method_def_id).ident;
index ab458f2799ddaa2e6c59036a92fc0820adfbea2d..162765350da073507ed047bdfe2f7058105f006c 100644 (file)
@@ -26,7 +26,6 @@
 use middle::trans::type_use;
 use middle::trans::intrinsic;
 use middle::ty;
-use middle::ty::{FnSig};
 use middle::typeck;
 use util::ppaux::{Repr,ty_to_str};
 
@@ -34,8 +33,6 @@
 use syntax::ast_map;
 use syntax::ast_map::path_name;
 use syntax::ast_util::local_def;
-use syntax::opt_vec;
-use syntax::abi::AbiSet;
 
 pub fn monomorphic_fn(ccx: @mut CrateContext,
                       fn_id: ast::def_id,
@@ -61,17 +58,10 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
     let _icx = push_ctxt("monomorphic_fn");
     let mut must_cast = false;
 
-    let do_normalize = |t: &ty::t| {
-        match normalize_for_monomorphization(ccx.tcx, *t) {
-          Some(t) => { must_cast = true; t }
-          None => *t
-        }
-    };
-
     let psubsts = @param_substs {
-        tys: real_substs.tps.map(|x| do_normalize(x)),
+        tys: real_substs.tps.to_owned(),
         vtables: vtables,
-        self_ty: real_substs.self_ty.map(|x| do_normalize(x)),
+        self_ty: real_substs.self_ty.clone(),
         self_vtables: self_vtables
     };
 
@@ -305,61 +295,6 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
     (lldecl, must_cast)
 }
 
-pub fn normalize_for_monomorphization(tcx: ty::ctxt,
-                                      ty: ty::t) -> Option<ty::t> {
-    // FIXME[mono] could do this recursively. is that worthwhile? (#2529)
-    return match ty::get(ty).sty {
-        ty::ty_box(*) => {
-            Some(ty::mk_opaque_box(tcx))
-        }
-        ty::ty_bare_fn(_) => {
-            Some(ty::mk_bare_fn(
-                tcx,
-                ty::BareFnTy {
-                    purity: ast::impure_fn,
-                    abis: AbiSet::Rust(),
-                    sig: FnSig {bound_lifetime_names: opt_vec::Empty,
-                                inputs: ~[],
-                                output: ty::mk_nil()}}))
-        }
-        ty::ty_closure(ref fty) => {
-            Some(normalized_closure_ty(tcx, fty.sigil))
-        }
-        ty::ty_trait(_, _, ref store, _, _) => {
-            let sigil = match *store {
-                ty::UniqTraitStore => ast::OwnedSigil,
-                ty::BoxTraitStore => ast::ManagedSigil,
-                ty::RegionTraitStore(_) => ast::BorrowedSigil,
-            };
-
-            // Traits have the same runtime representation as closures.
-            Some(normalized_closure_ty(tcx, sigil))
-        }
-        ty::ty_ptr(_) => {
-            Some(ty::mk_uint())
-        }
-        _ => {
-            None
-        }
-    };
-
-    fn normalized_closure_ty(tcx: ty::ctxt,
-                             sigil: ast::Sigil) -> ty::t
-    {
-        ty::mk_closure(
-            tcx,
-            ty::ClosureTy {
-                purity: ast::impure_fn,
-                sigil: sigil,
-                onceness: ast::Many,
-                region: ty::re_static,
-                bounds: ty::EmptyBuiltinBounds(),
-                sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
-                                inputs: ~[],
-                                output: ty::mk_nil()}})
-    }
-}
-
 pub fn make_mono_id(ccx: @mut CrateContext,
                     item: ast::def_id,
                     substs: &param_substs,
index dd1b041ef80f1aae3d49dd4012a6b087986b3464..98d2b6df88787531cd945f7bdf94d987920dbf9e 100644 (file)
@@ -317,7 +317,7 @@ pub fn visit_ty(&mut self, t: ty::t) {
                 for (i, v) in variants.iter().enumerate() {
                     let name = ccx.sess.str_of(v.name);
                     let variant_args = ~[this.c_uint(i),
-                                         this.c_uint(v.disr_val),
+                                         C_integral(self.bcx.ccx().int_type, v.disr_val, false),
                                          this.c_uint(v.args.len()),
                                          this.c_slice(name)];
                     do this.bracketed("enum_variant", variant_args) |this| {
index c67035021a3aab9f282abac4491cfefbd450a661..bf65986b5ba9bd60ba4f9a3f0b60edd0bd8bd77f 100644 (file)
@@ -149,7 +149,7 @@ fn store_type_uses(cx: Context, fn_id: def_id) -> @~[type_uses] {
                     "visit_tydesc"  | "forget" | "frame_address" |
                     "morestack_addr" => 0,
 
-                    "offset" | "offset_inbounds" |
+                    "offset" |
                     "memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
                     "memset32" | "memset64" => use_repr,
 
index 39ffffa25c7b581fc07a6174fefd5ada018c4e4b..6f90953cd413ab2c3274cc257759178e48e32cec 100644 (file)
@@ -48,7 +48,9 @@
 use syntax;
 use extra::enum_set::{EnumSet, CLike};
 
-pub static INITIAL_DISCRIMINANT_VALUE: uint = 0;
+pub type Disr = u64;
+
+pub static INITIAL_DISCRIMINANT_VALUE: Disr = 0;
 
 // Data types
 
@@ -58,6 +60,12 @@ pub struct field {
     mt: mt
 }
 
+#[deriving(Clone)]
+pub enum MethodContainer {
+    TraitContainer(ast::def_id),
+    ImplContainer(ast::def_id),
+}
+
 #[deriving(Clone)]
 pub struct Method {
     ident: ast::ident,
@@ -67,7 +75,7 @@ pub struct Method {
     explicit_self: ast::explicit_self_,
     vis: ast::visibility,
     def_id: ast::def_id,
-    container_id: ast::def_id,
+    container: MethodContainer,
 
     // If this method is provided, we need to know where it came from
     provided_source: Option<ast::def_id>
@@ -81,7 +89,7 @@ pub fn new(ident: ast::ident,
                explicit_self: ast::explicit_self_,
                vis: ast::visibility,
                def_id: ast::def_id,
-               container_id: ast::def_id,
+               container: MethodContainer,
                provided_source: Option<ast::def_id>)
                -> Method {
         // Check the invariants.
@@ -99,10 +107,17 @@ pub fn new(ident: ast::ident,
             explicit_self: explicit_self,
             vis: vis,
             def_id: def_id,
-            container_id: container_id,
+            container: container,
             provided_source: provided_source
         }
     }
+
+    pub fn container_id(&self) -> ast::def_id {
+        match self.container {
+            TraitContainer(id) => id,
+            ImplContainer(id) => id,
+        }
+    }
 }
 
 pub struct Impl {
@@ -322,7 +337,15 @@ struct ctxt_ {
     used_mut_nodes: @mut HashSet<ast::NodeId>,
 
     // vtable resolution information for impl declarations
-    impl_vtables: typeck::impl_vtable_map
+    impl_vtables: typeck::impl_vtable_map,
+
+    // The set of external nominal types whose implementations have been read.
+    // This is used for lazy resolution of methods.
+    populated_external_types: @mut HashSet<ast::def_id>,
+
+    // The set of external traits whose implementations have been read. This
+    // is used for lazy resolution of traits.
+    populated_external_traits: @mut HashSet<ast::def_id>,
 }
 
 pub enum tbox_flag {
@@ -936,6 +959,8 @@ pub fn mk_ctxt(s: session::Session,
         used_unsafe: @mut HashSet::new(),
         used_mut_nodes: @mut HashSet::new(),
         impl_vtables: @mut HashMap::new(),
+        populated_external_types: @mut HashSet::new(),
+        populated_external_traits: @mut HashSet::new(),
      }
 }
 
@@ -3474,18 +3499,18 @@ fn terr_vstore_kind_to_str(k: terr_vstore_kind) -> ~str {
         terr_ptr_mutability => ~"pointers differ in mutability",
         terr_ref_mutability => ~"references differ in mutability",
         terr_ty_param_size(values) => {
-            fmt!("expected a type with %? type params \
-                  but found one with %? type params",
+            fmt!("expected a type with %u type params \
+                  but found one with %u type params",
                  values.expected, values.found)
         }
         terr_tuple_size(values) => {
-            fmt!("expected a tuple with %? elements \
-                  but found one with %? elements",
+            fmt!("expected a tuple with %u elements \
+                  but found one with %u elements",
                  values.expected, values.found)
         }
         terr_record_size(values) => {
-            fmt!("expected a record with %? fields \
-                  but found one with %? fields",
+            fmt!("expected a record with %u fields \
+                  but found one with %u fields",
                  values.expected, values.found)
         }
         terr_record_mutability => {
@@ -3610,8 +3635,7 @@ pub fn def_has_ty_params(def: ast::def) -> bool {
     }
 }
 
-pub fn provided_source(cx: ctxt, id: ast::def_id)
-    -> Option<ast::def_id> {
+pub fn provided_source(cx: ctxt, id: ast::def_id) -> Option<ast::def_id> {
     cx.provided_method_sources.find(&id).map_move(|x| *x)
 }
 
@@ -3803,7 +3827,7 @@ pub struct VariantInfo {
     ctor_ty: t,
     name: ast::ident,
     id: ast::def_id,
-    disr_val: uint,
+    disr_val: Disr,
     vis: visibility
 }
 
@@ -3814,7 +3838,7 @@ impl VariantInfo {
     /// Does not do any caching of the value in the type context.
     pub fn from_ast_variant(cx: ctxt,
                             ast_variant: &ast::variant,
-                            discriminant: uint) -> VariantInfo {
+                            discriminant: Disr) -> VariantInfo {
 
         let ctor_ty = node_id_to_type(cx, ast_variant.node.id);
 
@@ -4008,7 +4032,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] {
                     node: ast::item_enum(ref enum_definition, _),
                     _
                 }, _) => {
-            let mut last_discriminant: Option<uint> = None;
+            let mut last_discriminant: Option<Disr> = None;
             @enum_definition.variants.iter().map(|variant| {
 
                 let mut discriminant = match last_discriminant {
@@ -4018,8 +4042,8 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] {
 
                 match variant.node.disr_expr {
                     Some(e) => match const_eval::eval_const_expr_partial(&cx, e) {
-                        Ok(const_eval::const_int(val)) => discriminant = val as uint,
-                        Ok(const_eval::const_uint(val)) => discriminant = val as uint,
+                        Ok(const_eval::const_int(val)) => discriminant = val as Disr,
+                        Ok(const_eval::const_uint(val)) => discriminant = val as Disr,
                         Ok(_) => {
                             cx.sess.span_err(e.span, "expected signed integer constant");
                         }
@@ -4551,3 +4575,135 @@ pub fn visitor_object_ty(tcx: ctxt,
                  ast::m_imm,
                  EmptyBuiltinBounds())))
 }
+
+/// Records a trait-to-implementation mapping.
+fn record_trait_implementation(tcx: ctxt,
+                               trait_def_id: def_id,
+                               implementation: @Impl) {
+    let implementation_list;
+    match tcx.trait_impls.find(&trait_def_id) {
+        None => {
+            implementation_list = @mut ~[];
+            tcx.trait_impls.insert(trait_def_id, implementation_list);
+        }
+        Some(&existing_implementation_list) => {
+            implementation_list = existing_implementation_list
+        }
+    }
+
+    implementation_list.push(implementation);
+}
+
+/// Populates the type context with all the implementations for the given type
+/// if necessary.
+pub fn populate_implementations_for_type_if_necessary(tcx: ctxt,
+                                                      type_id: ast::def_id) {
+    if type_id.crate == LOCAL_CRATE {
+        return
+    }
+    if tcx.populated_external_types.contains(&type_id) {
+        return
+    }
+
+    do csearch::each_implementation_for_type(tcx.sess.cstore, type_id)
+            |implementation_def_id| {
+        let implementation = @csearch::get_impl(tcx, implementation_def_id);
+
+        // Record the trait->implementation mappings, if applicable.
+        let associated_traits = csearch::get_impl_trait(tcx,
+                                                        implementation.did);
+        for trait_ref in associated_traits.iter() {
+            record_trait_implementation(tcx,
+                                        trait_ref.def_id,
+                                        implementation);
+        }
+
+        // For any methods that use a default implementation, add them to
+        // the map. This is a bit unfortunate.
+        for method in implementation.methods.iter() {
+            for source in method.provided_source.iter() {
+                tcx.provided_method_sources.insert(method.def_id, *source);
+            }
+        }
+
+        // If this is an inherent implementation, record it.
+        if associated_traits.is_none() {
+            let implementation_list;
+            match tcx.inherent_impls.find(&type_id) {
+                None => {
+                    implementation_list = @mut ~[];
+                    tcx.inherent_impls.insert(type_id, implementation_list);
+                }
+                Some(&existing_implementation_list) => {
+                    implementation_list = existing_implementation_list;
+                }
+            }
+            implementation_list.push(implementation);
+        }
+
+        // Store the implementation info.
+        tcx.impls.insert(implementation_def_id, implementation);
+    }
+
+    tcx.populated_external_types.insert(type_id);
+}
+
+/// Populates the type context with all the implementations for the given
+/// trait if necessary.
+pub fn populate_implementations_for_trait_if_necessary(
+        tcx: ctxt,
+        trait_id: ast::def_id) {
+    if trait_id.crate == LOCAL_CRATE {
+        return
+    }
+    if tcx.populated_external_traits.contains(&trait_id) {
+        return
+    }
+
+    do csearch::each_implementation_for_trait(tcx.sess.cstore, trait_id)
+            |implementation_def_id| {
+        let implementation = @csearch::get_impl(tcx, implementation_def_id);
+
+        // Record the trait->implementation mapping.
+        record_trait_implementation(tcx, trait_id, implementation);
+
+        // For any methods that use a default implementation, add them to
+        // the map. This is a bit unfortunate.
+        for method in implementation.methods.iter() {
+            for source in method.provided_source.iter() {
+                tcx.provided_method_sources.insert(method.def_id, *source);
+            }
+        }
+
+        // Store the implementation info.
+        tcx.impls.insert(implementation_def_id, implementation);
+    }
+
+    tcx.populated_external_traits.insert(trait_id);
+}
+
+/// If the given def ID describes a trait method, returns the ID of the trait
+/// that the method belongs to. Otherwise, returns `None`.
+pub fn trait_of_method(tcx: ctxt, def_id: ast::def_id)
+                       -> Option<ast::def_id> {
+    match tcx.methods.find(&def_id) {
+        Some(method_descriptor) => {
+            match method_descriptor.container {
+                TraitContainer(id) => return Some(id),
+                _ => {}
+            }
+        }
+        None => {}
+    }
+
+    // If the method was in the local crate, then if we got here we know the
+    // answer is negative.
+    if def_id.crate == LOCAL_CRATE {
+        return None
+    }
+
+    let result = csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
+
+    result
+}
+
index 62e46bdd23c8aa70ccaa3b1b3f65a4f1c2a7c160..6ebcf4facc180e43413c5644f7cfcc606c767e7d 100644 (file)
@@ -63,7 +63,6 @@
 use middle::typeck::lookup_def_tcx;
 
 use std::result;
-use std::vec;
 use syntax::abi::AbiSet;
 use syntax::{ast, ast_util};
 use syntax::codemap::span;
@@ -150,7 +149,8 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
     // If the type is parameterized by the this region, then replace this
     // region with the current anon region binding (in other words,
     // whatever & would get replaced with).
-    let regions = match (&decl_generics.region_param, &path.rp) {
+    let regions = match (&decl_generics.region_param,
+                         &path.segments.last().lifetime) {
         (&None, &None) => {
             opt_vec::Empty
         }
@@ -169,20 +169,34 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
         }
         (&Some(_), &Some(_)) => {
             opt_vec::with(
-                ast_region_to_region(this, rscope, path.span, &path.rp))
+                ast_region_to_region(this,
+                                     rscope,
+                                     path.span,
+                                     &path.segments.last().lifetime))
         }
     };
 
     // Convert the type parameters supplied by the user.
-    if !vec::same_length(*decl_generics.type_param_defs, path.types) {
+    let supplied_type_parameter_count =
+        path.segments.iter().flat_map(|s| s.types.iter()).len();
+    if decl_generics.type_param_defs.len() != supplied_type_parameter_count {
         this.tcx().sess.span_fatal(
             path.span,
             fmt!("wrong number of type arguments: expected %u but found %u",
-                 decl_generics.type_param_defs.len(), path.types.len()));
+                 decl_generics.type_param_defs.len(),
+                 supplied_type_parameter_count));
+    }
+    let tps = path.segments
+                  .iter()
+                  .flat_map(|s| s.types.iter())
+                  .map(|a_t| ast_ty_to_ty(this, rscope, a_t))
+                  .collect();
+
+    substs {
+        regions: ty::NonerasedRegions(regions),
+        self_ty: self_ty,
+        tps: tps
     }
-    let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t));
-
-    substs {regions:ty::NonerasedRegions(regions), self_ty:self_ty, tps:tps}
 }
 
 pub fn ast_path_to_substs_and_ty<AC:AstConv,
@@ -272,8 +286,7 @@ fn mk_pointer<AC:AstConv,RS:region_scope + Clone + 'static>(
         match a_seq_ty.ty.node {
             ast::ty_vec(ref mt) => {
                 let mut mt = ast_mt_to_mt(this, rscope, mt);
-                if a_seq_ty.mutbl == ast::m_mutbl ||
-                        a_seq_ty.mutbl == ast::m_const {
+                if a_seq_ty.mutbl == ast::m_mutbl {
                     mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl };
                 }
                 return ty::mk_evec(tcx, mt, vst);
@@ -326,7 +339,7 @@ fn check_path_args(tcx: ty::ctxt,
                        path: &ast::Path,
                        flags: uint) {
         if (flags & NO_TPS) != 0u {
-            if path.types.len() > 0u {
+            if !path.segments.iter().all(|s| s.types.is_empty()) {
                 tcx.sess.span_err(
                     path.span,
                     "type parameters are not allowed on this type");
@@ -334,7 +347,7 @@ fn check_path_args(tcx: ty::ctxt,
         }
 
         if (flags & NO_REGIONS) != 0u {
-            if path.rp.is_some() {
+            if path.segments.last().lifetime.is_some() {
                 tcx.sess.span_err(
                     path.span,
                     "region parameters are not allowed on this type");
index b7114e602830f3aa634dfc7eae180d7dd38c348c..628ceccd61e7e70f39f22e2db1b2f694d9a24b74 100644 (file)
@@ -128,7 +128,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
                 Some((enm, var)) => {
                     // Assign the pattern the type of the *enum*, not the variant.
                     let enum_tpt = ty::lookup_item_type(tcx, enm);
-                    instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);
+                    instantiate_path(pcx.fcx,
+                                     path,
+                                     enum_tpt,
+                                     v_def,
+                                     pat.span,
+                                     pat.id);
 
                     // check that the type of the value being matched is a subtype
                     // of the type of the pattern:
@@ -185,7 +190,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
             } else {
                 ctor_tpt
             };
-            instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id);
+            instantiate_path(pcx.fcx,
+                             path,
+                             struct_tpt,
+                             s_def,
+                             pat.span,
+                             pat.id);
 
             // Check that the type of the value being matched is a subtype of
             // the type of the pattern.
index c15f6a254457e66d8dcc91e8efece7af90514bf9..c20ccafe82c4e6c3bc05f98dbe372232b5a2af0b 100644 (file)
@@ -102,7 +102,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
 use extra::list::Nil;
 use syntax::ast::{def_id, sty_value, sty_region, sty_box};
 use syntax::ast::{sty_uniq, sty_static, NodeId};
-use syntax::ast::{m_const, m_mutbl, m_imm};
+use syntax::ast::{m_mutbl, m_imm};
 use syntax::ast;
 use syntax::ast_map;
 
@@ -350,6 +350,10 @@ fn push_extension_candidates(&self) {
         let opt_applicable_traits = trait_map.find(&self.expr.id);
         for applicable_traits in opt_applicable_traits.iter() {
             for trait_did in applicable_traits.iter() {
+                ty::populate_implementations_for_trait_if_necessary(
+                    self.tcx(),
+                    *trait_did);
+
                 // Look for explicit implementations.
                 let opt_impl_infos = self.tcx().trait_impls.find(trait_did);
                 for impl_infos in opt_impl_infos.iter() {
@@ -534,6 +538,10 @@ fn push_inherent_candidates_from_bounds_inner(
 
 
     fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
+        // Read the inherent implementation candidates for this type from the
+        // metadata if necessary.
+        ty::populate_implementations_for_type_if_necessary(self.tcx(), did);
+
         let opt_impl_infos = self.tcx().inherent_impls.find(&did);
         for impl_infos in opt_impl_infos.iter() {
             for impl_info in impl_infos.iter() {
@@ -700,7 +708,7 @@ fn search_for_autosliced_method(&self,
             ty_evec(mt, vstore_fixed(_)) => {
                 // First try to borrow to a slice
                 let entry = self.search_for_some_kind_of_autorefd_method(
-                    AutoBorrowVec, autoderefs, [m_const, m_imm, m_mutbl],
+                    AutoBorrowVec, autoderefs, [m_imm, m_mutbl],
                     |m,r| ty::mk_evec(tcx,
                                       ty::mt {ty:mt.ty, mutbl:m},
                                       vstore_slice(r)));
@@ -709,7 +717,7 @@ fn search_for_autosliced_method(&self,
 
                 // Then try to borrow to a slice *and* borrow a pointer.
                 self.search_for_some_kind_of_autorefd_method(
-                    AutoBorrowVecRef, autoderefs, [m_const, m_imm, m_mutbl],
+                    AutoBorrowVecRef, autoderefs, [m_imm, m_mutbl],
                     |m,r| {
                         let slice_ty = ty::mk_evec(tcx,
                                                    ty::mt {ty:mt.ty, mutbl:m},
@@ -744,7 +752,7 @@ fn search_for_autosliced_method(&self,
                 // Coerce ~/@/&Trait instances to &Trait.
 
                 self.search_for_some_kind_of_autorefd_method(
-                    AutoBorrowObj, autoderefs, [m_const, m_imm, m_mutbl],
+                    AutoBorrowObj, autoderefs, [m_imm, m_mutbl],
                     |trt_mut, reg| {
                         ty::mk_trait(tcx, trt_did, trt_substs.clone(),
                                      RegionTraitStore(reg), trt_mut, b)
@@ -779,7 +787,7 @@ fn search_for_autoptrd_method(&self, self_ty: ty::t, autoderefs: uint)
             ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_struct(*) | ty_tup(*) |
             ty_estr(*) | ty_evec(*) | ty_trait(*) | ty_closure(*) => {
                 self.search_for_some_kind_of_autorefd_method(
-                    AutoPtr, autoderefs, [m_const, m_imm, m_mutbl],
+                    AutoPtr, autoderefs, [m_imm, m_mutbl],
                     |m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m}))
             }
 
@@ -1270,18 +1278,10 @@ fn rcvr_matches_ty(fcx: @mut FnCtxt,
         }
 
         fn mutability_matches(self_mutbl: ast::mutability,
-                              candidate_mutbl: ast::mutability) -> bool {
+                              candidate_mutbl: ast::mutability)
+                              -> bool {
             //! True if `self_mutbl <: candidate_mutbl`
-
-            match (self_mutbl, candidate_mutbl) {
-                (_, m_const) => true,
-                (m_mutbl, m_mutbl) => true,
-                (m_imm, m_imm) => true,
-                (m_mutbl, m_imm) => false,
-                (m_imm, m_mutbl) => false,
-                (m_const, m_imm) => false,
-                (m_const, m_mutbl) => false,
-            }
+            self_mutbl == candidate_mutbl
         }
     }
 
index 5ce82ad6e2ca466dbd778a6ba67659d9380c804e..0b27a581a2aa4bc6cb4fc5bf041c147574b99964 100644 (file)
@@ -83,7 +83,7 @@
 use middle::lint::unreachable_code;
 use middle::ty::{FnSig, VariantInfo};
 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
-use middle::ty::{substs, param_ty, ExprTyProvider};
+use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
 use middle::ty;
 use middle::typeck::astconv::AstConv;
 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
@@ -377,7 +377,7 @@ fn visit_pat(&mut self, p:@ast::pat, _:()) {
                   if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
                 self.assign(p.id, None);
                 debug!("Pattern binding %s is assigned to %s",
-                       self.tcx.sess.str_of(path.idents[0]),
+                       self.tcx.sess.str_of(path.segments[0].identifier),
                        self.fcx.infcx().ty_to_str(
                            self.fcx.inh.locals.get_copy(&p.id)));
               }
@@ -1132,8 +1132,160 @@ pub enum DerefArgs {
     DoDerefArgs
 }
 
-pub fn break_here() {
-    debug!("break here!");
+// Given the provenance of a static method, returns the generics of the static
+// method's container.
+fn generics_of_static_method_container(type_context: ty::ctxt,
+                                       provenance: ast::MethodProvenance)
+                                       -> ty::Generics {
+    match provenance {
+        ast::FromTrait(trait_def_id) => {
+            ty::lookup_trait_def(type_context, trait_def_id).generics
+        }
+        ast::FromImpl(impl_def_id) => {
+            ty::lookup_item_type(type_context, impl_def_id).generics
+        }
+    }
+}
+
+// Verifies that type parameters supplied in paths are in the right
+// locations.
+fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt,
+                                          path: &ast::Path,
+                                          def: ast::def) {
+    // We only care about checking the case in which the path has two or
+    // more segments.
+    if path.segments.len() < 2 {
+        return
+    }
+
+    // Verify that no lifetimes or type parameters are present anywhere
+    // except the final two elements of the path.
+    for i in range(0, path.segments.len() - 2) {
+        match path.segments[i].lifetime {
+            None => {}
+            Some(lifetime) => {
+                function_context.tcx()
+                                .sess
+                                .span_err(lifetime.span,
+                                          "lifetime parameters may not \
+                                           appear here")
+            }
+        }
+
+        for typ in path.segments[i].types.iter() {
+            function_context.tcx()
+                            .sess
+                            .span_err(typ.span,
+                                      "type parameters may not appear here")
+        }
+    }
+
+    // If there are no parameters at all, there is nothing more to do; the
+    // rest of typechecking will (attempt to) infer everything.
+    if path.segments
+           .iter()
+           .all(|s| s.lifetime.is_none() && s.types.is_empty()) {
+        return
+    }
+
+    match def {
+        // If this is a static method of a trait or implementation, then
+        // ensure that the segment of the path which names the trait or
+        // implementation (the penultimate segment) is annotated with the
+        // right number of type parameters.
+        ast::def_static_method(_, provenance, _) => {
+            let generics =
+                generics_of_static_method_container(function_context.ccx.tcx,
+                                                    provenance);
+            let name = match provenance {
+                ast::FromTrait(_) => "trait",
+                ast::FromImpl(_) => "impl",
+            };
+
+            let trait_segment = &path.segments[path.segments.len() - 2];
+
+            // Make sure lifetime parameterization agrees with the trait or
+            // implementation type.
+            match (generics.region_param, trait_segment.lifetime) {
+                (Some(_), None) => {
+                    function_context.tcx()
+                                    .sess
+                                    .span_err(path.span,
+                                              fmt!("this %s has a lifetime \
+                                                    parameter but no \
+                                                    lifetime was specified",
+                                                   name))
+                }
+                (None, Some(_)) => {
+                    function_context.tcx()
+                                    .sess
+                                    .span_err(path.span,
+                                              fmt!("this %s has no lifetime \
+                                                    parameter but a lifetime \
+                                                    was specified",
+                                                   name))
+                }
+                (Some(_), Some(_)) | (None, None) => {}
+            }
+
+            // Make sure the number of type parameters supplied on the trait
+            // or implementation segment equals the number of type parameters
+            // on the trait or implementation definition.
+            let trait_type_parameter_count = generics.type_param_defs.len();
+            let supplied_type_parameter_count = trait_segment.types.len();
+            if trait_type_parameter_count != supplied_type_parameter_count {
+                let trait_count_suffix = if trait_type_parameter_count == 1 {
+                    ""
+                } else {
+                    "s"
+                };
+                let supplied_count_suffix =
+                    if supplied_type_parameter_count == 1 {
+                        ""
+                    } else {
+                        "s"
+                    };
+                function_context.tcx()
+                                .sess
+                                .span_err(path.span,
+                                          fmt!("the %s referenced by this \
+                                                path has %u type \
+                                                parameter%s, but %u type \
+                                                parameter%s were supplied",
+                                               name,
+                                               trait_type_parameter_count,
+                                               trait_count_suffix,
+                                               supplied_type_parameter_count,
+                                               supplied_count_suffix))
+            }
+        }
+        _ => {
+            // Verify that no lifetimes or type parameters are present on
+            // the penultimate segment of the path.
+            let segment = &path.segments[path.segments.len() - 2];
+            match segment.lifetime {
+                None => {}
+                Some(lifetime) => {
+                    function_context.tcx()
+                                    .sess
+                                    .span_err(lifetime.span,
+                                              "lifetime parameters may not
+                                               appear here")
+                }
+            }
+            for typ in segment.types.iter() {
+                function_context.tcx()
+                                .sess
+                                .span_err(typ.span,
+                                          "type parameters may not appear \
+                                           here");
+                function_context.tcx()
+                                .sess
+                                .span_note(typ.span,
+                                           fmt!("this is a %?", def));
+            }
+        }
+    }
 }
 
 /// Invariant:
@@ -2333,8 +2485,9 @@ fn check_struct_enum_variant(fcx: @mut FnCtxt,
       ast::expr_path(ref pth) => {
         let defn = lookup_def(fcx, pth.span, id);
 
+        check_type_parameter_positions_in_path(fcx, pth, defn);
         let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
-        instantiate_path(fcx, pth, tpt, expr.span, expr.id);
+        instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
       }
       ast::expr_self => {
         let definition = lookup_def(fcx, expr.span, id);
@@ -3000,8 +3153,8 @@ fn do_check(ccx: @mut CrateCtxt,
 
         let rty = ty::node_id_to_type(ccx.tcx, id);
         let mut variants: ~[@ty::VariantInfo] = ~[];
-        let mut disr_vals: ~[uint] = ~[];
-        let mut prev_disr_val: Option<uint> = None;
+        let mut disr_vals: ~[ty::Disr] = ~[];
+        let mut prev_disr_val: Option<ty::Disr> = None;
 
         for v in vs.iter() {
 
@@ -3024,8 +3177,8 @@ fn do_check(ccx: @mut CrateCtxt,
                     // handle, so we may still get an internal compiler error
 
                     match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
-                        Ok(const_eval::const_int(val)) => current_disr_val = val as uint,
-                        Ok(const_eval::const_uint(val)) => current_disr_val = val as uint,
+                        Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
+                        Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
                         Ok(_) => {
                             ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
                         }
@@ -3093,7 +3246,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
                                       defn: ast::def)
                                    -> ty_param_bounds_and_ty {
     match defn {
-      ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid, _) |
+      ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid) |
       ast::def_binding(nid, _) => {
           let typ = fcx.local_ty(sp, nid);
           return no_params(typ);
@@ -3141,12 +3294,16 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
 pub fn instantiate_path(fcx: @mut FnCtxt,
                         pth: &ast::Path,
                         tpt: ty_param_bounds_and_ty,
+                        def: ast::def,
                         span: span,
                         node_id: ast::NodeId) {
     debug!(">>> instantiate_path");
 
     let ty_param_count = tpt.generics.type_param_defs.len();
-    let ty_substs_len = pth.types.len();
+    let mut ty_substs_len = 0;
+    for segment in pth.segments.iter() {
+        ty_substs_len += segment.types.len()
+    }
 
     debug!("tpt=%s ty_param_count=%? ty_substs_len=%?",
            tpt.repr(fcx.tcx()),
@@ -3155,7 +3312,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
 
     // determine the region bound, using the value given by the user
     // (if any) and otherwise using a fresh region variable
-    let regions = match pth.rp {
+    let regions = match pth.segments.last().lifetime {
         Some(_) => { // user supplied a lifetime parameter...
             match tpt.generics.region_param {
                 None => { // ...but the type is not lifetime parameterized!
@@ -3165,7 +3322,10 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
                 }
                 Some(_) => { // ...and the type is lifetime parameterized, ok.
                     opt_vec::with(
-                        ast_region_to_region(fcx, fcx, span, &pth.rp))
+                        ast_region_to_region(fcx,
+                                             fcx,
+                                             span,
+                                             &pth.segments.last().lifetime))
                 }
             }
         }
@@ -3174,6 +3334,21 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
         }
     };
 
+    // Special case: If there is a self parameter, omit it from the list of
+    // type parameters.
+    //
+    // Here we calculate the "user type parameter count", which is the number
+    // of type parameters actually manifest in the AST. This will differ from
+    // the internal type parameter count when there are self types involved.
+    let (user_type_parameter_count, self_parameter_index) = match def {
+        ast::def_static_method(_, provenance @ ast::FromTrait(_), _) => {
+            let generics = generics_of_static_method_container(fcx.ccx.tcx,
+                                                               provenance);
+            (ty_param_count - 1, Some(generics.type_param_defs.len()))
+        }
+        _ => (ty_param_count, None),
+    };
+
     // determine values for type parameters, using the values given by
     // the user (if any) and otherwise using fresh type variables
     let tps = if ty_substs_len == 0 {
@@ -3182,34 +3357,51 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
         fcx.ccx.tcx.sess.span_err
             (span, "this item does not take type parameters");
         fcx.infcx().next_ty_vars(ty_param_count)
-    } else if ty_substs_len > ty_param_count {
+    } else if ty_substs_len > user_type_parameter_count {
         fcx.ccx.tcx.sess.span_err
             (span,
              fmt!("too many type parameters provided: expected %u, found %u",
-                  ty_param_count, ty_substs_len));
+                  user_type_parameter_count, ty_substs_len));
         fcx.infcx().next_ty_vars(ty_param_count)
-    } else if ty_substs_len < ty_param_count {
-        let is_static_method = match fcx.ccx.tcx.def_map.find(&node_id) {
-            Some(&ast::def_static_method(*)) => true,
-            _ => false
-        };
+    } else if ty_substs_len < user_type_parameter_count {
         fcx.ccx.tcx.sess.span_err
             (span,
              fmt!("not enough type parameters provided: expected %u, found %u",
-                  ty_param_count, ty_substs_len));
-        if is_static_method {
-            fcx.ccx.tcx.sess.span_note
-                (span, "Static methods have an extra implicit type parameter -- \
-                 did you omit the type parameter for the `Self` type?");
-        }
+                  user_type_parameter_count, ty_substs_len));
         fcx.infcx().next_ty_vars(ty_param_count)
     } else {
-        pth.types.map(|aty| fcx.to_ty(aty))
+        // Build up the list of type parameters, inserting the self parameter
+        // at the appropriate position.
+        let mut result = ~[];
+        let mut pushed = false;
+        for (i, ast_type) in pth.segments
+                                .iter()
+                                .flat_map(|segment| segment.types.iter())
+                                .enumerate() {
+            match self_parameter_index {
+                Some(index) if index == i => {
+                    result.push(fcx.infcx().next_ty_vars(1)[0]);
+                    pushed = true;
+                }
+                _ => {}
+            }
+            result.push(fcx.to_ty(ast_type))
+        }
+
+        // If the self parameter goes at the end, insert it there.
+        if !pushed && self_parameter_index.is_some() {
+            result.push(fcx.infcx().next_ty_vars(1)[0])
+        }
+
+        assert_eq!(result.len(), ty_param_count)
+        result
     };
 
-    let substs = substs {regions: ty::NonerasedRegions(regions),
-                         self_ty: None,
-                         tps: tps };
+    let substs = substs {
+        regions: ty::NonerasedRegions(regions),
+        self_ty: None,
+        tps: tps
+    };
     fcx.write_ty_substs(node_id, tpt.ty, substs);
 
     debug!("<<<");
@@ -3471,20 +3663,6 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
                    mutbl: ast::m_imm
                }))
             }
-            "offset_inbounds" => {
-              (1,
-               ~[
-                  ty::mk_ptr(tcx, ty::mt {
-                      ty: param(ccx, 0),
-                      mutbl: ast::m_imm
-                  }),
-                  ty::mk_int()
-               ],
-               ty::mk_ptr(tcx, ty::mt {
-                   ty: param(ccx, 0),
-                   mutbl: ast::m_imm
-               }))
-            }
             "memcpy32" => {
               (1,
                ~[
index 05f1323805b3527a4479bced18fc026e0f023375..b25d81056b0c06ffd7412ff8b8f85ec45909b707 100644 (file)
@@ -58,7 +58,7 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::def) -> ty::Region {
     let tcx = fcx.tcx();
     match def {
         def_local(node_id, _) | def_arg(node_id, _) |
-        def_self(node_id, _) | def_binding(node_id, _) => {
+        def_self(node_id) | def_binding(node_id, _) => {
             tcx.region_maps.encl_region(node_id)
         }
         def_upvar(_, subdef, closure_id, body_id) => {
index cd69a642b72c6e3295b84ae9d7cbacf60e602b98..670553f569a1105f3e5926db77d618e17da35a00 100644 (file)
@@ -29,7 +29,8 @@
 use syntax::ast_util;
 use syntax::codemap::span;
 use syntax::print::pprust::expr_to_str;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
 
 // vtable resolution looks for places where trait bounds are
 // substituted in and figures out which vtable is used. There is some
@@ -135,6 +136,9 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
         // ...and here trait_ref is each bound that was declared on A,
         // expressed in terms of the type parameters.
 
+        ty::populate_implementations_for_trait_if_necessary(tcx,
+                                                            trait_ref.def_id);
+
         // Substitute the values of the type parameters that may
         // appear in the bound.
         let trait_ref = substs.map_default(trait_ref, |substs| {
@@ -320,6 +324,10 @@ fn search_for_vtable(vcx: &VtableContext,
     let mut found = ~[];
     let mut impls_seen = HashSet::new();
 
+    // Load the implementations from external metadata if necessary.
+    ty::populate_implementations_for_trait_if_necessary(tcx,
+                                                        trait_ref.def_id);
+
     // XXX: this is a bad way to do this, since we do
     // pointless allocations.
     let impls = tcx.trait_impls.find(&trait_ref.def_id)
@@ -712,11 +720,11 @@ fn mutability_allowed(a_mutbl: ast::mutability,
     }
 }
 
-fn resolve_expr(ex: @ast::expr,
-                (fcx, v): (@mut FnCtxt,
-                           oldvisit::vt<@mut FnCtxt>)) {
+fn resolve_expr(v: &mut VtableResolveVisitor,
+                ex: @ast::expr,
+                fcx: @mut FnCtxt) {
     early_resolve_expr(ex, fcx, false);
-    oldvisit::visit_expr(ex, (fcx, v));
+    visit::walk_expr(v, ex, fcx);
 }
 
 pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) {
@@ -763,12 +771,20 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) {
     }
 }
 
+struct VtableResolveVisitor;
+
+impl visit::Visitor<@mut FnCtxt> for VtableResolveVisitor {
+    fn visit_expr(&mut self, ex:@ast::expr, e:@mut FnCtxt) {
+        resolve_expr(self, ex, e);
+    }
+    fn visit_item(&mut self, _:@ast::item, _:@mut FnCtxt) {
+        // no-op
+    }
+}
+
 // Detect points where a trait-bounded type parameter is
 // instantiated, resolve the impls for the parameters.
 pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::Block) {
-    oldvisit::visit_block(bl, (fcx, oldvisit::mk_vt(@oldvisit::Visitor {
-        visit_expr: resolve_expr,
-        visit_item: |_,_| {},
-        .. *oldvisit::default_visitor()
-    })));
+    let mut visitor = VtableResolveVisitor;
+    visit::walk_block(&mut visitor, bl, fcx);
 }
index b659f6081b12a05d0d13994884d0789b642b626a..2aa4e28f1a4de4fcfde84e772334793b2436708c 100644 (file)
 // each trait in the system to its implementations.
 
 
-use metadata::csearch::{each_path, get_impl_trait};
+use metadata::csearch::{each_impl, get_impl_trait};
 use metadata::csearch;
 use metadata::cstore::iter_crate_data;
-use metadata::decoder::{dl_def, dl_field, dl_impl};
 use middle::ty::get;
-use middle::ty::{lookup_item_type, subst};
+use middle::ty::{ImplContainer, lookup_item_type, subst};
 use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
 use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
 use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr};
 use syntax::ast_map::node_item;
 use syntax::ast_map;
 use syntax::ast_util::{def_id_of_def, local_def};
-use syntax::codemap::{span, dummy_sp};
+use syntax::codemap::span;
 use syntax::opt_vec;
 use syntax::visit;
 use syntax::parse;
-use util::ppaux::ty_to_str;
 
-use std::hashmap::{HashMap, HashSet};
+use std::hashmap::HashSet;
 use std::result::Ok;
 use std::vec;
 
@@ -150,19 +148,12 @@ pub fn CoherenceChecker(crate_context: @mut CrateCtxt) -> CoherenceChecker {
     CoherenceChecker {
         crate_context: crate_context,
         inference_context: new_infer_ctxt(crate_context.tcx),
-
-        base_type_def_ids: @mut HashMap::new(),
     }
 }
 
 pub struct CoherenceChecker {
     crate_context: @mut CrateCtxt,
     inference_context: @mut InferCtxt,
-
-    // A mapping from implementations to the corresponding base type
-    // definition ID.
-
-    base_type_def_ids: @mut HashMap<def_id,def_id>,
 }
 
 struct CoherenceCheckVisitor { cc: CoherenceChecker }
@@ -321,9 +312,6 @@ pub fn check_implementation(&self,
                 if associated_traits.len() == 0 {
                     self.add_inherent_impl(base_type_def_id, implementation);
                 }
-
-                self.base_type_def_ids.insert(local_def(item.id),
-                                              base_type_def_id);
             }
         }
 
@@ -680,9 +668,6 @@ pub fn add_external_impl(&self,
         let tcx = self.crate_context.tcx;
         let implementation = @csearch::get_impl(tcx, impl_def_id);
 
-        debug!("coherence: adding impl from external crate: %s",
-               ty::item_path_str(tcx, implementation.did));
-
         // Make sure we don't visit the same implementation multiple times.
         if !impls_seen.insert(implementation.did) {
             // Skip this one.
@@ -690,25 +675,11 @@ pub fn add_external_impl(&self,
         }
         // Good. Continue.
 
-        let self_type = lookup_item_type(tcx, implementation.did);
-        let associated_traits = get_impl_trait(tcx,
-                                               implementation.did);
+        let _ = lookup_item_type(tcx, implementation.did);
+        let associated_traits = get_impl_trait(tcx, implementation.did);
 
-        // Do a sanity check to make sure that inherent methods have base
-        // types.
-        if associated_traits.is_none() {
-            match get_base_type_def_id(self.inference_context,
-                                       dummy_sp(),
-                                       self_type.ty) {
-                None => {
-                    tcx.sess.bug(fmt!("no base type for external impl with no \
-                                      trait: %s (type %s)!",
-                                     tcx.sess.str_of(implementation.ident),
-                                     ty_to_str(tcx, self_type.ty)));
-                }
-                Some(_) => {} // Nothing to do.
-            }
-        }
+        // Do a sanity check.
+        assert!(associated_traits.is_some());
 
         // Record all the trait methods.
         for trait_ref in associated_traits.iter() {
@@ -723,25 +694,6 @@ pub fn add_external_impl(&self,
             }
         }
 
-        // Add the implementation to the mapping from implementation to base
-        // type def ID, if there is a base type for this implementation.
-        match get_base_type_def_id(self.inference_context,
-                                   dummy_sp(),
-                                   self_type.ty) {
-            None => {} // Nothing to do.
-            Some(base_type_def_id) => {
-                // inherent methods apply to `impl Type` but not
-                // `impl Trait for Type`:
-                if associated_traits.is_none() {
-                    self.add_inherent_impl(base_type_def_id,
-                                           implementation);
-                }
-
-                self.base_type_def_ids.insert(implementation.did,
-                                              base_type_def_id);
-            }
-        }
-
         tcx.impls.insert(implementation.did, implementation);
     }
 
@@ -752,15 +704,10 @@ pub fn add_external_crates(&self) {
 
         let crate_store = self.crate_context.tcx.sess.cstore;
         do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
-            do each_path(crate_store, crate_number) |_, def_like, _| {
-                match def_like {
-                    dl_impl(def_id) => {
-                        self.add_external_impl(&mut impls_seen, def_id)
-                    }
-                    dl_def(_) | dl_field => (),   // Skip this.
-                }
-                true
-            };
+            do each_impl(crate_store, crate_number) |def_id| {
+                assert_eq!(crate_number, def_id.crate);
+                self.add_external_impl(&mut impls_seen, def_id)
+            }
         }
     }
 
@@ -892,7 +839,7 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt,
         method.explicit_self,
         method.vis,
         new_def_id,
-        impl_id,
+        ImplContainer(impl_id),
         provided_source
     )
 }
index cb0244bb610b2c6a6f87f4ae0950a70676eac23a..63317d4ca5c91bb04915e3cd9e734475684ea767 100644 (file)
@@ -32,7 +32,8 @@
 
 
 use metadata::csearch;
-use middle::ty::{substs, ty_param_bounds_and_ty};
+use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs};
+use middle::ty::{ty_param_bounds_and_ty};
 use middle::ty;
 use middle::subst::Subst;
 use middle::typeck::astconv::{AstConv, ty_of_arg};
@@ -388,7 +389,7 @@ fn ty_method_of_trait_method(this: &CrateCtxt,
             // assume public, because this is only invoked on trait methods
             ast::public,
             local_def(*m_id),
-            local_def(trait_id),
+            TraitContainer(local_def(trait_id)),
             None
         )
     }
@@ -744,7 +745,7 @@ pub struct ConvertedMethod {
 }
 
 pub fn convert_methods(ccx: &CrateCtxt,
-                       container_id: ast::NodeId,
+                       container: MethodContainer,
                        ms: &[@ast::method],
                        untransformed_rcvr_ty: ty::t,
                        rcvr_ty_generics: &ty::Generics,
@@ -758,11 +759,14 @@ pub fn convert_methods(ccx: &CrateCtxt,
         let m_ty_generics =
             ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics,
                         num_rcvr_ty_params);
-        let mty =
-            @ty_of_method(ccx, container_id, *m, rcvr_ty_generics.region_param,
-                          untransformed_rcvr_ty,
-                          rcvr_ast_generics, rcvr_visibility,
-                          &m.generics);
+        let mty = @ty_of_method(ccx,
+                                container,
+                                *m,
+                                rcvr_ty_generics.region_param,
+                                untransformed_rcvr_ty,
+                                rcvr_ast_generics,
+                                rcvr_visibility,
+                                &m.generics);
         let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
         tcx.tcache.insert(
             local_def(m.id),
@@ -785,7 +789,7 @@ pub fn convert_methods(ccx: &CrateCtxt,
     }).collect();
 
     fn ty_of_method(ccx: &CrateCtxt,
-                    container_id: ast::NodeId,
+                    container: MethodContainer,
                     m: &ast::method,
                     rp: Option<ty::region_variance>,
                     untransformed_rcvr_ty: ty::t,
@@ -817,7 +821,7 @@ fn ty_of_method(ccx: &CrateCtxt,
             m.explicit_self.node,
             method_vis,
             local_def(m.id),
-            local_def(container_id),
+            container,
             None
         )
     }
@@ -877,8 +881,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
             it.vis
         };
 
-        let cms = convert_methods(ccx, it.id, *ms, selfty,
-                                  &i_ty_generics, generics,
+        let cms = convert_methods(ccx,
+                                  ImplContainer(local_def(it.id)),
+                                  *ms,
+                                  selfty,
+                                  &i_ty_generics,
+                                  generics,
                                   parent_visibility);
         for t in opt_trait_ref.iter() {
             // Prevent the builtin kind traits from being manually implemented.
@@ -901,9 +909,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
           let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id));
           let (ty_generics, _) = mk_item_substs(ccx, generics, rp,
                                                 Some(untransformed_rcvr_ty));
-          let _ = convert_methods(ccx, it.id, provided_methods,
+          let _ = convert_methods(ccx,
+                                  TraitContainer(local_def(it.id)),
+                                  provided_methods,
                                   untransformed_rcvr_ty,
-                                  &ty_generics, generics,
+                                  &ty_generics,
+                                  generics,
                                   it.vis);
 
           // We need to do this *after* converting methods, since
index 2e337f5f57b74b465d49c8ac5699b1963955a551..86c0736090c937e1a36a88b5cf00fd2517c276c8 100644 (file)
@@ -21,7 +21,7 @@
 use middle::typeck::infer::{TypeTrace, Subtype};
 use middle::typeck::infer::fold_regions_in_sig;
 use middle::typeck::isr_alist;
-use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl};
+use syntax::ast::{Many, Once, extern_fn, impure_fn, m_imm, m_mutbl};
 use syntax::ast::{unsafe_fn};
 use syntax::ast::{Onceness, purity};
 use util::common::{indenter};
@@ -52,16 +52,6 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
         match (a.mutbl, b.mutbl) {
           // If one side or both is mut, then the GLB must use
           // the precise type from the mut side.
-          (m_mutbl, m_const) => {
-            Sub(**self).tys(a.ty, b.ty).chain(|_t| {
-                Ok(ty::mt {ty: a.ty, mutbl: m_mutbl})
-            })
-          }
-          (m_const, m_mutbl) => {
-            Sub(**self).tys(b.ty, a.ty).chain(|_t| {
-                Ok(ty::mt {ty: b.ty, mutbl: m_mutbl})
-            })
-          }
           (m_mutbl, m_mutbl) => {
             eq_tys(self, a.ty, b.ty).then(|| {
                 Ok(ty::mt {ty: a.ty, mutbl: m_mutbl})
@@ -70,22 +60,12 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
 
           // If one side or both is immutable, we can use the GLB of
           // both sides but mutbl must be `m_imm`.
-          (m_imm, m_const) |
-          (m_const, m_imm) |
           (m_imm, m_imm) => {
             self.tys(a.ty, b.ty).chain(|t| {
                 Ok(ty::mt {ty: t, mutbl: m_imm})
             })
           }
 
-          // If both sides are const, then we can use GLB of both
-          // sides and mutbl of only `m_const`.
-          (m_const, m_const) => {
-            self.tys(a.ty, b.ty).chain(|t| {
-                Ok(ty::mt {ty: t, mutbl: m_const})
-            })
-          }
-
           // There is no mutual subtype of these combinations.
           (m_mutbl, m_imm) |
           (m_imm, m_mutbl) => {
index 4f38e2aaac6b6f524e78a5bec325647a4e58b59b..50bddaacc3fc98a95b47c83e15baeb0d42e777bb 100644 (file)
@@ -24,7 +24,7 @@
 use util::ppaux::mt_to_str;
 
 use extra::list;
-use syntax::ast::{Many, Once, extern_fn, m_const, impure_fn};
+use syntax::ast::{Many, Once, extern_fn, impure_fn};
 use syntax::ast::{unsafe_fn};
 use syntax::ast::{Onceness, purity};
 
@@ -55,14 +55,13 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
                mt_to_str(tcx, a),
                mt_to_str(tcx, b));
 
-        let m = if a.mutbl == b.mutbl {
-            a.mutbl
-        } else {
-            m_const
-        };
+        if a.mutbl != b.mutbl {
+            return Err(ty::terr_mutability)
+        }
 
+        let m = a.mutbl;
         match m {
-          m_imm | m_const => {
+          m_imm => {
             self.tys(a.ty, b.ty).chain(|t| Ok(ty::mt {ty: t, mutbl: m}) )
           }
 
@@ -71,11 +70,7 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
                 eq_tys(self, a.ty, b.ty).then(|| {
                     Ok(ty::mt {ty: a.ty, mutbl: m})
                 })
-            }).chain_err(|_e| {
-                self.tys(a.ty, b.ty).chain(|t| {
-                    Ok(ty::mt {ty: t, mutbl: m_const})
-                })
-            })
+            }).chain_err(|e| Err(e))
           }
         }
     }
index 5a4ea1c9f1f58e3f56c3b228d1fb121a268769ce..a00f018ceab0fdf650e5c93c3525b29060cad261 100644 (file)
@@ -26,7 +26,7 @@
 
 use extra::list::Nil;
 use extra::list;
-use syntax::ast::{Onceness, m_const, purity};
+use syntax::ast::{Onceness, purity};
 
 pub struct Sub(CombineFields);  // "subtype", "subregion" etc
 
@@ -67,7 +67,7 @@ fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
     fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
         debug!("mts(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx));
 
-        if a.mutbl != b.mutbl && b.mutbl != m_const {
+        if a.mutbl != b.mutbl {
             return Err(ty::terr_mutability);
         }
 
@@ -77,7 +77,7 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
             // (i.e., invariant if mut):
             eq_tys(self, a.ty, b.ty).then(|| Ok(*a))
           }
-          m_imm | m_const => {
+          m_imm => {
             // Otherwise we can be covariant:
             self.tys(a.ty, b.ty).chain(|_t| Ok(*a) )
           }
index 33407c91bcc23b1a7a034cb305514b5b83dcde2e..06b3f6aae2710b142f11e20b24d16e6b2e85e7fd 100644 (file)
@@ -92,7 +92,6 @@ pub mod back {
     pub mod x86_64;
     pub mod rpath;
     pub mod target_strs;
-    pub mod passes;
 }
 
 pub mod metadata;
@@ -232,7 +231,7 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
     }
 
     if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
-        back::passes::list_passes();
+        unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
         return;
     }
 
index 0fdcac26ac878fd57af887706f1d85febcdfdf6d..3549323cf085f91d3840633333ab7be3f33c3786 100644 (file)
@@ -239,7 +239,6 @@ fn mutability_to_str(m: ast::mutability) -> ~str {
     match m {
         ast::m_mutbl => ~"mut ",
         ast::m_imm => ~"",
-        ast::m_const => ~"const "
     }
 }
 
index c13e85ea71659724ac3b46102a5b905125f458a2..635d02196fe47fdbec14beed9bdad5a7ee624402 100644 (file)
@@ -104,14 +104,14 @@ fn pandoc_writer(
     ];
 
     do generic_writer |markdown| {
-        use std::io::WriterUtil;
-
         debug!("pandoc cmd: %s", pandoc_cmd);
         debug!("pandoc args: %s", pandoc_args.connect(" "));
 
-        let mut proc = run::Process::new(pandoc_cmd, pandoc_args, run::ProcessOptions::new());
+        let proc = run::Process::new(pandoc_cmd, pandoc_args,
+                                     run::ProcessOptions::new());
+        let mut proc = proc.unwrap();
 
-        proc.input().write_str(markdown);
+        proc.input().write(markdown.as_bytes());
         let output = proc.finish_with_output();
 
         debug!("pandoc result: %i", output.status);
index 2dbd054ef60bcbae27d49a3dedc30eca2b3201c3..467477ca479de6fe97e2aac3f2424a31c62f4ee7 100644 (file)
@@ -49,6 +49,9 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) }
 /// True if there's a directory in <workspace> with
 /// pkgid's short name
 pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
+    debug!("Checking in src dir of %s for %s",
+           workspace.to_str(), pkgid.to_str());
+
     let src_dir = workspace.push("src");
 
     let mut found = false;
@@ -81,6 +84,9 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
         }
         true
     };
+
+    debug!(if found { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
+           else     { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
     found
 }
 
index f5dc17851e5ccfca90696e771cf3ddafea019972..79836bcc5554bf2819b7242f89dc6e761065f849 100644 (file)
@@ -43,7 +43,7 @@
 use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
 use path_util::{target_executable_in_workspace, target_library_in_workspace};
 use source_control::is_git_dir;
-use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, in_workspace, cwd_to_workspace};
+use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
 use context::Ctx;
 use package_id::PkgId;
 use package_source::PkgSrc;
@@ -190,11 +190,10 @@ fn run(&self, cmd: &str, args: ~[~str]) {
         match cmd {
             "build" => {
                 if args.len() < 1 {
-                    if !in_workspace(|| { usage::build() } ) {
-                        return;
+                    match cwd_to_workspace() {
+                        None => { usage::build(); return }
+                        Some((ws, pkgid)) => self.build(&ws, &pkgid)
                     }
-                    let (workspace, pkgid) = cwd_to_workspace();
-                    self.build(&workspace, &pkgid);
                 }
                 else {
                     // The package id is presumed to be the first command-line
@@ -210,13 +209,12 @@ fn run(&self, cmd: &str, args: ~[~str]) {
             }
             "clean" => {
                 if args.len() < 1 {
-                    if !in_workspace(|| { usage::clean() } ) {
-                        return;
+                    match cwd_to_workspace() {
+                        None => { usage::clean(); return }
+                        // tjc: Maybe clean should clean all the packages in the
+                        // current workspace, though?
+                        Some((ws, pkgid)) => self.clean(&ws, &pkgid)
                     }
-                    // tjc: Maybe clean should clean all the packages in the
-                    // current workspace, though?
-                    let (workspace, pkgid) = cwd_to_workspace();
-                    self.clean(&workspace, &pkgid);
 
                 }
                 else {
@@ -239,17 +237,18 @@ fn run(&self, cmd: &str, args: ~[~str]) {
             }
             "install" => {
                 if args.len() < 1 {
-                    if !in_workspace(|| { usage::install() }) {
-                        return;
+                    match cwd_to_workspace() {
+                        None => { usage::install(); return }
+                        Some((ws, pkgid)) => self.install(&ws, &pkgid)
                     }
-                    let (workspace, pkgid) = cwd_to_workspace();
-                    self.install(&workspace, &pkgid);
                 }
                 else {
                     // The package id is presumed to be the first command-line
                     // argument
                     let pkgid = PkgId::new(args[0]);
                     let workspaces = pkg_parent_workspaces(&pkgid);
+                    debug!("package ID = %s, found it in %? workspaces",
+                           pkgid.to_str(), workspaces.len());
                     if workspaces.is_empty() {
                         let rp = rust_path();
                         assert!(!rp.is_empty());
@@ -473,7 +472,8 @@ pub fn main() {
 pub fn main_args(args: &[~str]) {
     let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
                  getopts::optflag("j"), getopts::optflag("json"),
-                 getopts::optmulti("c"), getopts::optmulti("cfg")];
+                 getopts::optmulti("c"), getopts::optmulti("cfg"),
+                 getopts::optflag("v"), getopts::optflag("version")];
     let matches = &match getopts::getopts(args, opts) {
         result::Ok(m) => m,
         result::Err(f) => {
@@ -486,6 +486,13 @@ pub fn main_args(args: &[~str]) {
                getopts::opt_present(matches, "help");
     let json = getopts::opt_present(matches, "j") ||
                getopts::opt_present(matches, "json");
+
+    if getopts::opt_present(matches, "v") ||
+       getopts::opt_present(matches, "version") {
+        rustc::version(args[0]);
+        return;
+    }
+
     let mut args = matches.free.clone();
 
     args.shift();
index ea0389fed7727a0810075dba598d388321717ea5..9862f870bcafb0a6d1afbe603c43837458d656c9 100644 (file)
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use path_util::installed_library_in_workspace;
+use path_util::{installed_library_in_workspace, rust_path};
+use version::Version;
 
 /// If a library with path `p` matching pkg_id's name exists under sroot_opt,
 /// return Some(p). Return None if there's no such path or if sroot_opt is None.
@@ -19,3 +20,18 @@ pub fn find_library_in_search_path(sroot_opt: Option<@Path>, short_name: &str) -
         installed_library_in_workspace(short_name, sroot)
     }
 }
+
+/// If some workspace `p` in the RUST_PATH contains a package matching short_name,
+/// return Some(p) (returns the first one of there are multiple matches.) Return
+/// None if there's no such path.
+/// FIXME #8711: This ignores the desired version.
+pub fn find_installed_library_in_rust_path(short_name: &str, _version: &Version) -> Option<Path> {
+    let rp = rust_path();
+    for p in rp.iter() {
+        match installed_library_in_workspace(short_name, p) {
+            Some(path) => return Some(path),
+            None => ()
+        }
+    }
+    None
+}
index caa004a53b22879363807268745510a0926659bf..c67a81581393d977e5b5040fafbdc39237c89364 100644 (file)
@@ -89,7 +89,7 @@ pub fn git_clone_general(source: &str, target: &Path, v: &Version) -> bool {
 
 fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput {
     let mut prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
-                                ,..ProcessOptions::new()});
+                                ,..ProcessOptions::new()}).unwrap();
     prog.finish_with_output()
 }
 
index 0efa0782da902629c87ac4173fc7a8b75a1ce57f..b0d996ea0afa81d126c6644c0c888b6bbd98a374 100644 (file)
 use installed_packages::list_installed_packages;
 use package_id::{PkgId};
 use version::{ExactRevision, NoVersion, Version, Tagged};
-use path_util::{target_executable_in_workspace, target_library_in_workspace,
-               target_test_in_workspace, target_bench_in_workspace,
-               make_dir_rwx, U_RWX, library_in_workspace,
+use path_util::{target_executable_in_workspace, target_test_in_workspace,
+               target_bench_in_workspace, make_dir_rwx, U_RWX,
+               library_in_workspace, installed_library_in_workspace,
                built_bench_in_workspace, built_test_in_workspace,
-               built_library_in_workspace, built_executable_in_workspace,
-                installed_library_in_workspace};
+               built_library_in_workspace, built_executable_in_workspace};
 use rustc::metadata::filesearch::rust_path;
 use rustc::driver::driver::host_triple;
 use target::*;
@@ -113,13 +112,14 @@ fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path {
 
 fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) {
     let cwd = (*cwd).clone();
-    let mut prog = run::Process::new("git", args, run::ProcessOptions {
+    let prog = run::Process::new("git", args, run::ProcessOptions {
         env: env,
         dir: Some(&cwd),
         in_fd: None,
         out_fd: None,
         err_fd: None
     });
+    let mut prog = prog.unwrap();
     let rslt = prog.finish_with_output();
     if rslt.status != 0 {
         fail!("%s [git returned %?, output = %s, error = %s]", err_msg,
@@ -227,7 +227,7 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
         in_fd: None,
         out_fd: None,
         err_fd: None
-    });
+    }).unwrap();
     let output = prog.finish_with_output();
     debug!("Output from command %s with args %? was %s {%s}[%?]",
                     cmd, args, str::from_bytes(output.output),
@@ -686,7 +686,7 @@ fn package_script_with_default_build() {
         push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
     debug!("package_script_with_default_build: %s", source.to_str());
     if !os::copy_file(&source,
-                      & dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
+                      &dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
         fail!("Couldn't copy file");
     }
     command_line_test([~"install", ~"fancy-lib"], &dir);
@@ -696,7 +696,8 @@ fn package_script_with_default_build() {
 
 #[test]
 fn rustpkg_build_no_arg() {
-    let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed");
+    let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed")
+              .push(".rust");
     let package_dir = tmp.push("src").push("foo");
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
 
@@ -710,7 +711,8 @@ fn rustpkg_build_no_arg() {
 #[test]
 fn rustpkg_install_no_arg() {
     let tmp = mkdtemp(&os::tmpdir(),
-                      "rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed");
+                      "rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed")
+              .push(".rust");
     let package_dir = tmp.push("src").push("foo");
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
     writeFile(&package_dir.push("lib.rs"),
@@ -722,7 +724,8 @@ fn rustpkg_install_no_arg() {
 
 #[test]
 fn rustpkg_clean_no_arg() {
-    let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed");
+    let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed")
+              .push(".rust");
     let package_dir = tmp.push("src").push("foo");
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
 
@@ -890,20 +893,28 @@ fn no_rebuilding_dep() {
     assert!(bar_date < foo_date);
 }
 
+// n.b. The following two tests are ignored; they worked "accidentally" before,
+// when the behavior was "always rebuild libraries" (now it's "never rebuild
+// libraries if they already exist"). They can be un-ignored once #7075 is done.
 #[test]
+#[ignore(reason = "Workcache not yet implemented -- see #7075")]
 fn do_rebuild_dep_dates_change() {
     let p_id = PkgId::new("foo");
     let dep_id = PkgId::new("bar");
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     command_line_test([~"build", ~"foo"], &workspace);
-    let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+    let bar_lib_name = lib_output_file_name(&workspace, "build", "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);
     command_line_test([~"build", ~"foo"], &workspace);
-    let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+    let new_bar_date = datestamp(&bar_lib_name);
+    debug!("Datestamp on %s is %?", bar_lib_name.to_str(), new_bar_date);
     assert!(new_bar_date > bar_date);
 }
 
 #[test]
+#[ignore(reason = "Workcache not yet implemented -- see #7075")]
 fn do_rebuild_dep_only_contents_change() {
     let p_id = PkgId::new("foo");
     let dep_id = PkgId::new("bar");
@@ -1017,16 +1028,17 @@ fn test_extern_mod() {
                      test_sysroot().to_str(),
                      exec_file.to_str());
 
-    let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
-                                                      ~"--sysroot", test_sysroot().to_str(),
-                                               ~"-o", exec_file.to_str()],
-                                     run::ProcessOptions {
+    let prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
+                                                  ~"--sysroot", test_sysroot().to_str(),
+                                                  ~"-o", exec_file.to_str()],
+                                 run::ProcessOptions {
         env: env,
         dir: Some(&dir),
         in_fd: None,
         out_fd: None,
         err_fd: None
     });
+    let mut prog = prog.unwrap();
     let outp = prog.finish_with_output();
     if outp.status != 0 {
         fail!("output was %s, error was %s",
@@ -1060,6 +1072,23 @@ fn test_macro_pkg_script() {
         os::EXE_SUFFIX))));
 }
 
+#[test]
+fn multiple_workspaces() {
+// Make a package foo; build/install in directory A
+// Copy the exact same package into directory B and install it
+// Set the RUST_PATH to A:B
+// Make a third package that uses foo, make sure we can build/install it
+    let a_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
+    let b_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
+    debug!("Trying to install foo in %s", a_loc.to_str());
+    command_line_test([~"install", ~"foo"], &a_loc);
+    debug!("Trying to install foo in %s", b_loc.to_str());
+    command_line_test([~"install", ~"foo"], &b_loc);
+    let env = Some(~[(~"RUST_PATH", fmt!("%s:%s", a_loc.to_str(), b_loc.to_str()))]);
+    let c_loc = create_local_package_with_dep(&PkgId::new("bar"), &PkgId::new("foo"));
+    command_line_test_with_env([~"install", ~"bar"], &c_loc, env);
+}
+
 /// Returns true if p exists and is executable
 fn is_executable(p: &Path) -> bool {
     use std::libc::consts::os::posix88::{S_IXUSR};
index 41c1c7e31aeff82eb7503c354e1ee3af0dc647c1..4bdb442c1e61920d98287fb985f3de1178e75dc8 100644 (file)
 use rustc::driver::session::{lib_crate, bin_crate};
 use context::{Ctx, in_target};
 use package_id::PkgId;
-use search::find_library_in_search_path;
+use search::{find_library_in_search_path, find_installed_library_in_rust_path};
 use path_util::{target_library_in_workspace, U_RWX};
 pub use target::{OutputType, Main, Lib, Bench, Test};
+use version::NoVersion;
 
 // 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
@@ -360,18 +361,32 @@ pub fn find_and_install_dependencies(ctxt: &Ctx,
                         debug!("It exists: %s", installed_path.to_str());
                     }
                     None => {
-                        // Try to install it
-                        let pkg_id = PkgId::new(lib_name);
-                        my_ctxt.install(&my_workspace, &pkg_id);
-                        // Also, add an additional search path
-                        debug!("let installed_path...")
-                        let installed_path = target_library_in_workspace(&pkg_id,
+                        // FIXME #8711: need to parse version out of path_opt
+                        match find_installed_library_in_rust_path(lib_name, &NoVersion) {
+                            Some(installed_path) => {
+                               debug!("Found library %s, not rebuilding it",
+                                      installed_path.to_str());
+                               // Once workcache is implemented, we'll actually check
+                               // whether or not the library at installed_path is fresh
+                               save(installed_path.pop());
+                            }
+                            None => {
+                               debug!("Trying to install library %s, rebuilding it",
+                                      lib_name.to_str());
+                               // Try to install it
+                               let pkg_id = PkgId::new(lib_name);
+                               my_ctxt.install(&my_workspace, &pkg_id);
+                               // Also, add an additional search path
+                               debug!("let installed_path...")
+                               let installed_path = target_library_in_workspace(&pkg_id,
                                                                          &my_workspace).pop();
-                        debug!("Great, I installed %s, and it's in %s",
-                               lib_name, installed_path.to_str());
-                        save(installed_path);
+                               debug!("Great, I installed %s, and it's in %s",
+                                   lib_name, installed_path.to_str());
+                               save(installed_path);
+                           }
                     }
                 }
+              }
             }
             // Ignore `use`s
             _ => ()
index f8658517cdff4d84b2590edb5bb618553cf711ad..4528a02db19785502de817c9483636c59d25f7c5 100644 (file)
@@ -213,11 +213,9 @@ fn is_url_like(p: &Path) -> bool {
 pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
     // Check for extra '#' characters separately
     if s.split_iter('#').len() > 2 {
-        None
-    }
-    else {
-        split_version_general(s, '#')
+        return None;
     }
+    split_version_general(s, '#')
 }
 
 pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {
index 6ac959e4a3260fc8c4e97628f1322037ecf160e8..1afe5d513cc14e2496c84e94518200704cb9e66f 100644 (file)
 
 // rustpkg utilities having to do with workspaces
 
-use std::os;
+use std::{os,util};
 use std::path::Path;
 use path_util::workspace_contains_package_id;
 use package_id::PkgId;
 
-use rustc::metadata::filesearch::rust_path;
+use path_util::rust_path;
 
 pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
     // Using the RUST_PATH, find workspaces that contain
@@ -42,23 +42,22 @@ pub fn pkg_parent_workspaces(pkgid: &PkgId) -> ~[Path] {
         .collect()
 }
 
-pub fn in_workspace(complain: &fn()) -> bool {
-    let dir_part = os::getcwd().pop().components.clone();
-    if  *(dir_part.last()) != ~"src" {
-        complain();
-        false
-    }
-    else {
-        true
-    }
-}
-
 /// Construct a workspace and package-ID name based on the current directory.
 /// This gets used when rustpkg gets invoked without a package-ID argument.
-pub fn cwd_to_workspace() -> (Path, PkgId) {
+pub fn cwd_to_workspace() -> Option<(Path, PkgId)> {
     let cwd = os::getcwd();
-    let ws = cwd.pop().pop();
-    let cwd_ = cwd.clone();
-    let pkgid = cwd_.components.last().to_str();
-    (ws, PkgId::new(pkgid))
+    for path in rust_path().move_iter() {
+        let srcpath = path.push("src");
+        if srcpath.is_ancestor_of(&cwd) {
+            // I'd love to use srcpath.get_relative_to(cwd) but it behaves wrong
+            // I'd say broken, but it has tests enforcing the wrong behavior.
+            // instead, just hack up the components vec
+            let mut pkgid = cwd;
+            pkgid.is_absolute = false;
+            let comps = util::replace(&mut pkgid.components, ~[]);
+            pkgid.components = comps.move_iter().skip(srcpath.components.len()).collect();
+            return Some((path, PkgId::new(pkgid.components.connect("/"))))
+        }
+    }
+    None
 }
index d001e2c6970f89a39b9037195b4a995697c22c6e..c192803efffa94576f51e3805f6341f106db8bf2 100644 (file)
@@ -276,7 +276,7 @@ fn local_realloc(ptr: *(), size: uint) -> *() {
             use rt::local::Local;
             use rt::task::Task;
 
-            do Local::borrow::<Task, *()> |task| {
+            do Local::borrow |task: &mut Task| {
                 task.heap.realloc(ptr as *libc::c_void, size) as *()
             }
         }
index df2fe70ff0e12a9d97abad9682debece3938edcb..70b04e37ee1ff3785de55096c1f9c56fb773073a 100644 (file)
@@ -179,7 +179,7 @@ fn to_c_str(&self) -> CString {
         do cs.with_mut_ref |buf| {
             for i in range(0, self.len()) {
                 unsafe {
-                    let p = buf.offset_inbounds(i as int);
+                    let p = buf.offset(i as int);
                     if *p == 0 {
                         match null_byte::cond.raise(self.to_owned()) {
                             Truncate => break,
@@ -222,7 +222,7 @@ fn next(&mut self) -> Option<libc::c_char> {
         if ch == 0 {
             None
         } else {
-            self.ptr = ptr::offset(self.ptr, 1);
+            self.ptr = unsafe { ptr::offset(self.ptr, 1) };
             Some(ch)
         }
     }
index 825d0147c80e2f669a27ebcbab0ead46769f3a11..a4e18d98f47ea6c90209ef76183942a09f700bca 100644 (file)
@@ -10,6 +10,7 @@
 
 //! Unsafe casting functions
 
+use ptr::RawPtr;
 use sys;
 use unstable::intrinsics;
 
@@ -94,13 +95,13 @@ pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
 
 /// Coerce an immutable reference to be mutable.
 #[inline]
-pub unsafe fn transmute_mut_unsafe<T>(ptr: *const T) -> *mut T {
+pub unsafe fn transmute_mut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *mut T {
     transmute(ptr)
 }
 
 /// Coerce an immutable reference to be mutable.
 #[inline]
-pub unsafe fn transmute_immut_unsafe<T>(ptr: *const T) -> *T {
+pub unsafe fn transmute_immut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *T {
     transmute(ptr)
 }
 
index f9f5b66acb60dcc4ef3de90dfb0cfd140a457b26..a1459b780dfb3cd204d4d47bc8f1d04eb2da374e 100644 (file)
@@ -100,7 +100,7 @@ fn test_basic() {
 #[test]
 #[should_fail]
 fn test_take_empty() {
-    let value_cell = Cell::new_empty::<~int>();
+    let value_cell: Cell<~int> = Cell::new_empty();
     value_cell.take();
 }
 
index 6a6ba12bae301bf9825f4b3afc75bdf9aefd7c17..6b982ec75da126255f7bc8545bfad0920f969b8c 100644 (file)
@@ -11,7 +11,7 @@
 #[doc(hidden)];
 
 use libc::c_void;
-use ptr::{mut_null};
+use ptr::null;
 use unstable::intrinsics::TyDesc;
 use unstable::raw;
 
@@ -37,7 +37,7 @@ unsafe fn each_live_alloc(read_next_before: bool,
     use rt::local_heap;
 
     let mut box = local_heap::live_allocs();
-    while box != mut_null() {
+    while box != null() {
         let next_before = (*box).next;
         let uniq = (*box).ref_count == managed::RC_MANAGED_UNIQUE;
 
diff --git a/src/libstd/default.rs b/src/libstd/default.rs
new file mode 100644 (file)
index 0000000..fbc60ff
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The Default trait
+
+/// A trait that types which have a useful default value should implement.
+pub trait Default {
+    /// Return the "default value" for a type.
+    fn default() -> Self;
+}
index db8a17c0bd07099b52e702ef6a377e4f25ce6ef0..cdce69f7cd760a05a9c684b6621607a81aef3845 100644 (file)
 
 # The Formatting Module
 
-This module contains the runtime support for the `ifmt!` syntax extension. This
+This module contains the runtime support for the `format!` syntax extension. This
 macro is implemented in the compiler to emit calls to this module in order to
 format arguments at runtime into strings and streams.
 
 The functions contained in this module should not normally be used in everyday
-use cases of `ifmt!`. The assumptions made by these functions are unsafe for all
+use cases of `format!`. The assumptions made by these functions are unsafe for all
 inputs, and the compiler performs a large amount of validation on the arguments
-to `ifmt!` in order to ensure safety at runtime. While it is possible to call
+to `format!` in order to ensure safety at runtime. While it is possible to call
 these functions directly, it is not recommended to do so in the general case.
 
 ## Usage
 
-The `ifmt!` macro is intended to be familiar to those coming from C's
-printf/sprintf functions or Python's `str.format` function. In its current
-revision, the `ifmt!` macro returns a `~str` type which is the result of the
+The `format!` macro is intended to be familiar to those coming from C's
+printf/fprintf functions or Python's `str.format` function. In its current
+revision, the `format!` macro returns a `~str` type which is the result of the
 formatting. In the future it will also be able to pass in a stream to format
 arguments directly while performing minimal allocations.
 
-Some examples of the `ifmt!` extension are:
+Some examples of the `format!` extension are:
 
 ~~~{.rust}
-ifmt!("Hello")                  // => ~"Hello"
-ifmt!("Hello, {:s}!", "world")  // => ~"Hello, world!"
-ifmt!("The number is {:d}", 1)  // => ~"The number is 1"
-ifmt!("{}", ~[3, 4])            // => ~"~[3, 4]"
-ifmt!("{value}", value=4)       // => ~"4"
-ifmt!("{} {}", 1, 2)            // => ~"1 2"
+format!("Hello")                  // => ~"Hello"
+format!("Hello, {:s}!", "world")  // => ~"Hello, world!"
+format!("The number is {:d}", 1)  // => ~"The number is 1"
+format!("{}", ~[3, 4])            // => ~"~[3, 4]"
+format!("{value}", value=4)       // => ~"4"
+format!("{} {}", 1, 2)            // => ~"1 2"
 ~~~
 
 From these, you can see that the first argument is a format string. It is
@@ -62,7 +62,7 @@
 ### Named parameters
 
 Rust itself does not have a Python-like equivalent of named parameters to a
-function, but the `ifmt!` macro is a syntax extension which allows it to
+function, but the `format!` macro is a syntax extension which allows it to
 leverage named parameters. Named parameters are listed at the end of the
 argument list and have the syntax:
 
 
 ## Internationalization
 
-The formatting syntax supported by the `ifmt!` extension supports
+The formatting syntax supported by the `format!` extension supports
 internationalization by providing "methods" which execute various different
 outputs depending on the input. The syntax and methods provided are similar to
 other internationalization systems, so again nothing should seem alien.
 example:
 
 ~~~
-ifmt!("{0, select, other{#}}", "hello") // => ~"hello"
+format!("{0, select, other{#}}", "hello") // => ~"hello"
 ~~~
 
 This example is the equivalent of `{0:s}` essentially.
@@ -399,7 +399,44 @@ pub struct Argument<'self> {
 #[allow(missing_doc)]
 pub trait Float { fn fmt(&Self, &mut Formatter); }
 
-/// The sprintf function takes a precompiled format string and a list of
+/// The `write` function takes an output stream, a precompiled format string,
+/// and a list of arguments. The arguments will be formatted according to the
+/// specified format string into the output stream provided.
+///
+/// See the documentation for `format` for why this function is unsafe and care
+/// should be taken if calling it manually.
+///
+/// Thankfully the rust compiler provides the macro `fmtf!` which will perform
+/// all of this validation at compile-time and provides a safe interface for
+/// invoking this function.
+///
+/// # Arguments
+///
+///   * output - the buffer to write output to
+///   * fmts - the precompiled format string to emit
+///   * args - the list of arguments to the format string. These are only the
+///            positional arguments (not named)
+///
+/// Note that this function assumes that there are enough arguments for the
+/// format string.
+pub unsafe fn write(output: &mut io::Writer,
+                    fmt: &[rt::Piece], args: &[Argument]) {
+    let mut formatter = Formatter {
+        flags: 0,
+        width: None,
+        precision: None,
+        buf: output,
+        align: parse::AlignUnknown,
+        fill: ' ',
+        args: args,
+        curarg: args.iter(),
+    };
+    for piece in fmt.iter() {
+        formatter.run(piece, None);
+    }
+}
+
+/// The format function takes a precompiled format string and a list of
 /// arguments, to return the resulting formatted string.
 ///
 /// This is currently an unsafe function because the types of all arguments
@@ -409,7 +446,7 @@ pub struct Argument<'self> {
 /// for formatting the right type value. Because of this, the function is marked
 /// as `unsafe` if this is being called manually.
 ///
-/// Thankfully the rust compiler provides the macro `ifmt!` which will perform
+/// Thankfully the rust compiler provides the macro `format!` which will perform
 /// all of this validation at compile-time and provides a safe interface for
 /// invoking this function.
 ///
@@ -421,24 +458,9 @@ pub struct Argument<'self> {
 ///
 /// Note that this function assumes that there are enough arguments for the
 /// format string.
-pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
-    let output = MemWriter::new();
-    {
-        let mut formatter = Formatter {
-            flags: 0,
-            width: None,
-            precision: None,
-            // FIXME(#8248): shouldn't need a transmute
-            buf: cast::transmute(&output as &io::Writer),
-            align: parse::AlignUnknown,
-            fill: ' ',
-            args: args,
-            curarg: args.iter(),
-        };
-        for piece in fmt.iter() {
-            formatter.run(piece, None);
-        }
-    }
+pub unsafe fn format(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
+    let mut output = MemWriter::new();
+    write(&mut output as &mut io::Writer, fmt, args);
     return str::from_bytes_owned(output.inner());
 }
 
@@ -446,7 +468,7 @@ impl<'self> Formatter<'self> {
 
     // First up is the collection of functions used to execute a format string
     // at runtime. This consumes all of the compile-time statics generated by
-    // the ifmt! syntax extension.
+    // the format! syntax extension.
 
     fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) {
         let setcount = |slot: &mut Option<uint>, cnt: &parse::Count| {
@@ -710,7 +732,7 @@ fn with_padding(&mut self, padding: uint,
 }
 
 /// This is a function which calls are emitted to by the compiler itself to
-/// create the Argument structures that are passed into the `sprintf` function.
+/// create the Argument structures that are passed into the `format` function.
 #[doc(hidden)]
 pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
                        t: &'a T) -> Argument<'a> {
@@ -862,10 +884,17 @@ fn fmt(t: &T, f: &mut Formatter) {
     }
 }
 
-// n.b. use 'const' to get an implementation for both '*mut' and '*' at the same
-//      time.
-impl<T> Pointer for *const T {
-    fn fmt(t: &*const T, f: &mut Formatter) {
+impl<T> Pointer for *T {
+    fn fmt(t: &*T, f: &mut Formatter) {
+        f.flags |= 1 << (parse::FlagAlternate as uint);
+        do ::uint::to_str_bytes(*t as uint, 16) |buf| {
+            f.pad_integral(buf, "0x", true);
+        }
+    }
+}
+
+impl<T> Pointer for *mut T {
+    fn fmt(t: &*mut T, f: &mut Formatter) {
         f.flags |= 1 << (parse::FlagAlternate as uint);
         do ::uint::to_str_bytes(*t as uint, 16) |buf| {
             f.pad_integral(buf, "0x", true);
@@ -901,8 +930,12 @@ fn fmt(me: &$ty, f: &mut Formatter) {
 delegate!(f32 to Float)
 delegate!(f64 to Float)
 
-impl<T> Default for *const T {
-    fn fmt(me: &*const T, f: &mut Formatter) { Pointer::fmt(me, f) }
+impl<T> Default for *T {
+    fn fmt(me: &*T, f: &mut Formatter) { Pointer::fmt(me, f) }
+}
+
+impl<T> Default for *mut T {
+    fn fmt(me: &*mut T, f: &mut Formatter) { Pointer::fmt(me, f) }
 }
 
 // If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
index 21b7ee321e8db2a1aa63d7d7b56c74879b1dc445..6682a41097925bbcf60aaa00aa1b0d461f021ad7 100644 (file)
@@ -59,14 +59,7 @@ pub trait Hash {
      * IterBytes trait, that feeds SipHash.
      */
     fn hash_keyed(&self, k0: u64, k1: u64) -> u64;
-}
-
-// When we have default methods, won't need this.
-pub trait HashUtil {
-    fn hash(&self) -> u64;
-}
 
-impl<A:Hash> HashUtil for A {
     #[inline]
     fn hash(&self) -> u64 { self.hash_keyed(0,0) }
 }
index 50e59cf438d0c21b46446664d40998497fd9f66d..bcd658ece66532a52401a041b78537c404de14b8 100644 (file)
@@ -869,21 +869,21 @@ fn test_swap() {
 
     #[test]
     fn test_find_or_insert() {
-        let mut m = HashMap::new::<int, int>();
+        let mut m: HashMap<int,int> = HashMap::new();
         assert_eq!(*m.find_or_insert(1, 2), 2);
         assert_eq!(*m.find_or_insert(1, 3), 2);
     }
 
     #[test]
     fn test_find_or_insert_with() {
-        let mut m = HashMap::new::<int, int>();
+        let mut m: HashMap<int,int> = HashMap::new();
         assert_eq!(*m.find_or_insert_with(1, |_| 2), 2);
         assert_eq!(*m.find_or_insert_with(1, |_| 3), 2);
     }
 
     #[test]
     fn test_insert_or_update_with() {
-        let mut m = HashMap::new::<int, int>();
+        let mut m: HashMap<int,int> = HashMap::new();
         assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2);
         assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3);
     }
index 2412ce9daf3c1a569ff929b1ee109249d46d6224..e3f88033bd06bc74296c46e91e9d7b9d97a571ee 100644 (file)
@@ -53,7 +53,7 @@
 use int;
 use iterator::Iterator;
 use libc::consts::os::posix88::*;
-use libc::{c_int, c_long, c_void, size_t, ssize_t};
+use libc::{c_int, c_void, size_t};
 use libc;
 use num;
 use ops::Drop;
@@ -970,7 +970,7 @@ fn seek(&self, offset: int, whence: SeekStyle) {
 
         unsafe {
             assert!(libc::fseek(*self,
-                                     offset as c_long,
+                                     offset as libc::c_long,
                                      convert_whence(whence)) == 0 as c_int);
         }
     }
@@ -1199,7 +1199,7 @@ fn seek(&self, offset: int, whence: SeekStyle) {
 
         unsafe {
             assert!(libc::fseek(*self,
-                                     offset as c_long,
+                                     offset as libc::c_long,
                                      convert_whence(whence)) == 0 as c_int);
         }
     }
@@ -1240,13 +1240,23 @@ impl Writer for fd_t {
     fn write(&self, v: &[u8]) {
         #[fixed_stack_segment]; #[inline(never)];
 
+        #[cfg(windows)]
+        type IoSize = libc::c_uint;
+        #[cfg(windows)]
+        type IoRet = c_int;
+
+        #[cfg(unix)]
+        type IoSize = size_t;
+        #[cfg(unix)]
+        type IoRet = libc::ssize_t;
+
         unsafe {
             let mut count = 0u;
             do v.as_imm_buf |vbuf, len| {
                 while count < len {
                     let vb = ptr::offset(vbuf, count as int) as *c_void;
-                    let nout = libc::write(*self, vb, len as size_t);
-                    if nout < 0 as ssize_t {
+                    let nout = libc::write(*self, vb, len as IoSize);
+                    if nout < 0 as IoRet {
                         error!("error writing buffer");
                         error!("%s", os::last_os_error());
                         fail!();
index 1af49ecd208ec2973181279a9412e2b17afa7fac..4af7b3e242596476ec131209c13d1cdc6540a5f4 100644 (file)
@@ -660,7 +660,10 @@ pub trait AdditiveIterator<A> {
 
 impl<A: Add<A, A> + Zero, T: Iterator<A>> AdditiveIterator<A> for T {
     #[inline]
-    fn sum(&mut self) -> A { self.fold(Zero::zero::<A>(), |s, x| s + x) }
+    fn sum(&mut self) -> A {
+        let zero: A = Zero::zero();
+        self.fold(zero, |s, x| s + x)
+    }
 }
 
 /// A trait for iterators over elements whose elements can be multiplied
@@ -685,7 +688,10 @@ pub trait MultiplicativeIterator<A> {
 
 impl<A: Mul<A, A> + One, T: Iterator<A>> MultiplicativeIterator<A> for T {
     #[inline]
-    fn product(&mut self) -> A { self.fold(One::one::<A>(), |p, x| p * x) }
+    fn product(&mut self) -> A {
+        let one: A = One::one();
+        self.fold(one, |p, x| p * x)
+    }
 }
 
 /// A trait for iterators over elements which can be compared to one another.
index 26b4f15f3e99f4d7fc31b9747d0c3ec800acfad4..790dc886c0497d94f010622fa53d78213ee8cf1e 100644 (file)
@@ -764,6 +764,172 @@ pub struct MEMORY_BASIC_INFORMATION {
                 pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
             }
         }
+
+        #[cfg(target_arch = "x86_64")]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i32;
+                pub type c_ulong = u32;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u64;
+                pub type ptrdiff_t = i64;
+                pub type clock_t = i32;
+                pub type time_t = i64;
+                pub type wchar_t = u16;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = int;
+                pub type uintptr_t = uint;
+            }
+            pub mod posix88 {
+                pub type off_t = i32; // XXX unless _FILE_OFFSET_BITS == 64
+                pub type dev_t = u32;
+                pub type ino_t = i16;
+                pub type pid_t = i64;
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+                pub type ssize_t = i64;
+            }
+            pub mod posix01 {
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+                use ptr;
+                use libc::types::common::c95::c_void;
+                use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t};
+                use libc::types::os::arch::c95::{c_ulong};
+                use libc::types::os::arch::c95::{wchar_t};
+                use libc::types::os::arch::c99::{c_ulonglong};
+
+                pub type BOOL = c_int;
+                pub type BYTE = u8;
+                pub type CCHAR = c_char;
+                pub type CHAR = c_char;
+
+                pub type DWORD = c_ulong;
+                pub type DWORDLONG = c_ulonglong;
+
+                pub type HANDLE = LPVOID;
+                pub type HMODULE = c_uint;
+
+                pub type LONG_PTR = i64; // changed
+
+                pub type LPCWSTR = *WCHAR;
+                pub type LPCSTR = *CHAR;
+                pub type LPCTSTR = *CHAR;
+                pub type LPTCH = *CHAR;
+
+                pub type LPWSTR = *mut WCHAR;
+                pub type LPSTR = *mut CHAR;
+                pub type LPTSTR = *mut CHAR;
+
+                // Not really, but opaque to us.
+                pub type LPSECURITY_ATTRIBUTES = LPVOID;
+
+                pub type LPVOID = *mut c_void;
+                pub type LPCVOID = *c_void;
+                pub type LPBYTE = *mut BYTE;
+                pub type LPWORD = *mut WORD;
+                pub type LPDWORD = *mut DWORD;
+                pub type LPHANDLE = *mut HANDLE;
+
+                pub type LRESULT = LONG_PTR;
+                pub type PBOOL = *mut BOOL;
+                pub type WCHAR = wchar_t;
+                pub type WORD = u16;
+                pub type SIZE_T = size_t;
+
+                pub type time64_t = i64;
+                pub type int64 = i64;
+
+                pub struct STARTUPINFO {
+                    cb: DWORD,
+                    lpReserved: LPTSTR,
+                    lpDesktop: LPTSTR,
+                    lpTitle: LPTSTR,
+                    dwX: DWORD,
+                    dwY: DWORD,
+                    dwXSize: DWORD,
+                    dwYSize: DWORD,
+                    dwXCountChars: DWORD,
+                    dwYCountCharts: DWORD,
+                    dwFillAttribute: DWORD,
+                    dwFlags: DWORD,
+                    wShowWindow: WORD,
+                    cbReserved2: WORD,
+                    lpReserved2: LPBYTE,
+                    hStdInput: HANDLE,
+                    hStdOutput: HANDLE,
+                    hStdError: HANDLE
+                }
+                pub type LPSTARTUPINFO = *mut STARTUPINFO;
+
+                pub struct PROCESS_INFORMATION {
+                    hProcess: HANDLE,
+                    hThread: HANDLE,
+                    dwProcessId: DWORD,
+                    dwThreadId: DWORD
+                }
+                pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
+
+                pub struct SYSTEM_INFO {
+                    wProcessorArchitecture: WORD,
+                    wReserved: WORD,
+                    dwPageSize: DWORD,
+                    lpMinimumApplicationAddress: LPVOID,
+                    lpMaximumApplicationAddress: LPVOID,
+                    dwActiveProcessorMask: DWORD,
+                    dwNumberOfProcessors: DWORD,
+                    dwProcessorType: DWORD,
+                    dwAllocationGranularity: DWORD,
+                    wProcessorLevel: WORD,
+                    wProcessorRevision: WORD
+                }
+                pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
+
+                impl SYSTEM_INFO {
+                    pub fn new() -> SYSTEM_INFO {
+                        SYSTEM_INFO {
+                            wProcessorArchitecture: 0,
+                            wReserved: 0,
+                            dwPageSize: 0,
+                            lpMinimumApplicationAddress: ptr::mut_null(),
+                            lpMaximumApplicationAddress: ptr::mut_null(),
+                            dwActiveProcessorMask: 0,
+                            dwNumberOfProcessors: 0,
+                            dwProcessorType: 0,
+                            dwAllocationGranularity: 0,
+                            wProcessorLevel: 0,
+                            wProcessorRevision: 0
+                        }
+                    }
+                }
+
+                pub struct MEMORY_BASIC_INFORMATION {
+                    BaseAddress: LPVOID,
+                    AllocationBase: LPVOID,
+                    AllocationProtect: DWORD,
+                    RegionSize: SIZE_T,
+                    State: DWORD,
+                    Protect: DWORD,
+                    Type: DWORD
+                }
+                pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
+            }
+        }
     }
 
     #[cfg(target_os = "macos")]
@@ -3093,6 +3259,7 @@ pub mod kernel32 {
                                                LPSYSTEM_INFO};
             use libc::types::os::arch::extra::{HANDLE, LPHANDLE};
 
+            #[cfg(target_arch = "x86")]
             #[abi = "stdcall"]
             extern "stdcall" {
                 pub fn GetEnvironmentVariableW(n: LPCWSTR,
@@ -3197,6 +3364,111 @@ pub fn MapViewOfFile(hFileMappingObject: HANDLE,
                                      -> LPVOID;
                 pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
             }
+
+            #[cfg(target_arch = "x86_64")]
+            extern {
+                pub fn GetEnvironmentVariableW(n: LPCWSTR,
+                                               v: LPWSTR,
+                                               nsize: DWORD)
+                                               -> DWORD;
+                pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
+                                               -> BOOL;
+                pub fn GetEnvironmentStringsA() -> LPTCH;
+                pub fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL;
+                pub fn GetModuleFileNameW(hModule: HMODULE,
+                                          lpFilename: LPWSTR,
+                                          nSize: DWORD)
+                                          -> DWORD;
+                pub fn CreateDirectoryW(lpPathName: LPCWSTR,
+                                        lpSecurityAttributes:
+                                        LPSECURITY_ATTRIBUTES)
+                                        -> BOOL;
+                pub fn CopyFileW(lpExistingFileName: LPCWSTR,
+                                        lpNewFileName: LPCWSTR,
+                                        bFailIfExists: BOOL)
+                                        -> BOOL;
+                pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
+                pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+                pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+                pub fn GetLastError() -> DWORD;
+                pub fn FindFirstFileW(fileName: *u16, findFileData: HANDLE)
+                                      -> HANDLE;
+                pub fn FindNextFileW(findFile: HANDLE, findFileData: HANDLE)
+                                     -> BOOL;
+                pub fn FindClose(findFile: HANDLE) -> BOOL;
+                pub fn DuplicateHandle(hSourceProcessHandle: HANDLE,
+                                       hSourceHandle: HANDLE,
+                                       hTargetProcessHandle: HANDLE,
+                                       lpTargetHandle: LPHANDLE,
+                                       dwDesiredAccess: DWORD,
+                                       bInheritHandle: BOOL,
+                                       dwOptions: DWORD)
+                                       -> BOOL;
+                pub fn CloseHandle(hObject: HANDLE) -> BOOL;
+                pub fn OpenProcess(dwDesiredAccess: DWORD,
+                                   bInheritHandle: BOOL,
+                                   dwProcessId: DWORD)
+                                   -> HANDLE;
+                pub fn GetCurrentProcess() -> HANDLE;
+                pub fn CreateProcessA(lpApplicationName: LPCTSTR,
+                                      lpCommandLine: LPTSTR,
+                                      lpProcessAttributes:
+                                      LPSECURITY_ATTRIBUTES,
+                                      lpThreadAttributes:
+                                      LPSECURITY_ATTRIBUTES,
+                                      bInheritHandles: BOOL,
+                                      dwCreationFlags: DWORD,
+                                      lpEnvironment: LPVOID,
+                                      lpCurrentDirectory: LPCTSTR,
+                                      lpStartupInfo: LPSTARTUPINFO,
+                                      lpProcessInformation:
+                                      LPPROCESS_INFORMATION)
+                                      -> BOOL;
+                pub fn WaitForSingleObject(hHandle: HANDLE,
+                                           dwMilliseconds: DWORD)
+                                           -> DWORD;
+                pub fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint)
+                                        -> BOOL;
+                pub fn GetExitCodeProcess(hProcess: HANDLE,
+                                          lpExitCode: LPDWORD)
+                                          -> BOOL;
+                pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
+                pub fn VirtualAlloc(lpAddress: LPVOID,
+                                    dwSize: SIZE_T,
+                                    flAllocationType: DWORD,
+                                    flProtect: DWORD)
+                                    -> LPVOID;
+                pub fn VirtualFree(lpAddress: LPVOID,
+                                   dwSize: SIZE_T,
+                                   dwFreeType: DWORD)
+                                   -> BOOL;
+                pub fn VirtualLock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL;
+                pub fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T)
+                                     -> BOOL;
+                pub fn VirtualProtect(lpAddress: LPVOID,
+                                      dwSize: SIZE_T,
+                                      flNewProtect: DWORD,
+                                      lpflOldProtect: LPDWORD)
+                                      -> BOOL;
+                pub fn VirtualQuery(lpAddress: LPCVOID,
+                                    lpBuffer: LPMEMORY_BASIC_INFORMATION,
+                                    dwLength: SIZE_T)
+                                    -> SIZE_T;
+                pub fn CreateFileMappingW(hFile: HANDLE,
+                                          lpAttributes: LPSECURITY_ATTRIBUTES,
+                                          flProtect: DWORD,
+                                          dwMaximumSizeHigh: DWORD,
+                                          dwMaximumSizeLow: DWORD,
+                                          lpName: LPCTSTR)
+                                          -> HANDLE;
+                pub fn MapViewOfFile(hFileMappingObject: HANDLE,
+                                     dwDesiredAccess: DWORD,
+                                     dwFileOffsetHigh: DWORD,
+                                     dwFileOffsetLow: DWORD,
+                                     dwNumberOfBytesToMap: SIZE_T)
+                                     -> LPVOID;
+                pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
+            }
         }
 
         pub mod msvcrt {
index 5d6610e6b55a315c68c955259abf503398ba697f..88e7dd692fec850419d90e5a512a31d02d66c49a 100644 (file)
 
 */
 
+use cast;
+use libc;
 use prelude::*;
-
-use task::local_data_priv::*;
-
-#[cfg(test)] use task;
+use rt::task::{Task, LocalStorage};
+use util;
 
 /**
  * Indexes a task-local data slot. This pointer is used for comparison to
 
 pub enum KeyValue<T> { Key }
 
-/**
- * Remove a task-local data value from the table, returning the
- * reference that was originally created to insert it.
- */
-pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
-    unsafe { local_pop(Handle::new(), key) }
-}
-
-/**
- * Retrieve a task-local data value. It will also be kept alive in the
- * table until explicitly removed.
- */
-pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
-    unsafe { local_get(Handle::new(), key, f) }
-}
+trait LocalData {}
+impl<T: 'static> LocalData for T {}
 
-/**
- * Retrieve a mutable borrowed pointer to a task-local data value.
- */
-pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
-    unsafe { local_get_mut(Handle::new(), key, f) }
+// The task-local-map stores all TLS information for the currently running task.
+// It is stored as an owned pointer into the runtime, and it's only allocated
+// when TLS is used for the first time. This map must be very carefully
+// constructed because it has many mutable loans unsoundly handed out on it to
+// the various invocations of TLS requests.
+//
+// One of the most important operations is loaning a value via `get` to a
+// caller. In doing so, the slot that the TLS entry is occupying cannot be
+// invalidated because upon returning it's loan state must be updated. Currently
+// the TLS map is a vector, but this is possibly dangerous because the vector
+// can be reallocated/moved when new values are pushed onto it.
+//
+// This problem currently isn't solved in a very elegant way. Inside the `get`
+// function, it internally "invalidates" all references after the loan is
+// finished and looks up into the vector again. In theory this will prevent
+// pointers from being moved under our feet so long as LLVM doesn't go too crazy
+// with the optimizations.
+//
+// n.b. If TLS is used heavily in future, this could be made more efficient with
+//      a proper map.
+#[doc(hidden)]
+pub type Map = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
+type TLSValue = ~LocalData;
+
+// Gets the map from the runtime. Lazily initialises if not done so already.
+unsafe fn get_local_map() -> &mut Map {
+    use rt::local::Local;
+
+    let task: *mut Task = Local::unsafe_borrow();
+    match &mut (*task).storage {
+        // If the at_exit function is already set, then we just need to take
+        // a loan out on the TLS map stored inside
+        &LocalStorage(Some(ref mut map_ptr)) => {
+            return map_ptr;
+        }
+        // If this is the first time we've accessed TLS, perform similar
+        // actions to the oldsched way of doing things.
+        &LocalStorage(ref mut slot) => {
+            *slot = Some(~[]);
+            match *slot {
+                Some(ref mut map_ptr) => { return map_ptr }
+                None => abort()
+            }
+        }
+    }
 }
 
-/**
- * Store a value in task-local data. If this key already has a value,
- * that value is overwritten (and its destructor is run).
- */
-pub fn set<T: 'static>(key: Key<T>, data: T) {
-    unsafe { local_set(Handle::new(), key, data) }
+#[deriving(Eq)]
+enum LoanState {
+    NoLoan, ImmLoan, MutLoan
 }
 
-/**
- * Modify a task-local data value. If the function returns 'None', the
- * data is removed (and its reference dropped).
- */
-pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
-    unsafe {
-        match f(pop(::cast::unsafe_copy(&key))) {
-            Some(next) => { set(key, next); }
-            None => {}
+impl LoanState {
+    fn describe(&self) -> &'static str {
+        match *self {
+            NoLoan => "no loan",
+            ImmLoan => "immutable",
+            MutLoan => "mutable"
         }
     }
 }
 
-#[test]
-fn test_tls_multitask() {
-    static my_key: Key<@~str> = &Key;
-    set(my_key, @~"parent data");
-    do task::spawn {
-        // TLS shouldn't carry over.
-        assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
-        set(my_key, @~"child data");
-        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
-                ~"child data");
-        // should be cleaned up for us
+fn key_to_key_value<T: 'static>(key: Key<T>) -> *libc::c_void {
+    unsafe { cast::transmute(key) }
+}
+
+/// Removes a task-local value from task-local storage. This will return
+/// Some(value) if the key was present in TLS, otherwise it will return None.
+///
+/// A runtime assertion will be triggered it removal of TLS value is attempted
+/// while the value is still loaned out via `get` or `get_mut`.
+pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
+    let map = unsafe { get_local_map() };
+    let key_value = key_to_key_value(key);
+
+    for entry in map.mut_iter() {
+        match *entry {
+            Some((k, _, loan)) if k == key_value => {
+                if loan != NoLoan {
+                    fail!("TLS value cannot be removed because it is currently \
+                          borrowed as %s", loan.describe());
+                }
+                // Move the data out of the `entry` slot via util::replace.
+                // This is guaranteed to succeed because we already matched
+                // on `Some` above.
+                let data = match util::replace(entry, None) {
+                    Some((_, data, _)) => data,
+                    None => abort()
+                };
+
+                // Move `data` into transmute to get out the memory that it
+                // owns, we must free it manually later.
+                let (_vtable, box): (uint, ~~T) = unsafe {
+                    cast::transmute(data)
+                };
+
+                // Now that we own `box`, we can just move out of it as we would
+                // with any other data.
+                return Some(**box);
+            }
+            _ => {}
+        }
     }
-    // Must work multiple times
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+    return None;
 }
 
-#[test]
-fn test_tls_overwrite() {
-    static my_key: Key<@~str> = &Key;
-    set(my_key, @~"first data");
-    set(my_key, @~"next data"); // Shouldn't leak.
-    assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+/// Retrieves a value from TLS. The closure provided is yielded `Some` of a
+/// reference to the value located in TLS if one exists, or `None` if the key
+/// provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via the `get_mut` method provided.
+pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
+    get_with(key, ImmLoan, f)
 }
 
-#[test]
-fn test_tls_pop() {
-    static my_key: Key<@~str> = &Key;
-    set(my_key, @~"weasel");
-    assert!(*(pop(my_key).unwrap()) == ~"weasel");
-    // Pop must remove the data from the map.
-    assert!(pop(my_key).is_none());
+/// Retrieves a mutable value from TLS. The closure provided is yielded `Some`
+/// of a reference to the mutable value located in TLS if one exists, or `None`
+/// if the key provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via this or the `get` methods. This is similar to how it's a runtime
+/// error to take two mutable loans on an `@mut` box.
+pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
+    do get_with(key, MutLoan) |x| {
+        match x {
+            None => f(None),
+            // We're violating a lot of compiler guarantees with this
+            // invocation of `transmute_mut`, but we're doing runtime checks to
+            // ensure that it's always valid (only one at a time).
+            //
+            // there is no need to be upset!
+            Some(x) => { f(Some(unsafe { cast::transmute_mut(x) })) }
+        }
+    }
 }
 
-#[test]
-fn test_tls_modify() {
-    static my_key: Key<@~str> = &Key;
-    modify(my_key, |data| {
-        match data {
-            Some(@ref val) => fail!("unwelcome value: %s", *val),
-            None           => Some(@~"first data")
+fn get_with<T: 'static, U>(key: Key<T>,
+                           state: LoanState,
+                           f: &fn(Option<&T>) -> U) -> U {
+    // This function must be extremely careful. Because TLS can store owned
+    // values, and we must have some form of `get` function other than `pop`,
+    // this function has to give a `&` reference back to the caller.
+    //
+    // One option is to return the reference, but this cannot be sound because
+    // the actual lifetime of the object is not known. The slot in TLS could not
+    // be modified until the object goes out of scope, but the TLS code cannot
+    // know when this happens.
+    //
+    // For this reason, the reference is yielded to a specified closure. This
+    // way the TLS code knows exactly what the lifetime of the yielded pointer
+    // is, allowing callers to acquire references to owned data. This is also
+    // sound so long as measures are taken to ensure that while a TLS slot is
+    // loaned out to a caller, it's not modified recursively.
+    let map = unsafe { get_local_map() };
+    let key_value = key_to_key_value(key);
+
+    let pos = map.iter().position(|entry| {
+        match *entry {
+            Some((k, _, _)) if k == key_value => true, _ => false
         }
     });
-    modify(my_key, |data| {
-        match data {
-            Some(@~"first data") => Some(@~"next data"),
-            Some(@ref val)       => fail!("wrong value: %s", *val),
-            None                 => fail!("missing value")
+    match pos {
+        None => { return f(None); }
+        Some(i) => {
+            let ret;
+            let mut return_loan = false;
+            match map[i] {
+                Some((_, ref data, ref mut loan)) => {
+                    match (state, *loan) {
+                        (_, NoLoan) => {
+                            *loan = state;
+                            return_loan = true;
+                        }
+                        (ImmLoan, ImmLoan) => {}
+                        (want, cur) => {
+                            fail!("TLS slot cannot be borrowed as %s because \
+                                   it is already borrowed as %s",
+                                  want.describe(), cur.describe());
+                        }
+                    }
+                    // data was created with `~~T as ~LocalData`, so we extract
+                    // pointer part of the trait, (as ~~T), and then use
+                    // compiler coercions to achieve a '&' pointer.
+                    unsafe {
+                        match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data){
+                            (_vtable, ref box) => {
+                                let value: &T = **box;
+                                ret = f(Some(value));
+                            }
+                        }
+                    }
+                }
+                _ => abort()
+            }
+
+            // n.b. 'data' and 'loans' are both invalid pointers at the point
+            // 'f' returned because `f` could have appended more TLS items which
+            // in turn relocated the vector. Hence we do another lookup here to
+            // fixup the loans.
+            if return_loan {
+                match map[i] {
+                    Some((_, _, ref mut loan)) => { *loan = NoLoan; }
+                    None => abort()
+                }
+            }
+            return ret;
         }
-    });
-    assert!(*(pop(my_key).unwrap()) == ~"next data");
+    }
 }
 
-#[test]
-fn test_tls_crust_automorestack_memorial_bug() {
-    // This might result in a stack-canary clobber if the runtime fails to
-    // set sp_limit to 0 when calling the cleanup extern - it might
-    // automatically jump over to the rust stack, which causes next_c_sp
-    // to get recorded as something within a rust stack segment. Then a
-    // subsequent upcall (esp. for logging, think vsnprintf) would run on
-    // a stack smaller than 1 MB.
-    static my_key: Key<@~str> = &Key;
-    do task::spawn {
-        set(my_key, @~"hax");
-    }
+fn abort() -> ! {
+    #[fixed_stack_segment]; #[inline(never)];
+    unsafe { libc::abort() }
 }
 
-#[test]
-fn test_tls_multiple_types() {
-    static str_key: Key<@~str> = &Key;
-    static box_key: Key<@@()> = &Key;
-    static int_key: Key<@int> = &Key;
-    do task::spawn {
-        set(str_key, @~"string data");
-        set(box_key, @@());
-        set(int_key, @42);
+/// Inserts a value into task local storage. If the key is already present in
+/// TLS, then the previous value is removed and replaced with the provided data.
+///
+/// It is considered a runtime error to attempt to set a key which is currently
+/// on loan via the `get` or `get_mut` methods.
+pub fn set<T: 'static>(key: Key<T>, data: T) {
+    let map = unsafe { get_local_map() };
+    let keyval = key_to_key_value(key);
+
+    // When the task-local map is destroyed, all the data needs to be cleaned
+    // up. For this reason we can't do some clever tricks to store '~T' as a
+    // '*c_void' or something like that. To solve the problem, we cast
+    // everything to a trait (LocalData) which is then stored inside the map.
+    // Upon destruction of the map, all the objects will be destroyed and the
+    // traits have enough information about them to destroy themselves.
+    //
+    // FIXME(#7673): This should be "~data as ~LocalData" (only one sigil)
+    let data = ~~data as ~LocalData:;
+
+    fn insertion_position(map: &mut Map,
+                          key: *libc::c_void) -> Option<uint> {
+        // First see if the map contains this key already
+        let curspot = map.iter().position(|entry| {
+            match *entry {
+                Some((ekey, _, loan)) if key == ekey => {
+                    if loan != NoLoan {
+                        fail!("TLS value cannot be overwritten because it is
+                               already borrowed as %s", loan.describe())
+                    }
+                    true
+                }
+                _ => false,
+            }
+        });
+        // If it doesn't contain the key, just find a slot that's None
+        match curspot {
+            Some(i) => Some(i),
+            None => map.iter().position(|entry| entry.is_none())
+        }
+    }
+
+    // The type of the local data map must ascribe to Send, so we do the
+    // transmute here to add the Send bound back on. This doesn't actually
+    // matter because TLS will always own the data (until its moved out) and
+    // we're not actually sending it to other schedulers or anything.
+    let data: ~LocalData = unsafe { cast::transmute(data) };
+    match insertion_position(map, keyval) {
+        Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
+        None => { map.push(Some((keyval, data, NoLoan))); }
     }
 }
 
-#[test]
-fn test_tls_overwrite_multiple_types() {
-    static str_key: Key<@~str> = &Key;
-    static box_key: Key<@@()> = &Key;
-    static int_key: Key<@int> = &Key;
-    do task::spawn {
-        set(str_key, @~"string data");
-        set(int_key, @42);
-        // This could cause a segfault if overwriting-destruction is done
-        // with the crazy polymorphic transmute rather than the provided
-        // finaliser.
-        set(int_key, @31337);
+/// Modifies a task-local value by temporarily removing it from task-local
+/// storage and then re-inserting if `Some` is returned from the closure.
+///
+/// This function will have the same runtime errors as generated from `pop` and
+/// `set` (the key must not currently be on loan
+pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
+    match f(pop(key)) {
+        Some(next) => { set(key, next); }
+        None => {}
     }
 }
 
-#[test]
-#[should_fail]
-fn test_tls_cleanup_on_failure() {
-    static str_key: Key<@~str> = &Key;
-    static box_key: Key<@@()> = &Key;
-    static int_key: Key<@int> = &Key;
-    set(str_key, @~"parent data");
-    set(box_key, @@());
-    do task::spawn {
-        // spawn_linked
-        set(str_key, @~"string data");
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+    use super::*;
+    use task;
+
+    #[test]
+    fn test_tls_multitask() {
+        static my_key: Key<@~str> = &Key;
+        set(my_key, @~"parent data");
+        do task::spawn {
+            // TLS shouldn't carry over.
+            assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
+            set(my_key, @~"child data");
+            assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
+                    ~"child data");
+            // should be cleaned up for us
+        }
+        // Must work multiple times
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+    }
+
+    #[test]
+    fn test_tls_overwrite() {
+        static my_key: Key<@~str> = &Key;
+        set(my_key, @~"first data");
+        set(my_key, @~"next data"); // Shouldn't leak.
+        assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+    }
+
+    #[test]
+    fn test_tls_pop() {
+        static my_key: Key<@~str> = &Key;
+        set(my_key, @~"weasel");
+        assert!(*(pop(my_key).unwrap()) == ~"weasel");
+        // Pop must remove the data from the map.
+        assert!(pop(my_key).is_none());
+    }
+
+    #[test]
+    fn test_tls_modify() {
+        static my_key: Key<@~str> = &Key;
+        modify(my_key, |data| {
+            match data {
+                Some(@ref val) => fail!("unwelcome value: %s", *val),
+                None           => Some(@~"first data")
+            }
+        });
+        modify(my_key, |data| {
+            match data {
+                Some(@~"first data") => Some(@~"next data"),
+                Some(@ref val)       => fail!("wrong value: %s", *val),
+                None                 => fail!("missing value")
+            }
+        });
+        assert!(*(pop(my_key).unwrap()) == ~"next data");
+    }
+
+    #[test]
+    fn test_tls_crust_automorestack_memorial_bug() {
+        // This might result in a stack-canary clobber if the runtime fails to
+        // set sp_limit to 0 when calling the cleanup extern - it might
+        // automatically jump over to the rust stack, which causes next_c_sp
+        // to get recorded as something within a rust stack segment. Then a
+        // subsequent upcall (esp. for logging, think vsnprintf) would run on
+        // a stack smaller than 1 MB.
+        static my_key: Key<@~str> = &Key;
+        do task::spawn {
+            set(my_key, @~"hax");
+        }
+    }
+
+    #[test]
+    fn test_tls_multiple_types() {
+        static str_key: Key<@~str> = &Key;
+        static box_key: Key<@@()> = &Key;
+        static int_key: Key<@int> = &Key;
+        do task::spawn {
+            set(str_key, @~"string data");
+            set(box_key, @@());
+            set(int_key, @42);
+        }
+    }
+
+    #[test]
+    fn test_tls_overwrite_multiple_types() {
+        static str_key: Key<@~str> = &Key;
+        static box_key: Key<@@()> = &Key;
+        static int_key: Key<@int> = &Key;
+        do task::spawn {
+            set(str_key, @~"string data");
+            set(int_key, @42);
+            // This could cause a segfault if overwriting-destruction is done
+            // with the crazy polymorphic transmute rather than the provided
+            // finaliser.
+            set(int_key, @31337);
+        }
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_tls_cleanup_on_failure() {
+        static str_key: Key<@~str> = &Key;
+        static box_key: Key<@@()> = &Key;
+        static int_key: Key<@int> = &Key;
+        set(str_key, @~"parent data");
         set(box_key, @@());
-        set(int_key, @42);
+        do task::spawn {
+            // spawn_linked
+            set(str_key, @~"string data");
+            set(box_key, @@());
+            set(int_key, @42);
+            fail!();
+        }
+        // Not quite nondeterministic.
+        set(int_key, @31337);
         fail!();
     }
-    // Not quite nondeterministic.
-    set(int_key, @31337);
-    fail!();
-}
 
-#[test]
-fn test_static_pointer() {
-    static key: Key<@&'static int> = &Key;
-    static VALUE: int = 0;
-    let v: @&'static int = @&VALUE;
-    set(key, v);
-}
+    #[test]
+    fn test_static_pointer() {
+        static key: Key<@&'static int> = &Key;
+        static VALUE: int = 0;
+        let v: @&'static int = @&VALUE;
+        set(key, v);
+    }
 
-#[test]
-fn test_owned() {
-    static key: Key<~int> = &Key;
-    set(key, ~1);
+    #[test]
+    fn test_owned() {
+        static key: Key<~int> = &Key;
+        set(key, ~1);
 
-    do get(key) |v| {
         do get(key) |v| {
             do get(key) |v| {
+                do get(key) |v| {
+                    assert_eq!(**v.unwrap(), 1);
+                }
                 assert_eq!(**v.unwrap(), 1);
             }
             assert_eq!(**v.unwrap(), 1);
         }
-        assert_eq!(**v.unwrap(), 1);
-    }
-    set(key, ~2);
-    do get(key) |v| {
-        assert_eq!(**v.unwrap(), 2);
+        set(key, ~2);
+        do get(key) |v| {
+            assert_eq!(**v.unwrap(), 2);
+        }
     }
-}
 
-#[test]
-fn test_get_mut() {
-    static key: Key<int> = &Key;
-    set(key, 1);
+    #[test]
+    fn test_get_mut() {
+        static key: Key<int> = &Key;
+        set(key, 1);
 
-    do get_mut(key) |v| {
-        *v.unwrap() = 2;
-    }
+        do get_mut(key) |v| {
+            *v.unwrap() = 2;
+        }
 
-    do get(key) |v| {
-        assert_eq!(*v.unwrap(), 2);
+        do get(key) |v| {
+            assert_eq!(*v.unwrap(), 2);
+        }
     }
-}
 
-#[test]
-fn test_same_key_type() {
-    static key1: Key<int> = &Key;
-    static key2: Key<int> = &Key;
-    static key3: Key<int> = &Key;
-    static key4: Key<int> = &Key;
-    static key5: Key<int> = &Key;
-    set(key1, 1);
-    set(key2, 2);
-    set(key3, 3);
-    set(key4, 4);
-    set(key5, 5);
-
-    get(key1, |x| assert_eq!(*x.unwrap(), 1));
-    get(key2, |x| assert_eq!(*x.unwrap(), 2));
-    get(key3, |x| assert_eq!(*x.unwrap(), 3));
-    get(key4, |x| assert_eq!(*x.unwrap(), 4));
-    get(key5, |x| assert_eq!(*x.unwrap(), 5));
-}
+    #[test]
+    fn test_same_key_type() {
+        static key1: Key<int> = &Key;
+        static key2: Key<int> = &Key;
+        static key3: Key<int> = &Key;
+        static key4: Key<int> = &Key;
+        static key5: Key<int> = &Key;
+        set(key1, 1);
+        set(key2, 2);
+        set(key3, 3);
+        set(key4, 4);
+        set(key5, 5);
+
+        get(key1, |x| assert_eq!(*x.unwrap(), 1));
+        get(key2, |x| assert_eq!(*x.unwrap(), 2));
+        get(key3, |x| assert_eq!(*x.unwrap(), 3));
+        get(key4, |x| assert_eq!(*x.unwrap(), 4));
+        get(key5, |x| assert_eq!(*x.unwrap(), 5));
+    }
 
-#[test]
-#[should_fail]
-fn test_nested_get_set1() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get(key) |_| {
+    #[test]
+    #[should_fail]
+    fn test_nested_get_set1() {
+        static key: Key<int> = &Key;
         set(key, 4);
+        do get(key) |_| {
+            set(key, 4);
+        }
     }
-}
 
-#[test]
-#[should_fail]
-fn test_nested_get_mut2() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get(key) |_| {
-        get_mut(key, |_| {})
+    #[test]
+    #[should_fail]
+    fn test_nested_get_mut2() {
+        static key: Key<int> = &Key;
+        set(key, 4);
+        do get(key) |_| {
+            get_mut(key, |_| {})
+        }
     }
-}
 
-#[test]
-#[should_fail]
-fn test_nested_get_mut3() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get_mut(key) |_| {
-        get(key, |_| {})
+    #[test]
+    #[should_fail]
+    fn test_nested_get_mut3() {
+        static key: Key<int> = &Key;
+        set(key, 4);
+        do get_mut(key) |_| {
+            get(key, |_| {})
+        }
     }
-}
 
-#[test]
-#[should_fail]
-fn test_nested_get_mut4() {
-    static key: Key<int> = &Key;
-    set(key, 4);
-    do get_mut(key) |_| {
-        get_mut(key, |_| {})
+    #[test]
+    #[should_fail]
+    fn test_nested_get_mut4() {
+        static key: Key<int> = &Key;
+        set(key, 4);
+        do get_mut(key) |_| {
+            get_mut(key, |_| {})
+        }
     }
 }
index 7de55f48317a556d8c66067fc0b010e5552779ca..215067ea729197c99e71c7e56609bc3a7304d277 100644 (file)
@@ -59,7 +59,8 @@ fn newsched_log_str(msg: ~str) {
     use rt::local::Local;
 
     unsafe {
-        match Local::try_unsafe_borrow::<Task>() {
+        let optional_task: Option<*mut Task> = Local::try_unsafe_borrow();
+        match optional_task {
             Some(local) => {
                 // Use the available logger
                 (*local).logger.log(Left(msg));
index 600d0bb133eff45573bdc6eb2a7e8bd60431805a..5378a2c798d8723a40fd103ccbe46822b0a878dc 100644 (file)
@@ -27,8 +27,10 @@ macro_rules! rtdebug (
 
 macro_rules! rtassert (
     ( $arg:expr ) => ( {
-        if !$arg {
-            rtabort!("assertion failed: %s", stringify!($arg));
+        if ::rt::util::ENFORCE_SANITY {
+            if !$arg {
+                rtabort!("assertion failed: %s", stringify!($arg));
+            }
         }
     } )
 )
index a493dba467e46426f8ba191a0578818ed515bb6b..1c59eaf021969ea446b182f3723e5b8200409442 100644 (file)
@@ -182,7 +182,7 @@ fn approx_epsilon() -> f32 { 1.0e-6 }
 
     #[inline]
     fn approx_eq(&self, other: &f32) -> bool {
-        self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f32, f32>())
+        self.approx_eq_eps(other, &1.0e-6)
     }
 
     #[inline]
@@ -561,11 +561,14 @@ fn ln_10() -> f32 { 2.30258509299404568401799145468436421 }
 
     /// Converts to degrees, assuming the number is in radians
     #[inline]
-    fn to_degrees(&self) -> f32 { *self * (180.0 / Real::pi::<f32>()) }
+    fn to_degrees(&self) -> f32 { *self * (180.0f32 / Real::pi()) }
 
     /// Converts to radians, assuming the number is in degrees
     #[inline]
-    fn to_radians(&self) -> f32 { *self * (Real::pi::<f32>() / 180.0) }
+    fn to_radians(&self) -> f32 {
+        let value: f32 = Real::pi();
+        *self * (value / 180.0f32)
+    }
 }
 
 impl Bounded for f32 {
@@ -578,10 +581,10 @@ fn max_value() -> f32 { 3.40282347e+38 }
 
 impl Primitive for f32 {
     #[inline]
-    fn bits() -> uint { 32 }
+    fn bits(_: Option<f32>) -> uint { 32 }
 
     #[inline]
-    fn bytes() -> uint { Primitive::bits::<f32>() / 8 }
+    fn bytes(_: Option<f32>) -> uint { Primitive::bits(Some(0f32)) / 8 }
 }
 
 impl Float for f32 {
@@ -638,25 +641,25 @@ fn classify(&self) -> FPCategory {
     }
 
     #[inline]
-    fn mantissa_digits() -> uint { 24 }
+    fn mantissa_digits(_: Option<f32>) -> uint { 24 }
 
     #[inline]
-    fn digits() -> uint { 6 }
+    fn digits(_: Option<f32>) -> uint { 6 }
 
     #[inline]
     fn epsilon() -> f32 { 1.19209290e-07 }
 
     #[inline]
-    fn min_exp() -> int { -125 }
+    fn min_exp(_: Option<f32>) -> int { -125 }
 
     #[inline]
-    fn max_exp() -> int { 128 }
+    fn max_exp(_: Option<f32>) -> int { 128 }
 
     #[inline]
-    fn min_10_exp() -> int { -37 }
+    fn min_10_exp(_: Option<f32>) -> int { -37 }
 
     #[inline]
-    fn max_10_exp() -> int { 38 }
+    fn max_10_exp(_: Option<f32>) -> int { 38 }
 
     /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
     #[inline]
@@ -949,9 +952,11 @@ fn test_clamp() {
         assert_eq!(1f32.clamp(&2f32, &4f32), 2f32);
         assert_eq!(8f32.clamp(&2f32, &4f32), 4f32);
         assert_eq!(3f32.clamp(&2f32, &4f32), 3f32);
-        assert!(3f32.clamp(&Float::NaN::<f32>(), &4f32).is_NaN());
-        assert!(3f32.clamp(&2f32, &Float::NaN::<f32>()).is_NaN());
-        assert!(Float::NaN::<f32>().clamp(&2f32, &4f32).is_NaN());
+
+        let nan: f32 = Float::NaN();
+        assert!(3f32.clamp(&nan, &4f32).is_NaN());
+        assert!(3f32.clamp(&2f32, &nan).is_NaN());
+        assert!(nan.clamp(&2f32, &4f32).is_NaN());
     }
 
     #[test]
@@ -1028,9 +1033,13 @@ fn test_fract() {
     fn test_asinh() {
         assert_eq!(0.0f32.asinh(), 0.0f32);
         assert_eq!((-0.0f32).asinh(), -0.0f32);
-        assert_eq!(Float::infinity::<f32>().asinh(), Float::infinity::<f32>());
-        assert_eq!(Float::neg_infinity::<f32>().asinh(), Float::neg_infinity::<f32>());
-        assert!(Float::NaN::<f32>().asinh().is_NaN());
+
+        let inf: f32 = Float::infinity();
+        let neg_inf: f32 = Float::neg_infinity();
+        let nan: f32 = Float::NaN();
+        assert_eq!(inf.asinh(), inf);
+        assert_eq!(neg_inf.asinh(), neg_inf);
+        assert!(nan.asinh().is_NaN());
         assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
         assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
     }
@@ -1039,9 +1048,13 @@ fn test_asinh() {
     fn test_acosh() {
         assert_eq!(1.0f32.acosh(), 0.0f32);
         assert!(0.999f32.acosh().is_NaN());
-        assert_eq!(Float::infinity::<f32>().acosh(), Float::infinity::<f32>());
-        assert!(Float::neg_infinity::<f32>().acosh().is_NaN());
-        assert!(Float::NaN::<f32>().acosh().is_NaN());
+
+        let inf: f32 = Float::infinity();
+        let neg_inf: f32 = Float::neg_infinity();
+        let nan: f32 = Float::NaN();
+        assert_eq!(inf.acosh(), inf);
+        assert!(neg_inf.acosh().is_NaN());
+        assert!(nan.acosh().is_NaN());
         assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
         assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
     }
@@ -1050,34 +1063,61 @@ fn test_acosh() {
     fn test_atanh() {
         assert_eq!(0.0f32.atanh(), 0.0f32);
         assert_eq!((-0.0f32).atanh(), -0.0f32);
-        assert_eq!(1.0f32.atanh(), Float::infinity::<f32>());
-        assert_eq!((-1.0f32).atanh(), Float::neg_infinity::<f32>());
+
+        let inf32: f32 = Float::infinity();
+        let neg_inf32: f32 = Float::neg_infinity();
+        assert_eq!(1.0f32.atanh(), inf32);
+        assert_eq!((-1.0f32).atanh(), neg_inf32);
+
         assert!(2f64.atanh().atanh().is_NaN());
         assert!((-2f64).atanh().atanh().is_NaN());
-        assert!(Float::infinity::<f64>().atanh().is_NaN());
-        assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
-        assert!(Float::NaN::<f32>().atanh().is_NaN());
+
+        let inf64: f32 = Float::infinity();
+        let neg_inf64: f32 = Float::neg_infinity();
+        let nan32: f32 = Float::NaN();
+        assert!(inf64.atanh().is_NaN());
+        assert!(neg_inf64.atanh().is_NaN());
+        assert!(nan32.atanh().is_NaN());
+
         assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
         assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
     }
 
     #[test]
     fn test_real_consts() {
-        assert_approx_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>());
-        assert_approx_eq!(Real::frac_pi_2::<f32>(), Real::pi::<f32>() / 2f32);
-        assert_approx_eq!(Real::frac_pi_3::<f32>(), Real::pi::<f32>() / 3f32);
-        assert_approx_eq!(Real::frac_pi_4::<f32>(), Real::pi::<f32>() / 4f32);
-        assert_approx_eq!(Real::frac_pi_6::<f32>(), Real::pi::<f32>() / 6f32);
-        assert_approx_eq!(Real::frac_pi_8::<f32>(), Real::pi::<f32>() / 8f32);
-        assert_approx_eq!(Real::frac_1_pi::<f32>(), 1f32 / Real::pi::<f32>());
-        assert_approx_eq!(Real::frac_2_pi::<f32>(), 2f32 / Real::pi::<f32>());
-        assert_approx_eq!(Real::frac_2_sqrtpi::<f32>(), 2f32 / Real::pi::<f32>().sqrt());
-        assert_approx_eq!(Real::sqrt2::<f32>(), 2f32.sqrt());
-        assert_approx_eq!(Real::frac_1_sqrt2::<f32>(), 1f32 / 2f32.sqrt());
-        assert_approx_eq!(Real::log2_e::<f32>(), Real::e::<f32>().log2());
-        assert_approx_eq!(Real::log10_e::<f32>(), Real::e::<f32>().log10());
-        assert_approx_eq!(Real::ln_2::<f32>(), 2f32.ln());
-        assert_approx_eq!(Real::ln_10::<f32>(), 10f32.ln());
+        let pi: f32 = Real::pi();
+        let two_pi: f32 = Real::two_pi();
+        let frac_pi_2: f32 = Real::frac_pi_2();
+        let frac_pi_3: f32 = Real::frac_pi_3();
+        let frac_pi_4: f32 = Real::frac_pi_4();
+        let frac_pi_6: f32 = Real::frac_pi_6();
+        let frac_pi_8: f32 = Real::frac_pi_8();
+        let frac_1_pi: f32 = Real::frac_1_pi();
+        let frac_2_pi: f32 = Real::frac_2_pi();
+        let frac_2_sqrtpi: f32 = Real::frac_2_sqrtpi();
+        let sqrt2: f32 = Real::sqrt2();
+        let frac_1_sqrt2: f32 = Real::frac_1_sqrt2();
+        let e: f32 = Real::e();
+        let log2_e: f32 = Real::log2_e();
+        let log10_e: f32 = Real::log10_e();
+        let ln_2: f32 = Real::ln_2();
+        let ln_10: f32 = Real::ln_10();
+
+        assert_approx_eq!(two_pi, 2f32 * pi);
+        assert_approx_eq!(frac_pi_2, pi / 2f32);
+        assert_approx_eq!(frac_pi_3, pi / 3f32);
+        assert_approx_eq!(frac_pi_4, pi / 4f32);
+        assert_approx_eq!(frac_pi_6, pi / 6f32);
+        assert_approx_eq!(frac_pi_8, pi / 8f32);
+        assert_approx_eq!(frac_1_pi, 1f32 / pi);
+        assert_approx_eq!(frac_2_pi, 2f32 / pi);
+        assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
+        assert_approx_eq!(sqrt2, 2f32.sqrt());
+        assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
+        assert_approx_eq!(log2_e, e.log2());
+        assert_approx_eq!(log10_e, e.log10());
+        assert_approx_eq!(ln_2, 2f32.ln());
+        assert_approx_eq!(ln_10, 10f32.ln());
     }
 
     #[test]
@@ -1153,17 +1193,23 @@ fn test_approx_eq() {
 
     #[test]
     fn test_primitive() {
-        assert_eq!(Primitive::bits::<f32>(), sys::size_of::<f32>() * 8);
-        assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>());
+        let none: Option<f32> = None;
+        assert_eq!(Primitive::bits(none), sys::size_of::<f32>() * 8);
+        assert_eq!(Primitive::bytes(none), sys::size_of::<f32>());
     }
 
     #[test]
     fn test_is_normal() {
-        assert!(!Float::NaN::<f32>().is_normal());
-        assert!(!Float::infinity::<f32>().is_normal());
-        assert!(!Float::neg_infinity::<f32>().is_normal());
-        assert!(!Zero::zero::<f32>().is_normal());
-        assert!(!Float::neg_zero::<f32>().is_normal());
+        let nan: f32 = Float::NaN();
+        let inf: f32 = Float::infinity();
+        let neg_inf: f32 = Float::neg_infinity();
+        let zero: f32 = Zero::zero();
+        let neg_zero: f32 = Float::neg_zero();
+        assert!(!nan.is_normal());
+        assert!(!inf.is_normal());
+        assert!(!neg_inf.is_normal());
+        assert!(!zero.is_normal());
+        assert!(!neg_zero.is_normal());
         assert!(1f32.is_normal());
         assert!(1e-37f32.is_normal());
         assert!(!1e-38f32.is_normal());
@@ -1171,11 +1217,16 @@ fn test_is_normal() {
 
     #[test]
     fn test_classify() {
-        assert_eq!(Float::NaN::<f32>().classify(), FPNaN);
-        assert_eq!(Float::infinity::<f32>().classify(), FPInfinite);
-        assert_eq!(Float::neg_infinity::<f32>().classify(), FPInfinite);
-        assert_eq!(Zero::zero::<f32>().classify(), FPZero);
-        assert_eq!(Float::neg_zero::<f32>().classify(), FPZero);
+        let nan: f32 = Float::NaN();
+        let inf: f32 = Float::infinity();
+        let neg_inf: f32 = Float::neg_infinity();
+        let zero: f32 = Zero::zero();
+        let neg_zero: f32 = Float::neg_zero();
+        assert_eq!(nan.classify(), FPNaN);
+        assert_eq!(inf.classify(), FPInfinite);
+        assert_eq!(neg_inf.classify(), FPInfinite);
+        assert_eq!(zero.classify(), FPZero);
+        assert_eq!(neg_zero.classify(), FPZero);
         assert_eq!(1f32.classify(), FPNormal);
         assert_eq!(1e-37f32.classify(), FPNormal);
         assert_eq!(1e-38f32.classify(), FPSubnormal);
@@ -1192,11 +1243,13 @@ fn test_ldexp() {
 
         assert_eq!(Float::ldexp(0f32, -123), 0f32);
         assert_eq!(Float::ldexp(-0f32, -123), -0f32);
-        assert_eq!(Float::ldexp(Float::infinity::<f32>(), -123),
-                   Float::infinity::<f32>());
-        assert_eq!(Float::ldexp(Float::neg_infinity::<f32>(), -123),
-                   Float::neg_infinity::<f32>());
-        assert!(Float::ldexp(Float::NaN::<f32>(), -123).is_NaN());
+
+        let inf: f32 = Float::infinity();
+        let neg_inf: f32 = Float::neg_infinity();
+        let nan: f32 = Float::NaN();
+        assert_eq!(Float::ldexp(inf, -123), inf);
+        assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
+        assert!(Float::ldexp(nan, -123).is_NaN());
     }
 
     #[test]
@@ -1214,10 +1267,12 @@ fn test_frexp() {
 
         assert_eq!(0f32.frexp(), (0f32, 0));
         assert_eq!((-0f32).frexp(), (-0f32, 0));
-        assert_eq!(match Float::infinity::<f32>().frexp() { (x, _) => x },
-                   Float::infinity::<f32>())
-        assert_eq!(match Float::neg_infinity::<f32>().frexp() { (x, _) => x },
-                   Float::neg_infinity::<f32>())
-        assert!(match Float::NaN::<f32>().frexp() { (x, _) => x.is_NaN() })
+
+        let inf: f32 = Float::infinity();
+        let neg_inf: f32 = Float::neg_infinity();
+        let nan: f32 = Float::NaN();
+        assert_eq!(match inf.frexp() { (x, _) => x }, inf)
+        assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
+        assert!(match nan.frexp() { (x, _) => x.is_NaN() })
     }
 }
index 52e74d969eb71901e2405e4065539a87d354bb29..8f5d6473aea2f4f3763de9c6f0790e9ed1ffb9fb 100644 (file)
@@ -205,7 +205,7 @@ fn approx_epsilon() -> f64 { 1.0e-6 }
 
     #[inline]
     fn approx_eq(&self, other: &f64) -> bool {
-        self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f64, f64>())
+        self.approx_eq_eps(other, &1.0e-6)
     }
 
     #[inline]
@@ -578,11 +578,14 @@ fn ln_10() -> f64 { 2.30258509299404568401799145468436421 }
 
     /// Converts to degrees, assuming the number is in radians
     #[inline]
-    fn to_degrees(&self) -> f64 { *self * (180.0 / Real::pi::<f64>()) }
+    fn to_degrees(&self) -> f64 { *self * (180.0f64 / Real::pi()) }
 
     /// Converts to radians, assuming the number is in degrees
     #[inline]
-    fn to_radians(&self) -> f64 { *self * (Real::pi::<f64>() / 180.0) }
+    fn to_radians(&self) -> f64 {
+        let value: f64 = Real::pi();
+        *self * (value / 180.0)
+    }
 }
 
 impl RealExt for f64 {
@@ -625,10 +628,10 @@ fn max_value() -> f64 { 1.7976931348623157e+308 }
 
 impl Primitive for f64 {
     #[inline]
-    fn bits() -> uint { 64 }
+    fn bits(_: Option<f64>) -> uint { 64 }
 
     #[inline]
-    fn bytes() -> uint { Primitive::bits::<f64>() / 8 }
+    fn bytes(_: Option<f64>) -> uint { Primitive::bits(Some(0f64)) / 8 }
 }
 
 impl Float for f64 {
@@ -685,25 +688,25 @@ fn classify(&self) -> FPCategory {
     }
 
     #[inline]
-    fn mantissa_digits() -> uint { 53 }
+    fn mantissa_digits(_: Option<f64>) -> uint { 53 }
 
     #[inline]
-    fn digits() -> uint { 15 }
+    fn digits(_: Option<f64>) -> uint { 15 }
 
     #[inline]
     fn epsilon() -> f64 { 2.2204460492503131e-16 }
 
     #[inline]
-    fn min_exp() -> int { -1021 }
+    fn min_exp(_: Option<f64>) -> int { -1021 }
 
     #[inline]
-    fn max_exp() -> int { 1024 }
+    fn max_exp(_: Option<f64>) -> int { 1024 }
 
     #[inline]
-    fn min_10_exp() -> int { -307 }
+    fn min_10_exp(_: Option<f64>) -> int { -307 }
 
     #[inline]
-    fn max_10_exp() -> int { 308 }
+    fn max_10_exp(_: Option<f64>) -> int { 308 }
 
     /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
     #[inline]
@@ -983,16 +986,20 @@ fn test_num() {
     fn test_min() {
         assert_eq!(1f64.min(&2f64), 1f64);
         assert_eq!(2f64.min(&1f64), 1f64);
-        assert!(1f64.min(&Float::NaN::<f64>()).is_NaN());
-        assert!(Float::NaN::<f64>().min(&1f64).is_NaN());
+
+        let nan: f64 = Float::NaN();
+        assert!(1f64.min(&nan).is_NaN());
+        assert!(nan.min(&1f64).is_NaN());
     }
 
     #[test]
     fn test_max() {
         assert_eq!(1f64.max(&2f64), 2f64);
         assert_eq!(2f64.max(&1f64), 2f64);
-        assert!(1f64.max(&Float::NaN::<f64>()).is_NaN());
-        assert!(Float::NaN::<f64>().max(&1f64).is_NaN());
+
+        let nan: f64 = Float::NaN();
+        assert!(1f64.max(&nan).is_NaN());
+        assert!(nan.max(&1f64).is_NaN());
     }
 
     #[test]
@@ -1000,9 +1007,11 @@ fn test_clamp() {
         assert_eq!(1f64.clamp(&2f64, &4f64), 2f64);
         assert_eq!(8f64.clamp(&2f64, &4f64), 4f64);
         assert_eq!(3f64.clamp(&2f64, &4f64), 3f64);
-        assert!(3f64.clamp(&Float::NaN::<f64>(), &4f64).is_NaN());
-        assert!(3f64.clamp(&2f64, &Float::NaN::<f64>()).is_NaN());
-        assert!(Float::NaN::<f64>().clamp(&2f64, &4f64).is_NaN());
+
+        let nan: f64 = Float::NaN();
+        assert!(3f64.clamp(&nan, &4f64).is_NaN());
+        assert!(3f64.clamp(&2f64, &nan).is_NaN());
+        assert!(nan.clamp(&2f64, &4f64).is_NaN());
     }
 
     #[test]
@@ -1079,9 +1088,13 @@ fn test_fract() {
     fn test_asinh() {
         assert_eq!(0.0f64.asinh(), 0.0f64);
         assert_eq!((-0.0f64).asinh(), -0.0f64);
-        assert_eq!(Float::infinity::<f64>().asinh(), Float::infinity::<f64>());
-        assert_eq!(Float::neg_infinity::<f64>().asinh(), Float::neg_infinity::<f64>());
-        assert!(Float::NaN::<f64>().asinh().is_NaN());
+
+        let inf: f64 = Float::infinity();
+        let neg_inf: f64 = Float::neg_infinity();
+        let nan: f64 = Float::NaN();
+        assert_eq!(inf.asinh(), inf);
+        assert_eq!(neg_inf.asinh(), neg_inf);
+        assert!(nan.asinh().is_NaN());
         assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
         assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
     }
@@ -1090,9 +1103,13 @@ fn test_asinh() {
     fn test_acosh() {
         assert_eq!(1.0f64.acosh(), 0.0f64);
         assert!(0.999f64.acosh().is_NaN());
-        assert_eq!(Float::infinity::<f64>().acosh(), Float::infinity::<f64>());
-        assert!(Float::neg_infinity::<f64>().acosh().is_NaN());
-        assert!(Float::NaN::<f64>().acosh().is_NaN());
+
+        let inf: f64 = Float::infinity();
+        let neg_inf: f64 = Float::neg_infinity();
+        let nan: f64 = Float::NaN();
+        assert_eq!(inf.acosh(), inf);
+        assert!(neg_inf.acosh().is_NaN());
+        assert!(nan.acosh().is_NaN());
         assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
         assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
     }
@@ -1101,34 +1118,56 @@ fn test_acosh() {
     fn test_atanh() {
         assert_eq!(0.0f64.atanh(), 0.0f64);
         assert_eq!((-0.0f64).atanh(), -0.0f64);
-        assert_eq!(1.0f64.atanh(), Float::infinity::<f64>());
-        assert_eq!((-1.0f64).atanh(), Float::neg_infinity::<f64>());
+
+        let inf: f64 = Float::infinity();
+        let neg_inf: f64 = Float::neg_infinity();
+        let nan: f64 = Float::NaN();
+        assert_eq!(1.0f64.atanh(), inf);
+        assert_eq!((-1.0f64).atanh(), neg_inf);
         assert!(2f64.atanh().atanh().is_NaN());
         assert!((-2f64).atanh().atanh().is_NaN());
-        assert!(Float::infinity::<f64>().atanh().is_NaN());
-        assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
-        assert!(Float::NaN::<f64>().atanh().is_NaN());
+        assert!(inf.atanh().is_NaN());
+        assert!(neg_inf.atanh().is_NaN());
+        assert!(nan.atanh().is_NaN());
         assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
         assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
     }
 
     #[test]
     fn test_real_consts() {
-        assert_approx_eq!(Real::two_pi::<f64>(), 2.0 * Real::pi::<f64>());
-        assert_approx_eq!(Real::frac_pi_2::<f64>(), Real::pi::<f64>() / 2f64);
-        assert_approx_eq!(Real::frac_pi_3::<f64>(), Real::pi::<f64>() / 3f64);
-        assert_approx_eq!(Real::frac_pi_4::<f64>(), Real::pi::<f64>() / 4f64);
-        assert_approx_eq!(Real::frac_pi_6::<f64>(), Real::pi::<f64>() / 6f64);
-        assert_approx_eq!(Real::frac_pi_8::<f64>(), Real::pi::<f64>() / 8f64);
-        assert_approx_eq!(Real::frac_1_pi::<f64>(), 1f64 / Real::pi::<f64>());
-        assert_approx_eq!(Real::frac_2_pi::<f64>(), 2f64 / Real::pi::<f64>());
-        assert_approx_eq!(Real::frac_2_sqrtpi::<f64>(), 2f64 / Real::pi::<f64>().sqrt());
-        assert_approx_eq!(Real::sqrt2::<f64>(), 2f64.sqrt());
-        assert_approx_eq!(Real::frac_1_sqrt2::<f64>(), 1f64 / 2f64.sqrt());
-        assert_approx_eq!(Real::log2_e::<f64>(), Real::e::<f64>().log2());
-        assert_approx_eq!(Real::log10_e::<f64>(), Real::e::<f64>().log10());
-        assert_approx_eq!(Real::ln_2::<f64>(), 2f64.ln());
-        assert_approx_eq!(Real::ln_10::<f64>(), 10f64.ln());
+        let pi: f64 = Real::pi();
+        let two_pi: f64 = Real::two_pi();
+        let frac_pi_2: f64 = Real::frac_pi_2();
+        let frac_pi_3: f64 = Real::frac_pi_3();
+        let frac_pi_4: f64 = Real::frac_pi_4();
+        let frac_pi_6: f64 = Real::frac_pi_6();
+        let frac_pi_8: f64 = Real::frac_pi_8();
+        let frac_1_pi: f64 = Real::frac_1_pi();
+        let frac_2_pi: f64 = Real::frac_2_pi();
+        let frac_2_sqrtpi: f64 = Real::frac_2_sqrtpi();
+        let sqrt2: f64 = Real::sqrt2();
+        let frac_1_sqrt2: f64 = Real::frac_1_sqrt2();
+        let e: f64 = Real::e();
+        let log2_e: f64 = Real::log2_e();
+        let log10_e: f64 = Real::log10_e();
+        let ln_2: f64 = Real::ln_2();
+        let ln_10: f64 = Real::ln_10();
+
+        assert_approx_eq!(two_pi, 2.0 * pi);
+        assert_approx_eq!(frac_pi_2, pi / 2f64);
+        assert_approx_eq!(frac_pi_3, pi / 3f64);
+        assert_approx_eq!(frac_pi_4, pi / 4f64);
+        assert_approx_eq!(frac_pi_6, pi / 6f64);
+        assert_approx_eq!(frac_pi_8, pi / 8f64);
+        assert_approx_eq!(frac_1_pi, 1f64 / pi);
+        assert_approx_eq!(frac_2_pi, 2f64 / pi);
+        assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
+        assert_approx_eq!(sqrt2, 2f64.sqrt());
+        assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
+        assert_approx_eq!(log2_e, e.log2());
+        assert_approx_eq!(log10_e, e.log10());
+        assert_approx_eq!(ln_2, 2f64.ln());
+        assert_approx_eq!(ln_10, 10f64.ln());
     }
 
     #[test]
@@ -1204,17 +1243,23 @@ fn test_approx_eq() {
 
     #[test]
     fn test_primitive() {
-        assert_eq!(Primitive::bits::<f64>(), sys::size_of::<f64>() * 8);
-        assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>());
+        let none: Option<f64> = None;
+        assert_eq!(Primitive::bits(none), sys::size_of::<f64>() * 8);
+        assert_eq!(Primitive::bytes(none), sys::size_of::<f64>());
     }
 
     #[test]
     fn test_is_normal() {
-        assert!(!Float::NaN::<f64>().is_normal());
-        assert!(!Float::infinity::<f64>().is_normal());
-        assert!(!Float::neg_infinity::<f64>().is_normal());
-        assert!(!Zero::zero::<f64>().is_normal());
-        assert!(!Float::neg_zero::<f64>().is_normal());
+        let nan: f64 = Float::NaN();
+        let inf: f64 = Float::infinity();
+        let neg_inf: f64 = Float::neg_infinity();
+        let zero: f64 = Zero::zero();
+        let neg_zero: f64 = Float::neg_zero();
+        assert!(!nan.is_normal());
+        assert!(!inf.is_normal());
+        assert!(!neg_inf.is_normal());
+        assert!(!zero.is_normal());
+        assert!(!neg_zero.is_normal());
         assert!(1f64.is_normal());
         assert!(1e-307f64.is_normal());
         assert!(!1e-308f64.is_normal());
@@ -1222,11 +1267,16 @@ fn test_is_normal() {
 
     #[test]
     fn test_classify() {
-        assert_eq!(Float::NaN::<f64>().classify(), FPNaN);
-        assert_eq!(Float::infinity::<f64>().classify(), FPInfinite);
-        assert_eq!(Float::neg_infinity::<f64>().classify(), FPInfinite);
-        assert_eq!(Zero::zero::<f64>().classify(), FPZero);
-        assert_eq!(Float::neg_zero::<f64>().classify(), FPZero);
+        let nan: f64 = Float::NaN();
+        let inf: f64 = Float::infinity();
+        let neg_inf: f64 = Float::neg_infinity();
+        let zero: f64 = Zero::zero();
+        let neg_zero: f64 = Float::neg_zero();
+        assert_eq!(nan.classify(), FPNaN);
+        assert_eq!(inf.classify(), FPInfinite);
+        assert_eq!(neg_inf.classify(), FPInfinite);
+        assert_eq!(zero.classify(), FPZero);
+        assert_eq!(neg_zero.classify(), FPZero);
         assert_eq!(1e-307f64.classify(), FPNormal);
         assert_eq!(1e-308f64.classify(), FPSubnormal);
     }
@@ -1242,11 +1292,13 @@ fn test_ldexp() {
 
         assert_eq!(Float::ldexp(0f64, -123), 0f64);
         assert_eq!(Float::ldexp(-0f64, -123), -0f64);
-        assert_eq!(Float::ldexp(Float::infinity::<f64>(), -123),
-                   Float::infinity::<f64>());
-        assert_eq!(Float::ldexp(Float::neg_infinity::<f64>(), -123),
-                   Float::neg_infinity::<f64>());
-        assert!(Float::ldexp(Float::NaN::<f64>(), -123).is_NaN());
+
+        let inf: f64 = Float::infinity();
+        let neg_inf: f64 = Float::neg_infinity();
+        let nan: f64 = Float::NaN();
+        assert_eq!(Float::ldexp(inf, -123), inf);
+        assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
+        assert!(Float::ldexp(nan, -123).is_NaN());
     }
 
     #[test]
@@ -1264,10 +1316,12 @@ fn test_frexp() {
 
         assert_eq!(0f64.frexp(), (0f64, 0));
         assert_eq!((-0f64).frexp(), (-0f64, 0));
-        assert_eq!(match Float::infinity::<f64>().frexp() { (x, _) => x },
-                   Float::infinity::<f64>())
-        assert_eq!(match Float::neg_infinity::<f64>().frexp() { (x, _) => x },
-                   Float::neg_infinity::<f64>())
-        assert!(match Float::NaN::<f64>().frexp() { (x, _) => x.is_NaN() })
+
+        let inf: f64 = Float::infinity();
+        let neg_inf: f64 = Float::neg_infinity();
+        let nan: f64 = Float::NaN();
+        assert_eq!(match inf.frexp() { (x, _) => x }, inf)
+        assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
+        assert!(match nan.frexp() { (x, _) => x.is_NaN() })
     }
 }
index 20c7adbd62c47887900510e5012a1b9a3547e830..d019de2468bdfa568699d8c76a0d8412da0ebd37 100644 (file)
@@ -342,7 +342,7 @@ fn approx_epsilon() -> float { 1.0e-6 }
 
     #[inline]
     fn approx_eq(&self, other: &float) -> bool {
-        self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<float, float>())
+        self.approx_eq_eps(other, &1.0e-6)
     }
 
     #[inline]
@@ -783,32 +783,56 @@ fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity }
 
 impl Bounded for float {
     #[inline]
-    fn min_value() -> float { Bounded::min_value::<f64>() as float }
+    fn min_value() -> float {
+        let x: f64 = Bounded::min_value();
+        x as float
+    }
 
     #[inline]
-    fn max_value() -> float { Bounded::max_value::<f64>() as float }
+    fn max_value() -> float {
+        let x: f64 = Bounded::max_value();
+        x as float
+    }
 }
 
 impl Primitive for float {
     #[inline]
-    fn bits() -> uint { Primitive::bits::<f64>() }
+    fn bits(_: Option<float>) -> uint {
+        let bits: uint = Primitive::bits(Some(0f64));
+        bits
+    }
 
     #[inline]
-    fn bytes() -> uint { Primitive::bytes::<f64>() }
+    fn bytes(_: Option<float>) -> uint {
+        let bytes: uint = Primitive::bytes(Some(0f64));
+        bytes
+    }
 }
 
 impl Float for float {
     #[inline]
-    fn NaN() -> float { Float::NaN::<f64>() as float }
+    fn NaN() -> float {
+        let value: f64 = Float::NaN();
+        value as float
+    }
 
     #[inline]
-    fn infinity() -> float { Float::infinity::<f64>() as float }
+    fn infinity() -> float {
+        let value: f64 = Float::infinity();
+        value as float
+    }
 
     #[inline]
-    fn neg_infinity() -> float { Float::neg_infinity::<f64>() as float }
+    fn neg_infinity() -> float {
+        let value: f64 = Float::neg_infinity();
+        value as float
+    }
 
     #[inline]
-    fn neg_zero() -> float { Float::neg_zero::<f64>() as float }
+    fn neg_zero() -> float {
+        let value: f64 = Float::neg_zero();
+        value as float
+    }
 
     /// Returns `true` if the number is NaN
     #[inline]
@@ -832,30 +856,46 @@ fn is_normal(&self) -> bool { (*self as f64).is_normal() }
     fn classify(&self) -> FPCategory { (*self as f64).classify() }
 
     #[inline]
-    fn mantissa_digits() -> uint { Float::mantissa_digits::<f64>() }
+    fn mantissa_digits(_: Option<float>) -> uint {
+        Float::mantissa_digits(Some(0f64))
+    }
 
     #[inline]
-    fn digits() -> uint { Float::digits::<f64>() }
+    fn digits(_: Option<float>) -> uint {
+        Float::digits(Some(0f64))
+    }
 
     #[inline]
-    fn epsilon() -> float { Float::epsilon::<f64>() as float }
+    fn epsilon() -> float {
+        let value: f64 = Float::epsilon();
+        value as float
+    }
 
     #[inline]
-    fn min_exp() -> int { Float::min_exp::<f64>() }
+    fn min_exp(_: Option<float>) -> int {
+        Float::min_exp(Some(0f64))
+    }
 
     #[inline]
-    fn max_exp() -> int { Float::max_exp::<f64>() }
+    fn max_exp(_: Option<float>) -> int {
+        Float::max_exp(Some(0f64))
+    }
 
     #[inline]
-    fn min_10_exp() -> int { Float::min_10_exp::<f64>() }
+    fn min_10_exp(_: Option<float>) -> int {
+        Float::min_10_exp(Some(0f64))
+    }
 
     #[inline]
-    fn max_10_exp() -> int { Float::max_10_exp::<f64>() }
+    fn max_10_exp(_: Option<float>) -> int {
+        Float::max_10_exp(Some(0f64))
+    }
 
     /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
     #[inline]
     fn ldexp(x: float, exp: int) -> float {
-        Float::ldexp(x as f64, exp) as float
+        let value: f64 = Float::ldexp(x as f64, exp);
+        value as float
     }
 
     ///
@@ -937,9 +977,10 @@ fn test_clamp() {
         assert_eq!(1f.clamp(&2f, &4f), 2f);
         assert_eq!(8f.clamp(&2f, &4f), 4f);
         assert_eq!(3f.clamp(&2f, &4f), 3f);
-        assert!(3f.clamp(&Float::NaN::<float>(), &4f).is_NaN());
-        assert!(3f.clamp(&2f, &Float::NaN::<float>()).is_NaN());
-        assert!(Float::NaN::<float>().clamp(&2f, &4f).is_NaN());
+        let nan: float = Float::NaN();
+        assert!(3f.clamp(&nan, &4f).is_NaN());
+        assert!(3f.clamp(&2f, &nan).is_NaN());
+        assert!(nan.clamp(&2f, &4f).is_NaN());
     }
 
     #[test]
@@ -1016,9 +1057,13 @@ fn test_fract() {
     fn test_asinh() {
         assert_eq!(0.0f.asinh(), 0.0f);
         assert_eq!((-0.0f).asinh(), -0.0f);
-        assert_eq!(Float::infinity::<float>().asinh(), Float::infinity::<float>());
-        assert_eq!(Float::neg_infinity::<float>().asinh(), Float::neg_infinity::<float>());
-        assert!(Float::NaN::<float>().asinh().is_NaN());
+
+        let inf: float = Float::infinity();
+        let neg_inf: float = Float::neg_infinity();
+        let nan: float = Float::NaN();
+        assert_eq!(inf.asinh(), inf);
+        assert_eq!(neg_inf.asinh(), neg_inf);
+        assert!(nan.asinh().is_NaN());
         assert_approx_eq!(2.0f.asinh(), 1.443635475178810342493276740273105f);
         assert_approx_eq!((-2.0f).asinh(), -1.443635475178810342493276740273105f);
     }
@@ -1027,9 +1072,13 @@ fn test_asinh() {
     fn test_acosh() {
         assert_eq!(1.0f.acosh(), 0.0f);
         assert!(0.999f.acosh().is_NaN());
-        assert_eq!(Float::infinity::<float>().acosh(), Float::infinity::<float>());
-        assert!(Float::neg_infinity::<float>().acosh().is_NaN());
-        assert!(Float::NaN::<float>().acosh().is_NaN());
+
+        let inf: float = Float::infinity();
+        let neg_inf: float = Float::neg_infinity();
+        let nan: float = Float::NaN();
+        assert_eq!(inf.acosh(), inf);
+        assert!(neg_inf.acosh().is_NaN());
+        assert!(nan.acosh().is_NaN());
         assert_approx_eq!(2.0f.acosh(), 1.31695789692481670862504634730796844f);
         assert_approx_eq!(3.0f.acosh(), 1.76274717403908605046521864995958461f);
     }
@@ -1038,34 +1087,58 @@ fn test_acosh() {
     fn test_atanh() {
         assert_eq!(0.0f.atanh(), 0.0f);
         assert_eq!((-0.0f).atanh(), -0.0f);
-        assert_eq!(1.0f.atanh(), Float::infinity::<float>());
-        assert_eq!((-1.0f).atanh(), Float::neg_infinity::<float>());
+
+        let inf: float = Float::infinity();
+        let neg_inf: float = Float::neg_infinity();
+        let inf64: f64 = Float::infinity();
+        let neg_inf64: f64 = Float::neg_infinity();
+        let nan: float = Float::NaN();
+        assert_eq!(1.0f.atanh(), inf);
+        assert_eq!((-1.0f).atanh(), neg_inf);
         assert!(2f64.atanh().atanh().is_NaN());
         assert!((-2f64).atanh().atanh().is_NaN());
-        assert!(Float::infinity::<f64>().atanh().is_NaN());
-        assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
-        assert!(Float::NaN::<float>().atanh().is_NaN());
+        assert!(inf64.atanh().is_NaN());
+        assert!(neg_inf64.atanh().is_NaN());
+        assert!(nan.atanh().is_NaN());
         assert_approx_eq!(0.5f.atanh(), 0.54930614433405484569762261846126285f);
         assert_approx_eq!((-0.5f).atanh(), -0.54930614433405484569762261846126285f);
     }
 
     #[test]
     fn test_real_consts() {
-        assert_approx_eq!(Real::two_pi::<float>(), 2f * Real::pi::<float>());
-        assert_approx_eq!(Real::frac_pi_2::<float>(), Real::pi::<float>() / 2f);
-        assert_approx_eq!(Real::frac_pi_3::<float>(), Real::pi::<float>() / 3f);
-        assert_approx_eq!(Real::frac_pi_4::<float>(), Real::pi::<float>() / 4f);
-        assert_approx_eq!(Real::frac_pi_6::<float>(), Real::pi::<float>() / 6f);
-        assert_approx_eq!(Real::frac_pi_8::<float>(), Real::pi::<float>() / 8f);
-        assert_approx_eq!(Real::frac_1_pi::<float>(), 1f / Real::pi::<float>());
-        assert_approx_eq!(Real::frac_2_pi::<float>(), 2f / Real::pi::<float>());
-        assert_approx_eq!(Real::frac_2_sqrtpi::<float>(), 2f / Real::pi::<float>().sqrt());
-        assert_approx_eq!(Real::sqrt2::<float>(), 2f.sqrt());
-        assert_approx_eq!(Real::frac_1_sqrt2::<float>(), 1f / 2f.sqrt());
-        assert_approx_eq!(Real::log2_e::<float>(), Real::e::<float>().log2());
-        assert_approx_eq!(Real::log10_e::<float>(), Real::e::<float>().log10());
-        assert_approx_eq!(Real::ln_2::<float>(), 2f.ln());
-        assert_approx_eq!(Real::ln_10::<float>(), 10f.ln());
+        let pi: float = Real::pi();
+        let two_pi: float = Real::two_pi();
+        let frac_pi_2: float = Real::frac_pi_2();
+        let frac_pi_3: float = Real::frac_pi_3();
+        let frac_pi_4: float = Real::frac_pi_4();
+        let frac_pi_6: float = Real::frac_pi_6();
+        let frac_pi_8: float = Real::frac_pi_8();
+        let frac_1_pi: float = Real::frac_1_pi();
+        let frac_2_pi: float = Real::frac_2_pi();
+        let frac_2_sqrtpi: float = Real::frac_2_sqrtpi();
+        let sqrt2: float = Real::sqrt2();
+        let frac_1_sqrt2: float = Real::frac_1_sqrt2();
+        let e: float = Real::e();
+        let log2_e: float = Real::log2_e();
+        let log10_e: float = Real::log10_e();
+        let ln_2: float = Real::ln_2();
+        let ln_10: float = Real::ln_10();
+
+        assert_approx_eq!(two_pi, 2f * pi);
+        assert_approx_eq!(frac_pi_2, pi / 2f);
+        assert_approx_eq!(frac_pi_3, pi / 3f);
+        assert_approx_eq!(frac_pi_4, pi / 4f);
+        assert_approx_eq!(frac_pi_6, pi / 6f);
+        assert_approx_eq!(frac_pi_8, pi / 8f);
+        assert_approx_eq!(frac_1_pi, 1f / pi);
+        assert_approx_eq!(frac_2_pi, 2f / pi);
+        assert_approx_eq!(frac_2_sqrtpi, 2f / pi.sqrt());
+        assert_approx_eq!(sqrt2, 2f.sqrt());
+        assert_approx_eq!(frac_1_sqrt2, 1f / 2f.sqrt());
+        assert_approx_eq!(log2_e, e.log2());
+        assert_approx_eq!(log10_e, e.log10());
+        assert_approx_eq!(ln_2, 2f.ln());
+        assert_approx_eq!(ln_10, 10f.ln());
     }
 
     #[test]
@@ -1141,17 +1214,23 @@ fn test_approx_eq() {
 
     #[test]
     fn test_primitive() {
-        assert_eq!(Primitive::bits::<float>(), sys::size_of::<float>() * 8);
-        assert_eq!(Primitive::bytes::<float>(), sys::size_of::<float>());
+        let none: Option<float> = None;
+        assert_eq!(Primitive::bits(none), sys::size_of::<float>() * 8);
+        assert_eq!(Primitive::bytes(none), sys::size_of::<float>());
     }
 
     #[test]
     fn test_is_normal() {
-        assert!(!Float::NaN::<float>().is_normal());
-        assert!(!Float::infinity::<float>().is_normal());
-        assert!(!Float::neg_infinity::<float>().is_normal());
-        assert!(!Zero::zero::<float>().is_normal());
-        assert!(!Float::neg_zero::<float>().is_normal());
+        let nan: float = Float::NaN();
+        let inf: float = Float::infinity();
+        let neg_inf: float = Float::neg_infinity();
+        let zero: float = Zero::zero();
+        let neg_zero: float = Float::neg_zero();
+        assert!(!nan.is_normal());
+        assert!(!inf.is_normal());
+        assert!(!neg_inf.is_normal());
+        assert!(!zero.is_normal());
+        assert!(!neg_zero.is_normal());
         assert!(1f.is_normal());
         assert!(1e-307f.is_normal());
         assert!(!1e-308f.is_normal());
@@ -1159,11 +1238,16 @@ fn test_is_normal() {
 
     #[test]
     fn test_classify() {
-        assert_eq!(Float::NaN::<float>().classify(), FPNaN);
-        assert_eq!(Float::infinity::<float>().classify(), FPInfinite);
-        assert_eq!(Float::neg_infinity::<float>().classify(), FPInfinite);
-        assert_eq!(Zero::zero::<float>().classify(), FPZero);
-        assert_eq!(Float::neg_zero::<float>().classify(), FPZero);
+        let nan: float = Float::NaN();
+        let inf: float = Float::infinity();
+        let neg_inf: float = Float::neg_infinity();
+        let zero: float = Zero::zero();
+        let neg_zero: float = Float::neg_zero();
+        assert_eq!(nan.classify(), FPNaN);
+        assert_eq!(inf.classify(), FPInfinite);
+        assert_eq!(neg_inf.classify(), FPInfinite);
+        assert_eq!(zero.classify(), FPZero);
+        assert_eq!(neg_zero.classify(), FPZero);
         assert_eq!(1f.classify(), FPNormal);
         assert_eq!(1e-307f.classify(), FPNormal);
         assert_eq!(1e-308f.classify(), FPSubnormal);
@@ -1180,11 +1264,13 @@ fn test_ldexp() {
 
         assert_eq!(Float::ldexp(0f, -123), 0f);
         assert_eq!(Float::ldexp(-0f, -123), -0f);
-        assert_eq!(Float::ldexp(Float::infinity::<float>(), -123),
-                   Float::infinity::<float>());
-        assert_eq!(Float::ldexp(Float::neg_infinity::<float>(), -123),
-                   Float::neg_infinity::<float>());
-        assert!(Float::ldexp(Float::NaN::<float>(), -123).is_NaN());
+
+        let inf: float = Float::infinity();
+        let neg_inf: float = Float::neg_infinity();
+        let nan: float = Float::NaN();
+        assert_eq!(Float::ldexp(inf, -123), inf);
+        assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
+        assert!(Float::ldexp(nan, -123).is_NaN());
     }
 
     #[test]
@@ -1202,11 +1288,13 @@ fn test_frexp() {
 
         assert_eq!(0f.frexp(), (0f, 0));
         assert_eq!((-0f).frexp(), (-0f, 0));
-        assert_eq!(match Float::infinity::<float>().frexp() { (x, _) => x },
-                   Float::infinity::<float>())
-        assert_eq!(match Float::neg_infinity::<float>().frexp() { (x, _) => x },
-                   Float::neg_infinity::<float>())
-        assert!(match Float::NaN::<float>().frexp() { (x, _) => x.is_NaN() })
+
+        let inf: float = Float::infinity();
+        let neg_inf: float = Float::neg_infinity();
+        let nan: float = Float::NaN();
+        assert_eq!(match inf.frexp() { (x, _) => x }, inf);
+        assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
+        assert!(match nan.frexp() { (x, _) => x.is_NaN() })
     }
 
     #[test]
index e2218ce27362637fd0c415dbf4cbf2dd035b1c07..6054d557fa5cd7547b556d36bd0d7fb979be2cd2 100644 (file)
@@ -466,10 +466,10 @@ impl Int for $T {}
 
 impl Primitive for $T {
     #[inline]
-    fn bits() -> uint { bits }
+    fn bits(_: Option<$T>) -> uint { bits }
 
     #[inline]
-    fn bytes() -> uint { bits / 8 }
+    fn bytes(_: Option<$T>) -> uint { bits / 8 }
 }
 
 // String conversion functions and impl str -> num
@@ -754,8 +754,9 @@ fn test_bitcount() {
 
     #[test]
     fn test_primitive() {
-        assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8);
-        assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>());
+        let none: Option<$T> = None;
+        assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8);
+        assert_eq!(Primitive::bytes(none), sys::size_of::<$T>());
     }
 
     #[test]
index fbb8913fbfa89577e0acd368e1a9bd97e3a283ed..80ab0caac670ccdc911cabd92b808d8ad6da32ad 100644 (file)
@@ -272,8 +272,8 @@ pub trait Primitive: Num
                    + Div<Self,Self>
                    + Rem<Self,Self> {
     // FIXME (#5527): These should be associated constants
-    fn bits() -> uint;
-    fn bytes() -> uint;
+    fn bits(unused_self: Option<Self>) -> uint;
+    fn bytes(unused_self: Option<Self>) -> uint;
 }
 
 /// A collection of traits relevant to primitive signed and unsigned integers
@@ -314,13 +314,13 @@ pub trait Float: Real
     fn is_normal(&self) -> bool;
     fn classify(&self) -> FPCategory;
 
-    fn mantissa_digits() -> uint;
-    fn digits() -> uint;
+    fn mantissa_digits(unused_self: Option<Self>) -> uint;
+    fn digits(unused_self: Option<Self>) -> uint;
     fn epsilon() -> Self;
-    fn min_exp() -> int;
-    fn max_exp() -> int;
-    fn min_10_exp() -> int;
-    fn max_10_exp() -> int;
+    fn min_exp(unused_self: Option<Self>) -> int;
+    fn max_exp(unused_self: Option<Self>) -> int;
+    fn min_10_exp(unused_self: Option<Self>) -> int;
+    fn max_10_exp(unused_self: Option<Self>) -> int;
 
     fn ldexp(x: Self, exp: int) -> Self;
     fn frexp(&self) -> (Self, int);
@@ -484,9 +484,9 @@ fn saturating_add(self, v: T) -> T {
         match self.checked_add(&v) {
             Some(x) => x,
             None => if v >= Zero::zero() {
-                Bounded::max_value::<T>()
+                Bounded::max_value()
             } else {
-                Bounded::min_value::<T>()
+                Bounded::min_value()
             }
         }
     }
@@ -496,9 +496,9 @@ fn saturating_sub(self, v: T) -> T {
         match self.checked_sub(&v) {
             Some(x) => x,
             None => if v >= Zero::zero() {
-                Bounded::min_value::<T>()
+                Bounded::min_value()
             } else {
-                Bounded::max_value::<T>()
+                Bounded::max_value()
             }
         }
     }
index d81a2756ad84a5802c0dc32950193079f9095b4a..8ffaed22d01afd1b339030f81b29dc0115511620 100644 (file)
@@ -404,10 +404,10 @@ fn to_str_radix(&self, radix: uint) -> ~str {
 
 impl Primitive for $T {
     #[inline]
-    fn bits() -> uint { bits }
+    fn bits(_: Option<$T>) -> uint { bits }
 
     #[inline]
-    fn bytes() -> uint { bits / 8 }
+    fn bytes(_: Option<$T>) -> uint { bits / 8 }
 }
 
 impl BitCount for $T {
@@ -532,8 +532,9 @@ fn test_bitcount() {
 
     #[test]
     fn test_primitive() {
-        assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8);
-        assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>());
+        let none: Option<$T> = None;
+        assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8);
+        assert_eq!(Primitive::bytes(none), sys::size_of::<$T>());
     }
 
     #[test]
index 34c47d9f61ecdefb86dfb7b031abedf2c12165be..f99a595f2eb866eea22d7a1cab787e37182379b5 100644 (file)
@@ -43,7 +43,6 @@
 
 use clone::Clone;
 use cmp::{Eq,Ord};
-use ops::Add;
 use util;
 use num::Zero;
 use iterator;
@@ -77,18 +76,6 @@ fn gt(&self, other: &Option<T>) -> bool {
     }
 }
 
-impl<T: Add<T, T>> Add<Option<T>, Option<T>> for Option<T> {
-    #[inline]
-    fn add(&self, other: &Option<T>) -> Option<T> {
-        match (&*self, &*other) {
-            (&None, &None) => None,
-            (_, &None) => None,
-            (&None, _) => None,
-            (&Some(ref lhs), &Some(ref rhs)) => Some(*lhs + *rhs)
-        }
-    }
-}
-
 // FIXME: #8242 implementing manually because deriving doesn't work for some reason
 impl<T: ToStr> ToStr for Option<T> {
     fn to_str(&self) -> ~str {
index 0b5f53dbf19e407b2fcdb6ccbeba28005ed285ab..7aae9425302255fdfaadac1a28a1612cdaf88096 100644 (file)
@@ -1042,12 +1042,19 @@ pub fn errno() -> uint {
     #[fixed_stack_segment]; #[inline(never)];
     use libc::types::os::arch::extra::DWORD;
 
+    #[cfg(target_arch = "x86")]
     #[link_name = "kernel32"]
     #[abi = "stdcall"]
     extern "stdcall" {
         fn GetLastError() -> DWORD;
     }
 
+    #[cfg(target_arch = "x86_64")]
+    #[link_name = "kernel32"]
+    extern {
+        fn GetLastError() -> DWORD;
+    }
+
     unsafe {
         GetLastError() as uint
     }
@@ -1113,6 +1120,7 @@ fn strerror() -> ~str {
         use libc::types::os::arch::extra::LPSTR;
         use libc::types::os::arch::extra::LPVOID;
 
+        #[cfg(target_arch = "x86")]
         #[link_name = "kernel32"]
         #[abi = "stdcall"]
         extern "stdcall" {
@@ -1126,6 +1134,19 @@ fn FormatMessageA(flags: DWORD,
                               -> DWORD;
         }
 
+        #[cfg(target_arch = "x86_64")]
+        #[link_name = "kernel32"]
+        extern {
+            fn FormatMessageA(flags: DWORD,
+                              lpSrc: LPVOID,
+                              msgId: DWORD,
+                              langId: DWORD,
+                              buf: LPSTR,
+                              nsize: DWORD,
+                              args: *c_void)
+                              -> DWORD;
+        }
+
         static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
         static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
 
@@ -1241,7 +1262,7 @@ fn real_args() -> ~[~str] {
 
 type LPCWSTR = *u16;
 
-#[cfg(windows)]
+#[cfg(windows, target_arch = "x86")]
 #[link_name="kernel32"]
 #[abi="stdcall"]
 extern "stdcall" {
@@ -1249,13 +1270,26 @@ fn real_args() -> ~[~str] {
     fn LocalFree(ptr: *c_void);
 }
 
-#[cfg(windows)]
+#[cfg(windows, target_arch = "x86_64")]
+#[link_name="kernel32"]
+extern {
+    fn GetCommandLineW() -> LPCWSTR;
+    fn LocalFree(ptr: *c_void);
+}
+
+#[cfg(windows, target_arch = "x86")]
 #[link_name="shell32"]
 #[abi="stdcall"]
 extern "stdcall" {
     fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
 }
 
+#[cfg(windows, target_arch = "x86_64")]
+#[link_name="shell32"]
+extern {
+    fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
+}
+
 struct OverriddenArgs {
     val: ~[~str]
 }
@@ -1487,7 +1521,7 @@ pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError>
         let r = unsafe {
             libc::mmap(addr, len, prot, flags, fd, offset)
         };
-        if r == libc::MAP_FAILED {
+        if r.equiv(&libc::MAP_FAILED) {
             Err(match errno() as c_int {
                 libc::EACCES => ErrFdNotAvail,
                 libc::EBADF => ErrInvalidFd,
index e91c78e8223d1cb330de076ef6c83a8013e19dbd..bfe5b498f8f1327e2edbb455bbb9f2f852e9767a 100644 (file)
@@ -81,6 +81,7 @@
 pub use vec::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCopyableVector};
 pub use vec::{OwnedVector, OwnedCopyableVector,OwnedEqVector, MutableVector};
 pub use io::{Reader, ReaderUtil, Writer, WriterUtil};
+pub use default::Default;
 
 // Reexported runtime types
 pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
index 12af303f33ffe7fb5a3b1f8f34ae031631b8a9c4..02469527b7af66a741181950c9e85c7ab0ec4ec6 100644 (file)
 
 use cast;
 use clone::Clone;
+use cmp::Equiv;
 use iterator::{range, Iterator};
 use option::{Option, Some, None};
+#[cfg(stage0)]
+use sys;
 use unstable::intrinsics;
 use util::swap;
 
-#[cfg(not(test))] use ops::{Add,Sub};
-#[cfg(not(test))] use num::Int;
-
 #[cfg(not(test))] use cmp::{Eq, Ord};
 
-/// Calculate the offset from a pointer
+/// Calculate the offset from a pointer. The count *must* be in bounds or
+/// otherwise the loads of this address are undefined.
 #[inline]
-pub fn offset<T>(ptr: *T, count: int) -> *T {
-    unsafe { intrinsics::offset(ptr, count) }
+#[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 const pointer
+/// Calculate the offset from a mut pointer
 #[inline]
-pub fn const_offset<T>(ptr: *const T, count: int) -> *const T {
-    unsafe { intrinsics::offset(ptr as *T, count) }
+#[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 mut pointer
+/// Calculate the offset from a pointer
+#[inline]
+#[cfg(not(stage0))]
+pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
+    intrinsics::offset(ptr, count)
+}
+
+/// Calculate the offset from a mut pointer. The count *must* be in bounds or
+/// otherwise the loads of this address are undefined.
 #[inline]
-pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
-    unsafe { intrinsics::offset(ptr as *T, count) as *mut T }
+#[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
 }
 
 /// Return the offset of the first null pointer in `buf`.
@@ -73,11 +85,11 @@ pub fn mut_null<T>() -> *mut T { 0 as *mut T }
 
 /// Returns true if the pointer is equal to the null pointer.
 #[inline]
-pub fn is_null<T>(ptr: *const T) -> bool { ptr == null() }
+pub fn is_null<T,P:RawPtr<T>>(ptr: P) -> bool { ptr.is_null() }
 
 /// Returns true if the pointer is not equal to the null pointer.
 #[inline]
-pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
+pub fn is_not_null<T,P:RawPtr<T>>(ptr: P) -> bool { ptr.is_not_null() }
 
 /**
  * Copies data from one location to another.
@@ -87,8 +99,10 @@ pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
  */
 #[inline]
 #[cfg(target_word_size = "32")]
-pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
-    intrinsics::memmove32(dst, src as *T, count as u32);
+pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
+    intrinsics::memmove32(dst,
+                          cast::transmute_immut_unsafe(src),
+                          count as u32);
 }
 
 /**
@@ -99,8 +113,10 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
  */
 #[inline]
 #[cfg(target_word_size = "64")]
-pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
-    intrinsics::memmove64(dst, src as *T, count as u64);
+pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
+    intrinsics::memmove64(dst,
+                          cast::transmute_immut_unsafe(src),
+                          count as u64);
 }
 
 /**
@@ -111,8 +127,12 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
  */
 #[inline]
 #[cfg(target_word_size = "32")]
-pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
-    intrinsics::memcpy32(dst, src as *T, count as u32);
+pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
+                                                        src: P,
+                                                        count: uint) {
+    intrinsics::memcpy32(dst,
+                         cast::transmute_immut_unsafe(src),
+                         count as u32);
 }
 
 /**
@@ -123,8 +143,12 @@ pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: u
  */
 #[inline]
 #[cfg(target_word_size = "64")]
-pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
-    intrinsics::memcpy64(dst, src as *T, count as u64);
+pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
+                                                        src: P,
+                                                        count: uint) {
+    intrinsics::memcpy64(dst,
+                         cast::transmute_immut_unsafe(src),
+                         count as u64);
 }
 
 /**
@@ -216,12 +240,6 @@ pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
     thing as *T
 }
 
-/// Transform a const region pointer - &const T - to a const unsafe pointer - *const T.
-#[inline]
-pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
-    thing as *const T
-}
-
 /// Transform a mutable region pointer - &mut T - to a mutable unsafe pointer - *mut T.
 #[inline]
 pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
@@ -269,22 +287,31 @@ pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) {
 
 #[allow(missing_doc)]
 pub trait RawPtr<T> {
+    fn null() -> Self;
     fn is_null(&self) -> bool;
     fn is_not_null(&self) -> bool;
+    fn to_uint(&self) -> uint;
     unsafe fn to_option(&self) -> Option<&T>;
-    fn offset(&self, count: int) -> Self;
-    unsafe fn offset_inbounds(self, count: int) -> Self;
+    unsafe fn offset(self, count: int) -> Self;
 }
 
 /// Extension methods for immutable pointers
 impl<T> RawPtr<T> for *T {
+    /// Returns the null pointer.
+    #[inline]
+    fn null() -> *T { null() }
+
     /// Returns true if the pointer is equal to the null pointer.
     #[inline]
-    fn is_null(&self) -> bool { is_null(*self) }
+    fn is_null(&self) -> bool { *self == RawPtr::null() }
 
     /// Returns true if the pointer is not equal to the null pointer.
     #[inline]
-    fn is_not_null(&self) -> bool { is_not_null(*self) }
+    fn is_not_null(&self) -> bool { *self != RawPtr::null() }
+
+    /// Returns the address of this pointer.
+    #[inline]
+    fn to_uint(&self) -> uint { *self as uint }
 
     ///
     /// Returns `None` if the pointer is null, or else returns the value wrapped
@@ -303,27 +330,29 @@ unsafe fn to_option(&self) -> Option<&T> {
         }
     }
 
-    /// Calculates the offset from a pointer.
-    #[inline]
-    fn offset(&self, count: int) -> *T { offset(*self, count) }
-
     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
     /// the object, or one-byte-past-the-end.
     #[inline]
-    unsafe fn offset_inbounds(self, count: int) -> *T {
-        intrinsics::offset_inbounds(self, count)
-    }
+    unsafe fn offset(self, count: int) -> *T { offset(self, count) }
 }
 
 /// Extension methods for mutable pointers
 impl<T> RawPtr<T> for *mut T {
+    /// Returns the null pointer.
+    #[inline]
+    fn null() -> *mut T { mut_null() }
+
     /// Returns true if the pointer is equal to the null pointer.
     #[inline]
-    fn is_null(&self) -> bool { is_null(*self) }
+    fn is_null(&self) -> bool { *self == RawPtr::null() }
 
     /// Returns true if the pointer is not equal to the null pointer.
     #[inline]
-    fn is_not_null(&self) -> bool { is_not_null(*self) }
+    fn is_not_null(&self) -> bool { *self != RawPtr::null() }
+
+    /// Returns the address of this pointer.
+    #[inline]
+    fn to_uint(&self) -> uint { *self as uint }
 
     ///
     /// Returns `None` if the pointer is null, or else returns the value wrapped
@@ -342,10 +371,6 @@ unsafe fn to_option(&self) -> Option<&T> {
         }
     }
 
-    /// Calculates the offset from a mutable pointer.
-    #[inline]
-    fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
-
     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
     /// the object, or one-byte-past-the-end. An arithmetic overflow is also
     /// undefined behaviour.
@@ -353,20 +378,43 @@ fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
     /// This method should be preferred over `offset` when the guarantee can be
     /// satisfied, to enable better optimization.
     #[inline]
-    unsafe fn offset_inbounds(self, count: int) -> *mut T {
-        intrinsics::offset_inbounds(self as *T, count) as *mut T
-    }
+    unsafe fn offset(self, count: int) -> *mut T { mut_offset(self, count) }
 }
 
 // Equality for pointers
 #[cfg(not(test))]
-impl<T> Eq for *const T {
+impl<T> Eq for *T {
     #[inline]
-    fn eq(&self, other: &*const T) -> bool {
+    fn eq(&self, other: &*T) -> bool {
         (*self as uint) == (*other as uint)
     }
     #[inline]
-    fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
+    fn ne(&self, other: &*T) -> bool { !self.eq(other) }
+}
+
+#[cfg(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) }
+}
+
+// Equivalence for pointers
+#[cfg(not(test))]
+impl<T> Equiv<*mut T> for *T {
+    fn equiv(&self, other: &*mut T) -> bool {
+        self.to_uint() == other.to_uint()
+    }
+}
+
+#[cfg(not(test))]
+impl<T> Equiv<*T> for *mut T {
+    fn equiv(&self, other: &*T) -> bool {
+        self.to_uint() == other.to_uint()
+    }
 }
 
 // Equality for extern "C" fn pointers
@@ -412,62 +460,42 @@ fn ne(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
 
 // Comparison for pointers
 #[cfg(not(test))]
-impl<T> Ord for *const T {
+impl<T> Ord for *T {
     #[inline]
-    fn lt(&self, other: &*const T) -> bool {
+    fn lt(&self, other: &*T) -> bool {
         (*self as uint) < (*other as uint)
     }
     #[inline]
-    fn le(&self, other: &*const T) -> bool {
+    fn le(&self, other: &*T) -> bool {
         (*self as uint) <= (*other as uint)
     }
     #[inline]
-    fn ge(&self, other: &*const T) -> bool {
+    fn ge(&self, other: &*T) -> bool {
         (*self as uint) >= (*other as uint)
     }
     #[inline]
-    fn gt(&self, other: &*const T) -> bool {
+    fn gt(&self, other: &*T) -> bool {
         (*self as uint) > (*other as uint)
     }
 }
 
 #[cfg(not(test))]
-impl<T, I: Int> Add<I, *T> for *T {
-    /// Add an integer value to a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
+impl<T> Ord for *mut T {
     #[inline]
-    fn add(&self, rhs: &I) -> *T {
-        self.offset(rhs.to_int() as int)
+    fn lt(&self, other: &*mut T) -> bool {
+        (*self as uint) < (*other as uint)
     }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *T> for *T {
-    /// Subtract an integer value from a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
     #[inline]
-    fn sub(&self, rhs: &I) -> *T {
-        self.offset(-rhs.to_int() as int)
+    fn le(&self, other: &*mut T) -> bool {
+        (*self as uint) <= (*other as uint)
     }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Add<I, *mut T> for *mut T {
-    /// Add an integer value to a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
     #[inline]
-    fn add(&self, rhs: &I) -> *mut T {
-        self.offset(rhs.to_int() as int)
+    fn ge(&self, other: &*mut T) -> bool {
+        (*self as uint) >= (*other as uint)
     }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *mut T> for *mut T {
-    /// Subtract an integer value from a pointer to get an offset pointer.
-    /// Is calculated according to the size of the type pointed to.
     #[inline]
-    fn sub(&self, rhs: &I) -> *mut T {
-        self.offset(-rhs.to_int() as int)
+    fn gt(&self, other: &*mut T) -> bool {
+        (*self as uint) > (*other as uint)
     }
 }
 
@@ -553,7 +581,7 @@ fn test_is_null() {
         assert!(p.is_null());
         assert!(!p.is_not_null());
 
-        let q = offset(p, 1);
+        let q = unsafe { offset(p, 1) };
         assert!(!q.is_null());
         assert!(q.is_not_null());
 
@@ -561,7 +589,7 @@ fn test_is_null() {
         assert!(mp.is_null());
         assert!(!mp.is_not_null());
 
-        let mq = mp.offset(1);
+        let mq = unsafe { mp.offset(1) };
         assert!(!mq.is_null());
         assert!(mq.is_not_null());
     }
@@ -590,20 +618,20 @@ fn test_ptr_addition() {
         unsafe {
             let xs = ~[5, ..16];
             let mut ptr = to_ptr(xs);
-            let end = ptr + 16;
+            let end = ptr.offset(16);
 
             while ptr < end {
                 assert_eq!(*ptr, 5);
-                ptr = ptr + 1u;
+                ptr = ptr.offset(1);
             }
 
             let mut xs_mut = xs.clone();
             let mut m_ptr = to_mut_ptr(xs_mut);
-            let m_end = m_ptr + 16i16;
+            let m_end = m_ptr.offset(16);
 
             while m_ptr < m_end {
                 *m_ptr += 5;
-                m_ptr = m_ptr + 1u8;
+                m_ptr = m_ptr.offset(1);
             }
 
             assert_eq!(xs_mut, ~[10, ..16]);
@@ -620,17 +648,17 @@ fn test_ptr_subtraction() {
             let ptr = to_ptr(xs);
 
             while idx >= 0i8 {
-                assert_eq!(*(ptr + idx), idx as int);
+                assert_eq!(*(ptr.offset(idx as int)), idx as int);
                 idx = idx - 1i8;
             }
 
             let mut xs_mut = xs.clone();
             let m_start = to_mut_ptr(xs_mut);
-            let mut m_ptr = m_start + 9u32;
+            let mut m_ptr = m_start.offset(9);
 
             while m_ptr >= m_start {
                 *m_ptr += *m_ptr;
-                m_ptr = m_ptr - 1i8;
+                m_ptr = m_ptr.offset(-1);
             }
 
             assert_eq!(xs_mut, ~[0,2,4,6,8,10,12,14,16,18]);
index 1d093c4c14b8b2a779ccbb74fdfadb3f56b91b2f..56e0f83e05cf0ea722ae87f93a52dd82f474da9a 100644 (file)
@@ -460,16 +460,6 @@ fn visit_trait(&self) -> bool {
         true
     }
 
-    fn visit_var(&self) -> bool {
-        if ! self.inner.visit_var() { return false; }
-        true
-    }
-
-    fn visit_var_integral(&self) -> bool {
-        if ! self.inner.visit_var_integral() { return false; }
-        true
-    }
-
     fn visit_param(&self, i: uint) -> bool {
         if ! self.inner.visit_param(i) { return false; }
         true
@@ -494,11 +484,6 @@ fn visit_opaque_box(&self) -> bool {
         true
     }
 
-    fn visit_constr(&self, inner: *TyDesc) -> bool {
-        if ! self.inner.visit_constr(inner) { return false; }
-        true
-    }
-
     fn visit_closure_ptr(&self, ck: uint) -> bool {
         self.align_to::<@fn()>();
         if ! self.inner.visit_closure_ptr(ck) { return false; }
index 743a47a812aed10b2b78c30be715654809aa791d..588010bd5b179f14a41a825d46090d055671568a 100644 (file)
@@ -75,35 +75,50 @@ fn write_repr(&self, writer: @Writer) {
     }
 }
 
-macro_rules! int_repr(($ty:ident) => (impl Repr for $ty {
+impl Repr for int {
+    fn write_repr(&self, writer: @Writer) {
+        do ::int::to_str_bytes(*self, 10u) |bits| {
+            writer.write(bits);
+        }
+    }
+}
+
+macro_rules! int_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
     fn write_repr(&self, writer: @Writer) {
         do ::$ty::to_str_bytes(*self, 10u) |bits| {
             writer.write(bits);
+            writer.write(bytes!($suffix));
         }
     }
 }))
 
-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 {
+int_repr!(i8, "i8")
+int_repr!(i16, "i16")
+int_repr!(i32, "i32")
+int_repr!(i64, "i64")
+int_repr!(uint, "u")
+int_repr!(u8, "u8")
+int_repr!(u16, "u16")
+int_repr!(u32, "u32")
+int_repr!(u64, "u64")
+
+impl Repr for float {
+    fn write_repr(&self, writer: @Writer) {
+        let s = self.to_str();
+        writer.write(s.as_bytes());
+    }
+}
+
+macro_rules! num_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
     fn write_repr(&self, writer: @Writer) {
         let s = self.to_str();
         writer.write(s.as_bytes());
+        writer.write(bytes!($suffix));
     }
 }))
 
-num_repr!(float)
-num_repr!(f32)
-num_repr!(f64)
+num_repr!(f32, "f32")
+num_repr!(f64, "f64")
 
 // New implementation using reflect::MovePtr
 
@@ -213,7 +228,7 @@ pub fn write_vec_range(&self,
                 self.writer.write_str(", ");
             }
             self.visit_ptr_inner(p as *c_void, inner);
-            p = align(ptr::offset(p, sz as int) as uint, al) as *u8;
+            p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8;
             left -= dec;
         }
         self.writer.write_char(']');
@@ -267,12 +282,14 @@ fn visit_estr_box(&self) -> bool {
             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);
@@ -307,6 +324,7 @@ fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
         }
     }
 
+    #[cfg(stage0)]
     fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool {
         do self.get::<*c_void> |p| {
             self.writer.write_str(fmt!("(0x%x as *())",
@@ -314,6 +332,15 @@ fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool {
         }
     }
 
+    #[cfg(not(stage0))]
+    fn visit_ptr(&self, mtbl: uint, _inner: *TyDesc) -> bool {
+        do self.get::<*c_void> |p| {
+            self.writer.write_str(fmt!("(0x%x as *", *p as uint));
+            self.write_mut_qualifier(mtbl);
+            self.writer.write_str("())");
+        }
+    }
+
     fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
         self.writer.write_char('&');
         self.write_mut_qualifier(mtbl);
@@ -536,8 +563,6 @@ fn visit_leave_fn(&self, _purity: uint, _proto: uint,
 
 
     fn visit_trait(&self) -> bool { true }
-    fn visit_var(&self) -> bool { true }
-    fn visit_var_integral(&self) -> bool { true }
     fn visit_param(&self, _i: uint) -> bool { true }
     fn visit_self(&self) -> bool { true }
     fn visit_type(&self) -> bool { true }
@@ -550,9 +575,6 @@ fn visit_opaque_box(&self) -> bool {
         }
     }
 
-    // Type no longer exists, vestigial function.
-    fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); }
-
     fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
 }
 
@@ -590,7 +612,7 @@ fn exact_test<T>(t: &T, e:&str) {
     exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\"");
 
     exact_test(&(@10), "@10");
-    exact_test(&(@mut 10), "@10"); // FIXME: #4210: incorrect
+    exact_test(&(@mut 10), "@mut 10");
     exact_test(&((@mut 10, 2)), "(@mut 10, 2)");
     exact_test(&(~10), "~10");
     exact_test(&(&10), "&10");
@@ -598,11 +620,14 @@ fn exact_test<T>(t: &T, e:&str) {
     exact_test(&(&mut x), "&mut 10");
     exact_test(&(@mut [1, 2]), "@mut [1, 2]");
 
+    exact_test(&(0 as *()), "(0x0 as *())");
+    exact_test(&(0 as *mut ()), "(0x0 as *mut ())");
+
     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]");
+               "@[1u8, 2u8, 3u8, 4u8]");
     exact_test(&(@["hi", "there"]),
                "@[\"hi\", \"there\"]");
     exact_test(&(~["hi", "there"]),
@@ -615,14 +640,14 @@ fn exact_test<T>(t: &T, e:&str) {
                "@{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\")");
+    exact_test(&(10u8, ~"hello"),
+               "(10u8, ~\"hello\")");
+    exact_test(&(10u16, ~"hello"),
+               "(10u16, ~\"hello\")");
+    exact_test(&(10u32, ~"hello"),
+               "(10u32, ~\"hello\")");
+    exact_test(&(10u64, ~"hello"),
+               "(10u64, ~\"hello\")");
 
     struct Foo;
     exact_test(&(~[Foo, Foo, Foo]), "~[{}, {}, {}]");
index cbac43f27c73b865aa0b1802a09e61eef0c63264..9dc0abdfbd88ae506faff3c97552c118e42f344a 100644 (file)
 use cell::Cell;
 use c_str::ToCStr;
 use cast::transmute;
-use libc::{c_char, size_t, STDERR_FILENO};
-use io;
 use io::{Writer, WriterUtil};
+use io;
+use libc::{c_char, size_t, STDERR_FILENO};
 use option::{Option, None, Some};
-use uint;
+use ptr::RawPtr;
 use rt::env;
 use rt::local::Local;
 use rt::task::Task;
-use str;
 use str::{OwnedStr, StrSlice};
+use str;
 use sys;
+use uint;
 use unstable::raw;
 use vec::ImmutableVector;
 
@@ -37,7 +38,7 @@ pub struct BorrowRecord {
 }
 
 fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
-    do Local::borrow::<Task, Option<~[BorrowRecord]>> |task| {
+    do Local::borrow |task: &mut Task| {
         task.borrow_list.take()
     }
 }
@@ -49,7 +50,7 @@ fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
     };
     let borrows = f(borrows);
     let borrows = Cell::new(borrows);
-    do Local::borrow::<Task, ()> |task| {
+    do Local::borrow |task: &mut Task| {
         task.borrow_list = Some(borrows.take());
     }
 }
@@ -93,12 +94,12 @@ unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) {
 static ENABLE_DEBUG: bool = false;
 
 #[inline]
-unsafe fn debug_borrow<T>(tag: &'static str,
-                          p: *const T,
-                          old_bits: uint,
-                          new_bits: uint,
-                          filename: *c_char,
-                          line: size_t) {
+unsafe fn debug_borrow<T,P:RawPtr<T>>(tag: &'static str,
+                                      p: P,
+                                      old_bits: uint,
+                                      new_bits: uint,
+                                      filename: *c_char,
+                                      line: size_t) {
     //! A useful debugging function that prints a pointer + tag + newline
     //! without allocating memory.
 
@@ -106,15 +107,15 @@ unsafe fn debug_borrow<T>(tag: &'static str,
         debug_borrow_slow(tag, p, old_bits, new_bits, filename, line);
     }
 
-    unsafe fn debug_borrow_slow<T>(tag: &'static str,
-                                   p: *const T,
-                                   old_bits: uint,
-                                   new_bits: uint,
-                                   filename: *c_char,
-                                   line: size_t) {
+    unsafe fn debug_borrow_slow<T,P:RawPtr<T>>(tag: &'static str,
+                                               p: P,
+                                               old_bits: uint,
+                                               new_bits: uint,
+                                               filename: *c_char,
+                                               line: size_t) {
         let dbg = STDERR_FILENO as io::fd_t;
         dbg.write_str(tag);
-        dbg.write_hex(p as uint);
+        dbg.write_hex(p.to_uint());
         dbg.write_str(" ");
         dbg.write_hex(old_bits);
         dbg.write_str(" ");
index 8ef9c1332f9e9ea220e0daded4ea57928211d3bf..4b1881409f44f54e35f002342ee9bf23350e5411 100644 (file)
@@ -21,7 +21,7 @@
 use rt::select::{SelectInner, SelectPortInner};
 use select::{Select, SelectPort};
 use unstable::atomics::{AtomicUint, AtomicOption, Acquire, Relaxed, SeqCst};
-use unstable::sync::UnsafeAtomicRcBox;
+use unstable::sync::UnsafeArc;
 use util::Void;
 use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable};
 use cell::Cell;
@@ -125,7 +125,7 @@ fn try_send_inner(self, val: T, do_resched: bool) -> bool {
         unsafe {
 
             // Install the payload
-            assert!((*packet).payload.is_none());
+            rtassert!((*packet).payload.is_none());
             (*packet).payload = Some(val);
 
             // Atomically swap out the old state to figure out what
@@ -144,16 +144,8 @@ fn try_send_inner(self, val: T, do_resched: bool) -> bool {
             match oldstate {
                 STATE_BOTH => {
                     // Port is not waiting yet. Nothing to do
-                    do Local::borrow::<Scheduler, ()> |sched| {
-                        rtdebug!("non-rendezvous send");
-                        sched.metrics.non_rendezvous_sends += 1;
-                    }
                 }
                 STATE_ONE => {
-                    do Local::borrow::<Scheduler, ()> |sched| {
-                        rtdebug!("rendezvous send");
-                        sched.metrics.rendezvous_sends += 1;
-                    }
                     // Port has closed. Need to clean up.
                     let _packet: ~Packet<T> = cast::transmute(this.void_packet);
                     recvr_active = false;
@@ -167,7 +159,7 @@ fn try_send_inner(self, val: T, do_resched: bool) -> bool {
                         };
                     } else {
                         let recvr = Cell::new(recvr);
-                        do Local::borrow::<Scheduler, ()> |sched| {
+                        do Local::borrow |sched: &mut Scheduler| {
                             sched.enqueue_blocked_task(recvr.take());
                         }
                     }
@@ -207,7 +199,7 @@ pub fn try_recv(self) -> Option<T> {
         if !this.optimistic_check() {
             // No data available yet.
             // Switch to the scheduler to put the ~Task into the Packet state.
-            let sched = Local::take::<Scheduler>();
+            let sched: ~Scheduler = Local::take();
             do sched.deschedule_running_task_and_then |sched, task| {
                 this.block_on(sched, task);
             }
@@ -229,7 +221,7 @@ fn optimistic_check(&mut self) -> bool {
         // The optimistic check is never necessary for correctness. For testing
         // purposes, making it randomly return false simulates a racing sender.
         use rand::{Rand};
-        let actually_check = do Local::borrow::<Scheduler, bool> |sched| {
+        let actually_check = do Local::borrow |sched: &mut Scheduler| {
             Rand::rand(&mut sched.rng)
         };
         if actually_check {
@@ -251,7 +243,6 @@ fn block_on(&mut self, sched: &mut Scheduler, task: BlockedTask) -> bool {
                 STATE_BOTH => {
                     // Data has not been sent. Now we're blocked.
                     rtdebug!("non-rendezvous recv");
-                    sched.metrics.non_rendezvous_recvs += 1;
                     false
                 }
                 STATE_ONE => {
@@ -267,7 +258,6 @@ fn block_on(&mut self, sched: &mut Scheduler, task: BlockedTask) -> bool {
                     (*self.packet()).state.store(STATE_ONE, Relaxed);
 
                     rtdebug!("rendezvous recv");
-                    sched.metrics.rendezvous_recvs += 1;
 
                     // Channel is closed. Switch back and check the data.
                     // NB: We have to drop back into the scheduler event loop here
@@ -307,7 +297,7 @@ fn unblock_from(&mut self) -> bool {
                         STATE_ONE  => true, // Lost the race. Data available.
                         same_ptr   => {
                             // We successfully unblocked our task pointer.
-                            assert!(task_as_state == same_ptr);
+                            rtassert!(task_as_state == same_ptr);
                             let handle = BlockedTask::cast_from_uint(task_as_state);
                             // Because we are already awake, the handle we
                             // gave to this port shall already be empty.
@@ -341,7 +331,8 @@ fn recv_ready(self) -> Option<T> {
         unsafe {
             // See corresponding store() above in block_on for rationale.
             // FIXME(#8130) This can happen only in test builds.
-            assert!((*packet).state.load(Relaxed) == STATE_ONE);
+            // This load is not required for correctness and may be compiled out.
+            rtassert!((*packet).state.load(Relaxed) == STATE_ONE);
 
             let payload = (*packet).payload.take();
 
@@ -387,7 +378,7 @@ fn drop(&self) {
                 },
                 task_as_state => {
                     // The port is blocked waiting for a message we will never send. Wake it.
-                    assert!((*this.packet()).payload.is_none());
+                    rtassert!((*this.packet()).payload.is_none());
                     let recvr = BlockedTask::cast_from_uint(task_as_state);
                     do recvr.wake().map_move |woken_task| {
                         Scheduler::run_task(woken_task);
@@ -576,14 +567,14 @@ impl<'self, T> SelectPort<T> for &'self Port<T> { }
 
 pub struct SharedChan<T> {
     // Just like Chan, but a shared AtomicOption instead of Cell
-    priv next: UnsafeAtomicRcBox<AtomicOption<StreamChanOne<T>>>
+    priv next: UnsafeArc<AtomicOption<StreamChanOne<T>>>
 }
 
 impl<T> SharedChan<T> {
     pub fn new(chan: Chan<T>) -> SharedChan<T> {
         let next = chan.next.take();
         let next = AtomicOption::new(~next);
-        SharedChan { next: UnsafeAtomicRcBox::new(next) }
+        SharedChan { next: UnsafeArc::new(next) }
     }
 }
 
@@ -629,7 +620,7 @@ fn clone(&self) -> SharedChan<T> {
 
 pub struct SharedPort<T> {
     // The next port on which we will receive the next port on which we will receive T
-    priv next_link: UnsafeAtomicRcBox<AtomicOption<PortOne<StreamPortOne<T>>>>
+    priv next_link: UnsafeArc<AtomicOption<PortOne<StreamPortOne<T>>>>
 }
 
 impl<T> SharedPort<T> {
@@ -639,7 +630,7 @@ pub fn new(port: Port<T>) -> SharedPort<T> {
         let (next_link_port, next_link_chan) = oneshot();
         next_link_chan.send(next_data_port);
         let next_link = AtomicOption::new(~next_link_port);
-        SharedPort { next_link: UnsafeAtomicRcBox::new(next_link) }
+        SharedPort { next_link: UnsafeArc::new(next_link) }
     }
 }
 
index 5aaddc68383f1e34171aff4f29347f6970e275e0..476554bf7f7bec7801bf58332bc5ede4e700cbf2 100644 (file)
@@ -47,6 +47,7 @@ pub fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
 
         let fp: *c_void = task_start_wrapper as *c_void;
         let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) };
+        let stack_base: *uint = stack.start();
         let sp: *uint = stack.end();
         let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) };
         // Save and then immediately load the current context,
@@ -56,7 +57,7 @@ pub fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
             swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs));
         };
 
-        initialize_call_frame(&mut *regs, fp, argp, sp);
+        initialize_call_frame(&mut *regs, fp, argp, sp, stack_base);
 
         return Context {
             start: Some(start),
@@ -107,7 +108,8 @@ fn new_regs() -> ~Registers {
 }
 
 #[cfg(target_arch = "x86")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+                         sp: *mut uint, _stack_base: *uint) {
 
     let sp = align_down(sp);
     let sp = mut_offset(sp, -4);
@@ -123,14 +125,19 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp:
     regs.ebp = 0;
 }
 
-#[cfg(target_arch = "x86_64")]
+#[cfg(windows, target_arch = "x86_64")]
+type Registers = [uint, ..34];
+#[cfg(not(windows), target_arch = "x86_64")]
 type Registers = [uint, ..22];
 
-#[cfg(target_arch = "x86_64")]
+#[cfg(windows, target_arch = "x86_64")]
+fn new_regs() -> ~Registers { ~([0, .. 34]) }
+#[cfg(not(windows), target_arch = "x86_64")]
 fn new_regs() -> ~Registers { ~([0, .. 22]) }
 
 #[cfg(target_arch = "x86_64")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+                         sp: *mut uint, stack_base: *uint) {
 
     // Redefinitions from regs.h
     static RUSTRT_ARG0: uint = 3;
@@ -138,6 +145,21 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp:
     static RUSTRT_IP: uint = 8;
     static RUSTRT_RBP: uint = 2;
 
+    #[cfg(windows)]
+    fn initialize_tib(regs: &mut Registers, sp: *mut uint, stack_base: *uint) {
+        // Redefinitions from regs.h
+        static RUSTRT_ST1: uint = 11; // stack bottom
+        static RUSTRT_ST2: uint = 12; // stack top
+        regs[RUSTRT_ST1] = sp as uint;
+        regs[RUSTRT_ST2] = stack_base as uint;
+    }
+    #[cfg(not(windows))]
+    fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
+    }
+
+    // Win64 manages stack range at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
+    initialize_tib(regs, sp, stack_base);
+
     let sp = align_down(sp);
     let sp = mut_offset(sp, -1);
 
@@ -164,7 +186,8 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp:
 fn new_regs() -> ~Registers { ~([0, .. 32]) }
 
 #[cfg(target_arch = "arm")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+                         sp: *mut uint, _stack_base: *uint) {
     let sp = align_down(sp);
     // sp of arm eabi is 8-byte aligned
     let sp = mut_offset(sp, -2);
@@ -184,7 +207,8 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp:
 fn new_regs() -> ~Registers { ~([0, .. 32]) }
 
 #[cfg(target_arch = "mips")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+                         sp: *mut uint, _stack_base: *uint) {
     let sp = align_down(sp);
     // sp of mips o32 is 8-byte aligned
     let sp = mut_offset(sp, -2);
index bc07de7d965da817f49c37cb6877059e1464da20..e82662c6b0d2f69edfeb4a0adf13697e565d3894 100644 (file)
@@ -68,174 +68,174 @@ pub trait ReaderByteConversions {
     /// Reads `n` little-endian unsigned integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_le_uint_n(&mut self, nbytes: uint) -> u64;
+    fn read_le_uint_n_(&mut self, nbytes: uint) -> u64;
 
     /// Reads `n` little-endian signed integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_le_int_n(&mut self, nbytes: uint) -> i64;
+    fn read_le_int_n_(&mut self, nbytes: uint) -> i64;
 
     /// Reads `n` big-endian unsigned integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_be_uint_n(&mut self, nbytes: uint) -> u64;
+    fn read_be_uint_n_(&mut self, nbytes: uint) -> u64;
 
     /// Reads `n` big-endian signed integer bytes.
     ///
     /// `n` must be between 1 and 8, inclusive.
-    fn read_be_int_n(&mut self, nbytes: uint) -> i64;
+    fn read_be_int_n_(&mut self, nbytes: uint) -> i64;
 
     /// Reads a little-endian unsigned integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_le_uint(&mut self) -> uint;
+    fn read_le_uint_(&mut self) -> uint;
 
     /// Reads a little-endian integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_le_int(&mut self) -> int;
+    fn read_le_int_(&mut self) -> int;
 
     /// Reads a big-endian unsigned integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_be_uint(&mut self) -> uint;
+    fn read_be_uint_(&mut self) -> uint;
 
     /// Reads a big-endian integer.
     ///
     /// The number of bytes returned is system-dependant.
-    fn read_be_int(&mut self) -> int;
+    fn read_be_int_(&mut self) -> int;
 
     /// Reads a big-endian `u64`.
     ///
     /// `u64`s are 8 bytes long.
-    fn read_be_u64(&mut self) -> u64;
+    fn read_be_u64_(&mut self) -> u64;
 
     /// Reads a big-endian `u32`.
     ///
     /// `u32`s are 4 bytes long.
-    fn read_be_u32(&mut self) -> u32;
+    fn read_be_u32_(&mut self) -> u32;
 
     /// Reads a big-endian `u16`.
     ///
     /// `u16`s are 2 bytes long.
-    fn read_be_u16(&mut self) -> u16;
+    fn read_be_u16_(&mut self) -> u16;
 
     /// Reads a big-endian `i64`.
     ///
     /// `i64`s are 8 bytes long.
-    fn read_be_i64(&mut self) -> i64;
+    fn read_be_i64_(&mut self) -> i64;
 
     /// Reads a big-endian `i32`.
     ///
     /// `i32`s are 4 bytes long.
-    fn read_be_i32(&mut self) -> i32;
+    fn read_be_i32_(&mut self) -> i32;
 
     /// Reads a big-endian `i16`.
     ///
     /// `i16`s are 2 bytes long.
-    fn read_be_i16(&mut self) -> i16;
+    fn read_be_i16_(&mut self) -> i16;
 
     /// Reads a big-endian `f64`.
     ///
     /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
-    fn read_be_f64(&mut self) -> f64;
+    fn read_be_f64_(&mut self) -> f64;
 
     /// Reads a big-endian `f32`.
     ///
     /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
-    fn read_be_f32(&mut self) -> f32;
+    fn read_be_f32_(&mut self) -> f32;
 
     /// Reads a little-endian `u64`.
     ///
     /// `u64`s are 8 bytes long.
-    fn read_le_u64(&mut self) -> u64;
+    fn read_le_u64_(&mut self) -> u64;
 
     /// Reads a little-endian `u32`.
     ///
     /// `u32`s are 4 bytes long.
-    fn read_le_u32(&mut self) -> u32;
+    fn read_le_u32_(&mut self) -> u32;
 
     /// Reads a little-endian `u16`.
     ///
     /// `u16`s are 2 bytes long.
-    fn read_le_u16(&mut self) -> u16;
+    fn read_le_u16_(&mut self) -> u16;
 
     /// Reads a little-endian `i64`.
     ///
     /// `i64`s are 8 bytes long.
-    fn read_le_i64(&mut self) -> i64;
+    fn read_le_i64_(&mut self) -> i64;
 
     /// Reads a little-endian `i32`.
     ///
     /// `i32`s are 4 bytes long.
-    fn read_le_i32(&mut self) -> i32;
+    fn read_le_i32_(&mut self) -> i32;
 
     /// Reads a little-endian `i16`.
     ///
     /// `i16`s are 2 bytes long.
-    fn read_le_i16(&mut self) -> i16;
+    fn read_le_i16_(&mut self) -> i16;
 
     /// Reads a little-endian `f64`.
     ///
     /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
-    fn read_le_f64(&mut self) -> f64;
+    fn read_le_f64_(&mut self) -> f64;
 
     /// Reads a little-endian `f32`.
     ///
     /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
-    fn read_le_f32(&mut self) -> f32;
+    fn read_le_f32_(&mut self) -> f32;
 
     /// Read a u8.
     ///
     /// `u8`s are 1 byte.
-    fn read_u8(&mut self) -> u8;
+    fn read_u8_(&mut self) -> u8;
 
     /// Read an i8.
     ///
     /// `i8`s are 1 byte.
-    fn read_i8(&mut self) -> i8;
+    fn read_i8_(&mut self) -> i8;
 
 }
 
 pub trait WriterByteConversions {
     /// Write the result of passing n through `int::to_str_bytes`.
-    fn write_int(&mut self, n: int);
+    fn write_int_(&mut self, n: int);
 
     /// Write the result of passing n through `uint::to_str_bytes`.
-    fn write_uint(&mut self, n: uint);
+    fn write_uint_(&mut self, n: uint);
 
     /// Write a little-endian uint (number of bytes depends on system).
-    fn write_le_uint(&mut self, n: uint);
+    fn write_le_uint_(&mut self, n: uint);
 
     /// Write a little-endian int (number of bytes depends on system).
-    fn write_le_int(&mut self, n: int);
+    fn write_le_int_(&mut self, n: int);
 
     /// Write a big-endian uint (number of bytes depends on system).
-    fn write_be_uint(&mut self, n: uint);
+    fn write_be_uint_(&mut self, n: uint);
 
     /// Write a big-endian int (number of bytes depends on system).
-    fn write_be_int(&mut self, n: int);
+    fn write_be_int_(&mut self, n: int);
 
     /// Write a big-endian u64 (8 bytes).
     fn write_be_u64_(&mut self, n: u64);
 
     /// Write a big-endian u32 (4 bytes).
-    fn write_be_u32(&mut self, n: u32);
+    fn write_be_u32_(&mut self, n: u32);
 
     /// Write a big-endian u16 (2 bytes).
-    fn write_be_u16(&mut self, n: u16);
+    fn write_be_u16_(&mut self, n: u16);
 
     /// Write a big-endian i64 (8 bytes).
-    fn write_be_i64(&mut self, n: i64);
+    fn write_be_i64_(&mut self, n: i64);
 
     /// Write a big-endian i32 (4 bytes).
     fn write_be_i32_(&mut self, n: i32);
 
     /// Write a big-endian i16 (2 bytes).
-    fn write_be_i16(&mut self, n: i16);
+    fn write_be_i16_(&mut self, n: i16);
 
     /// Write a big-endian IEEE754 double-precision floating-point (8 bytes).
-    fn write_be_f64(&mut self, f: f64);
+    fn write_be_f64_(&mut self, f: f64);
 
     /// Write a big-endian IEEE754 single-precision floating-point (4 bytes).
     fn write_be_f32_(&mut self, f: f32);
@@ -244,33 +244,33 @@ pub trait WriterByteConversions {
     fn write_le_u64_(&mut self, n: u64);
 
     /// Write a little-endian u32 (4 bytes).
-    fn write_le_u32(&mut self, n: u32);
+    fn write_le_u32_(&mut self, n: u32);
 
     /// Write a little-endian u16 (2 bytes).
-    fn write_le_u16(&mut self, n: u16);
+    fn write_le_u16_(&mut self, n: u16);
 
     /// Write a little-endian i64 (8 bytes).
-    fn write_le_i64(&mut self, n: i64);
+    fn write_le_i64_(&mut self, n: i64);
 
     /// Write a little-endian i32 (4 bytes).
-    fn write_le_i32(&mut self, n: i32);
+    fn write_le_i32_(&mut self, n: i32);
 
     /// Write a little-endian i16 (2 bytes).
-    fn write_le_i16(&mut self, n: i16);
+    fn write_le_i16_(&mut self, n: i16);
 
     /// Write a little-endian IEEE754 double-precision floating-point
     /// (8 bytes).
-    fn write_le_f64(&mut self, f: f64);
+    fn write_le_f64_(&mut self, f: f64);
 
     /// Write a little-endian IEEE754 single-precision floating-point
     /// (4 bytes).
     fn write_le_f32_(&mut self, f: f32);
 
     /// Write a u8 (1 byte).
-    fn write_u8(&mut self, n: u8);
+    fn write_u8_(&mut self, n: u8);
 
     /// Write a i8 (1 byte).
-    fn write_i8(&mut self, n: i8);
+    fn write_i8_(&mut self, n: i8);
 }
 
 impl<T: Reader> ReaderUtil for T {
@@ -340,136 +340,136 @@ fn read_to_end(&mut self) -> ~[u8] {
 }
 
 impl<T: Reader> ReaderByteConversions for T {
-    fn read_le_uint_n(&mut self, nbytes: uint) -> u64 {
+    fn read_le_uint_n_(&mut self, nbytes: uint) -> u64 {
         assert!(nbytes > 0 && nbytes <= 8);
 
         let mut val = 0u64;
         let mut pos = 0;
         let mut i = nbytes;
         while i > 0 {
-            val += (self.read_u8() as u64) << pos;
+            val += (self.read_u8_() as u64) << pos;
             pos += 8;
             i -= 1;
         }
         val
     }
 
-    fn read_le_int_n(&mut self, nbytes: uint) -> i64 {
-        extend_sign(self.read_le_uint_n(nbytes), nbytes)
+    fn read_le_int_n_(&mut self, nbytes: uint) -> i64 {
+        extend_sign(self.read_le_uint_n_(nbytes), nbytes)
     }
 
-    fn read_be_uint_n(&mut self, nbytes: uint) -> u64 {
+    fn read_be_uint_n_(&mut self, nbytes: uint) -> u64 {
         assert!(nbytes > 0 && nbytes <= 8);
 
         let mut val = 0u64;
         let mut i = nbytes;
         while i > 0 {
             i -= 1;
-            val += (self.read_u8() as u64) << i * 8;
+            val += (self.read_u8_() as u64) << i * 8;
         }
         val
     }
 
-    fn read_be_int_n(&mut self, nbytes: uint) -> i64 {
-        extend_sign(self.read_be_uint_n(nbytes), nbytes)
+    fn read_be_int_n_(&mut self, nbytes: uint) -> i64 {
+        extend_sign(self.read_be_uint_n_(nbytes), nbytes)
     }
 
-    fn read_le_uint(&mut self) -> uint {
-        self.read_le_uint_n(uint::bytes) as uint
+    fn read_le_uint_(&mut self) -> uint {
+        self.read_le_uint_n_(uint::bytes) as uint
     }
 
-    fn read_le_int(&mut self) -> int {
-        self.read_le_int_n(int::bytes) as int
+    fn read_le_int_(&mut self) -> int {
+        self.read_le_int_n_(int::bytes) as int
     }
 
-    fn read_be_uint(&mut self) -> uint {
-        self.read_be_uint_n(uint::bytes) as uint
+    fn read_be_uint_(&mut self) -> uint {
+        self.read_be_uint_n_(uint::bytes) as uint
     }
 
-    fn read_be_int(&mut self) -> int {
-        self.read_be_int_n(int::bytes) as int
+    fn read_be_int_(&mut self) -> int {
+        self.read_be_int_n_(int::bytes) as int
     }
 
-    fn read_be_u64(&mut self) -> u64 {
-        self.read_be_uint_n(8) as u64
+    fn read_be_u64_(&mut self) -> u64 {
+        self.read_be_uint_n_(8) as u64
     }
 
-    fn read_be_u32(&mut self) -> u32 {
-        self.read_be_uint_n(4) as u32
+    fn read_be_u32_(&mut self) -> u32 {
+        self.read_be_uint_n_(4) as u32
     }
 
-    fn read_be_u16(&mut self) -> u16 {
-        self.read_be_uint_n(2) as u16
+    fn read_be_u16_(&mut self) -> u16 {
+        self.read_be_uint_n_(2) as u16
     }
 
-    fn read_be_i64(&mut self) -> i64 {
-        self.read_be_int_n(8) as i64
+    fn read_be_i64_(&mut self) -> i64 {
+        self.read_be_int_n_(8) as i64
     }
 
-    fn read_be_i32(&mut self) -> i32 {
-        self.read_be_int_n(4) as i32
+    fn read_be_i32_(&mut self) -> i32 {
+        self.read_be_int_n_(4) as i32
     }
 
-    fn read_be_i16(&mut self) -> i16 {
-        self.read_be_int_n(2) as i16
+    fn read_be_i16_(&mut self) -> i16 {
+        self.read_be_int_n_(2) as i16
     }
 
-    fn read_be_f64(&mut self) -> f64 {
+    fn read_be_f64_(&mut self) -> f64 {
         unsafe {
-            cast::transmute::<u64, f64>(self.read_be_u64())
+            cast::transmute::<u64, f64>(self.read_be_u64_())
         }
     }
 
-    fn read_be_f32(&mut self) -> f32 {
+    fn read_be_f32_(&mut self) -> f32 {
         unsafe {
-            cast::transmute::<u32, f32>(self.read_be_u32())
+            cast::transmute::<u32, f32>(self.read_be_u32_())
         }
     }
 
-    fn read_le_u64(&mut self) -> u64 {
-        self.read_le_uint_n(8) as u64
+    fn read_le_u64_(&mut self) -> u64 {
+        self.read_le_uint_n_(8) as u64
     }
 
-    fn read_le_u32(&mut self) -> u32 {
-        self.read_le_uint_n(4) as u32
+    fn read_le_u32_(&mut self) -> u32 {
+        self.read_le_uint_n_(4) as u32
     }
 
-    fn read_le_u16(&mut self) -> u16 {
-        self.read_le_uint_n(2) as u16
+    fn read_le_u16_(&mut self) -> u16 {
+        self.read_le_uint_n_(2) as u16
     }
 
-    fn read_le_i64(&mut self) -> i64 {
-        self.read_le_int_n(8) as i64
+    fn read_le_i64_(&mut self) -> i64 {
+        self.read_le_int_n_(8) as i64
     }
 
-    fn read_le_i32(&mut self) -> i32 {
-        self.read_le_int_n(4) as i32
+    fn read_le_i32_(&mut self) -> i32 {
+        self.read_le_int_n_(4) as i32
     }
 
-    fn read_le_i16(&mut self) -> i16 {
-        self.read_le_int_n(2) as i16
+    fn read_le_i16_(&mut self) -> i16 {
+        self.read_le_int_n_(2) as i16
     }
 
-    fn read_le_f64(&mut self) -> f64 {
+    fn read_le_f64_(&mut self) -> f64 {
         unsafe {
-            cast::transmute::<u64, f64>(self.read_le_u64())
+            cast::transmute::<u64, f64>(self.read_le_u64_())
         }
     }
 
-    fn read_le_f32(&mut self) -> f32 {
+    fn read_le_f32_(&mut self) -> f32 {
         unsafe {
-            cast::transmute::<u32, f32>(self.read_le_u32())
+            cast::transmute::<u32, f32>(self.read_le_u32_())
         }
     }
 
-    fn read_u8(&mut self) -> u8 {
+    fn read_u8_(&mut self) -> u8 {
         match self.read_byte() {
             Some(b) => b as u8,
             None => 0
         }
     }
 
-    fn read_i8(&mut self) -> i8 {
+    fn read_i8_(&mut self) -> i8 {
         match self.read_byte() {
             Some(b) => b as i8,
             None => 0
@@ -479,27 +479,27 @@ fn read_i8(&mut self) -> i8 {
 }
 
 impl<T: Writer> WriterByteConversions for T {
-    fn write_int(&mut self, n: int) {
+    fn write_int_(&mut self, n: int) {
         int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
     }
 
-    fn write_uint(&mut self, n: uint) {
+    fn write_uint_(&mut self, n: uint) {
         uint::to_str_bytes(n, 10u, |bytes| self.write(bytes))
     }
 
-    fn write_le_uint(&mut self, n: uint) {
+    fn write_le_uint_(&mut self, n: uint) {
         u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v))
     }
 
-    fn write_le_int(&mut self, n: int) {
+    fn write_le_int_(&mut self, n: int) {
         u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v))
     }
 
-    fn write_be_uint(&mut self, n: uint) {
+    fn write_be_uint_(&mut self, n: uint) {
         u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v))
     }
 
-    fn write_be_int(&mut self, n: int) {
+    fn write_be_int_(&mut self, n: int) {
         u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v))
     }
 
@@ -507,15 +507,15 @@ fn write_be_u64_(&mut self, n: u64) {
         u64_to_be_bytes(n, 8u, |v| self.write(v))
     }
 
-    fn write_be_u32(&mut self, n: u32) {
+    fn write_be_u32_(&mut self, n: u32) {
         u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
     }
 
-    fn write_be_u16(&mut self, n: u16) {
+    fn write_be_u16_(&mut self, n: u16) {
         u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
     }
 
-    fn write_be_i64(&mut self, n: i64) {
+    fn write_be_i64_(&mut self, n: i64) {
         u64_to_be_bytes(n as u64, 8u, |v| self.write(v))
     }
 
@@ -523,11 +523,11 @@ fn write_be_i32_(&mut self, n: i32) {
         u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
     }
 
-    fn write_be_i16(&mut self, n: i16) {
+    fn write_be_i16_(&mut self, n: i16) {
         u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
     }
 
-    fn write_be_f64(&mut self, f: f64) {
+    fn write_be_f64_(&mut self, f: f64) {
         unsafe {
             self.write_be_u64_(cast::transmute(f))
         }
@@ -535,7 +535,7 @@ fn write_be_f64(&mut self, f: f64) {
 
     fn write_be_f32_(&mut self, f: f32) {
         unsafe {
-            self.write_be_u32(cast::transmute(f))
+            self.write_be_u32_(cast::transmute(f))
         }
     }
 
@@ -543,27 +543,27 @@ fn write_le_u64_(&mut self, n: u64) {
         u64_to_le_bytes(n, 8u, |v| self.write(v))
     }
 
-    fn write_le_u32(&mut self, n: u32) {
+    fn write_le_u32_(&mut self, n: u32) {
         u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
     }
 
-    fn write_le_u16(&mut self, n: u16) {
+    fn write_le_u16_(&mut self, n: u16) {
         u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
     }
 
-    fn write_le_i64(&mut self, n: i64) {
+    fn write_le_i64_(&mut self, n: i64) {
         u64_to_le_bytes(n as u64, 8u, |v| self.write(v))
     }
 
-    fn write_le_i32(&mut self, n: i32) {
+    fn write_le_i32_(&mut self, n: i32) {
         u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
     }
 
-    fn write_le_i16(&mut self, n: i16) {
+    fn write_le_i16_(&mut self, n: i16) {
         u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
     }
 
-    fn write_le_f64(&mut self, f: f64) {
+    fn write_le_f64_(&mut self, f: f64) {
         unsafe {
             self.write_le_u64_(cast::transmute(f))
         }
@@ -571,15 +571,15 @@ fn write_le_f64(&mut self, f: f64) {
 
     fn write_le_f32_(&mut self, f: f32) {
         unsafe {
-            self.write_le_u32(cast::transmute(f))
+            self.write_le_u32_(cast::transmute(f))
         }
     }
 
-    fn write_u8(&mut self, n: u8) {
+    fn write_u8_(&mut self, n: u8) {
         self.write([n])
     }
 
-    fn write_i8(&mut self, n: i8) {
+    fn write_i8_(&mut self, n: i8) {
         self.write([n as u8])
     }
 }
@@ -825,7 +825,6 @@ fn read_to_end_error() {
         assert!(buf == ~[10, 11]);
     }
 
-
     #[test]
     fn test_read_write_le_mem() {
         let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::max_value];
@@ -837,7 +836,7 @@ fn test_read_write_le_mem() {
 
         let mut reader = MemReader::new(writer.inner());
         for i in uints.iter() {
-            assert!(reader.read_le_u64() == *i);
+            assert!(reader.read_le_u64_() == *i);
         }
     }
 
@@ -853,7 +852,7 @@ fn test_read_write_be() {
 
         let mut reader = MemReader::new(writer.inner());
         for i in uints.iter() {
-            assert!(reader.read_be_u64() == *i);
+            assert!(reader.read_be_u64_() == *i);
         }
     }
 
@@ -870,7 +869,7 @@ fn test_read_be_int_n() {
         for i in ints.iter() {
             // this tests that the sign extension is working
             // (comparing the values as i32 would not test this)
-            assert!(reader.read_be_int_n(4) == *i as i64);
+            assert!(reader.read_be_int_n_(4) == *i as i64);
         }
     }
 
@@ -883,7 +882,7 @@ fn test_read_f32() {
         writer.write(buf);
 
         let mut reader = MemReader::new(writer.inner());
-        let f = reader.read_be_f32();
+        let f = reader.read_be_f32_();
         assert!(f == 8.1250);
     }
 
@@ -896,8 +895,8 @@ fn test_read_write_f32() {
         writer.write_le_f32_(f);
 
         let mut reader = MemReader::new(writer.inner());
-        assert!(reader.read_be_f32() == 8.1250);
-        assert!(reader.read_le_f32() == 8.1250);
+        assert!(reader.read_be_f32_() == 8.1250);
+        assert!(reader.read_le_f32_() == 8.1250);
     }
 
 }
index 65db76d5ef768d1a1c17cb6f4db05270dce8e91b..534e308a1a6e8dc65e0414560617070abe56aaa7 100644 (file)
@@ -24,7 +24,7 @@ pub fn open<P: PathLike>(path: &P,
                          access: FileAccess
                         ) -> Option<FileStream> {
     let open_result = unsafe {
-        let io = Local::unsafe_borrow::<IoFactoryObject>();
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
         (*io).fs_open(path, mode, access)
     };
     match open_result {
@@ -43,7 +43,7 @@ pub fn open<P: PathLike>(path: &P,
 /// by `path`.
 pub fn unlink<P: PathLike>(path: &P) {
     let unlink_result = unsafe {
-        let io = Local::unsafe_borrow::<IoFactoryObject>();
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
         (*io).fs_unlink(path)
     };
     match unlink_result {
@@ -71,9 +71,6 @@ pub struct FileStream {
     last_nread: int,
 }
 
-impl FileStream {
-}
-
 impl Reader for FileStream {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
         match self.fd.read(buf) {
index 116d240308a36c9cabf988df7d4bfe93c6762f53..038fca9a1ade441c2e0a867ee1cf3eb89ae3a71f 100644 (file)
 /// Synchronous, non-blocking file I/O.
 pub mod file;
 
+/// Synchronous, in-memory I/O.
+pub mod pipe;
+
 /// Synchronous, non-blocking network I/O.
 pub mod net {
     pub mod tcp;
index 3b3ea80eafa8fac1e30a85781393130f5cdb5642..d1d6b16e2eb3cd12cc368c38aba3cb1474f1d298 100644 (file)
@@ -359,7 +359,7 @@ fn from_str(s: &str) -> Option<SocketAddr> {
 mod test {
     use super::*;
     use from_str::FromStr;
-    use option::{Some, None};
+    use option::{Option, Some, None};
 
     #[test]
     fn test_from_str_ipv4() {
@@ -368,13 +368,17 @@ fn test_from_str_ipv4() {
         assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0"));
 
         // out of range
-        assert_eq!(None, FromStr::from_str::<IpAddr>("256.0.0.1"));
+        let none: Option<IpAddr> = FromStr::from_str("256.0.0.1");
+        assert_eq!(None, none);
         // too short
-        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0"));
+        let none: Option<IpAddr> = FromStr::from_str("255.0.0");
+        assert_eq!(None, none);
         // too long
-        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0.1.2"));
+        let none: Option<IpAddr> = FromStr::from_str("255.0.0.1.2");
+        assert_eq!(None, none);
         // no number between dots
-        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0..1"));
+        let none: Option<IpAddr> = FromStr::from_str("255.0..1");
+        assert_eq!(None, none);
     }
 
     #[test]
@@ -389,15 +393,20 @@ fn test_from_str_ipv6() {
                 FromStr::from_str("2a02:6b8::11:11"));
 
         // too long group
-        assert_eq!(None, FromStr::from_str::<IpAddr>("::00000"));
+        let none: Option<IpAddr> = FromStr::from_str("::00000");
+        assert_eq!(None, none);
         // too short
-        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7"));
+        let none: Option<IpAddr> = FromStr::from_str("1:2:3:4:5:6:7");
+        assert_eq!(None, none);
         // too long
-        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7:8:9"));
+        let none: Option<IpAddr> = FromStr::from_str("1:2:3:4:5:6:7:8:9");
+        assert_eq!(None, none);
         // triple colon
-        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:::6:7:8"));
+        let none: Option<IpAddr> = FromStr::from_str("1:2:::6:7:8");
+        assert_eq!(None, none);
         // two double colons
-        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2::6::8"));
+        let none: Option<IpAddr> = FromStr::from_str("1:2::6::8");
+        assert_eq!(None, none);
     }
 
     #[test]
@@ -412,11 +421,15 @@ fn test_from_str_ipv4_in_ipv6() {
                 FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33"));
 
         // colon after v4
-        assert_eq!(None, FromStr::from_str::<IpAddr>("::127.0.0.1:"));
+        let none: Option<IpAddr> = FromStr::from_str("::127.0.0.1:");
+        assert_eq!(None, none);
         // not enought groups
-        assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:127.0.0.1"));
+        let none: Option<IpAddr> = FromStr::from_str("1.2.3.4.5:127.0.0.1");
+        assert_eq!(None, none);
         // too many groups
-        assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:6:7:127.0.0.1"));
+        let none: Option<IpAddr> =
+            FromStr::from_str("1.2.3.4.5:6:7:127.0.0.1");
+        assert_eq!(None, none);
     }
 
     #[test]
@@ -429,13 +442,17 @@ fn test_from_str_socket_addr() {
                 FromStr::from_str("[::127.0.0.1]:22"));
 
         // without port
-        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1"));
+        let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1");
+        assert_eq!(None, none);
         // without port
-        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:"));
+        let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1:");
+        assert_eq!(None, none);
         // wrong brackets around v4
-        assert_eq!(None, FromStr::from_str::<SocketAddr>("[127.0.0.1]:22"));
+        let none: Option<SocketAddr> = FromStr::from_str("[127.0.0.1]:22");
+        assert_eq!(None, none);
         // port out of range
-        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:123456"));
+        let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1:123456");
+        assert_eq!(None, none);
     }
 
     #[test]
index 746fa5668a5f0651e9f898598570ceda87d78715..dc7135f4a61ecb2bea11351b4a6b67fc3e6c9d52 100644 (file)
@@ -16,7 +16,7 @@
 use rt::rtio::{IoFactory, IoFactoryObject,
                RtioSocket, RtioTcpListener,
                RtioTcpListenerObject, RtioTcpStream,
-               RtioTcpStreamObject};
+               RtioTcpStreamObject, RtioStream};
 use rt::local::Local;
 
 pub struct TcpStream(~RtioTcpStreamObject);
@@ -29,7 +29,7 @@ fn new(s: ~RtioTcpStreamObject) -> TcpStream {
     pub fn connect(addr: SocketAddr) -> Option<TcpStream> {
         let stream = unsafe {
             rtdebug!("borrowing io to connect");
-            let io = Local::unsafe_borrow::<IoFactoryObject>();
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
             rtdebug!("about to connect");
             (*io).tcp_connect(addr)
         };
@@ -69,7 +69,7 @@ pub fn socket_name(&mut self) -> Option<SocketAddr> {
 
 impl Reader for TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        match (**self).read(buf) {
+        match (***self).read(buf) {
             Ok(read) => Some(read),
             Err(ioerr) => {
                 // EOF is indicated by returning None
@@ -86,7 +86,7 @@ fn eof(&mut self) -> bool { fail!() }
 
 impl Writer for TcpStream {
     fn write(&mut self, buf: &[u8]) {
-        match (**self).write(buf) {
+        match (***self).write(buf) {
             Ok(_) => (),
             Err(ioerr) => io_error::cond.raise(ioerr),
         }
@@ -100,7 +100,7 @@ fn flush(&mut self) { fail!() }
 impl TcpListener {
     pub fn bind(addr: SocketAddr) -> Option<TcpListener> {
         let listener = unsafe {
-            let io = Local::unsafe_borrow::<IoFactoryObject>();
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
             (*io).tcp_bind(addr)
         };
         match listener {
@@ -166,7 +166,7 @@ fn connect_error() {
         do run_in_newsched_task {
             let mut called = false;
             do io_error::cond.trap(|e| {
-                assert!(e.kind == ConnectionRefused);
+                assert_eq!(e.kind, ConnectionRefused);
                 called = true;
             }).inside {
                 let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
index 644abcbe145ec710fe6025aa3041895111c9ad49..132ca064515c1c867ecf141ad405750124b35dd5 100644 (file)
 
 impl UdpSocket {
     pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
-        let socket = unsafe { (*Local::unsafe_borrow::<IoFactoryObject>()).udp_bind(addr) };
+        let socket = unsafe {
+            let factory: *mut IoFactoryObject = Local::unsafe_borrow();
+            (*factory).udp_bind(addr)
+        };
         match socket {
             Ok(s) => Some(UdpSocket(s)),
             Err(ioerr) => {
diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs
new file mode 100644 (file)
index 0000000..02b3d0f
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Synchronous, in-memory pipes.
+//!
+//! Currently these aren't particularly useful, there only exists bindings
+//! enough so that pipes can be created to child processes.
+
+use prelude::*;
+use super::{Reader, Writer};
+use rt::io::{io_error, read_error, EndOfFile};
+use rt::local::Local;
+use rt::rtio::{RtioPipeObject, RtioStream, IoFactoryObject, IoFactory};
+use rt::uv::pipe;
+
+pub struct PipeStream(~RtioPipeObject);
+
+impl PipeStream {
+    /// Creates a new pipe initialized, but not bound to any particular
+    /// source/destination
+    pub fn new() -> Option<PipeStream> {
+        let pipe = unsafe {
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
+            (*io).pipe_init(false)
+        };
+        match pipe {
+            Ok(p) => Some(PipeStream(p)),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+
+    /// Extracts the underlying libuv pipe to be bound to another source.
+    pub fn uv_pipe(&self) -> pipe::Pipe {
+        // Did someone say multiple layers of indirection?
+        (**self).uv_pipe()
+    }
+}
+
+impl Reader for PipeStream {
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+        match (***self).read(buf) {
+            Ok(read) => Some(read),
+            Err(ioerr) => {
+                // EOF is indicated by returning None
+                if ioerr.kind != EndOfFile {
+                    read_error::cond.raise(ioerr);
+                }
+                return None;
+            }
+        }
+    }
+
+    fn eof(&mut self) -> bool { fail!() }
+}
+
+impl Writer for PipeStream {
+    fn write(&mut self, buf: &[u8]) {
+        match (***self).write(buf) {
+            Ok(_) => (),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+            }
+        }
+    }
+
+    fn flush(&mut self) { fail!() }
+}
index b0ec747800d23287b55453c1e1a2069f69fb796f..7f2d88f994d8cc1fb891ecd438eb7f6e191a8014 100644 (file)
@@ -22,7 +22,7 @@ impl Timer {
     pub fn new() -> Option<Timer> {
         let timer = unsafe {
             rtdebug!("Timer::init: borrowing io to init timer");
-            let io = Local::unsafe_borrow::<IoFactoryObject>();
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
             rtdebug!("about to init timer");
             (*io).timer_init()
         };
index 1608d8cbc2c31fe81c28fbe71e6b4535ec26b4c6..e6003fb1a4449d77f9be472a3984101900be7630 100644 (file)
@@ -20,6 +20,7 @@
 (such as any #[test] function). In both cases the data structures live in
 KillHandle.
 
+
 I. Task killing.
 
 The model for killing involves two atomic flags, the "kill flag" and the
 unkillable flag, which means an unkillable task will see KILL_KILLED and fail
 immediately (rendering the subsequent write to the kill flag unnecessary).
 
+
 II. Exit code propagation.
 
-FIXME(#7544): Decide on the ultimate model for this and document it.
+The basic model for exit code propagation, which is used with the "watched"
+spawn mode (on by default for linked spawns, off for supervised and unlinked
+spawns), is that a parent will wait for all its watched children to exit
+before reporting whether it succeeded or failed. A watching parent will only
+report success if it succeeded and all its children also reported success;
+otherwise, it will report failure. This is most useful for writing test cases:
+
+~~~
+#[test]
+fn test_something_in_another_task {
+    do spawn {
+        assert!(collatz_conjecture_is_false());
+    }
+}
+~~~
+
+Here, as the child task will certainly outlive the parent task, we might miss
+the failure of the child when deciding whether or not the test case passed.
+The watched spawn mode avoids this problem.
+
+In order to propagate exit codes from children to their parents, any
+'watching' parent must wait for all of its children to exit before it can
+report its final exit status. We achieve this by using an UnsafeArc, using the
+reference counting to track how many children are still alive, and using the
+unwrap() operation in the parent's exit path to wait for all children to exit.
+The UnsafeArc referred to here is actually the KillHandle itself.
+
+This also works transitively, as if a "middle" watched child task is itself
+watching a grandchild task, the "middle" task will do unwrap() on its own
+KillHandle (thereby waiting for the grandchild to exit) before dropping its
+reference to its watching parent (which will alert the parent).
+
+While UnsafeArc::unwrap() accomplishes the synchronization, there remains the
+matter of reporting the exit codes themselves. This is easiest when an exiting
+watched task has no watched children of its own:
+
+- If the task with no watched children exits successfully, it need do nothing.
+- If the task with no watched children has failed, it sets a flag in the
+  parent's KillHandle ("any_child_failed") to false. It then stays false forever.
+
+However, if a "middle" watched task with watched children of its own exits
+before its child exits, we need to ensure that the grandparent task may still
+see a failure from the grandchild task. While we could achieve this by having
+each intermediate task block on its handle, this keeps around the other resources
+the task was using. To be more efficient, this is accomplished via "tombstones".
+
+A tombstone is a closure, ~fn() -> bool, which will perform any waiting necessary
+to collect the exit code of descendant tasks. In its environment is captured
+the KillHandle of whichever task created the tombstone, and perhaps also any
+tombstones that that task itself had, and finally also another tombstone,
+effectively creating a lazy-list of heap closures.
+
+When a child wishes to exit early and leave tombstones behind for its parent,
+it must use a LittleLock (pthread mutex) to synchronize with any possible
+sibling tasks which are trying to do the same thing with the same parent.
+However, on the other side, when the parent is ready to pull on the tombstones,
+it need not use this lock, because the unwrap() serves as a barrier that ensures
+no children will remain with references to the handle.
+
+The main logic for creating and assigning tombstones can be found in the
+function reparent_children_to() in the impl for KillHandle.
+
+
+IIA. Issues with exit code propagation.
+
+There are two known issues with the current scheme for exit code propagation.
+
+- As documented in issue #8136, the structure mandates the possibility for stack
+  overflow when collecting tombstones that are very deeply nested. This cannot
+  be avoided with the closure representation, as tombstones end up structured in
+  a sort of tree. However, notably, the tombstones do not actually need to be
+  collected in any particular order, and so a doubly-linked list may be used.
+  However we do not do this yet because DList is in libextra.
+
+- A discussion with Graydon made me realize that if we decoupled the exit code
+  propagation from the parents-waiting action, this could result in a simpler
+  implementation as the exit codes themselves would not have to be propagated,
+  and could instead be propagated implicitly through the taskgroup mechanism
+  that we already have. The tombstoning scheme would still be required. I have
+  not implemented this because currently we can't receive a linked failure kill
+  signal during the task cleanup activity, as that is currently "unkillable",
+  and occurs outside the task's unwinder's "try" block, so would require some
+  restructuring.
 
 */
 
 use task::spawn::Taskgroup;
 use to_bytes::IterBytes;
 use unstable::atomics::{AtomicUint, Relaxed};
-use unstable::sync::{UnsafeAtomicRcBox, LittleLock};
+use unstable::sync::{UnsafeArc, LittleLock};
 use util;
 
 static KILLED_MSG: &'static str = "killed by linked failure";
 static KILL_UNKILLABLE: uint = 2;
 
 struct KillFlag(AtomicUint);
-type KillFlagHandle = UnsafeAtomicRcBox<KillFlag>;
+type KillFlagHandle = UnsafeArc<KillFlag>;
 
 /// A handle to a blocked task. Usually this means having the ~Task pointer by
 /// ownership, but if the task is killable, a killer can steal it at any time.
@@ -127,7 +211,7 @@ struct KillHandleInner {
 
 /// State shared between tasks used for task killing during linked failure.
 #[deriving(Clone)]
-pub struct KillHandle(UnsafeAtomicRcBox<KillHandleInner>);
+pub struct KillHandle(UnsafeArc<KillHandleInner>);
 
 /// Per-task state related to task death, killing, failure, etc.
 pub struct Death {
@@ -233,7 +317,7 @@ pub fn make_selectable(self, num_handles: uint) -> ~[BlockedTask] {
         let handles = match self {
             Unkillable(task) => {
                 let flag = unsafe { KillFlag(AtomicUint::new(cast::transmute(task))) };
-                UnsafeAtomicRcBox::newN(flag, num_handles)
+                UnsafeArc::newN(flag, num_handles)
             }
             Killable(flag_arc) => flag_arc.cloneN(num_handles),
         };
@@ -296,8 +380,8 @@ impl Eq for KillHandle {
 impl KillHandle {
     pub fn new() -> (KillHandle, KillFlagHandle) {
         let (flag, flag_clone) =
-            UnsafeAtomicRcBox::new2(KillFlag(AtomicUint::new(KILL_RUNNING)));
-        let handle = KillHandle(UnsafeAtomicRcBox::new(KillHandleInner {
+            UnsafeArc::new2(KillFlag(AtomicUint::new(KILL_RUNNING)));
+        let handle = KillHandle(UnsafeArc::new(KillHandleInner {
             // Linked failure fields
             killed:     flag,
             unkillable: AtomicUint::new(KILL_RUNNING),
@@ -376,7 +460,7 @@ pub fn killed(&self) -> bool {
     pub fn notify_immediate_failure(&mut self) {
         // A benign data race may happen here if there are failing sibling
         // tasks that were also spawned-watched. The refcount's write barriers
-        // in UnsafeAtomicRcBox ensure that this write will be seen by the
+        // in UnsafeArc ensure that this write will be seen by the
         // unwrapper/destructor, whichever task may unwrap it.
         unsafe { (*self.get()).any_child_failed = true; }
     }
@@ -563,7 +647,11 @@ pub fn inhibit_kill(&mut self, already_failing: bool) {
     /// All calls must be paired with a preceding call to inhibit_kill.
     #[inline]
     pub fn allow_kill(&mut self, already_failing: bool) {
-        rtassert!(self.unkillable != 0);
+        if self.unkillable == 0 {
+            // we need to decrement the counter before failing.
+            self.unkillable -= 1;
+            fail!("Cannot enter a rekillable() block without a surrounding unkillable()");
+        }
         self.unkillable -= 1;
         if self.unkillable == 0 {
             rtassert!(self.kill_handle.is_some());
index 1faad913b50258b82fc7dd11322178213d9a449d..d4f31879c003a01bd49bde2617f33727bbbafe37 100644 (file)
 pub trait Local {
     fn put(value: ~Self);
     fn take() -> ~Self;
-    fn exists() -> bool;
+    fn exists(unused_value: Option<Self>) -> bool;
     fn borrow<T>(f: &fn(&mut Self) -> T) -> T;
+    unsafe fn unsafe_take() -> ~Self;
     unsafe fn unsafe_borrow() -> *mut Self;
     unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
 }
 
 impl Local for Task {
+    #[inline]
     fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
+    #[inline]
     fn take() -> ~Task { unsafe { local_ptr::take() } }
-    fn exists() -> bool { local_ptr::exists() }
+    fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
     fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
         let mut res: Option<T> = None;
         let res_ptr: *mut Option<T> = &mut res;
@@ -43,7 +46,11 @@ fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
             None => { rtabort!("function failed in local_borrow") }
         }
     }
+    #[inline]
+    unsafe fn unsafe_take() -> ~Task { local_ptr::unsafe_take() }
+    #[inline]
     unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
+    #[inline]
     unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
         local_ptr::try_unsafe_borrow()
     }
@@ -52,21 +59,21 @@ unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
 impl Local for Scheduler {
     fn put(value: ~Scheduler) {
         let value = Cell::new(value);
-        do Local::borrow::<Task,()> |task| {
+        do Local::borrow |task: &mut Task| {
             let task = task;
             task.sched = Some(value.take());
         };
     }
+    #[inline]
     fn take() -> ~Scheduler {
-        do Local::borrow::<Task,~Scheduler> |task| {
-            let sched = task.sched.take_unwrap();
-            let task = task;
-            task.sched = None;
-            sched
+        unsafe {
+            // XXX: Unsafe for speed
+            let task: *mut Task = Local::unsafe_borrow();
+            (*task).sched.take_unwrap()
         }
     }
-    fn exists() -> bool {
-        do Local::borrow::<Task,bool> |task| {
+    fn exists(_: Option<Scheduler>) -> bool {
+        do Local::borrow |task: &mut Task| {
             match task.sched {
                 Some(ref _task) => true,
                 None => false
@@ -74,7 +81,7 @@ fn exists() -> bool {
         }
     }
     fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T {
-        do Local::borrow::<Task, T> |task| {
+        do Local::borrow |task: &mut Task| {
             match task.sched {
                 Some(~ref mut task) => {
                     f(task)
@@ -85,8 +92,10 @@ fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T {
             }
         }
     }
+    unsafe fn unsafe_take() -> ~Scheduler { rtabort!("unimpl") }
     unsafe fn unsafe_borrow() -> *mut Scheduler {
-        match (*Local::unsafe_borrow::<Task>()).sched {
+        let task: *mut Task = Local::unsafe_borrow();
+        match (*task).sched {
             Some(~ref mut sched) => {
                 let s: *mut Scheduler = &mut *sched;
                 return s;
@@ -97,10 +106,18 @@ unsafe fn unsafe_borrow() -> *mut Scheduler {
         }
     }
     unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
-        if Local::exists::<Scheduler>() {
-            Some(Local::unsafe_borrow())
-        } else {
-            None
+        let task_opt: Option<*mut Task> = Local::try_unsafe_borrow();
+        match task_opt {
+            Some(task) => {
+                match (*task).sched {
+                    Some(~ref mut sched) => {
+                        let s: *mut Scheduler = &mut *sched;
+                        Some(s)
+                    }
+                    None => None
+                }
+            }
+            None => None
         }
     }
 }
@@ -109,14 +126,17 @@ unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
 impl Local for IoFactoryObject {
     fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") }
     fn take() -> ~IoFactoryObject { rtabort!("unimpl") }
-    fn exists() -> bool { rtabort!("unimpl") }
+    fn exists(_: Option<IoFactoryObject>) -> bool { rtabort!("unimpl") }
     fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") }
+    unsafe fn unsafe_take() -> ~IoFactoryObject { rtabort!("unimpl") }
     unsafe fn unsafe_borrow() -> *mut IoFactoryObject {
-        let sched = Local::unsafe_borrow::<Scheduler>();
+        let sched: *mut Scheduler = Local::unsafe_borrow();
         let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap();
         return io;
     }
-    unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl") }
+    unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> {
+        rtabort!("unimpl")
+    }
 }
 
 
@@ -182,7 +202,7 @@ fn borrow_with_return() {
             let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
             Local::put(task);
 
-            let res = do Local::borrow::<Task,bool> |_task| {
+            let res = do Local::borrow |_task: &mut Task| {
                 true
             };
             assert!(res)
index bca1b4a70f4c933ba604d15f117255bb593251e3..12ec19a1ecc67af345c332a072da5055da186c87 100644 (file)
@@ -13,7 +13,7 @@
 use libc;
 use libc::{c_void, uintptr_t, size_t};
 use ops::Drop;
-use option::{Some, None};
+use option::{Option, None, Some};
 use rt::local::Local;
 use rt::task::Task;
 use unstable::raw;
@@ -40,12 +40,10 @@ impl LocalHeap {
     #[fixed_stack_segment] #[inline(never)]
     pub fn new() -> LocalHeap {
         unsafe {
-            // Don't need synchronization for the single-threaded local heap
-            let synchronized = false as uintptr_t;
             // XXX: These usually come from the environment
             let detailed_leaks = false as uintptr_t;
             let poison_on_free = false as uintptr_t;
-            let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free);
+            let region = rust_new_memory_region(detailed_leaks, poison_on_free);
             assert!(region.is_not_null());
             let boxed = rust_new_boxed_region(region, poison_on_free);
             assert!(boxed.is_not_null());
@@ -91,7 +89,8 @@ fn drop(&self) {
 // A little compatibility function
 pub unsafe fn local_free(ptr: *libc::c_char) {
     // XXX: Unsafe borrow for speed. Lame.
-    match Local::try_unsafe_borrow::<Task>() {
+    let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
+    match task_ptr {
         Some(task) => {
             (*task).heap.free(ptr as *libc::c_void);
         }
@@ -100,7 +99,7 @@ pub unsafe fn local_free(ptr: *libc::c_char) {
 }
 
 pub fn live_allocs() -> *raw::Box<()> {
-    let region = do Local::borrow::<Task, *BoxedRegion> |task| {
+    let region = do Local::borrow |task: &mut Task| {
         task.heap.boxed_region
     };
 
@@ -109,8 +108,7 @@ pub fn live_allocs() -> *raw::Box<()> {
 
 extern {
     #[fast_ffi]
-    fn rust_new_memory_region(synchronized: uintptr_t,
-                               detailed_leaks: uintptr_t,
+    fn rust_new_memory_region(detailed_leaks: uintptr_t,
                                poison_on_free: uintptr_t) -> *MemoryRegion;
     #[fast_ffi]
     fn rust_delete_memory_region(region: *MemoryRegion);
index 77303cb8c06cf5b04759624bd6ffa03d1ee29f5a..e843fd1adef07aa6e258ac16cc52c628b1b374f7 100644 (file)
 use unstable::finally::Finally;
 use tls = rt::thread_local_storage;
 
+static mut RT_TLS_KEY: tls::Key = -1;
+
 /// Initialize the TLS key. Other ops will fail if this isn't executed first.
 #[fixed_stack_segment]
 #[inline(never)]
 pub fn init_tls_key() {
     unsafe {
-        rust_initialize_rt_tls_key();
+        rust_initialize_rt_tls_key(&mut RT_TLS_KEY);
         extern {
-            fn rust_initialize_rt_tls_key();
+            fn rust_initialize_rt_tls_key(key: *mut tls::Key);
         }
     }
 }
@@ -40,6 +42,7 @@ pub fn init_tls_key() {
 /// # Safety note
 ///
 /// Does not validate the pointer type.
+#[inline]
 pub unsafe fn put<T>(sched: ~T) {
     let key = tls_key();
     let void_ptr: *mut c_void = cast::transmute(sched);
@@ -51,6 +54,7 @@ pub unsafe fn put<T>(sched: ~T) {
 /// # Safety note
 ///
 /// Does not validate the pointer type.
+#[inline]
 pub unsafe fn take<T>() -> ~T {
     let key = tls_key();
     let void_ptr: *mut c_void = tls::get(key);
@@ -62,6 +66,23 @@ pub unsafe fn take<T>() -> ~T {
     return ptr;
 }
 
+/// Take ownership of a pointer from thread-local storage.
+///
+/// # Safety note
+///
+/// Does not validate the pointer type.
+/// Leaves the old pointer in TLS for speed.
+#[inline]
+pub unsafe fn unsafe_take<T>() -> ~T {
+    let key = tls_key();
+    let void_ptr: *mut c_void = tls::get(key);
+    if void_ptr.is_null() {
+        rtabort!("thread-local pointer is null. bogus!");
+    }
+    let ptr: ~T = cast::transmute(void_ptr);
+    return ptr;
+}
+
 /// Check whether there is a thread-local pointer installed.
 pub fn exists() -> bool {
     unsafe {
@@ -99,10 +120,15 @@ pub unsafe fn borrow<T>(f: &fn(&mut T)) {
 /// Because this leaves the value in thread-local storage it is possible
 /// For the Scheduler pointer to be aliased
 pub unsafe fn unsafe_borrow<T>() -> *mut T {
-    match try_unsafe_borrow() {
-        Some(p) => p,
-        None => rtabort!("thread-local pointer is null. bogus!")
+    let key = tls_key();
+    let mut void_ptr: *mut c_void = tls::get(key);
+    if void_ptr.is_null() {
+        rtabort!("thread-local pointer is null. bogus!");
     }
+    let ptr: *mut *mut c_void = &mut void_ptr;
+    let ptr: *mut ~T = ptr as *mut ~T;
+    let ptr: *mut T = &mut **ptr;
+    return ptr;
 }
 
 pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
@@ -119,6 +145,7 @@ pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
     }
 }
 
+#[inline]
 fn tls_key() -> tls::Key {
     match maybe_tls_key() {
         Some(key) => key,
@@ -126,15 +153,10 @@ fn tls_key() -> tls::Key {
     }
 }
 
-#[fixed_stack_segment]
-#[inline(never)]
-fn maybe_tls_key() -> Option<tls::Key> {
+#[inline]
+#[cfg(not(test))]
+pub fn maybe_tls_key() -> Option<tls::Key> {
     unsafe {
-        let key: *mut c_void = rust_get_rt_tls_key();
-        let key: &mut tls::Key = cast::transmute(key);
-        let key = *key;
-        // Check that the key has been initialized.
-
         // NB: This is a little racy because, while the key is
         // initalized under a mutex and it's assumed to be initalized
         // in the Scheduler ctor by any thread that needs to use it,
@@ -145,14 +167,19 @@ fn maybe_tls_key() -> Option<tls::Key> {
         // another thread. I think this is fine since the only action
         // they could take if it was initialized would be to check the
         // thread-local value and see that it's not set.
-        if key != -1 {
-            return Some(key);
+        if RT_TLS_KEY != -1 {
+            return Some(RT_TLS_KEY);
         } else {
             return None;
         }
     }
+}
 
-    extern {
-        fn rust_get_rt_tls_key() -> *mut c_void;
-    }
+// XXX: The boundary between the running runtime and the testing runtime
+// seems to be fuzzy at the moment, and trying to use two different keys
+// results in disaster. This should not be necessary.
+#[inline]
+#[cfg(test)]
+pub fn maybe_tls_key() -> Option<tls::Key> {
+    unsafe { ::cast::transmute(::realstd::rt::local_ptr::maybe_tls_key()) }
 }
index 8518ddaeae15f08a0a8076b898c43c0356e1106b..99b5156b319553b1ece12c24ccfa8a8a1e91ecd8 100644 (file)
 use vec::OwnedVector;
 use cell::Cell;
 use option::*;
-use unstable::sync::Exclusive;
+use unstable::sync::{UnsafeArc, LittleLock};
 use clone::Clone;
 
 pub struct MessageQueue<T> {
-    // XXX: Another mystery bug fixed by boxing this lock
-    priv queue: ~Exclusive<~[T]>
+    priv state: UnsafeArc<State<T>>
+}
+
+struct State<T> {
+    count: uint,
+    queue: ~[T],
+    lock: LittleLock
 }
 
 impl<T: Send> MessageQueue<T> {
     pub fn new() -> MessageQueue<T> {
         MessageQueue {
-            queue: ~Exclusive::new(~[])
+            state: UnsafeArc::new(State {
+                count: 0,
+                queue: ~[],
+                lock: LittleLock::new()
+            })
         }
     }
 
     pub fn push(&mut self, value: T) {
         unsafe {
             let value = Cell::new(value);
-            self.queue.with(|q| q.push(value.take()) );
+            let state = self.state.get();
+            do (*state).lock.lock {
+                (*state).count += 1;
+                (*state).queue.push(value.take());
+            }
         }
     }
 
     pub fn pop(&mut self) -> Option<T> {
         unsafe {
-            do self.queue.with |q| {
-                if !q.is_empty() {
-                    Some(q.shift())
+            let state = self.state.get();
+            do (*state).lock.lock {
+                if !(*state).queue.is_empty() {
+                    (*state).count += 1;
+                    Some((*state).queue.shift())
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    /// A pop that may sometimes miss enqueued elements, but is much faster
+    /// to give up without doing any synchronization
+    pub fn casual_pop(&mut self) -> Option<T> {
+        unsafe {
+            let state = self.state.get();
+            // NB: Unsynchronized check
+            if (*state).count == 0 { return None; }
+            do (*state).lock.lock {
+                if !(*state).queue.is_empty() {
+                    (*state).count += 1;
+                    Some((*state).queue.shift())
                 } else {
                     None
                 }
@@ -51,10 +84,10 @@ pub fn pop(&mut self) -> Option<T> {
     }
 }
 
-impl<T> Clone for MessageQueue<T> {
+impl<T: Send> Clone for MessageQueue<T> {
     fn clone(&self) -> MessageQueue<T> {
         MessageQueue {
-            queue: self.queue.clone()
+            state: self.state.clone()
         }
     }
 }
diff --git a/src/libstd/rt/metrics.rs b/src/libstd/rt/metrics.rs
deleted file mode 100644 (file)
index b0c0fa5..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use to_str::ToStr;
-
-pub struct SchedMetrics {
-    // The number of times executing `run_sched_once`.
-    turns: uint,
-    // The number of turns that received a message.
-    messages_received: uint,
-    // The number of turns that ran a task from the queue.
-    tasks_resumed_from_queue: uint,
-    // The number of turns that found no work to perform.
-    wasted_turns: uint,
-    // The number of times the scheduler went to sleep.
-    sleepy_times: uint,
-    // Context switches from the scheduler into a task.
-    context_switches_sched_to_task: uint,
-    // Context switches from a task into the scheduler.
-    context_switches_task_to_sched: uint,
-    // Context switches from a task to a task.
-    context_switches_task_to_task: uint,
-    // Message sends that unblock the receiver
-    rendezvous_sends: uint,
-    // Message sends that do not unblock the receiver
-    non_rendezvous_sends: uint,
-    // Message receives that do not block the receiver
-    rendezvous_recvs: uint,
-    // Message receives that block the receiver
-    non_rendezvous_recvs: uint,
-    // JoinLatch releases that create tombstones
-    release_tombstone: uint,
-    // JoinLatch releases that do not create tombstones
-    release_no_tombstone: uint,
-}
-
-impl SchedMetrics {
-    pub fn new() -> SchedMetrics {
-        SchedMetrics {
-            turns: 0,
-            messages_received: 0,
-            tasks_resumed_from_queue: 0,
-            wasted_turns: 0,
-            sleepy_times: 0,
-            context_switches_sched_to_task: 0,
-            context_switches_task_to_sched: 0,
-            context_switches_task_to_task: 0,
-            rendezvous_sends: 0,
-            non_rendezvous_sends: 0,
-            rendezvous_recvs: 0,
-            non_rendezvous_recvs: 0,
-            release_tombstone: 0,
-            release_no_tombstone: 0
-        }
-    }
-}
-
-impl ToStr for SchedMetrics {
-    fn to_str(&self) -> ~str {
-        fmt!("turns: %u\n\
-              messages_received: %u\n\
-              tasks_resumed_from_queue: %u\n\
-              wasted_turns: %u\n\
-              sleepy_times: %u\n\
-              context_switches_sched_to_task: %u\n\
-              context_switches_task_to_sched: %u\n\
-              context_switches_task_to_task: %u\n\
-              rendezvous_sends: %u\n\
-              non_rendezvous_sends: %u\n\
-              rendezvous_recvs: %u\n\
-              non_rendezvous_recvs: %u\n\
-              release_tombstone: %u\n\
-              release_no_tombstone: %u\n\
-              ",
-             self.turns,
-             self.messages_received,
-             self.tasks_resumed_from_queue,
-             self.wasted_turns,
-             self.sleepy_times,
-             self.context_switches_sched_to_task,
-             self.context_switches_task_to_sched,
-             self.context_switches_task_to_task,
-             self.rendezvous_sends,
-             self.non_rendezvous_sends,
-             self.rendezvous_recvs,
-             self.non_rendezvous_recvs,
-             self.release_tombstone,
-             self.release_no_tombstone
-        )
-    }
-}
\ No newline at end of file
index 8b3e65b57ab7abe37995025474d11b7414f2bc84..7728a388c658a689c023f7b583acb00093684ee0 100644 (file)
 */
 
 #[doc(hidden)];
-#[deny(unused_imports)];
-#[deny(unused_mut)];
-#[deny(unused_variable)];
-#[deny(unused_unsafe)];
 
 use cell::Cell;
 use clone::Clone;
 use container::Container;
 use iterator::{Iterator, range};
-use option::{Some, None};
+use option::{Option, None, Some};
 use ptr::RawPtr;
 use rt::local::Local;
 use rt::sched::{Scheduler, Shutdown};
@@ -74,7 +70,7 @@
 use rt::work_queue::WorkQueue;
 use rt::uv::uvio::UvEventLoop;
 use unstable::atomics::{AtomicInt, SeqCst};
-use unstable::sync::UnsafeAtomicRcBox;
+use unstable::sync::UnsafeArc;
 use vec::{OwnedVector, MutableVector};
 
 /// The global (exchange) heap.
 /// Bindings to pthread/windows thread-local storage.
 pub mod thread_local_storage;
 
-pub mod metrics;
-
 // FIXME #5248 shouldn't be pub
 /// Just stuff
 pub mod util;
@@ -224,10 +218,7 @@ pub fn init(argc: int, argv: **u8, crate_map: *u8) {
         args::init(argc, argv);
         env::init();
         logging::init(crate_map);
-        rust_update_gc_metadata(crate_map);
     }
-
-    externfn!(fn rust_update_gc_metadata(crate_map: *u8));
 }
 
 /// One-time runtime cleanup.
@@ -316,7 +307,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
 
     // Create a shared cell for transmitting the process exit
     // code from the main task to this function.
-    let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
+    let exit_code = UnsafeArc::new(AtomicInt::new(0));
     let exit_code_clone = exit_code.clone();
 
     // When the main task exits, after all the tasks in the main
@@ -413,7 +404,8 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
 
 pub fn in_sched_context() -> bool {
     unsafe {
-        match Local::try_unsafe_borrow::<Task>() {
+        let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
+        match task_ptr {
             Some(task) => {
                 match (*task).task_type {
                     SchedTask => true,
@@ -427,7 +419,8 @@ pub fn in_sched_context() -> bool {
 
 pub fn in_green_task_context() -> bool {
     unsafe {
-        match Local::try_unsafe_borrow::<Task>() {
+        let task: Option<*mut Task> = Local::try_unsafe_borrow();
+        match task {
             Some(task) => {
                 match (*task).task_type {
                     GreenTask(_) => true,
index 1788b7a04e33446c3e8c04b77671481eed5bea29..1a7ef6ea309b9ac78c4f781298b782a93b131c93 100644 (file)
@@ -8,12 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use libc;
 use option::*;
 use result::*;
 use libc::c_int;
 
 use rt::io::IoError;
 use super::io::net::ip::{IpAddr, SocketAddr};
+use rt::uv;
 use rt::uv::uvio;
 use path::Path;
 use super::io::support::PathLike;
@@ -30,6 +32,9 @@
 pub type RtioUdpSocketObject = uvio::UvUdpSocket;
 pub type RtioTimerObject = uvio::UvTimer;
 pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
+pub type RtioPipeObject = uvio::UvPipeStream;
+pub type RtioProcessObject = uvio::UvProcess;
+pub type RtioProcessConfig<'self> = uv::process::Config<'self>;
 
 pub trait EventLoop {
     fn run(&mut self);
@@ -72,6 +77,13 @@ pub trait IoFactory {
     fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
         -> Result<~RtioFileStream, IoError>;
     fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
+    fn pipe_init(&mut self, ipc: bool) -> Result<~RtioPipeObject, IoError>;
+    fn spawn(&mut self, config: &RtioProcessConfig) -> Result<~RtioProcessObject, IoError>;
+}
+
+pub trait RtioStream {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
 }
 
 pub trait RtioTcpListener : RtioSocket {
@@ -80,9 +92,7 @@ pub trait RtioTcpListener : RtioSocket {
     fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>;
 }
 
-pub trait RtioTcpStream : RtioSocket {
-    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
-    fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
+pub trait RtioTcpStream : RtioSocket + RtioStream {
     fn peer_name(&mut self) -> Result<SocketAddr, IoError>;
     fn control_congestion(&mut self) -> Result<(), IoError>;
     fn nodelay(&mut self) -> Result<(), IoError>;
@@ -124,3 +134,9 @@ pub trait RtioFileStream {
     fn tell(&self) -> Result<u64, IoError>;
     fn flush(&mut self) -> Result<(), IoError>;
 }
+
+pub trait RtioProcess {
+    fn id(&self) -> libc::pid_t;
+    fn kill(&mut self, signal: int) -> Result<(), IoError>;
+    fn wait(&mut self) -> int;
+}
index 5ec2df32c48caaf6982d03d65a16ef2c97b56eac..b393832871dd7dae2074f028d5fafea4c8fa612c 100644 (file)
@@ -24,7 +24,6 @@
 use rt::local_ptr;
 use rt::local::Local;
 use rt::rtio::{RemoteCallback, PausibleIdleCallback};
-use rt::metrics::SchedMetrics;
 use borrow::{to_uint};
 use cell::Cell;
 use rand::{XorShiftRng, RngUtil};
@@ -71,7 +70,6 @@ pub struct Scheduler {
     /// An action performed after a context switch on behalf of the
     /// code running before the context switch
     cleanup_job: Option<CleanupJob>,
-    metrics: SchedMetrics,
     /// Should this scheduler run any task, or only pinned tasks?
     run_anything: bool,
     /// If the scheduler shouldn't run some tasks, a friend to send
@@ -83,6 +81,14 @@ pub struct Scheduler {
     idle_callback: Option<~PausibleIdleCallback>
 }
 
+/// An indication of how hard to work on a given operation, the difference
+/// mainly being whether memory is synchronized or not
+#[deriving(Eq)]
+enum EffortLevel {
+    DontTryTooHard,
+    GiveItYourBest
+}
+
 impl Scheduler {
 
     // * Initialization Functions
@@ -118,7 +124,6 @@ pub fn new_special(event_loop: ~EventLoopObject,
             stack_pool: StackPool::new(),
             sched_task: None,
             cleanup_job: None,
-            metrics: SchedMetrics::new(),
             run_anything: run_anything,
             friend_handle: friend,
             rng: XorShiftRng::new(),
@@ -164,13 +169,13 @@ pub fn bootstrap(~self, task: ~Task) {
         // successfully run the input task. Start by running the
         // scheduler. Grab it out of TLS - performing the scheduler
         // action will have given it away.
-        let sched = Local::take::<Scheduler>();
+        let sched: ~Scheduler = Local::take();
 
         rtdebug!("starting scheduler %u", sched.sched_id());
         sched.run();
 
         // Close the idle callback.
-        let mut sched = Local::take::<Scheduler>();
+        let mut sched: ~Scheduler = Local::take();
         sched.idle_callback.get_mut_ref().close();
         // Make one go through the loop to run the close callback.
         sched.run();
@@ -180,13 +185,13 @@ pub fn bootstrap(~self, task: ~Task) {
         // cleaning up the memory it uses. As we didn't actually call
         // task.run() on the scheduler task we never get through all
         // the cleanup code it runs.
-        let mut stask = Local::take::<Task>();
+        let mut stask: ~Task = Local::take();
 
         rtdebug!("stopping scheduler %u", stask.sched.get_ref().sched_id());
 
         // Should not have any messages
         let message = stask.sched.get_mut_ref().message_queue.pop();
-        assert!(message.is_none());
+        rtassert!(message.is_none());
 
         stask.destroyed = true;
     }
@@ -207,7 +212,7 @@ pub fn run(~self) {
             // Our scheduler must be in the task before the event loop
             // is started.
             let self_sched = Cell::new(self_sched);
-            do Local::borrow::<Task,()> |stask| {
+            do Local::borrow |stask: &mut Task| {
                 stask.sched = Some(self_sched.take());
             };
 
@@ -229,7 +234,7 @@ fn run_sched_once() {
         // already have a scheduler stored in our local task, so we
         // start off by taking it. This is the only path through the
         // scheduler where we get the scheduler this way.
-        let mut sched = Local::take::<Scheduler>();
+        let mut sched: ~Scheduler = Local::take();
 
         // Assume that we need to continue idling unless we reach the
         // end of this function without performing an action.
@@ -237,14 +242,21 @@ fn run_sched_once() {
 
         // First we check for scheduler messages, these are higher
         // priority than regular tasks.
-        let sched = match sched.interpret_message_queue() {
+        let sched = match sched.interpret_message_queue(DontTryTooHard) {
             Some(sched) => sched,
             None => return
         };
 
         // This helper will use a randomized work-stealing algorithm
         // to find work.
-        let mut sched = match sched.do_work() {
+        let sched = match sched.do_work() {
+            Some(sched) => sched,
+            None => return
+        };
+
+        // Now, before sleeping we need to find out if there really
+        // were any messages. Give it your best!
+        let mut sched = match sched.interpret_message_queue(GiveItYourBest) {
             Some(sched) => sched,
             None => return
         };
@@ -252,10 +264,8 @@ fn run_sched_once() {
         // If we got here then there was no work to do.
         // Generate a SchedHandle and push it to the sleeper list so
         // somebody can wake us up later.
-        sched.metrics.wasted_turns += 1;
         if !sched.sleepy && !sched.no_sleep {
             rtdebug!("scheduler has no work to do, going to sleep");
-            sched.metrics.sleepy_times += 1;
             sched.sleepy = true;
             let handle = sched.make_handle();
             sched.sleeper_list.push(handle);
@@ -277,10 +287,18 @@ fn run_sched_once() {
     // returns the still-available scheduler. At this point all
     // message-handling will count as a turn of work, and as a result
     // return None.
-    fn interpret_message_queue(~self) -> Option<~Scheduler> {
+    fn interpret_message_queue(~self, effort: EffortLevel) -> Option<~Scheduler> {
 
         let mut this = self;
-        match this.message_queue.pop() {
+
+        let msg = if effort == DontTryTooHard {
+            // Do a cheap check that may miss messages
+            this.message_queue.casual_pop()
+        } else {
+            this.message_queue.pop()
+        };
+
+        match msg {
             Some(PinnedTask(task)) => {
                 let mut task = task;
                 task.give_home(Sched(this.make_handle()));
@@ -469,10 +487,7 @@ pub fn enqueue_task(&mut self, task: ~Task) {
         // We've made work available. Notify a
         // sleeping scheduler.
 
-        // XXX: perf. Check for a sleeper without
-        // synchronizing memory.  It's not critical
-        // that we always find it.
-        match this.sleeper_list.pop() {
+        match this.sleeper_list.casual_pop() {
             Some(handle) => {
                         let mut handle = handle;
                 handle.send(Wake)
@@ -505,7 +520,9 @@ pub fn change_task_context(~self,
         let mut this = self;
 
         // The current task is grabbed from TLS, not taken as an input.
-        let current_task: ~Task = Local::take::<Task>();
+        // Doing an unsafe_take to avoid writing back a null pointer -
+        // We're going to call `put` later to do that.
+        let current_task: ~Task = unsafe { Local::unsafe_take() };
 
         // Check that the task is not in an atomically() section (e.g.,
         // holding a pthread mutex, which could deadlock the scheduler).
@@ -537,7 +554,8 @@ pub fn change_task_context(~self,
 
             let current_task: &mut Task = match sched.cleanup_job {
                 Some(CleanupJob { task: ref task, _ }) => {
-                    transmute_mut_region(*transmute_mut_unsafe(task))
+                    let task_ptr: *~Task = task;
+                    transmute_mut_region(*transmute_mut_unsafe(task_ptr))
                 }
                 None => {
                     rtabort!("no cleanup job");
@@ -563,11 +581,10 @@ pub fn change_task_context(~self,
         // run the cleanup job, as expected by the previously called
         // swap_contexts function.
         unsafe {
-            let sched = Local::unsafe_borrow::<Scheduler>();
-            (*sched).run_cleanup_job();
+            let task: *mut Task = Local::unsafe_borrow();
+            (*task).sched.get_mut_ref().run_cleanup_job();
 
             // Must happen after running the cleanup job (of course).
-            let task = Local::unsafe_borrow::<Task>();
             (*task).death.check_killed((*task).unwinder.unwinding);
         }
     }
@@ -669,13 +686,13 @@ pub fn terminate_current_task(~self) {
     }
 
     pub fn run_task(task: ~Task) {
-        let sched = Local::take::<Scheduler>();
+        let sched: ~Scheduler = Local::take();
         sched.process_task(task, Scheduler::switch_task).map_move(Local::put);
     }
 
     pub fn run_task_later(next_task: ~Task) {
         let next_task = Cell::new(next_task);
-        do Local::borrow::<Scheduler,()> |sched| {
+        do Local::borrow |sched: &mut Scheduler| {
             sched.enqueue_task(next_task.take());
         };
     }
@@ -1007,12 +1024,12 @@ fn test_io_callback() {
         // exit before emptying the work queue
         do run_in_newsched_task {
             do spawntask {
-                let sched = Local::take::<Scheduler>();
+                let sched: ~Scheduler = Local::take();
                 do sched.deschedule_running_task_and_then |sched, task| {
                     let task = Cell::new(task);
                     do sched.event_loop.callback_ms(10) {
                         rtdebug!("in callback");
-                        let mut sched = Local::take::<Scheduler>();
+                        let mut sched: ~Scheduler = Local::take();
                         sched.enqueue_blocked_task(task.take());
                         Local::put(sched);
                     }
index 19a4948af3c5ae8e8582536b9776ef999127b982..6cde0a1f2169f5f6f47c38040d1dc15570e5f7f4 100644 (file)
@@ -26,3 +26,4 @@ pub trait SelectInner {
 pub trait SelectPortInner<T> {
     fn recv_ready(self) -> Option<T>;
 }
+
index d327023de978adb8bf33946ed10ffee9df61392d..f4fdf15cda62e2f11ea71eabf16401e127e99530 100644 (file)
 use vec::OwnedVector;
 use option::{Option, Some, None};
 use cell::Cell;
-use unstable::sync::Exclusive;
+use unstable::sync::{UnsafeArc, LittleLock};
 use rt::sched::SchedHandle;
 use clone::Clone;
 
 pub struct SleeperList {
-    priv stack: ~Exclusive<~[SchedHandle]>
+    priv state: UnsafeArc<State>
+}
+
+struct State {
+    count: uint,
+    stack: ~[SchedHandle],
+    lock: LittleLock
 }
 
 impl SleeperList {
     pub fn new() -> SleeperList {
         SleeperList {
-            stack: ~Exclusive::new(~[])
+            state: UnsafeArc::new(State {
+                count: 0,
+                stack: ~[],
+                lock: LittleLock::new()
+            })
         }
     }
 
     pub fn push(&mut self, handle: SchedHandle) {
         let handle = Cell::new(handle);
         unsafe {
-            self.stack.with(|s| s.push(handle.take()));
+            let state = self.state.get();
+            do (*state).lock.lock {
+                (*state).count += 1;
+                (*state).stack.push(handle.take());
+            }
         }
     }
 
     pub fn pop(&mut self) -> Option<SchedHandle> {
         unsafe {
-            do self.stack.with |s| {
-                if !s.is_empty() {
-                    Some(s.pop())
+            let state = self.state.get();
+            do (*state).lock.lock {
+                if !(*state).stack.is_empty() {
+                    (*state).count -= 1;
+                    Some((*state).stack.pop())
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    /// A pop that may sometimes miss enqueued elements, but is much faster
+    /// to give up without doing any synchronization
+    pub fn casual_pop(&mut self) -> Option<SchedHandle> {
+        unsafe {
+            let state = self.state.get();
+            // NB: Unsynchronized check
+            if (*state).count == 0 { return None; }
+            do (*state).lock.lock {
+                if !(*state).stack.is_empty() {
+                    // NB: count is also protected by the lock
+                    (*state).count -= 1;
+                    Some((*state).stack.pop())
                 } else {
                     None
                 }
@@ -53,7 +88,7 @@ pub fn pop(&mut self) -> Option<SchedHandle> {
 impl Clone for SleeperList {
     fn clone(&self) -> SleeperList {
         SleeperList {
-            stack: self.stack.clone()
+            state: self.state.clone()
         }
     }
-}
\ No newline at end of file
+}
index 4b2a9b7a6cce40b418df65d081be82ac787a5ab9..da70659acec2edfe577607b7a54b1fa1152cad27 100644 (file)
@@ -46,7 +46,9 @@ pub fn start(&self) -> *uint {
 
     /// Point one word beyond the high end of the allocated stack
     pub fn end(&self) -> *uint {
-        vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+        unsafe {
+            vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+        }
     }
 }
 
index 12ba39a6dcd67c9195636a2b0a6d92b95e130cdc..da81aab0f7849eb6bfd5742629af46168b383219 100644 (file)
@@ -16,8 +16,8 @@
 use borrow;
 use cast::transmute;
 use cleanup;
+use local_data;
 use libc::{c_void, uintptr_t};
-use ptr;
 use prelude::*;
 use option::{Option, Some, None};
 use rt::borrowck;
@@ -59,7 +59,7 @@ pub struct Task {
 }
 
 pub enum TaskType {
-    GreenTask(Option<~SchedHome>),
+    GreenTask(Option<SchedHome>),
     SchedTask
 }
 
@@ -80,7 +80,7 @@ pub enum SchedHome {
 }
 
 pub struct GarbageCollector;
-pub struct LocalStorage(*c_void, Option<extern "Rust" fn(*c_void)>);
+pub struct LocalStorage(Option<local_data::Map>);
 
 pub struct Unwinder {
     unwinding: bool,
@@ -93,7 +93,7 @@ impl Task {
     pub fn build_homed_child(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
         let f = Cell::new(f);
         let home = Cell::new(home);
-        do Local::borrow::<Task, ~Task> |running_task| {
+        do Local::borrow |running_task: &mut Task| {
             let mut sched = running_task.sched.take_unwrap();
             let new_task = ~running_task.new_child_homed(&mut sched.stack_pool,
                                                          stack_size,
@@ -111,7 +111,7 @@ pub fn build_child(stack_size: Option<uint>, f: ~fn()) -> ~Task {
     pub fn build_homed_root(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
         let f = Cell::new(f);
         let home = Cell::new(home);
-        do Local::borrow::<Task, ~Task> |running_task| {
+        do Local::borrow |running_task: &mut Task| {
             let mut sched = running_task.sched.take_unwrap();
             let new_task = ~Task::new_root_homed(&mut sched.stack_pool,
                                                  stack_size,
@@ -130,7 +130,7 @@ pub fn new_sched_task() -> Task {
         Task {
             heap: LocalHeap::new(),
             gc: GarbageCollector,
-            storage: LocalStorage(ptr::null(), None),
+            storage: LocalStorage(None),
             logger: StdErrLogger,
             unwinder: Unwinder { unwinding: false },
             taskgroup: None,
@@ -164,7 +164,7 @@ pub fn new_root_homed(stack_pool: &mut StackPool,
         Task {
             heap: LocalHeap::new(),
             gc: GarbageCollector,
-            storage: LocalStorage(ptr::null(), None),
+            storage: LocalStorage(None),
             logger: StdErrLogger,
             unwinder: Unwinder { unwinding: false },
             taskgroup: None,
@@ -173,7 +173,7 @@ pub fn new_root_homed(stack_pool: &mut StackPool,
             name: None,
             coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
             sched: None,
-            task_type: GreenTask(Some(~home)),
+            task_type: GreenTask(Some(home)),
             borrow_list: None
         }
     }
@@ -186,7 +186,7 @@ pub fn new_child_homed(&mut self,
         Task {
             heap: LocalHeap::new(),
             gc: GarbageCollector,
-            storage: LocalStorage(ptr::null(), None),
+            storage: LocalStorage(None),
             logger: StdErrLogger,
             unwinder: Unwinder { unwinding: false },
             taskgroup: None,
@@ -196,7 +196,7 @@ pub fn new_child_homed(&mut self,
             name: None,
             coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
             sched: None,
-            task_type: GreenTask(Some(~home)),
+            task_type: GreenTask(Some(home)),
             borrow_list: None
         }
     }
@@ -204,7 +204,7 @@ pub fn new_child_homed(&mut self,
     pub fn give_home(&mut self, new_home: SchedHome) {
         match self.task_type {
             GreenTask(ref mut home) => {
-                *home = Some(~new_home);
+                *home = Some(new_home);
             }
             SchedTask => {
                 rtabort!("type error: used SchedTask as GreenTask");
@@ -216,7 +216,7 @@ pub fn take_unwrap_home(&mut self) -> SchedHome {
         match self.task_type {
             GreenTask(ref mut home) => {
                 let out = home.take_unwrap();
-                return *out;
+                return out;
             }
             SchedTask => {
                 rtabort!("type error: used SchedTask as GreenTask");
@@ -233,15 +233,8 @@ pub fn run(&mut self, f: &fn()) {
 
             // Run the task main function, then do some cleanup.
             do f.finally {
-
-                // Destroy task-local storage. This may run user dtors.
-                match self.storage {
-                    LocalStorage(ptr, Some(ref dtor)) => {
-                        (*dtor)(ptr)
-                    }
-                    _ => ()
-                }
-
+                // First, destroy task-local storage. This may run user dtors.
+                //
                 // FIXME #8302: Dear diary. I'm so tired and confused.
                 // There's some interaction in rustc between the box
                 // annihilator and the TLS dtor by which TLS is
@@ -253,7 +246,13 @@ pub fn run(&mut self, f: &fn()) {
                 // TLS would be reinitialized but never destroyed,
                 // but somehow this works. I have no idea what's going
                 // on but this seems to make things magically work. FML.
-                self.storage = LocalStorage(ptr::null(), None);
+                //
+                // (added after initial comment) A possible interaction here is
+                // that the destructors for the objects in TLS themselves invoke
+                // TLS, or possibly some destructors for those objects being
+                // annihilated invoke TLS. Sadly these two operations seemed to
+                // be intertwined, and miraculously work for now...
+                self.storage.take();
 
                 // Destroy remaining boxes. Also may run user dtors.
                 unsafe { cleanup::annihilate(); }
@@ -275,8 +274,8 @@ pub fn run(&mut self, f: &fn()) {
 
     pub fn is_home_no_tls(&self, sched: &~Scheduler) -> bool {
         match self.task_type {
-            GreenTask(Some(~AnySched)) => { false }
-            GreenTask(Some(~Sched(SchedHandle { sched_id: ref id, _}))) => {
+            GreenTask(Some(AnySched)) => { false }
+            GreenTask(Some(Sched(SchedHandle { sched_id: ref id, _}))) => {
                 *id == sched.sched_id()
             }
             GreenTask(None) => {
@@ -291,8 +290,8 @@ pub fn is_home_no_tls(&self, sched: &~Scheduler) -> bool {
 
     pub fn homed(&self) -> bool {
         match self.task_type {
-            GreenTask(Some(~AnySched)) => { false }
-            GreenTask(Some(~Sched(SchedHandle { _ }))) => { true }
+            GreenTask(Some(AnySched)) => { false }
+            GreenTask(Some(Sched(SchedHandle { _ }))) => { true }
             GreenTask(None) => {
                 rtabort!("task without home");
             }
@@ -305,15 +304,15 @@ pub fn homed(&self) -> bool {
     // Grab both the scheduler and the task from TLS and check if the
     // task is executing on an appropriate scheduler.
     pub fn on_appropriate_sched() -> bool {
-        do Local::borrow::<Task,bool> |task| {
+        do Local::borrow |task: &mut Task| {
             let sched_id = task.sched.get_ref().sched_id();
             let sched_run_anything = task.sched.get_ref().run_anything;
             match task.task_type {
-                GreenTask(Some(~AnySched)) => {
+                GreenTask(Some(AnySched)) => {
                     rtdebug!("anysched task in sched check ****");
                     sched_run_anything
                 }
-                GreenTask(Some(~Sched(SchedHandle { sched_id: ref id, _ }))) => {
+                GreenTask(Some(Sched(SchedHandle { sched_id: ref id, _ }))) => {
                     rtdebug!("homed task in sched check ****");
                     *id == sched_id
                 }
@@ -369,7 +368,7 @@ fn build_start_wrapper(start: ~fn()) -> ~fn() {
             unsafe {
 
                 // Again - might work while safe, or it might not.
-                do Local::borrow::<Scheduler,()> |sched| {
+                do Local::borrow |sched: &mut Scheduler| {
                     sched.run_cleanup_job();
                 }
 
@@ -378,7 +377,7 @@ fn build_start_wrapper(start: ~fn()) -> ~fn() {
                 // simply unsafe_borrow it to get this reference. We
                 // need to still have the task in TLS though, so we
                 // need to unsafe_borrow.
-                let task = Local::unsafe_borrow::<Task>();
+                let task: *mut Task = Local::unsafe_borrow();
 
                 do (*task).run {
                     // N.B. Removing `start` from the start wrapper
@@ -397,7 +396,7 @@ fn build_start_wrapper(start: ~fn()) -> ~fn() {
             }
 
             // We remove the sched from the Task in TLS right now.
-            let sched = Local::take::<Scheduler>();
+            let sched: ~Scheduler = Local::take();
             // ... allowing us to give it away when performing a
             // scheduling operation.
             sched.terminate_current_task()
index a9cd29c18c9652d58a2fbe10704d236bf6650ccb..b2c2c670b5558eec4482738cb44789622a9967b0 100644 (file)
@@ -86,7 +86,7 @@ pub unsafe fn get(key: Key) -> *mut c_void {
     TlsGetValue(key)
 }
 
-#[cfg(windows)]
+#[cfg(windows, target_arch = "x86")]
 #[abi = "stdcall"]
 extern "stdcall" {
        fn TlsAlloc() -> DWORD;
@@ -94,6 +94,13 @@ pub unsafe fn get(key: Key) -> *mut c_void {
        fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
 }
 
+#[cfg(windows, target_arch = "x86_64")]
+extern {
+       fn TlsAlloc() -> DWORD;
+       fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
+       fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+}
+
 #[test]
 fn tls_smoke_test() {
     use cast::transmute;
index 247893f75de0096c2dc89806b0a444b184ad0028..b8e535e4c7dfd3ac202427402039dcf6f58e39e2 100644 (file)
@@ -51,7 +51,7 @@ pub fn send(&mut self, val: T) {
                 // There's a waiting task. Wake it up
                 rtdebug!("waking blocked tube");
                 let task = (*state).blocked_task.take_unwrap();
-                let sched = Local::take::<Scheduler>();
+                let sched: ~Scheduler = Local::take();
                 sched.resume_blocked_task_immediately(task);
             }
         }
@@ -67,7 +67,7 @@ pub fn recv(&mut self) -> T {
                 rtdebug!("blocking on tube recv");
                 assert!(self.p.refcount() > 1); // There better be somebody to wake us up
                 assert!((*state).blocked_task.is_none());
-                let sched = Local::take::<Scheduler>();
+                let sched: ~Scheduler = Local::take();
                 do sched.deschedule_running_task_and_then |_, task| {
                     (*state).blocked_task = Some(task);
                 }
@@ -102,7 +102,7 @@ fn simple_test() {
             let mut tube: Tube<int> = Tube::new();
             let tube_clone = tube.clone();
             let tube_clone_cell = Cell::new(tube_clone);
-            let sched = Local::take::<Scheduler>();
+            let sched: ~Scheduler = Local::take();
             do sched.deschedule_running_task_and_then |sched, task| {
                 let mut tube_clone = tube_clone_cell.take();
                 tube_clone.send(1);
@@ -119,7 +119,7 @@ fn blocking_test() {
             let mut tube: Tube<int> = Tube::new();
             let tube_clone = tube.clone();
             let tube_clone = Cell::new(tube_clone);
-            let sched = Local::take::<Scheduler>();
+            let sched: ~Scheduler = Local::take();
             do sched.deschedule_running_task_and_then |sched, task| {
                 let tube_clone = Cell::new(tube_clone.take());
                 do sched.event_loop.callback {
@@ -143,7 +143,7 @@ fn many_blocking_test() {
             let mut tube: Tube<int> = Tube::new();
             let tube_clone = tube.clone();
             let tube_clone = Cell::new(tube_clone);
-            let sched = Local::take::<Scheduler>();
+            let sched: ~Scheduler = Local::take();
             do sched.deschedule_running_task_and_then |sched, task| {
                 callback_send(tube_clone.take(), 0);
 
@@ -151,7 +151,7 @@ fn callback_send(tube: Tube<int>, i: int) {
                     if i == 100 { return; }
 
                     let tube = Cell::new(Cell::new(tube));
-                    do Local::borrow::<Scheduler, ()> |sched| {
+                    do Local::borrow |sched: &mut Scheduler| {
                         let tube = tube.take();
                         do sched.event_loop.callback {
                             let mut tube = tube.take();
index 1f29830aa04f364e076dc4caa474ebded19da0f4..9113f03ffee1cd9402574ea4db971ffbd30be56c 100644 (file)
 use option::{Some, None};
 use os;
 use str::StrSlice;
+use unstable::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
 
 #[cfg(target_os="macos")]
 use unstable::running_on_valgrind;
 
+// Indicates whether we should perform expensive sanity checks, including rtassert!
+// XXX: Once the runtime matures remove the `true` below to turn off rtassert, etc.
+pub static ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || cfg!(rtassert);
+
 /// Get the number of cores available
 pub fn num_cpus() -> uint {
     #[fixed_stack_segment]; #[inline(never)];
@@ -129,24 +134,12 @@ fn abort() -> ! {
     }
 }
 
-pub fn set_exit_status(code: int) {
-    #[fixed_stack_segment]; #[inline(never)];
-    unsafe {
-        return rust_set_exit_status_newrt(code as libc::uintptr_t);
-    }
+static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
 
-    extern {
-        fn rust_set_exit_status_newrt(code: libc::uintptr_t);
-    }
+pub fn set_exit_status(code: int) {
+    unsafe { EXIT_STATUS.store(code, SeqCst) }
 }
 
 pub fn get_exit_status() -> int {
-    #[fixed_stack_segment]; #[inline(never)];
-    unsafe {
-        return rust_get_exit_status_newrt() as int;
-    }
-
-    extern {
-        fn rust_get_exit_status_newrt() -> libc::uintptr_t;
-    }
+    unsafe { EXIT_STATUS.load(SeqCst) }
 }
index d0ca38317cbededd13675b41c17ad764ee7f982b..ff7bb9dd03abcf8403fd40a0d703e44c2c339618 100644 (file)
@@ -34,7 +34,7 @@ pub fn new(loop_: &mut Loop, cb: AsyncCallback) -> AsyncWatcher {
 
         extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
             let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
-            let status = status_to_maybe_uv_error(watcher, status);
+            let status = status_to_maybe_uv_error(status);
             let data = watcher.get_watcher_data();
             let cb = data.async_cb.get_ref();
             (*cb)(watcher, status);
index 405dfe0a7f099b6606a08c4a9f9d2897255b2f69..5c77181d7eb83a7098a3cb194a85ee89c6157fa8 100644 (file)
@@ -11,8 +11,8 @@
 use prelude::*;
 use ptr::null;
 use libc::c_void;
-use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
-             status_to_maybe_uv_error_with_loop, UvError};
+use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, UvError};
+use rt::uv::status_to_maybe_uv_error;
 use rt::uv::uvll;
 use rt::uv::uvll::*;
 use super::super::io::support::PathLike;
@@ -62,7 +62,7 @@ pub fn open<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int,
     pub fn open_sync<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int)
           -> Result<int, UvError> {
         let result = FsRequest::open_common(loop_, path, flags, mode, None);
-        sync_cleanup(loop_, result)
+        sync_cleanup(result)
     }
 
     fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) -> int {
@@ -83,11 +83,11 @@ fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) ->
     }
     pub fn unlink<P: PathLike>(loop_: &Loop, path: &P, cb: FsCallback) {
         let result = FsRequest::unlink_common(loop_, path, Some(cb));
-        sync_cleanup(loop_, result);
+        sync_cleanup(result);
     }
     pub fn unlink_sync<P: PathLike>(loop_: &Loop, path: &P) -> Result<int, UvError> {
         let result = FsRequest::unlink_common(loop_, path, None);
-        sync_cleanup(loop_, result)
+        sync_cleanup(result)
     }
 
     pub fn install_req_data(&self, cb: Option<FsCallback>) {
@@ -139,9 +139,8 @@ fn native_handle(&self) -> *uvll::uv_fs_t {
         match self { &FsRequest(ptr) => ptr }
     }
 }
-    fn sync_cleanup(loop_: &Loop, result: int)
-          -> Result<int, UvError> {
-        match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
+    fn sync_cleanup(result: int) -> Result<int, UvError> {
+        match status_to_maybe_uv_error(result as i32) {
             Some(err) => Err(err),
             None => Ok(result)
         }
@@ -184,7 +183,7 @@ pub fn write(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
     pub fn write_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
           -> Result<int, UvError> {
         let result = self.write_common(loop_, buf, offset, None);
-        sync_cleanup(loop_, result)
+        sync_cleanup(result)
     }
 
     fn read_common(&mut self, loop_: &Loop, buf: Buf,
@@ -212,7 +211,7 @@ pub fn read(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
     pub fn read_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
           -> Result<int, UvError> {
         let result = self.read_common(loop_, buf, offset, None);
-        sync_cleanup(loop_, result)
+        sync_cleanup(result)
     }
 
     fn close_common(self, loop_: &Loop, cb: Option<FsCallback>) -> int {
@@ -234,12 +233,11 @@ pub fn close(self, loop_: &Loop, cb: FsCallback) {
     }
     pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
         let result = self.close_common(loop_, None);
-        sync_cleanup(loop_, result)
+        sync_cleanup(result)
     }
 }
 extern fn compl_cb(req: *uv_fs_t) {
     let mut req: FsRequest = NativeHandle::from_native_handle(req);
-    let loop_ = req.get_loop();
     // pull the user cb out of the req data
     let cb = {
         let data = req.get_req_data();
@@ -250,8 +248,7 @@ pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
     // in uv_fs_open calls, the result will be the fd in the
     // case of success, otherwise it's -1 indicating an error
     let result = req.get_result();
-    let status = status_to_maybe_uv_error_with_loop(
-        loop_.native_handle(), result);
+    let status = status_to_maybe_uv_error(result);
     // we have a req and status, call the user cb..
     // only giving the user a ref to the FsRequest, as we
     // have to clean it up, afterwards (and they aren't really
index a21146620ca823ec8643adfdb84c00f31a391b38..8cbcd7b77c0824fdea0b1df2e1234cdc0a412b3c 100644 (file)
@@ -43,7 +43,7 @@ pub fn start(&mut self, cb: IdleCallback) {
             let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
             let data = idle_watcher.get_watcher_data();
             let cb: &IdleCallback = data.idle_cb.get_ref();
-            let status = status_to_maybe_uv_error(idle_watcher, status);
+            let status = status_to_maybe_uv_error(status);
             (*cb)(idle_watcher, status);
         }
     }
@@ -57,7 +57,7 @@ pub fn restart(&mut self) {
             let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
             let data = idle_watcher.get_watcher_data();
             let cb: &IdleCallback = data.idle_cb.get_ref();
-            let status = status_to_maybe_uv_error(idle_watcher, status);
+            let status = status_to_maybe_uv_error(status);
             (*cb)(idle_watcher, status);
         }
     }
index 75b9a5ac553e8eff77d5d096730081f2e12cd902..700b80c7398b53675416cb92cbbc8a168c6d9b57 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;
@@ -70,6 +72,8 @@
 pub mod idle;
 pub mod timer;
 pub mod async;
+pub mod process;
+pub mod pipe;
 
 /// XXX: Loop(*handle) is buggy with destructors. Normal structs
 /// with dtors may not be destructured, but tuple structs can,
@@ -126,6 +130,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>);
@@ -143,7 +149,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 {
@@ -175,7 +182,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);
@@ -202,12 +210,12 @@ fn drop_watcher_data(&mut self) {
 // XXX: Need to define the error constants like EOF so they can be
 // compared to the UvError type
 
-pub struct UvError(uvll::uv_err_t);
+pub struct UvError(c_int);
 
 impl UvError {
     pub fn name(&self) -> ~str {
         unsafe {
-            let inner = match self { &UvError(ref a) => a };
+            let inner = match self { &UvError(a) => a };
             let name_str = uvll::err_name(inner);
             assert!(name_str.is_not_null());
             from_c_str(name_str)
@@ -216,7 +224,7 @@ pub fn name(&self) -> ~str {
 
     pub fn desc(&self) -> ~str {
         unsafe {
-            let inner = match self { &UvError(ref a) => a };
+            let inner = match self { &UvError(a) => a };
             let desc_str = uvll::strerror(inner);
             assert!(desc_str.is_not_null());
             from_c_str(desc_str)
@@ -224,7 +232,7 @@ pub fn desc(&self) -> ~str {
     }
 
     pub fn is_eof(&self) -> bool {
-        self.code == uvll::EOF
+        **self == uvll::EOF
     }
 }
 
@@ -236,18 +244,10 @@ fn to_str(&self) -> ~str {
 
 #[test]
 fn error_smoke_test() {
-    let err = uvll::uv_err_t { code: 1, sys_errno_: 1 };
-    let err: UvError = UvError(err);
+    let err: UvError = UvError(uvll::EOF);
     assert_eq!(err.to_str(), ~"EOF: end of file");
 }
 
-pub fn last_uv_error<H, W: Watcher + NativeHandle<*H>>(watcher: &W) -> UvError {
-    unsafe {
-        let loop_ = watcher.event_loop();
-        UvError(uvll::last_error(loop_.native_handle()))
-    }
-}
-
 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
     unsafe {
         // Importing error constants
@@ -255,10 +255,10 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
         use rt::io::*;
 
         // uv error descriptions are static
-        let c_desc = uvll::strerror(&*uverr);
+        let c_desc = uvll::strerror(*uverr);
         let desc = str::raw::c_str_to_static_slice(c_desc);
 
-        let kind = match uverr.code {
+        let kind = match *uverr {
             UNKNOWN => OtherIoError,
             OK => OtherIoError,
             EOF => EndOfFile,
@@ -266,8 +266,8 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
             ECONNREFUSED => ConnectionRefused,
             ECONNRESET => ConnectionReset,
             EPIPE => BrokenPipe,
-            _ => {
-                rtdebug!("uverr.code %u", uverr.code as uint);
+            err => {
+                rtdebug!("uverr.code %d", err as int);
                 // XXX: Need to map remaining uv error types
                 OtherIoError
             }
@@ -281,31 +281,12 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
     }
 }
 
-/// Given a uv handle, convert a callback status to a UvError
-pub fn status_to_maybe_uv_error_with_loop(
-    loop_: *uvll::uv_loop_t,
-    status: c_int) -> Option<UvError> {
-    if status != -1 {
-        None
-    } else {
-        unsafe {
-            rtdebug!("loop: %x", loop_ as uint);
-            let err = uvll::last_error(loop_);
-            Some(UvError(err))
-        }
-    }
-}
-/// Given a uv handle, convert a callback status to a UvError
-pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
-                                                                 status: c_int) -> Option<UvError> {
-    if status != -1 {
+/// Convert a callback status to a UvError
+pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
+    if status >= 0 {
         None
     } else {
-        unsafe {
-            rtdebug!("handle: %x", handle.native_handle() as uint);
-            let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle());
-            status_to_maybe_uv_error_with_loop(loop_, status)
-        }
+        Some(UvError(status))
     }
 }
 
index e8d0296e543a44afbc7e24ba5754a37016a4116c..1581b0170878fb0f7276c732860d7e6e2ef65df1 100644 (file)
@@ -16,7 +16,6 @@
 use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback,
              status_to_maybe_uv_error};
 use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
-use rt::uv::last_uv_error;
 use vec;
 use str;
 use from_str::{FromStr};
@@ -137,7 +136,7 @@ pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) {
             rtdebug!("buf len: %d", buf.len as int);
             let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
             let cb = stream_watcher.get_watcher_data().read_cb.get_ref();
-            let status = status_to_maybe_uv_error(stream_watcher, nread as c_int);
+            let status = status_to_maybe_uv_error(nread as c_int);
             (*cb)(stream_watcher, nread as int, buf, status);
         }
     }
@@ -167,7 +166,7 @@ pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) {
             let mut stream_watcher = write_request.stream();
             write_request.delete();
             let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap();
-            let status = status_to_maybe_uv_error(stream_watcher, status);
+            let status = status_to_maybe_uv_error(status);
             cb(stream_watcher, status);
         }
     }
@@ -232,7 +231,7 @@ pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
             };
             match result {
                 0 => Ok(()),
-                _ => Err(last_uv_error(self)),
+                _ => Err(UvError(result)),
             }
         }
     }
@@ -260,7 +259,7 @@ pub fn connect(&mut self, address: SocketAddr, cb: ConnectionCallback) {
                 let mut stream_watcher = connect_request.stream();
                 connect_request.delete();
                 let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
-                let status = status_to_maybe_uv_error(stream_watcher, status);
+                let status = status_to_maybe_uv_error(status);
                 cb(stream_watcher, status);
             }
         }
@@ -283,7 +282,7 @@ pub fn listen(&mut self, cb: ConnectionCallback) {
             rtdebug!("connection_cb");
             let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
             let cb = stream_watcher.get_watcher_data().connect_cb.get_ref();
-            let status = status_to_maybe_uv_error(stream_watcher, status);
+            let status = status_to_maybe_uv_error(status);
             (*cb)(stream_watcher, status);
         }
     }
@@ -327,7 +326,7 @@ pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
             };
             match result {
                 0 => Ok(()),
-                _ => Err(last_uv_error(self)),
+                _ => Err(UvError(result)),
             }
         }
     }
@@ -360,7 +359,7 @@ pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) {
             rtdebug!("buf len: %d", buf.len as int);
             let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
             let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref();
-            let status = status_to_maybe_uv_error(udp_watcher, nread as c_int);
+            let status = status_to_maybe_uv_error(nread as c_int);
             let addr = uv_socket_addr_to_socket_addr(sockaddr_to_UvSocketAddr(addr));
             (*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status);
         }
@@ -395,7 +394,7 @@ pub fn send(&mut self, buf: Buf, address: SocketAddr, cb: UdpSendCallback) {
             let mut udp_watcher = send_request.handle();
             send_request.delete();
             let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap();
-            let status = status_to_maybe_uv_error(udp_watcher, status);
+            let status = status_to_maybe_uv_error(status);
             cb(udp_watcher, status);
         }
     }
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..a02cf67
--- /dev/null
@@ -0,0 +1,264 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+use libc;
+use ptr;
+use vec;
+use cell::Cell;
+
+use rt::uv;
+use rt::uv::net;
+use rt::uv::pipe;
+use rt::uv::uvll;
+
+/// A process wraps the handle of the underlying uv_process_t.
+pub struct Process(*uvll::uv_process_t);
+
+/// This configuration describes how a new process should be spawned. This is
+/// translated to libuv's own configuration
+pub struct Config<'self> {
+    /// Path to the program to run
+    program: &'self str,
+
+    /// Arguments to pass to the program (doesn't include the program itself)
+    args: &'self [~str],
+
+    /// Optional environment to specify for the program. If this is None, then
+    /// it will inherit the current process's environment.
+    env: Option<&'self [(~str, ~str)]>,
+
+    /// Optional working directory for the new process. If this is None, then
+    /// the current directory of the running process is inherited.
+    cwd: Option<&'self str>,
+
+    /// Any number of streams/file descriptors/pipes may be attached to this
+    /// process. This list enumerates the file descriptors and such for the
+    /// process to be spawned, and the file descriptors inherited will start at
+    /// 0 and go to the length of this array.
+    ///
+    /// Standard file descriptors are:
+    ///
+    ///     0 - stdin
+    ///     1 - stdout
+    ///     2 - stderr
+    io: &'self [StdioContainer]
+}
+
+/// Describes what to do with a standard io stream for a child process.
+pub enum StdioContainer {
+    /// This stream will be ignored. This is the equivalent of attaching the
+    /// stream to `/dev/null`
+    Ignored,
+
+    /// The specified file descriptor is inherited for the stream which it is
+    /// specified for.
+    InheritFd(libc::c_int),
+
+    /// The specified libuv stream is inherited for the corresponding file
+    /// descriptor it is assigned to.
+    InheritStream(net::StreamWatcher),
+
+    /// Creates a pipe for the specified file descriptor which will be directed
+    /// into the previously-initialized pipe passed in.
+    ///
+    /// The first boolean argument is whether the pipe is readable, and the
+    /// second is whether it is writable. These properties are from the view of
+    /// the *child* process, not the parent process.
+    CreatePipe(pipe::Pipe, bool /* readable */, bool /* writable */),
+}
+
+impl uv::Watcher for Process {}
+
+impl Process {
+    /// Creates a new process, ready to spawn inside an event loop
+    pub fn new() -> Process {
+        let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
+        assert!(handle.is_not_null());
+        let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
+        ret.install_watcher_data();
+        return ret;
+    }
+
+    /// Spawn a new process inside the specified event loop.
+    ///
+    /// The `config` variable will be passed down to libuv, and the `exit_cb`
+    /// will be run only once, when the process exits.
+    ///
+    /// Returns either the corresponding process object or an error which
+    /// occurred.
+    pub fn spawn(&mut self, loop_: &uv::Loop, config: &Config,
+                 exit_cb: uv::ExitCallback) -> Result<(), uv::UvError> {
+        let cwd = config.cwd.map_move(|s| s.to_c_str());
+
+        extern fn on_exit(p: *uvll::uv_process_t,
+                          exit_status: libc::c_int,
+                          term_signal: libc::c_int) {
+            let mut p: Process = uv::NativeHandle::from_native_handle(p);
+            let err = match exit_status {
+                0 => None,
+                _ => uv::status_to_maybe_uv_error(-1)
+            };
+            p.get_watcher_data().exit_cb.take_unwrap()(p,
+                                                       exit_status as int,
+                                                       term_signal as int,
+                                                       err);
+        }
+
+        let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(
+                                config.io.len());
+        unsafe {
+            vec::raw::set_len(&mut stdio, config.io.len());
+            for (slot, &other) in stdio.iter().zip(config.io.iter()) {
+                set_stdio(slot as *uvll::uv_stdio_container_t, other);
+            }
+        }
+
+        let exit_cb = Cell::new(exit_cb);
+        do with_argv(config.program, config.args) |argv| {
+            do with_env(config.env) |envp| {
+                let options = uvll::uv_process_options_t {
+                    exit_cb: on_exit,
+                    file: unsafe { *argv },
+                    args: argv,
+                    env: envp,
+                    cwd: match cwd {
+                        Some(ref cwd) => cwd.with_ref(|p| p),
+                        None => ptr::null(),
+                    },
+                    flags: 0,
+                    stdio_count: stdio.len() as libc::c_int,
+                    stdio: stdio.as_imm_buf(|p, _| p),
+                    uid: 0,
+                    gid: 0,
+                };
+
+                match unsafe {
+                    uvll::spawn(loop_.native_handle(), **self, options)
+                } {
+                    0 => {
+                        (*self).get_watcher_data().exit_cb = Some(exit_cb.take());
+                        Ok(())
+                    }
+                    err => Err(uv::UvError(err))
+                }
+            }
+        }
+    }
+
+    /// Sends a signal to this process.
+    ///
+    /// This is a wrapper around `uv_process_kill`
+    pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
+        match unsafe {
+            uvll::process_kill(self.native_handle(), signum as libc::c_int)
+        } {
+            0 => Ok(()),
+            err => Err(uv::UvError(err))
+        }
+    }
+
+    /// Returns the process id of a spawned process
+    pub fn pid(&self) -> libc::pid_t {
+        unsafe { uvll::process_pid(**self) as libc::pid_t }
+    }
+
+    /// Closes this handle, invoking the specified callback once closed
+    pub fn close(self, cb: uv::NullCallback) {
+        {
+            let mut this = self;
+            let data = this.get_watcher_data();
+            assert!(data.close_cb.is_none());
+            data.close_cb = Some(cb);
+        }
+
+        unsafe { uvll::close(self.native_handle(), close_cb); }
+
+        extern fn close_cb(handle: *uvll::uv_process_t) {
+            let mut process: Process = uv::NativeHandle::from_native_handle(handle);
+            process.get_watcher_data().close_cb.take_unwrap()();
+            process.drop_watcher_data();
+            unsafe { uvll::free_handle(handle as *libc::c_void) }
+        }
+    }
+}
+
+unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, io: StdioContainer) {
+    match io {
+        Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); }
+        InheritFd(fd) => {
+            uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
+            uvll::set_stdio_container_fd(dst, fd);
+        }
+        InheritStream(stream) => {
+            uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_STREAM);
+            uvll::set_stdio_container_stream(dst, stream.native_handle());
+        }
+        CreatePipe(pipe, readable, writable) => {
+            let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
+            if readable {
+                flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
+            }
+            if writable {
+                flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
+            }
+            uvll::set_stdio_container_flags(dst, flags);
+            uvll::set_stdio_container_stream(dst,
+                                             pipe.as_stream().native_handle());
+        }
+    }
+}
+
+/// Converts the program and arguments to the argv array expected by libuv
+fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
+    // First, allocation space to put all the C-strings (we need to have
+    // ownership of them somewhere
+    let mut c_strs = vec::with_capacity(args.len() + 1);
+    c_strs.push(prog.to_c_str());
+    for arg in args.iter() {
+        c_strs.push(arg.to_c_str());
+    }
+
+    // Next, create the char** array
+    let mut c_args = vec::with_capacity(c_strs.len() + 1);
+    for s in c_strs.iter() {
+        c_args.push(s.with_ref(|p| p));
+    }
+    c_args.push(ptr::null());
+    c_args.as_imm_buf(|buf, _| f(buf))
+}
+
+/// Converts the environment to the env array expected by libuv
+fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
+    let env = match env {
+        Some(s) => s,
+        None => { return f(ptr::null()); }
+    };
+    // As with argv, create some temporary storage and then the actual array
+    let mut envp = vec::with_capacity(env.len());
+    for &(ref key, ref value) in env.iter() {
+        envp.push(fmt!("%s=%s", *key, *value).to_c_str());
+    }
+    let mut c_envp = vec::with_capacity(envp.len() + 1);
+    for s in envp.iter() {
+        c_envp.push(s.with_ref(|p| p));
+    }
+    c_envp.push(ptr::null());
+    c_envp.as_imm_buf(|buf, _| f(buf))
+}
+
+impl uv::NativeHandle<*uvll::uv_process_t> for Process {
+    fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
+        Process(handle)
+    }
+    fn native_handle(&self) -> *uvll::uv_process_t {
+        match self { &Process(ptr) => ptr }
+    }
+}
index eaa5e77a6da2fe71b3a67a11105dc5acee18c4f5..7b09cf2eb0e3ab058f4c2cf2d65526585964e758 100644 (file)
@@ -43,7 +43,7 @@ pub fn start(&mut self, timeout: u64, repeat: u64, cb: TimerCallback) {
             let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
             let data = watcher.get_watcher_data();
             let cb = data.timer_cb.get_ref();
-            let status = status_to_maybe_uv_error(watcher, status);
+            let status = status_to_maybe_uv_error(status);
             (*cb)(watcher, status);
         }
     }
index f794c0a2bec5ff84e955972824add2b279a3bd44..c771f93cef5e0de13b9b80e62b47fad4411662c2 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,7 @@
 use rt::io::IoError;
 use rt::io::net::ip::{SocketAddr, IpAddr};
 use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd};
+use rt::kill::BlockedTask;
 use rt::local::Local;
 use rt::rtio::*;
 use rt::sched::{Scheduler, SchedHandle};
@@ -35,6 +36,7 @@
           S_IRUSR, S_IWUSR};
 use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
             CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite};
+use task;
 
 #[cfg(test)] use container::Container;
 #[cfg(test)] use unstable::run_in_bare_thread;
@@ -55,35 +57,73 @@ fn home_for_io<A>(&mut self, io: &fn(&mut Self) -> A) -> A {
         // go home
         let old_home = Cell::new_empty();
         let old_home_ptr = &old_home;
-        let scheduler = Local::take::<Scheduler>();
-        do scheduler.deschedule_running_task_and_then |_, task| {
-            // get the old home first
-            do task.wake().map_move |mut task| {
-                old_home_ptr.put_back(task.take_unwrap_home());
-                self.home().send(PinnedTask(task));
-            };
+        do task::unkillable { // FIXME(#8674)
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                // get the old home first
+                do task.wake().map_move |mut task| {
+                    old_home_ptr.put_back(task.take_unwrap_home());
+                    self.home().send(PinnedTask(task));
+                };
+            }
         }
 
         // do IO
         let a = io(self);
 
         // unhome home
-        let scheduler = Local::take::<Scheduler>();
-        do scheduler.deschedule_running_task_and_then |scheduler, task| {
-            do task.wake().map_move |mut task| {
-                task.give_home(old_home.take());
-                scheduler.make_handle().send(TaskFromFriend(task));
-            };
+        do task::unkillable { // FIXME(#8674)
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |scheduler, task| {
+                do task.wake().map_move |mut task| {
+                    task.give_home(old_home.take());
+                    scheduler.make_handle().send(TaskFromFriend(task));
+                };
+            }
         }
 
         // return the result of the IO
         a
     }
+
+    fn home_for_io_with_sched<A>(&mut self, io_sched: &fn(&mut Self, ~Scheduler) -> A) -> A {
+        use rt::sched::{PinnedTask, TaskFromFriend};
+
+        do task::unkillable { // FIXME(#8674)
+            // go home
+            let old_home = Cell::new_empty();
+            let old_home_ptr = &old_home;
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                // get the old home first
+                do task.wake().map_move |mut task| {
+                    old_home_ptr.put_back(task.take_unwrap_home());
+                    self.home().send(PinnedTask(task));
+                };
+            }
+
+            // do IO
+            let scheduler: ~Scheduler = Local::take();
+            let a = io_sched(self, scheduler);
+
+            // unhome home
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |scheduler, task| {
+                do task.wake().map_move |mut task| {
+                    task.give_home(old_home.take());
+                    scheduler.make_handle().send(TaskFromFriend(task));
+                };
+            }
+
+            // return the result of the IO
+            a
+        }
+    }
 }
 
 // get a handle for the current scheduler
 macro_rules! get_handle_to_current_scheduler(
-    () => (do Local::borrow::<Scheduler, SchedHandle> |sched| { sched.make_handle() })
+    () => (do Local::borrow |sched: &mut Scheduler| { sched.make_handle() })
 )
 
 enum SocketNameKind {
@@ -109,7 +149,7 @@ fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
     };
 
     if r != 0 {
-        let status = status_to_maybe_uv_error(handle, r);
+        let status = status_to_maybe_uv_error(r);
         return Err(uv_error_to_io_error(status.unwrap()));
     }
 
@@ -336,7 +376,7 @@ fn test_uv_remote() {
             let mut tube = Tube::new();
             let tube_clone = tube.clone();
             let remote_cell = Cell::new_empty();
-            do Local::borrow::<Scheduler, ()>() |sched| {
+            do Local::borrow |sched: &mut Scheduler| {
                 let tube_clone = tube_clone.clone();
                 let tube_clone_cell = Cell::new(tube_clone);
                 let remote = do sched.event_loop.remote_callback {
@@ -376,35 +416,37 @@ fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoEr
         let result_cell_ptr: *Cell<Result<~RtioTcpStreamObject, IoError>> = &result_cell;
 
         // Block this task and take ownership, switch to scheduler context
-        let scheduler = Local::take::<Scheduler>();
-        do scheduler.deschedule_running_task_and_then |_, task| {
-
-            let mut tcp = TcpWatcher::new(self.uv_loop());
-            let task_cell = Cell::new(task);
+        do task::unkillable { // FIXME(#8674)
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
 
-            // Wait for a connection
-            do tcp.connect(addr) |stream, status| {
-                match status {
-                    None => {
-                        let tcp = NativeHandle::from_native_handle(stream.native_handle());
-                        let home = get_handle_to_current_scheduler!();
-                        let res = Ok(~UvTcpStream { watcher: tcp, home: home });
+                let mut tcp = TcpWatcher::new(self.uv_loop());
+                let task_cell = Cell::new(task);
 
-                        // Store the stream in the task's stack
-                        unsafe { (*result_cell_ptr).put_back(res); }
+                // Wait for a connection
+                do tcp.connect(addr) |stream, status| {
+                    match status {
+                        None => {
+                            let tcp = NativeHandle::from_native_handle(stream.native_handle());
+                            let home = get_handle_to_current_scheduler!();
+                            let res = Ok(~UvTcpStream { watcher: tcp, home: home });
 
-                        // Context switch
-                        let scheduler = Local::take::<Scheduler>();
-                        scheduler.resume_blocked_task_immediately(task_cell.take());
-                    }
-                    Some(_) => {
-                        let task_cell = Cell::new(task_cell.take());
-                        do stream.close {
-                            let res = Err(uv_error_to_io_error(status.unwrap()));
+                            // Store the stream in the task's stack
                             unsafe { (*result_cell_ptr).put_back(res); }
-                            let scheduler = Local::take::<Scheduler>();
+
+                            // Context switch
+                            let scheduler: ~Scheduler = Local::take();
                             scheduler.resume_blocked_task_immediately(task_cell.take());
                         }
+                        Some(_) => {
+                            let task_cell = Cell::new(task_cell.take());
+                            do stream.close {
+                                let res = Err(uv_error_to_io_error(status.unwrap()));
+                                unsafe { (*result_cell_ptr).put_back(res); }
+                                let scheduler: ~Scheduler = Local::take();
+                                scheduler.resume_blocked_task_immediately(task_cell.take());
+                            }
+                        }
                     }
                 }
             }
@@ -422,15 +464,17 @@ fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoErr
                 Ok(~UvTcpListener::new(watcher, home))
             }
             Err(uverr) => {
-                let scheduler = Local::take::<Scheduler>();
-                do scheduler.deschedule_running_task_and_then |_, task| {
-                    let task_cell = Cell::new(task);
-                    do watcher.as_stream().close {
-                        let scheduler = Local::take::<Scheduler>();
-                        scheduler.resume_blocked_task_immediately(task_cell.take());
+                do task::unkillable { // FIXME(#8674)
+                    let scheduler: ~Scheduler = Local::take();
+                    do scheduler.deschedule_running_task_and_then |_, task| {
+                        let task_cell = Cell::new(task);
+                        do watcher.as_stream().close {
+                            let scheduler: ~Scheduler = Local::take();
+                            scheduler.resume_blocked_task_immediately(task_cell.take());
+                        }
                     }
+                    Err(uv_error_to_io_error(uverr))
                 }
-                Err(uv_error_to_io_error(uverr))
             }
         }
     }
@@ -443,15 +487,17 @@ fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError
                 Ok(~UvUdpSocket { watcher: watcher, home: home })
             }
             Err(uverr) => {
-                let scheduler = Local::take::<Scheduler>();
-                do scheduler.deschedule_running_task_and_then |_, task| {
-                    let task_cell = Cell::new(task);
-                    do watcher.close {
-                        let scheduler = Local::take::<Scheduler>();
-                        scheduler.resume_blocked_task_immediately(task_cell.take());
+                do task::unkillable { // FIXME(#8674)
+                    let scheduler: ~Scheduler = Local::take();
+                    do scheduler.deschedule_running_task_and_then |_, task| {
+                        let task_cell = Cell::new(task);
+                        do watcher.close {
+                            let scheduler: ~Scheduler = Local::take();
+                            scheduler.resume_blocked_task_immediately(task_cell.take());
+                        }
                     }
+                    Err(uv_error_to_io_error(uverr))
                 }
-                Err(uv_error_to_io_error(uverr))
             }
         }
     }
@@ -493,30 +539,32 @@ fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
         let result_cell_ptr: *Cell<Result<~RtioFileStream,
                                            IoError>> = &result_cell;
         let path_cell = Cell::new(path);
-        let scheduler = Local::take::<Scheduler>();
-        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)
-                  |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 fs = ~UvFileStream::new(
-                        loop_, fd, true, home) as ~RtioFileStream;
-                    let res = Ok(fs);
-                    unsafe { (*result_cell_ptr).put_back(res); }
-                    let scheduler = Local::take::<Scheduler>();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                } else {
-                    let res = Err(uv_error_to_io_error(err.unwrap()));
-                    unsafe { (*result_cell_ptr).put_back(res); }
-                    let scheduler = Local::take::<Scheduler>();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                }
+        do task::unkillable { // FIXME(#8674)
+            let scheduler: ~Scheduler = Local::take();
+            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)
+                      |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 fs = ~UvFileStream::new(
+                            loop_, fd, true, home) as ~RtioFileStream;
+                        let res = Ok(fs);
+                        unsafe { (*result_cell_ptr).put_back(res); }
+                        let scheduler: ~Scheduler = Local::take();
+                        scheduler.resume_blocked_task_immediately(task_cell.take());
+                    } else {
+                        let res = Err(uv_error_to_io_error(err.unwrap()));
+                        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();
     }
@@ -525,23 +573,82 @@ fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
         let result_cell = Cell::new_empty();
         let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
         let path_cell = Cell::new(path);
-        let scheduler = Local::take::<Scheduler>();
-        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 res = match err {
-                    None => Ok(()),
-                    Some(err) => Err(uv_error_to_io_error(err))
+        do task::unkillable { // FIXME(#8674)
+            let scheduler: ~Scheduler = Local::take();
+            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 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());
                 };
-                unsafe { (*result_cell_ptr).put_back(res); }
-                let scheduler = Local::take::<Scheduler>();
-                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<~RtioPipeObject, IoError> {
+        let home = get_handle_to_current_scheduler!();
+        Ok(~UvPipeStream { pipe: Pipe::new(self.uv_loop(), ipc), home: home })
+    }
+
+    fn spawn(&mut self,
+             config: &process::Config) -> Result<~RtioProcessObject, IoError> {
+        // Sadly, we must create the UvProcess before we actually call uv_spawn
+        // so that the exit_cb can close over it and notify it when the process
+        // has exited.
+        let mut ret = ~UvProcess {
+            process: Process::new(),
+            home: None,
+            exit_status: None,
+            term_signal: None,
+            exit_error: None,
+            descheduled: None,
+        };
+        let ret_ptr = unsafe {
+            *cast::transmute::<&~UvProcess, &*mut UvProcess>(&ret)
+        };
+
+        // The purpose of this exit callback is to record the data about the
+        // exit and then wake up the task which may be waiting for the process
+        // to exit. This is all performed in the current io-loop, and the
+        // implementation of UvProcess ensures that reading these fields always
+        // occurs on the current io-loop.
+        let exit_cb: ExitCallback = |_, exit_status, term_signal, error| {
+            unsafe {
+                assert!((*ret_ptr).exit_status.is_none());
+                (*ret_ptr).exit_status = Some(exit_status);
+                (*ret_ptr).term_signal = Some(term_signal);
+                (*ret_ptr).exit_error = error;
+                match (*ret_ptr).descheduled.take() {
+                    Some(task) => {
+                        let scheduler: ~Scheduler = Local::take();
+                        scheduler.resume_blocked_task_immediately(task);
+                    }
+                    None => {}
+                }
+            }
+        };
+
+        match ret.process.spawn(self.uv_loop(), config, exit_cb) {
+            Ok(()) => {
+                // Only now do we actually get a handle to this scheduler.
+                ret.home = Some(get_handle_to_current_scheduler!());
+                Ok(ret)
+            }
+            Err(uverr) => {
+                // We still need to close the process handle we created, but
+                // that's taken care for us in the destructor of UvProcess
+                Err(uv_error_to_io_error(uverr))
+            }
+        }
+    }
 }
 
 pub struct UvTcpListener {
@@ -572,12 +679,11 @@ impl Drop for UvTcpListener {
     fn drop(&self) {
         // XXX need mutable finalizer
         let self_ = unsafe { transmute::<&UvTcpListener, &mut UvTcpListener>(self) };
-        do self_.home_for_io |self_| {
-            let scheduler = Local::take::<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_.watcher().as_stream().close {
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -631,7 +737,7 @@ fn accept_simultaneously(&mut self) -> Result<(), IoError> {
                 uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 1 as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher(), r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -644,7 +750,7 @@ fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
                 uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 0 as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher(), r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -652,47 +758,20 @@ fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
     }
 }
 
-pub struct UvTcpStream {
-    watcher: TcpWatcher,
-    home: SchedHandle,
-}
-
-impl HomingIO for UvTcpStream {
-    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvTcpStream {
-    fn drop(&self) {
-        // XXX need mutable finalizer
-        let this = unsafe { transmute::<&UvTcpStream, &mut UvTcpStream>(self) };
-        do this.home_for_io |self_| {
-            let scheduler = Local::take::<Scheduler>();
-            do scheduler.deschedule_running_task_and_then |_, task| {
-                let task_cell = Cell::new(task);
-                do self_.watcher.as_stream().close {
-                    let scheduler = Local::take::<Scheduler>();
-                    scheduler.resume_blocked_task_immediately(task_cell.take());
-                }
-            }
-        }
-    }
+trait UvStream: HomingIO {
+    fn as_stream(&mut self) -> StreamWatcher;
 }
 
-impl RtioSocket for UvTcpStream {
-    fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
-        do self.home_for_io |self_| {
-            socket_name(Tcp, self_.watcher)
-        }
-    }
-}
-
-impl RtioTcpStream for UvTcpStream {
+// FIXME(#3429) I would rather this be `impl<T: UvStream> RtioStream for T` but
+//              that has conflicts with other traits that also have methods
+//              called `read` and `write`
+macro_rules! rtiostream(($t:ident) => {
+impl RtioStream for $t {
     fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
-        do self.home_for_io |self_| {
+        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 scheduler = Local::take::<Scheduler>();
             let buf_ptr: *&mut [u8] = &buf;
             do scheduler.deschedule_running_task_and_then |_sched, task| {
                 let task_cell = Cell::new(task);
@@ -701,7 +780,7 @@ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
                 let alloc: AllocCallback = |_| unsafe {
                     slice_to_uv_buf(*buf_ptr)
                 };
-                let mut watcher = self_.watcher.as_stream();
+                let mut watcher = self_.as_stream();
                 do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
 
                     // Stop reading so that no read callbacks are
@@ -719,7 +798,7 @@ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
 
                     unsafe { (*result_cell_ptr).put_back(result); }
 
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -730,15 +809,14 @@ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
     }
 
     fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
-        do self.home_for_io |self_| {
+        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 scheduler = Local::take::<Scheduler>();
             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();
+                let mut watcher = self_.as_stream();
                 do watcher.write(buf) |_watcher, status| {
                     let result = if status.is_none() {
                         Ok(())
@@ -748,7 +826,7 @@ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
 
                     unsafe { (*result_cell_ptr).put_back(result); }
 
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -757,7 +835,85 @@ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
             result_cell.take()
         }
     }
+}
+})
+
+rtiostream!(UvPipeStream)
+rtiostream!(UvTcpStream)
+
+pub struct UvPipeStream {
+    pipe: Pipe,
+    home: SchedHandle,
+}
+
+impl UvStream for UvPipeStream {
+    fn as_stream(&mut self) -> StreamWatcher { self.pipe.as_stream() }
+}
+
+impl HomingIO for UvPipeStream {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvPipeStream {
+    fn drop(&self) {
+        // FIXME(#4330): should not need a transmute
+        let this = unsafe { cast::transmute_mut(self) };
+        do this.home_for_io |self_| {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task_cell = Cell::new(task);
+                do self_.pipe.close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task_cell.take());
+                }
+            }
+        }
+    }
+}
+
+impl UvPipeStream {
+    pub fn uv_pipe(&self) -> Pipe { self.pipe }
+}
+
+pub struct UvTcpStream {
+    watcher: TcpWatcher,
+    home: SchedHandle,
+}
+
+impl HomingIO for UvTcpStream {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvTcpStream {
+    fn drop(&self) {
+        // FIXME(#4330): should not need a transmute
+        let this = unsafe { cast::transmute_mut(self) };
+        do this.home_for_io |self_| {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task_cell = Cell::new(task);
+                do self_.watcher.as_stream().close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task_cell.take());
+                }
+            }
+        }
+    }
+}
+
+impl UvStream for UvTcpStream {
+    fn as_stream(&mut self) -> StreamWatcher { self.watcher.as_stream() }
+}
+
+impl RtioSocket for UvTcpStream {
+    fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
+        do self.home_for_io |self_| {
+            socket_name(Tcp, self_.watcher)
+        }
+    }
+}
 
+impl RtioTcpStream for UvTcpStream {
     fn peer_name(&mut self) -> Result<SocketAddr, IoError> {
         do self.home_for_io |self_| {
             socket_name(TcpPeer, self_.watcher)
@@ -768,7 +924,7 @@ fn control_congestion(&mut self) -> Result<(), IoError> {
         do self.home_for_io |self_| {
             let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 0 as c_int) };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -779,7 +935,7 @@ fn nodelay(&mut self) -> Result<(), IoError> {
         do self.home_for_io |self_| {
             let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 1 as c_int) };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -793,7 +949,7 @@ fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
                                     delay_in_seconds as c_uint)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -806,7 +962,7 @@ fn letdie(&mut self) -> Result<(), IoError> {
                 uvll::tcp_keepalive(self_.watcher.native_handle(), 0 as c_int, 0 as c_uint)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -827,12 +983,11 @@ impl Drop for UvUdpSocket {
     fn drop(&self) {
         // XXX need mutable finalizer
         let this = unsafe { transmute::<&UvUdpSocket, &mut UvUdpSocket>(self) };
-        do this.home_for_io |_| {
-            let scheduler = Local::take::<Scheduler>();
+        do this.home_for_io_with_sched |self_, scheduler| {
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
-                do this.watcher.close {
-                    let scheduler = Local::take::<Scheduler>();
+                do self_.watcher.close {
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -850,11 +1005,10 @@ fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
 
 impl RtioUdpSocket for UvUdpSocket {
     fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError> {
-        do self.home_for_io |self_| {
+        do self.home_for_io_with_sched |self_, scheduler| {
             let result_cell = Cell::new_empty();
             let result_cell_ptr: *Cell<Result<(uint, SocketAddr), IoError>> = &result_cell;
 
-            let scheduler = Local::take::<Scheduler>();
             let buf_ptr: *&mut [u8] = &buf;
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
@@ -874,7 +1028,7 @@ fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError> {
 
                     unsafe { (*result_cell_ptr).put_back(result); }
 
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -885,10 +1039,9 @@ fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError> {
     }
 
     fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> Result<(), IoError> {
-        do self.home_for_io |self_| {
+        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 scheduler = Local::take::<Scheduler>();
             let buf_ptr: *&[u8] = &buf;
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
@@ -902,7 +1055,7 @@ fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> Result<(), IoError> {
 
                     unsafe { (*result_cell_ptr).put_back(result); }
 
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -921,7 +1074,7 @@ fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
                 }
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -937,7 +1090,7 @@ fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
                 }
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -951,7 +1104,7 @@ fn loop_multicast_locally(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 1 as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -965,7 +1118,7 @@ fn dont_loop_multicast_locally(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 0 as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -979,7 +1132,7 @@ fn multicast_time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
                 uvll::udp_set_multicast_ttl(self_.watcher.native_handle(), ttl as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -993,7 +1146,7 @@ fn time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
                 uvll::udp_set_ttl(self_.watcher.native_handle(), ttl as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1007,7 +1160,7 @@ fn hear_broadcasts(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_broadcast(self_.watcher.native_handle(), 1 as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1021,7 +1174,7 @@ fn ignore_broadcasts(&mut self) -> Result<(), IoError> {
                 uvll::udp_set_broadcast(self_.watcher.native_handle(), 0 as c_int)
             };
 
-            match status_to_maybe_uv_error(self_.watcher, r) {
+            match status_to_maybe_uv_error(r) {
                 Some(err) => Err(uv_error_to_io_error(err)),
                 None => Ok(())
             }
@@ -1047,13 +1200,12 @@ 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 |self_| {
+        do self_.home_for_io_with_sched |self_, scheduler| {
             rtdebug!("closing UvTimer");
-            let scheduler = Local::take::<Scheduler>();
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let task_cell = Cell::new(task);
                 do self_.watcher.close {
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -1063,14 +1215,13 @@ fn drop(&self) {
 
 impl RtioTimer for UvTimer {
     fn sleep(&mut self, msecs: u64) {
-        do self.home_for_io |self_| {
-            let scheduler = Local::take::<Scheduler>();
+        do self.home_for_io_with_sched |self_, scheduler| {
             do scheduler.deschedule_running_task_and_then |_sched, task| {
                 rtdebug!("sleep: entered scheduler context");
                 let task_cell = Cell::new(task);
                 do self_.watcher.start(msecs, 0) |_, status| {
                     assert!(status.is_none());
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 }
             }
@@ -1104,8 +1255,7 @@ fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError> {
         let result_cell = Cell::new_empty();
         let result_cell_ptr: *Cell<Result<int, IoError>> = &result_cell;
         let buf_ptr: *&mut [u8] = &buf;
-        do self.home_for_io |self_| {
-            let scheduler = Local::take::<Scheduler>();
+        do self.home_for_io_with_sched |self_, scheduler| {
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
                 let task_cell = Cell::new(task);
@@ -1115,7 +1265,7 @@ fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError> {
                         Some(err) => Err(uv_error_to_io_error(err))
                     };
                     unsafe { (*result_cell_ptr).put_back(res); }
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 };
             };
@@ -1126,8 +1276,7 @@ fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> {
         let result_cell = Cell::new_empty();
         let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
         let buf_ptr: *&[u8] = &buf;
-        do self.home_for_io |self_| {
-            let scheduler = Local::take::<Scheduler>();
+        do self.home_for_io_with_sched |self_, scheduler| {
             do scheduler.deschedule_running_task_and_then |_, task| {
                 let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
                 let task_cell = Cell::new(task);
@@ -1137,7 +1286,7 @@ fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> {
                         Some(err) => Err(uv_error_to_io_error(err))
                     };
                     unsafe { (*result_cell_ptr).put_back(res); }
-                    let scheduler = Local::take::<Scheduler>();
+                    let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
                 };
             };
@@ -1166,12 +1315,11 @@ impl Drop for UvFileStream {
     fn drop(&self) {
         let self_ = unsafe { transmute::<&UvFileStream, &mut UvFileStream>(self) };
         if self.close_on_drop {
-            do self_.home_for_io |self_| {
-                let scheduler = Local::take::<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 scheduler = Local::take::<Scheduler>();
+                        let scheduler: ~Scheduler = Local::take();
                         scheduler.resume_blocked_task_immediately(task_cell.take());
                     };
                 };
@@ -1213,11 +1361,94 @@ fn flush(&mut self) -> Result<(), IoError> {
     }
 }
 
+pub struct UvProcess {
+    process: process::Process,
+
+    // Sadly, this structure must be created before we return it, so in that
+    // brief interim the `home` is None.
+    home: Option<SchedHandle>,
+
+    // All None until the process exits (exit_error may stay None)
+    priv exit_status: Option<int>,
+    priv term_signal: Option<int>,
+    priv exit_error: Option<UvError>,
+
+    // Used to store which task to wake up from the exit_cb
+    priv descheduled: Option<BlockedTask>,
+}
+
+impl HomingIO for UvProcess {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.home.get_mut_ref() }
+}
+
+impl Drop for UvProcess {
+    fn drop(&self) {
+        // FIXME(#4330): should not need a transmute
+        let this = unsafe { cast::transmute_mut(self) };
+
+        let close = |self_: &mut UvProcess| {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task = Cell::new(task);
+                do self_.process.close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task.take());
+                }
+            }
+        };
+
+        // If home is none, then this process never actually successfully
+        // spawned, so there's no need to switch event loops
+        if this.home.is_none() {
+            close(this)
+        } else {
+            this.home_for_io(close)
+        }
+    }
+}
+
+impl RtioProcess for UvProcess {
+    fn id(&self) -> pid_t {
+        self.process.pid()
+    }
+
+    fn kill(&mut self, signal: int) -> Result<(), IoError> {
+        do self.home_for_io |self_| {
+            match self_.process.kill(signal) {
+                Ok(()) => Ok(()),
+                Err(uverr) => Err(uv_error_to_io_error(uverr))
+            }
+        }
+    }
+
+    fn wait(&mut self) -> int {
+        // Make sure (on the home scheduler) that we have an exit status listed
+        do self.home_for_io |self_| {
+            match self_.exit_status {
+                Some(*) => {}
+                None => {
+                    // If there's no exit code previously listed, then the
+                    // process's exit callback has yet to be invoked. We just
+                    // need to deschedule ourselves and wait to be reawoken.
+                    let scheduler: ~Scheduler = Local::take();
+                    do scheduler.deschedule_running_task_and_then |_, task| {
+                        assert!(self_.descheduled.is_none());
+                        self_.descheduled = Some(task);
+                    }
+                    assert!(self_.exit_status.is_some());
+                }
+            }
+        }
+
+        self.exit_status.unwrap()
+    }
+}
+
 #[test]
 fn test_simple_io_no_connect() {
     do run_in_newsched_task {
         unsafe {
-            let io = Local::unsafe_borrow::<IoFactoryObject>();
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
             let addr = next_test_ip4();
             let maybe_chan = (*io).tcp_connect(addr);
             assert!(maybe_chan.is_err());
@@ -1229,7 +1460,7 @@ fn test_simple_io_no_connect() {
 fn test_simple_udp_io_bind_only() {
     do run_in_newsched_task {
         unsafe {
-            let io = Local::unsafe_borrow::<IoFactoryObject>();
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
             let addr = next_test_ip4();
             let maybe_socket = (*io).udp_bind(addr);
             assert!(maybe_socket.is_ok());
@@ -1266,21 +1497,25 @@ fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() {
         };
 
         let test_function: ~fn() = || {
-            let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+            let io: *mut IoFactoryObject = unsafe {
+                Local::unsafe_borrow()
+            };
             let addr = next_test_ip4();
             let maybe_socket = unsafe { (*io).udp_bind(addr) };
             // this socket is bound to this event loop
             assert!(maybe_socket.is_ok());
 
             // block self on sched1
-            let scheduler = Local::take::<Scheduler>();
-            do scheduler.deschedule_running_task_and_then |_, task| {
-                // unblock task
-                do task.wake().map_move |task| {
-                  // send self to sched2
-                  tasksFriendHandle.take().send(TaskFromFriend(task));
-                };
-                // sched1 should now sleep since it has nothing else to do
+            do task::unkillable { // FIXME(#8674)
+                let scheduler: ~Scheduler = Local::take();
+                do scheduler.deschedule_running_task_and_then |_, task| {
+                    // unblock task
+                    do task.wake().map_move |task| {
+                      // send self to sched2
+                      tasksFriendHandle.take().send(TaskFromFriend(task));
+                    };
+                    // sched1 should now sleep since it has nothing else to do
+                }
             }
             // sched2 will wake up and get the task
             // as we do nothing else, the function ends and the socket goes out of scope
@@ -1338,7 +1573,9 @@ fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() {
         let chan = Cell::new(chan);
 
         let body1: ~fn() = || {
-            let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+            let io: *mut IoFactoryObject = unsafe {
+                Local::unsafe_borrow()
+            };
             let addr = next_test_ip4();
             let socket = unsafe { (*io).udp_bind(addr) };
             assert!(socket.is_ok());
@@ -1391,7 +1628,7 @@ fn test_simple_tcp_server_and_client() {
         // Start the server first so it's listening when we connect
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut listener = (*io).tcp_bind(addr).unwrap();
                 let mut stream = listener.accept().unwrap();
                 let mut buf = [0, .. 2048];
@@ -1406,7 +1643,7 @@ fn test_simple_tcp_server_and_client() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut stream = (*io).tcp_connect(addr).unwrap();
                 stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
             }
@@ -1450,7 +1687,9 @@ fn test_simple_tcp_server_and_client_on_diff_threads() {
         };
 
         let server_fn: ~fn() = || {
-            let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+            let io: *mut IoFactoryObject = unsafe {
+                Local::unsafe_borrow()
+            };
             let mut listener = unsafe { (*io).tcp_bind(server_addr).unwrap() };
             let mut stream = listener.accept().unwrap();
             let mut buf = [0, .. 2048];
@@ -1462,7 +1701,9 @@ fn test_simple_tcp_server_and_client_on_diff_threads() {
         };
 
         let client_fn: ~fn() = || {
-            let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+            let io: *mut IoFactoryObject = unsafe {
+                Local::unsafe_borrow()
+            };
             let mut stream = unsafe { (*io).tcp_connect(client_addr) };
             while stream.is_err() {
                 stream = unsafe { (*io).tcp_connect(client_addr) };
@@ -1501,7 +1742,7 @@ fn test_simple_udp_server_and_client() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut server_socket = (*io).udp_bind(server_addr).unwrap();
                 let mut buf = [0, .. 2048];
                 let (nread,src) = server_socket.recvfrom(buf).unwrap();
@@ -1516,7 +1757,7 @@ fn test_simple_udp_server_and_client() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut client_socket = (*io).udp_bind(client_addr).unwrap();
                 client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr);
             }
@@ -1530,7 +1771,7 @@ fn test_read_and_block() {
         let addr = next_test_ip4();
 
         do spawntask {
-            let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+            let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() };
             let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() };
             let mut stream = listener.accept().unwrap();
             let mut buf = [0, .. 2048];
@@ -1548,13 +1789,15 @@ fn test_read_and_block() {
                 }
                 reads += 1;
 
-                let scheduler = Local::take::<Scheduler>();
-                // Yield to the other task in hopes that it
-                // will trigger a read callback while we are
-                // not ready for it
-                do scheduler.deschedule_running_task_and_then |sched, task| {
-                    let task = Cell::new(task);
-                    sched.enqueue_blocked_task(task.take());
+                do task::unkillable { // FIXME(#8674)
+                    let scheduler: ~Scheduler = Local::take();
+                    // Yield to the other task in hopes that it
+                    // will trigger a read callback while we are
+                    // not ready for it
+                    do scheduler.deschedule_running_task_and_then |sched, task| {
+                        let task = Cell::new(task);
+                        sched.enqueue_blocked_task(task.take());
+                    }
                 }
             }
 
@@ -1564,7 +1807,7 @@ fn test_read_and_block() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut stream = (*io).tcp_connect(addr).unwrap();
                 stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
                 stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
@@ -1584,7 +1827,7 @@ fn test_read_read_read() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut listener = (*io).tcp_bind(addr).unwrap();
                 let mut stream = listener.accept().unwrap();
                 let buf = [1, .. 2048];
@@ -1598,7 +1841,7 @@ fn test_read_read_read() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut stream = (*io).tcp_connect(addr).unwrap();
                 let mut buf = [0, .. 2048];
                 let mut total_bytes_read = 0;
@@ -1624,7 +1867,7 @@ fn test_udp_twice() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut client = (*io).udp_bind(client_addr).unwrap();
                 assert!(client.sendto([1], server_addr).is_ok());
                 assert!(client.sendto([2], server_addr).is_ok());
@@ -1633,7 +1876,7 @@ fn test_udp_twice() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut server = (*io).udp_bind(server_addr).unwrap();
                 let mut buf1 = [0];
                 let mut buf2 = [0];
@@ -1661,7 +1904,7 @@ fn test_udp_many_read() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut server_out = (*io).udp_bind(server_out_addr).unwrap();
                 let mut server_in = (*io).udp_bind(server_in_addr).unwrap();
                 let msg = [1, .. 2048];
@@ -1684,7 +1927,7 @@ fn test_udp_many_read() {
 
         do spawntask {
             unsafe {
-                let io = Local::unsafe_borrow::<IoFactoryObject>();
+                let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut client_out = (*io).udp_bind(client_out_addr).unwrap();
                 let mut client_in = (*io).udp_bind(client_in_addr).unwrap();
                 let mut total_bytes_recv = 0;
@@ -1713,7 +1956,7 @@ fn test_udp_many_read() {
 fn test_timer_sleep_simple() {
     do run_in_newsched_task {
         unsafe {
-            let io = Local::unsafe_borrow::<IoFactoryObject>();
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
             let timer = (*io).timer_init();
             do timer.map_move |mut t| { t.sleep(1) };
         }
@@ -1727,7 +1970,7 @@ fn file_test_uvio_full_simple_impl() {
     use path::Path;
     use rt::io::{Open, Create, ReadWrite, Read};
     unsafe {
-        let io = Local::unsafe_borrow::<IoFactoryObject>();
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
         let write_val = "hello uvio!";
         let path = "./tmp/file_test_uvio_full.txt";
         {
@@ -1761,7 +2004,7 @@ fn uvio_naive_print(input: &str) {
     use str::StrSlice;
     unsafe {
         use libc::{STDOUT_FILENO};
-        let io = Local::unsafe_borrow::<IoFactoryObject>();
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
         {
             let mut fd = (*io).fs_from_raw_fd(STDOUT_FILENO, false);
             let write_buf = input.as_bytes();
index 1e189e90885501b981f635e81576b3f8ed77e95e..24e070ca239d1bfbc855dfb799fae2c08dffabaa 100644 (file)
 use libc;
 use prelude::*;
 use ptr;
-use str;
 use vec;
 
-pub static UNKNOWN: c_int = -1;
+pub use self::errors::*;
+
 pub static OK: c_int = 0;
-pub static EOF: c_int = 1;
-pub static EADDRINFO: c_int = 2;
-pub static EACCES: c_int = 3;
-pub static ECONNREFUSED: c_int = 12;
-pub static ECONNRESET: c_int = 13;
-pub static EPIPE: c_int = 36;
+pub static EOF: c_int = -4095;
+pub static UNKNOWN: c_int = -4094;
+
+// uv-errno.h redefines error codes for windows, but not for unix...
+
+#[cfg(windows)]
+pub mod errors {
+    use libc::c_int;
 
-pub struct uv_err_t {
-    code: c_int,
-    sys_errno_: c_int
+    pub static EACCES: c_int = -4093;
+    pub static ECONNREFUSED: c_int = -4079;
+    pub static ECONNRESET: c_int = -4078;
+    pub static EPIPE: c_int = -4048;
 }
+#[cfg(not(windows))]
+pub mod errors {
+    use libc;
+    use libc::c_int;
+
+    pub static EACCES: c_int = -libc::EACCES;
+    pub static ECONNREFUSED: c_int = -libc::ECONNREFUSED;
+    pub static ECONNRESET: c_int = -libc::ECONNRESET;
+    pub static EPIPE: c_int = -libc::EPIPE;
+}
+
+pub static PROCESS_SETUID: c_int = 1 << 0;
+pub static PROCESS_SETGID: c_int = 1 << 1;
+pub static PROCESS_WINDOWS_VERBATIM_ARGUMENTS: c_int = 1 << 2;
+pub static PROCESS_DETACHED: c_int = 1 << 3;
+pub static PROCESS_WINDOWS_HIDE: c_int = 1 << 4;
+
+pub static STDIO_IGNORE: c_int = 0x00;
+pub static STDIO_CREATE_PIPE: c_int = 0x01;
+pub static STDIO_INHERIT_FD: c_int = 0x02;
+pub static STDIO_INHERIT_STREAM: c_int = 0x04;
+pub static STDIO_READABLE_PIPE: c_int = 0x10;
+pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
 
 pub struct uv_buf_t {
     base: *u8,
     len: libc::size_t,
 }
 
+pub struct uv_process_options_t {
+    exit_cb: uv_exit_cb,
+    file: *libc::c_char,
+    args: **libc::c_char,
+    env: **libc::c_char,
+    cwd: *libc::c_char,
+    flags: libc::c_uint,
+    stdio_count: libc::c_int,
+    stdio: *uv_stdio_container_t,
+    uid: uv_uid_t,
+    gid: uv_gid_t,
+}
+
+// These fields are private because they must be interfaced with through the
+// functions below.
+pub struct uv_stdio_container_t {
+    priv flags: libc::c_int,
+    priv stream: *uv_stream_t,
+}
+
 pub type uv_handle_t = c_void;
 pub type uv_loop_t = c_void;
 pub type uv_idle_t = c_void;
@@ -72,6 +118,8 @@ pub struct uv_buf_t {
 pub type uv_stream_t = c_void;
 pub type uv_fs_t = c_void;
 pub type uv_udp_send_t = c_void;
+pub type uv_process_t = c_void;
+pub type uv_pipe_t = c_void;
 
 #[cfg(stage0)]
 pub type uv_idle_cb = *u8;
@@ -97,6 +145,8 @@ pub struct uv_buf_t {
 pub type uv_timer_cb = *u8;
 #[cfg(stage0)]
 pub type uv_write_cb = *u8;
+#[cfg(stage0)]
+pub type uv_exit_cb = *u8;
 
 #[cfg(not(stage0))]
 pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
@@ -137,12 +187,21 @@ pub struct uv_buf_t {
 #[cfg(not(stage0))]
 pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
                                      status: c_int);
+#[cfg(not(stage0))]
+pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t,
+                                    exit_status: c_int,
+                                    term_signal: c_int);
 
 pub type sockaddr = c_void;
 pub type sockaddr_in = c_void;
 pub type sockaddr_in6 = c_void;
 pub type sockaddr_storage = c_void;
 
+#[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
+#[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
+#[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
+#[cfg(windows)] pub type uv_gid_t = libc::c_uchar;
+
 #[deriving(Eq)]
 pub enum uv_handle_type {
     UV_UNKNOWN_HANDLE,
@@ -487,20 +546,12 @@ pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
     return rust_uv_read_stop(stream as *c_void);
 }
 
-pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
+pub unsafe fn strerror(err: c_int) -> *c_char {
     #[fixed_stack_segment]; #[inline(never)];
-
-    return rust_uv_last_error(loop_handle);
-}
-
-pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
-    #[fixed_stack_segment]; #[inline(never)];
-
     return rust_uv_strerror(err);
 }
-pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
+pub unsafe fn err_name(err: c_int) -> *c_char {
     #[fixed_stack_segment]; #[inline(never)];
-
     return rust_uv_err_name(err);
 }
 
@@ -654,6 +705,45 @@ pub unsafe fn fs_req_cleanup(req: *uv_fs_t) {
     rust_uv_fs_req_cleanup(req);
 }
 
+pub unsafe fn spawn(loop_ptr: *c_void, result: *uv_process_t,
+                    options: uv_process_options_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    return rust_uv_spawn(loop_ptr, result, options);
+}
+
+pub unsafe fn process_kill(p: *uv_process_t, signum: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    return rust_uv_process_kill(p, signum);
+}
+
+pub unsafe fn process_pid(p: *uv_process_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    return rust_uv_process_pid(p);
+}
+
+pub unsafe fn set_stdio_container_flags(c: *uv_stdio_container_t,
+                                        flags: libc::c_int) {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_set_stdio_container_flags(c, flags);
+}
+
+pub unsafe fn set_stdio_container_fd(c: *uv_stdio_container_t,
+                                     fd: libc::c_int) {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_set_stdio_container_fd(c, fd);
+}
+
+pub unsafe fn set_stdio_container_stream(c: *uv_stdio_container_t,
+                                         stream: *uv_stream_t) {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_set_stdio_container_stream(c, stream);
+}
+
+pub unsafe fn pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_uv_pipe_init(loop_ptr, p, ipc)
+}
+
 // data access helpers
 pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
     #[fixed_stack_segment]; #[inline(never)];
@@ -720,22 +810,6 @@ pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
 
     return rust_uv_get_len_from_buf(buf);
 }
-pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
-    let err = last_error(uv_loop);
-    let err_ptr = ptr::to_unsafe_ptr(&err);
-    let err_name = str::raw::from_c_str(err_name(err_ptr));
-    let err_msg = str::raw::from_c_str(strerror(err_ptr));
-    return fmt!("LIBUV ERROR: name: %s msg: %s",
-                    err_name, err_msg);
-}
-
-pub unsafe fn get_last_err_data(uv_loop: *c_void) -> uv_err_data {
-    let err = last_error(uv_loop);
-    let err_ptr = ptr::to_unsafe_ptr(&err);
-    let err_name = str::raw::from_c_str(err_name(err_ptr));
-    let err_msg = str::raw::from_c_str(strerror(err_ptr));
-    uv_err_data { err_name: err_name, err_msg: err_msg }
-}
 
 pub struct uv_err_data {
     err_name: ~str,
@@ -768,9 +842,8 @@ fn rust_uv_async_init(loop_handle: *c_void,
                           cb: uv_async_cb) -> c_int;
     fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int;
     fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t);
-    fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t;
-    fn rust_uv_strerror(err: *uv_err_t) -> *c_char;
-    fn rust_uv_err_name(err: *uv_err_t) -> *c_char;
+    fn rust_uv_strerror(err: c_int) -> *c_char;
+    fn rust_uv_err_name(err: c_int) -> *c_char;
     fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in;
     fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6;
     fn rust_uv_free_ip4_addr(addr: *sockaddr_in);
@@ -856,4 +929,13 @@ fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
     fn rust_uv_set_data_for_req(req: *c_void, data: *c_void);
     fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
     fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t;
+    fn rust_uv_spawn(loop_ptr: *c_void, outptr: *uv_process_t,
+                     options: uv_process_options_t) -> c_int;
+    fn rust_uv_process_kill(p: *uv_process_t, signum: c_int) -> c_int;
+    fn rust_uv_process_pid(p: *uv_process_t) -> c_int;
+    fn rust_set_stdio_container_flags(c: *uv_stdio_container_t, flags: c_int);
+    fn rust_set_stdio_container_fd(c: *uv_stdio_container_t, fd: c_int);
+    fn rust_set_stdio_container_stream(c: *uv_stdio_container_t,
+                                       stream: *uv_stream_t);
+    fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int;
 }
index eeaee4c14a51264ae801491926078e5a02c9e7ba..b91aac2224401a532dcd9f54afda9ceb7f8a144f 100644 (file)
 
 //! Process spawning.
 
-#[allow(missing_doc)];
-
-use c_str::ToCStr;
 use cast;
-use clone::Clone;
+use cell::Cell;
 use comm::{stream, SharedChan, GenericChan, GenericPort};
-use io;
-use libc::{pid_t, c_void, c_int};
+#[cfg(not(windows))]
 use libc;
-use option::{Some, None};
-use os;
+use libc::{pid_t, c_int};
 use prelude::*;
-use ptr;
 use task;
 use vec::ImmutableVector;
 
+use rt::io;
+use rt::local::Local;
+use rt::rtio::{IoFactoryObject, RtioProcessObject, RtioProcess, IoFactory};
+use rt::uv::process;
+
 /**
  * A value representing a child process.
  *
  * for the process to terminate.
  */
 pub struct Process {
-
     /// The unique id of the process (this should never be negative).
     priv pid: pid_t,
 
-    /**
-     * A handle to the process - on unix this will always be NULL, but on
-     * windows it will be a HANDLE to the process, which will prevent the
-     * pid being re-used until the handle is closed.
-     */
-    priv handle: *(),
+    /// The internal handle to the underlying libuv process.
+    priv handle: ~RtioProcessObject,
 
-    /// Some(fd), or None when stdin is being redirected from a fd not created by Process::new.
-    priv input: Option<c_int>,
+    /// Some(fd), or None when stdin is being redirected from a fd not created
+    /// by Process::new.
+    priv input: Option<~io::Writer>,
 
-    /// Some(file), or None when stdout is being redirected to a fd not created by Process::new.
-    priv output: Option<*libc::FILE>,
+    /// Some(file), or None when stdout is being redirected to a fd not created
+    /// by Process::new.
+    priv output: Option<~io::Reader>,
 
-    /// Some(file), or None when stderr is being redirected to a fd not created by Process::new.
-    priv error: Option<*libc::FILE>,
-
-    /// None until finish() is called.
-    priv exit_code: Option<int>,
+    /// Some(file), or None when stderr is being redirected to a fd not created
+    /// by Process::new.
+    priv error: Option<~io::Reader>,
 }
 
 /// Options that can be given when starting a Process.
@@ -93,26 +87,27 @@ pub struct ProcessOptions<'self> {
      * If this is None then a new pipe will be created for the new program's
      * output and Process.output() will provide a Reader to read from this pipe.
      *
-     * If this is Some(file-descriptor) then the new process will write its output
-     * to the given file descriptor, Process.output_redirected() will return
-     * true, and Process.output() will fail.
+     * If this is Some(file-descriptor) then the new process will write its
+     * output to the given file descriptor, Process.output_redirected() will
+     * return true, and Process.output() will fail.
      */
     out_fd: Option<c_int>,
 
     /**
-     * If this is None then a new pipe will be created for the new program's
-     * error stream and Process.error() will provide a Reader to read from this pipe.
+     * If this is None then a new pipe will be created for the new progam's
+     * error stream and Process.error() will provide a Reader to read from this
+     * pipe.
      *
-     * If this is Some(file-descriptor) then the new process will write its error output
-     * to the given file descriptor, Process.error_redirected() will return true, and
-     * and Process.error() will fail.
+     * If this is Some(file-descriptor) then the new process will write its
+     * error output to the given file descriptor, Process.error_redirected()
+     * will return true, and and Process.error() will fail.
      */
     err_fd: Option<c_int>,
 }
 
-impl <'self> ProcessOptions<'self> {
+impl<'self> ProcessOptions<'self> {
     /// Return a ProcessOptions that has None in every field.
-    pub fn new<'a>() -> ProcessOptions<'a> {
+    pub fn new() -> ProcessOptions {
         ProcessOptions {
             env: None,
             dir: None,
@@ -125,7 +120,6 @@ pub fn new<'a>() -> ProcessOptions<'a> {
 
 /// The output of a finished process.
 pub struct ProcessOutput {
-
     /// The status (exit code) of the process.
     status: int,
 
@@ -148,223 +142,159 @@ impl Process {
      *             the working directory and the standard IO streams.
      */
     pub fn new(prog: &str, args: &[~str],
-               options: ProcessOptions)
-               -> Process {
-        #[fixed_stack_segment]; #[inline(never)];
-
-        let (in_pipe, in_fd) = match options.in_fd {
+               options: ProcessOptions) -> Option<Process> {
+        // First, translate all the stdio options into their libuv equivalents
+        let (uv_stdin, stdin) = match options.in_fd {
+            Some(fd) => (process::InheritFd(fd), None),
             None => {
-                let pipe = os::pipe();
-                (Some(pipe), pipe.input)
-            },
-            Some(fd) => (None, fd)
+                let p = io::pipe::PipeStream::new().expect("need stdin pipe");
+                (process::CreatePipe(p.uv_pipe(), true, false),
+                 Some(~p as ~io::Writer))
+            }
         };
-        let (out_pipe, out_fd) = match options.out_fd {
+        let (uv_stdout, stdout) = match options.out_fd {
+            Some(fd) => (process::InheritFd(fd), None),
             None => {
-                let pipe = os::pipe();
-                (Some(pipe), pipe.out)
-            },
-            Some(fd) => (None, fd)
+                let p = io::pipe::PipeStream::new().expect("need stdout pipe");
+                (process::CreatePipe(p.uv_pipe(), false, true),
+                 Some(~p as ~io::Reader))
+            }
         };
-        let (err_pipe, err_fd) = match options.err_fd {
+        let (uv_stderr, stderr) = match options.err_fd {
+            Some(fd) => (process::InheritFd(fd), None),
             None => {
-                let pipe = os::pipe();
-                (Some(pipe), pipe.out)
-            },
-            Some(fd) => (None, fd)
+                let p = io::pipe::PipeStream::new().expect("need stderr pipe");
+                (process::CreatePipe(p.uv_pipe(), false, true),
+                 Some(~p as ~io::Reader))
+            }
         };
 
-        let res = spawn_process_os(prog, args, options.env.clone(), options.dir,
-                                   in_fd, out_fd, err_fd);
+        // Next, massage our options into the libuv options
+        let dir = options.dir.map(|d| d.to_str());
+        let dir = dir.map(|d| d.as_slice());
+        let config = process::Config {
+            program: prog,
+            args: args,
+            env: options.env.map(|e| e.as_slice()),
+            cwd: dir,
+            io: [uv_stdin, uv_stdout, uv_stderr],
+        };
 
+        // Finally, actually spawn the process
         unsafe {
-            for pipe in in_pipe.iter() { libc::close(pipe.input); }
-            for pipe in out_pipe.iter() { libc::close(pipe.out); }
-            for pipe in err_pipe.iter() { libc::close(pipe.out); }
-        }
-
-        Process {
-            pid: res.pid,
-            handle: res.handle,
-            input: in_pipe.map(|pipe| pipe.out),
-            output: out_pipe.map(|pipe| os::fdopen(pipe.input)),
-            error: err_pipe.map(|pipe| os::fdopen(pipe.input)),
-            exit_code: None,
+            let io: *mut IoFactoryObject = Local::unsafe_borrow();
+            match (*io).spawn(&config) {
+                Ok(handle) => {
+                    Some(Process {
+                        pid: handle.id(),
+                        handle: handle,
+                        input: stdin,
+                        output: stdout,
+                        error: stderr,
+                    })
+                }
+                Err(*) => { None }
+            }
         }
     }
 
     /// Returns the unique id of the process
     pub fn get_id(&self) -> pid_t { self.pid }
 
-    fn input_fd(&mut self) -> c_int {
-        match self.input {
-            Some(fd) => fd,
-            None => fail!("This Process's stdin was redirected to an \
-                           existing file descriptor.")
-        }
-    }
-
-    fn output_file(&mut self) -> *libc::FILE {
-        match self.output {
-            Some(file) => file,
-            None => fail!("This Process's stdout was redirected to an \
-                           existing file descriptor.")
-        }
-    }
-
-    fn error_file(&mut self) -> *libc::FILE {
-        match self.error {
-            Some(file) => file,
-            None => fail!("This Process's stderr was redirected to an \
-                           existing file descriptor.")
-        }
-    }
-
     /**
-     * Returns whether this process is reading its stdin from an existing file
-     * descriptor rather than a pipe that was created specifically for this
-     * process.
+     * Returns a rt::io::Writer that can be used to write to this Process's
+     * stdin.
      *
-     * If this method returns true then self.input() will fail.
+     * Fails if this Process's stdin was redirected to an existing file
+     * descriptor.
      */
-    pub fn input_redirected(&self) -> bool {
-        self.input.is_none()
+    pub fn input<'a>(&'a mut self) -> &'a mut io::Writer {
+        let ret: &mut io::Writer = *self.input.get_mut_ref();
+        return ret;
     }
 
     /**
-     * Returns whether this process is writing its stdout to an existing file
-     * descriptor rather than a pipe that was created specifically for this
-     * process.
+     * Returns a rt::io::Reader that can be used to read from this Process's
+     * stdout.
      *
-     * If this method returns true then self.output() will fail.
+     * Fails if this Process's stdout was redirected to an existing file
+     * descriptor.
      */
-    pub fn output_redirected(&self) -> bool {
-        self.output.is_none()
+    pub fn output<'a>(&'a mut self) -> &'a mut io::Reader {
+        let ret: &mut io::Reader = *self.output.get_mut_ref();
+        return ret;
     }
 
     /**
-     * Returns whether this process is writing its stderr to an existing file
-     * descriptor rather than a pipe that was created specifically for this
-     * process.
+     * Returns a rt::io::Reader that can be used to read from this Process's
+     * stderr.
      *
-     * If this method returns true then self.error() will fail.
+     * Fails if this Process's stderr was redirected to an existing file
+     * descriptor.
      */
-    pub fn error_redirected(&self) -> bool {
-        self.error.is_none()
+    pub fn error<'a>(&'a mut self) -> &'a mut io::Reader {
+        let ret: &mut io::Reader = *self.error.get_mut_ref();
+        return ret;
     }
 
     /**
-     * Returns an io::Writer that can be used to write to this Process's stdin.
+     * Closes the handle to stdin, waits for the child process to terminate, and
+     * returns the exit code.
      *
-     * Fails if this Process's stdin was redirected to an existing file descriptor.
+     * If the child has already been finished then the exit code is returned.
      */
-    pub fn input(&mut self) -> @io::Writer {
-        // FIXME: the Writer can still be used after self is destroyed: #2625
-       io::fd_writer(self.input_fd(), false)
-    }
+    pub fn finish(&mut self) -> int {
+        // We're not going to be giving any more input, so close the input by
+        // destroying it. Also, if the output is desired, then
+        // finish_with_output is called so we discard all the outputs here. Note
+        // that the process may not terminate if we don't destroy stdio because
+        // it'll be waiting in a write which we'll just never read.
+        self.input.take();
+        self.output.take();
+        self.error.take();
 
-    /**
-     * Returns an io::Reader that can be used to read from this Process's stdout.
-     *
-     * Fails if this Process's stdout was redirected to an existing file descriptor.
-     */
-    pub fn output(&mut self) -> @io::Reader {
-        // FIXME: the Reader can still be used after self is destroyed: #2625
-        io::FILE_reader(self.output_file(), false)
+        self.handle.wait()
     }
 
     /**
-     * Returns an io::Reader that can be used to read from this Process's stderr.
+     * Closes the handle to stdin, waits for the child process to terminate,
+     * and reads and returns all remaining output of stdout and stderr, along
+     * with the exit code.
      *
-     * Fails if this Process's stderr was redirected to an existing file descriptor.
-     */
-    pub fn error(&mut self) -> @io::Reader {
-        // FIXME: the Reader can still be used after self is destroyed: #2625
-        io::FILE_reader(self.error_file(), false)
-    }
-
-    /**
-     * Closes the handle to the child process's stdin.
+     * If the child has already been finished then the exit code and any
+     * remaining unread output of stdout and stderr will be returned.
      *
-     * If this process is reading its stdin from an existing file descriptor, then this
-     * method does nothing.
+     * This method will fail if the child process's stdout or stderr streams
+     * were redirected to existing file descriptors, or if this method has
+     * already been called.
      */
-    pub fn close_input(&mut self) {
-        #[fixed_stack_segment]; #[inline(never)];
-        match self.input {
-            Some(-1) | None => (),
-            Some(fd) => {
-                unsafe {
-                    libc::close(fd);
+    pub fn finish_with_output(&mut self) -> ProcessOutput {
+        // This should probably be a helper method in rt::io
+        fn read_everything(input: &mut io::Reader) -> ~[u8] {
+            let mut result = ~[];
+            let mut buf = [0u8, ..1024];
+            loop {
+                match input.read(buf) {
+                    Some(i) => { result = result + buf.slice_to(i) }
+                    None => break
                 }
-                self.input = Some(-1);
             }
+            return result;
         }
-    }
-
-    fn close_outputs(&mut self) {
-        #[fixed_stack_segment]; #[inline(never)];
-        fclose_and_null(&mut self.output);
-        fclose_and_null(&mut self.error);
-
-        fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
-            #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
-            match *f_opt {
-                Some(f) if !f.is_null() => {
-                    unsafe {
-                        libc::fclose(f);
-                        *f_opt = Some(0 as *libc::FILE);
-                    }
-                },
-                _ => ()
-            }
-        }
-    }
-
-    /**
-     * Closes the handle to stdin, waits for the child process to terminate,
-     * and returns the exit code.
-     *
-     * If the child has already been finished then the exit code is returned.
-     */
-    pub fn finish(&mut self) -> int {
-        for &code in self.exit_code.iter() {
-            return code;
-        }
-        self.close_input();
-        let code = waitpid(self.pid);
-        self.exit_code = Some(code);
-        return code;
-    }
 
-    /**
-     * Closes the handle to stdin, waits for the child process to terminate, and reads
-     * and returns all remaining output of stdout and stderr, along with the exit code.
-     *
-     * If the child has already been finished then the exit code and any remaining
-     * unread output of stdout and stderr will be returned.
-     *
-     * This method will fail if the child process's stdout or stderr streams were
-     * redirected to existing file descriptors.
-     */
-    pub fn finish_with_output(&mut self) -> ProcessOutput {
-        let output_file = self.output_file();
-        let error_file = self.error_file();
-
-        // Spawn two entire schedulers to read both stdout and sterr
-        // in parallel so we don't deadlock while blocking on one
-        // or the other. FIXME (#2625): Surely there's a much more
-        // clever way to do this.
         let (p, ch) = stream();
         let ch = SharedChan::new(ch);
         let ch_clone = ch.clone();
-        do task::spawn_sched(task::SingleThreaded) {
-            let errput = io::FILE_reader(error_file, false);
-            ch.send((2, errput.read_whole_stream()));
+
+        let stderr = Cell::new(self.error.take().unwrap());
+        do task::spawn {
+            let output = read_everything(stderr.take());
+            ch.send((2, output));
         }
-        do task::spawn_sched(task::SingleThreaded) {
-            let output = io::FILE_reader(output_file, false);
-            ch_clone.send((1, output.read_whole_stream()));
+        let stdout = Cell::new(self.output.take().unwrap());
+        do task::spawn {
+            let output = read_everything(stdout.take());
+            ch_clone.send((1, output));
         }
 
         let status = self.finish();
@@ -382,40 +312,6 @@ pub fn finish_with_output(&mut self) -> ProcessOutput {
                               error: errs};
     }
 
-    fn destroy_internal(&mut self, force: bool) {
-        // if the process has finished, and therefore had waitpid called,
-        // and we kill it, then on unix we might ending up killing a
-        // newer process that happens to have the same (re-used) id
-        if self.exit_code.is_none() {
-            killpid(self.pid, force);
-            self.finish();
-        }
-
-        #[cfg(windows)]
-        fn killpid(pid: pid_t, _force: bool) {
-            #[fixed_stack_segment]; #[inline(never)];
-            unsafe {
-                libc::funcs::extra::kernel32::TerminateProcess(
-                    cast::transmute(pid), 1);
-            }
-        }
-
-        #[cfg(unix)]
-        fn killpid(pid: pid_t, force: bool) {
-            #[fixed_stack_segment]; #[inline(never)];
-
-            let signal = if force {
-                libc::consts::os::posix88::SIGKILL
-            } else {
-                libc::consts::os::posix88::SIGTERM
-            };
-
-            unsafe {
-                libc::funcs::posix88::signal::kill(pid, signal as c_int);
-            }
-        }
-    }
-
     /**
      * Terminates the process, giving it a chance to clean itself up if
      * this is supported by the operating system.
@@ -423,7 +319,12 @@ fn killpid(pid: pid_t, force: bool) {
      * On Posix OSs SIGTERM will be sent to the process. On Win32
      * TerminateProcess(..) will be called.
      */
-    pub fn destroy(&mut self) { self.destroy_internal(false); }
+    pub fn destroy(&mut self) {
+        #[cfg(windows)]      fn sigterm() -> int { 15 }
+        #[cfg(not(windows))] fn sigterm() -> int { libc::SIGTERM as int }
+        self.handle.kill(sigterm());
+        self.finish();
+    }
 
     /**
      * Terminates the process as soon as possible without giving it a
@@ -432,378 +333,22 @@ fn killpid(pid: pid_t, force: bool) {
      * On Posix OSs SIGKILL will be sent to the process. On Win32
      * TerminateProcess(..) will be called.
      */
-    pub fn force_destroy(&mut self) { self.destroy_internal(true); }
+    pub fn force_destroy(&mut self) {
+        #[cfg(windows)]      fn sigkill() -> int { 9 }
+        #[cfg(not(windows))] fn sigkill() -> int { libc::SIGKILL as int }
+        self.handle.kill(sigkill());
+        self.finish();
+    }
 }
 
 impl Drop for Process {
     fn drop(&self) {
         // FIXME(#4330) Need self by value to get mutability.
         let mut_self: &mut Process = unsafe { cast::transmute(self) };
-
         mut_self.finish();
-        mut_self.close_outputs();
-        free_handle(self.handle);
-    }
-}
-
-struct SpawnProcessResult {
-    pid: pid_t,
-    handle: *(),
-}
-
-#[cfg(windows)]
-fn spawn_process_os(prog: &str, args: &[~str],
-                    env: Option<~[(~str, ~str)]>,
-                    dir: Option<&Path>,
-                    in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
-    use libc::consts::os::extra::{
-        TRUE, FALSE,
-        STARTF_USESTDHANDLES,
-        INVALID_HANDLE_VALUE,
-        DUPLICATE_SAME_ACCESS
-    };
-    use libc::funcs::extra::kernel32::{
-        GetCurrentProcess,
-        DuplicateHandle,
-        CloseHandle,
-        CreateProcessA
-    };
-    use libc::funcs::extra::msvcrt::get_osfhandle;
-
-    use sys;
-
-    unsafe {
-
-        let mut si = zeroed_startupinfo();
-        si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
-        si.dwFlags = STARTF_USESTDHANDLES;
-
-        let cur_proc = GetCurrentProcess();
-
-        let orig_std_in = get_osfhandle(in_fd) as HANDLE;
-        if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
-            fail!("failure in get_osfhandle: %s", os::last_os_error());
-        }
-        if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
-                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
-            fail!("failure in DuplicateHandle: %s", os::last_os_error());
-        }
-
-        let orig_std_out = get_osfhandle(out_fd) as HANDLE;
-        if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
-            fail!("failure in get_osfhandle: %s", os::last_os_error());
-        }
-        if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
-                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
-            fail!("failure in DuplicateHandle: %s", os::last_os_error());
-        }
-
-        let orig_std_err = get_osfhandle(err_fd) as HANDLE;
-        if orig_std_err == INVALID_HANDLE_VALUE as HANDLE {
-            fail!("failure in get_osfhandle: %s", os::last_os_error());
-        }
-        if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
-                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
-            fail!("failure in DuplicateHandle: %s", os::last_os_error());
-        }
-
-        let cmd = make_command_line(prog, args);
-        let mut pi = zeroed_process_information();
-        let mut create_err = None;
-
-        do with_envp(env) |envp| {
-            do with_dirp(dir) |dirp| {
-                do cmd.with_c_str |cmdp| {
-                    let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
-                                                 ptr::mut_null(), ptr::mut_null(), TRUE,
-                                                 0, envp, dirp, &mut si, &mut pi);
-                    if created == FALSE {
-                        create_err = Some(os::last_os_error());
-                    }
-                }
-            }
-        }
-
-        CloseHandle(si.hStdInput);
-        CloseHandle(si.hStdOutput);
-        CloseHandle(si.hStdError);
-
-        for msg in create_err.iter() {
-            fail!("failure in CreateProcess: %s", *msg);
-        }
-
-        // We close the thread handle because we don't care about keeping the thread id valid,
-        // and we aren't keeping the thread handle around to be able to close it later. We don't
-        // close the process handle however because we want the process id to stay valid at least
-        // until the calling code closes the process handle.
-        CloseHandle(pi.hThread);
-
-        SpawnProcessResult {
-            pid: pi.dwProcessId as pid_t,
-            handle: pi.hProcess as *()
-        }
-    }
-}
-
-#[cfg(windows)]
-fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
-    libc::types::os::arch::extra::STARTUPINFO {
-        cb: 0,
-        lpReserved: ptr::mut_null(),
-        lpDesktop: ptr::mut_null(),
-        lpTitle: ptr::mut_null(),
-        dwX: 0,
-        dwY: 0,
-        dwXSize: 0,
-        dwYSize: 0,
-        dwXCountChars: 0,
-        dwYCountCharts: 0,
-        dwFillAttribute: 0,
-        dwFlags: 0,
-        wShowWindow: 0,
-        cbReserved2: 0,
-        lpReserved2: ptr::mut_null(),
-        hStdInput: ptr::mut_null(),
-        hStdOutput: ptr::mut_null(),
-        hStdError: ptr::mut_null()
-    }
-}
-
-#[cfg(windows)]
-fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
-    libc::types::os::arch::extra::PROCESS_INFORMATION {
-        hProcess: ptr::mut_null(),
-        hThread: ptr::mut_null(),
-        dwProcessId: 0,
-        dwThreadId: 0
-    }
-}
-
-// FIXME: this is only pub so it can be tested (see issue #4536)
-#[cfg(windows)]
-pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
-    let mut cmd = ~"";
-    append_arg(&mut cmd, prog);
-    for arg in args.iter() {
-        cmd.push_char(' ');
-        append_arg(&mut cmd, *arg);
-    }
-    return cmd;
-
-    fn append_arg(cmd: &mut ~str, arg: &str) {
-        let quote = arg.iter().any(|c| c == ' ' || c == '\t');
-        if quote {
-            cmd.push_char('"');
-        }
-        for i in range(0u, arg.len()) {
-            append_char_at(cmd, arg, i);
-        }
-        if quote {
-            cmd.push_char('"');
-        }
-    }
-
-    fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
-        match arg[i] as char {
-            '"' => {
-                // Escape quotes.
-                cmd.push_str("\\\"");
-            }
-            '\\' => {
-                if backslash_run_ends_in_quote(arg, i) {
-                    // Double all backslashes that are in runs before quotes.
-                    cmd.push_str("\\\\");
-                } else {
-                    // Pass other backslashes through unescaped.
-                    cmd.push_char('\\');
-                }
-            }
-            c => {
-                cmd.push_char(c);
-            }
-        }
-    }
-
-    fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
-        while i < s.len() && s[i] as char == '\\' {
-            i += 1;
-        }
-        return i < s.len() && s[i] as char == '"';
-    }
-}
-
-#[cfg(unix)]
-fn spawn_process_os(prog: &str, args: &[~str],
-                    env: Option<~[(~str, ~str)]>,
-                    dir: Option<&Path>,
-                    in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
-    use libc::funcs::bsd44::getdtablesize;
-
-    mod rustrt {
-        use libc::c_void;
-
-        #[abi = "cdecl"]
-        extern {
-            pub fn rust_unset_sigprocmask();
-            pub fn rust_set_environ(envp: *c_void);
-        }
-    }
-
-    unsafe {
-
-        let pid = fork();
-        if pid < 0 {
-            fail!("failure in fork: %s", os::last_os_error());
-        } else if pid > 0 {
-            return SpawnProcessResult {pid: pid, handle: ptr::null()};
-        }
-
-        rustrt::rust_unset_sigprocmask();
-
-        if dup2(in_fd, 0) == -1 {
-            fail!("failure in dup2(in_fd, 0): %s", os::last_os_error());
-        }
-        if dup2(out_fd, 1) == -1 {
-            fail!("failure in dup2(out_fd, 1): %s", os::last_os_error());
-        }
-        if dup2(err_fd, 2) == -1 {
-            fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
-        }
-        // close all other fds
-        for fd in range(3, getdtablesize()).invert() {
-            close(fd as c_int);
-        }
-
-        do with_dirp(dir) |dirp| {
-            if !dirp.is_null() && chdir(dirp) == -1 {
-                fail!("failure in chdir: %s", os::last_os_error());
-            }
-        }
-
-        do with_envp(env) |envp| {
-            if !envp.is_null() {
-                rustrt::rust_set_environ(envp);
-            }
-            do with_argv(prog, args) |argv| {
-                execvp(*argv, argv);
-                // execvp only returns if an error occurred
-                fail!("failure in execvp: %s", os::last_os_error());
-            }
-        }
-    }
-}
-
-#[cfg(unix)]
-fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
-    use vec;
-
-    // We can't directly convert `str`s into `*char`s, as someone needs to hold
-    // a reference to the intermediary byte buffers. So first build an array to
-    // hold all the ~[u8] byte strings.
-    let mut tmps = vec::with_capacity(args.len() + 1);
-
-    tmps.push(prog.to_c_str());
-
-    for arg in args.iter() {
-        tmps.push(arg.to_c_str());
-    }
-
-    // Next, convert each of the byte strings into a pointer. This is
-    // technically unsafe as the caller could leak these pointers out of our
-    // scope.
-    let mut ptrs = do tmps.map |tmp| {
-        tmp.with_ref(|buf| buf)
-    };
-
-    // Finally, make sure we add a null pointer.
-    ptrs.push(ptr::null());
-
-    ptrs.as_imm_buf(|buf, _| cb(buf))
-}
-
-#[cfg(unix)]
-fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
-    use vec;
-
-    // On posixy systems we can pass a char** for envp, which is a
-    // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
-    // have a temporary buffer to hold the intermediary `~[u8]` byte strings.
-    match env {
-        Some(env) => {
-            let mut tmps = vec::with_capacity(env.len());
-
-            for pair in env.iter() {
-                // Use of match here is just to workaround limitations
-                // in the stage0 irrefutable pattern impl.
-                let kv = fmt!("%s=%s", pair.first(), pair.second());
-                tmps.push(kv.to_c_str());
-            }
-
-            // Once again, this is unsafe.
-            let mut ptrs = do tmps.map |tmp| {
-                tmp.with_ref(|buf| buf)
-            };
-            ptrs.push(ptr::null());
-
-            do ptrs.as_imm_buf |buf, _| {
-                unsafe { cb(cast::transmute(buf)) }
-            }
-        }
-        _ => cb(ptr::null())
-    }
-}
-
-#[cfg(windows)]
-fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
-    // On win32 we pass an "environment block" which is not a char**, but
-    // rather a concatenation of null-terminated k=v\0 sequences, with a final
-    // \0 to terminate.
-    match env {
-        Some(env) => {
-            let mut blk = ~[];
-
-            for pair in env.iter() {
-                let kv = fmt!("%s=%s", pair.first(), pair.second());
-                blk.push_all(kv.as_bytes());
-                blk.push(0);
-            }
-
-            blk.push(0);
-
-            do blk.as_imm_buf |p, _len| {
-                unsafe { cb(cast::transmute(p)) }
-            }
-        }
-        _ => cb(ptr::mut_null())
-    }
-}
-
-fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
-    match d {
-      Some(dir) => dir.with_c_str(|buf| cb(buf)),
-      None => cb(ptr::null())
-    }
-}
-
-#[cfg(windows)]
-fn free_handle(handle: *()) {
-    #[fixed_stack_segment]; #[inline(never)];
-    unsafe {
-        libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
     }
 }
 
-#[cfg(unix)]
-fn free_handle(_handle: *()) {
-    // unix has no process handle object, just a pid
-}
-
 /**
  * Spawns a process and waits for it to terminate. The process will
  * inherit the current stdin/stdout/stderr file descriptors.
@@ -824,7 +369,7 @@ pub fn process_status(prog: &str, args: &[~str]) -> int {
         in_fd: Some(0),
         out_fd: Some(1),
         err_fd: Some(2)
-    });
+    }).unwrap();
     prog.finish()
 }
 
@@ -841,162 +386,38 @@ pub fn process_status(prog: &str, args: &[~str]) -> int {
  * The process's stdout/stderr output and exit code.
  */
 pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput {
-    let mut prog = Process::new(prog, args, ProcessOptions::new());
+    let mut prog = Process::new(prog, args, ProcessOptions::new()).unwrap();
     prog.finish_with_output()
 }
 
-/**
- * Waits for a process to exit and returns the exit code, failing
- * if there is no process with the specified id.
- *
- * Note that this is private to avoid race conditions on unix where if
- * a user calls waitpid(some_process.get_id()) then some_process.finish()
- * and some_process.destroy() and some_process.finalize() will then either
- * operate on a none-existent process or, even worse, on a newer process
- * with the same id.
- */
-fn waitpid(pid: pid_t) -> int {
-    return waitpid_os(pid);
-
-    #[cfg(windows)]
-    fn waitpid_os(pid: pid_t) -> int {
-        #[fixed_stack_segment]; #[inline(never)];
-
-        use libc::types::os::arch::extra::DWORD;
-        use libc::consts::os::extra::{
-            SYNCHRONIZE,
-            PROCESS_QUERY_INFORMATION,
-            FALSE,
-            STILL_ACTIVE,
-            INFINITE,
-            WAIT_FAILED
-        };
-        use libc::funcs::extra::kernel32::{
-            OpenProcess,
-            GetExitCodeProcess,
-            CloseHandle,
-            WaitForSingleObject
-        };
-
-        unsafe {
-
-            let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
-            if proc.is_null() {
-                fail!("failure in OpenProcess: %s", os::last_os_error());
-            }
-
-            loop {
-                let mut status = 0;
-                if GetExitCodeProcess(proc, &mut status) == FALSE {
-                    CloseHandle(proc);
-                    fail!("failure in GetExitCodeProcess: %s", os::last_os_error());
-                }
-                if status != STILL_ACTIVE {
-                    CloseHandle(proc);
-                    return status as int;
-                }
-                if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
-                    CloseHandle(proc);
-                    fail!("failure in WaitForSingleObject: %s", os::last_os_error());
-                }
-            }
-        }
-    }
-
-    #[cfg(unix)]
-    fn waitpid_os(pid: pid_t) -> int {
-        #[fixed_stack_segment]; #[inline(never)];
-
-        use libc::funcs::posix01::wait::*;
-
-        #[cfg(target_os = "linux")]
-        #[cfg(target_os = "android")]
-        fn WIFEXITED(status: i32) -> bool {
-            (status & 0xffi32) == 0i32
-        }
-
-        #[cfg(target_os = "macos")]
-        #[cfg(target_os = "freebsd")]
-        fn WIFEXITED(status: i32) -> bool {
-            (status & 0x7fi32) == 0i32
-        }
-
-        #[cfg(target_os = "linux")]
-        #[cfg(target_os = "android")]
-        fn WEXITSTATUS(status: i32) -> i32 {
-            (status >> 8i32) & 0xffi32
-        }
-
-        #[cfg(target_os = "macos")]
-        #[cfg(target_os = "freebsd")]
-        fn WEXITSTATUS(status: i32) -> i32 {
-            status >> 8i32
-        }
-
-        let mut status = 0 as c_int;
-        if unsafe { waitpid(pid, &mut status, 0) } == -1 {
-            fail!("failure in waitpid: %s", os::last_os_error());
-        }
-
-        return if WIFEXITED(status) {
-            WEXITSTATUS(status) as int
-        } else {
-            1
-        };
-    }
-}
-
 #[cfg(test)]
 mod tests {
-    use io;
-    use libc::{c_int, uintptr_t};
-    use option::{Option, None, Some};
     use os;
     use path::Path;
-    use run;
+    use prelude::*;
     use str;
+    use super::*;
     use unstable::running_on_valgrind;
 
-    #[test]
-    #[cfg(windows)]
-    fn test_make_command_line() {
-        assert_eq!(
-            run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
-            ~"prog aaa bbb ccc"
-        );
-        assert_eq!(
-            run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
-            ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
-        );
-        assert_eq!(
-            run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
-            ~"\"C:\\Program Files\\test\" aa\\\"bb"
-        );
-        assert_eq!(
-            run::make_command_line("echo", [~"a b c"]),
-            ~"echo \"a b c\""
-        );
-    }
-
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_process_status() {
-        assert_eq!(run::process_status("false", []), 1);
-        assert_eq!(run::process_status("true", []), 0);
+        assert_eq!(process_status("false", []), 1);
+        assert_eq!(process_status("true", []), 0);
     }
     #[test]
     #[cfg(target_os="android")]
     fn test_process_status() {
-        assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"false"]), 1);
-        assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"true"]), 0);
+        assert_eq!(process_status("/system/bin/sh", [~"-c",~"false"]), 1);
+        assert_eq!(process_status("/system/bin/sh", [~"-c",~"true"]), 0);
     }
 
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_process_output_output() {
 
-        let run::ProcessOutput {status, output, error}
-             = run::process_output("echo", [~"hello"]);
+        let ProcessOutput {status, output, error}
+             = process_output("echo", [~"hello"]);
         let output_str = str::from_bytes(output);
 
         assert_eq!(status, 0);
@@ -1010,8 +431,8 @@ fn test_process_output_output() {
     #[cfg(target_os="android")]
     fn test_process_output_output() {
 
-        let run::ProcessOutput {status, output, error}
-             = run::process_output("/system/bin/sh", [~"-c",~"echo hello"]);
+        let ProcessOutput {status, output, error}
+             = process_output("/system/bin/sh", [~"-c",~"echo hello"]);
         let output_str = str::from_bytes(output);
 
         assert_eq!(status, 0);
@@ -1026,8 +447,8 @@ fn test_process_output_output() {
     #[cfg(not(target_os="android"))]
     fn test_process_output_error() {
 
-        let run::ProcessOutput {status, output, error}
-             = run::process_output("mkdir", [~"."]);
+        let ProcessOutput {status, output, error}
+             = process_output("mkdir", [~"."]);
 
         assert_eq!(status, 1);
         assert_eq!(output, ~[]);
@@ -1037,90 +458,40 @@ fn test_process_output_error() {
     #[cfg(target_os="android")]
     fn test_process_output_error() {
 
-        let run::ProcessOutput {status, output, error}
-             = run::process_output("/system/bin/mkdir", [~"."]);
+        let ProcessOutput {status, output, error}
+             = process_output("/system/bin/mkdir", [~"."]);
 
         assert_eq!(status, 255);
         assert_eq!(output, ~[]);
         assert!(!error.is_empty());
     }
 
-    #[test]
-    fn test_pipes() {
-
-        let pipe_in = os::pipe();
-        let pipe_out = os::pipe();
-        let pipe_err = os::pipe();
-
-        let mut proc = run::Process::new("cat", [], run::ProcessOptions {
-            dir: None,
-            env: None,
-            in_fd: Some(pipe_in.input),
-            out_fd: Some(pipe_out.out),
-            err_fd: Some(pipe_err.out)
-        });
-
-        assert!(proc.input_redirected());
-        assert!(proc.output_redirected());
-        assert!(proc.error_redirected());
-
-        os::close(pipe_in.input);
-        os::close(pipe_out.out);
-        os::close(pipe_err.out);
-
-        let expected = ~"test";
-        writeclose(pipe_in.out, expected);
-        let actual = readclose(pipe_out.input);
-        readclose(pipe_err.input);
-        proc.finish();
-
-        assert_eq!(expected, actual);
-    }
-
-    fn writeclose(fd: c_int, s: &str) {
-        let writer = io::fd_writer(fd, false);
-        writer.write_str(s);
-        os::close(fd);
-    }
-
-    fn readclose(fd: c_int) -> ~str {
-        #[fixed_stack_segment]; #[inline(never)];
-
-        unsafe {
-            let file = os::fdopen(fd);
-            let reader = io::FILE_reader(file, false);
-            let buf = reader.read_whole_stream();
-            os::fclose(file);
-            str::from_bytes(buf)
-        }
-    }
-
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_finish_once() {
-        let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
+        let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
         assert_eq!(prog.finish(), 1);
     }
     #[test]
     #[cfg(target_os="android")]
     fn test_finish_once() {
-        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
-                                         run::ProcessOptions::new());
+        let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
+                                    ProcessOptions::new()).unwrap();
         assert_eq!(prog.finish(), 1);
     }
 
     #[test]
     #[cfg(not(target_os="android"))]
     fn test_finish_twice() {
-        let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
+        let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
         assert_eq!(prog.finish(), 1);
         assert_eq!(prog.finish(), 1);
     }
     #[test]
     #[cfg(target_os="android")]
     fn test_finish_twice() {
-        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
-                                         run::ProcessOptions::new());
+        let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
+                                    ProcessOptions::new()).unwrap();
         assert_eq!(prog.finish(), 1);
         assert_eq!(prog.finish(), 1);
     }
@@ -1129,8 +500,9 @@ fn test_finish_twice() {
     #[cfg(not(target_os="android"))]
     fn test_finish_with_output_once() {
 
-        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
-        let run::ProcessOutput {status, output, error}
+        let prog = Process::new("echo", [~"hello"], ProcessOptions::new());
+        let mut prog = prog.unwrap();
+        let ProcessOutput {status, output, error}
             = prog.finish_with_output();
         let output_str = str::from_bytes(output);
 
@@ -1145,28 +517,10 @@ fn test_finish_with_output_once() {
     #[cfg(target_os="android")]
     fn test_finish_with_output_once() {
 
-        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
-                                         run::ProcessOptions::new());
-        let run::ProcessOutput {status, output, error}
-            = prog.finish_with_output();
-        let output_str = str::from_bytes(output);
-
-        assert_eq!(status, 0);
-        assert_eq!(output_str.trim().to_owned(), ~"hello");
-        // FIXME #7224
-        if !running_on_valgrind() {
-            assert_eq!(error, ~[]);
-        }
-    }
-
-    #[test]
-    #[cfg(not(target_os="android"))]
-    fn test_finish_with_output_twice() {
-
-        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
-        let run::ProcessOutput {status, output, error}
+        let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+                                    ProcessOptions::new()).unwrap();
+        let ProcessOutput {status, output, error}
             = prog.finish_with_output();
-
         let output_str = str::from_bytes(output);
 
         assert_eq!(status, 0);
@@ -1175,97 +529,61 @@ fn test_finish_with_output_twice() {
         if !running_on_valgrind() {
             assert_eq!(error, ~[]);
         }
-
-        let run::ProcessOutput {status, output, error}
-            = prog.finish_with_output();
-
-        assert_eq!(status, 0);
-        assert_eq!(output, ~[]);
-        // FIXME #7224
-        if !running_on_valgrind() {
-            assert_eq!(error, ~[]);
-        }
-    }
-    #[test]
-    #[cfg(target_os="android")]
-    fn test_finish_with_output_twice() {
-
-        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
-                                         run::ProcessOptions::new());
-        let run::ProcessOutput {status, output, error}
-            = prog.finish_with_output();
-
-        let output_str = str::from_bytes(output);
-
-        assert_eq!(status, 0);
-        assert_eq!(output_str.trim().to_owned(), ~"hello");
-        // FIXME #7224
-        if !running_on_valgrind() {
-            assert_eq!(error, ~[]);
-        }
-
-        let run::ProcessOutput {status, output, error}
-            = prog.finish_with_output();
-
-        assert_eq!(status, 0);
-        assert_eq!(output, ~[]);
-        // FIXME #7224
-        if !running_on_valgrind() {
-            assert_eq!(error, ~[]);
-        }
     }
 
     #[test]
     #[should_fail]
     #[cfg(not(windows),not(target_os="android"))]
     fn test_finish_with_output_redirected() {
-        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions {
+        let mut prog = Process::new("echo", [~"hello"], ProcessOptions {
             env: None,
             dir: None,
             in_fd: Some(0),
             out_fd: Some(1),
             err_fd: Some(2)
-        });
-        // this should fail because it is not valid to read the output when it was redirected
+        }).unwrap();
+        // this should fail because it is not valid to read the output when it
+        // was redirected
         prog.finish_with_output();
     }
     #[test]
     #[should_fail]
     #[cfg(not(windows),target_os="android")]
     fn test_finish_with_output_redirected() {
-        let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
-                                         run::ProcessOptions {
+        let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+                                    ProcessOptions {
             env: None,
             dir: None,
             in_fd: Some(0),
             out_fd: Some(1),
             err_fd: Some(2)
-        });
-        // this should fail because it is not valid to read the output when it was redirected
+        }).unwrap();
+        // this should fail because it is not valid to read the output when it
+        // was redirected
         prog.finish_with_output();
     }
 
     #[cfg(unix,not(target_os="android"))]
-    fn run_pwd(dir: Option<&Path>) -> run::Process {
-        run::Process::new("pwd", [], run::ProcessOptions {
+    fn run_pwd(dir: Option<&Path>) -> Process {
+        Process::new("pwd", [], ProcessOptions {
             dir: dir,
-            .. run::ProcessOptions::new()
-        })
+            .. ProcessOptions::new()
+        }).unwrap()
     }
     #[cfg(unix,target_os="android")]
-    fn run_pwd(dir: Option<&Path>) -> run::Process {
-        run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions {
+    fn run_pwd(dir: Option<&Path>) -> Process {
+        Process::new("/system/bin/sh", [~"-c",~"pwd"], ProcessOptions {
             dir: dir,
-            .. run::ProcessOptions::new()
-        })
+            .. ProcessOptions::new()
+        }).unwrap()
     }
 
     #[cfg(windows)]
-    fn run_pwd(dir: Option<&Path>) -> run::Process {
-        run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions {
+    fn run_pwd(dir: Option<&Path>) -> Process {
+        Process::new("cmd", [~"/c", ~"cd"], ProcessOptions {
             dir: dir,
-            .. run::ProcessOptions::new()
-        })
+            .. ProcessOptions::new()
+        }).unwrap()
     }
 
     #[test]
@@ -1301,26 +619,26 @@ fn test_change_working_directory() {
     }
 
     #[cfg(unix,not(target_os="android"))]
-    fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
-        run::Process::new("env", [], run::ProcessOptions {
+    fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
+        Process::new("env", [], ProcessOptions {
             env: env,
-            .. run::ProcessOptions::new()
-        })
+            .. ProcessOptions::new()
+        }).unwrap()
     }
     #[cfg(unix,target_os="android")]
-    fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
-        run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
+    fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
+        Process::new("/system/bin/sh", [~"-c",~"set"], ProcessOptions {
             env: env,
-            .. run::ProcessOptions::new()
-        })
+            .. ProcessOptions::new()
+        }).unwrap()
     }
 
     #[cfg(windows)]
-    fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
-        run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
+    fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
+        Process::new("cmd", [~"/c", ~"set"], ProcessOptions {
             env: env,
-            .. run::ProcessOptions::new()
-        })
+            .. ProcessOptions::new()
+        }).unwrap()
     }
 
     #[test]
@@ -1357,7 +675,6 @@ fn test_inherit_env() {
 
     #[test]
     fn test_add_to_env() {
-
         let mut new_env = os::env();
         new_env.push((~"RUN_TEST_NEW_ENV", ~"123"));
 
index 531d55f6043b38e08291f9f3cfa5f98148df7c82..f121158d4c525cfe02254028531fb6bb0815bd9b 100644 (file)
@@ -60,7 +60,7 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
 
     do (|| {
         let c = Cell::new(c.take());
-        let sched = Local::take::<Scheduler>();
+        let sched: ~Scheduler = Local::take();
         do sched.deschedule_running_task_and_then |sched, task| {
             let task_handles = task.make_selectable(ports.len());
 
index 278df5b170e4bb3db035e1c7f2d82c1cc46e6496..ad3e4368daa5298c3e4f07e3b9a7c9316d0810ac 100644 (file)
@@ -148,7 +148,7 @@ pub mod linkhack {
 pub mod io;
 pub mod hash;
 pub mod container;
-
+pub mod default;
 
 /* Common data structures */
 
index 610ca93494c9971f0e91b9ee2d44d6b598ac9bca..9ca6e8ad0899238bd568bc07d8e00faab7c71b60 100644 (file)
 use container::{Container, Mutable};
 use iter::Times;
 use iterator::{Iterator, FromIterator, Extendable};
-use iterator::{Filter, AdditiveIterator, Map, Enumerate};
+use iterator::{Filter, AdditiveIterator, Map};
 use iterator::{Invert, DoubleEndedIterator};
 use libc;
-use num::{Saturating, Zero};
+use num::{Saturating};
 use option::{None, Option, Some};
 use ptr;
 use ptr::RawPtr;
@@ -35,6 +35,7 @@
 use unstable::raw::{Repr, Slice};
 use vec;
 use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
+use default::Default;
 
 /*
 Section: Conditions
 pub fn from_bytes(vv: &[u8]) -> ~str {
     use str::not_utf8::cond;
 
-    if !is_utf8(vv) {
-        let first_bad_byte = *vv.iter().find(|&b| !is_utf8([*b])).unwrap();
-        cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u",
-                        first_bad_byte as uint))
+    match from_bytes_opt(vv) {
+        None => {
+            let first_bad_byte = *vv.iter().find(|&b| !is_utf8([*b])).unwrap();
+            cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u",
+                            first_bad_byte as uint))
+        }
+        Some(s) => s
+    }
+}
+
+/// Convert a vector of bytes to a new UTF-8 string, if possible.
+/// Returns None if the vector contains invalid UTF-8.
+pub fn from_bytes_opt(vv: &[u8]) -> Option<~str> {
+    if is_utf8(vv) {
+        Some(unsafe { raw::from_bytes(vv) })
     } else {
-        return unsafe { raw::from_bytes(vv) }
+        None
     }
 }
 
@@ -78,7 +90,17 @@ pub fn from_bytes_owned(vv: ~[u8]) -> ~str {
         cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u",
                         first_bad_byte as uint))
     } else {
-        return unsafe { raw::from_bytes_owned(vv) }
+        unsafe { raw::from_bytes_owned(vv) }
+    }
+}
+
+/// Consumes a vector of bytes to create a new utf-8 string.
+/// Returns None if the vector contains invalid UTF-8.
+pub fn from_bytes_owned_opt(vv: ~[u8]) -> Option<~str> {
+    if is_utf8(vv) {
+        Some(unsafe { raw::from_bytes_owned(vv) })
+    } else {
+        None
     }
 }
 
@@ -91,8 +113,16 @@ pub fn from_bytes_owned(vv: ~[u8]) -> ~str {
 ///
 /// Fails if invalid UTF-8
 pub fn from_bytes_slice<'a>(v: &'a [u8]) -> &'a str {
-    assert!(is_utf8(v));
-    unsafe { cast::transmute(v) }
+    from_bytes_slice_opt(v).expect("from_bytes_slice: not utf-8")
+}
+
+/// Converts a vector to a string slice without performing any allocations.
+///
+/// Returns None if the slice is not utf-8.
+pub fn from_bytes_slice_opt<'a>(v: &'a [u8]) -> Option<&'a str> {
+    if is_utf8(v) {
+        Some(unsafe { cast::transmute(v) })
+    } else { None }
 }
 
 impl ToStr for ~str {
@@ -359,28 +389,32 @@ fn next_back(&mut self) -> Option<(uint, char)> {
 /// Use with the `std::iterator` module.
 pub type ByteRevIterator<'self> = Invert<ByteIterator<'self>>;
 
-/// An iterator over byte index and either &u8 or char
-#[deriving(Clone)]
-enum OffsetIterator<'self> {
-    // use ByteIterator here when it can be cloned
-    ByteOffset(Enumerate<vec::VecIterator<'self, u8>>),
-    CharOffset(CharOffsetIterator<'self>),
-}
-
 /// An iterator over the substrings of a string, separated by `sep`.
 #[deriving(Clone)]
-pub struct CharSplitIterator<'self,Sep> {
-    priv iter: OffsetIterator<'self>,
+pub struct CharSplitIterator<'self, Sep> {
+    /// The slice remaining to be iterated
     priv string: &'self str,
-    priv position: uint,
     priv sep: Sep,
-    /// The number of splits remaining
-    priv count: uint,
     /// Whether an empty string at the end is allowed
     priv allow_trailing_empty: bool,
+    priv only_ascii: bool,
     priv finished: bool,
 }
 
+/// An iterator over the substrings of a string, separated by `sep`,
+/// starting from the back of the string.
+pub type CharRSplitIterator<'self, Sep> = Invert<CharSplitIterator<'self, Sep>>;
+
+/// An iterator over the substrings of a string, separated by `sep`,
+/// splitting at most `count` times.
+#[deriving(Clone)]
+pub struct CharSplitNIterator<'self, Sep> {
+    priv iter: CharSplitIterator<'self, Sep>,
+    /// The number of splits remaining
+    priv count: uint,
+    priv invert: bool,
+}
+
 /// An iterator over the words of a string, separated by an sequence of whitespace
 pub type WordIterator<'self> =
     Filter<'self, &'self str, CharSplitIterator<'self, extern "Rust" fn(char) -> bool>>;
@@ -389,46 +423,101 @@ pub struct CharSplitIterator<'self,Sep> {
 pub type AnyLineIterator<'self> =
     Map<'self, &'self str, &'self str, CharSplitIterator<'self, char>>;
 
+impl<'self, Sep> CharSplitIterator<'self, Sep> {
+    #[inline]
+    fn get_end(&mut self) -> Option<&'self str> {
+        if !self.finished && (self.allow_trailing_empty || self.string.len() > 0) {
+            self.finished = true;
+            Some(self.string)
+        } else {
+            None
+        }
+    }
+}
+
 impl<'self, Sep: CharEq> Iterator<&'self str> for CharSplitIterator<'self, Sep> {
     #[inline]
     fn next(&mut self) -> Option<&'self str> {
         if self.finished { return None }
 
-        let start = self.position;
-        let len = self.string.len();
+        let mut next_split = None;
+        if self.only_ascii {
+            for (idx, byte) in self.string.byte_iter().enumerate() {
+                if self.sep.matches(byte as char) && byte < 128u8 {
+                    next_split = Some((idx, idx + 1));
+                    break;
+                }
+            }
+        } else {
+            for (idx, ch) in self.string.char_offset_iter() {
+                if self.sep.matches(ch) {
+                    next_split = Some((idx, self.string.char_range_at(idx).next));
+                    break;
+                }
+            }
+        }
+        match next_split {
+            Some((a, b)) => unsafe {
+                let elt = raw::slice_unchecked(self.string, 0, a);
+                self.string = raw::slice_unchecked(self.string, b, self.string.len());
+                Some(elt)
+            },
+            None => self.get_end(),
+        }
+    }
+}
 
-        if self.count > 0 {
-            match self.iter {
-                // this gives a *huge* speed up for splitting on ASCII
-                // characters (e.g. '\n' or ' ')
-                ByteOffset(ref mut iter) =>
-                    for (idx, &byte) in *iter {
-                        if self.sep.matches(byte as char) {
-                            self.position = idx + 1;
-                            self.count -= 1;
-                            return Some(unsafe {
-                                raw::slice_bytes(self.string, start, idx)
-                            })
-                        }
-                    },
-                CharOffset(ref mut iter) =>
-                    for (idx, ch) in *iter {
-                        if self.sep.matches(ch) {
-                            // skip over the separator
-                            self.position = self.string.char_range_at(idx).next;
-                            self.count -= 1;
-                            return Some(unsafe {
-                                raw::slice_bytes(self.string, start, idx)
-                            })
-                        }
-                    },
+impl<'self, Sep: CharEq> DoubleEndedIterator<&'self str>
+for CharSplitIterator<'self, Sep> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'self str> {
+        if self.finished { return None }
+
+        if !self.allow_trailing_empty {
+            self.allow_trailing_empty = true;
+            match self.next_back() {
+                Some(elt) if !elt.is_empty() => return Some(elt),
+                _ => if self.finished { return None }
+            }
+        }
+        let len = self.string.len();
+        let mut next_split = None;
+
+        if self.only_ascii {
+            for (j, byte) in self.string.byte_rev_iter().enumerate() {
+                if self.sep.matches(byte as char) && byte < 128u8 {
+                    let idx = len - j - 1;
+                    next_split = Some((idx, idx + 1));
+                    break;
+                }
+            }
+        } else {
+            for (idx, ch) in self.string.char_offset_rev_iter() {
+                if self.sep.matches(ch) {
+                    next_split = Some((idx, self.string.char_range_at(idx).next));
+                    break;
+                }
             }
         }
-        self.finished = true;
-        if self.allow_trailing_empty || start < len {
-            Some(unsafe { raw::slice_bytes(self.string, start, len) })
+        match next_split {
+            Some((a, b)) => unsafe {
+                let elt = raw::slice_unchecked(self.string, b, len);
+                self.string = raw::slice_unchecked(self.string, 0, a);
+                Some(elt)
+            },
+            None => { self.finished = true; Some(self.string) }
+        }
+    }
+}
+
+impl<'self, Sep: CharEq> Iterator<&'self str> for CharSplitNIterator<'self, Sep> {
+    #[inline]
+    fn next(&mut self) -> Option<&'self str> {
+        if self.count != 0 {
+            self.count -= 1;
+            if self.invert { self.iter.next_back() } else { self.iter.next() }
         } else {
-            None
+            self.iter.get_end()
         }
     }
 }
@@ -1003,7 +1092,7 @@ pub unsafe fn slice_bytes<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
     pub unsafe fn slice_unchecked<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
         do s.as_imm_buf |sbuf, _n| {
              cast::transmute(Slice {
-                 data: sbuf.offset_inbounds(begin as int),
+                 data: sbuf.offset(begin as int),
                  len: end - begin,
              })
         }
@@ -1271,9 +1360,10 @@ pub trait StrSlice<'self> {
     fn char_offset_iter(&self) -> CharOffsetIterator<'self>;
     fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self>;
     fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
-    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitIterator<'self, Sep>;
-    fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool)
-        -> CharSplitIterator<'self, Sep>;
+    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
+    fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
+    fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep>;
+    fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
     fn matches_index_iter(&self, sep: &'self str) -> MatchesIndexIterator<'self>;
     fn split_str_iter(&self, &'self str) -> StrSplitIterator<'self>;
     fn line_iter(&self) -> CharSplitIterator<'self, char>;
@@ -1410,40 +1500,78 @@ fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self> {
     /// ~~~
     #[inline]
     fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep> {
-        self.split_options_iter(sep, self.len(), true)
+        CharSplitIterator {
+            string: *self,
+            only_ascii: sep.only_ascii(),
+            sep: sep,
+            allow_trailing_empty: true,
+            finished: false,
+        }
     }
 
     /// An iterator over substrings of `self`, separated by characters
     /// matched by `sep`, restricted to splitting at most `count`
     /// times.
     #[inline]
-    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitIterator<'self, Sep> {
-        self.split_options_iter(sep, count, true)
+    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
+        -> CharSplitNIterator<'self, Sep> {
+        CharSplitNIterator {
+            iter: self.split_iter(sep),
+            count: count,
+            invert: false,
+        }
     }
 
     /// An iterator over substrings of `self`, separated by characters
-    /// matched by `sep`, splitting at most `count` times, and
-    /// possibly not including the trailing empty substring, if it
-    /// exists.
+    /// matched by `sep`.
+    ///
+    /// Equivalent to `split_iter`, except that the trailing substring
+    /// is skipped if empty (terminator semantics).
+    ///
+    /// # Example
+    ///
+    /// ~~~ {.rust}
+    /// let v: ~[&str] = "A.B.".split_terminator_iter('.').collect();
+    /// assert_eq!(v, ~["A", "B"]);
+    /// ~~~
     #[inline]
-    fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool)
+    fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep)
         -> CharSplitIterator<'self, Sep> {
-        let iter = if sep.only_ascii() {
-            ByteOffset(self.as_bytes().iter().enumerate())
-        } else {
-            CharOffset(self.char_offset_iter())
-        };
         CharSplitIterator {
-            iter: iter,
-            string: *self,
-            position: 0,
-            sep: sep,
+            allow_trailing_empty: false,
+            ..self.split_iter(sep)
+        }
+    }
+
+    /// An iterator over substrings of `self`, separated by characters
+    /// matched by `sep`, in reverse order
+    ///
+    /// # Example
+    ///
+    /// ~~~ {.rust}
+    /// let v: ~[&str] = "Mary had a little lamb".rsplit_iter(' ').collect();
+    /// assert_eq!(v, ~["lamb", "little", "a", "had", "Mary"]);
+    /// ~~~
+    #[inline]
+    fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep> {
+        self.split_iter(sep).invert()
+    }
+
+    /// An iterator over substrings of `self`, separated by characters
+    /// matched by `sep`, starting from the end of the string.
+    /// Restricted to splitting at most `count` times.
+    #[inline]
+    fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
+        -> CharSplitNIterator<'self, Sep> {
+        CharSplitNIterator {
+            iter: self.split_iter(sep),
             count: count,
-            allow_trailing_empty: allow_trailing_empty,
-            finished: false,
+            invert: true,
         }
     }
 
+
+
     /// An iterator over the start and end indices of each match of
     /// `sep` within `self`.
     #[inline]
@@ -1477,7 +1605,7 @@ fn split_str_iter(&self, sep: &'self str) -> StrSplitIterator<'self> {
     /// by `\n`).
     #[inline]
     fn line_iter(&self) -> CharSplitIterator<'self, char> {
-        self.split_options_iter('\n', self.len(), false)
+        self.split_terminator_iter('\n')
     }
 
     /// An iterator over the lines of a string, separated by either
@@ -2107,6 +2235,8 @@ pub trait OwnedStr {
     fn reserve(&mut self, n: uint);
     fn reserve_at_least(&mut self, n: uint);
     fn capacity(&self) -> uint;
+    fn truncate(&mut self, len: uint);
+    fn into_bytes(self) -> ~[u8];
 
     /// Work with the mutable byte buffer and length of a slice.
     ///
@@ -2264,6 +2394,22 @@ fn capacity(&self) -> uint {
         }
     }
 
+    /// Shorten a string to the specified length (which must be <= the current length)
+    #[inline]
+    fn truncate(&mut self, len: uint) {
+        assert!(len <= self.len());
+        assert!(self.is_char_boundary(len));
+        unsafe { raw::set_len(self, len); }
+    }
+
+    /// Consumes the string, returning the underlying byte buffer.
+    ///
+    /// The buffer does not have a null terminator.
+    #[inline]
+    fn into_bytes(self) -> ~[u8] {
+        unsafe { cast::transmute(self) }
+    }
+
     #[inline]
     fn as_mut_buf<T>(&mut self, f: &fn(*mut u8, uint) -> T) -> T {
         let v: &mut ~[u8] = unsafe { cast::transmute(self) };
@@ -2322,31 +2468,28 @@ fn extend<T: Iterator<char>>(&mut self, iterator: &mut T) {
 }
 
 // This works because every lifetime is a sub-lifetime of 'static
-impl<'self> Zero for &'self str {
-    fn zero() -> &'self str { "" }
-    fn is_zero(&self) -> bool { self.is_empty() }
+impl<'self> Default for &'self str {
+    fn default() -> &'self str { "" }
 }
 
-impl Zero for ~str {
-    fn zero() -> ~str { ~"" }
-    fn is_zero(&self) -> bool { self.len() == 0 }
+impl Default for ~str {
+    fn default() -> ~str { ~"" }
 }
 
-impl Zero for @str {
-    fn zero() -> @str { @"" }
-    fn is_zero(&self) -> bool { self.len() == 0 }
+impl Default for @str {
+    fn default() -> @str { @"" }
 }
 
 #[cfg(test)]
 mod tests {
     use container::Container;
-    use option::Some;
+    use option::{None, Some};
     use libc::c_char;
     use libc;
     use ptr;
     use str::*;
     use vec;
-    use vec::{ImmutableVector, CopyableVector};
+    use vec::{Vector, ImmutableVector, CopyableVector};
     use cmp::{TotalOrd, Less, Equal, Greater};
 
     #[test]
@@ -2514,6 +2657,13 @@ fn test_clear() {
         assert_eq!("华", data.as_slice());
     }
 
+    #[test]
+    fn test_into_bytes() {
+        let data = ~"asdf";
+        let buf = data.into_bytes();
+        assert_eq!(bytes!("asdf"), buf.as_slice());
+    }
+
     #[test]
     fn test_find_str() {
         // byte positions
@@ -3346,17 +3496,33 @@ fn test_split_char_iterator() {
         let data = "\nMäry häd ä little lämb\nLittle lämb\n";
 
         let split: ~[&str] = data.split_iter(' ').collect();
-        assert_eq!(split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+        assert_eq!( split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+        let mut rsplit: ~[&str] = data.rsplit_iter(' ').collect();
+        rsplit.reverse();
+        assert_eq!(rsplit, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
 
         let split: ~[&str] = data.split_iter(|c: char| c == ' ').collect();
-        assert_eq!(split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+        assert_eq!( split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+        let mut rsplit: ~[&str] = data.rsplit_iter(|c: char| c == ' ').collect();
+        rsplit.reverse();
+        assert_eq!(rsplit, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
 
         // Unicode
         let split: ~[&str] = data.split_iter('ä').collect();
-        assert_eq!(split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+        assert_eq!( split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+
+        let mut rsplit: ~[&str] = data.rsplit_iter('ä').collect();
+        rsplit.reverse();
+        assert_eq!(rsplit, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
 
         let split: ~[&str] = data.split_iter(|c: char| c == 'ä').collect();
-        assert_eq!(split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+        assert_eq!( split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+
+        let mut rsplit: ~[&str] = data.rsplit_iter(|c: char| c == 'ä').collect();
+        rsplit.reverse();
+        assert_eq!(rsplit, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
     }
 
     #[test]
@@ -3377,14 +3543,49 @@ fn test_splitn_char_iterator() {
         assert_eq!(split, ~["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
     }
 
+    #[test]
+    fn test_rsplitn_char_iterator() {
+        let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+        let mut split: ~[&str] = data.rsplitn_iter(' ', 3).collect();
+        split.reverse();
+        assert_eq!(split, ~["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+
+        let mut split: ~[&str] = data.rsplitn_iter(|c: char| c == ' ', 3).collect();
+        split.reverse();
+        assert_eq!(split, ~["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+
+        // Unicode
+        let mut split: ~[&str] = data.rsplitn_iter('ä', 3).collect();
+        split.reverse();
+        assert_eq!(split, ~["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+
+        let mut split: ~[&str] = data.rsplitn_iter(|c: char| c == 'ä', 3).collect();
+        split.reverse();
+        assert_eq!(split, ~["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+    }
+
     #[test]
     fn test_split_char_iterator_no_trailing() {
         let data = "\nMäry häd ä little lämb\nLittle lämb\n";
 
-        let split: ~[&str] = data.split_options_iter('\n', 1000, true).collect();
+        let split: ~[&str] = data.split_iter('\n').collect();
+        assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb", ""]);
+
+        let split: ~[&str] = data.split_terminator_iter('\n').collect();
+        assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb"]);
+    }
+
+    #[test]
+    fn test_rev_split_char_iterator_no_trailing() {
+        let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+        let mut split: ~[&str] = data.split_iter('\n').invert().collect();
+        split.reverse();
         assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb", ""]);
 
-        let split: ~[&str] = data.split_options_iter('\n', 1000, false).collect();
+        let mut split: ~[&str] = data.split_terminator_iter('\n').invert().collect();
+        split.reverse();
         assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb"]);
     }
 
@@ -3457,12 +3658,11 @@ fn t<'a>(s: &str, sep: &'a str, u: ~[&str]) {
     }
 
     #[test]
-    fn test_str_zero() {
-        use num::Zero;
-        fn t<S: Zero + Str>() {
-            let s: S = Zero::zero();
+    fn test_str_default() {
+        use default::Default;
+        fn t<S: Default + Str>() {
+            let s: S = Default::default();
             assert_eq!(s.as_slice(), "");
-            assert!(s.is_zero());
         }
 
         t::<&str>();
@@ -3482,6 +3682,108 @@ fn sum_len<S: Container>(v: &[S]) -> uint {
         assert_eq!(5, sum_len([~"01", ~"2", ~"34", ~""]));
         assert_eq!(5, sum_len([s.as_slice()]));
     }
+
+    #[test]
+    fn test_str_truncate() {
+        let mut s = ~"12345";
+        s.truncate(5);
+        assert_eq!(s.as_slice(), "12345");
+        s.truncate(3);
+        assert_eq!(s.as_slice(), "123");
+        s.truncate(0);
+        assert_eq!(s.as_slice(), "");
+
+        let mut s = ~"12345";
+        let p = s.as_imm_buf(|p,_| p);
+        s.truncate(3);
+        s.push_str("6");
+        let p_ = s.as_imm_buf(|p,_| p);
+        assert_eq!(p_, p);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_str_truncate_invalid_len() {
+        let mut s = ~"12345";
+        s.truncate(6);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_str_truncate_split_codepoint() {
+        let mut s = ~"\u00FC"; // ü
+        s.truncate(1);
+    }
+
+    #[test]
+    fn test_str_from_bytes_slice() {
+        let xs = bytes!("hello");
+        assert_eq!(from_bytes_slice(xs), "hello");
+
+        let xs = bytes!("ศไทย中华Việt Nam");
+        assert_eq!(from_bytes_slice(xs), "ศไทย中华Việt Nam");
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_str_from_bytes_slice_invalid() {
+        let xs = bytes!("hello", 0xff);
+        let _ = from_bytes_slice(xs);
+    }
+
+    #[test]
+    fn test_str_from_bytes_slice_opt() {
+        let xs = bytes!("hello");
+        assert_eq!(from_bytes_slice_opt(xs), Some("hello"));
+
+        let xs = bytes!("ศไทย中华Việt Nam");
+        assert_eq!(from_bytes_slice_opt(xs), Some("ศไทย中华Việt Nam"));
+
+        let xs = bytes!("hello", 0xff);
+        assert_eq!(from_bytes_slice_opt(xs), None);
+    }
+
+    #[test]
+    fn test_str_from_bytes() {
+        let xs = bytes!("hello");
+        assert_eq!(from_bytes(xs), ~"hello");
+
+        let xs = bytes!("ศไทย中华Việt Nam");
+        assert_eq!(from_bytes(xs), ~"ศไทย中华Việt Nam");
+    }
+
+    #[test]
+    fn test_str_from_bytes_opt() {
+        let xs = bytes!("hello").to_owned();
+        assert_eq!(from_bytes_opt(xs), Some(~"hello"));
+
+        let xs = bytes!("ศไทย中华Việt Nam");
+        assert_eq!(from_bytes_opt(xs), Some(~"ศไทย中华Việt Nam"));
+
+        let xs = bytes!("hello", 0xff);
+        assert_eq!(from_bytes_opt(xs), None);
+    }
+
+    #[test]
+    fn test_str_from_bytes_owned() {
+        let xs = bytes!("hello").to_owned();
+        assert_eq!(from_bytes_owned(xs), ~"hello");
+
+        let xs = bytes!("ศไทย中华Việt Nam").to_owned();
+        assert_eq!(from_bytes_owned(xs), ~"ศไทย中华Việt Nam");
+    }
+
+    #[test]
+    fn test_str_from_bytes_owned_opt() {
+        let xs = bytes!("hello").to_owned();
+        assert_eq!(from_bytes_owned_opt(xs), Some(~"hello"));
+
+        let xs = bytes!("ศไทย中华Việt Nam").to_owned();
+        assert_eq!(from_bytes_owned_opt(xs), Some(~"ศไทย中华Việt Nam"));
+
+        let xs = bytes!("hello", 0xff).to_owned();
+        assert_eq!(from_bytes_owned_opt(xs), None);
+    }
 }
 
 #[cfg(test)]
@@ -3545,6 +3847,89 @@ fn char_offset_iterator_rev(bh: &mut BenchHarness) {
         }
     }
 
+    #[bench]
+    fn split_iter_unicode_ascii(bh: &mut BenchHarness) {
+        let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
+
+        do bh.iter {
+            assert_eq!(s.split_iter('V').len(), 3);
+        }
+    }
+
+    #[bench]
+    fn split_iter_unicode_not_ascii(bh: &mut BenchHarness) {
+        struct NotAscii(char);
+        impl CharEq for NotAscii {
+            fn matches(&self, c: char) -> bool {
+                **self == c
+            }
+            fn only_ascii(&self) -> bool { false }
+        }
+        let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
+
+        do bh.iter {
+            assert_eq!(s.split_iter(NotAscii('V')).len(), 3);
+        }
+    }
+
+
+    #[bench]
+    fn split_iter_ascii(bh: &mut BenchHarness) {
+        let s = "Mary had a little lamb, Little lamb, little-lamb.";
+        let len = s.split_iter(' ').len();
+
+        do bh.iter {
+            assert_eq!(s.split_iter(' ').len(), len);
+        }
+    }
+
+    #[bench]
+    fn split_iter_not_ascii(bh: &mut BenchHarness) {
+        struct NotAscii(char);
+        impl CharEq for NotAscii {
+            #[inline]
+            fn matches(&self, c: char) -> bool { **self == c }
+            fn only_ascii(&self) -> bool { false }
+        }
+        let s = "Mary had a little lamb, Little lamb, little-lamb.";
+        let len = s.split_iter(' ').len();
+
+        do bh.iter {
+            assert_eq!(s.split_iter(NotAscii(' ')).len(), len);
+        }
+    }
+
+    #[bench]
+    fn split_iter_extern_fn(bh: &mut BenchHarness) {
+        let s = "Mary had a little lamb, Little lamb, little-lamb.";
+        let len = s.split_iter(' ').len();
+        fn pred(c: char) -> bool { c == ' ' }
+
+        do bh.iter {
+            assert_eq!(s.split_iter(pred).len(), len);
+        }
+    }
+
+    #[bench]
+    fn split_iter_closure(bh: &mut BenchHarness) {
+        let s = "Mary had a little lamb, Little lamb, little-lamb.";
+        let len = s.split_iter(' ').len();
+
+        do bh.iter {
+            assert_eq!(s.split_iter(|c: char| c == ' ').len(), len);
+        }
+    }
+
+    #[bench]
+    fn split_iter_slice(bh: &mut BenchHarness) {
+        let s = "Mary had a little lamb, Little lamb, little-lamb.";
+        let len = s.split_iter(' ').len();
+
+        do bh.iter {
+            assert_eq!(s.split_iter(&[' ']).len(), len);
+        }
+    }
+
     #[bench]
     fn is_utf8_100_ascii(bh: &mut BenchHarness) {
 
index bfb9bee78028c3d59755739f3021f64194d0c427..cb0753fb2e5dee4a45ea3a8d8bbbf871a3857a83 100644 (file)
@@ -143,7 +143,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
         if in_green_task_context() {
             // XXX: Logging doesn't work here - the check to call the log
             // function never passes - so calling the log function directly.
-            do Local::borrow::<Task, ()> |task| {
+            do Local::borrow |task: &mut Task| {
                 let msg = match task.name {
                     Some(ref name) =>
                     fmt!("task '%s' failed at '%s', %s:%i",
@@ -160,7 +160,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
                      msg, file, line as int);
         }
 
-        let task = Local::unsafe_borrow::<Task>();
+        let task: *mut Task = Local::unsafe_borrow();
         if (*task).unwinder.unwinding {
             rtabort!("unwinding again");
         }
diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs
deleted file mode 100644 (file)
index 8132bfe..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[allow(missing_doc)];
-
-use cast;
-use libc;
-use local_data;
-use prelude::*;
-use ptr;
-use unstable::raw;
-use util;
-
-use rt::task::{Task, LocalStorage};
-
-pub enum Handle {
-    NewHandle(*mut LocalStorage)
-}
-
-impl Handle {
-    pub fn new() -> Handle {
-        use rt::local::Local;
-        unsafe {
-            let task = Local::unsafe_borrow::<Task>();
-            NewHandle(&mut (*task).storage)
-        }
-    }
-}
-
-#[deriving(Eq)]
-enum LoanState {
-    NoLoan, ImmLoan, MutLoan
-}
-
-impl LoanState {
-    fn describe(&self) -> &'static str {
-        match *self {
-            NoLoan => "no loan",
-            ImmLoan => "immutable",
-            MutLoan => "mutable"
-        }
-    }
-}
-
-trait LocalData {}
-impl<T: 'static> LocalData for T {}
-
-// The task-local-map stores all TLS information for the currently running task.
-// It is stored as an owned pointer into the runtime, and it's only allocated
-// when TLS is used for the first time. This map must be very carefully
-// constructed because it has many mutable loans unsoundly handed out on it to
-// the various invocations of TLS requests.
-//
-// One of the most important operations is loaning a value via `get` to a
-// caller. In doing so, the slot that the TLS entry is occupying cannot be
-// invalidated because upon returning it's loan state must be updated. Currently
-// the TLS map is a vector, but this is possibly dangerous because the vector
-// can be reallocated/moved when new values are pushed onto it.
-//
-// This problem currently isn't solved in a very elegant way. Inside the `get`
-// function, it internally "invalidates" all references after the loan is
-// finished and looks up into the vector again. In theory this will prevent
-// pointers from being moved under our feet so long as LLVM doesn't go too crazy
-// with the optimizations.
-//
-// n.b. Other structures are not sufficient right now:
-//          * HashMap uses ~[T] internally (push reallocates/moves)
-//          * TreeMap is plausible, but it's in extra
-//          * dlist plausible, but not in std
-//          * a custom owned linked list was attempted, but difficult to write
-//            and involved a lot of extra code bloat
-//
-// n.b. Has to be stored with a pointer at outermost layer; the foreign call
-//      returns void *.
-//
-// n.b. If TLS is used heavily in future, this could be made more efficient with
-//      a proper map.
-type TaskLocalMap = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
-type TLSValue = ~LocalData:;
-
-fn cleanup_task_local_map(map_ptr: *libc::c_void) {
-    unsafe {
-        assert!(!map_ptr.is_null());
-        // Get and keep the single reference that was created at the
-        // beginning.
-        let _map: TaskLocalMap = cast::transmute(map_ptr);
-        // All local_data will be destroyed along with the map.
-    }
-}
-
-// Gets the map from the runtime. Lazily initialises if not done so already.
-unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
-
-    unsafe fn newsched_map(local: *mut LocalStorage) -> &mut TaskLocalMap {
-        // This is based on the same idea as the oldsched code above.
-        match &mut *local {
-            // If the at_exit function is already set, then we just need to take
-            // a loan out on the TLS map stored inside
-            &LocalStorage(ref mut map_ptr, Some(_)) => {
-                assert!(map_ptr.is_not_null());
-                return cast::transmute(map_ptr);
-            }
-            // If this is the first time we've accessed TLS, perform similar
-            // actions to the oldsched way of doing things.
-            &LocalStorage(ref mut map_ptr, ref mut at_exit) => {
-                assert!(map_ptr.is_null());
-                assert!(at_exit.is_none());
-                let map: TaskLocalMap = ~[];
-                *map_ptr = cast::transmute(map);
-                *at_exit = Some(cleanup_task_local_map);
-                return cast::transmute(map_ptr);
-            }
-        }
-    }
-
-    match handle {
-        NewHandle(local_storage) => newsched_map(local_storage)
-    }
-}
-
-unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
-    let pair: raw::Closure = cast::transmute_copy(&key);
-    return pair.code as *libc::c_void;
-}
-
-pub unsafe fn local_pop<T: 'static>(handle: Handle,
-                                    key: local_data::Key<T>) -> Option<T> {
-    let map = get_local_map(handle);
-    let key_value = key_to_key_value(key);
-
-    for entry in map.mut_iter() {
-        match *entry {
-            Some((k, _, loan)) if k == key_value => {
-                if loan != NoLoan {
-                    fail!("TLS value cannot be removed because it is already \
-                          borrowed as %s", loan.describe());
-                }
-                // Move the data out of the `entry` slot via util::replace. This
-                // is guaranteed to succeed because we already matched on `Some`
-                // above.
-                let data = match util::replace(entry, None) {
-                    Some((_, data, _)) => data,
-                    None => abort(),
-                };
-
-                // Move `data` into transmute to get out the memory that it
-                // owns, we must free it manually later.
-                let (_vtable, box): (uint, ~~T) = cast::transmute(data);
-
-                // Read the box's value (using the compiler's built-in
-                // auto-deref functionality to obtain a pointer to the base)
-                let ret = ptr::read_ptr(cast::transmute::<&T, *mut T>(*box));
-
-                // Finally free the allocated memory. we don't want this to
-                // actually touch the memory inside because it's all duplicated
-                // now, so the box is transmuted to a 0-sized type. We also use
-                // a type which references `T` because currently the layout
-                // could depend on whether T contains managed pointers or not.
-                let _: ~~[T, ..0] = cast::transmute(box);
-
-                // Everything is now deallocated, and we own the value that was
-                // located inside TLS, so we now return it.
-                return Some(ret);
-            }
-            _ => {}
-        }
-    }
-    return None;
-}
-
-pub unsafe fn local_get<T: 'static, U>(handle: Handle,
-                                       key: local_data::Key<T>,
-                                       f: &fn(Option<&T>) -> U) -> U {
-    local_get_with(handle, key, ImmLoan, f)
-}
-
-pub unsafe fn local_get_mut<T: 'static, U>(handle: Handle,
-                                           key: local_data::Key<T>,
-                                           f: &fn(Option<&mut T>) -> U) -> U {
-    do local_get_with(handle, key, MutLoan) |x| {
-        match x {
-            None => f(None),
-            // We're violating a lot of compiler guarantees with this
-            // invocation of `transmute_mut`, but we're doing runtime checks to
-            // ensure that it's always valid (only one at a time).
-            //
-            // there is no need to be upset!
-            Some(x) => { f(Some(cast::transmute_mut(x))) }
-        }
-    }
-}
-
-unsafe fn local_get_with<T: 'static, U>(handle: Handle,
-                                        key: local_data::Key<T>,
-                                        state: LoanState,
-                                        f: &fn(Option<&T>) -> U) -> U {
-    // This function must be extremely careful. Because TLS can store owned
-    // values, and we must have some form of `get` function other than `pop`,
-    // this function has to give a `&` reference back to the caller.
-    //
-    // One option is to return the reference, but this cannot be sound because
-    // the actual lifetime of the object is not known. The slot in TLS could not
-    // be modified until the object goes out of scope, but the TLS code cannot
-    // know when this happens.
-    //
-    // For this reason, the reference is yielded to a specified closure. This
-    // way the TLS code knows exactly what the lifetime of the yielded pointer
-    // is, allowing callers to acquire references to owned data. This is also
-    // sound so long as measures are taken to ensure that while a TLS slot is
-    // loaned out to a caller, it's not modified recursively.
-    let map = get_local_map(handle);
-    let key_value = key_to_key_value(key);
-
-    let pos = map.iter().position(|entry| {
-        match *entry {
-            Some((k, _, _)) if k == key_value => true, _ => false
-        }
-    });
-    match pos {
-        None => { return f(None); }
-        Some(i) => {
-            let ret;
-            let mut return_loan = false;
-            match map[i] {
-                Some((_, ref data, ref mut loan)) => {
-                    match (state, *loan) {
-                        (_, NoLoan) => {
-                            *loan = state;
-                            return_loan = true;
-                        }
-                        (ImmLoan, ImmLoan) => {}
-                        (want, cur) => {
-                            fail!("TLS slot cannot be borrowed as %s because \
-                                   it is already borrowed as %s",
-                                  want.describe(), cur.describe());
-                        }
-                    }
-                    // data was created with `~~T as ~LocalData`, so we extract
-                    // pointer part of the trait, (as ~~T), and then use
-                    // compiler coercions to achieve a '&' pointer.
-                    match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data) {
-                        (_vtable, ref box) => {
-                            let value: &T = **box;
-                            ret = f(Some(value));
-                        }
-                    }
-                }
-                _ => abort()
-            }
-
-            // n.b. 'data' and 'loans' are both invalid pointers at the point
-            // 'f' returned because `f` could have appended more TLS items which
-            // in turn relocated the vector. Hence we do another lookup here to
-            // fixup the loans.
-            if return_loan {
-                match map[i] {
-                    Some((_, _, ref mut loan)) => { *loan = NoLoan; }
-                    None => { abort(); }
-                }
-            }
-            return ret;
-        }
-    }
-}
-
-fn abort() -> ! {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    unsafe { libc::abort() }
-}
-
-pub unsafe fn local_set<T: 'static>(handle: Handle,
-                                    key: local_data::Key<T>,
-                                    data: T) {
-    let map = get_local_map(handle);
-    let keyval = key_to_key_value(key);
-
-    // When the task-local map is destroyed, all the data needs to be cleaned
-    // up. For this reason we can't do some clever tricks to store '~T' as a
-    // '*c_void' or something like that. To solve the problem, we cast
-    // everything to a trait (LocalData) which is then stored inside the map.
-    // Upon destruction of the map, all the objects will be destroyed and the
-    // traits have enough information about them to destroy themselves.
-    //
-    // FIXME(#7673): This should be "~data as ~LocalData" (without the colon at
-    //               the end, and only one sigil)
-    let data = ~~data as ~LocalData:;
-
-    fn insertion_position(map: &mut TaskLocalMap,
-                          key: *libc::c_void) -> Option<uint> {
-        // First see if the map contains this key already
-        let curspot = map.iter().position(|entry| {
-            match *entry {
-                Some((ekey, _, loan)) if key == ekey => {
-                    if loan != NoLoan {
-                        fail!("TLS value cannot be overwritten because it is
-                               already borrowed as %s", loan.describe())
-                    }
-                    true
-                }
-                _ => false,
-            }
-        });
-        // If it doesn't contain the key, just find a slot that's None
-        match curspot {
-            Some(i) => Some(i),
-            None => map.iter().position(|entry| entry.is_none())
-        }
-    }
-
-    match insertion_position(map, keyval) {
-        Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
-        None => { map.push(Some((keyval, data, NoLoan))); }
-    }
-}
index e76b81a904df24efbb82b38db50d2f91847c8ee7..b52dd3a906bd687811f8a829f8386d26d5dda037 100644 (file)
@@ -52,7 +52,6 @@
 #[cfg(test)] use ptr;
 #[cfg(test)] use task;
 
-mod local_data_priv;
 pub mod spawn;
 
 /**
@@ -526,7 +525,7 @@ pub fn with_task_name<U>(blk: &fn(Option<&str>) -> U) -> U {
     use rt::task::Task;
 
     if in_green_task_context() {
-        do Local::borrow::<Task, U> |task| {
+        do Local::borrow |task: &mut Task| {
             match task.name {
                 Some(ref name) => blk(Some(name.as_slice())),
                 None => blk(None)
@@ -545,7 +544,7 @@ pub fn deschedule() {
 
     // FIXME #6842: What does yield really mean in newsched?
     // FIXME(#7544): Optimize this, since we know we won't block.
-    let sched = Local::take::<Scheduler>();
+    let sched: ~Scheduler = Local::take();
     do sched.deschedule_running_task_and_then |sched, task| {
         sched.enqueue_blocked_task(task);
     }
@@ -556,7 +555,7 @@ pub fn failing() -> bool {
 
     use rt::task::Task;
 
-    do Local::borrow::<Task, bool> |local| {
+    do Local::borrow |local: &mut Task| {
         local.unwinder.unwinding
     }
 }
@@ -582,7 +581,7 @@ pub fn unkillable<U>(f: &fn() -> U) -> U {
     unsafe {
         if in_green_task_context() {
             // The inhibits/allows might fail and need to borrow the task.
-            let t = Local::unsafe_borrow::<Task>();
+            let t: *mut Task = Local::unsafe_borrow();
             do (|| {
                 (*t).death.inhibit_kill((*t).unwinder.unwinding);
                 f()
@@ -597,21 +596,36 @@ pub fn unkillable<U>(f: &fn() -> U) -> U {
     }
 }
 
-/// The inverse of unkillable. Only ever to be used nested in unkillable().
-pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
+/**
+ * Makes killable a task marked as unkillable. This
+ * is meant to be used only nested in unkillable.
+ *
+ * # Example
+ *
+ * ~~~
+ * do task::unkillable {
+ *     do task::rekillable {
+ *          // Task is killable
+ *     }
+ *    // Task is unkillable again
+ * }
+ */
+pub fn rekillable<U>(f: &fn() -> U) -> U {
     use rt::task::Task;
 
-    if in_green_task_context() {
-        let t = Local::unsafe_borrow::<Task>();
-        do (|| {
-            (*t).death.allow_kill((*t).unwinder.unwinding);
+    unsafe {
+        if in_green_task_context() {
+            let t: *mut Task = Local::unsafe_borrow();
+            do (|| {
+                (*t).death.allow_kill((*t).unwinder.unwinding);
+                f()
+            }).finally {
+                (*t).death.inhibit_kill((*t).unwinder.unwinding);
+            }
+        } else {
+            // FIXME(#3095): As in unkillable().
             f()
-        }).finally {
-            (*t).death.inhibit_kill((*t).unwinder.unwinding);
         }
-    } else {
-        // FIXME(#3095): As in unkillable().
-        f()
     }
 }
 
@@ -636,8 +650,8 @@ fn test_kill_unkillable_task() {
     }
 }
 
-#[ignore(reason = "linked failure")]
 #[test]
+#[ignore(cfg(windows))]
 fn test_kill_rekillable_task() {
     use rt::test::*;
 
@@ -646,11 +660,9 @@ fn test_kill_rekillable_task() {
     do run_in_newsched_task {
         do task::try {
             do task::unkillable {
-                unsafe {
-                    do task::rekillable {
-                        do task::spawn {
-                            fail!();
-                        }
+                do task::rekillable {
+                    do task::spawn {
+                        fail!();
                     }
                 }
             }
@@ -658,7 +670,39 @@ fn test_kill_rekillable_task() {
     }
 }
 
-#[test] #[should_fail]
+#[test]
+#[should_fail]
+#[ignore(cfg(windows))]
+fn test_rekillable_not_nested() {
+    do rekillable {
+        // This should fail before
+        // receiving anything since
+        // this block should be nested
+        // into a unkillable block.
+        deschedule();
+    }
+}
+
+
+#[test]
+#[ignore(cfg(windows))]
+fn test_rekillable_nested_failure() {
+
+    let result = do task::try {
+        do unkillable {
+            do rekillable {
+                let (port,chan) = comm::stream();
+                do task::spawn { chan.send(()); fail!(); }
+                port.recv(); // wait for child to exist
+                port.recv(); // block forever, expect to get killed.
+            }
+        }
+    };
+    assert!(result.is_err());
+}
+
+
+#[test] #[should_fail] #[ignore(cfg(windows))]
 fn test_cant_dup_task_builder() {
     let mut builder = task();
     builder.unlinked();
@@ -987,7 +1031,7 @@ fn test_try_fail() {
 
 #[cfg(test)]
 fn get_sched_id() -> int {
-    do Local::borrow::<::rt::sched::Scheduler, int> |sched| {
+    do Local::borrow |sched: &mut ::rt::sched::Scheduler| {
         sched.sched_id() as int
     }
 }
index 980141d29c3984e1e7e7fa68b7b576942d876ebf..c3a3dc56ce2330de23a04374d359a7de753b0148 100644 (file)
@@ -449,7 +449,7 @@ impl RuntimeGlue {
     fn kill_task(mut handle: KillHandle) {
         do handle.kill().map_move |killed_task| {
             let killed_task = Cell::new(killed_task);
-            do Local::borrow::<Scheduler, ()> |sched| {
+            do Local::borrow |sched: &mut Scheduler| {
                 sched.enqueue_task(killed_task.take());
             }
         };
@@ -460,7 +460,7 @@ fn with_task_handle_and_failing(blk: &fn(&KillHandle, bool)) {
         unsafe {
             // Can't use safe borrow, because the taskgroup destructor needs to
             // access the scheduler again to send kill signals to other tasks.
-            let me = Local::unsafe_borrow::<Task>();
+            let me: *mut Task = Local::unsafe_borrow();
             blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding)
         }
     }
@@ -470,7 +470,7 @@ fn with_my_taskgroup<U>(blk: &fn(&Taskgroup) -> U) -> U {
         unsafe {
             // Can't use safe borrow, because creating new hashmaps for the
             // tasksets requires an rng, which needs to borrow the sched.
-            let me = Local::unsafe_borrow::<Task>();
+            let me: *mut Task = Local::unsafe_borrow();
             blk(match (*me).taskgroup {
                 None => {
                     // First task in its (unlinked/unsupervised) taskgroup.
@@ -574,7 +574,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
         // If child data is 'None', the enlist is vacuously successful.
         let enlist_success = do child_data.take().map_move_default(true) |child_data| {
             let child_data = Cell::new(child_data); // :(
-            do Local::borrow::<Task, bool> |me| {
+            do Local::borrow |me: &mut Task| {
                 let (child_tg, ancestors) = child_data.take();
                 let mut ancestors = ancestors;
                 let handle = me.death.kill_handle.get_ref();
@@ -608,7 +608,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
     } else {
         unsafe {
             // Creating a 1:1 task:thread ...
-            let sched = Local::unsafe_borrow::<Scheduler>();
+            let sched: *mut Scheduler = Local::unsafe_borrow();
             let sched_handle = (*sched).make_handle();
 
             // Since this is a 1:1 scheduler we create a queue not in
index 198c09964bb6ff274354d4f8b559afeaaaf5a1ac..01f57c231dadef53cdab7b5ae1e8b05a6ead16b5 100644 (file)
@@ -343,7 +343,14 @@ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
 
 // NB: raw-pointer IterBytes does _not_ dereference
 // to the target; it just gives you the pointer-bytes.
-impl<A> IterBytes for *const A {
+impl<A> IterBytes for *A {
+    #[inline]
+    fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+        (*self as uint).iter_bytes(lsb0, f)
+    }
+}
+
+impl<A> IterBytes for *mut A {
     #[inline]
     fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
         (*self as uint).iter_bytes(lsb0, f)
index 12073a1f4f0951e4db9d64ba54de5279a5bed565..5d9ca6202e26293b47fef8cf4e0b26c6ec35a73c 100644 (file)
@@ -176,7 +176,7 @@ fn cmp(&self, other: &($($T,)+)) -> Ordering {
                 impl<$($T:Zero),+> Zero for ($($T,)+) {
                     #[inline]
                     fn zero() -> ($($T,)+) {
-                        ($(Zero::zero::<$T>(),)+)
+                        ($({ let x: $T = Zero::zero(); x},)+)
                     }
                     #[inline]
                     fn is_zero(&self) -> bool {
index 82f14e4c8d72b507fe680212e83e3aa333672860..3af0322df56da0a951d90a50fdbe7ef970a49695 100644 (file)
@@ -52,3 +52,8 @@ fn zero() -> () { () }
     #[inline]
     fn is_zero(&self) -> bool { true }
 }
+
+#[cfg(not(test))]
+impl Default for () {
+    fn default() -> () { () }
+}
index f286235ca0e18b9694cf584c861bcb736e97ae60..f9380e7ad1241fd2f6bf7c3bc9c99d51218a2e9b 100644 (file)
@@ -538,7 +538,8 @@ fn flag() {
 
     #[test]
     fn option_empty() {
-        assert!(AtomicOption::empty::<()>().is_empty(SeqCst));
+        let mut option: AtomicOption<()> = AtomicOption::empty();
+        assert!(option.is_empty(SeqCst));
     }
 
     #[test]
index 6dbe68200b3b7fe23d28c62b72dc39083e7ec993..90cf49cad1ccf2a9553507091bfa31c925ee146b 100644 (file)
@@ -252,6 +252,7 @@ pub unsafe fn close(handle: *libc::c_void) {
         FreeLibrary(handle); ()
     }
 
+    #[cfg(target_arch = "x86")]
     #[link_name = "kernel32"]
     extern "stdcall" {
         fn SetLastError(error: u32);
@@ -261,4 +262,15 @@ fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
         fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
         fn FreeLibrary(handle: *libc::c_void);
     }
+
+    #[cfg(target_arch = "x86_64")]
+    #[link_name = "kernel32"]
+    extern {
+        fn SetLastError(error: u32);
+        fn LoadLibraryW(name: *u16) -> *libc::c_void;
+        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
+                              handle: **libc::c_void) -> *libc::c_void;
+        fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
+        fn FreeLibrary(handle: *libc::c_void);
+    }
 }
index 0642bb1973745423c725e64e3ecabdd8d7942677..cdd93ce87c35bbdfb14944571782e07cd71a1d06 100644 (file)
@@ -161,13 +161,10 @@ fn visit_leave_fn(&self, purity: uint, proto: uint,
                       n_inputs: uint, retstyle: uint) -> bool;
 
     fn visit_trait(&self) -> bool;
-    fn visit_var(&self) -> bool;
-    fn visit_var_integral(&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_constr(&self, inner: *TyDesc) -> bool;
     fn visit_closure_ptr(&self, ck: uint) -> bool;
 }
 
@@ -335,19 +332,13 @@ fn visit_leave_fn(&self, purity: uint, proto: uint,
     /// Get the address of the `__morestack` stack growth function.
     pub fn morestack_addr() -> *();
 
-    /// Calculates the offset from a pointer.
-    ///
-    /// This is implemented as an intrinsic to avoid converting to and from an
-    /// integer, since the conversion would throw away aliasing information.
-    pub fn offset<T>(dst: *T, offset: int) -> *T;
-
     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
     /// the object, or one-byte-past-the-end. An arithmetic overflow is also
     /// undefined behaviour.
     ///
-    /// This intrinsic should be preferred over `offset` when the guarantee can
-    /// be satisfied, to enable better optimization.
-    pub fn offset_inbounds<T>(dst: *T, offset: int) -> *T;
+    /// This is implemented as an intrinsic to avoid converting to and from an
+    /// integer, since the conversion would throw away aliasing information.
+    pub fn offset<T>(dst: *T, offset: int) -> *T;
 
     /// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
     /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
index e47a3c49f96bfc6a101f9ae47b3ef4ac7f36d586..1d839b55195be9c7bc436d1d001238b69f70bc54 100644 (file)
@@ -13,7 +13,7 @@
 use c_str::ToCStr;
 use cast::transmute;
 use libc::{c_char, c_void, size_t, uintptr_t};
-use option::{Some, None};
+use option::{Option, None, Some};
 use sys;
 use rt::task::Task;
 use rt::local::Local;
@@ -37,7 +37,8 @@ pub fn fail_bounds_check(file: *c_char, line: size_t,
 #[lang="malloc"]
 pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
     // XXX: Unsafe borrow for speed. Lame.
-    match Local::try_unsafe_borrow::<Task>() {
+    let task: Option<*mut Task> = Local::try_unsafe_borrow();
+    match task {
         Some(task) => {
             (*task).heap.alloc(td as *c_void, size as uint) as *c_char
         }
index bdf84604fb37f852bf3898ba49efe3d800c996b6..a538566fa189822b1da848a41208098a025df4ea 100644 (file)
@@ -57,6 +57,7 @@ impl<'self> Repr<Slice<u8>> for &'self str {}
 impl<T> Repr<*Box<T>> for @T {}
 impl<T> Repr<*Box<Vec<T>>> for @[T] {}
 impl Repr<*String> for ~str {}
+impl Repr<*Box<String>> for @str {}
 
 // sure would be nice to have this
 // impl<T> Repr<*Vec<T>> for ~[T] {}
index d7f9988edeff92da064b43bcd15e669c305abc2f..8d1545ea2b4506061f8c1d1c48c3bf2b3af34a3b 100644 (file)
 /// An atomically reference counted pointer.
 ///
 /// Enforces no shared-memory safety.
-pub struct UnsafeAtomicRcBox<T> {
-    data: *mut libc::c_void,
+pub struct UnsafeArc<T> {
+    data: *mut ArcData<T>,
 }
 
-struct AtomicRcBoxData<T> {
+struct ArcData<T> {
     count: AtomicUint,
     // An unwrapper uses this protocol to communicate with the "other" task that
     // drops the last refcount on an arc. Unfortunately this can't be a proper
@@ -41,52 +41,51 @@ struct AtomicRcBoxData<T> {
     data: Option<T>,
 }
 
-unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut libc::c_void {
-    let data = ~AtomicRcBoxData { count: AtomicUint::new(refcount),
-                                  unwrapper: AtomicOption::empty(),
-                                  data: Some(data) };
+unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
+    let data = ~ArcData { count: AtomicUint::new(refcount),
+                          unwrapper: AtomicOption::empty(),
+                          data: Some(data) };
     cast::transmute(data)
 }
 
-impl<T: Send> UnsafeAtomicRcBox<T> {
-    pub fn new(data: T) -> UnsafeAtomicRcBox<T> {
-        unsafe { UnsafeAtomicRcBox { data: new_inner(data, 1) } }
+impl<T: Send> UnsafeArc<T> {
+    pub fn new(data: T) -> UnsafeArc<T> {
+        unsafe { UnsafeArc { data: new_inner(data, 1) } }
     }
 
     /// As new(), but returns an extra pre-cloned handle.
-    pub fn new2(data: T) -> (UnsafeAtomicRcBox<T>, UnsafeAtomicRcBox<T>) {
+    pub fn new2(data: T) -> (UnsafeArc<T>, UnsafeArc<T>) {
         unsafe {
             let ptr = new_inner(data, 2);
-            (UnsafeAtomicRcBox { data: ptr }, UnsafeAtomicRcBox { data: ptr })
+            (UnsafeArc { data: ptr }, UnsafeArc { data: ptr })
         }
     }
 
     /// As new(), but returns a vector of as many pre-cloned handles as requested.
-    pub fn newN(data: T, num_handles: uint) -> ~[UnsafeAtomicRcBox<T>] {
+    pub fn newN(data: T, num_handles: uint) -> ~[UnsafeArc<T>] {
         unsafe {
             if num_handles == 0 {
                 ~[] // need to free data here
             } else {
                 let ptr = new_inner(data, num_handles);
-                vec::from_fn(num_handles, |_| UnsafeAtomicRcBox { data: ptr })
+                vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
             }
         }
     }
 
     /// As newN(), but from an already-existing handle. Uses one xadd.
-    pub fn cloneN(self, num_handles: uint) -> ~[UnsafeAtomicRcBox<T>] {
+    pub fn cloneN(self, num_handles: uint) -> ~[UnsafeArc<T>] {
         if num_handles == 0 {
             ~[] // The "num_handles - 1" trick (below) fails in the 0 case.
         } else {
             unsafe {
-                let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
                 // Minus one because we are recycling the given handle's refcount.
-                let old_count = data.count.fetch_add(num_handles - 1, Acquire);
-                // let old_count = data.count.fetch_add(num_handles, Acquire);
+                let old_count = (*self.data).count.fetch_add(num_handles - 1, Acquire);
+                // let old_count = (*self.data).count.fetch_add(num_handles, Acquire);
                 assert!(old_count >= 1);
-                let ptr = cast::transmute(data);
+                let ptr = self.data;
                 cast::forget(self); // Don't run the destructor on this handle.
-                vec::from_fn(num_handles, |_| UnsafeAtomicRcBox { data: ptr })
+                vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
             }
         }
     }
@@ -94,10 +93,8 @@ pub fn cloneN(self, num_handles: uint) -> ~[UnsafeAtomicRcBox<T>] {
     #[inline]
     pub fn get(&self) -> *mut T {
         unsafe {
-            let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
-            assert!(data.count.load(Relaxed) > 0);
-            let r: *mut T = data.data.get_mut_ref();
-            cast::forget(data);
+            assert!((*self.data).count.load(Relaxed) > 0);
+            let r: *mut T = (*self.data).data.get_mut_ref();
             return r;
         }
     }
@@ -105,10 +102,8 @@ pub fn get(&self) -> *mut T {
     #[inline]
     pub fn get_immut(&self) -> *T {
         unsafe {
-            let data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
-            assert!(data.count.load(Relaxed) > 0);
-            let r: *T = data.data.get_ref();
-            cast::forget(data);
+            assert!((*self.data).count.load(Relaxed) > 0);
+            let r: *T = (*self.data).data.get_ref();
             return r;
         }
     }
@@ -122,7 +117,8 @@ pub fn unwrap(self) -> T {
         do task::unkillable {
             unsafe {
                 let mut this = this.take();
-                let mut data: ~AtomicRcBoxData<T> = cast::transmute(this.data);
+                // The ~ dtor needs to run if this code succeeds.
+                let mut data: ~ArcData<T> = cast::transmute(this.data);
                 // Set up the unwrap protocol.
                 let (p1,c1) = comm::oneshot(); // ()
                 let (p2,c2) = comm::oneshot(); // bool
@@ -139,7 +135,7 @@ pub fn unwrap(self) -> T {
                         // We were the last owner. Can unwrap immediately.
                         // AtomicOption's destructor will free the server endpoint.
                         // FIXME(#3224): it should be like this
-                        // let ~AtomicRcBoxData { data: user_data, _ } = data;
+                        // let ~ArcData { data: user_data, _ } = data;
                         // user_data
                         data.data.take_unwrap()
                     } else {
@@ -154,7 +150,7 @@ pub fn unwrap(self) -> T {
                             let (c2, data) = c2_and_data.take();
                             c2.send(true);
                             // FIXME(#3224): it should be like this
-                            // let ~AtomicRcBoxData { data: user_data, _ } = data;
+                            // let ~ArcData { data: user_data, _ } = data;
                             // user_data
                             let mut data = data;
                             data.data.take_unwrap()
@@ -183,10 +179,11 @@ pub fn unwrap(self) -> T {
 
     /// As unwrap above, but without blocking. Returns 'Left(self)' if this is
     /// not the last reference; 'Right(unwrapped_data)' if so.
-    pub fn try_unwrap(self) -> Either<UnsafeAtomicRcBox<T>, T> {
+    pub fn try_unwrap(self) -> Either<UnsafeArc<T>, T> {
         unsafe {
             let mut this = self; // FIXME(#4330) mutable self
-            let mut data: ~AtomicRcBoxData<T> = cast::transmute(this.data);
+            // The ~ dtor needs to run if this code succeeds.
+            let mut data: ~ArcData<T> = cast::transmute(this.data);
             // This can of course race with anybody else who has a handle, but in
             // such a case, the returned count will always be at least 2. If we
             // see 1, no race was possible. All that matters is 1 or not-1.
@@ -209,27 +206,25 @@ pub fn try_unwrap(self) -> Either<UnsafeAtomicRcBox<T>, T> {
     }
 }
 
-impl<T: Send> Clone for UnsafeAtomicRcBox<T> {
-    fn clone(&self) -> UnsafeAtomicRcBox<T> {
+impl<T: Send> Clone for UnsafeArc<T> {
+    fn clone(&self) -> UnsafeArc<T> {
         unsafe {
-            let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
             // This barrier might be unnecessary, but I'm not sure...
-            let old_count = data.count.fetch_add(1, Acquire);
+            let old_count = (*self.data).count.fetch_add(1, Acquire);
             assert!(old_count >= 1);
-            cast::forget(data);
-            return UnsafeAtomicRcBox { data: self.data };
+            return UnsafeArc { data: self.data };
         }
     }
 }
 
 #[unsafe_destructor]
-impl<T> Drop for UnsafeAtomicRcBox<T>{
+impl<T> Drop for UnsafeArc<T>{
     fn drop(&self) {
         unsafe {
             if self.data.is_null() {
                 return; // Happens when destructing an unwrapper's handle.
             }
-            let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+            let mut data: ~ArcData<T> = cast::transmute(self.data);
             // Must be acquire+release, not just release, to make sure this
             // doesn't get reordered to after the unwrapper pointer load.
             let old_count = data.count.fetch_sub(1, SeqCst);
@@ -281,20 +276,25 @@ fn drop(&self) {
  */
 // FIXME(#8140) should not be pub
 pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
-    use rt::task::Task;
+    use rt::task::{Task, GreenTask, SchedTask};
     use rt::local::Local;
-    use rt::in_green_task_context;
-
-    if in_green_task_context() {
-        let t = Local::unsafe_borrow::<Task>();
-        do (|| {
-            (*t).death.inhibit_deschedule();
-            f()
-        }).finally {
-            (*t).death.allow_deschedule();
+
+    let task_opt: Option<*mut Task> = Local::try_unsafe_borrow();
+    match task_opt {
+        Some(t) => {
+            match (*t).task_type {
+                GreenTask(_) => {
+                    do (|| {
+                        (*t).death.inhibit_deschedule();
+                        f()
+                    }).finally {
+                        (*t).death.allow_deschedule();
+                    }
+                }
+                SchedTask => f()
+            }
         }
-    } else {
-        f()
+        None => f()
     }
 }
 
@@ -351,7 +351,7 @@ struct ExData<T> {
  * need to block or deschedule while accessing shared state, use extra::sync::RWArc.
  */
 pub struct Exclusive<T> {
-    x: UnsafeAtomicRcBox<ExData<T>>
+    x: UnsafeArc<ExData<T>>
 }
 
 impl<T:Send> Clone for Exclusive<T> {
@@ -369,7 +369,7 @@ pub fn new(user_data: T) -> Exclusive<T> {
             data: user_data
         };
         Exclusive {
-            x: UnsafeAtomicRcBox::new(data)
+            x: UnsafeArc::new(data)
         }
     }
 
@@ -437,7 +437,7 @@ mod tests {
     use comm;
     use option::*;
     use prelude::*;
-    use super::{Exclusive, UnsafeAtomicRcBox, atomically};
+    use super::{Exclusive, UnsafeArc, atomically};
     use task;
     use util;
 
@@ -502,44 +502,44 @@ fn exclusive_new_poison() {
     #[test]
     fn arclike_newN() {
         // Tests that the many-refcounts-at-once constructors don't leak.
-        let _ = UnsafeAtomicRcBox::new2(~~"hello");
-        let x = UnsafeAtomicRcBox::newN(~~"hello", 0);
+        let _ = UnsafeArc::new2(~~"hello");
+        let x = UnsafeArc::newN(~~"hello", 0);
         assert_eq!(x.len(), 0)
-        let x = UnsafeAtomicRcBox::newN(~~"hello", 1);
+        let x = UnsafeArc::newN(~~"hello", 1);
         assert_eq!(x.len(), 1)
-        let x = UnsafeAtomicRcBox::newN(~~"hello", 10);
+        let x = UnsafeArc::newN(~~"hello", 10);
         assert_eq!(x.len(), 10)
     }
 
     #[test]
     fn arclike_cloneN() {
         // Tests that the many-refcounts-at-once special-clone doesn't leak.
-        let x = UnsafeAtomicRcBox::new(~~"hello");
+        let x = UnsafeArc::new(~~"hello");
         let x = x.cloneN(0);
         assert_eq!(x.len(), 0);
-        let x = UnsafeAtomicRcBox::new(~~"hello");
+        let x = UnsafeArc::new(~~"hello");
         let x = x.cloneN(1);
         assert_eq!(x.len(), 1);
-        let x = UnsafeAtomicRcBox::new(~~"hello");
+        let x = UnsafeArc::new(~~"hello");
         let x = x.cloneN(10);
         assert_eq!(x.len(), 10);
     }
 
     #[test]
     fn arclike_unwrap_basic() {
-        let x = UnsafeAtomicRcBox::new(~~"hello");
+        let x = UnsafeArc::new(~~"hello");
         assert!(x.unwrap() == ~~"hello");
     }
 
     #[test]
     fn arclike_try_unwrap() {
-        let x = UnsafeAtomicRcBox::new(~~"hello");
+        let x = UnsafeArc::new(~~"hello");
         assert!(x.try_unwrap().expect_right("try_unwrap failed") == ~~"hello");
     }
 
     #[test]
     fn arclike_try_unwrap_fail() {
-        let x = UnsafeAtomicRcBox::new(~~"hello");
+        let x = UnsafeArc::new(~~"hello");
         let x2 = x.clone();
         let left_x = x.try_unwrap();
         assert!(left_x.is_left());
@@ -550,7 +550,7 @@ fn arclike_try_unwrap_fail() {
     #[test]
     fn arclike_try_unwrap_unwrap_race() {
         // When an unwrap and a try_unwrap race, the unwrapper should always win.
-        let x = UnsafeAtomicRcBox::new(~~"hello");
+        let x = UnsafeArc::new(~~"hello");
         let x2 = Cell::new(x.clone());
         let (p,c) = comm::stream();
         do task::spawn {
index b46876ad3fe44db96389a84194f9be1ac2009680..5085f337d4bba216103ddf9f17c1505dca509123 100644 (file)
@@ -54,8 +54,10 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
         let t: *mut T = &mut tmp;
 
         // Perform the swap, `&mut` pointers never alias
-        ptr::copy_nonoverlapping_memory(t, x, 1);
-        ptr::copy_nonoverlapping_memory(x, y, 1);
+        let x_raw: *mut T = x;
+        let y_raw: *mut T = y;
+        ptr::copy_nonoverlapping_memory(t, x_raw, 1);
+        ptr::copy_nonoverlapping_memory(x, y_raw, 1);
         ptr::copy_nonoverlapping_memory(y, t, 1);
 
         // y and t now point to the same thing, but we need to completely forget `tmp`
index f196cf423c130204dda7470c89eb8bcdcf9869d1..12aebe20161a03f337c7a6a677984d17de73e300 100644 (file)
@@ -59,7 +59,7 @@
 #[warn(non_camel_case_types)];
 
 use cast;
-use clone::Clone;
+use clone::{Clone, DeepClone};
 use container::{Container, Mutable};
 use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
 use cmp;
@@ -75,6 +75,7 @@
 use sys;
 use sys::size_of;
 use uint;
+use unstable::finally::Finally;
 use unstable::intrinsics;
 use unstable::intrinsics::{get_tydesc, contains_managed};
 use unstable::raw::{Box, Repr, Slice, Vec};
@@ -97,11 +98,14 @@ pub fn from_fn<T>(n_elts: uint, op: &fn(uint) -> T) -> ~[T] {
         let mut v = with_capacity(n_elts);
         let p = raw::to_mut_ptr(v);
         let mut i: uint = 0u;
-        while i < n_elts {
-            intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), op(i));
-            i += 1u;
+        do (|| {
+            while i < n_elts {
+                intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), op(i));
+                i += 1u;
+            }
+        }).finally {
+            raw::set_len(&mut v, i);
         }
-        raw::set_len(&mut v, n_elts);
         v
     }
 }
@@ -121,11 +125,14 @@ pub fn from_elem<T:Clone>(n_elts: uint, t: T) -> ~[T] {
         let mut v = with_capacity(n_elts);
         let p = raw::to_mut_ptr(v);
         let mut i = 0u;
-        while i < n_elts {
-            intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), t.clone());
-            i += 1u;
+        do (|| {
+            while i < n_elts {
+                intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), t.clone());
+                i += 1u;
+            }
+        }).finally {
+            raw::set_len(&mut v, i);
         }
-        raw::set_len(&mut v, n_elts);
         v
     }
 }
@@ -889,7 +896,7 @@ fn iter(self) -> VecIterator<'self, T> {
                             lifetime: cast::transmute(p)}
             } else {
                 VecIterator{ptr: p,
-                            end: p.offset_inbounds(self.len() as int),
+                            end: p.offset(self.len() as int),
                             lifetime: cast::transmute(p)}
             }
         }
@@ -1115,14 +1122,7 @@ fn map<U>(&self, f: &fn(t: &T) -> U) -> ~[U] {
      * foreign interop.
      */
     #[inline]
-    fn as_imm_buf<U>(&self,
-                     /* NB---this CANNOT be const, see below */
-                     f: &fn(*T, uint) -> U) -> U {
-        // NB---Do not change the type of s to `&const [T]`.  This is
-        // unsound.  The reason is that we are going to create immutable pointers
-        // into `s` and pass them to `f()`, but in fact they are potentially
-        // pointing at *mutable memory*.  Use `as_mut_buf` instead!
-
+    fn as_imm_buf<U>(&self, f: &fn(*T, uint) -> U) -> U {
         let s = self.repr();
         f(s.data, s.len / sys::nonzero_size_of::<T>())
     }
@@ -1401,7 +1401,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(new_len);
+        self.reserve_at_least(new_len);
         unsafe { // Note: infallible.
             let self_p = vec::raw::to_mut_ptr(*self);
             let rhs_p = vec::raw::to_ptr(rhs);
@@ -1884,7 +1884,7 @@ fn mut_iter(self) -> VecMutIterator<'self, T> {
                                lifetime: cast::transmute(p)}
             } else {
                 VecMutIterator{ptr: p,
-                               end: p.offset_inbounds(self.len() as int),
+                               end: p.offset(self.len() as int),
                                lifetime: cast::transmute(p)}
             }
         }
@@ -2192,13 +2192,20 @@ pub fn copy_memory(dst: &mut [u8], src: &[u8], count: uint) {
     }
 }
 
-impl<A:Clone> Clone for ~[A] {
+impl<A: Clone> Clone for ~[A] {
     #[inline]
     fn clone(&self) -> ~[A] {
         self.iter().map(|item| item.clone()).collect()
     }
 }
 
+impl<A: DeepClone> DeepClone for ~[A] {
+    #[inline]
+    fn deep_clone(&self) -> ~[A] {
+        self.iter().map(|item| item.deep_clone()).collect()
+    }
+}
+
 // This works because every lifetime is a sub-lifetime of 'static
 impl<'self, A> Zero for &'self [A] {
     fn zero() -> &'self [A] { &'self [] }
@@ -2240,7 +2247,7 @@ fn next(&mut self) -> Option<$elem> {
                             // same pointer.
                             cast::transmute(self.ptr as uint + 1)
                         } else {
-                            self.ptr.offset_inbounds(1)
+                            self.ptr.offset(1)
                         };
 
                         Some(cast::transmute(old))
@@ -2272,7 +2279,7 @@ fn next_back(&mut self) -> Option<$elem> {
                             // See above for why 'ptr.offset' isn't used
                             cast::transmute(self.end as uint - 1)
                         } else {
-                            self.end.offset_inbounds(-1)
+                            self.end.offset(-1)
                         };
                         Some(cast::transmute(self.end))
                     }
@@ -3130,6 +3137,29 @@ fn test_from_fn_fail() {
         };
     }
 
+    #[test]
+    #[should_fail]
+    fn test_from_elem_fail() {
+        use cast;
+
+        struct S {
+            f: int,
+            boxes: (~int, @int)
+        }
+
+        impl Clone for S {
+            fn clone(&self) -> S {
+                let s = unsafe { cast::transmute_mut(self) };
+                s.f += 1;
+                if s.f == 10 { fail!() }
+                S { f: s.f, boxes: s.boxes.clone() }
+            }
+        }
+
+        let s = S { f: 0, boxes: (~0, @0) };
+        let _ = from_elem(100, s);
+    }
+
     #[test]
     #[should_fail]
     fn test_build_fail() {
@@ -3154,7 +3184,6 @@ fn test_grow_fn_fail() {
         }
     }
 
-    #[ignore] // FIXME #8698
     #[test]
     #[should_fail]
     fn test_map_fail() {
@@ -3164,12 +3193,11 @@ fn test_map_fail() {
             if i == 2 {
                 fail!()
             }
-            i += 0;
+            i += 1;
             ~[(~0, @0)]
         };
     }
 
-    #[ignore] // FIXME #8698
     #[test]
     #[should_fail]
     fn test_flat_map_fail() {
@@ -3179,12 +3207,11 @@ fn test_flat_map_fail() {
             if i == 2 {
                 fail!()
             }
-            i += 0;
+            i += 1;
             ~[(~0, @0)]
         };
     }
 
-    #[ignore] // FIXME #8698
     #[test]
     #[should_fail]
     fn test_rposition_fail() {
@@ -3194,12 +3221,11 @@ fn test_rposition_fail() {
             if i == 2 {
                 fail!()
             }
-            i += 0;
+            i += 1;
             false
         };
     }
 
-    #[ignore] // FIXME #8698
     #[test]
     #[should_fail]
     fn test_permute_fail() {
@@ -3209,7 +3235,7 @@ fn test_permute_fail() {
             if i == 2 {
                 fail!()
             }
-            i += 0;
+            i += 1;
             true
         };
     }
index b0c324012929f0e9cb77a7ff55e8562f75fc0333..aec279e9c53bd1bff8d8ffbb7c570fd6f9e7992c 100644 (file)
@@ -109,12 +109,21 @@ pub struct Path {
     /// A `::foo` path, is relative to the crate root rather than current
     /// module (like paths in an import).
     global: bool,
-    /// The segments in the path (the things separated by ::)
-    idents: ~[ident],
-    /// "Region parameter", currently only one lifetime is allowed in a path.
-    rp: Option<Lifetime>,
-    /// These are the type parameters, ie, the `a, b` in `foo::bar::<a, b>`
-    types: ~[Ty],
+    /// The segments in the path: the things separated by `::`.
+    segments: ~[PathSegment],
+}
+
+/// A segment of a path: an identifier, an optional lifetime, and a set of
+/// types.
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
+pub struct PathSegment {
+    /// The identifier portion of this path segment.
+    identifier: ident,
+    /// The lifetime parameter for this path segment. Currently only one
+    /// lifetime parameter is allowed.
+    lifetime: Option<Lifetime>,
+    /// The type parameters for this path segment, if present.
+    types: OptVec<Ty>,
 }
 
 pub type CrateNum = int;
@@ -165,13 +174,17 @@ pub fn is_type_parameterized(&self) -> bool {
     }
 }
 
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
+pub enum MethodProvenance {
+    FromTrait(def_id),
+    FromImpl(def_id),
+}
+
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum def {
     def_fn(def_id, purity),
-    def_static_method(/* method */ def_id,
-                      /* trait */  Option<def_id>,
-                      purity),
-    def_self(NodeId, bool /* is_implicit */),
+    def_static_method(/* method */ def_id, MethodProvenance, purity),
+    def_self(NodeId),
     def_self_ty(/* trait id */ NodeId),
     def_mod(def_id),
     def_foreign_mod(def_id),
@@ -298,7 +311,10 @@ pub enum pat_ {
 }
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub enum mutability { m_mutbl, m_imm, m_const, }
+pub enum mutability {
+    m_mutbl,
+    m_imm,
+}
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum Sigil {
@@ -704,7 +720,7 @@ fn to_str(&self) -> ~str {
 }
 
 // NB Eq method appears below.
-#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub struct Ty {
     id: NodeId,
     node: ty_,
index cfbe61ca65e682726add25c8286f1b00c468e2ff..2fe42af65ca17aefd9cd25c71bb8b0fa597ab66d 100644 (file)
@@ -28,8 +28,8 @@ pub fn path_name_i(idents: &[ident]) -> ~str {
     idents.map(|i| token::interner_get(i.name)).connect("::")
 }
 
-pub fn path_to_ident(p: &Path) -> ident {
-    *p.idents.last()
+pub fn path_to_ident(path: &Path) -> ident {
+    path.segments.last().identifier
 }
 
 pub fn local_def(id: NodeId) -> def_id {
@@ -64,7 +64,7 @@ pub fn def_id_of_def(d: def) -> def_id {
       def_use(id) | def_struct(id) | def_trait(id) | def_method(id, _) => {
         id
       }
-      def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id)
+      def_arg(id, _) | def_local(id, _) | def_self(id) | def_self_ty(id)
       | def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id)
       | def_typaram_binder(id) | def_label(id) => {
         local_def(id)
@@ -217,12 +217,18 @@ pub fn default_block(
     }
 }
 
-pub fn ident_to_path(s: span, i: ident) -> Path {
-    ast::Path { span: s,
-                 global: false,
-                 idents: ~[i],
-                 rp: None,
-                 types: ~[] }
+pub fn ident_to_path(s: span, identifier: ident) -> Path {
+    ast::Path {
+        span: s,
+        global: false,
+        segments: ~[
+            ast::PathSegment {
+                identifier: identifier,
+                lifetime: None,
+                types: opt_vec::Empty,
+            }
+        ],
+    }
 }
 
 pub fn ident_to_pat(id: NodeId, s: span, i: ident) -> @pat {
@@ -420,7 +426,7 @@ fn visit_generics_helper(&self, generics: &Generics) {
 impl Visitor<()> for IdVisitor {
     fn visit_mod(&mut self,
                  module: &_mod,
-                 _span: span,
+                 _: span,
                  node_id: NodeId,
                  env: ()) {
         (self.visit_callback)(node_id);
index dfaffa0c2759dd3fc2e52329f1c5b4dfe61a45f3..7432cf80a41c3756ea280ca155a05e869ac639ee 100644 (file)
@@ -139,8 +139,12 @@ fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
                                 ext::tt::macro_rules::add_new_extension));
     syntax_expanders.insert(intern(&"fmt"),
                             builtin_normal_tt(ext::fmt::expand_syntax_ext));
-    syntax_expanders.insert(intern(&"ifmt"),
-                            builtin_normal_tt(ext::ifmt::expand_syntax_ext));
+    syntax_expanders.insert(intern(&"format"),
+                            builtin_normal_tt(ext::ifmt::expand_format));
+    syntax_expanders.insert(intern(&"write"),
+                            builtin_normal_tt(ext::ifmt::expand_write));
+    syntax_expanders.insert(intern(&"writeln"),
+                            builtin_normal_tt(ext::ifmt::expand_writeln));
     syntax_expanders.insert(
         intern(&"auto_encode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
@@ -325,20 +329,6 @@ pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: &str) -> @str {
     }
 }
 
-pub fn expr_to_ident(cx: @ExtCtxt,
-                     expr: @ast::expr,
-                     err_msg: &str) -> ast::ident {
-    match expr.node {
-      ast::expr_path(ref p) => {
-        if p.types.len() > 0u || p.idents.len() != 1u {
-            cx.span_fatal(expr.span, err_msg);
-        }
-        return p.idents[0];
-      }
-      _ => cx.span_fatal(expr.span, err_msg)
-    }
-}
-
 pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
                       name: &str) {
     if tts.len() != 0 {
@@ -349,15 +339,15 @@ pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
 pub fn get_single_str_from_tts(cx: @ExtCtxt,
                                sp: span,
                                tts: &[ast::token_tree],
-                               name: &str) -> @str {
+                               name: &str)
+                               -> @str {
     if tts.len() != 1 {
         cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
     }
 
     match tts[0] {
         ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
-        _ =>
-        cx.span_fatal(sp, fmt!("%s requires a string.", name))
+        _ => cx.span_fatal(sp, fmt!("%s requires a string.", name)),
     }
 }
 
index 9f179672422cd7295fffcfbd8a006d6e9ee19eb5..21d67493cbffb9049e9384782f89a0afc0d10c30 100644 (file)
@@ -74,6 +74,13 @@ fn ty_rptr(&self, span: span,
     // statements
     fn stmt_expr(&self, expr: @ast::expr) -> @ast::stmt;
     fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt;
+    fn stmt_let_typed(&self,
+                      sp: span,
+                      mutbl: bool,
+                      ident: ast::ident,
+                      typ: ast::Ty,
+                      ex: @ast::expr)
+                      -> @ast::stmt;
 
     // blocks
     fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::Block;
@@ -233,18 +240,31 @@ fn path_ident(&self, span: span, id: ast::ident) -> ast::Path {
     fn path_global(&self, span: span, strs: ~[ast::ident]) -> ast::Path {
         self.path_all(span, true, strs, None, ~[])
     }
-    fn path_all(&self, sp: span,
+    fn path_all(&self,
+                sp: span,
                 global: bool,
-                idents: ~[ast::ident],
+                mut idents: ~[ast::ident],
                 rp: Option<ast::Lifetime>,
                 types: ~[ast::Ty])
-        -> ast::Path {
+                -> ast::Path {
+        let last_identifier = idents.pop();
+        let mut segments: ~[ast::PathSegment] = idents.move_iter()
+                                                      .map(|ident| {
+            ast::PathSegment {
+                identifier: ident,
+                lifetime: None,
+                types: opt_vec::Empty,
+            }
+        }).collect();
+        segments.push(ast::PathSegment {
+            identifier: last_identifier,
+            lifetime: rp,
+            types: opt_vec::from(types),
+        });
         ast::Path {
             span: sp,
             global: global,
-            idents: idents,
-            rp: rp,
-            types: types
+            segments: segments,
         }
     }
 
@@ -387,6 +407,26 @@ fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) ->
         @respan(sp, ast::stmt_decl(@decl, self.next_id()))
     }
 
+    fn stmt_let_typed(&self,
+                      sp: span,
+                      mutbl: bool,
+                      ident: ast::ident,
+                      typ: ast::Ty,
+                      ex: @ast::expr)
+                      -> @ast::stmt {
+        let pat = self.pat_ident(sp, ident);
+        let local = @ast::Local {
+            is_mutbl: mutbl,
+            ty: typ,
+            pat: pat,
+            init: Some(ex),
+            id: self.next_id(),
+            span: sp,
+        };
+        let decl = respan(sp, ast::decl_local(local));
+        @respan(sp, ast::stmt_decl(@decl, self.next_id()))
+    }
+
     fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::Block {
         self.block_all(span, ~[], stmts, expr)
     }
index edb5c634d5698b78d175bab9f779d59dc20570df..477f3fde99c734c1d23f8650cc317314180bed10 100644 (file)
@@ -12,6 +12,7 @@
 use codemap::span;
 use ext::base::*;
 use ext::base;
+use opt_vec;
 use parse::token;
 use parse::token::{str_to_ident};
 
@@ -39,9 +40,13 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
             ast::Path {
                  span: sp,
                  global: false,
-                 idents: ~[res],
-                 rp: None,
-                 types: ~[],
+                 segments: ~[
+                    ast::PathSegment {
+                        identifier: res,
+                        lifetime: None,
+                        types: opt_vec::Empty,
+                    }
+                ]
             }
         ),
         span: sp,
index e55a96f77ff9b57e811000a58265e54a42928bc2..b8cf3de635f04673de303bd8f31829989b143651 100644 (file)
@@ -76,24 +76,33 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
 
             let variant_count = cx.expr_uint(span, variants.len());
 
-            // need to specify the uint-ness of the random number
-            let uint_ty = cx.ty_ident(span, cx.ident_of("uint"));
-            let r_ty = cx.ty_ident(span, cx.ident_of("R"));
             let rand_name = cx.path_all(span,
                                         true,
                                         rand_ident.clone(),
                                         None,
-                                        ~[ uint_ty, r_ty ]);
+                                        ~[]);
             let rand_name = cx.expr_path(rand_name);
 
-            // ::std::rand::Rand::rand::<uint>(rng)
+            // ::std::rand::Rand::rand(rng)
             let rv_call = cx.expr_call(span,
                                        rand_name,
                                        ~[ rng[0].duplicate(cx) ]);
 
+            // need to specify the uint-ness of the random number
+            let uint_ty = cx.ty_ident(span, cx.ident_of("uint"));
+            let value_ident = cx.ident_of("__value");
+            let let_statement = cx.stmt_let_typed(span,
+                                                  false,
+                                                  value_ident,
+                                                  uint_ty,
+                                                  rv_call);
+
             // rand() % variants.len()
-            let rand_variant = cx.expr_binary(span, ast::rem,
-                                              rv_call, variant_count);
+            let value_ref = cx.expr_ident(span, value_ident);
+            let rand_variant = cx.expr_binary(span,
+                                              ast::rem,
+                                              value_ref,
+                                              variant_count);
 
             let mut arms = do variants.iter().enumerate().map |(i, id_sum)| {
                 let i_expr = cx.expr_uint(span, i);
@@ -111,7 +120,10 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
             // _ => {} at the end. Should never occur
             arms.push(cx.arm_unreachable(span));
 
-            cx.expr_match(span, rand_variant, arms)
+            let match_expr = cx.expr_match(span, rand_variant, arms);
+
+            let block = cx.block(span, ~[ let_statement ], Some(match_expr));
+            cx.expr_block(block)
         }
         _ => cx.bug("Non-static method in `deriving(Rand)`")
     };
index 4bea1dc23e737a0d4ae660130ec9358030ddcb9b..86639c6f121e8c92ff0ca09baeb55e2301e6db57 100644 (file)
@@ -19,6 +19,7 @@
 use codemap::{span, spanned, ExpnInfo, NameAndSpan};
 use ext::base::*;
 use fold::*;
+use opt_vec;
 use parse;
 use parse::{parse_item_from_source_str};
 use parse::token;
@@ -42,13 +43,13 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
             match (*mac).node {
                 // Token-tree macros:
                 mac_invoc_tt(ref pth, ref tts) => {
-                    if (pth.idents.len() > 1u) {
+                    if (pth.segments.len() > 1u) {
                         cx.span_fatal(
                             pth.span,
                             fmt!("expected macro name without module \
                                   separators"));
                     }
-                    let extname = &pth.idents[0];
+                    let extname = &pth.segments[0].identifier;
                     let extnamestr = ident_to_str(extname);
                     // leaving explicit deref here to highlight unbox op:
                     match (*extsbox).find(&extname.name) {
@@ -143,9 +144,13 @@ fn mk_simple_path(ident: ast::ident, span: span) -> ast::Path {
                 ast::Path {
                     span: span,
                     global: false,
-                    idents: ~[ident],
-                    rp: None,
-                    types: ~[]
+                    segments: ~[
+                        ast::PathSegment {
+                            identifier: ident,
+                            lifetime: None,
+                            types: opt_vec::Empty,
+                        }
+                    ],
                 }
             }
 
@@ -368,7 +373,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
         _ => cx.span_bug(it.span, "invalid item macro invocation")
     };
 
-    let extname = &pth.idents[0];
+    let extname = &pth.segments[0].identifier;
     let extnamestr = ident_to_str(extname);
     let expanded = match (*extsbox).find(&extname.name) {
         None => cx.span_fatal(pth.span,
@@ -459,13 +464,13 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
         }
         _ => return orig(s, sp, fld)
     };
-    if (pth.idents.len() > 1u) {
+    if (pth.segments.len() > 1u) {
         cx.span_fatal(
             pth.span,
             fmt!("expected macro name without module \
                   separators"));
     }
-    let extname = &pth.idents[0];
+    let extname = &pth.segments[0].identifier;
     let extnamestr = ident_to_str(extname);
     let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
         None =>
@@ -534,10 +539,14 @@ fn visit_pat(&mut self, pattern: @ast::pat, _: ()) {
                     // a path of length one:
                     &ast::Path {
                         global: false,
-                        idents: [id],
                         span: _,
-                        rp: _,
-                        types: _
+                        segments: [
+                            ast::PathSegment {
+                                identifier: id,
+                                lifetime: _,
+                                types: _
+                            }
+                        ]
                     } => self.ident_accumulator.push(id),
                     // I believe these must be enums...
                     _ => ()
@@ -758,32 +767,32 @@ macro_rules! info (
         )
     )
 
-    // conditionally define debug!, but keep it type checking even
-    // in non-debug builds.
-    macro_rules! __debug (
+    macro_rules! debug (
         ($arg:expr) => (
-            __log(4u32, fmt!( \"%?\", $arg ))
+            if cfg!(debug) { __log(4u32, fmt!( \"%?\", $arg )) }
         );
         ($( $arg:expr ),+) => (
-            __log(4u32, fmt!( $($arg),+ ))
+            if cfg!(debug) { __log(4u32, fmt!( $($arg),+ )) }
         )
     )
 
-    #[cfg(debug)]
-    #[macro_escape]
-    mod debug_macro {
-        macro_rules! debug (($($arg:expr),*) => {
-            __debug!($($arg),*)
-        })
-    }
+    macro_rules! error2 (
+        ($($arg:tt)*) => ( __log(1u32, format!($($arg)*)))
+    )
 
-    #[cfg(not(debug))]
-    #[macro_escape]
-    mod debug_macro {
-        macro_rules! debug (($($arg:expr),*) => {
-            if false { __debug!($($arg),*) }
-        })
-    }
+    macro_rules! warn2 (
+        ($($arg:tt)*) => ( __log(2u32, format!($($arg)*)))
+    )
+
+    macro_rules! info2 (
+        ($($arg:tt)*) => ( __log(3u32, format!($($arg)*)))
+    )
+
+    macro_rules! debug2 (
+        ($($arg:tt)*) => (
+            if cfg!(debug) { __log(4u32, format!($($arg)*)) }
+        )
+    )
 
     macro_rules! fail(
         () => (
@@ -797,6 +806,15 @@ macro_rules! fail(
         )
     )
 
+    macro_rules! fail2(
+        () => (
+            fail!(\"explicit failure\")
+        );
+        ($($arg:tt)+) => (
+            ::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!())
+        )
+    )
+
     macro_rules! assert(
         ($cond:expr) => {
             if !$cond {
@@ -940,6 +958,7 @@ macro_rules! cond (
         );
     )
 
+    // NOTE(acrichto): start removing this after the next snapshot
     macro_rules! printf (
         ($arg:expr) => (
             print(fmt!(\"%?\", $arg))
@@ -949,6 +968,7 @@ macro_rules! printf (
         )
     )
 
+    // NOTE(acrichto): start removing this after the next snapshot
     macro_rules! printfln (
         ($arg:expr) => (
             println(fmt!(\"%?\", $arg))
@@ -958,6 +978,19 @@ macro_rules! printfln (
         )
     )
 
+    // FIXME(#6846) once stdio is redesigned, this shouldn't perform an
+    //              allocation but should rather delegate to an invocation of
+    //              write! instead of format!
+    macro_rules! print (
+        ($($arg:tt)+) => ( ::std::io::print(format!($($arg)+)))
+    )
+
+    // FIXME(#6846) once stdio is redesigned, this shouldn't perform an
+    //              allocation but should rather delegate to an io::Writer
+    macro_rules! println (
+        ($($arg:tt)+) => ({ print!($($arg)+); ::std::io::println(\"\"); })
+    )
+
     // NOTE: use this after a snapshot lands to abstract the details
     // of the TLS interface.
     macro_rules! local_data_key (
index 35be77b95c5f9ae1b850218a627dc175d621098d..d4274746a4eda838318c0189b35321f37dc0226e 100644 (file)
@@ -54,20 +54,32 @@ impl Context {
     /// Parses the arguments from the given list of tokens, returning None if
     /// there's a parse error so we can continue parsing other fmt! expressions.
     fn parse_args(&mut self, sp: span,
-                  tts: &[ast::token_tree]) -> Option<@ast::expr> {
+                  leading_expr: bool,
+                  tts: &[ast::token_tree]) -> (Option<@ast::expr>,
+                                               Option<@ast::expr>) {
         let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(),
                                              self.ecx.cfg(),
                                              tts.to_owned());
+        // If we want a leading expression (for ifmtf), parse it here
+        let extra = if leading_expr {
+            let e = Some(p.parse_expr());
+            if !p.eat(&token::COMMA) {
+                self.ecx.span_err(sp, "expected token: `,`");
+                return (e, None);
+            }
+            e
+        } else { None };
+
         if *p.token == token::EOF {
-            self.ecx.span_err(sp, "ifmt! expects at least one argument");
-            return None;
+            self.ecx.span_err(sp, "requires at least a format string argument");
+            return (extra, None);
         }
         let fmtstr = p.parse_expr();
         let mut named = false;
         while *p.token != token::EOF {
             if !p.eat(&token::COMMA) {
                 self.ecx.span_err(sp, "expected token: `,`");
-                return None;
+                return (extra, None);
             }
             if named || (token::is_ident(p.token) &&
                          p.look_ahead(1, |t| *t == token::EQ)) {
@@ -81,14 +93,14 @@ fn parse_args(&mut self, sp: span,
                         self.ecx.span_err(*p.span,
                                           "expected ident, positional arguments \
                                            cannot follow named arguments");
-                        return None;
+                        return (extra, None);
                     }
                     _ => {
                         self.ecx.span_err(*p.span,
                                           fmt!("expected ident for named \
                                                 argument, but found `%s`",
                                                p.this_token_to_str()));
-                        return None;
+                        return (extra, None);
                     }
                 };
                 let name = self.ecx.str_of(ident);
@@ -110,7 +122,7 @@ fn parse_args(&mut self, sp: span,
                 self.arg_types.push(None);
             }
         }
-        return Some(fmtstr);
+        return (extra, Some(fmtstr));
     }
 
     /// Verifies one piece of a parse string. All errors are not emitted as
@@ -530,7 +542,7 @@ fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::expr {
 
     /// Actually builds the expression which the ifmt! block will be expanded
     /// to
-    fn to_expr(&self) -> @ast::expr {
+    fn to_expr(&self, extra: Option<@ast::expr>, f: &str) -> @ast::expr {
         let mut lets = ~[];
         let mut locals = ~[];
         let mut names = vec::from_fn(self.name_positions.len(), |_| None);
@@ -596,15 +608,18 @@ fn to_expr(&self) -> @ast::expr {
         let args = names.move_iter().map(|a| a.unwrap());
         let mut args = locals.move_iter().chain(args);
 
-        // Next, build up the actual call to the sprintf function.
+        let mut fmt_args = match extra {
+            Some(e) => ~[e], None => ~[]
+        };
+        fmt_args.push(self.ecx.expr_ident(self.fmtsp, static_name));
+        fmt_args.push(self.ecx.expr_vec(self.fmtsp, args.collect()));
+
+        // Next, build up the actual call to the {s,f}printf function.
         let result = self.ecx.expr_call_global(self.fmtsp, ~[
                 self.ecx.ident_of("std"),
                 self.ecx.ident_of("fmt"),
-                self.ecx.ident_of("sprintf"),
-            ], ~[
-                self.ecx.expr_ident(self.fmtsp, static_name),
-                self.ecx.expr_vec(self.fmtsp, args.collect()),
-            ]);
+                self.ecx.ident_of(f),
+            ], fmt_args);
 
         // sprintf is unsafe, but we just went through a lot of work to
         // validate that our call is save, so inject the unsafe block for the
@@ -682,8 +697,24 @@ fn format_arg(&self, sp: span, arg: Either<uint, @str>,
     }
 }
 
-pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
-                         tts: &[ast::token_tree]) -> base::MacResult {
+pub fn expand_format(ecx: @ExtCtxt, sp: span,
+                     tts: &[ast::token_tree]) -> base::MacResult {
+    expand_ifmt(ecx, sp, tts, false, false, "format")
+}
+
+pub fn expand_write(ecx: @ExtCtxt, sp: span,
+                    tts: &[ast::token_tree]) -> base::MacResult {
+    expand_ifmt(ecx, sp, tts, true, false, "write")
+}
+
+pub fn expand_writeln(ecx: @ExtCtxt, sp: span,
+                      tts: &[ast::token_tree]) -> base::MacResult {
+    expand_ifmt(ecx, sp, tts, true, true, "write")
+}
+
+fn expand_ifmt(ecx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
+               leading_arg: bool, append_newline: bool,
+               function: &str) -> base::MacResult {
     let mut cx = Context {
         ecx: ecx,
         args: ~[],
@@ -697,13 +728,14 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
         method_statics: ~[],
         fmtsp: sp,
     };
-    let efmt = match cx.parse_args(sp, tts) {
-        Some(e) => e,
-        None => { return MRExpr(ecx.expr_uint(sp, 2)); }
+    let (extra, efmt) = match cx.parse_args(sp, leading_arg, tts) {
+        (extra, Some(e)) => (extra, e),
+        (_, None) => { return MRExpr(ecx.expr_uint(sp, 2)); }
     };
     cx.fmtsp = efmt.span;
     let fmt = expr_to_str(ecx, efmt,
-                          "first argument to ifmt! must be a string literal.");
+                          "format argument must be a string literal.");
+    let fmt = if append_newline { fmt + "\n" } else { fmt.to_owned() };
 
     let mut err = false;
     do parse::parse_error::cond.trap(|m| {
@@ -734,5 +766,5 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
         }
     }
 
-    MRExpr(cx.to_expr())
+    MRExpr(cx.to_expr(extra, function))
 }
index c208a7f7e3e403b77ab9fa6144027158527fe32d..327ee331c3814fe6491f514cbe04eb0703b0a1ca 100644 (file)
@@ -16,8 +16,8 @@
 use codemap;
 use parse::lexer::*; //resolve bug?
 use parse::ParseSess;
-use parse::parser::Parser;
 use parse::attr::parser_attr;
+use parse::parser::{LifetimeAndTypesWithoutColons, Parser};
 use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str};
 use parse::token;
 
@@ -430,7 +430,9 @@ pub fn parse_nt(p: &Parser, name: &str) -> nonterminal {
         _ => p.fatal(~"expected ident, found "
                      + token::to_str(get_ident_interner(), p.token))
       },
-      "path" => token::nt_path(~p.parse_path_with_tps(false)),
+      "path" => {
+        token::nt_path(~p.parse_path(LifetimeAndTypesWithoutColons).path)
+      }
       "attr" => token::nt_attr(@p.parse_attribute(false)),
       "tt" => {
         *p.quote_depth += 1u; //but in theory, non-quoted tts might be useful
index 2b483c2c2a9638524081d789f9b97e2d776454c4..6e3cd8e71597178664b8be07e86feaebb62a8b9e 100644 (file)
@@ -766,9 +766,11 @@ fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path {
     ast::Path {
         span: fld.new_span(p.span),
         global: p.global,
-        idents: p.idents.map(|x| fld.fold_ident(*x)),
-        rp: p.rp,
-        types: p.types.map(|x| fld.fold_ty(x)),
+        segments: p.segments.map(|segment| ast::PathSegment {
+            identifier: fld.fold_ident(segment.identifier),
+            lifetime: segment.lifetime,
+            types: segment.types.map(|typ| fld.fold_ty(typ)),
+        })
     }
 }
 
index 8087efd5a8b00cf55a3307925409f12a44633d0c..e1dcdb9222c7bdc654b13848d0be63822143c7f9 100644 (file)
@@ -287,7 +287,11 @@ pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
 }
 
 pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
-    for tp in p.types.iter() { (v.visit_ty)(tp, (e.clone(), v)); }
+    for segment in p.segments.iter() {
+        for typ in segment.types.iter() {
+            (v.visit_ty)(typ, (e.clone(), v))
+        }
+    }
 }
 
 pub fn visit_pat<E:Clone>(p: &pat, (e, v): (E, vt<E>)) {
index 23c6a8b97208b014aa3f782fa96d2a7ec61a6980..81113f2432923c6089cf37e932a07806c2a821c8 100644 (file)
@@ -361,27 +361,47 @@ fn sp (a: uint, b: uint) -> span {
         span{lo:BytePos(a),hi:BytePos(b),expn_info:None}
     }
 
-    #[test] fn path_exprs_1 () {
+    #[test] fn path_exprs_1() {
         assert_eq!(string_to_expr(@"a"),
-                   @ast::expr{id:1,
-                              node:ast::expr_path(ast::Path {span:sp(0,1),
-                                                              global:false,
-                                                              idents:~[str_to_ident("a")],
-                                                              rp:None,
-                                                              types:~[]}),
-                              span:sp(0,1)})
+                   @ast::expr{
+                    id: 1,
+                    node: ast::expr_path(ast::Path {
+                        span: sp(0, 1),
+                        global: false,
+                        segments: ~[
+                            ast::PathSegment {
+                                identifier: str_to_ident("a"),
+                                lifetime: None,
+                                types: opt_vec::Empty,
+                            }
+                        ],
+                    }),
+                    span: sp(0, 1)
+                   })
     }
 
     #[test] fn path_exprs_2 () {
         assert_eq!(string_to_expr(@"::a::b"),
-                   @ast::expr{id:1,
-                               node:ast::expr_path(
-                                    ast::Path {span:sp(0,6),
-                                               global:true,
-                                               idents:strs_to_idents(~["a","b"]),
-                                               rp:None,
-                                               types:~[]}),
-                              span:sp(0,6)})
+                   @ast::expr {
+                    id:1,
+                    node: ast::expr_path(ast::Path {
+                            span: sp(0, 6),
+                            global: true,
+                            segments: ~[
+                                ast::PathSegment {
+                                    identifier: str_to_ident("a"),
+                                    lifetime: None,
+                                    types: opt_vec::Empty,
+                                },
+                                ast::PathSegment {
+                                    identifier: str_to_ident("b"),
+                                    lifetime: None,
+                                    types: opt_vec::Empty,
+                                }
+                            ]
+                        }),
+                    span: sp(0, 6)
+                   })
     }
 
     #[should_fail]
@@ -420,32 +440,43 @@ fn sp (a: uint, b: uint) -> span {
 
     #[test] fn ret_expr() {
         assert_eq!(string_to_expr(@"return d"),
-                   @ast::expr{id:2,
-                              node:ast::expr_ret(
-                                  Some(@ast::expr{id:1,
-                                                  node:ast::expr_path(
-                                                       ast::Path{span:sp(7,8),
-                                                                 global:false,
-                                                                 idents:~[str_to_ident("d")],
-                                                                 rp:None,
-                                                                 types:~[]
-                                                                }),
-                                                  span:sp(7,8)})),
-                              span:sp(0,8)})
+                   @ast::expr{
+                    id:2,
+                    node:ast::expr_ret(Some(@ast::expr{
+                        id:1,
+                        node:ast::expr_path(ast::Path{
+                            span: sp(7, 8),
+                            global: false,
+                            segments: ~[
+                                ast::PathSegment {
+                                    identifier: str_to_ident("d"),
+                                    lifetime: None,
+                                    types: opt_vec::Empty,
+                                }
+                            ],
+                        }),
+                        span:sp(7,8)
+                    })),
+                    span:sp(0,8)
+                   })
     }
 
     #[test] fn parse_stmt_1 () {
         assert_eq!(string_to_stmt(@"b;"),
                    @spanned{
-                       node: ast::stmt_expr(@ast::expr{
+                       node: ast::stmt_expr(@ast::expr {
                            id: 1,
-                           node: ast::expr_path(
-                                ast::Path{
-                                   span:sp(0,1),
-                                   global:false,
-                                   idents:~[str_to_ident("b")],
-                                   rp:None,
-                                   types: ~[]}),
+                           node: ast::expr_path(ast::Path {
+                               span:sp(0,1),
+                               global:false,
+                               segments: ~[
+                                ast::PathSegment {
+                                    identifier: str_to_ident("b"),
+                                    lifetime: None,
+                                    types: opt_vec::Empty,
+                                }
+                               ],
+                            }),
                            span: sp(0,1)},
                                             2), // fixme
                        span: sp(0,1)})
@@ -460,49 +491,24 @@ fn parser_done(p: Parser){
         let parser = string_to_parser(@"b");
         assert_eq!(parser.parse_pat(),
                    @ast::pat{id:1, // fixme
-                             node: ast::pat_ident(ast::bind_infer,
-                                                   ast::Path{
-                                                      span:sp(0,1),
-                                                      global:false,
-                                                      idents:~[str_to_ident("b")],
-                                                      rp: None,
-                                                      types: ~[]},
-                                                  None // no idea
-                                                 ),
+                             node: ast::pat_ident(
+                                ast::bind_infer,
+                                ast::Path {
+                                    span:sp(0,1),
+                                    global:false,
+                                    segments: ~[
+                                        ast::PathSegment {
+                                            identifier: str_to_ident("b"),
+                                            lifetime: None,
+                                            types: opt_vec::Empty,
+                                        }
+                                    ],
+                                },
+                                None /* no idea */),
                              span: sp(0,1)});
         parser_done(parser);
     }
 
-    #[test] fn parse_arg () {
-        let parser = string_to_parser(@"b : int");
-        assert_eq!(parser.parse_arg_general(true),
-                   ast::arg{
-                       is_mutbl: false,
-                       ty: ast::Ty{id:3, // fixme
-                                    node: ast::ty_path(ast::Path{
-                                        span:sp(4,4), // this is bizarre...
-                                        // check this in the original parser?
-                                        global:false,
-                                        idents:~[str_to_ident("int")],
-                                        rp: None,
-                                        types: ~[]},
-                                                       None, 2),
-                                    span:sp(4,7)},
-                       pat: @ast::pat{id:1,
-                                      node: ast::pat_ident(ast::bind_infer,
-                                                            ast::Path{
-                                                               span:sp(0,1),
-                                                               global:false,
-                                                               idents:~[str_to_ident("b")],
-                                                               rp: None,
-                                                               types: ~[]},
-                                                           None // no idea
-                                                          ),
-                                      span: sp(0,1)},
-                       id: 4 // fixme
-                   })
-    }
-
     // check the contents of the tt manually:
     #[test] fn parse_fundecl () {
         // this test depends on the intern order of "fn" and "int", and on the
@@ -519,23 +525,37 @@ fn parser_done(p: Parser){
                                                 node: ast::ty_path(ast::Path{
                                         span:sp(10,13),
                                         global:false,
-                                        idents:~[str_to_ident("int")],
-                                        rp: None,
-                                        types: ~[]},
-                                                       None, 2),
-                                                span:sp(10,13)},
-                                    pat: @ast::pat{id:1, // fixme
-                                                   node: ast::pat_ident(
-                                                       ast::bind_infer,
-                                                       ast::Path{
-                                                           span:sp(6,7),
-                                                           global:false,
-                                                           idents:~[str_to_ident("b")],
-                                                           rp: None,
-                                                           types: ~[]},
-                                                       None // no idea
-                                                   ),
-                                                  span: sp(6,7)},
+                                        segments: ~[
+                                            ast::PathSegment {
+                                                identifier:
+                                                    str_to_ident("int"),
+                                                lifetime: None,
+                                                types: opt_vec::Empty,
+                                            }
+                                        ],
+                                        }, None, 2),
+                                        span:sp(10,13)
+                                    },
+                                    pat: @ast::pat {
+                                        id:1, // fixme
+                                        node: ast::pat_ident(
+                                            ast::bind_infer,
+                                            ast::Path {
+                                                span:sp(6,7),
+                                                global:false,
+                                                segments: ~[
+                                                    ast::PathSegment {
+                                                        identifier:
+                                                            str_to_ident("b"),
+                                                        lifetime: None,
+                                                        types: opt_vec::Empty,
+                                                    }
+                                                ],
+                                            },
+                                            None // no idea
+                                        ),
+                                        span: sp(6,7)
+                                    },
                                     id: 4 // fixme
                                 }],
                                 output: ast::Ty{id:5, // fixme
@@ -558,9 +578,18 @@ fn parser_done(p: Parser){
                                                       ast::Path{
                                                         span:sp(17,18),
                                                         global:false,
-                                                        idents:~[str_to_ident("b")],
-                                                        rp:None,
-                                                        types: ~[]}),
+                                                        segments: ~[
+                                                            ast::PathSegment {
+                                                                identifier:
+                                                                str_to_ident(
+                                                                    "b"),
+                                                                lifetime:
+                                                                    None,
+                                                                types:
+                                                                opt_vec::Empty
+                                                            }
+                                                        ],
+                                                      }),
                                                 span: sp(17,18)},
                                                                  7), // fixme
                                             span: sp(17,18)}],
index 989a796cbc9127f800b01d8f9ff4cb1d1e18dcdb..ab1bde3a3b9eb357c0089d832c353ff9121e43d9 100644 (file)
@@ -53,7 +53,6 @@ pub enum ObsoleteSyntax {
     ObsoleteMode,
     ObsoleteImplicitSelf,
     ObsoleteLifetimeNotation,
-    ObsoleteConstManagedPointer,
     ObsoletePurity,
     ObsoleteStaticMethod,
     ObsoleteConstItem,
@@ -65,6 +64,7 @@ pub enum ObsoleteSyntax {
     ObsoleteUnsafeExternFn,
     ObsoletePrivVisibility,
     ObsoleteTraitFuncVisibility,
+    ObsoleteConstPointer,
 }
 
 impl to_bytes::IterBytes for ObsoleteSyntax {
@@ -201,10 +201,6 @@ fn obsolete(&self, sp: span, kind: ObsoleteSyntax) {
                 "instead of `&foo/bar`, write `&'foo bar`; instead of \
                  `bar/&foo`, write `&bar<'foo>"
             ),
-            ObsoleteConstManagedPointer => (
-                "const `@` pointer",
-                "instead of `@const Foo`, write `@Foo`"
-            ),
             ObsoletePurity => (
                 "pure function",
                 "remove `pure`"
@@ -255,6 +251,11 @@ fn obsolete(&self, sp: span, kind: ObsoleteSyntax) {
                 "visibility not necessary",
                 "trait functions inherit the visibility of the trait itself"
             ),
+            ObsoleteConstPointer => (
+                "const pointer",
+                "instead of `&const Foo` or `@const Foo`, write `&Foo` or \
+                 `@Foo`"
+            ),
         };
 
         self.report(sp, kind, kind_str, desc);
index 6db9828fa252c102fae7f605a40d4603b5e79f36..ea7a7540e363dce1a3f520a3e090e54f57bd31b2 100644 (file)
@@ -38,7 +38,7 @@
 use ast::{item_enum, item_fn, item_foreign_mod, item_impl};
 use ast::{item_mac, item_mod, item_struct, item_trait, item_ty, lit, lit_};
 use ast::{lit_bool, lit_float, lit_float_unsuffixed, lit_int};
-use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local, m_const};
+use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local};
 use ast::{m_imm, m_mutbl, mac_, mac_invoc_tt, matcher, match_nonterminal};
 use ast::{match_seq, match_tok, method, mt, mul, mutability};
 use ast::{named_field, neg, NodeId, noreturn, not, pat, pat_box, pat_enum};
@@ -97,6 +97,37 @@ enum restriction {
 type arg_or_capture_item = Either<arg, ()>;
 type item_info = (ident, item_, Option<~[Attribute]>);
 
+/// How to parse a path. There are four different kinds of paths, all of which
+/// are parsed somewhat differently.
+#[deriving(Eq)]
+pub enum PathParsingMode {
+    /// A path with no type parameters; e.g. `foo::bar::Baz`
+    NoTypesAllowed,
+    /// A path with a lifetime and type parameters, with no double colons
+    /// before the type parameters; e.g. `foo::bar<'self>::Baz<T>`
+    LifetimeAndTypesWithoutColons,
+    /// A path with a lifetime and type parameters with double colons before
+    /// the type parameters; e.g. `foo::bar::<'self>::Baz::<T>`
+    LifetimeAndTypesWithColons,
+    /// A path with a lifetime and type parameters with bounds before the last
+    /// set of type parameters only; e.g. `foo::bar<'self>::Baz:X+Y<T>` This
+    /// form does not use extra double colons.
+    LifetimeAndTypesAndBounds,
+}
+
+/// A pair of a path segment and group of type parameter bounds. (See `ast.rs`
+/// for the definition of a path segment.)
+struct PathSegmentAndBoundSet {
+    segment: ast::PathSegment,
+    bound_set: Option<OptVec<TyParamBound>>,
+}
+
+/// A path paired with optional type bounds.
+struct PathAndBounds {
+    path: ast::Path,
+    bounds: Option<OptVec<TyParamBound>>,
+}
+
 pub enum item_or_view_item {
     // Indicates a failure to parse any kind of item. The attributes are
     // returned.
@@ -1115,7 +1146,10 @@ pub fn parse_ty(&self, _: bool) -> Ty {
         } else if *self.token == token::MOD_SEP
             || is_ident_or_path(self.token) {
             // NAMED TYPE
-            let (path, bounds) = self.parse_type_path();
+            let PathAndBounds {
+                path,
+                bounds
+            } = self.parse_path(LifetimeAndTypesAndBounds);
             ty_path(path, bounds, self.get_id())
         } else {
             self.fatal(fmt!("expected type, found token %?",
@@ -1160,9 +1194,6 @@ pub fn parse_box_or_uniq_pointee(&self,
         if mt.mutbl != m_imm && sigil == OwnedSigil {
             self.obsolete(*self.last_span, ObsoleteMutOwnedPointer);
         }
-        if mt.mutbl == m_const && sigil == ManagedSigil {
-            self.obsolete(*self.last_span, ObsoleteConstManagedPointer);
-        }
 
         ctor(mt)
     }
@@ -1339,139 +1370,155 @@ pub fn parse_literal_maybe_minus(&self) -> @expr {
         }
     }
 
-    // parse a path into a vector of idents, whether the path starts
-    // with ::, and a span.
-    pub fn parse_path(&self) -> (~[ast::ident],bool,span) {
+    /// Parses a path and optional type parameter bounds, depending on the
+    /// mode. The `mode` parameter determines whether lifetimes, types, and/or
+    /// bounds are permitted and whether `::` must precede type parameter
+    /// groups.
+    pub fn parse_path(&self, mode: PathParsingMode) -> PathAndBounds {
+        // Check for a whole path...
+        let found = match *self.token {
+            INTERPOLATED(token::nt_path(_)) => Some(self.bump_and_get()),
+            _ => None,
+        };
+        match found {
+            Some(INTERPOLATED(token::nt_path(~path))) => {
+                return PathAndBounds {
+                    path: path,
+                    bounds: None,
+                }
+            }
+            _ => {}
+        }
+
         let lo = self.span.lo;
         let is_global = self.eat(&token::MOD_SEP);
-        let (ids,span{lo:_,hi,expn_info}) = self.parse_path_non_global();
-        (ids,is_global,span{lo:lo,hi:hi,expn_info:expn_info})
-    }
 
-    // parse a path beginning with an identifier into a vector of idents and a span
-    pub fn parse_path_non_global(&self) -> (~[ast::ident],span) {
-        let lo = self.span.lo;
-        let mut ids = ~[];
-        // must be at least one to begin:
-        ids.push(self.parse_ident());
+        // Parse any number of segments and bound sets. A segment is an
+        // identifier followed by an optional lifetime and a set of types.
+        // A bound set is a set of type parameter bounds.
+        let mut segments = ~[];
         loop {
+            // First, parse an identifier.
             match *self.token {
-                token::MOD_SEP => {
-                    let is_ident = do self.look_ahead(1) |t| {
-                        match *t {
-                            token::IDENT(*) => true,
-                            _ => false,
-                        }
-                    };
-                    if is_ident {
-                        self.bump();
-                        ids.push(self.parse_ident());
-                    } else {
-                        break
-                    }
-                }
-                _ => break
+                token::IDENT(*) => {}
+                _ => break,
             }
-        }
-        (ids, mk_sp(lo, self.last_span.hi))
-    }
+            let identifier = self.parse_ident();
 
-    // parse a path that doesn't have type parameters attached
-    pub fn parse_path_without_tps(&self) -> ast::Path {
-        maybe_whole!(deref self, nt_path);
-        let (ids,is_global,sp) = self.parse_path();
-        ast::Path { span: sp,
-                     global: is_global,
-                     idents: ids,
-                     rp: None,
-                     types: ~[] }
-    }
+            // Next, parse a colon and bounded type parameters, if applicable.
+            let bound_set = if mode == LifetimeAndTypesAndBounds {
+                self.parse_optional_ty_param_bounds()
+            } else {
+                None
+            };
 
-    pub fn parse_bounded_path_with_tps(&self, colons: bool,
-                                        before_tps: Option<&fn()>) -> ast::Path {
-        debug!("parse_path_with_tps(colons=%b)", colons);
+            // Parse the '::' before type parameters if it's required. If
+            // it is required and wasn't present, then we're done.
+            if mode == LifetimeAndTypesWithColons &&
+                    !self.eat(&token::MOD_SEP) {
+                segments.push(PathSegmentAndBoundSet {
+                    segment: ast::PathSegment {
+                        identifier: identifier,
+                        lifetime: None,
+                        types: opt_vec::Empty,
+                    },
+                    bound_set: bound_set
+                });
+                break
+            }
 
-        maybe_whole!(deref self, nt_path);
-        let lo = self.span.lo;
-        let path = self.parse_path_without_tps();
-        if colons && !self.eat(&token::MOD_SEP) {
-            return path;
-        }
-
-        // If the path might have bounds on it, they should be parsed before
-        // the parameters, e.g. module::TraitName:B1+B2<T>
-        before_tps.map_move(|callback| callback());
-
-        // Parse the (obsolete) trailing region parameter, if any, which will
-        // be written "foo/&x"
-        let rp_slash = {
-            if *self.token == token::BINOP(token::SLASH)
-                && self.look_ahead(1, |t| *t == token::BINOP(token::AND))
-            {
-                self.bump(); self.bump();
-                self.obsolete(*self.last_span, ObsoleteLifetimeNotation);
-                match *self.token {
-                    token::IDENT(sid, _) => {
-                        let span = self.span;
-                        self.bump();
-                        Some(ast::Lifetime {
-                            id: self.get_id(),
-                            span: *span,
-                            ident: sid
-                        })
+            // Parse the `<` before the lifetime and types, if applicable.
+            let (any_lifetime_or_types, optional_lifetime, types) =
+                    if mode != NoTypesAllowed && self.eat(&token::LT) {
+                // Parse an optional lifetime.
+                let optional_lifetime = match *self.token {
+                    token::LIFETIME(*) => Some(self.parse_lifetime()),
+                    _ => None,
+                };
+
+                // Parse type parameters.
+                let mut types = opt_vec::Empty;
+                let mut need_comma = optional_lifetime.is_some();
+                loop {
+                    // We're done if we see a `>`.
+                    match *self.token {
+                        token::GT | token::BINOP(token::SHR) => {
+                            self.expect_gt();
+                            break
+                        }
+                        _ => {} // Go on.
                     }
-                    _ => {
-                        self.fatal(fmt!("Expected a lifetime name"));
+
+                    if need_comma {
+                        self.expect(&token::COMMA)
+                    } else {
+                        need_comma = true
                     }
+
+                    types.push(self.parse_ty(false))
                 }
+
+                (true, optional_lifetime, types)
             } else {
-                None
-            }
-        };
+                (false, None, opt_vec::Empty)
+            };
 
-        // Parse any lifetime or type parameters which may appear:
-        let (lifetimes, tps) = self.parse_generic_values();
-        let hi = self.span.lo;
+            // Assemble and push the result.
+            segments.push(PathSegmentAndBoundSet {
+                segment: ast::PathSegment {
+                    identifier: identifier,
+                    lifetime: optional_lifetime,
+                    types: types,
+                },
+                bound_set: bound_set
+            });
 
-        let rp = match (&rp_slash, &lifetimes) {
-            (&Some(_), _) => rp_slash,
-            (&None, v) => {
-                if v.len() == 0 {
-                    None
-                } else if v.len() == 1 {
-                    Some(*v.get(0))
-                } else {
-                    self.fatal(fmt!("Expected at most one \
-                                     lifetime name (for now)"));
+            // We're done if we don't see a '::', unless the mode required
+            // a double colon to get here in the first place.
+            if !(mode == LifetimeAndTypesWithColons &&
+                    !any_lifetime_or_types) {
+                if !self.eat(&token::MOD_SEP) {
+                    break
                 }
             }
-        };
-
-        ast::Path {
-            span: mk_sp(lo, hi),
-            rp: rp,
-            types: tps,
-            .. path.clone()
         }
-    }
 
-    // parse a path optionally with type parameters. If 'colons'
-    // is true, then type parameters must be preceded by colons,
-    // as in a::t::<t1,t2>
-    pub fn parse_path_with_tps(&self, colons: bool) -> ast::Path {
-        self.parse_bounded_path_with_tps(colons, None)
-    }
+        // Assemble the span.
+        let span = mk_sp(lo, self.last_span.hi);
 
-    // Like the above, but can also parse kind bounds in the case of a
-    // path to be used as a type that might be a trait.
-    pub fn parse_type_path(&self) -> (ast::Path, Option<OptVec<TyParamBound>>) {
+        // Assemble the path segments.
+        let mut path_segments = ~[];
         let mut bounds = None;
-        let path = self.parse_bounded_path_with_tps(false, Some(|| {
-            // Note: this closure might not even get called in the case of a
-            // macro-generated path. But that's the macro parser's job.
-            bounds = self.parse_optional_ty_param_bounds();
-        }));
-        (path, bounds)
+        let last_segment_index = segments.len() - 1;
+        for (i, segment_and_bounds) in segments.move_iter().enumerate() {
+            let PathSegmentAndBoundSet {
+                segment: segment,
+                bound_set: bound_set
+            } = segment_and_bounds;
+            path_segments.push(segment);
+
+            if bound_set.is_some() {
+                if i != last_segment_index {
+                    self.span_err(span,
+                                  "type parameter bounds are allowed only \
+                                   before the last segment in a path")
+                }
+
+                bounds = bound_set
+            }
+        }
+
+        // Assemble the result.
+        let path_and_bounds = PathAndBounds {
+            path: ast::Path {
+                span: span,
+                global: is_global,
+                segments: path_segments,
+            },
+            bounds: bounds,
+        };
+
+        path_and_bounds
     }
 
     /// parses 0 or 1 lifetime
@@ -1575,7 +1622,8 @@ pub fn parse_mutability(&self) -> mutability {
         if self.eat_keyword(keywords::Mut) {
             m_mutbl
         } else if self.eat_keyword(keywords::Const) {
-            m_const
+            self.obsolete(*self.last_span, ObsoleteConstPointer);
+            m_imm
         } else {
             m_imm
         }
@@ -1734,7 +1782,7 @@ pub fn parse_bottom_expr(&self) -> @expr {
         } else if *self.token == token::LBRACKET {
             self.bump();
             let mutbl = self.parse_mutability();
-            if mutbl == m_mutbl || mutbl == m_const {
+            if mutbl == m_mutbl {
                 self.obsolete(*self.last_span, ObsoleteMutVector);
             }
 
@@ -1798,7 +1846,7 @@ pub fn parse_bottom_expr(&self) -> @expr {
         } else if *self.token == token::MOD_SEP ||
                 is_ident(&*self.token) && !self.is_keyword(keywords::True) &&
                 !self.is_keyword(keywords::False) {
-            let pth = self.parse_path_with_tps(true);
+            let pth = self.parse_path(LifetimeAndTypesWithColons).path;
 
             // `!`, as an operator, is prefix, so we know this isn't that
             if *self.token == token::NOT {
@@ -2189,10 +2237,6 @@ pub fn parse_prefix_expr(&self) -> @expr {
           token::AT => {
             self.bump();
             let m = self.parse_mutability();
-            if m == m_const {
-                self.obsolete(*self.last_span, ObsoleteConstManagedPointer);
-            }
-
             let e = self.parse_prefix_expr();
             hi = e.span.hi;
             // HACK: turn @[...] into a @-evec
@@ -2893,7 +2937,8 @@ pub fn parse_pat(&self) -> @pat {
             let val = self.parse_literal_maybe_minus();
             if self.eat(&token::DOTDOT) {
                 let end = if is_ident_or_path(tok) {
-                    let path = self.parse_path_with_tps(true);
+                    let path = self.parse_path(LifetimeAndTypesWithColons)
+                                   .path;
                     let hi = self.span.hi;
                     self.mk_expr(lo, hi, expr_path(path))
                 } else {
@@ -2922,7 +2967,7 @@ pub fn parse_pat(&self) -> @pat {
                 let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
                 pat = pat_range(start, end);
             } else if is_plain_ident(&*self.token) && !can_be_enum_or_struct {
-                let name = self.parse_path_without_tps();
+                let name = self.parse_path(NoTypesAllowed).path;
                 let sub;
                 if self.eat(&token::AT) {
                     // parse foo @ pat
@@ -2934,7 +2979,8 @@ pub fn parse_pat(&self) -> @pat {
                 pat = pat_ident(bind_infer, name, sub);
             } else {
                 // parse an enum pat
-                let enum_path = self.parse_path_with_tps(true);
+                let enum_path = self.parse_path(LifetimeAndTypesWithColons)
+                                    .path;
                 match *self.token {
                     token::LBRACE => {
                         self.bump();
@@ -2970,7 +3016,7 @@ pub fn parse_pat(&self) -> @pat {
                             }
                           },
                           _ => {
-                              if enum_path.idents.len()==1u {
+                              if enum_path.segments.len() == 1 {
                                   // it could still be either an enum
                                   // or an identifier pattern, resolve
                                   // will sort it out:
@@ -3005,7 +3051,7 @@ fn parse_pat_ident(&self,
                             "expected identifier, found path");
         }
         // why a path here, and not just an identifier?
-        let name = self.parse_path_without_tps();
+        let name = self.parse_path(NoTypesAllowed).path;
         let sub = if self.eat(&token::AT) {
             Some(self.parse_pat())
         } else {
@@ -3122,7 +3168,7 @@ fn check_expected_item(p: &Parser, found_attrs: bool) {
 
             // Potential trouble: if we allow macros with paths instead of
             // idents, we'd need to look ahead past the whole path here...
-            let pth = self.parse_path_without_tps();
+            let pth = self.parse_path(NoTypesAllowed).path;
             self.bump();
 
             let id = if *self.token == token::LPAREN {
@@ -3811,7 +3857,7 @@ fn parse_item_impl(&self, visibility: ast::visibility) -> item_info {
     // parse a::B<~str,int>
     fn parse_trait_ref(&self) -> trait_ref {
         ast::trait_ref {
-            path: self.parse_path_with_tps(false),
+            path: self.parse_path(LifetimeAndTypesWithoutColons).path,
             ref_id: self.get_id(),
         }
     }
@@ -4727,7 +4773,7 @@ fn parse_macro_use_or_failure(
             }
 
             // item macro.
-            let pth = self.parse_path_without_tps();
+            let pth = self.parse_path(NoTypesAllowed).path;
             self.expect(&token::NOT);
 
             // a 'special' identifier (like what `macro_rules!` uses)
@@ -4811,11 +4857,17 @@ fn parse_view_path(&self) -> @view_path {
                 let id = self.parse_ident();
                 path.push(id);
             }
-            let path = ast::Path { span: mk_sp(lo, self.span.hi),
-                                    global: false,
-                                    idents: path,
-                                    rp: None,
-                                    types: ~[] };
+            let path = ast::Path {
+                span: mk_sp(lo, self.span.hi),
+                global: false,
+                segments: path.move_iter().map(|identifier| {
+                    ast::PathSegment {
+                        identifier: identifier,
+                        lifetime: None,
+                        types: opt_vec::Empty,
+                    }
+                }).collect()
+            };
             return @spanned(lo, self.span.hi,
                             view_path_simple(first_ident,
                                              path,
@@ -4841,11 +4893,17 @@ fn parse_view_path(&self) -> @view_path {
                         seq_sep_trailing_allowed(token::COMMA),
                         |p| p.parse_path_list_ident()
                     );
-                    let path = ast::Path { span: mk_sp(lo, self.span.hi),
-                                            global: false,
-                                            idents: path,
-                                            rp: None,
-                                            types: ~[] };
+                    let path = ast::Path {
+                        span: mk_sp(lo, self.span.hi),
+                        global: false,
+                        segments: path.move_iter().map(|identifier| {
+                            ast::PathSegment {
+                                identifier: identifier,
+                                lifetime: None,
+                                types: opt_vec::Empty,
+                            }
+                        }).collect()
+                    };
                     return @spanned(lo, self.span.hi,
                                  view_path_list(path, idents, self.get_id()));
                   }
@@ -4853,11 +4911,17 @@ fn parse_view_path(&self) -> @view_path {
                   // foo::bar::*
                   token::BINOP(token::STAR) => {
                     self.bump();
-                    let path = ast::Path { span: mk_sp(lo, self.span.hi),
-                                            global: false,
-                                            idents: path,
-                                            rp: None,
-                                            types: ~[] };
+                    let path = ast::Path {
+                        span: mk_sp(lo, self.span.hi),
+                        global: false,
+                        segments: path.move_iter().map(|identifier| {
+                            ast::PathSegment {
+                                identifier: identifier,
+                                lifetime: None,
+                                types: opt_vec::Empty,
+                            }
+                        }).collect()
+                    };
                     return @spanned(lo, self.span.hi,
                                     view_path_glob(path, self.get_id()));
                   }
@@ -4869,11 +4933,17 @@ fn parse_view_path(&self) -> @view_path {
           _ => ()
         }
         let last = path[path.len() - 1u];
-        let path = ast::Path { span: mk_sp(lo, self.span.hi),
-                                global: false,
-                                idents: path,
-                                rp: None,
-                                types: ~[] };
+        let path = ast::Path {
+            span: mk_sp(lo, self.span.hi),
+            global: false,
+            segments: path.move_iter().map(|identifier| {
+                ast::PathSegment {
+                    identifier: identifier,
+                    lifetime: None,
+                    types: opt_vec::Empty,
+                }
+            }).collect()
+        };
         return @spanned(lo,
                         self.last_span.hi,
                         view_path_simple(last, path, self.get_id()));
index f7714d4e8365a0573c18eb8c2e061eec4217497c..9c31d982590eafd4c943bcd3dc55575239711d9e 100644 (file)
@@ -386,7 +386,6 @@ pub fn print_type(s: @ps, ty: &ast::Ty) {
         word(s.s, "[");
         match mt.mutbl {
           ast::m_mutbl => word_space(s, "mut"),
-          ast::m_const => word_space(s, "const"),
           ast::m_imm => ()
         }
         print_type(s, mt.ty);
@@ -429,7 +428,6 @@ pub fn print_type(s: @ps, ty: &ast::Ty) {
         word(s.s, "[");
         match mt.mutbl {
             ast::m_mutbl => word_space(s, "mut"),
-            ast::m_const => word_space(s, "const"),
             ast::m_imm => ()
         }
         print_type(s, mt.ty);
@@ -1508,34 +1506,52 @@ pub fn print_for_decl(s: @ps, loc: &ast::Local, coll: &ast::expr) {
     print_expr(s, coll);
 }
 
-fn print_path_(s: @ps, path: &ast::Path, colons_before_params: bool,
+fn print_path_(s: @ps,
+               path: &ast::Path,
+               colons_before_params: bool,
                opt_bounds: &Option<OptVec<ast::TyParamBound>>) {
     maybe_print_comment(s, path.span.lo);
-    if path.global { word(s.s, "::"); }
-    let mut first = true;
-    for id in path.idents.iter() {
-        if first { first = false; } else { word(s.s, "::"); }
-        print_ident(s, *id);
+    if path.global {
+        word(s.s, "::");
     }
-    do opt_bounds.map |bounds| {
-        print_bounds(s, bounds, true);
-    };
-    if path.rp.is_some() || !path.types.is_empty() {
-        if colons_before_params { word(s.s, "::"); }
 
-        if path.rp.is_some() || !path.types.is_empty() {
+    let mut first = true;
+    for (i, segment) in path.segments.iter().enumerate() {
+        if first {
+            first = false
+        } else {
+            word(s.s, "::")
+        }
+
+        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 colons_before_params {
+                word(s.s, "::")
+            }
             word(s.s, "<");
 
-            for r in path.rp.iter() {
-                print_lifetime(s, r);
-                if !path.types.is_empty() {
-                    word_space(s, ",");
+            for lifetime in segment.lifetime.iter() {
+                print_lifetime(s, lifetime);
+                if !segment.types.is_empty() {
+                    word_space(s, ",")
                 }
             }
 
-            commasep(s, inconsistent, path.types, print_type);
+            commasep(s,
+                     inconsistent,
+                     segment.types.map_to_vec(|t| (*t).clone()),
+                     print_type);
 
-            word(s.s, ">");
+            word(s.s, ">")
         }
     }
 }
@@ -1826,7 +1842,7 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) {
 pub fn print_view_path(s: @ps, vp: &ast::view_path) {
     match vp.node {
       ast::view_path_simple(ident, ref path, _) => {
-        if path.idents[path.idents.len()-1u] != ident {
+        if path.segments.last().identifier != ident {
             print_ident(s, ident);
             space(s.s);
             word_space(s, "=");
@@ -1887,7 +1903,6 @@ pub fn print_view_item(s: @ps, item: &ast::view_item) {
 pub fn print_mutability(s: @ps, mutbl: ast::mutability) {
     match mutbl {
       ast::m_mutbl => word_nbsp(s, "mut"),
-      ast::m_const => word_nbsp(s, "const"),
       ast::m_imm => {/* nothing */ }
     }
 }
@@ -1907,8 +1922,9 @@ pub fn print_arg(s: @ps, input: &ast::arg) {
       _ => {
         match input.pat.node {
             ast::pat_ident(_, ref path, _) if
-                path.idents.len() == 1 &&
-                path.idents[0] == parse::token::special_idents::invalid => {
+                path.segments.len() == 1 &&
+                path.segments[0].identifier ==
+                    parse::token::special_idents::invalid => {
                 // Do nothing.
             }
             _ => {
index b78bf41bc30f6027f6db2f6dae4fef369be32c0b..79304aebea2d47afb94f0f9b31afe0781ab1ec1c 100644 (file)
@@ -322,8 +322,10 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
 }
 
 pub fn walk_path<E:Clone, V:Visitor<E>>(visitor: &mut V, path: &Path, env: E) {
-    for typ in path.types.iter() {
-        visitor.visit_ty(typ, env.clone())
+    for segment in path.segments.iter() {
+        for typ in segment.types.iter() {
+            visitor.visit_ty(typ, env.clone())
+        }
     }
 }
 
index dfae9c3e958dc086d9c0ab068cd76d196c95a433..ef2bcd134164adcaa072dcb56e62b737fdcb075e 160000 (submodule)
--- a/src/libuv
+++ b/src/libuv
@@ -1 +1 @@
-Subproject commit dfae9c3e958dc086d9c0ab068cd76d196c95a433
+Subproject commit ef2bcd134164adcaa072dcb56e62b737fdcb075e
index f718cac963470402a7844e36dfa34f1ff188fc36..857fe91c9141b85c1603cedf69433ffa78317eba 100644 (file)
@@ -54,7 +54,7 @@ First four arguments:
         anyhow.
 */
 
-#if defined(__APPLE__) || defined(_WIN32)
+#if defined(__APPLE__)
 #define SWAP_REGISTERS _swap_registers
 #else
 #define SWAP_REGISTERS swap_registers
@@ -86,16 +86,40 @@ SWAP_REGISTERS:
         mov %r14, (RUSTRT_R14*8)(ARG0)
         mov %r15, (RUSTRT_R15*8)(ARG0)
 
+#if defined(__MINGW32__) || defined(_WINDOWS)
+        mov %rdi, (RUSTRT_RDI*8)(ARG0)
+        mov %rsi, (RUSTRT_RSI*8)(ARG0)
+
+        // Save stack range
+        mov %gs:0x08, %r8
+        mov %r8, (RUSTRT_ST1*8)(ARG0)
+        mov %gs:0x10, %r9
+        mov %r9, (RUSTRT_ST2*8)(ARG0)
+#endif
+
         // Save 0th argument register:
         mov ARG0, (RUSTRT_ARG0*8)(ARG0)
 
         // Save non-volatile XMM registers:
+#if defined(__MINGW32__) || defined(_WINDOWS)
+        movapd %xmm6, (RUSTRT_XMM6*8)(ARG0)
+        movapd %xmm7, (RUSTRT_XMM7*8)(ARG0)
+        movapd %xmm8, (RUSTRT_XMM8*8)(ARG0)
+        movapd %xmm9, (RUSTRT_XMM9*8)(ARG0)
+        movapd %xmm10, (RUSTRT_XMM10*8)(ARG0)
+        movapd %xmm11, (RUSTRT_XMM11*8)(ARG0)
+        movapd %xmm12, (RUSTRT_XMM12*8)(ARG0)
+        movapd %xmm13, (RUSTRT_XMM13*8)(ARG0)
+        movapd %xmm14, (RUSTRT_XMM14*8)(ARG0)
+        movapd %xmm15, (RUSTRT_XMM15*8)(ARG0)
+#else
         movapd %xmm0, (RUSTRT_XMM0*8)(ARG0)
         movapd %xmm1, (RUSTRT_XMM1*8)(ARG0)
         movapd %xmm2, (RUSTRT_XMM2*8)(ARG0)
         movapd %xmm3, (RUSTRT_XMM3*8)(ARG0)
         movapd %xmm4, (RUSTRT_XMM4*8)(ARG0)
         movapd %xmm5, (RUSTRT_XMM5*8)(ARG0)
+#endif
 
         // Restore non-volatile integer registers:
         //   (including RSP)
@@ -107,16 +131,40 @@ SWAP_REGISTERS:
         mov (RUSTRT_R14*8)(ARG1), %r14
         mov (RUSTRT_R15*8)(ARG1), %r15
 
+#if defined(__MINGW32__) || defined(_WINDOWS)
+        mov (RUSTRT_RDI*8)(ARG1), %rdi
+        mov (RUSTRT_RSI*8)(ARG1), %rsi
+
+        // Restore stack range
+        mov (RUSTRT_ST1*8)(ARG1), %r8
+        mov %r8, %gs:0x08
+        mov (RUSTRT_ST2*8)(ARG1), %r9
+        mov %r9, %gs:0x10
+#endif
+
         // Restore 0th argument register:
         mov (RUSTRT_ARG0*8)(ARG1), ARG0
 
         // Restore non-volatile XMM registers:
+#if defined(__MINGW32__) || defined(_WINDOWS)
+        movapd (RUSTRT_XMM6*8)(ARG1), %xmm6
+        movapd (RUSTRT_XMM7*8)(ARG1), %xmm7
+        movapd (RUSTRT_XMM8*8)(ARG1), %xmm8
+        movapd (RUSTRT_XMM9*8)(ARG1), %xmm9
+        movapd (RUSTRT_XMM10*8)(ARG1), %xmm10
+        movapd (RUSTRT_XMM11*8)(ARG1), %xmm11
+        movapd (RUSTRT_XMM12*8)(ARG1), %xmm12
+        movapd (RUSTRT_XMM13*8)(ARG1), %xmm13
+        movapd (RUSTRT_XMM14*8)(ARG1), %xmm14
+        movapd (RUSTRT_XMM15*8)(ARG1), %xmm15
+#else
         movapd (RUSTRT_XMM0*8)(ARG1), %xmm0
         movapd (RUSTRT_XMM1*8)(ARG1), %xmm1
         movapd (RUSTRT_XMM2*8)(ARG1), %xmm2
         movapd (RUSTRT_XMM3*8)(ARG1), %xmm3
         movapd (RUSTRT_XMM4*8)(ARG1), %xmm4
         movapd (RUSTRT_XMM5*8)(ARG1), %xmm5
+#endif
 
         // Jump to the instruction pointer
         // found in regs:
index d4bc37fee957d3f6ac62b43e4c6b7369693a3d5f..dbee5bcdc90a3222e518d9d6fee72391c3a4de82 100644 (file)
 
         .text
 
-#if defined(__APPLE__) || defined(_WIN32)
+#if defined(__APPLE__)
 .globl ___morestack
 .private_extern MORESTACK
 ___morestack:
+#elif defined(_WIN32)
+.globl __morestack
+__morestack:
 #else
 .globl __morestack
 .hidden __morestack
index 9d16afc0a1b3546cca2664f4b1d9acd0e6dc568a..b718c9121c57b8a3d30143c3f0c16508a49ce384 100644 (file)
@@ -11,7 +11,7 @@
 
 .text
 
-#if defined(__APPLE__) || defined(_WIN32)
+#if defined(__APPLE__)
 #define UPCALL_NEW_STACK        _upcall_new_stack
 #define UPCALL_DEL_STACK        _upcall_del_stack
 #define MORESTACK               ___morestack
index 1aca452df108b84e7fb0ccb77c54127e5d7c537c..cff47ac378af0e192a739b9382206865263ed52c 100644 (file)
 #define RUSTRT_R14   6
 #define RUSTRT_R15   7
 #define RUSTRT_IP    8
-// Not used, just padding
-#define RUSTRT_XXX   9
-#define RUSTRT_XMM0 10
-#define RUSTRT_XMM1 12
-#define RUSTRT_XMM2 14
-#define RUSTRT_XMM3 16
-#define RUSTRT_XMM4 18
-#define RUSTRT_XMM5 20
-#define RUSTRT_MAX  22
+#if defined(__MINGW32__) || defined(_WINDOWS)
+    #define RUSTRT_RDI   9
+    #define RUSTRT_RSI   10
+    #define RUSTRT_ST1   11
+    #define RUSTRT_ST2   12
+    #define RUSTRT_XMM6  14
+    #define RUSTRT_XMM7  16
+    #define RUSTRT_XMM8  18
+    #define RUSTRT_XMM9  20
+    #define RUSTRT_XMM10 22
+    #define RUSTRT_XMM11 24
+    #define RUSTRT_XMM12 26
+    #define RUSTRT_XMM13 28
+    #define RUSTRT_XMM14 30
+    #define RUSTRT_XMM15 32
+    #define RUSTRT_MAX   34
+#else
+    // Not used, just padding
+    #define RUSTRT_XXX   9
+    #define RUSTRT_XMM0 10
+    #define RUSTRT_XMM1 12
+    #define RUSTRT_XMM2 14
+    #define RUSTRT_XMM3 16
+    #define RUSTRT_XMM4 18
+    #define RUSTRT_XMM5 20
+    #define RUSTRT_MAX  22
+#endif
 
 // ARG0 is the register in which the first argument goes.
 // Naturally this depends on your operating system.
index bf011f4d01976aee960105858f1805aafa28e29b..764927759fe684bf17ca0996160340d21b5d5401 100644 (file)
@@ -43,6 +43,10 @@ extern "C" CDECL ALWAYS_INLINE uintptr_t get_sp_limit() {
     asm volatile (
         "movq %%fs:24, %0"
         : "=r"(limit));
+#elif defined(_WIN64)
+    asm volatile (
+        "movq %%gs:0x28, %0"
+        : "=r"(limit));
 #endif
 
     return limit;
@@ -65,6 +69,10 @@ extern "C" CDECL ALWAYS_INLINE void record_sp_limit(void *limit) {
     asm volatile (
         "movq %0, %%fs:24"
         :: "r"(limit));
+#elif defined(_WIN64)
+    asm volatile (
+        "movq %0, %%gs:0x28"
+        :: "r"(limit));
 #endif
 }
 
index 0d58d4dae922ff430ee8aae82ae9380d0cbaa9a5..4a34312c6d4a5582cfb6b7bcc64dfccbb10ddfe4 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 
-#include "sync/sync.h"
 #include "memory_region.h"
 
 #if RUSTRT_TRACK_ALLOCATIONS >= 3
@@ -42,30 +41,25 @@ inline void memory_region::maybe_print_backtrace(const alloc_header *header) con
 #   endif
 }
 
-memory_region::memory_region(bool synchronized,
-                             bool detailed_leaks,
+memory_region::memory_region(bool detailed_leaks,
                              bool poison_on_free) :
     _parent(NULL), _live_allocations(0),
     _detailed_leaks(detailed_leaks),
-    _poison_on_free(poison_on_free),
-    _synchronized(synchronized) {
+    _poison_on_free(poison_on_free) {
 }
 
 memory_region::memory_region(memory_region *parent) :
     _parent(parent), _live_allocations(0),
     _detailed_leaks(parent->_detailed_leaks),
-    _poison_on_free(parent->_poison_on_free),
-    _synchronized(parent->_synchronized) {
+    _poison_on_free(parent->_poison_on_free) {
 }
 
 void memory_region::add_alloc() {
-    //_live_allocations++;
-    sync::increment(_live_allocations);
+    _live_allocations++;
 }
 
 void memory_region::dec_alloc() {
-    //_live_allocations--;
-    sync::decrement(_live_allocations);
+    _live_allocations--;
 }
 
 void memory_region::free(void *mem) {
@@ -112,7 +106,6 @@ memory_region::realloc(void *mem, size_t orig_size) {
 #   endif
 
 #   if RUSTRT_TRACK_ALLOCATIONS >= 2
-    if (_synchronized) { _lock.lock(); }
     if (_allocation_list[newMem->index] != alloc) {
         printf("at index %d, found %p, expected %p\n",
                alloc->index, _allocation_list[alloc->index], alloc);
@@ -125,7 +118,6 @@ memory_region::realloc(void *mem, size_t orig_size) {
         // printf("realloc: stored %p at index %d, replacing %p\n",
         //        newMem, index, mem);
     }
-    if (_synchronized) { _lock.unlock(); }
 #   endif
 
     return get_data(newMem);
@@ -160,9 +152,7 @@ memory_region::malloc(size_t size, const char *tag) {
 }
 
 memory_region::~memory_region() {
-    if (_synchronized) { _lock.lock(); }
     if (_live_allocations == 0 && !_detailed_leaks) {
-        if (_synchronized) { _lock.unlock(); }
         return;
     }
     char msg[128];
@@ -193,7 +183,6 @@ memory_region::~memory_region() {
         fprintf(stderr, "%s\n", msg);
         assert(false);
     }
-    if (_synchronized) { _lock.unlock(); }
 }
 
 void
@@ -204,7 +193,6 @@ memory_region::release_alloc(void *mem) {
 #   endif
 
 #   if RUSTRT_TRACK_ALLOCATIONS >= 2
-    if (_synchronized) { _lock.lock(); }
     if (((size_t) alloc->index) >= _allocation_list.size()) {
         printf("free: ptr 0x%" PRIxPTR " (%s) index %d is beyond allocation_list of size %zu\n",
                (uintptr_t) get_data(alloc), alloc->tag, alloc->index, _allocation_list.size());
@@ -222,7 +210,6 @@ memory_region::release_alloc(void *mem) {
         _allocation_list[alloc->index] = NULL;
         alloc->index = -1;
     }
-    if (_synchronized) { _lock.unlock(); }
 #   endif
 
     dec_alloc();
@@ -236,9 +223,7 @@ memory_region::claim_alloc(void *mem) {
 #   endif
 
 #   if RUSTRT_TRACK_ALLOCATIONS >= 2
-    if (_synchronized) { _lock.lock(); }
     alloc->index = _allocation_list.append(alloc);
-    if (_synchronized) { _lock.unlock(); }
 #   endif
 
 #   if RUSTRT_TRACK_ALLOCATIONS >= 3
index b833b90d42accb18f264f810b3128dc4470edbab..ace463ede2187eb4c5527bd049c14f9b5fc37e00 100644 (file)
@@ -59,7 +59,6 @@ private:
     array_list<alloc_header *> _allocation_list;
     const bool _detailed_leaks;
     const bool _poison_on_free;
-    const bool _synchronized;
     lock_and_signal _lock;
 
     void add_alloc();
@@ -77,8 +76,7 @@ private:
     memory_region& operator=(const memory_region& rhs);
 
 public:
-    memory_region(bool synchronized,
-                  bool detailed_leaks, bool poison_on_free);
+    memory_region(bool detailed_leaks, bool poison_on_free);
     memory_region(memory_region *parent);
     void *malloc(size_t size, const char *tag);
     void *realloc(void *mem, size_t size);
diff --git a/src/rt/rust_abi.cpp b/src/rt/rust_abi.cpp
deleted file mode 100644 (file)
index fd1b786..0000000
+++ /dev/null
@@ -1,88 +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.
-
-// ABI-specific routines.
-
-#include <sstream>
-#include <string>
-#include <vector>
-#include <cstdlib>
-#include <stdint.h>
-#include "rust_abi.h"
-
-#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__)
-#define HAVE_DLFCN_H
-#include <dlfcn.h>
-#elif defined(_WIN32)
-// Otherwise it's windows.h -- included in rust_abi.h
-#endif
-
-#define END_OF_STACK_RA     (void (*)())0xdeadbeef
-
-weak_symbol<uint32_t> abi_version("rust_abi_version");
-
-uint32_t get_abi_version() {
-    return (*abi_version == NULL) ? 0 : **abi_version;
-}
-
-namespace stack_walk {
-
-#ifdef HAVE_DLFCN_H
-std::string
-frame::symbol() const {
-    std::stringstream ss;
-
-    Dl_info info;
-    if (!dladdr((void *)ra, &info))
-        ss << "??";
-    else
-        ss << info.dli_sname;
-
-    ss << " @ " << std::hex << (uintptr_t)ra;
-    return ss.str();
-}
-#else
-std::string
-frame::symbol() const {
-    std::stringstream ss;
-    ss << std::hex << (uintptr_t)ra;
-    return ss.str();
-}
-#endif
-
-std::vector<frame>
-backtrace() {
-    std::vector<frame> frames;
-
-    // Ideally we would use the current value of EIP here, but there's no
-    // portable way to get that and there are never any GC roots in our C++
-    // frames anyhow.
-    frame f(__builtin_frame_address(0), (void (*)())NULL);
-
-    while (f.ra != END_OF_STACK_RA) {
-        frames.push_back(f);
-        f.next();
-    }
-    return frames;
-}
-
-std::string
-symbolicate(const std::vector<frame> &frames) {
-    std::stringstream ss;
-    std::vector<frame>::const_iterator begin(frames.begin()),
-                                       end(frames.end());
-    while (begin != end) {
-        ss << begin->symbol() << std::endl;
-        ++begin;
-    }
-    return ss.str();
-}
-
-}   // end namespace stack_walk
diff --git a/src/rt/rust_abi.h b/src/rt/rust_abi.h
deleted file mode 100644 (file)
index 4179bf7..0000000
+++ /dev/null
@@ -1,78 +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.
-
-// ABI-specific routines.
-
-#ifndef RUST_ABI_H
-#define RUST_ABI_H
-
-#include <cstdlib>
-#include <string>
-#include <vector>
-#include <stdint.h>
-
-#ifdef __WIN32__
-#include <windows.h>
-#else
-#include <dlfcn.h>
-#endif
-
-template<typename T>
-class weak_symbol {
-private:
-    bool init;
-    T *data;
-    const char *name;
-
-    void fill() {
-        if (init)
-            return;
-
-#ifdef __WIN32__
-        data = (T *)GetProcAddress(GetModuleHandle(NULL), name);
-#else
-        data = (T *)dlsym(RTLD_DEFAULT, name);
-#endif
-
-        init = true;
-    }
-
-public:
-    weak_symbol(const char *in_name)
-    : init(false), data(NULL), name(in_name) {}
-
-    T *&operator*() { fill(); return data; }
-};
-
-namespace stack_walk {
-
-struct frame {
-    uint8_t *bp;    // The frame pointer.
-    void (*ra)();   // The return address.
-
-    frame(void *in_bp, void (*in_ra)()) : bp((uint8_t *)in_bp), ra(in_ra) {}
-
-    inline void next() {
-        ra = *(void (**)())(bp + sizeof(void *));
-        bp = *(uint8_t **)bp;
-    }
-
-    std::string symbol() const;
-};
-
-std::vector<frame> backtrace();
-std::string symbolicate(const std::vector<frame> &frames);
-
-}   // end namespace stack_walk
-
-
-uint32_t get_abi_version();
-
-#endif
index de86035b6329ac7b948b05015db5f0c8515ea115..27cc486c39efc2bfd48e09c7868269045b791a02 100644 (file)
 /* Foreign builtins. */
 
 #include "rust_util.h"
-#include "sync/timer.h"
 #include "sync/rust_thread.h"
 #include "sync/lock_and_signal.h"
 #include "memory_region.h"
 #include "boxed_region.h"
-#include "rust_abi.h"
 #include "rust_rng.h"
 #include "vg/valgrind.h"
 #include "sp.h"
@@ -25,6 +23,7 @@
 
 #ifdef __APPLE__
 #include <crt_externs.h>
+#include <mach/mach_time.h>
 #endif
 
 #if !defined(__WIN32__)
@@ -99,53 +98,6 @@ rand_free(rust_rng *rng) {
     free(rng);
 }
 
-
-/* Debug helpers strictly to verify ABI conformance.
- *
- * FIXME (#2665): move these into a testcase when the testsuite
- * understands how to have explicit C files included.
- */
-
-struct quad {
-    uint64_t a;
-    uint64_t b;
-    uint64_t c;
-    uint64_t d;
-};
-
-struct floats {
-    double a;
-    uint8_t b;
-    double c;
-};
-
-extern "C" quad
-debug_abi_1(quad q) {
-    quad qq = { q.c + 1,
-                q.d - 1,
-                q.a + 1,
-                q.b - 1 };
-    return qq;
-}
-
-extern "C" floats
-debug_abi_2(floats f) {
-    floats ff = { f.c + 1.0,
-                  0xff,
-                  f.a - 1.0 };
-    return ff;
-}
-
-extern "C" int
-debug_static_mut;
-
-int debug_static_mut = 3;
-
-extern "C" void
-debug_static_mut_check_four() {
-    assert(debug_static_mut == 4);
-}
-
 extern "C" CDECL char*
 #if defined(__WIN32__)
 rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
@@ -242,10 +194,33 @@ get_time(int64_t *sec, int32_t *nsec) {
 }
 #endif
 
+const uint64_t ns_per_s = 1000000000LL;
+
 extern "C" CDECL void
 precise_time_ns(uint64_t *ns) {
-    timer t;
-    *ns = t.time_ns();
+
+#ifdef __APPLE__
+    uint64_t time = mach_absolute_time();
+    mach_timebase_info_data_t info = {0, 0};
+    if (info.denom == 0) {
+        mach_timebase_info(&info);
+    }
+    uint64_t time_nano = time * (info.numer / info.denom);
+    *ns = time_nano;
+#elif __WIN32__
+    uint64_t ticks_per_s;
+    QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_s);
+    if (ticks_per_s == 0LL) {
+        ticks_per_s = 1LL;
+    }
+    uint64_t ticks;
+    QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
+    *ns = ((ticks * ns_per_s) / ticks_per_s);
+#else
+    timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    *ns = (ts.tv_sec * ns_per_s + ts.tv_nsec);
+#endif
 }
 
 struct rust_tm {
@@ -292,7 +267,7 @@ void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
 
     if (zone != NULL) {
         size_t size = strlen(zone);
-        reserve_vec_exact(&out_tm->tm_zone, size);
+        assert(out_tm->tm_zone->alloc >= size);
         memcpy(out_tm->tm_zone->data, zone, size);
         out_tm->tm_zone->fill = size;
     }
@@ -472,19 +447,14 @@ rust_readdir() {
 #endif
 
 #ifndef _WIN32
-pthread_key_t rt_key = -1;
+typedef pthread_key_t tls_key;
 #else
-DWORD rt_key = -1;
+typedef DWORD tls_key;
 #endif
 
-extern "C" void*
-rust_get_rt_tls_key() {
-    return &rt_key;
-}
-
 // Initialize the TLS key used by the new scheduler
 extern "C" CDECL void
-rust_initialize_rt_tls_key() {
+rust_initialize_rt_tls_key(tls_key *key) {
 
     static lock_and_signal init_lock;
     static bool initialized = false;
@@ -494,10 +464,10 @@ rust_initialize_rt_tls_key() {
     if (!initialized) {
 
 #ifndef _WIN32
-        assert(!pthread_key_create(&rt_key, NULL));
+        assert(!pthread_key_create(key, NULL));
 #else
-        rt_key = TlsAlloc();
-        assert(rt_key != TLS_OUT_OF_INDEXES);
+        *key = TlsAlloc();
+        assert(*key != TLS_OUT_OF_INDEXES);
 #endif
 
         initialized = true;
@@ -505,11 +475,9 @@ rust_initialize_rt_tls_key() {
 }
 
 extern "C" CDECL memory_region*
-rust_new_memory_region(uintptr_t synchronized,
-                       uintptr_t detailed_leaks,
+rust_new_memory_region(uintptr_t detailed_leaks,
                        uintptr_t poison_on_free) {
-    return new memory_region((bool)synchronized,
-                             (bool)detailed_leaks,
+    return new memory_region((bool)detailed_leaks,
                              (bool)poison_on_free);
 }
 
@@ -632,21 +600,6 @@ rust_get_global_args_ptr() {
     return &global_args_ptr;
 }
 
-static lock_and_signal exit_status_lock;
-static uintptr_t exit_status = 0;
-
-extern "C" CDECL void
-rust_set_exit_status_newrt(uintptr_t code) {
-    scoped_lock with(exit_status_lock);
-    exit_status = code;
-}
-
-extern "C" CDECL uintptr_t
-rust_get_exit_status_newrt() {
-    scoped_lock with(exit_status_lock);
-    return exit_status;
-}
-
 static lock_and_signal change_dir_lock;
 
 extern "C" CDECL void
diff --git a/src/rt/rust_exchange_alloc.cpp b/src/rt/rust_exchange_alloc.cpp
deleted file mode 100644 (file)
index 658d970..0000000
+++ /dev/null
@@ -1,35 +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.
-
-#include "rust_exchange_alloc.h"
-#include "sync/sync.h"
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-#include <stdio.h>
-
-void *
-rust_exchange_alloc::malloc(size_t size) {
-  void *value = ::malloc(size);
-  assert(value);
-  return value;
-}
-
-void *
-rust_exchange_alloc::realloc(void *ptr, size_t size) {
-  void *new_ptr = ::realloc(ptr, size);
-  assert(new_ptr);
-  return new_ptr;
-}
-
-void
-rust_exchange_alloc::free(void *ptr) {
-  ::free(ptr);
-}
diff --git a/src/rt/rust_exchange_alloc.h b/src/rt/rust_exchange_alloc.h
deleted file mode 100644 (file)
index 9699ef6..0000000
+++ /dev/null
@@ -1,24 +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.
-
-#ifndef RUST_EXCHANGE_ALLOC_H
-#define RUST_EXCHANGE_ALLOC_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-class rust_exchange_alloc {
- public:
-    void *malloc(size_t size);
-    void *realloc(void *mem, size_t size);
-    void free(void *mem);
-};
-
-#endif
diff --git a/src/rt/rust_gc_metadata.cpp b/src/rt/rust_gc_metadata.cpp
deleted file mode 100644 (file)
index e378562..0000000
+++ /dev/null
@@ -1,95 +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_gc_metadata.h"
-#include "rust_crate_map.h"
-#include "rust_globals.h"
-
-#include <algorithm>
-#include <vector>
-
-struct safe_point {
-    uintptr_t safe_point_loc;
-    uintptr_t safe_point_meta;
-    uintptr_t function_meta;
-};
-
-struct update_gc_entry_args {
-    std::vector<safe_point> *safe_points;
-};
-
-static void
-update_gc_entry(const mod_entry *entry, void *cookie) {
-    update_gc_entry_args *args = (update_gc_entry_args *)cookie;
-    if (!strcmp(entry->name, "_gc_module_metadata")) {
-        uintptr_t *next = (uintptr_t *)entry->state;
-        uint32_t num_safe_points = *(uint32_t *)next;
-        next++;
-
-        for (uint32_t i = 0; i < num_safe_points; i++) {
-            safe_point sp = { next[0], next[1], next[2] };
-            next += 3;
-
-            args->safe_points->push_back(sp);
-        }
-    }
-}
-
-static bool
-cmp_safe_point(safe_point a, safe_point b) {
-    return a.safe_point_loc < b.safe_point_loc;
-}
-
-uintptr_t *global_safe_points = 0;
-
-void
-update_gc_metadata(const void* map) {
-    std::vector<safe_point> safe_points;
-    update_gc_entry_args args = { &safe_points };
-
-    // Extract list of safe points from each module.
-    iter_crate_map((const cratemap *)map, update_gc_entry, (void *)&args);
-    std::sort(safe_points.begin(), safe_points.end(), cmp_safe_point);
-
-    // Serialize safe point list into format expected by runtime.
-    global_safe_points =
-        (uintptr_t *)malloc((safe_points.size()*3 + 1)*sizeof(uintptr_t));
-    if (!global_safe_points) return;
-
-    uintptr_t *next = global_safe_points;
-    *next = safe_points.size();
-    next++;
-    for (uint32_t i = 0; i < safe_points.size(); i++) {
-        next[0] = safe_points[i].safe_point_loc;
-        next[1] = safe_points[i].safe_point_meta;
-        next[2] = safe_points[i].function_meta;
-        next += 3;
-    }
-}
-
-extern "C" CDECL void *
-rust_gc_metadata() {
-    return (void *)global_safe_points;
-}
-
-extern "C" CDECL void
-rust_update_gc_metadata(const void* map) {
-    update_gc_metadata(map);
-}
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
diff --git a/src/rt/rust_gc_metadata.h b/src/rt/rust_gc_metadata.h
deleted file mode 100644 (file)
index d8d98e7..0000000
+++ /dev/null
@@ -1,26 +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.
-
-#ifndef RUST_GC_METADATA_H
-#define RUST_GC_METADATA_H
-
-void update_gc_metadata(const void* map);
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
-
-#endif /* RUST_GC_METADATA_H */
index b0aab9672ea8f2b64109c93aa208ddf9ff7c6a8b..f10a1f36938a30cc9a73834e997ab06535db1438 100644 (file)
 // Helper functions used only in tests
 
 #include "rust_util.h"
-#include "sync/timer.h"
 #include "sync/rust_thread.h"
 #include "sync/lock_and_signal.h"
-#include "rust_abi.h"
 
 // These functions are used in the unit tests for C ABI calls.
 
@@ -179,3 +177,49 @@ extern "C" CDECL intptr_t
 rust_get_test_int() {
   return 1;
 }
+
+/* Debug helpers strictly to verify ABI conformance.
+ *
+ * FIXME (#2665): move these into a testcase when the testsuite
+ * understands how to have explicit C files included.
+ */
+
+struct quad {
+    uint64_t a;
+    uint64_t b;
+    uint64_t c;
+    uint64_t d;
+};
+
+struct floats {
+    double a;
+    uint8_t b;
+    double c;
+};
+
+extern "C" quad
+rust_dbg_abi_1(quad q) {
+    quad qq = { q.c + 1,
+                q.d - 1,
+                q.a + 1,
+                q.b - 1 };
+    return qq;
+}
+
+extern "C" floats
+rust_dbg_abi_2(floats f) {
+    floats ff = { f.c + 1.0,
+                  0xff,
+                  f.a - 1.0 };
+    return ff;
+}
+
+extern "C" int
+rust_dbg_static_mut;
+
+int rust_dbg_static_mut = 3;
+
+extern "C" void
+rust_dbg_static_mut_check_four() {
+    assert(rust_dbg_static_mut == 4);
+}
index 21c0d219242613d91a75518af7b2ae391404115c..7ccb06a3296f4ced2905c390e120e949e6b8f317 100644 (file)
@@ -54,8 +54,18 @@ upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) {
 
 /**********************************************************************/
 
+#ifdef __SEH__
+#  define PERSONALITY_FUNC __gxx_personality_seh0
+#else
+#  ifdef __USING_SJLJ_EXCEPTIONS__
+#    define PERSONALITY_FUNC __gxx_personality_sjlj
+#  else
+#    define PERSONALITY_FUNC __gxx_personality_v0
+#  endif
+#endif
+
 extern "C" _Unwind_Reason_Code
-__gxx_personality_v0(int version,
+PERSONALITY_FUNC(int version,
                      _Unwind_Action actions,
                      uint64_t exception_class,
                      _Unwind_Exception *ue_header,
@@ -72,11 +82,11 @@ struct s_rust_personality_args {
 
 extern "C" void
 upcall_s_rust_personality(s_rust_personality_args *args) {
-    args->retval = __gxx_personality_v0(args->version,
-                                        args->actions,
-                                        args->exception_class,
-                                        args->ue_header,
-                                        args->context);
+    args->retval = PERSONALITY_FUNC(args->version,
+                                    args->actions,
+                                    args->exception_class,
+                                    args->ue_header,
+                                    args->context);
 }
 
 /**
diff --git a/src/rt/rust_util.cpp b/src/rt/rust_util.cpp
deleted file mode 100644 (file)
index 28c69af..0000000
+++ /dev/null
@@ -1,35 +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_type.h"
-
-
-// A hardcoded type descriptor for strings, since the runtime needs to
-// be able to create them.
-
-struct type_desc str_body_tydesc = {
-    1, // size
-    1, // align
-    NULL, // take_glue
-    NULL, // drop_glue
-    NULL, // free_glue
-    NULL, // visit_glue
-    0, // borrow_offset
-};
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
index 7c531297ccddc4fc8e23e6e73d641a5b7a0accbd..d78ade4e94c51f678230fbb4e27b0bc118e0abe9 100644 (file)
 #define RUST_UTIL_H
 
 #include <limits.h>
-#include "rust_exchange_alloc.h"
 #include "rust_type.h"
 
-extern struct type_desc str_body_tydesc;
-
 // Inline fn used regularly elsewhere.
 
 // Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
@@ -57,16 +54,6 @@ vec_data(rust_vec *v) {
     return reinterpret_cast<T*>(v->data);
 }
 
-inline void reserve_vec_exact(rust_vec** vpp,
-                              size_t size) {
-    if (size > (*vpp)->alloc) {
-        rust_exchange_alloc exchange_alloc;
-        *vpp = (rust_vec*)exchange_alloc
-            .realloc(*vpp, size + sizeof(rust_vec));
-        (*vpp)->alloc = size;
-    }
-}
-
 typedef rust_vec rust_str;
 
 inline size_t get_box_size(size_t body_size, size_t body_align) {
index 8ef4572f8108f0170b577359475da5cde9fbad4b..a181e76df5ca70f1bb31ee21a93c7c4be96fcd6a 100644 (file)
@@ -329,20 +329,13 @@ rust_uv_get_len_from_buf(uv_buf_t buf) {
     return buf.len;
 }
 
-extern "C" uv_err_t
-rust_uv_last_error(uv_loop_t* loop) {
-    return uv_last_error(loop);
-}
-
 extern "C" const char*
-rust_uv_strerror(uv_err_t* err_ptr) {
-    uv_err_t err = *err_ptr;
+rust_uv_strerror(int err) {
     return uv_strerror(err);
 }
 
 extern "C" const char*
-rust_uv_err_name(uv_err_t* err_ptr) {
-    uv_err_t err = *err_ptr;
+rust_uv_err_name(int err) {
     return uv_err_name(err);
 }
 
@@ -553,3 +546,37 @@ extern "C" uv_loop_t*
 rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
   return req->loop;
 }
+extern "C" int
+rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) {
+  return uv_spawn(loop, p, options);
+}
+
+extern "C" int
+rust_uv_process_kill(uv_process_t *p, int signum) {
+  return uv_process_kill(p, signum);
+}
+
+extern "C" void
+rust_set_stdio_container_flags(uv_stdio_container_t *c, int flags) {
+  c->flags = (uv_stdio_flags) flags;
+}
+
+extern "C" void
+rust_set_stdio_container_fd(uv_stdio_container_t *c, int fd) {
+  c->data.fd = fd;
+}
+
+extern "C" void
+rust_set_stdio_container_stream(uv_stdio_container_t *c, uv_stream_t *stream) {
+  c->data.stream = stream;
+}
+
+extern "C" int
+rust_uv_process_pid(uv_process_t* p) {
+  return p->pid;
+}
+
+extern "C" int
+rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) {
+  return uv_pipe_init(loop, p, ipc);
+}
index 5100e732308f2dbeb39d38460a751ff44e3e5c31..2fc1a91a132da55d66c5ba660612398ebbfe06d1 100644 (file)
@@ -1,7 +1,7 @@
-debug_abi_1
-debug_abi_2
-debug_static_mut
-debug_static_mut_check_four
+rust_dbg_abi_1
+rust_dbg_abi_2
+rust_dbg_static_mut
+rust_dbg_static_mut_check_four
 get_time
 rust_tzset
 rust_gmtime
@@ -47,7 +47,6 @@ rust_uv_timer_start
 rust_uv_timer_stop
 rust_uv_tcp_init
 rust_uv_buf_init
-rust_uv_last_error
 rust_uv_strerror
 rust_uv_err_name
 rust_uv_ip4_addr
@@ -130,8 +129,6 @@ rust_lock_little_lock
 rust_unlock_little_lock
 tdefl_compress_mem_to_heap
 tinfl_decompress_mem_to_heap
-rust_gc_metadata
-rust_update_gc_metadata
 rust_uv_ip4_port
 rust_uv_ip6_port
 rust_uv_tcp_getpeername
@@ -145,7 +142,6 @@ linenoiseHistoryLoad
 rust_raw_thread_start
 rust_raw_thread_join
 rust_raw_thread_delete
-rust_get_rt_tls_key
 swap_registers
 rust_readdir
 rust_opendir
@@ -191,9 +187,14 @@ rust_get_num_cpus
 rust_get_global_args_ptr
 rust_take_global_args_lock
 rust_drop_global_args_lock
-rust_set_exit_status_newrt
-rust_get_exit_status_newrt
 rust_take_change_dir_lock
 rust_drop_change_dir_lock
 rust_get_test_int
-rust_get_task
\ No newline at end of file
+rust_get_task
+rust_uv_spawn
+rust_uv_process_kill
+rust_set_stdio_container_flags
+rust_set_stdio_container_fd
+rust_set_stdio_container_stream
+rust_uv_process_pid
+rust_uv_pipe_init
diff --git a/src/rt/sync/sync.h b/src/rt/sync/sync.h
deleted file mode 100644 (file)
index 6ac97d5..0000000
+++ /dev/null
@@ -1,53 +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.
-
-#ifndef SYNC_H
-#define SYNC_H
-
-class sync {
-public:
-    template <class T>
-    static bool compare_and_swap(T *address,
-        T oldValue, T newValue) {
-        return __sync_bool_compare_and_swap(address, oldValue, newValue);
-    }
-
-    template <class T>
-    static T increment(T *address) {
-        return __sync_add_and_fetch(address, 1);
-    }
-
-    template <class T>
-    static T decrement(T *address) {
-        return __sync_sub_and_fetch(address, 1);
-    }
-
-    template <class T>
-    static T increment(T &address) {
-        return __sync_add_and_fetch(&address, 1);
-    }
-
-    template <class T>
-    static T decrement(T &address) {
-        return __sync_sub_and_fetch(&address, 1);
-    }
-
-    template <class T>
-    static T read(T *address) {
-        return __sync_add_and_fetch(address, 0);
-    }
-
-    template <class T>
-    static T read(T &address) {
-        return __sync_add_and_fetch(&address, 0);
-    }
-};
-
-#endif /* SYNC_H */
diff --git a/src/rt/sync/timer.cpp b/src/rt/sync/timer.cpp
deleted file mode 100644 (file)
index 99e5b10..0000000
+++ /dev/null
@@ -1,85 +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"
-#include "timer.h"
-
-#if defined(__APPLE__)
-#include <mach/mach_time.h>
-#endif
-
-uint64_t ns_per_s = 1000000000LL;
-
-timer::timer() {
-#if __WIN32__
-    _ticks_per_s = 0LL;
-    // FIXME (#2675): assert this works or have a workaround.
-    QueryPerformanceFrequency((LARGE_INTEGER *)&_ticks_per_s);
-    if (_ticks_per_s == 0LL) {
-      _ticks_per_s = 1LL;
-    }
-#endif
-    reset_us(0);
-}
-
-void
-timer::reset_us(uint64_t timeout_us) {
-    _start_us = time_us();
-    _timeout_us = timeout_us;
-}
-
-uint64_t
-timer::elapsed_us() {
-    return time_us() - _start_us;
-}
-
-double
-timer::elapsed_ms() {
-    return (double) elapsed_us() / 1000.0;
-}
-
-int64_t
-timer::remaining_us() {
-    return _timeout_us - elapsed_us();
-}
-
-bool
-timer::has_timed_out() {
-    return remaining_us() <= 0;
-}
-
-uint64_t
-timer::time_ns() {
-#ifdef __APPLE__
-    uint64_t time = mach_absolute_time();
-    mach_timebase_info_data_t info = {0, 0};
-    if (info.denom == 0) {
-        mach_timebase_info(&info);
-    }
-    uint64_t time_nano = time * (info.numer / info.denom);
-    return time_nano;
-#elif __WIN32__
-    uint64_t ticks;
-    QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
-    return ((ticks * ns_per_s) / _ticks_per_s);
-#else
-    timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    return (ts.tv_sec * ns_per_s + ts.tv_nsec);
-#endif
-}
-
-uint64_t
-timer::time_us() {
-    return time_ns() / 1000;
-}
-
-timer::~timer() {
-}
diff --git a/src/rt/sync/timer.h b/src/rt/sync/timer.h
deleted file mode 100644 (file)
index 59d0587..0000000
+++ /dev/null
@@ -1,37 +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.
-
-/*
- *  Utility class to measure time in a platform independent way.
- */
-
-#ifndef TIMER_H
-#define TIMER_H
-
-class timer {
-private:
-    uint64_t _start_us;
-    uint64_t _timeout_us;
-    uint64_t time_us();
-#if __WIN32__
-    uint64_t _ticks_per_s;
-#endif
-public:
-    timer();
-    void reset_us(uint64_t timeout);
-    uint64_t elapsed_us();
-    double elapsed_ms();
-    int64_t remaining_us();
-    bool has_timed_out();
-    uint64_t time_ns();
-    virtual ~timer();
-};
-
-#endif /* TIMER_H */
diff --git a/src/rt/util/indexed_list.h b/src/rt/util/indexed_list.h
deleted file mode 100644 (file)
index 4673e9e..0000000
+++ /dev/null
@@ -1,115 +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.
-
-#ifndef INDEXED_LIST_H
-#define INDEXED_LIST_H
-
-#include <assert.h>
-#include "array_list.h"
-
-class indexed_list_object {
-public:
-    virtual ~indexed_list_object() {}
-    int32_t list_index;
-};
-
-template<typename T>
-class indexed_list_element : public indexed_list_object {
-public:
-    T value;
-    indexed_list_element(T value) : value(value) {
-    }
-};
-
-/**
- * An array list of objects that are aware of their position in the list.
- * Normally, objects in this list should derive from the base class
- * "indexed_list_object" however because of nasty Rust compiler dependencies
- * on the layout of runtime objects we cannot always derive from this
- * base class, so instead we just enforce the informal protocol that any
- * object inserted in this list must define a "int32_t list_index" member.
- */
-template<typename T> class indexed_list {
-    array_list<T*> list;
-public:
-    int32_t append(T *value);
-    bool pop(T **value);
-    /**
-     * Same as pop(), except that it returns NULL if the list is empty.
-     */
-    T* pop_value();
-    size_t length() const {
-        return list.size();
-    }
-    bool is_empty() const {
-        return list.is_empty();
-    }
-    int32_t remove(T* value);
-    T * operator[](int32_t index);
-    const T * operator[](int32_t index) const;
-    ~indexed_list() {}
-};
-
-template<typename T> int32_t
-indexed_list<T>::append(T *value) {
-    value->list_index = list.push(value);
-    return value->list_index;
-}
-
-/**
- * Swap delete the last object in the list with the specified object.
- */
-template<typename T> int32_t
-indexed_list<T>::remove(T *value) {
-    assert (value->list_index >= 0);
-    assert (value->list_index < (int32_t)list.size());
-    int32_t removeIndex = value->list_index;
-    T *last = 0;
-    list.pop(&last);
-    if (last->list_index == removeIndex) {
-        last->list_index = -1;
-        return removeIndex;
-    } else {
-        value->list_index = -1;
-        list[removeIndex] = last;
-        last->list_index = removeIndex;
-        return removeIndex;
-    }
-}
-
-template<typename T> bool
-indexed_list<T>::pop(T **value) {
-    return list.pop(value);
-}
-
-template<typename T> T*
-indexed_list<T>::pop_value() {
-    T *value = NULL;
-    if (list.pop(&value)) {
-        return value;
-    }
-    return NULL;
-}
-
-template <typename T> T *
-indexed_list<T>::operator[](int32_t index) {
-    T *value = list[index];
-    assert(value->list_index == index);
-    return value;
-}
-
-template <typename T> const T *
-indexed_list<T>::operator[](int32_t index) const {
-    T *value = list[index];
-    assert(value->list_index == index);
-    return value;
-}
-
-#endif /* INDEXED_LIST_H */
index 222a58e156323c6c183db5856690d6fea8d55a09..c9aa0fd0328356b0d3b376fc575b2ad6420074d4 100644 (file)
 #undef PLAT_x86_darwin
 #undef PLAT_amd64_darwin
 #undef PLAT_x86_win32
+#undef PLAT_amd64_win64
 #undef PLAT_x86_linux
 #undef PLAT_amd64_linux
 #undef PLAT_ppc32_linux
 #  define PLAT_amd64_darwin 1
 #elif defined(__MINGW32__) || defined(__CYGWIN32__) \
       || (defined(_WIN32) && defined(_M_IX86))
-#  define PLAT_x86_win32 1
+#  if defined(__x86_64__)
+#    define PLAT_amd64_win64 1
+#  elif defined(__i386__)
+#    define PLAT_x86_win32 1
+#  endif
 #elif defined(__linux__) && defined(__i386__)
 #  define PLAT_x86_linux 1
 #elif defined(__linux__) && defined(__x86_64__)
@@ -349,7 +354,8 @@ valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request,
 
 /* ------------------------ amd64-{linux,darwin} --------------- */
 
-#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin) \
+    || defined(PLAT_amd64_win64)
 
 typedef
    struct { 
@@ -3716,14 +3722,14 @@ VALGRIND_PRINTF(const char *format, ...)
 #if defined(NVALGRIND)
    return 0;
 #else /* NVALGRIND */
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
    uintptr_t _qzz_res;
 #else
    unsigned long _qzz_res;
 #endif
    va_list vargs;
    va_start(vargs, format);
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
    _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
                               VG_USERREQ__PRINTF_VALIST_BY_REF,
                               (uintptr_t)format,
@@ -3754,14 +3760,14 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
 #if defined(NVALGRIND)
    return 0;
 #else /* NVALGRIND */
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
    uintptr_t _qzz_res;
 #else
    unsigned long _qzz_res;
 #endif
    va_list vargs;
    va_start(vargs, format);
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
    _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
                               VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
                               (uintptr_t)format,
index 32b6df4e1dd595c572d1cab9a45b3731750798aa..56ba56cf89377fb2ea265ce1dca82df995bb5c70 100644 (file)
@@ -8,29 +8,29 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#include <stdio.h>
+
 #include "rustllvm.h"
 
-using namespace llvm;
+#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
 
-// Pass conversion fns
-typedef struct LLVMOpaquePass *LLVMPassRef;
+#include "llvm-c/Transforms/PassManagerBuilder.h"
 
-inline Pass *unwrap(LLVMPassRef P) {
-    return reinterpret_cast<Pass*>(P);
-}
+using namespace llvm;
 
-inline LLVMPassRef wrap(const Pass *P) {
-    return reinterpret_cast<LLVMPassRef>(const_cast<Pass*>(P));
-}
+extern cl::opt<bool> EnableARMEHABI;
 
-template<typename T>
-inline T *unwrap(LLVMPassRef P) {
-    T *Q = (T*)unwrap(P);
-    assert(Q && "Invalid cast!");
-    return Q;
-}
+typedef struct LLVMOpaquePass *LLVMPassRef;
+typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
+
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, LLVMPassManagerBuilderRef)
 
-extern "C" void LLVMInitializePasses() {
+extern "C" void
+LLVMInitializePasses() {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
   initializeCore(Registry);
   initializeCodeGen(Registry);
@@ -45,26 +45,185 @@ extern "C" void LLVMInitializePasses() {
   initializeTarget(Registry);
 }
 
-extern "C" void LLVMAddPass(LLVMPassManagerRef PM, LLVMPassRef P) {
-    PassManagerBase * pm = unwrap(PM);
-    Pass * p = unwrap(P);
-
-    pm->add(p);
-}
+extern "C" bool
+LLVMRustAddPass(LLVMPassManagerRef PM, const char *PassName) {
+    PassManagerBase *pm = unwrap(PM);
 
-extern "C" LLVMPassRef LLVMCreatePass(const char * PassName) {
     StringRef SR(PassName);
-    PassRegistry * PR = PassRegistry::getPassRegistry();
+    PassRegistry *PR = PassRegistry::getPassRegistry();
 
-    const PassInfo * PI = PR->getPassInfo(SR);
+    const PassInfo *PI = PR->getPassInfo(SR);
     if (PI) {
-        return wrap(PI->createPass());
-    } else {
-        return (LLVMPassRef)0;
+        pm->add(PI->createPass());
+        return true;
+    }
+    return false;
+}
+
+extern "C" LLVMTargetMachineRef
+LLVMRustCreateTargetMachine(const char *triple,
+                            const char *cpu,
+                            const char *feature,
+                            CodeModel::Model CM,
+                            Reloc::Model RM,
+                            CodeGenOpt::Level OptLevel,
+                            bool EnableSegmentedStacks) {
+    std::string Error;
+    Triple Trip(Triple::normalize(triple));
+    const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(),
+                                                                 Error);
+    if (TheTarget == NULL) {
+        LLVMRustError = Error.c_str();
+        return NULL;
+    }
+
+    TargetOptions Options;
+    Options.EnableSegmentedStacks = EnableSegmentedStacks;
+    Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
+    Options.FloatABIType =
+         (Trip.getEnvironment() == Triple::GNUEABIHF) ? FloatABI::Hard :
+                                                        FloatABI::Default;
+
+    TargetMachine *TM = TheTarget->createTargetMachine(Trip.getTriple(),
+                                                       cpu,
+                                                       feature,
+                                                       Options,
+                                                       RM,
+                                                       CM,
+                                                       OptLevel);
+    return wrap(TM);
+}
+
+extern "C" void
+LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
+    delete unwrap(TM);
+}
+
+// Unfortunately, LLVM doesn't expose a C API to add the corresponding analysis
+// passes for a target to a pass manager. We export that functionality through
+// this function.
+extern "C" void
+LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
+                          LLVMPassManagerRef PMR,
+                          LLVMModuleRef M) {
+    PassManagerBase *PM = unwrap(PMR);
+    PM->add(new DataLayout(unwrap(M)));
+    unwrap(TM)->addAnalysisPasses(*PM);
+}
+
+// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
+// field of a PassManagerBuilder, we expose our own method of doing so.
+extern "C" void
+LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M) {
+    Triple TargetTriple(unwrap(M)->getTargetTriple());
+    unwrap(PMB)->LibraryInfo = new TargetLibraryInfo(TargetTriple);
+}
+
+// Unfortunately, the LLVM C API doesn't provide a way to create the
+// TargetLibraryInfo pass, so we use this method to do so.
+extern "C" void
+LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M) {
+    Triple TargetTriple(unwrap(M)->getTargetTriple());
+    unwrap(PMB)->add(new TargetLibraryInfo(TargetTriple));
+}
+
+// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
+// all the functions in a module, so we do that manually here. You'll find
+// similar code in clang's BackendUtil.cpp file.
+extern "C" void
+LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) {
+    FunctionPassManager *P = unwrap<FunctionPassManager>(PM);
+    P->doInitialization();
+    for (Module::iterator I = unwrap(M)->begin(),
+         E = unwrap(M)->end(); I != E; ++I)
+        if (!I->isDeclaration())
+            P->run(*I);
+    P->doFinalization();
+}
+
+extern "C" void
+LLVMRustSetLLVMOptions(bool PrintPasses,
+                       bool VectorizeLoops,
+                       bool VectorizeSLP,
+                       bool TimePasses) {
+    // Initializing the command-line options more than once is not allowed. So,
+    // check if they've already been initialized.  (This could happen if we're
+    // being called from rustpkg, for example). If the arguments change, then
+    // that's just kinda unfortunate.
+    static bool initialized = false;
+    if (initialized) return;
+
+    int argc = 3;
+    const char *argv[20] = {"rustc",
+                            "-arm-enable-ehabi",
+                            "-arm-enable-ehabi-descriptors"};
+    if (PrintPasses) {
+        argv[argc++] = "-debug-pass";
+        argv[argc++] = "Structure";
+    }
+    if (VectorizeLoops) {
+        argv[argc++] = "-vectorize-loops";
+    }
+    if (VectorizeSLP) {
+        argv[argc++] = "-vectorize-slp";
     }
+    if (TimePasses) {
+        argv[argc++] = "-time-passes";
+    }
+    cl::ParseCommandLineOptions(argc, argv);
+    initialized = true;
+}
+
+extern "C" bool
+LLVMRustWriteOutputFile(LLVMTargetMachineRef Target,
+                        LLVMPassManagerRef PMR,
+                        LLVMModuleRef M,
+                        const char *path,
+                        TargetMachine::CodeGenFileType FileType) {
+  PassManager *PM = unwrap<PassManager>(PMR);
+
+  std::string ErrorInfo;
+  raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
+  if (ErrorInfo != "") {
+    LLVMRustError = ErrorInfo.c_str();
+    return false;
+  }
+  formatted_raw_ostream FOS(OS);
+
+  unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false);
+  PM->run(*unwrap(M));
+  return true;
+}
+
+extern "C" void
+LLVMRustPrintModule(LLVMPassManagerRef PMR,
+                    LLVMModuleRef M,
+                    const char* path) {
+  PassManager *PM = unwrap<PassManager>(PMR);
+  std::string ErrorInfo;
+  raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
+  formatted_raw_ostream FOS(OS);
+  PM->add(createPrintModulePass(&FOS));
+  PM->run(*unwrap(M));
+}
+
+extern "C" void
+LLVMRustPrintPasses() {
+    LLVMInitializePasses();
+    struct MyListener : PassRegistrationListener {
+        void passEnumerate(const PassInfo *info) {
+            if (info->getPassArgument() && *info->getPassArgument()) {
+                printf("%15s - %s\n", info->getPassArgument(),
+                       info->getPassName());
+            }
+        }
+    } listener;
+
+    PassRegistry *PR = PassRegistry::getPassRegistry();
+    PR->enumerateWith(&listener);
 }
 
-extern "C" void LLVMDestroyPass(LLVMPassRef PassRef) {
-    Pass *p = unwrap(PassRef);
-    delete p;
+extern "C" void
+LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMB, bool AddLifetimes) {
+    unwrap(PMB)->Inliner = createAlwaysInlinerPass(AddLifetimes);
 }
index 7e9a790e215aa161996d9c4a466cf43cffd0e958..40ee486ec2d9c6a2906e75f4ce132bc58024b1d1 100644 (file)
@@ -20,9 +20,7 @@
 using namespace llvm;
 using namespace llvm::sys;
 
-static const char *LLVMRustError;
-
-extern cl::opt<bool> EnableARMEHABI;
+const char *LLVMRustError;
 
 extern "C" LLVMMemoryBufferRef
 LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
@@ -36,62 +34,6 @@ extern "C" const char *LLVMRustGetLastError(void) {
   return LLVMRustError;
 }
 
-extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);
-
-extern "C" void LLVMRustAddPrintModulePass(LLVMPassManagerRef PMR,
-                                           LLVMModuleRef M,
-                                           const char* path) {
-  PassManager *PM = unwrap<PassManager>(PMR);
-  std::string ErrorInfo;
-  raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
-  formatted_raw_ostream FOS(OS);
-  PM->add(createPrintModulePass(&FOS));
-  PM->run(*unwrap(M));
-}
-
-void LLVMInitializeX86TargetInfo();
-void LLVMInitializeX86Target();
-void LLVMInitializeX86TargetMC();
-void LLVMInitializeX86AsmPrinter();
-void LLVMInitializeX86AsmParser();
-
-
-void LLVMInitializeARMTargetInfo();
-void LLVMInitializeARMTarget();
-void LLVMInitializeARMTargetMC();
-void LLVMInitializeARMAsmPrinter();
-void LLVMInitializeARMAsmParser();
-
-void LLVMInitializeMipsTargetInfo();
-void LLVMInitializeMipsTarget();
-void LLVMInitializeMipsTargetMC();
-void LLVMInitializeMipsAsmPrinter();
-void LLVMInitializeMipsAsmParser();
-// Only initialize the platforms supported by Rust here,
-// because using --llvm-root will have multiple platforms
-// that rustllvm doesn't actually link to and it's pointless to put target info
-// into the registry that Rust can not generate machine code for.
-
-void LLVMRustInitializeTargets() {
-  LLVMInitializeX86TargetInfo();
-  LLVMInitializeX86Target();
-  LLVMInitializeX86TargetMC();
-  LLVMInitializeX86AsmPrinter();
-  LLVMInitializeX86AsmParser();
-
-  LLVMInitializeARMTargetInfo();
-  LLVMInitializeARMTarget();
-  LLVMInitializeARMTargetMC();
-  LLVMInitializeARMAsmPrinter();
-  LLVMInitializeARMAsmParser();
-
-  LLVMInitializeMipsTargetInfo();
-  LLVMInitializeMipsTarget();
-  LLVMInitializeMipsTargetMC();
-  LLVMInitializeMipsAsmPrinter();
-  LLVMInitializeMipsAsmParser();
-}
-
 // Custom memory manager for MCJITting. It needs special features
 // that the generic JIT memory manager doesn't entail. Based on
 // code from LLI, change where needed for Rust.
@@ -367,81 +309,9 @@ LLVMRustBuildJIT(void* mem,
   return wrap(EE);
 }
 
-extern "C" bool
-LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
-                        LLVMModuleRef M,
-                        const char *triple,
-                        const char *cpu,
-                        const char *feature,
-                        const char *path,
-                        TargetMachine::CodeGenFileType FileType,
-                        CodeGenOpt::Level OptLevel,
-      bool EnableSegmentedStacks) {
-
-  LLVMRustInitializeTargets();
-
-  // Initializing the command-line options more than once is not
-  // allowed. So, check if they've already been initialized.
-  // (This could happen if we're being called from rustpkg, for
-  // example.)
-  if (!EnableARMEHABI) {
-    int argc = 3;
-    const char* argv[] = {"rustc", "-arm-enable-ehabi",
-        "-arm-enable-ehabi-descriptors"};
-    cl::ParseCommandLineOptions(argc, argv);
-  }
-
-  TargetOptions Options;
-  Options.EnableSegmentedStacks = EnableSegmentedStacks;
-  Options.FixedStackSegmentSize = 2 * 1024 * 1024;  // XXX: This is too big.
-
-  PassManager *PM = unwrap<PassManager>(PMR);
-
-  std::string Err;
-  std::string Trip(Triple::normalize(triple));
-  std::string FeaturesStr(feature);
-  std::string CPUStr(cpu);
-  const Target *TheTarget = TargetRegistry::lookupTarget(Trip, Err);
-  TargetMachine *Target =
-    TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr,
-           Options, Reloc::PIC_,
-           CodeModel::Default, OptLevel);
-  Target->addAnalysisPasses(*PM);
-
-  bool NoVerify = false;
-  std::string ErrorInfo;
-  raw_fd_ostream OS(path, ErrorInfo,
-                    sys::fs::F_Binary);
-  if (ErrorInfo != "") {
-    LLVMRustError = ErrorInfo.c_str();
-    return false;
-  }
-  formatted_raw_ostream FOS(OS);
-
-  bool foo = Target->addPassesToEmitFile(*PM, FOS, FileType, NoVerify);
-  assert(!foo);
-  (void)foo;
-  PM->run(*unwrap(M));
-  delete Target;
-  return true;
-}
-
-extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(LLVMContextRef C,
-                                                   const char *Filename) {
-  SMDiagnostic d;
-  Module *m = ParseAssemblyFile(Filename, d, *unwrap(C));
-  if (m) {
-    return wrap(m);
-  } else {
-    LLVMRustError = d.getMessage().str().c_str();
-    return NULL;
-  }
-}
-
-extern "C" LLVMModuleRef LLVMRustParseBitcode(LLVMMemoryBufferRef MemBuf) {
-  LLVMModuleRef M;
-  return LLVMParseBitcode(MemBuf, &M, const_cast<char **>(&LLVMRustError))
-         ? NULL : M;
+extern "C" void
+LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *triple) {
+    unwrap(M)->setTargetTriple(Triple::normalize(triple));
 }
 
 extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N,
@@ -459,11 +329,6 @@ extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy,
   return LLVMConstInt(IntTy, N, SignExtend);
 }
 
-extern bool llvm::TimePassesIsEnabled;
-extern "C" void LLVMRustEnableTimePasses() {
-  TimePassesIsEnabled = true;
-}
-
 extern "C" void LLVMRustPrintPassTimings() {
   raw_fd_ostream OS (2, false); // stderr.
   TimerGroup::printAll(OS);
index 75a55fdf88a4197c906f5bb111f9c2b73a0a77fb..e2cec6a04f346001e6a03dbbddca691e59a6ef6a 100644 (file)
@@ -1,5 +1,4 @@
 LLVMRustCreateMemoryBufferWithContentsOfFile
-LLVMRustEnableTimePasses
 LLVMRustWriteOutputFile
 LLVMRustGetLastError
 LLVMRustConstSmallInt
@@ -7,8 +6,6 @@ LLVMRustConstInt
 LLVMRustLoadCrate
 LLVMRustPrepareJIT
 LLVMRustBuildJIT
-LLVMRustParseBitcode
-LLVMRustParseAssemblyFile
 LLVMRustPrintPassTimings
 LLVMRustStartMultithreading
 LLVMCreateObjectFile
@@ -28,7 +25,6 @@ LLVMAddAlias
 LLVMAddArgumentPromotionPass
 LLVMAddAttribute
 LLVMAddBasicAliasAnalysisPass
-LLVMRustAddPrintModulePass
 LLVMAddCFGSimplificationPass
 LLVMAddCase
 LLVMAddClause
@@ -589,9 +585,6 @@ LLVMStructCreateNamed
 LLVMStructSetBody
 LLVMInlineAsm
 LLVMInitializePasses
-LLVMAddPass
-LLVMCreatePass
-LLVMDestroyPass
 LLVMDIBuilderCreate
 LLVMDIBuilderDispose
 LLVMDIBuilderFinalize
@@ -616,3 +609,15 @@ LLVMDIBuilderCreateEnumerationType
 LLVMDIBuilderCreateUnionType
 LLVMDIBuilderCreateTemplateTypeParameter
 LLVMSetUnnamedAddr
+LLVMRustAddPass
+LLVMRustAddAnalysisPasses
+LLVMRustAddLibraryInfo
+LLVMRustCreateTargetMachine
+LLVMRustRunFunctionPassManager
+LLVMRustPrintModule
+LLVMRustDisposeTargetMachine
+LLVMRustAddBuilderLibraryInfo
+LLVMRustSetLLVMOptions
+LLVMRustPrintPasses
+LLVMRustSetNormalizedTarget
+LLVMRustAddAlwaysInlinePass
index eeefb19883eb38666957f25fa5f4247439556e3f..94bb00aab77577cc4871d4c9d42cd6af762e33dd 100644 (file)
@@ -59,3 +59,5 @@
 #include <fcntl.h>
 #include <unistd.h>
 #endif
+
+extern const char* LLVMRustError;
index 6475012e0097e9e7180f7eb55fce18ed49fe012e..2571d60145906db1d20da9a6723e14d1979c15a0 100644 (file)
@@ -121,54 +121,54 @@ fn main() {
     io::println("\nTreeMap:");
 
     {
-        let mut map = TreeMap::new::<uint, uint>();
+        let mut map: TreeMap<uint,uint> = TreeMap::new();
         ascending(&mut map, n_keys);
     }
 
     {
-        let mut map = TreeMap::new::<uint, uint>();
+        let mut map: TreeMap<uint,uint> = TreeMap::new();
         descending(&mut map, n_keys);
     }
 
     {
         io::println(" Random integers:");
-        let mut map = TreeMap::new::<uint, uint>();
+        let mut map: TreeMap<uint,uint> = TreeMap::new();
         vector(&mut map, n_keys, rand);
     }
 
     io::println("\nHashMap:");
 
     {
-        let mut map = HashMap::new::<uint, uint>();
+        let mut map: HashMap<uint,uint> = HashMap::new();
         ascending(&mut map, n_keys);
     }
 
     {
-        let mut map = HashMap::new::<uint, uint>();
+        let mut map: HashMap<uint,uint> = HashMap::new();
         descending(&mut map, n_keys);
     }
 
     {
         io::println(" Random integers:");
-        let mut map = HashMap::new::<uint, uint>();
+        let mut map: HashMap<uint,uint> = HashMap::new();
         vector(&mut map, n_keys, rand);
     }
 
     io::println("\nTrieMap:");
 
     {
-        let mut map = TrieMap::new::<uint>();
+        let mut map: TrieMap<uint> = TrieMap::new();
         ascending(&mut map, n_keys);
     }
 
     {
-        let mut map = TrieMap::new::<uint>();
+        let mut map: TrieMap<uint> = TrieMap::new();
         descending(&mut map, n_keys);
     }
 
     {
         io::println(" Random integers:");
-        let mut map = TrieMap::new::<uint>();
+        let mut map: TrieMap<uint> = TrieMap::new();
         vector(&mut map, n_keys, rand);
     }
 }
index 22622c1cac33afa2ae24ab7f657fc9b74c69a9ed..fe77196e2b101512fc89c03a178e9d882b29572c 100644 (file)
@@ -169,16 +169,28 @@ fn main() {
     {
         let mut rng = rand::IsaacRng::new_seeded(seed);
         let mut results = empty_results();
-        results.bench_int(&mut rng, num_keys, max, || HashSet::new::<uint>());
-        results.bench_str(&mut rng, num_keys, || HashSet::new::<~str>());
+        results.bench_int(&mut rng, num_keys, max, || {
+            let s: HashSet<uint> = HashSet::new();
+            s
+        });
+        results.bench_str(&mut rng, num_keys, || {
+            let s: HashSet<~str> = HashSet::new();
+            s
+        });
         write_results("std::hashmap::HashSet", &results);
     }
 
     {
         let mut rng = rand::IsaacRng::new_seeded(seed);
         let mut results = empty_results();
-        results.bench_int(&mut rng, num_keys, max, || TreeSet::new::<uint>());
-        results.bench_str(&mut rng, num_keys, || TreeSet::new::<~str>());
+        results.bench_int(&mut rng, num_keys, max, || {
+            let s: TreeSet<uint> = TreeSet::new();
+            s
+        });
+        results.bench_str(&mut rng, num_keys, || {
+            let s: TreeSet<~str> = TreeSet::new();
+            s
+        });
         write_results("extra::treemap::TreeSet", &results);
     }
 
index 1903786eef85190e5ce069f0d7f7f9245776a3cf..3102fb2664f7d53eb36d38584bcd851b0b691cfc 100644 (file)
@@ -16,8 +16,8 @@
 
 #[nolink]
 extern {
-    static mut debug_static_mut: libc::c_int;
-    pub fn debug_static_mut_check_four();
+    static mut rust_dbg_static_mut: libc::c_int;
+    pub fn rust_dbg_static_mut_check_four();
     #[cfg(stage37)] //~ ERROR expected item after attributes
 }
 
diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs
new file mode 100644 (file)
index 0000000..e483334
--- /dev/null
@@ -0,0 +1,37 @@
+#[no_std];
+
+struct S<T> {
+    contents: T,
+}
+
+impl<T> S<T> {
+    fn new<U>(x: T, _: U) -> S<T> {
+        S {
+            contents: x,
+        }
+    }
+}
+
+trait Trait<T> {
+    fn new<U>(x: T, y: U) -> Self;
+}
+
+struct S2 {
+    contents: int,
+}
+
+impl Trait<int> for S2 {
+    fn new<U>(x: int, _: U) -> S2 {
+        S2 {
+            contents: x,
+        }
+    }
+}
+
+fn main() {
+    let _ = S::new::<int,float>(1, 1.0);    //~ ERROR the impl referenced by this path has 1 type parameter, but 0 type parameters were supplied
+    let _ = S::<'self,int>::new::<float>(1, 1.0);  //~ ERROR this impl has no lifetime parameter
+    let _: S2 = Trait::new::<int,float>(1, 1.0);    //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied
+    let _: S2 = Trait::<'self,int>::new::<float>(1, 1.0);   //~ ERROR this trait has no lifetime parameter
+}
+
diff --git a/src/test/compile-fail/borrowck-alias-mut-base-ptr.rs b/src/test/compile-fail/borrowck-alias-mut-base-ptr.rs
deleted file mode 100644 (file)
index c51cf5b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Test that attempt to alias `&mut` pointer while pointee is borrowed
-// yields an error.
-//
-// Example from src/middle/borrowck/doc.rs
-
-use std::util::swap;
-
-fn foo(t0: &mut int) {
-    let p: &int = &*t0; // Freezes `*t0`
-    let q: &const &mut int = &const t0; //~ ERROR cannot borrow `t0`
-    **q = 22; //~ ERROR cannot assign to an `&mut` in a `&const` pointer
-}
-
-fn main() {
-}
\ No newline at end of file
diff --git a/src/test/compile-fail/borrowck-assign-to-andmut-in-aliasable-loc.rs b/src/test/compile-fail/borrowck-assign-to-andmut-in-aliasable-loc.rs
new file mode 100644 (file)
index 0000000..e4a23e7
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'self> {
+    pointer: &'self mut int
+}
+
+fn a(s: &S) {
+    *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn b(s: &mut S) {
+    *s.pointer += 1;
+}
+
+fn c(s: & &mut S) {
+    *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs b/src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs
new file mode 100644 (file)
index 0000000..dcef74b
--- /dev/null
@@ -0,0 +1,31 @@
+// 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.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'self> {
+    pointer: &'self mut int
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+    S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+    let mut x = 1;
+
+    {
+        let mut y = S { pointer: &mut x };
+        let z = copy_borrowed_ptr(&mut y);
+        *y.pointer += 1; //~ ERROR cannot assign
+        *z.pointer += 1;
+    }
+}
index 7e9c298ba4732582e7b4ed8799e59f5604290055..843b5436d842c7c89322641dc8c0c70a501df5ef 100644 (file)
@@ -11,16 +11,6 @@ fn foo(t0: & &mut int) {
     **t1 = 22; //~ ERROR cannot assign
 }
 
-fn foo2(t0: &const &mut int) {
-    // Note: reborrowing from an &const actually yields two errors, since it
-    // is unsafe in two ways: we can't control the aliasing, and we can't
-    // control the mutation.
-    let t1 = t0;
-    let p: &int = &**t0; //~ ERROR cannot borrow an `&mut` in a `&const` pointer
-    //~^ ERROR unsafe borrow of aliasable, const value
-    **t1 = 22; //~ ERROR cannot assign
-}
-
 fn foo3(t0: &mut &mut int) {
     let t1 = &mut *t0;
     let p: &int = &**t0; //~ ERROR cannot borrow
@@ -28,4 +18,4 @@ fn foo3(t0: &mut &mut int) {
 }
 
 fn main() {
-}
\ No newline at end of file
+}
index bd87a57af2570fb7b9ba71177c72499672e03f1a..c004b3d0e5498fb821eda257abf44e2beec7124c 100644 (file)
@@ -13,8 +13,7 @@
 use std::hashmap::HashMap;
 
 fn main() {
-    let mut buggy_map :HashMap<uint, &uint> =
-      HashMap::new::<uint, &uint>();
+    let mut buggy_map: HashMap<uint, &uint> = HashMap::new();
     buggy_map.insert(42, &*~1); //~ ERROR borrowed value does not live long enough
 
     // but it is ok if we use a temporary
index 0aa7cbf50b7a327e8a2ec1df94d33123811cadda..537e52120d9f1f2c02712f0037ec5aaf6dc55d65 100644 (file)
@@ -14,29 +14,18 @@ struct Foo {
 
 impl Foo {
     pub fn f(&self) {}
-    pub fn g(&const self) {}
     pub fn h(&mut self) {}
 }
 
 fn a(x: &mut Foo) {
     x.f();
-    x.g();
     x.h();
 }
 
 fn b(x: &Foo) {
     x.f();
-    x.g();
     x.h(); //~ ERROR cannot borrow
 }
 
-fn c(x: &const Foo) {
-    x.f(); //~ ERROR cannot borrow
-    //~^ ERROR unsafe borrow
-    x.g();
-    x.h(); //~ ERROR cannot borrow
-    //~^ ERROR unsafe borrow
-}
-
 fn main() {
 }
index 59cac0c5d953a8f8f180f4d533c15ff5eac32d99..ea840a28b4e6ac97efd6fe7ebb3af8bbcbe691a9 100644 (file)
@@ -32,14 +32,6 @@ fn pre_freeze() {
     borrow_mut(v); //~ ERROR cannot borrow
 }
 
-fn pre_const() {
-    // In this instance, the freeze starts before the mut borrow.
-
-    let mut v = ~3;
-    let _w = &const v;
-    borrow_mut(v);
-}
-
 fn post_freeze() {
     // In this instance, the const alias starts after the borrow.
 
index 6a8e64377aab22898a4afd171b5a370c8952cc51..8a4a2cdedb23095987208afbdf2383b9e9c1722f 100644 (file)
@@ -29,16 +29,5 @@ fn has_mut_vec_but_tries_to_change_it() {
     }
 }
 
-fn takes_const_elt(_v: &const int, f: &fn()) {
-    f();
-}
-
-fn has_mut_vec_and_tries_to_change_it() {
-    let mut v = ~[1, 2, 3];
-    do takes_const_elt(&const v[0]) {
-        v[1] = 4;
-    }
-}
-
 fn main() {
 }
diff --git a/src/test/compile-fail/borrowck-pat-by-value-binding.rs b/src/test/compile-fail/borrowck-pat-by-value-binding.rs
deleted file mode 100644 (file)
index e77f524..0000000
+++ /dev/null
@@ -1,45 +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.
-
-fn process<T>(_t: T) {}
-
-fn match_const_opt_by_mut_ref(v: &const Option<int>) {
-    match *v {
-      Some(ref mut i) => process(i), //~ ERROR cannot borrow
-        //~^ ERROR unsafe borrow of aliasable, const value
-      None => ()
-    }
-}
-
-fn match_const_opt_by_const_ref(v: &const Option<int>) {
-    match *v {
-      Some(ref const i) => process(i),
-        //~^ ERROR unsafe borrow of aliasable, const value
-      None => ()
-    }
-}
-
-fn match_const_opt_by_imm_ref(v: &const Option<int>) {
-    match *v {
-      Some(ref i) => process(i), //~ ERROR cannot borrow
-        //~^ ERROR unsafe borrow of aliasable, const value
-      None => ()
-    }
-}
-
-fn match_const_opt_by_value(v: &const Option<int>) {
-    match *v {
-      Some(i) => process(i),
-      None => ()
-    }
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/borrowck-pat-enum.rs b/src/test/compile-fail/borrowck-pat-enum.rs
deleted file mode 100644 (file)
index f1cca89..0000000
+++ /dev/null
@@ -1,68 +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.
-
-fn match_ref(v: Option<int>) -> int {
-    match v {
-      Some(ref i) => {
-        *i
-      }
-      None => {0}
-    }
-}
-
-fn match_ref_unused(v: Option<int>) {
-    match v {
-      Some(_) => {}
-      None => {}
-    }
-}
-
-fn match_const_reg(v: &const Option<int>) -> int {
-    match *v {
-      Some(ref i) => {*i} //~ ERROR cannot borrow
-        //~^ ERROR unsafe borrow
-      None => {0}
-    }
-}
-
-fn impure(_i: int) {
-}
-
-fn match_const_reg_unused(v: &const Option<int>) {
-    match *v {
-      Some(_) => {impure(0)} // OK because nothing is captured
-      None => {}
-    }
-}
-
-fn match_const_reg_impure(v: &const Option<int>) {
-    match *v {
-      Some(ref i) => {impure(*i)} //~ ERROR cannot borrow
-        //~^ ERROR unsafe borrow
-      None => {}
-    }
-}
-
-fn match_imm_reg(v: &Option<int>) {
-    match *v {
-      Some(ref i) => {impure(*i)} // OK because immutable
-      None => {}
-    }
-}
-
-fn match_mut_reg(v: &mut Option<int>) {
-    match *v {
-      Some(ref i) => {impure(*i)} // OK, frozen
-      None => {}
-    }
-}
-
-fn main() {
-}
index 43459acaaf1850d6ee6d01c088fa319bafd86d14..c87428cd300a7ab47bdcb7ca2dc4cac3d0397660 100644 (file)
@@ -35,12 +35,6 @@ fn aliased_imm() {
     borrow(v);
 }
 
-fn aliased_const() {
-    let mut v = ~3;
-    let _w = &const v;
-    borrow(v);
-}
-
 fn aliased_mut() {
     let mut v = ~3;
     let _w = &mut v;
diff --git a/src/test/compile-fail/borrowck-uniq-via-ref.rs b/src/test/compile-fail/borrowck-uniq-via-ref.rs
deleted file mode 100644 (file)
index 8bf627d..0000000
+++ /dev/null
@@ -1,67 +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.
-
-struct Rec {
-    f: ~int,
-}
-
-struct Outer {
-    f: Inner
-}
-
-struct Inner {
-    g: Innermost
-}
-
-struct Innermost {
-    h: ~int,
-}
-
-fn borrow(_v: &int) {}
-fn borrow_const(_v: &const int) {}
-
-fn box_mut(v: &mut ~int) {
-    borrow(*v); // OK: &mut -> &imm
-}
-
-fn box_mut_rec(v: &mut Rec) {
-    borrow(v.f); // OK: &mut -> &imm
-}
-
-fn box_mut_recs(v: &mut Outer) {
-    borrow(v.f.g.h); // OK: &mut -> &imm
-}
-
-fn box_imm(v: &~int) {
-    borrow(*v); // OK
-}
-
-fn box_imm_rec(v: &Rec) {
-    borrow(v.f); // OK
-}
-
-fn box_imm_recs(v: &Outer) {
-    borrow(v.f.g.h); // OK
-}
-
-fn box_const(v: &const ~int) {
-    borrow_const(*v); //~ ERROR unsafe borrow
-}
-
-fn box_const_rec(v: &const Rec) {
-    borrow_const(v.f); //~ ERROR unsafe borrow
-}
-
-fn box_const_recs(v: &const Outer) {
-    borrow_const(v.f.g.h); //~ ERROR unsafe borrow
-}
-
-fn main() {
-}
index 630eb4b538d58bc93070efde8e8e65a75fb45b28..e42c6b658e4f7b87b5307935c361bc1702e3f940 100644 (file)
@@ -23,13 +23,10 @@ fn main() {
 
     // @int <: X
     //
-    // This constraint forces X to be
-    // @const int.
-    r(@3);
+    // Here the type check fails because @const is gone and there is no
+    // supertype.
+    r(@3);  //~ ERROR mismatched types
 
-    // Here the type check succeeds but the
-    // mutability check will fail, because the
-    // type of r has been inferred to be
-    // fn(@const int) -> @const int
-    *r(@mut 3) = 4; //~ ERROR cannot assign to const dereference of @ pointer
+    // Here the type check succeeds.
+    *r(@mut 3) = 4;
 }
index 875ad0d2b62a5e8c31ce75a0e55acfa296e35199..273394794a9965e69e5ce12a6670cd70db6ba91b 100644 (file)
@@ -9,66 +9,66 @@
 // except according to those terms.
 
 fn main() {
-    // bad arguments to the ifmt! call
+    // bad arguments to the format! call
 
-    ifmt!();                //~ ERROR: expects at least one
-    ifmt!("{}");            //~ ERROR: invalid reference to argument
+    format!();                //~ ERROR: requires at least a format string
+    format!("{}");            //~ ERROR: invalid reference to argument
 
-    ifmt!("{1}", 1);        //~ ERROR: invalid reference to argument `1`
+    format!("{1}", 1);        //~ ERROR: invalid reference to argument `1`
                             //~^ ERROR: argument never used
-    ifmt!("{foo}");         //~ ERROR: no argument named `foo`
+    format!("{foo}");         //~ ERROR: no argument named `foo`
 
-    ifmt!("{}", 1, 2);               //~ ERROR: argument never used
-    ifmt!("{1}", 1, 2);              //~ ERROR: argument never used
-    ifmt!("{}", 1, foo=2);           //~ ERROR: named argument never used
-    ifmt!("{foo}", 1, foo=2);        //~ ERROR: argument never used
-    ifmt!("", foo=2);                //~ ERROR: named argument never used
+    format!("{}", 1, 2);               //~ ERROR: argument never used
+    format!("{1}", 1, 2);              //~ ERROR: argument never used
+    format!("{}", 1, foo=2);           //~ ERROR: named argument never used
+    format!("{foo}", 1, foo=2);        //~ ERROR: argument never used
+    format!("", foo=2);                //~ ERROR: named argument never used
 
-    ifmt!("{0:d} {0:s}", 1);         //~ ERROR: redeclared with type `s`
-    ifmt!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s`
+    format!("{0:d} {0:s}", 1);         //~ ERROR: redeclared with type `s`
+    format!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s`
 
-    ifmt!("{foo}", foo=1, foo=2);    //~ ERROR: duplicate argument
-    ifmt!("#");                      //~ ERROR: `#` reference used
-    ifmt!("", foo=1, 2);             //~ ERROR: positional arguments cannot follow
-    ifmt!("" 1);                     //~ ERROR: expected token: `,`
-    ifmt!("", 1 1);                  //~ ERROR: expected token: `,`
+    format!("{foo}", foo=1, foo=2);    //~ ERROR: duplicate argument
+    format!("#");                      //~ ERROR: `#` reference used
+    format!("", foo=1, 2);             //~ ERROR: positional arguments cannot follow
+    format!("" 1);                     //~ ERROR: expected token: `,`
+    format!("", 1 1);                  //~ ERROR: expected token: `,`
 
-    ifmt!("{0, select, a{} a{} other{}}", "a");    //~ ERROR: duplicate selector
-    ifmt!("{0, plural, =1{} =1{} other{}}", 1u);   //~ ERROR: duplicate selector
-    ifmt!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector
+    format!("{0, select, a{} a{} other{}}", "a");    //~ ERROR: duplicate selector
+    format!("{0, plural, =1{} =1{} other{}}", 1u);   //~ ERROR: duplicate selector
+    format!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector
 
     // bad syntax of the format string
 
-    ifmt!("{"); //~ ERROR: unterminated format string
-    ifmt!("\\ "); //~ ERROR: invalid escape
-    ifmt!("\\"); //~ ERROR: expected an escape
+    format!("{"); //~ ERROR: unterminated format string
+    format!("\\ "); //~ ERROR: invalid escape
+    format!("\\"); //~ ERROR: expected an escape
 
-    ifmt!("{0, }", 1); //~ ERROR: expected method
-    ifmt!("{0, foo}", 1); //~ ERROR: unknown method
-    ifmt!("{0, select}", "a"); //~ ERROR: must be followed by
-    ifmt!("{0, plural}", 1); //~ ERROR: must be followed by
+    format!("{0, }", 1); //~ ERROR: expected method
+    format!("{0, foo}", 1); //~ ERROR: unknown method
+    format!("{0, select}", "a"); //~ ERROR: must be followed by
+    format!("{0, plural}", 1); //~ ERROR: must be followed by
 
-    ifmt!("{0, select, a{{}", 1); //~ ERROR: must be terminated
-    ifmt!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector
-    ifmt!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other`
-    ifmt!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer
-    ifmt!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:`
-    ifmt!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer
-    ifmt!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural
-    ifmt!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other`
-    ifmt!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other`
+    format!("{0, select, a{{}", 1); //~ ERROR: must be terminated
+    format!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector
+    format!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other`
+    format!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer
+    format!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:`
+    format!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer
+    format!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural
+    format!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other`
+    format!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other`
 
-    ifmt!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as
-    ifmt!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to
-    ifmt!("{0, select, other{}} \
-           {0, plural, other{}}", "a");
+    format!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as
+    format!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to
+    format!("{0, select, other{}} \
+             {0, plural, other{}}", "a");
     //~^ ERROR: declared with multiple formats
 
     // It should be illegal to use implicit placement arguments nested inside of
     // format strings because otherwise the "internal pointer of which argument
     // is next" would be invalidated if different cases had different numbers of
     // arguments.
-    ifmt!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit
-    ifmt!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit
-    ifmt!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit
+    format!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit
+    format!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit
+    format!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit
 }
index 76a697b174f5447b59cc00329e56e89729719553..21c2d4b5934df5e950506145b4d4fb6b0b1fb027 100644 (file)
@@ -9,6 +9,6 @@
 // except according to those terms.
 
 fn main() {
-    ifmt!("{0, plural, other{}}", "a");
+    format!("{0, plural, other{}}", "a");
     //~^ ERROR: expected uint but found
 }
index abe3b6ed65a6d577467d840fea14377df6610772..8a72b7920d7d2b8b189c4190c47fc104ff247eda 100644 (file)
@@ -9,6 +9,6 @@
 // except according to those terms.
 
 fn main() {
-    ifmt!("{0, select, other{}}", 2);
+    format!("{0, select, other{}}", 2);
     //~^ ERROR: expected &str but found integral
 }
index 427f5ea562c7eb6c6c3389acaf3090e4dc2189e6..830b041bbc7156c365629386042e245a24815346 100644 (file)
@@ -9,6 +9,6 @@
 // except according to those terms.
 
 fn main() {
-    ifmt!("{:d}", "3");
+    format!("{:d}", "3");
     //~^ ERROR: failed to find an implementation of trait std::fmt::Signed
 }
index 85556f9501acb436715f0f19676ca96a3ba33006..d90b3d3cf81df865054166f3d22b0f02b82978af 100644 (file)
@@ -9,6 +9,6 @@
 // except according to those terms.
 
 fn main() {
-    ifmt!("{:notimplemented}", "3");
+    format!("{:notimplemented}", "3");
     //~^ ERROR: unknown format trait `notimplemented`
 }
diff --git a/src/test/compile-fail/issue-3969.rs b/src/test/compile-fail/issue-3969.rs
deleted file mode 100644 (file)
index b60a54a..0000000
+++ /dev/null
@@ -1,25 +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.
-
-struct Bike {
-    name: ~str,
-}
-
-trait BikeMethods {
-    fn woops(&const self) -> ~str;
-}
-
-impl BikeMethods for Bike {
-    fn woops() -> ~str { ~"foo" }
-    //~^ ERROR has a `&const self` declaration in the trait, but not in the impl
-}
-
-pub fn main() {
-}
diff --git a/src/test/compile-fail/issue-4096.rs b/src/test/compile-fail/issue-4096.rs
deleted file mode 100644 (file)
index 3f1172b..0000000
+++ /dev/null
@@ -1,22 +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.
-
-pub trait Nummy {
-    fn from_inty<T>() -> Self;
-}
-
-impl Nummy for float {
-    fn from_inty<T>() -> float { 0.0 }
-}
-
-fn main() {
-    let _1:float = Nummy::from_inty::<int>();  //~ ERROR not enough type
-    //~^ NOTE Static methods have an extra implicit type parameter
-}
diff --git a/src/test/compile-fail/keyword-as-as-identifier.rs b/src/test/compile-fail/keyword-as-as-identifier.rs
new file mode 100644 (file)
index 0000000..f307b12
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py as'
+
+fn main() {
+    let as = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-break-as-identifier.rs b/src/test/compile-fail/keyword-break-as-identifier.rs
new file mode 100644 (file)
index 0000000..1e2725e
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py break'
+
+fn main() {
+    let break = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-do-as-identifier.rs b/src/test/compile-fail/keyword-do-as-identifier.rs
new file mode 100644 (file)
index 0000000..b2a0c8a
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py do'
+
+fn main() {
+    let do = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-else-as-identifier.rs b/src/test/compile-fail/keyword-else-as-identifier.rs
new file mode 100644 (file)
index 0000000..101fd93
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py else'
+
+fn main() {
+    let else = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-enum-as-identifier.rs b/src/test/compile-fail/keyword-enum-as-identifier.rs
new file mode 100644 (file)
index 0000000..ed504cc
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py enum'
+
+fn main() {
+    let enum = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-extern-as-identifier.rs b/src/test/compile-fail/keyword-extern-as-identifier.rs
new file mode 100644 (file)
index 0000000..3260506
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py extern'
+
+fn main() {
+    let extern = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-false-as-identifier.rs b/src/test/compile-fail/keyword-false-as-identifier.rs
new file mode 100644 (file)
index 0000000..d875898
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py false'
+
+fn main() {
+    let false = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-fn-as-identifier.rs b/src/test/compile-fail/keyword-fn-as-identifier.rs
new file mode 100644 (file)
index 0000000..8c98da2
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py fn'
+
+fn main() {
+    let fn = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-for-as-identifier.rs b/src/test/compile-fail/keyword-for-as-identifier.rs
new file mode 100644 (file)
index 0000000..196a339
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py for'
+
+fn main() {
+    let for = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-if-as-identifier.rs b/src/test/compile-fail/keyword-if-as-identifier.rs
new file mode 100644 (file)
index 0000000..05f82ec
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py if'
+
+fn main() {
+    let if = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-impl-as-identifier.rs b/src/test/compile-fail/keyword-impl-as-identifier.rs
new file mode 100644 (file)
index 0000000..1dd2180
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py impl'
+
+fn main() {
+    let impl = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-let-as-identifier.rs b/src/test/compile-fail/keyword-let-as-identifier.rs
new file mode 100644 (file)
index 0000000..0069a26
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py let'
+
+fn main() {
+    let let = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-loop-as-identifier.rs b/src/test/compile-fail/keyword-loop-as-identifier.rs
new file mode 100644 (file)
index 0000000..6e469e8
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py loop'
+
+fn main() {
+    let loop = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-match-as-identifier.rs b/src/test/compile-fail/keyword-match-as-identifier.rs
new file mode 100644 (file)
index 0000000..9155ebc
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py match'
+
+fn main() {
+    let match = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-mod-as-identifier.rs b/src/test/compile-fail/keyword-mod-as-identifier.rs
new file mode 100644 (file)
index 0000000..02f57e9
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py mod'
+
+fn main() {
+    let mod = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-mut-as-identifier.rs b/src/test/compile-fail/keyword-mut-as-identifier.rs
new file mode 100644 (file)
index 0000000..b5d36e5
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py mut'
+
+fn main() {
+    let mut = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-priv-as-identifier.rs b/src/test/compile-fail/keyword-priv-as-identifier.rs
new file mode 100644 (file)
index 0000000..7cbaeb9
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py priv'
+
+fn main() {
+    let priv = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-pub-as-identifier.rs b/src/test/compile-fail/keyword-pub-as-identifier.rs
new file mode 100644 (file)
index 0000000..aa67974
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py pub'
+
+fn main() {
+    let pub = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-ref-as-identifier.rs b/src/test/compile-fail/keyword-ref-as-identifier.rs
new file mode 100644 (file)
index 0000000..72af521
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py ref'
+
+fn main() {
+    let ref = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-return-as-identifier.rs b/src/test/compile-fail/keyword-return-as-identifier.rs
new file mode 100644 (file)
index 0000000..c567644
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py return'
+
+fn main() {
+    let return = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-self-as-identifier.rs b/src/test/compile-fail/keyword-self-as-identifier.rs
new file mode 100644 (file)
index 0000000..8bb5214
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py self'
+
+fn main() {
+    let self = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-static-as-identifier.rs b/src/test/compile-fail/keyword-static-as-identifier.rs
new file mode 100644 (file)
index 0000000..7268c4f
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py static'
+
+fn main() {
+    let static = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-struct-as-identifier.rs b/src/test/compile-fail/keyword-struct-as-identifier.rs
new file mode 100644 (file)
index 0000000..bd42eac
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py struct'
+
+fn main() {
+    let struct = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-super-as-identifier.rs b/src/test/compile-fail/keyword-super-as-identifier.rs
new file mode 100644 (file)
index 0000000..0378c32
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py super'
+
+fn main() {
+    let super = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-trait-as-identifier.rs b/src/test/compile-fail/keyword-trait-as-identifier.rs
new file mode 100644 (file)
index 0000000..95c0d17
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py trait'
+
+fn main() {
+    let trait = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-true-as-identifier.rs b/src/test/compile-fail/keyword-true-as-identifier.rs
new file mode 100644 (file)
index 0000000..048b640
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py true'
+
+fn main() {
+    let true = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-type-as-identifier.rs b/src/test/compile-fail/keyword-type-as-identifier.rs
new file mode 100644 (file)
index 0000000..0aaa2a6
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py type'
+
+fn main() {
+    let type = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-unsafe-as-identifier.rs b/src/test/compile-fail/keyword-unsafe-as-identifier.rs
new file mode 100644 (file)
index 0000000..1b631eb
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py unsafe'
+
+fn main() {
+    let unsafe = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-use-as-identifier.rs b/src/test/compile-fail/keyword-use-as-identifier.rs
new file mode 100644 (file)
index 0000000..e82afd5
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py use'
+
+fn main() {
+    let use = "foo"; //~ error: ident
+}
diff --git a/src/test/compile-fail/keyword-while-as-identifier.rs b/src/test/compile-fail/keyword-while-as-identifier.rs
new file mode 100644 (file)
index 0000000..95cea65
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py while'
+
+fn main() {
+    let while = "foo"; //~ error: ident
+}
index f6fd8e29a4f4d274307b71439aaac90d8876b2db..19423c6690f316a77aa1ae2192c5d7fef7797af4 100644 (file)
@@ -14,8 +14,8 @@
 // Test that trait types printed in error msgs include the type arguments.
 
 fn main() {
-    let x: @Map<~str, ~str> = @HashMap::new::<~str, ~str>() as
-        @Map<~str, ~str>;
+    let x: @HashMap<~str, ~str> = @HashMap::new();
+    let x: @Map<~str, ~str> = x as @Map<~str, ~str>;
     let y: @Map<uint, ~str> = @x;
     //~^ ERROR expected trait std::container::Map but found @-ptr
 }
diff --git a/src/test/compile-fail/mutable-huh-ptr-assign.rs b/src/test/compile-fail/mutable-huh-ptr-assign.rs
deleted file mode 100644 (file)
index 4460da7..0000000
+++ /dev/null
@@ -1,23 +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.
-
-extern mod extra;
-
-fn main() {
-    unsafe fn f(v: *const int) {
-        *v = 1 //~ ERROR cannot assign
-    }
-
-    unsafe {
-        let mut a = 0;
-        let v = &mut a;
-        f(v);
-    }
-}
index 40d5a44124177029380626bab681bf271b6f255c..e60fbf4fc49a8c4904438b5eacd07be55db4943c 100644 (file)
@@ -23,17 +23,17 @@ fn main() {
 let x: float<int>; //~ ERROR type parameters are not allowed on this type
 let x: char<int>; //~ ERROR type parameters are not allowed on this type
 
-let x: int<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i8<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i16<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i32<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i64<'static>; //~ ERROR region parameters are not allowed on this type
-let x: uint<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u8<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u16<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u32<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u64<'static>; //~ ERROR region parameters are not allowed on this type
-let x: float<'static>; //~ ERROR region parameters are not allowed on this type
-let x: char<'static>; //~ ERROR region parameters are not allowed on this type
+let x: int<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i8<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i16<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i32<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i64<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: uint<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u8<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u16<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u32<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u64<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: float<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: char<'static>; //~ ERROR lifetime parameters are not allowed on this type
 
 }
index 9db023a779ba09a1d9a7394e7ff007f69994cd17..c3946b330103aa57ee361d81dd1349c6698f14da 100644 (file)
@@ -1,4 +1,5 @@
 // aux-build:private_variant_xc.rs
+// xfail-test
 
 extern mod private_variant_xc;
 
index ab2ac6cc0e5b9e4420042c933e578dd50b5c878a..ab365c1bf6fb38ced9cd18e02a886fd21b69bf96 100644 (file)
@@ -25,8 +25,4 @@ fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> {
     //~^ ERROR cannot infer an appropriate lifetime
 }
 
-fn a_fn4<'a,'b>() {
-    let _: int<'a> = 1; //~ ERROR region parameters are not allowed on this type
-}
-
 fn main() { }
index 65fbbfc6e198582698c20c8084fe73475a2ab936..351daf461d2fea5bfbaf26ca1cbb923c7bb501d6 100644 (file)
@@ -26,13 +26,6 @@ fn matcher2(x: opts) {
     }
 }
 
-fn matcher3(x: opts) {
-    match x {
-      a(ref mut i) | b(ref const i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
-      c(_) => {}
-    }
-}
-
 fn matcher4(x: opts) {
     match x {
       a(ref mut i) | b(ref i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
index 0fd82b5ace3a7f12aaf10ccd1283e989f2f94ea7..b637037f60e8f6167e9a3a8c415d36cf4bd6cfc0 100644 (file)
@@ -6,5 +6,5 @@ fn new() -> S { S }
 }
 
 fn main() {
-    let _ = a::S::new();    //~ ERROR function `new` is private
+    let _ = a::S::new();    //~ ERROR method `new` is private
 }
index 8314755af3b3d7195303d6aa1d34248bf0df6e79..371bac7a902feecd1470aa8d9fcd6bdbcaf202dc 100644 (file)
@@ -7,10 +7,10 @@ fn main() {
     // normal method on struct
     let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct();  //~ ERROR method `meth_struct` is private
     // static method on struct
-    let _ = xc_private_method_lib::Struct::static_meth_struct();  //~ ERROR function `static_meth_struct` is private
+    let _ = xc_private_method_lib::Struct::static_meth_struct();  //~ ERROR method `static_meth_struct` is private
 
     // normal method on enum
     let _ = xc_private_method_lib::Variant1(20).meth_enum();  //~ ERROR method `meth_enum` is private
     // static method on enum
-    let _ = xc_private_method_lib::Enum::static_meth_enum();  //~ ERROR function `static_meth_enum` is private
+    let _ = xc_private_method_lib::Enum::static_meth_enum();  //~ ERROR method `static_meth_enum` is private
 }
index 4e8f7d0d4aaa655b7aac2c5e5637956dd5e285f5..5f769fceded9cdbfe8e7067d3d3d3cbce0a5af46 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // Caveats - gdb prints any 8-bit value (meaning rust i8 and u8 values)
 // as its numerical value along with its associated ASCII char, there
 // doesn't seem to be any way around this. Also, gdb doesn't know
index 9de460163f091c8a2333c71b19d4d610d675fa74..8c19225311a2166aa541a781aeabfdfe0c4b9007 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // Gdb doesn't know about UTF-32 character encoding and will print a rust char as only
 // its numerical value.
 
index 3b398201726c3b10e5f618ea4241dd6452f4cd28..b947cd80984e4b39206ce0a0f5062ce652723395 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 2052ce3c93256e50a35c6dd6d32a07e425f9f9aa..6ac0239022520cb43c6f276a3f796eb2b2a6bfef 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index bf0edef83a0aadd3e7362e147cf730427719de8b..c91f64973ad81bdcc890ca17f1d561e100566138 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // Gdb doesn't know about UTF-32 character encoding and will print a rust char as only
 // its numerical value.
 
index 77f8bd21fb3d40ad36c5aeaf42cb821ab7f4a751..75a47a0d8fea71ca0ade87199a31038dba668276 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 8810c493aed07e5fe771c4c9f270b839c831b102..493cd2ab3e15c4b40702655d6f92a805662cef40 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index c62b05d13583a9cfa4c62bafa33f6676f8b908c3..50ac34cbcf6e191275a30a1eef48949aea8b733d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // Gdb doesn't know about UTF-32 character encoding and will print a rust char as only
 // its numerical value.
 
index cc41267e5c20255b02fd9be0a9e1920ca1b57345..1a87392e6af5a66c8a52384b1f581b6393d24a4c 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break _zzz
index 0e22980025be8d948d56b7a3a67669efa0810de2..03be8f7f220bf08d07508d2db6278a5032235e67 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 84b1ad44ebc1a174d02cfbe4b31868fb4a2d76a3..b08f549e129262d91ec7e74bafd74b3c4617af28 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index def0a8275c07f4948f41ee59381370c92803d793..8baca2baa4292c2c310378538b445640665c0f9b 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 1b57ab0d447e1d96c409ead80f55ec5c3f241e2d..a60c28cedb4a0166e35ee0d56352905eb515ff84 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index b6cf6afff1ed2bf91344546d8646fdc9532eab55..37ad6f173d181740d2dc4b862cfa583d3ea9d8d5 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 0269d3f4155746117721bdf8bf3881ee4d75b35b..63b46875a4947e99ee6f92d141c882702a834c3b 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index bc78b6cd35e947d401c9d3b88bff6b51fadc79e3..424e195e681cc63995605de7ec008127a9773e45 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 1594de4f5c05d6d057c2c637a7672d643cf674c0..de556bb17728b0dbfa808fdb6de8989acbc1a16e 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 1fe79b8e2a9e903b04ff5fb74b2232f245d918b3..5a410ef6462caf40fd9a80c3b9859f89f4b8083c 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index c3b48f27b7381382883a0d51533c3759c4054194..1bde5acd9f63e846e691637e51e73db1014c9544 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 1d883b5ab4df19abe47009efcc141a089dacbdd3..3151562f3f294ec8affba48e1e4e8a6dbea9bb22 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 20569691fd4b530e8b189a35030c06c6f1acde59..131f89c5a6da825c586726effb5f87d9625ca6a5 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 3a5380b8ab28aaf5df1dac466e0ff21f14fc38e7..f7ecad0b095e7b6b8d1a1f2cafed62bffd1d52c9 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 77ac7895366d78bb51f3db2857c923e30721aaa7..6a8f81aa843024211e4920cc429ebd8a973a366a 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
 // debugger:break zzz
index 0044def2707d465ae10ab65c9fe994878ce1e274..efc250018c116a6cb02868e06cc68ce9ee6b5c2f 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index ef75c93a56bea36941b3fa7c256f44fd92e1a5b2..9dd6d1ef173df35359aa17cc1612d95fe65edca7 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-test
+
 // 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.
@@ -8,8 +10,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index d6350e033f0ce3a05dd7e7c064b651826f774b79..b97fa7b636b397d2d4e128248d6a4ff0bf60de2b 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
 // debugger:break zzz
index 9aae26b50be78925c02c520a644eb61d78bbdb22..ed2f9e1a0c460159e43e83dfb20fad223ab5a4eb 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
 
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
index 296ad7ca861e6cfecfbfd9cb5898edd6d08a4d42..cc637f55fee8a95df7c6f3445ac83227220f0018 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
 
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
index d04818b56cdab785062fc6d04c97d7db15be323c..8af674d5ebd88ab3911a941796b2f563105bb4bb 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index ccdb20d8202048092cd28ef68e9f690975a56320..fe57f1f588e127dfbc227b88ccb0ae7134b8579a 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
 
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
index 11b142b3d2301510475ff23337c6ddbd6b86a8b3..a8846247f6f2f8f7524a9954ff4af32cf8830433 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z debug-info
 // debugger:run
 
index dd86b4a8673a5acddc6dbcd31e448d75efff135c..101b076a460939e8c37d1e26ed6f46ccbbf09969 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 21c4e74668590ea48b29995177d1bc919d51b5d3..6031a0ac714d0d5a12d42738d9fd7f61362e93fb 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 32251f4a8c230ba6db8179cf5e39c241c86d8efd..e167d7637adcaa4adde11c7bbbc658da42c3a43c 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index b350130df8f40083b98f818e90820c04cce7d426..2a3071ba496cef596d794c5932f1b4b6b18f17a5 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 409ecd5a0e2298b7f640bb7c26bc4c9174efbf93..1223786eb18a9ffadfb6a75a98e22a61528964d6 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 03de640053b7e90b1b8bb4665d9d84ca205cb624..ea2a7f0d94a3448cd1dfed7648ce607e9a3b5b8c 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
 
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
index f2d753fc88d8f0b02a71a3cf7c6abbb7dbe87cb4..99452dc255aff9c8648843b4608e9313295f72dd 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index a0b6f0e2b4f513862282d0c27e13144ffec24339..35df9454e1063315c094278e49fc0a7ad5d49520 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 4acf8d6efc7da07de366cb3989e9c5d533201122..e007f012ce2f6fb064346dd25ee53dadeb5022ae 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 07481011df3f99597588e3263113ac2602dade47..c68b4e7deedf4a5d0ea711e71a9c51a543aa18fc 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index f482846027ee4679bf3577b020eabfebebe216b8..4c793a6d9c77ee45916a68eebc1260cc049f8a5b 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 211f83e6107de40da7af7aa5dfca40cd2af7f765..5711c945b65caebb66d90822c51babc3b387a859 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index ad6c9a1cada4fdf68c3d0f2d8f9fa31e6946de72..c2f3a7f4324b33f6a963214739e3baf6d47457ac 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 03d7c44059fa19ec1cdb72a0460cbf8a1a5e3dee..e14880ae1a0d9ce3c7c990a5699dd9de7633b079 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 3f9dd1a0748fb7f15a8965e2c5385410c6ad5a68..32b3da074115eb4065a0fe12249e0c91ae690501 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 4d709070763cdbd982a4f2f7f8b567a798c6be1c..be26af4fe2f86817c4c672d542abe55cca599cc6 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index ba8c08e46fd1086ae39df475731a2d8803556a85..739d3aa78f45b6c969764a52280194486fcdcdaa 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 8622795ee90488fcd4d8ff205841ac96974c45e3..94e5b706ac60ac3651223631763dc2dc4bab274d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 02fd294a0bd5e555c12c9b31a177ef4fc7826aba..a75f4ff0086a5a40efe5709e63a2352cdcc43b56 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index f36e8454da99e252e4362fd40ee0ef21da7ddec3..90033b9c4e6e49cab72aa0f614a9d7c8e4154d4d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 93d3a9f2f116e8c070f5bc0cda6384f9e0cca023..203f6595a0492c0c8c9825b381672d803c107d82 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index cc7cab395934064fee3e29af8078ca79e62dc9d8..426d2f46e6b046b93ce08b642f722272c95da98f 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 57068df7c0bf33869a3457fdcd1dbca149619c1a..16a028808e7ccffa12f85122db8a929957e482ae 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index b79b65c5f80db3652f2f24fb592a247b131e82ed..a6a7b34c87b1d3ab0744b4e8a7ed230bb504f8e3 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index a532f7fbc2e0c9ae7e6a42f4327d1b6d8b002dd5..9018e24691e57ebc21a6c408ad5d5bc7e70a3eba 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 96a394b5ed7b98fd56786ba7ccc2c521993fec1e..11e890c44fa962bffc6190be942a92394c82980c 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 6532a3841e5ef42581024eb3ab993b5a493f75ba..01cc163d7aad0ba4fb088526dfeba06a715887e6 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 81a6c4a3ee56e1d7c9947cda0082a27e713e0d74..ee65e4dcb200a3835dca620957d71ea3544b05fe 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index ecc74e442d040626f0f6f22e1851eb1d53b101d5..5cf0bbdc8cf2e8c5bba962928410c413402ffd3b 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index c7879ac472092b726b25abd11f01cba13b018770..8542dd867f4a2d7810f81865c1885bae3238b6d3 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
 // debugger:break zzz
index ca02283de3788274b1c53aca09789100aa18b3de..307d141c3e27ebf5014504532d8f0afea977cb24 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 30be3b845634d4695a54cf81ca955f4630574321..fe6845a9077c9a14f98faa420ed36de46aa57084 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
 // debugger:break zzz
index 09bb690988c3115770ee5e6381bfb1f4ecc1e383..2dc1bfbf236c1ed23f7abbafb09049467134ad19 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 33468c974eba71a2c1278f9ff8a1237b6443cfff..2d666bf4cf5aa7d483c879144b234f209e67735c 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-test
+
 // 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.
@@ -8,8 +10,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index b2611b3077d61a2c517a0f23003dd272de7ea529..e5844cd19a719f5beb3b36216ca4f2c8c611f3e0 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 940edd08975194584b5b9d3a558ebcda50f097f9..8a50760bcc27fcf5ff79526b43207fdfb3716de1 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index ada3802e15d5a899edb651c11110bd0980d2d26b..1368053f48cb4e7d5e16cb68183bfe6f1b541bfa 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 5dadfa84ba9671521ee8bd98af60359d09cfb51f..29950e6c76669507c9028508e8441bcf95c40038 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
 // debugger:break zzz
index 84f7e817d2488018e1c5a781f2a9483238a4bd07..8c085b1c62bc07a3c3bf64cd5f9fab0fbefea8da 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:break zzz
 // debugger:run
index 14ff159769d7076e4956064bd5759d4e897b4a86..95679f3a6163be1aa53954344c13f72b7defbb54 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 8387214b3bc62f75c55fc06b37c9ba8b473cf0b0..0dc52c7b220e528e3efe3254d32c60095eae15e8 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
 // debugger:break zzz
index 58a477900c3248113495824c2ca5d685d8195516..d35341516f2a73d5b3ab86420cdd5e65587e2d9e 100644 (file)
 
 trait MyIter {
     fn test_imm(&self);
-    fn test_const(&const self);
 }
 
 impl<'self> MyIter for &'self [int] {
     fn test_imm(&self) { assert_eq!(self[0], 1) }
-    fn test_const(&const self) { assert_eq!(self[0], 1) }
 }
 
 impl<'self> MyIter for &'self str {
     fn test_imm(&self) { assert_eq!(*self, "test") }
-    fn test_const(&const self) { assert_eq!(self[0], 't' as u8) }
 }
 
 pub fn main() {
@@ -40,15 +37,6 @@ pub fn main() {
 
     // XXX: Other types of mutable vecs don't currently exist
 
-    ([1]).test_const();
-    (~[1]).test_const();
-    (@[1]).test_const();
-    (&[1]).test_const();
-    ("test").test_const();
-    (~"test").test_const();
-    (@"test").test_const();
-    (&"test").test_const();
-
     // NB: We don't do this double autoreffing for &mut self because that would
     // allow creating a mutable pointer to a temporary, which would be a source
     // of confusion
index b00d8980c69fefbb56eb2be088a7793dbcda5671..fc643ec594089a4cc62f9eca2343f6e4afc6ee01 100644 (file)
@@ -13,7 +13,7 @@ struct Foo {
 }
 
 impl Foo {
-    pub fn f(&const self) {}
+    pub fn f(&self) {}
 }
 
 fn g(x: &mut Foo) {
diff --git a/src/test/run-pass/borrowck-pat-enum.rs b/src/test/run-pass/borrowck-pat-enum.rs
new file mode 100644 (file)
index 0000000..f320de3
--- /dev/null
@@ -0,0 +1,47 @@
+// xfail-pretty
+
+// 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.
+
+fn match_ref(v: Option<int>) -> int {
+    match v {
+      Some(ref i) => {
+        *i
+      }
+      None => {0}
+    }
+}
+
+fn match_ref_unused(v: Option<int>) {
+    match v {
+      Some(_) => {}
+      None => {}
+    }
+}
+
+fn impure(_i: int) {
+}
+
+fn match_imm_reg(v: &Option<int>) {
+    match *v {
+      Some(ref i) => {impure(*i)} // OK because immutable
+      None => {}
+    }
+}
+
+fn match_mut_reg(v: &mut Option<int>) {
+    match *v {
+      Some(ref i) => {impure(*i)} // OK, frozen
+      None => {}
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/borrowck-uniq-via-ref.rs b/src/test/run-pass/borrowck-uniq-via-ref.rs
new file mode 100644 (file)
index 0000000..44f3a8f
--- /dev/null
@@ -0,0 +1,54 @@
+// 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.
+
+struct Rec {
+    f: ~int,
+}
+
+struct Outer {
+    f: Inner
+}
+
+struct Inner {
+    g: Innermost
+}
+
+struct Innermost {
+    h: ~int,
+}
+
+fn borrow(_v: &int) {}
+
+fn box_mut(v: &mut ~int) {
+    borrow(*v); // OK: &mut -> &imm
+}
+
+fn box_mut_rec(v: &mut Rec) {
+    borrow(v.f); // OK: &mut -> &imm
+}
+
+fn box_mut_recs(v: &mut Outer) {
+    borrow(v.f.g.h); // OK: &mut -> &imm
+}
+
+fn box_imm(v: &~int) {
+    borrow(*v); // OK
+}
+
+fn box_imm_rec(v: &Rec) {
+    borrow(v.f); // OK
+}
+
+fn box_imm_recs(v: &Outer) {
+    borrow(v.f.g.h); // OK
+}
+
+fn main() {
+}
index 01907da38ad9da818df8b0f3b5e1aebf6c02c2af..03dd33b08e2350fe167a8421038f78678ebab177 100644 (file)
@@ -49,8 +49,8 @@ pub fn eat(&mut self) -> bool {
 }
 
 impl<T> Container for cat<T> {
-    fn len(&const self) -> uint { self.meows as uint }
-    fn is_empty(&const self) -> bool { self.meows == 0 }
+    fn len(&self) -> uint { self.meows as uint }
+    fn is_empty(&self) -> bool { self.meows == 0 }
 }
 
 impl<T> Mutable for cat<T> {
index 5525062581c1a6676b9caf575e1bebc750872ffe..52fa1399363cdf4de434167400dce4ee8bbb49c3 100644 (file)
@@ -3,14 +3,14 @@ struct SpeechMaker {
 }
 
 impl SpeechMaker {
-    pub fn how_many(&const self) -> uint { self.speeches }
+    pub fn how_many(&self) -> uint { self.speeches }
 }
 
-fn foo(speaker: &const SpeechMaker) -> uint {
+fn foo(speaker: &SpeechMaker) -> uint {
     speaker.how_many() + 33
 }
 
 pub fn main() {
     let lincoln = SpeechMaker {speeches: 22};
-    assert_eq!(foo(&const lincoln), 55);
+    assert_eq!(foo(&lincoln), 55);
 }
index 625f6ec30cc13657b3a92490bf89111c90081c83..84ee54cfdde6d548203c8ba43e7b09f61f17ad27 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn f(_: &const [int]) {}
+fn f(_: &[int]) {}
 
 pub fn main() {
     let v = [ 1, 2, 3 ];
index 2551d1a5cfcba32455e421de89a3cae23a37c9b8..90e63fc977d866841394f491be862265b95ef0c2 100644 (file)
 
 #[test]
 fn test_destroy_once() {
-    let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
+    let p = run::Process::new("echo", [], run::ProcessOptions::new());
+    let mut p = p.unwrap();
     p.destroy(); // this shouldn't crash (and nor should the destructor)
 }
 
 #[test]
 fn test_destroy_twice() {
-    let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
+    let p = run::Process::new("echo", [], run::ProcessOptions::new());
+    let mut p = p.unwrap();
     p.destroy(); // this shouldnt crash...
     p.destroy(); // ...and nor should this (and nor should the destructor)
 }
@@ -74,7 +76,8 @@ fn process_exists(pid: libc::pid_t) -> bool {
     }
 
     // this process will stay alive indefinitely trying to read from stdin
-    let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
+    let p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
+    let mut p = p.unwrap();
 
     assert!(process_exists(p.get_id()));
 
index b17632e4ee7523fd3fc24a2418c9fea9a347b92a..85b8f55af6712292ad10429815f62c301ed4517f 100644 (file)
@@ -19,8 +19,6 @@ struct Foo {
 }
 
 pub fn main() {
-    use std::hash::HashUtil; // necessary for IterBytes check
-
     let a = Foo {bar: 4, baz: -3};
 
     a == a;    // check for Eq impl w/o testing its correctness
index 2fa77ee16356bd8682143a0ae771d0ebf667d7af..04e0dbb6d0e931eb947e6fec7a7013c6ebb1a7b3 100644 (file)
@@ -17,8 +17,6 @@ struct Foo {
 }
 
 pub fn main() {
-    use std::hash::HashUtil; // necessary for IterBytes check
-
     let a = Foo {bar: 4, baz: -3};
 
     a == a;    // check for Eq impl w/o testing its correctness
index 54895d1796f409c33a92f521a887ffadecaa29d7..aba23e53282c788e7a4902ca5b3c54fc5a644e87 100644 (file)
@@ -24,8 +24,6 @@ struct E { a: int, b: int }
 
 #[deriving(Zero)]
 struct Lots {
-    a: ~str,
-    b: @str,
     c: Option<util::NonCopyable>,
     d: u8,
     e: char,
@@ -38,5 +36,6 @@ struct Lots {
 }
 
 fn main() {
-    assert!(Zero::zero::<Lots>().is_zero());
+    let lots: Lots = Zero::zero();
+    assert!(lots.is_zero());
 }
diff --git a/src/test/run-pass/enum-discrim-width-stuff.rs b/src/test/run-pass/enum-discrim-width-stuff.rs
new file mode 100644 (file)
index 0000000..a0b180f
--- /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.
+
+use std::sys;
+
+pub fn main() {
+    enum E { V = 0x1717171717171717 }
+    static C: E = V;
+    let expected: u64 = if sys::size_of::<uint>() < 8 {
+        0x17171717
+    } else {
+        0x1717171717171717
+    };
+    assert_eq!(expected, V as u64);
+    assert_eq!(expected, C as u64);
+    assert_eq!(fmt!("%?", V), ~"V");
+    assert_eq!(fmt!("%?", C), ~"V");
+}
index d026f041250b50dc34b2980870b5044927c5492c..eb67c45ed0015f136583ea1a9e6d44ce763de8b4 100644 (file)
@@ -16,5 +16,5 @@ pub fn main() {
     let arr = [1,2,3];
     let struc = Struc {a: 13u8, b: arr, c: 42};
     let s = sys::log_str(&struc);
-    assert_eq!(s, ~"{a: 13, b: [1, 2, 3], c: 42}");
+    assert_eq!(s, ~"{a: 13u8, b: [1, 2, 3], c: 42}");
 }
index 29a180db1855d82e09ad0e3aec15f55b49d4dda3..d59b8c77d006701d7348f48e467ace828521c629 100644 (file)
 use std::num::Float;
 
 pub fn main() {
-  let nan = Float::NaN::<float>();
+  let nan: float = Float::NaN();
   assert!((nan).is_NaN());
 
-  let inf = Float::infinity::<float>();
-  assert_eq!(-inf, Float::neg_infinity::<float>());
+  let inf: float = Float::infinity();
+  let neg_inf: float = Float::neg_infinity();
+  assert_eq!(-inf, neg_inf);
 
   assert!( nan !=  nan);
   assert!( nan != -nan);
index cba28463f990687f1a1854c9c376d92463e768c0..7bf9d004ee069d3c7613ec2dbf77f761e6c545b2 100644 (file)
@@ -21,193 +21,228 @@ impl fmt::Signed for B {
     fn fmt(_: &B, f: &mut fmt::Formatter) { f.buf.write("adios".as_bytes()); }
 }
 
+macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) })
+
 pub fn main() {
-    macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) })
 
     // Make sure there's a poly formatter that takes anything
-    t!(ifmt!("{:?}", 1), "1");
-    t!(ifmt!("{:?}", A), "{}");
-    t!(ifmt!("{:?}", ()), "()");
-    t!(ifmt!("{:?}", @(~1, "foo")), "@(~1, \"foo\")");
+    t!(format!("{:?}", 1), "1");
+    t!(format!("{:?}", A), "{}");
+    t!(format!("{:?}", ()), "()");
+    t!(format!("{:?}", @(~1, "foo")), "@(~1, \"foo\")");
 
     // Various edge cases without formats
-    t!(ifmt!(""), "");
-    t!(ifmt!("hello"), "hello");
-    t!(ifmt!("hello \\{"), "hello {");
+    t!(format!(""), "");
+    t!(format!("hello"), "hello");
+    t!(format!("hello \\{"), "hello {");
 
     // default formatters should work
-    t!(ifmt!("{}", 1i), "1");
-    t!(ifmt!("{}", 1i8), "1");
-    t!(ifmt!("{}", 1i16), "1");
-    t!(ifmt!("{}", 1i32), "1");
-    t!(ifmt!("{}", 1i64), "1");
-    t!(ifmt!("{}", 1u), "1");
-    t!(ifmt!("{}", 1u8), "1");
-    t!(ifmt!("{}", 1u16), "1");
-    t!(ifmt!("{}", 1u32), "1");
-    t!(ifmt!("{}", 1u64), "1");
-    t!(ifmt!("{}", 1.0f), "1");
-    t!(ifmt!("{}", 1.0f32), "1");
-    t!(ifmt!("{}", 1.0f64), "1");
-    t!(ifmt!("{}", "a"), "a");
-    t!(ifmt!("{}", ~"a"), "a");
-    t!(ifmt!("{}", @"a"), "a");
-    t!(ifmt!("{}", false), "false");
-    t!(ifmt!("{}", 'a'), "a");
+    t!(format!("{}", 1i), "1");
+    t!(format!("{}", 1i8), "1");
+    t!(format!("{}", 1i16), "1");
+    t!(format!("{}", 1i32), "1");
+    t!(format!("{}", 1i64), "1");
+    t!(format!("{}", 1u), "1");
+    t!(format!("{}", 1u8), "1");
+    t!(format!("{}", 1u16), "1");
+    t!(format!("{}", 1u32), "1");
+    t!(format!("{}", 1u64), "1");
+    t!(format!("{}", 1.0f), "1");
+    t!(format!("{}", 1.0f32), "1");
+    t!(format!("{}", 1.0f64), "1");
+    t!(format!("{}", "a"), "a");
+    t!(format!("{}", ~"a"), "a");
+    t!(format!("{}", @"a"), "a");
+    t!(format!("{}", false), "false");
+    t!(format!("{}", 'a'), "a");
 
     // At least exercise all the formats
-    t!(ifmt!("{:b}", true), "true");
-    t!(ifmt!("{:c}", '☃'), "☃");
-    t!(ifmt!("{:d}", 10), "10");
-    t!(ifmt!("{:i}", 10), "10");
-    t!(ifmt!("{:u}", 10u), "10");
-    t!(ifmt!("{:o}", 10u), "12");
-    t!(ifmt!("{:x}", 10u), "a");
-    t!(ifmt!("{:X}", 10u), "A");
-    t!(ifmt!("{:s}", "foo"), "foo");
-    t!(ifmt!("{:s}", ~"foo"), "foo");
-    t!(ifmt!("{:s}", @"foo"), "foo");
-    t!(ifmt!("{:p}", 0x1234 as *int), "0x1234");
-    t!(ifmt!("{:p}", 0x1234 as *mut int), "0x1234");
-    t!(ifmt!("{:d}", A), "aloha");
-    t!(ifmt!("{:d}", B), "adios");
-    t!(ifmt!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
-    t!(ifmt!("{1} {0}", 0, 1), "1 0");
-    t!(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1");
-    t!(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
-    t!(ifmt!("{} {0:s}", "a"), "a a");
-    t!(ifmt!("{} {0}", "a"), "a a");
+    t!(format!("{:b}", true), "true");
+    t!(format!("{:c}", '☃'), "☃");
+    t!(format!("{:d}", 10), "10");
+    t!(format!("{:i}", 10), "10");
+    t!(format!("{:u}", 10u), "10");
+    t!(format!("{:o}", 10u), "12");
+    t!(format!("{:x}", 10u), "a");
+    t!(format!("{:X}", 10u), "A");
+    t!(format!("{:s}", "foo"), "foo");
+    t!(format!("{:s}", ~"foo"), "foo");
+    t!(format!("{:s}", @"foo"), "foo");
+    t!(format!("{:p}", 0x1234 as *int), "0x1234");
+    t!(format!("{:p}", 0x1234 as *mut int), "0x1234");
+    t!(format!("{:d}", A), "aloha");
+    t!(format!("{:d}", B), "adios");
+    t!(format!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
+    t!(format!("{1} {0}", 0, 1), "1 0");
+    t!(format!("{foo} {bar}", foo=0, bar=1), "0 1");
+    t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
+    t!(format!("{} {0:s}", "a"), "a a");
+    t!(format!("{} {0}", "a"), "a a");
 
     // Methods should probably work
-    t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
-    t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1");
-    t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2");
-    t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3");
-    t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa");
-    t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb");
-    t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc");
-    t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd");
-    t!(ifmt!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab");
-    t!(ifmt!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb");
+    t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
+    t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1");
+    t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2");
+    t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3");
+    t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa");
+    t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb");
+    t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc");
+    t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd");
+    t!(format!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab");
+    t!(format!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb");
 
     // Formatting strings and their arguments
-    t!(ifmt!("{:s}", "a"), "a");
-    t!(ifmt!("{:4s}", "a"), "a   ");
-    t!(ifmt!("{:>4s}", "a"), "   a");
-    t!(ifmt!("{:<4s}", "a"), "a   ");
-    t!(ifmt!("{:.4s}", "a"), "a");
-    t!(ifmt!("{:4.4s}", "a"), "a   ");
-    t!(ifmt!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(ifmt!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(ifmt!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(ifmt!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(ifmt!("{:2.4s}", "aaaaa"), "aaaa");
-    t!(ifmt!("{:2.4s}", "aaaa"), "aaaa");
-    t!(ifmt!("{:2.4s}", "aaa"), "aaa");
-    t!(ifmt!("{:2.4s}", "aa"), "aa");
-    t!(ifmt!("{:2.4s}", "a"), "a ");
-    t!(ifmt!("{:0>2s}", "a"), "0a");
-    t!(ifmt!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(ifmt!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
-    t!(ifmt!("{:1$s}", "a", 4), "a   ");
-    t!(ifmt!("{:-#s}", "a"), "a");
-    t!(ifmt!("{:+#s}", "a"), "a");
+    t!(format!("{:s}", "a"), "a");
+    t!(format!("{:4s}", "a"), "a   ");
+    t!(format!("{:>4s}", "a"), "   a");
+    t!(format!("{:<4s}", "a"), "a   ");
+    t!(format!("{:.4s}", "a"), "a");
+    t!(format!("{:4.4s}", "a"), "a   ");
+    t!(format!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:2.4s}", "aaaaa"), "aaaa");
+    t!(format!("{:2.4s}", "aaaa"), "aaaa");
+    t!(format!("{:2.4s}", "aaa"), "aaa");
+    t!(format!("{:2.4s}", "aa"), "aa");
+    t!(format!("{:2.4s}", "a"), "a ");
+    t!(format!("{:0>2s}", "a"), "0a");
+    t!(format!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
+    t!(format!("{:1$s}", "a", 4), "a   ");
+    t!(format!("{:-#s}", "a"), "a");
+    t!(format!("{:+#s}", "a"), "a");
 
     // Formatting integers should select the right implementation based off the
     // type of the argument. Also, hex/octal/binary should be defined for
     // integers, but they shouldn't emit the negative sign.
-    t!(ifmt!("{:d}", -1i), "-1");
-    t!(ifmt!("{:d}", -1i8), "-1");
-    t!(ifmt!("{:d}", -1i16), "-1");
-    t!(ifmt!("{:d}", -1i32), "-1");
-    t!(ifmt!("{:d}", -1i64), "-1");
-    t!(ifmt!("{:t}", 1i), "1");
-    t!(ifmt!("{:t}", 1i8), "1");
-    t!(ifmt!("{:t}", 1i16), "1");
-    t!(ifmt!("{:t}", 1i32), "1");
-    t!(ifmt!("{:t}", 1i64), "1");
-    t!(ifmt!("{:x}", 1i), "1");
-    t!(ifmt!("{:x}", 1i8), "1");
-    t!(ifmt!("{:x}", 1i16), "1");
-    t!(ifmt!("{:x}", 1i32), "1");
-    t!(ifmt!("{:x}", 1i64), "1");
-    t!(ifmt!("{:X}", 1i), "1");
-    t!(ifmt!("{:X}", 1i8), "1");
-    t!(ifmt!("{:X}", 1i16), "1");
-    t!(ifmt!("{:X}", 1i32), "1");
-    t!(ifmt!("{:X}", 1i64), "1");
-    t!(ifmt!("{:o}", 1i), "1");
-    t!(ifmt!("{:o}", 1i8), "1");
-    t!(ifmt!("{:o}", 1i16), "1");
-    t!(ifmt!("{:o}", 1i32), "1");
-    t!(ifmt!("{:o}", 1i64), "1");
-
-    t!(ifmt!("{:u}", 1u), "1");
-    t!(ifmt!("{:u}", 1u8), "1");
-    t!(ifmt!("{:u}", 1u16), "1");
-    t!(ifmt!("{:u}", 1u32), "1");
-    t!(ifmt!("{:u}", 1u64), "1");
-    t!(ifmt!("{:t}", 1u), "1");
-    t!(ifmt!("{:t}", 1u8), "1");
-    t!(ifmt!("{:t}", 1u16), "1");
-    t!(ifmt!("{:t}", 1u32), "1");
-    t!(ifmt!("{:t}", 1u64), "1");
-    t!(ifmt!("{:x}", 1u), "1");
-    t!(ifmt!("{:x}", 1u8), "1");
-    t!(ifmt!("{:x}", 1u16), "1");
-    t!(ifmt!("{:x}", 1u32), "1");
-    t!(ifmt!("{:x}", 1u64), "1");
-    t!(ifmt!("{:X}", 1u), "1");
-    t!(ifmt!("{:X}", 1u8), "1");
-    t!(ifmt!("{:X}", 1u16), "1");
-    t!(ifmt!("{:X}", 1u32), "1");
-    t!(ifmt!("{:X}", 1u64), "1");
-    t!(ifmt!("{:o}", 1u), "1");
-    t!(ifmt!("{:o}", 1u8), "1");
-    t!(ifmt!("{:o}", 1u16), "1");
-    t!(ifmt!("{:o}", 1u32), "1");
-    t!(ifmt!("{:o}", 1u64), "1");
+    t!(format!("{:d}", -1i), "-1");
+    t!(format!("{:d}", -1i8), "-1");
+    t!(format!("{:d}", -1i16), "-1");
+    t!(format!("{:d}", -1i32), "-1");
+    t!(format!("{:d}", -1i64), "-1");
+    t!(format!("{:t}", 1i), "1");
+    t!(format!("{:t}", 1i8), "1");
+    t!(format!("{:t}", 1i16), "1");
+    t!(format!("{:t}", 1i32), "1");
+    t!(format!("{:t}", 1i64), "1");
+    t!(format!("{:x}", 1i), "1");
+    t!(format!("{:x}", 1i8), "1");
+    t!(format!("{:x}", 1i16), "1");
+    t!(format!("{:x}", 1i32), "1");
+    t!(format!("{:x}", 1i64), "1");
+    t!(format!("{:X}", 1i), "1");
+    t!(format!("{:X}", 1i8), "1");
+    t!(format!("{:X}", 1i16), "1");
+    t!(format!("{:X}", 1i32), "1");
+    t!(format!("{:X}", 1i64), "1");
+    t!(format!("{:o}", 1i), "1");
+    t!(format!("{:o}", 1i8), "1");
+    t!(format!("{:o}", 1i16), "1");
+    t!(format!("{:o}", 1i32), "1");
+    t!(format!("{:o}", 1i64), "1");
+
+    t!(format!("{:u}", 1u), "1");
+    t!(format!("{:u}", 1u8), "1");
+    t!(format!("{:u}", 1u16), "1");
+    t!(format!("{:u}", 1u32), "1");
+    t!(format!("{:u}", 1u64), "1");
+    t!(format!("{:t}", 1u), "1");
+    t!(format!("{:t}", 1u8), "1");
+    t!(format!("{:t}", 1u16), "1");
+    t!(format!("{:t}", 1u32), "1");
+    t!(format!("{:t}", 1u64), "1");
+    t!(format!("{:x}", 1u), "1");
+    t!(format!("{:x}", 1u8), "1");
+    t!(format!("{:x}", 1u16), "1");
+    t!(format!("{:x}", 1u32), "1");
+    t!(format!("{:x}", 1u64), "1");
+    t!(format!("{:X}", 1u), "1");
+    t!(format!("{:X}", 1u8), "1");
+    t!(format!("{:X}", 1u16), "1");
+    t!(format!("{:X}", 1u32), "1");
+    t!(format!("{:X}", 1u64), "1");
+    t!(format!("{:o}", 1u), "1");
+    t!(format!("{:o}", 1u8), "1");
+    t!(format!("{:o}", 1u16), "1");
+    t!(format!("{:o}", 1u32), "1");
+    t!(format!("{:o}", 1u64), "1");
 
     // Test the flags for formatting integers
-    t!(ifmt!("{:3d}", 1),  "  1");
-    t!(ifmt!("{:>3d}", 1),  "  1");
-    t!(ifmt!("{:>+3d}", 1), " +1");
-    t!(ifmt!("{:<3d}", 1), "1  ");
-    t!(ifmt!("{:#d}", 1), "1");
-    t!(ifmt!("{:#x}", 10), "0xa");
-    t!(ifmt!("{:#X}", 10), "0xA");
-    t!(ifmt!("{:#5x}", 10), "  0xa");
-    t!(ifmt!("{:#o}", 10), "0o12");
-    t!(ifmt!("{:08x}", 10),  "0000000a");
-    t!(ifmt!("{:8x}", 10),   "       a");
-    t!(ifmt!("{:<8x}", 10),  "a       ");
-    t!(ifmt!("{:>8x}", 10),  "       a");
-    t!(ifmt!("{:#08x}", 10), "0x00000a");
-    t!(ifmt!("{:08d}", -10), "-0000010");
-    t!(ifmt!("{:x}", -1u8), "ff");
-    t!(ifmt!("{:X}", -1u8), "FF");
-    t!(ifmt!("{:t}", -1u8), "11111111");
-    t!(ifmt!("{:o}", -1u8), "377");
-    t!(ifmt!("{:#x}", -1u8), "0xff");
-    t!(ifmt!("{:#X}", -1u8), "0xFF");
-    t!(ifmt!("{:#t}", -1u8), "0b11111111");
-    t!(ifmt!("{:#o}", -1u8), "0o377");
+    t!(format!("{:3d}", 1),  "  1");
+    t!(format!("{:>3d}", 1),  "  1");
+    t!(format!("{:>+3d}", 1), " +1");
+    t!(format!("{:<3d}", 1), "1  ");
+    t!(format!("{:#d}", 1), "1");
+    t!(format!("{:#x}", 10), "0xa");
+    t!(format!("{:#X}", 10), "0xA");
+    t!(format!("{:#5x}", 10), "  0xa");
+    t!(format!("{:#o}", 10), "0o12");
+    t!(format!("{:08x}", 10),  "0000000a");
+    t!(format!("{:8x}", 10),   "       a");
+    t!(format!("{:<8x}", 10),  "a       ");
+    t!(format!("{:>8x}", 10),  "       a");
+    t!(format!("{:#08x}", 10), "0x00000a");
+    t!(format!("{:08d}", -10), "-0000010");
+    t!(format!("{:x}", -1u8), "ff");
+    t!(format!("{:X}", -1u8), "FF");
+    t!(format!("{:t}", -1u8), "11111111");
+    t!(format!("{:o}", -1u8), "377");
+    t!(format!("{:#x}", -1u8), "0xff");
+    t!(format!("{:#X}", -1u8), "0xFF");
+    t!(format!("{:#t}", -1u8), "0b11111111");
+    t!(format!("{:#o}", -1u8), "0o377");
 
     // Signed combinations
-    t!(ifmt!("{:+5d}", 1),  "   +1");
-    t!(ifmt!("{:+5d}", -1), "   -1");
-    t!(ifmt!("{:05d}", 1),   "00001");
-    t!(ifmt!("{:05d}", -1),  "-0001");
-    t!(ifmt!("{:+05d}", 1),  "+0001");
-    t!(ifmt!("{:+05d}", -1), "-0001");
+    t!(format!("{:+5d}", 1),  "   +1");
+    t!(format!("{:+5d}", -1), "   -1");
+    t!(format!("{:05d}", 1),   "00001");
+    t!(format!("{:05d}", -1),  "-0001");
+    t!(format!("{:+05d}", 1),  "+0001");
+    t!(format!("{:+05d}", -1), "-0001");
 
     // Some float stuff
-    t!(ifmt!("{:f}", 1.0f), "1");
-    t!(ifmt!("{:f}", 1.0f32), "1");
-    t!(ifmt!("{:f}", 1.0f64), "1");
-    t!(ifmt!("{:.3f}", 1.0f), "1.000");
-    t!(ifmt!("{:10.3f}", 1.0f),   "     1.000");
-    t!(ifmt!("{:+10.3f}", 1.0f),  "    +1.000");
-    t!(ifmt!("{:+10.3f}", -1.0f), "    -1.000");
+    t!(format!("{:f}", 1.0f), "1");
+    t!(format!("{:f}", 1.0f32), "1");
+    t!(format!("{:f}", 1.0f64), "1");
+    t!(format!("{:.3f}", 1.0f), "1.000");
+    t!(format!("{:10.3f}", 1.0f),   "     1.000");
+    t!(format!("{:+10.3f}", 1.0f),  "    +1.000");
+    t!(format!("{:+10.3f}", -1.0f), "    -1.000");
+
+    test_write();
+    test_print();
+}
+
+// Basic test to make sure that we can invoke the `write!` macro with an
+// io::Writer instance.
+fn test_write() {
+    use std::rt::io::Decorator;
+    use std::rt::io::mem::MemWriter;
+    use std::rt::io;
+    use std::str;
+
+    let mut buf = MemWriter::new();
+    write!(&mut buf as &mut io::Writer, "{}", 3);
+    {
+        let w = &mut buf as &mut io::Writer;
+        write!(w, "{foo}", foo=4);
+        write!(w, "{:s}", "hello");
+        writeln!(w, "{}", "line");
+        writeln!(w, "{foo}", foo="bar");
+    }
+
+    let s = str::from_bytes_owned(buf.inner());
+    t!(s, "34helloline\nbar\n");
 }
 
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+fn test_print() {
+    print!("hi");
+    print!("{:?}", ~[0u8]);
+    println!("hello");
+    println!("this is a {}", "test");
+    println!("{foo}", foo="bar");
+}
index a4b37f0ba0f0b53e46d6efdd4c43eda039ae541d..ce471e5c827ecd6e1ac2f107fc86083c3d3307b5 100644 (file)
@@ -13,7 +13,7 @@
 use std::hashmap::HashMap;
 
 pub fn main() {
-    let mut buggy_map: HashMap<uint, &uint> = HashMap::new::<uint, &uint>();
+    let mut buggy_map: HashMap<uint, &uint> = HashMap::new();
     let x = ~1;
     buggy_map.insert(42, &*x);
 }
diff --git a/src/test/run-pass/issue-5783.rs b/src/test/run-pass/issue-5783.rs
new file mode 100644 (file)
index 0000000..7f988dc
--- /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.
+
+// Issue #5783
+// Nondeterministic behavior when referencing a closure more than once
+
+fn main() {
+    let a: &fn(int) -> @fn(int) -> int = |x:int| |y:int| -> int x + y;
+    let b = a(2);
+    assert!(a(2)(3) == 5);
+    assert!(b(6) == 8);
+}
index 2d612bb742eb383fd1342853d253acbe44159967..8e9502d6d49e616d82b99284721180853795d092 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-test
+
 // 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.
index 5318e5ca348d379c3be39fc4d8e2aca61a564c95..ec048d13a181aed1ff65e85c6d43e64def44bd46 100644 (file)
@@ -25,7 +25,7 @@ fn check_log<T>(exp: ~str, v: T) {
 
 pub fn main() {
     let x = list::from_vec([a(22u), b(~"hi")]);
-    let exp = ~"@Cons(a(22), @Cons(b(~\"hi\"), @Nil))";
+    let exp = ~"@Cons(a(22u), @Cons(b(~\"hi\"), @Nil))";
     let act = fmt!("%?", x);
     assert!(act == exp);
     check_log(exp, x);
index 7a0d763f7e0f463789f8651dbafc87f84c29287e..4727e61b1fd0ffaeeb8551a7d7df2506f27d7df7 100644 (file)
@@ -19,7 +19,7 @@ enum bar {
 }
 
 pub fn main() {
-    assert_eq!(~"a(22)", fmt!("%?", a(22u)));
+    assert_eq!(~"a(22u)", fmt!("%?", a(22u)));
     assert_eq!(~"b(~\"hi\")", fmt!("%?", b(~"hi")));
     assert_eq!(~"c", fmt!("%?", c));
     assert_eq!(~"d", fmt!("%?", d));
diff --git a/src/test/run-pass/mid-path-type-params.rs b/src/test/run-pass/mid-path-type-params.rs
new file mode 100644 (file)
index 0000000..1bc37a0
--- /dev/null
@@ -0,0 +1,33 @@
+struct S<T> {
+    contents: T,
+}
+
+impl<T> S<T> {
+    fn new<U>(x: T, _: U) -> S<T> {
+        S {
+            contents: x,
+        }
+    }
+}
+
+trait Trait<T> {
+    fn new<U>(x: T, y: U) -> Self;
+}
+
+struct S2 {
+    contents: int,
+}
+
+impl Trait<int> for S2 {
+    fn new<U>(x: int, _: U) -> S2 {
+        S2 {
+            contents: x,
+        }
+    }
+}
+
+fn main() {
+    let _ = S::<int>::new::<float>(1, 1.0);
+    let _: S2 = Trait::<int>::new::<float>(1, 1.0);
+}
+
index 23c271f53cac8866e2dede7ff7388345dd01f4f7..baef20944f7047a0fbc825b0bd3be85286f74f35 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-pretty
+
 // 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.
diff --git a/src/test/run-pass/option_addition.rs b/src/test/run-pass/option_addition.rs
deleted file mode 100644 (file)
index 8af1731..0000000
+++ /dev/null
@@ -1,25 +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.
-
-pub fn main() {
-    let foo: int = 1;
-    let bar: int = 2;
-    let foobar = foo + bar;
-
-    let nope = None::<int> + None::<int>;
-    let somefoo = Some(foo) + None::<int>;
-    let somebar = None::<int> + Some(bar);
-    let somefoobar = Some(foo) + Some(bar);
-
-    assert_eq!(nope, None::<int>);
-    assert_eq!(somefoo, None::<int>);
-    assert_eq!(somebar, None::<int>);
-    assert_eq!(foobar, somefoobar.unwrap());
-}
index f475292093cc294df2f6052803d84a0a1f142d56..11aa2b852045f1e1b2ded40472fa3bb3a2d5a649 100644 (file)
@@ -64,6 +64,6 @@ pub fn main() {
         // because `inner`s alignment was 4.
         assert_eq!(sys::size_of::<Outer>(), m::size());
 
-        assert_eq!(y, ~"{c8: 22, t: {c64: 44}}");
+        assert_eq!(y, ~"{c8: 22u8, t: {c64: 44u32}}");
     }
 }
index 571ad2f3fb2c4585e84cf075efc496bdf0f6f6d6..cca2adc0873dba54d6730216ccb130779a5b44e0 100644 (file)
@@ -86,6 +86,6 @@ pub fn main() {
         // because `Inner`s alignment was 4.
         assert_eq!(sys::size_of::<Outer>(), m::m::size());
 
-        assert_eq!(y, ~"{c8: 22, t: {c64: 44}}");
+        assert_eq!(y, ~"{c8: 22u8, t: {c64: 44u64}}");
     }
 }
index 72bdc2ee0a63e2873ee976b879b4d44d75fc6444..b56cef4277f5742faec632f7a3098b8e4a1e4d80 100644 (file)
@@ -436,16 +436,6 @@ fn visit_trait(&self) -> bool {
         true
     }
 
-    fn visit_var(&self) -> bool {
-        if ! self.inner.visit_var() { return false; }
-        true
-    }
-
-    fn visit_var_integral(&self) -> bool {
-        if ! self.inner.visit_var_integral() { return false; }
-        true
-    }
-
     fn visit_param(&self, i: uint) -> bool {
         if ! self.inner.visit_param(i) { return false; }
         true
@@ -470,11 +460,6 @@ fn visit_opaque_box(&self) -> bool {
         true
     }
 
-    fn visit_constr(&self, inner: *TyDesc) -> bool {
-        if ! self.inner.visit_constr(inner) { return false; }
-        true
-    }
-
     fn visit_closure_ptr(&self, ck: uint) -> bool {
         self.align_to::<@fn()>();
         if ! self.inner.visit_closure_ptr(ck) { return false; }
@@ -633,13 +618,10 @@ fn visit_leave_fn(&self, _purity: uint, _proto: uint,
 
 
     fn visit_trait(&self) -> bool { true }
-    fn visit_var(&self) -> bool { true }
-    fn visit_var_integral(&self) -> bool { true }
     fn visit_param(&self, _i: uint) -> bool { true }
     fn visit_self(&self) -> bool { true }
     fn visit_type(&self) -> bool { true }
     fn visit_opaque_box(&self) -> bool { true }
-    fn visit_constr(&self, _inner: *TyDesc) -> bool { true }
     fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
 }
 
index 544f42eb69f5eeffe5d0ba83add01ed21b7ae0dd..1462d8aace130cbe73a31ffe699a91306cabe679 100644 (file)
@@ -144,13 +144,10 @@ fn visit_leave_fn(&self, _purity: uint, _proto: uint,
 
 
     fn visit_trait(&self) -> bool { true }
-    fn visit_var(&self) -> bool { true }
-    fn visit_var_integral(&self) -> bool { true }
     fn visit_param(&self, _i: uint) -> bool { true }
     fn visit_self(&self) -> bool { true }
     fn visit_type(&self) -> bool { true }
     fn visit_opaque_box(&self) -> bool { true }
-    fn visit_constr(&self, _inner: *TyDesc) -> bool { true }
     fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
 }
 
index 429b49375e0daa0576e3f8c1405dff560eed200b..0d042d002a144211f0b0c1e1a89de87dab6192bd 100644 (file)
@@ -16,8 +16,8 @@
 
 #[nolink]
 extern {
-    static mut debug_static_mut: libc::c_int;
-    pub fn debug_static_mut_check_four();
+    static mut rust_dbg_static_mut: libc::c_int;
+    pub fn rust_dbg_static_mut_check_four();
 }
 
 unsafe fn static_bound(_: &'static libc::c_int) {}
@@ -28,18 +28,18 @@ fn static_bound_set(a: &'static mut libc::c_int) {
 
 #[fixed_stack_segment] #[inline(never)]
 unsafe fn run() {
-    assert!(debug_static_mut == 3);
-    debug_static_mut = 4;
-    assert!(debug_static_mut == 4);
-    debug_static_mut_check_four();
-    debug_static_mut += 1;
-    assert!(debug_static_mut == 5);
-    debug_static_mut *= 3;
-    assert!(debug_static_mut == 15);
-    debug_static_mut = -3;
-    assert!(debug_static_mut == -3);
-    static_bound(&debug_static_mut);
-    static_bound_set(&mut debug_static_mut);
+    assert!(rust_dbg_static_mut == 3);
+    rust_dbg_static_mut = 4;
+    assert!(rust_dbg_static_mut == 4);
+    rust_dbg_static_mut_check_four();
+    rust_dbg_static_mut += 1;
+    assert!(rust_dbg_static_mut == 5);
+    rust_dbg_static_mut *= 3;
+    assert!(rust_dbg_static_mut == 15);
+    rust_dbg_static_mut = -3;
+    assert!(rust_dbg_static_mut == -3);
+    static_bound(&rust_dbg_static_mut);
+    static_bound_set(&mut rust_dbg_static_mut);
 }
 
 pub fn main() {
index 1c39504ba717bc5cf5f7c9773983f049c753bcec..3f63902eb3193f298888d9510a58567720bc8f68 100644 (file)
@@ -16,8 +16,8 @@ mod rustrt {
 
     #[nolink]
     extern {
-        pub fn debug_abi_1(q: Quad) -> Quad;
-        pub fn debug_abi_2(f: Floats) -> Floats;
+        pub fn rust_dbg_abi_1(q: Quad) -> Quad;
+        pub fn rust_dbg_abi_2(f: Floats) -> Floats;
     }
 }
 
@@ -28,7 +28,7 @@ fn test1() {
                  b: 0xbbbb_bbbb_bbbb_bbbb_u64,
                  c: 0xcccc_cccc_cccc_cccc_u64,
                  d: 0xdddd_dddd_dddd_dddd_u64 };
-        let qq = rustrt::debug_abi_1(q);
+        let qq = rustrt::rust_dbg_abi_1(q);
         error!("a: %x", qq.a as uint);
         error!("b: %x", qq.b as uint);
         error!("c: %x", qq.c as uint);
@@ -48,7 +48,7 @@ fn test2() {
         let f = Floats { a: 1.234567890e-15_f64,
                  b: 0b_1010_1010_u8,
                  c: 1.0987654321e-15_f64 };
-        let ff = rustrt::debug_abi_2(f);
+        let ff = rustrt::rust_dbg_abi_2(f);
         error!("a: %f", ff.a as float);
         error!("b: %u", ff.b as uint);
         error!("c: %f", ff.c as float);
index f86c134eef247edac0a9e02e526f3d505e531f43..cb93cea28956b7e7121d46540215a2acc055f67a 100644 (file)
@@ -21,5 +21,5 @@ pub fn main() {
     let x = t_rec {c8: 22u8, t: a_tag(44u64)};
     let y = fmt!("%?", x);
     info!("y = %s", y);
-    assert_eq!(y, ~"{c8: 22, t: a_tag(44)}");
+    assert_eq!(y, ~"{c8: 22u8, t: a_tag(44u64)}");
 }
index 1360b76653c5d01794ab38773d901ecbdec5ed46..a4510ef70e1b257b1db70f9dbcddf21b79801084 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-pretty
+
 // 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.
index 0c334909b259cc778be16b44cfbfb4df18dd911a..baf4cf45b3ce8aa1f996ed7d1842990f9fbd215d 100644 (file)
@@ -59,7 +59,7 @@ fn main () {
 
     assert_eq!(0i.thing(3.14, 1), (3.14, 1));
     assert_eq!(B::staticthing(&0i, 3.14, 1), (3.14, 1));
-    assert_eq!(B::staticthing::<float, int, int>(&0i, 3.14, 1), (3.14, 1));
+    assert_eq!(B::<float>::staticthing::<int>(&0i, 3.14, 1), (3.14, 1));
 
     assert_eq!(g(0i, 3.14, 1), (3.14, 1));
     assert_eq!(g(false, 3.14, 1), (3.14, 1));
index e95b80447e4812614a4e010910420a753b566443..5ac26e65d888010bb94b9e5f9eb4e98b2ad283a4 100644 (file)
@@ -14,7 +14,7 @@ mod base {
     use std::io;
 
     pub trait HasNew<T> {
-        fn new() -> T;
+        fn new() -> Self;
     }
 
     pub struct Foo {
@@ -41,6 +41,6 @@ fn new() -> Bar {
 }
 
 pub fn main() {
-    let _f: base::Foo = base::HasNew::new::<base::Foo, base::Foo>();
-    let _b: base::Bar = base::HasNew::new::<base::Bar, base::Bar>();
+    let _f: base::Foo = base::HasNew::<base::Foo>::new();
+    let _b: base::Bar = base::HasNew::<base::Bar>::new();
 }