]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #9118 : alexcrichton/rust/llvm-fix, r=sanxiyn
authorbors <bors@rust-lang.org>
Mon, 16 Sep 2013 05:30:55 +0000 (22:30 -0700)
committerbors <bors@rust-lang.org>
Mon, 16 Sep 2013 05:30:55 +0000 (22:30 -0700)
I created a new branch  rust-llvm-2013-09-11 in my llvm repo to mark this momentous occasion

275 files changed:
doc/rust.md
doc/rustpkg.md
doc/tutorial-conditions.md
doc/tutorial.md
mk/rt.mk
src/compiletest/compiletest.rs
src/etc/emacs/README.md
src/libextra/comm.rs
src/libextra/crypto/md5.rs
src/libextra/crypto/sha2.rs
src/libextra/fileinput.rs
src/libextra/glob.rs
src/libextra/num/bigint.rs
src/libextra/num/rational.rs
src/libextra/rl.rs
src/libextra/semver.rs
src/libextra/tempfile.rs
src/libextra/test.rs
src/libextra/time.rs
src/libextra/uuid.rs
src/libextra/workcache.rs
src/librust/rust.rs
src/librustc/driver/driver.rs
src/librustc/front/config.rs
src/librustc/lib/llvm.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/metadata/filesearch.rs
src/librustc/middle/astencode.rs
src/librustc/middle/check_const.rs
src/librustc/middle/check_match.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/effect.rs
src/librustc/middle/kind.rs
src/librustc/middle/lint.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/privacy.rs
src/librustc/middle/resolve.rs
src/librustc/middle/stack_check.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/build.rs
src/librustc/middle/trans/builder.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/common.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/debuginfo.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/foreign.rs
src/librustc/middle/trans/glue.rs
src/librustc/middle/trans/intrinsic.rs
src/librustc/middle/trans/value.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/infer/combine.rs
src/librustc/middle/typeck/infer/glb.rs
src/librustc/middle/typeck/infer/lattice.rs
src/librustc/middle/typeck/infer/lub.rs
src/librustc/middle/typeck/infer/mod.rs
src/librustc/middle/typeck/infer/sub.rs
src/librustc/middle/typeck/rscope.rs
src/librustc/util/ppaux.rs
src/librustdoc/attr_pass.rs
src/librustdoc/config.rs
src/librusti/rusti.rs
src/librustpkg/api.rs
src/librustpkg/context.rs
src/librustpkg/package_id.rs
src/librustpkg/package_source.rs
src/librustpkg/path_util.rs
src/librustpkg/rustpkg.rs
src/librustpkg/search.rs
src/librustpkg/tests.rs
src/librustpkg/usage.rs
src/librustpkg/util.rs
src/librustpkg/version.rs
src/librustpkg/workspace.rs
src/libstd/at_vec.rs
src/libstd/bool.rs
src/libstd/char.rs
src/libstd/comm.rs
src/libstd/default.rs
src/libstd/either.rs
src/libstd/fmt/mod.rs
src/libstd/fmt/parse.rs
src/libstd/hashmap.rs
src/libstd/io.rs
src/libstd/iter.rs
src/libstd/local_data.rs
src/libstd/logging.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/num/float.rs
src/libstd/num/int_macros.rs
src/libstd/num/num.rs
src/libstd/num/uint_macros.rs
src/libstd/option.rs
src/libstd/os.rs
src/libstd/ptr.rs
src/libstd/rand.rs
src/libstd/result.rs
src/libstd/rt/crate_map.rs [new file with mode: 0644]
src/libstd/rt/io/buffered.rs
src/libstd/rt/io/file.rs
src/libstd/rt/io/mem.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/option.rs
src/libstd/rt/io/timer.rs
src/libstd/rt/logging.rs
src/libstd/rt/mod.rs
src/libstd/rt/test.rs
src/libstd/rt/uv/uvio.rs
src/libstd/rt/uv/uvll.rs
src/libstd/sys.rs
src/libstd/to_bytes.rs
src/libstd/trie.rs
src/libstd/tuple.rs
src/libstd/unit.rs
src/libstd/unstable/dynamic_lib.rs
src/libstd/unstable/mod.rs
src/libstd/vec.rs
src/libsyntax/ast.rs
src/libsyntax/ast_map.rs
src/libsyntax/ast_util.rs
src/libsyntax/attr.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/deriving/default.rs [new file with mode: 0644]
src/libsyntax/ext/deriving/mod.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/format.rs [new file with mode: 0644]
src/libsyntax/ext/ifmt.rs [deleted file]
src/libsyntax/fold.rs
src/libsyntax/oldvisit.rs [deleted file]
src/libsyntax/opt_vec.rs
src/libsyntax/parse/lexer.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/syntax.rs
src/rt/rust_builtin.cpp
src/rt/rust_crate_map.cpp [deleted file]
src/rt/rust_crate_map.h [deleted file]
src/rt/rustrt.def.in
src/rustllvm/RustWrapper.cpp
src/rustllvm/rustllvm.def.in
src/test/auxiliary/issue_9123.rs [new file with mode: 0644]
src/test/auxiliary/static-methods-crate.rs
src/test/auxiliary/struct_variant_xc_aux.rs [new file with mode: 0644]
src/test/bench/core-map.rs
src/test/bench/core-set.rs
src/test/bench/core-uint-to-str.rs
src/test/bench/graph500-bfs.rs
src/test/bench/msgsend-pipes-shared.rs
src/test/bench/msgsend-pipes.rs
src/test/bench/msgsend-ring-mutex-arcs.rs
src/test/bench/msgsend-ring-rw-arcs.rs
src/test/bench/rt-messaging-ping-pong.rs
src/test/bench/rt-parfib.rs
src/test/bench/rt-spawn-rate.rs
src/test/bench/shootout-ackermann.rs
src/test/bench/shootout-binarytrees.rs
src/test/bench/shootout-chameneos-redux.rs
src/test/bench/shootout-fasta.rs
src/test/bench/shootout-fibo.rs
src/test/bench/std-smallintmap.rs
src/test/bench/sudoku.rs
src/test/bench/task-perf-jargon-metal-smoke.rs
src/test/bench/task-perf-linked-failure.rs
src/test/bench/task-perf-one-million.rs
src/test/bench/task-perf-spawnalot.rs
src/test/compile-fail/debug-correct-span.rs [new file with mode: 0644]
src/test/compile-fail/ifmt-bad-arg.rs
src/test/compile-fail/ifmt-bad-format-args.rs [new file with mode: 0644]
src/test/compile-fail/ifmt-bad-format-args2.rs [new file with mode: 0644]
src/test/compile-fail/lint-cstack.rs [new file with mode: 0644]
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/by-value-non-immediate-argument.rs
src/test/debug-info/by-value-self-argument-in-trait-impl.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-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/recursive-struct.rs [new file with mode: 0644]
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/trait-pointers.rs [new file with mode: 0644]
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/var-captured-in-managed-closure.rs
src/test/debug-info/var-captured-in-nested-closure.rs
src/test/debug-info/var-captured-in-sendable-closure.rs
src/test/debug-info/var-captured-in-stack-closure.rs
src/test/debug-info/vec-slices.rs
src/test/debug-info/vec.rs
src/test/pretty/empty-impl.pp [new file with mode: 0644]
src/test/pretty/empty-impl.rs [new file with mode: 0644]
src/test/run-fail/binop-fail-3.rs [new file with mode: 0644]
src/test/run-pass/deriving-zero.rs
src/test/run-pass/glob-std.rs [new file with mode: 0644]
src/test/run-pass/ifmt.rs
src/test/run-pass/issue-4241.rs
src/test/run-pass/issue-9110.rs [new file with mode: 0644]
src/test/run-pass/issue-9123.rs [new file with mode: 0644]
src/test/run-pass/lint-cstack.rs [new file with mode: 0644]
src/test/run-pass/match-with-ret-arm.rs
src/test/run-pass/num-range-rev.rs [deleted file]
src/test/run-pass/num-range.rs [deleted file]
src/test/run-pass/rl-human-test.rs [new file with mode: 0644]
src/test/run-pass/struct_variant_xc.rs [new file with mode: 0644]
src/test/run-pass/tempfile.rs [new file with mode: 0644]

index 3c6157e44ba6f111b2b56978c0b05deddbd4d7d3..8e1028b472737d6399eb2e379b2a06c2708478a8 100644 (file)
@@ -1717,7 +1717,8 @@ Supported traits for `deriving` are:
 * `Clone` and `DeepClone`, to perform (deep) copies.
 * `IterBytes`, to iterate over the bytes in a data type.
 * `Rand`, to create a random instance of a data type.
-* `Zero`, to create an zero (or empty) instance of a data type.
+* `Default`, to create an empty instance of a data type.
+* `Zero`, to create an zero instance of a numeric data type.
 * `ToStr`, to convert to a string. For a type with this instance,
   `obj.to_str()` has similar output as `fmt!("%?", obj)`, but it differs in that
   each constituent field of the type must also implement `ToStr` and will have
@@ -2459,25 +2460,12 @@ do k(3) |j| {
 ### For expressions
 
 ~~~~~~~~{.ebnf .gram}
-for_expr : "for" expr [ '|' ident_list '|' ] ? '{' block '}' ;
+for_expr : "for" pat "in" expr '{' block '}' ;
 ~~~~~~~~
 
-A _for expression_ is similar to a [`do` expression](#do-expressions),
-in that it provides a special block-form of lambda expression,
-suited to passing the `block` function to a higher-order function implementing a loop.
-
-In contrast to a `do` expression, a `for` expression is designed to work
-with methods such as `each` and `times`, that require the body block to
-return a boolean. The `for` expression accommodates this by implicitly
-returning `true` at the end of each block, unless a `break` expression
-is evaluated.
-
-In addition, [`break`](#break-expressions) and [`loop`](#loop-expressions) expressions
-are rewritten inside `for` expressions in the same way that `return` expressions are,
-with a combination of local flag variables,
-and early boolean-valued returns from the `block` function,
-such that the meaning of `break` and `loop` is preserved in a primitive loop
-when rewritten as a `for` loop controlled by a higher order function.
+A `for` expression is a syntactic construct for looping
+over elements provided by an implementation of
+`std::iterator::Iterator`.
 
 An example of a for loop over the contents of a vector:
 
index 1e6e4e29cb951ef2461c56047178e3b9010253d5..399a76426654ac76dd2e82aca1cf590b6e1b2069 100644 (file)
@@ -52,13 +52,11 @@ A valid workspace must contain each of the following subdirectories:
      rustpkg will install libraries for bar to `foo/lib/x86_64-apple-darwin/`.
      The libraries will have names of the form `foo/lib/x86_64-apple-darwin/libbar-[hash].dylib`,
      where [hash] is a hash of the package ID.
-* 'bin/': `rustpkg install` installs executable binaries into a target-specific subdirectory of this directory.
+* 'bin/': `rustpkg install` installs executable binaries into this directory.
 
-     For example, on a 64-bit machine running Mac OS X,
-     if `foo` is a workspace, containing the package `bar`,
-     rustpkg will install executables for `bar` to
-     `foo/bin/x86_64-apple-darwin/`.
-     The executables will have names of the form `foo/bin/x86_64-apple-darwin/bar`.
+     For example, rustpkg will install executables for `bar` to
+     `foo/bin`.
+     The executables will have names of the form `foo/bin/bar`.
 * 'build/': `rustpkg build` stores temporary build artifacts in a target-specific subdirectory of this directory.
 
      For example, on a 64-bit machine running Mac OS X,
@@ -85,6 +83,12 @@ rustpkg also interprets any dependencies on such a package ID literally
 Thus, `github.com/mozilla/rust#5c4cd30f80` is also a valid package ID,
 since git can deduce that 5c4cd30f80 refers to a revision of the desired repository.
 
+A package identifier can name a subdirectory of another package.
+For example, if `foo` is a workspace, and `foo/src/bar/lib.rs` exists,
+as well as `foo/src/bar/extras/baz/lib.rs`,
+then both `bar` and `bar/extras/baz` are valid package identifiers
+in the workspace `foo`.
+
 ## Source files
 
 rustpkg searches for four different fixed filenames in order to determine the crates to build:
@@ -140,9 +144,11 @@ but not in their `lib` or `bin` directories.
 
 ## install
 
-`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`,
-and then installs them either into `foo`'s `lib` and `bin` directories,
-or into the `lib` and `bin` subdirectories of the first entry in `RUST_PATH`.
+`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`.
+If `RUST_PATH` is declared as an environment variable, then rustpkg installs the
+libraries and executables into the `lib` and `bin` subdirectories
+of the first entry in `RUST_PATH`.
+Otherwise, it installs them into `foo`'s `lib` and `bin` directories.
 
 ## test
 
index bcee4377f1433c563516b14ab088c3b78d7b26e8..bdf3c6089f8855655fabccf734bbef98f347350e 100644 (file)
@@ -91,7 +91,7 @@ fn read_int_pairs() -> ~[(int,int)] {
             [a, b] => {
 
                 // 5. Try parsing both fields as ints.
-                match (int::from_str(a), int::from_str(b)) {
+                match (from_str::<int>(a), from_str::<int>(b)) {
 
                     // 6. If parsing succeeded for both, push both.
                     (Some(a), Some(b)) => pairs.push((a,b)),
@@ -124,7 +124,7 @@ for conveying a value of type `T`, represented as `Some(T)`
 _or_ the sentinel `None`, to indicate the absence of a `T` value.
 For simple APIs, it may be sufficient to encode errors as `Option<T>`,
 returning `Some(T)` on success and `None` on error.
-In the example program, the call to `int::from_str` returns `Option<int>`
+In the example program, the call to `from_str::<int>` returns `Option<int>`
 with the understanding that "all parse errors" result in `None`.
 The resulting `Option<int>` values are matched against the pattern `(Some(a), Some(b))`
 in steps 5 and 6 in the example program,
@@ -161,7 +161,7 @@ This second mechanism for indicating an error is called a `Result`.
 The type `std::result::Result<T,E>` is another simple `enum` type with two forms, `Ok(T)` and `Err(E)`.
 The `Result` type is not substantially different from the `Option` type in terms of its ergonomics.
 Its main advantage is that the error constructor `Err(E)` can convey _more detail_ about the error.
-For example, the `int::from_str` API could be reformed
+For example, the `from_str` API could be reformed
 to return a `Result` carrying an informative description of a parse error,
 like this:
 
@@ -172,7 +172,7 @@ enum IntParseErr {
      BadChar(char)
 }
 
-fn int::from_str(&str) -> Result<int,IntParseErr> {
+fn from_str(&str) -> Result<int,IntParseErr> {
   // ...
 }
 ~~~~
@@ -297,8 +297,8 @@ fn read_int_pairs() -> ~[(int,int)] {
         let line = fi.read_line();
         let fields = line.word_iter().to_owned_vec();
         match fields {
-            [a, b] => pairs.push((int::from_str(a).unwrap(),
-                                  int::from_str(b).unwrap())),
+            [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+                                  from_str::<int>(b).unwrap())),
 
             // Explicitly fail on malformed lines.
             _ => fail!()
@@ -398,8 +398,8 @@ fn read_int_pairs() -> ~[(int,int)] {
         let line = fi.read_line();
         let fields = line.word_iter().to_owned_vec();
         match fields {
-            [a, b] => pairs.push((int::from_str(a).unwrap(),
-                                  int::from_str(b).unwrap())),
+            [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+                                  from_str::<int>(b).unwrap())),
 
             // On malformed lines, call the condition handler and
             // push whatever the condition handler returns.
@@ -475,8 +475,8 @@ fn read_int_pairs() -> ~[(int,int)] {
         let line = fi.read_line();
         let fields = line.word_iter().to_owned_vec();
         match fields {
-            [a, b] => pairs.push((int::from_str(a).unwrap(),
-                                  int::from_str(b).unwrap())),
+            [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+                                  from_str::<int>(b).unwrap())),
             _ => pairs.push(malformed_line::cond.raise(line.clone()))
         }
     }
@@ -553,8 +553,8 @@ fn read_int_pairs() -> ~[(int,int)] {
         let line = fi.read_line();
         let fields = line.word_iter().to_owned_vec();
         match fields {
-            [a, b] => pairs.push((int::from_str(a).unwrap(),
-                                  int::from_str(b).unwrap())),
+            [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+                                  from_str::<int>(b).unwrap())),
 
             // On malformed lines, call the condition handler and
             // either ignore the line (if the handler returns `None`)
@@ -649,8 +649,8 @@ fn read_int_pairs() -> ~[(int,int)] {
         let line = fi.read_line();
         let fields = line.word_iter().to_owned_vec();
         match fields {
-            [a, b] => pairs.push((int::from_str(a).unwrap(),
-                                  int::from_str(b).unwrap())),
+            [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+                                  from_str::<int>(b).unwrap())),
 
             // On malformed lines, call the condition handler and
             // take action appropriate to the enum value returned.
@@ -776,7 +776,7 @@ fn main() {
 // Parse an int; if parsing fails, call the condition handler and
 // return whatever it returns.
 fn parse_int(x: &str) -> int {
-    match int::from_str(x) {
+    match from_str::<int>(x) {
         Some(v) => v,
         None => malformed_int::cond.raise(x.to_owned())
     }
@@ -833,8 +833,8 @@ There are three other things to note in this variant of the example program:
     so long as the `raise` occurs within a callee (of any depth) of the logic protected by the `trap` call,
     it will invoke the handler.
 
-  - This variant insulates callers from a design choice in the `int` library:
-    the `int::from_str` function was designed to return an `Option<int>`,
+  - This variant insulates callers from a design choice in the library:
+    the `from_str` function was designed to return an `Option<int>`,
     but this program insulates callers from that choice,
     routing all `None` values that arise from parsing integers in this file into the condition.
 
@@ -873,4 +873,4 @@ To compensate for this risk, correct C++ and Java code must program in an extrem
 or else risk introducing silent and very difficult-to-debug errors due to control resuming in a corrupted heap after a caught exception.
 These errors are frequently memory-safety errors, which Rust strives to eliminate,
 and so Rust unwinding is unrecoverable within a single task:
-once unwinding starts, the entire local heap of a task is destroyed and the task is terminated.
\ No newline at end of file
+once unwinding starts, the entire local heap of a task is destroyed and the task is terminated.
index 7614e8482377c458cde8fe2c38dd9bb059a5a387..637dbb10c23559616db7121f659a5cd804356e0d 100644 (file)
@@ -2249,7 +2249,7 @@ enum ABC { A, B, C }
 
 The full list of derivable traits is `Eq`, `TotalEq`, `Ord`,
 `TotalOrd`, `Encodable` `Decodable`, `Clone`, `DeepClone`,
-`IterBytes`, `Rand`, `Zero`, and `ToStr`.
+`IterBytes`, `Rand`, `Default`, `Zero`, and `ToStr`.
 
 # Crates and the module system
 
index 4dff262330ae63a8780c559a88fc2edffcf6fe66..e31f2228e3f774b45f40033c55dfe3f795103bc0 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -75,7 +75,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
               rt/rust_rng.cpp \
               rt/rust_upcall.cpp \
               rt/rust_uv.cpp \
-              rt/rust_crate_map.cpp \
               rt/isaac/randport.cpp \
               rt/miniz.cpp \
               rt/memory_region.cpp \
index df0462203a9eba30db3d3c11760f73fa3cfc716e..166638bc359bf98e4c560ad6d82187492b5cf4e3 100644 (file)
@@ -309,7 +309,7 @@ fn shorten(path: &Path) -> ~str {
         let filename = path.filename();
         let p = path.pop();
         let dir = p.filename();
-        fmt!("%s/%s", dir.unwrap_or_default(""), filename.unwrap_or_default(""))
+        fmt!("%s/%s", dir.unwrap_or(""), filename.unwrap_or(""))
     }
 
     test::DynTestName(fmt!("[%s] %s",
index 63fbe1f681cb2deec059b41da34725823c533604..edcb61a913e47b5c442c03eb3a2e53007680dab3 100644 (file)
@@ -1,27 +1,29 @@
-rust-mode: A major emacs mode for editing Rust source code
-==========================================================
+`rust-mode`: A major Emacs mode for editing Rust source code
+============================================================
 
-`rust-mode` makes editing [Rust](http://rust-lang.org) code with emacs
+`rust-mode` makes editing [Rust](http://rust-lang.org) code with Emacs
 enjoyable.
 
 
 ### Manual Installation
 
-To install manually, check out this repository and add this to your .emacs
-file:
+To install manually, check out this repository and add this to your
+`.emacs` file:
 
-    (add-to-list 'load-path "/path/to/rust-mode/")
-    (require 'rust-mode)
+```lisp
+(add-to-list 'load-path "/path/to/rust-mode/")
+(require 'rust-mode)
+```
 
-Rust mode will automatically be associated with .rs files. To enable it
-explicitly, do `M-x rust-mode`.
+`rust-mode` will automatically be associated with `.rs` files. To enable it
+explicitly, do <kbd>M-x rust-mode</kbd>.
 
-### package.el installation via Marmalade or MELPA
+### `package.el` installation via Marmalade or MELPA
 
 It can be more convenient to use Emacs's package manager to handle
 installation for you if you use many elisp libraries. If you have
-package.el but haven't added Marmalade or MELPA, the community package source,
-yet, add this to ~/.emacs.d/init.el:
+`package.el` but haven't added Marmalade or MELPA, the community
+package source, yet, add this to `~/.emacs.d/init.el`:
 
 Using Marmalade:
 
@@ -47,32 +49,33 @@ Then do this to load the package listing:
 * <kbd>M-x package-refresh-contents</kbd>
 
 If you use a version of Emacs prior to 24 that doesn't include
-package.el, you can get it from http://bit.ly/pkg-el23.
+`package.el`, you can get it from [here](http://bit.ly/pkg-el23).
 
-If you have an older ELPA package.el installed from tromey.com, you
+If you have an older ELPA `package.el` installed from tromey.com, you
 should upgrade in order to support installation from multiple sources.
 The ELPA archive is deprecated and no longer accepting new packages,
 so the version there (1.7.1) is very outdated.
 
-#### Install rust-mode
+#### Install `rust-mode`
 
-From there you can install rust-mode or any other modes by choosing
-them from a list:
+One you have `package.el`, you can install `rust-mode` or any other
+modes by choosing them from a list:
 
 * <kbd>M-x package-list-packages</kbd>
 
-Now, to install packages, move your cursor to them and press i. This
-will mark the packages for installation. When you're done with
-marking, press x, and ELPA will install the packages for you (under
-~/.emacs.d/elpa/).
+Now, to install packages, move your cursor to them and press
+<kbd>i</kbd>. This will mark the packages for installation. When
+you're done with marking, press <kbd>x</kbd>, and ELPA will install
+the packages for you (under `~/.emacs.d/elpa/`).
 
-* or using <kbd>M-x package-install rust-mode
+* or using <kbd>M-x package-install rust-mode</kbd>
 
 ### Tests via ERT
 
-The file `rust-mode-tests.el` contains tests that can be run via ERT.  You can
-use `run_rust_emacs_tests.sh` to run them in batch mode, if emacs is somewhere
-in your `$PATH`.
+The file `rust-mode-tests.el` contains tests that can be run via
+[ERT](http://www.gnu.org/software/emacs/manual/html_node/ert/index.html).
+You can use `run_rust_emacs_tests.sh` to run them in batch mode, if
+Emacs is somewhere in your `$PATH`.
 
 ### Known bugs
 
index 776e25cac8908447988c204aca86bea7c717db87..dc6f4964b317794d4cba77022ec2ee24043af92e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -90,9 +90,55 @@ pub fn DuplexStream<T:Send,U:Send>()
      })
 }
 
+/// An extension of `pipes::stream` that provides synchronous message sending.
+pub struct SyncChan<T> { priv duplex_stream: DuplexStream<T, ()> }
+/// An extension of `pipes::stream` that acknowledges each message received.
+pub struct SyncPort<T> { priv duplex_stream: DuplexStream<(), T> }
+
+impl<T: Send> GenericChan<T> for SyncChan<T> {
+    fn send(&self, val: T) {
+        assert!(self.try_send(val), "SyncChan.send: receiving port closed");
+    }
+}
+
+impl<T: Send> GenericSmartChan<T> for SyncChan<T> {
+    /// Sends a message, or report if the receiver has closed the connection before receiving.
+    fn try_send(&self, val: T) -> bool {
+        self.duplex_stream.try_send(val) && self.duplex_stream.try_recv().is_some()
+    }
+}
+
+impl<T: Send> GenericPort<T> for SyncPort<T> {
+    fn recv(&self) -> T {
+        self.try_recv().expect("SyncPort.recv: sending channel closed")
+    }
+
+    fn try_recv(&self) -> Option<T> {
+        do self.duplex_stream.try_recv().map_move |val| {
+            self.duplex_stream.try_send(());
+            val
+        }
+    }
+}
+
+impl<T: Send> Peekable<T> for SyncPort<T> {
+    fn peek(&self) -> bool {
+        self.duplex_stream.peek()
+    }
+}
+
+/// Creates a stream whose channel, upon sending a message, blocks until the message is received.
+pub fn rendezvous<T: Send>() -> (SyncPort<T>, SyncChan<T>) {
+    let (chan_stream, port_stream) = DuplexStream();
+    (SyncPort { duplex_stream: port_stream }, SyncChan { duplex_stream: chan_stream })
+}
+
 #[cfg(test)]
 mod test {
-    use comm::DuplexStream;
+    use comm::{DuplexStream, rendezvous};
+    use std::rt::test::run_in_newsched_task;
+    use std::task::spawn_unlinked;
+
 
     #[test]
     pub fn DuplexStream1() {
@@ -104,4 +150,58 @@ pub fn DuplexStream1() {
         assert!(left.recv() == 123);
         assert!(right.recv() == ~"abc");
     }
+
+    #[test]
+    pub fn basic_rendezvous_test() {
+        let (port, chan) = rendezvous();
+
+        do spawn {
+            chan.send("abc");
+        }
+
+        assert!(port.recv() == "abc");
+    }
+
+    #[test]
+    fn recv_a_lot() {
+        // Rendezvous streams should be able to handle any number of messages being sent
+        do run_in_newsched_task {
+            let (port, chan) = rendezvous();
+            do spawn {
+                do 1000000.times { chan.send(()) }
+            }
+            do 1000000.times { port.recv() }
+        }
+    }
+
+    #[test]
+    fn send_and_fail_and_try_recv() {
+        let (port, chan) = rendezvous();
+        do spawn_unlinked {
+            chan.duplex_stream.send(()); // Can't access this field outside this module
+            fail!()
+        }
+        port.recv()
+    }
+
+    #[test]
+    fn try_send_and_recv_then_fail_before_ack() {
+        let (port, chan) = rendezvous();
+        do spawn_unlinked {
+            port.duplex_stream.recv();
+            fail!()
+        }
+        chan.try_send(());
+    }
+
+    #[test]
+    #[should_fail]
+    fn send_and_recv_then_fail_before_ack() {
+        let (port, chan) = rendezvous();
+        do spawn_unlinked {
+            port.duplex_stream.recv();
+            fail!()
+        }
+        chan.send(());
+    }
 }
index 8e8b752da80754fa47d50d9cf5fe9961deeabc68..8e07c7ee1c7cac43a4903a382022ce6d867e4350 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::uint;
+use std::iter::range_step;
 
 use cryptoutil::{write_u32_le, read_u32v_le, FixedBuffer, FixedBuffer64, StandardPadding};
 use digest::Digest;
@@ -86,46 +86,42 @@ fn op_i(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
         read_u32v_le(data, input);
 
         // round 1
-        do uint::range_step(0, 16, 4) |i| {
+        for i in range_step(0u, 16, 4) {
             a = op_f(a, b, c, d, data[i] + C1[i], 7);
             d = op_f(d, a, b, c, data[i + 1] + C1[i + 1], 12);
             c = op_f(c, d, a, b, data[i + 2] + C1[i + 2], 17);
             b = op_f(b, c, d, a, data[i + 3] + C1[i + 3], 22);
-            true
-        };
+        }
 
         // round 2
         let mut t = 1;
-        do uint::range_step(0, 16, 4) |i| {
+        for i in range_step(0u, 16, 4) {
             a = op_g(a, b, c, d, data[t & 0x0f] + C2[i], 5);
             d = op_g(d, a, b, c, data[(t + 5) & 0x0f] + C2[i + 1], 9);
             c = op_g(c, d, a, b, data[(t + 10) & 0x0f] + C2[i + 2], 14);
             b = op_g(b, c, d, a, data[(t + 15) & 0x0f] + C2[i + 3], 20);
             t += 20;
-            true
-        };
+        }
 
         // round 3
         t = 5;
-        do uint::range_step(0, 16, 4) |i| {
+        for i in range_step(0u, 16, 4) {
             a = op_h(a, b, c, d, data[t & 0x0f] + C3[i], 4);
             d = op_h(d, a, b, c, data[(t + 3) & 0x0f] + C3[i + 1], 11);
             c = op_h(c, d, a, b, data[(t + 6) & 0x0f] + C3[i + 2], 16);
             b = op_h(b, c, d, a, data[(t + 9) & 0x0f] + C3[i + 3], 23);
             t += 12;
-            true
-        };
+        }
 
         // round 4
         t = 0;
-        do uint::range_step(0, 16, 4) |i| {
+        for i in range_step(0u, 16, 4) {
             a = op_i(a, b, c, d, data[t & 0x0f] + C4[i], 6);
             d = op_i(d, a, b, c, data[(t + 7) & 0x0f] + C4[i + 1], 10);
             c = op_i(c, d, a, b, data[(t + 14) & 0x0f] + C4[i + 2], 15);
             b = op_i(b, c, d, a, data[(t + 21) & 0x0f] + C4[i + 3], 21);
             t += 28;
-            true
-        };
+        }
 
         self.s0 += a;
         self.s1 += b;
index 49bbddca1dbb773d648807b5f2a9b846d9be7449..10289fb8b976465ebde8557f07746ddd25ff7994 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::uint;
+use std::iter::range_step;
 
 use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, add_bytes_to_bits,
     add_bytes_to_bits_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
@@ -111,7 +111,7 @@ macro_rules! sha2_round(
 
         // Putting the message schedule inside the same loop as the round calculations allows for
         // the compiler to generate better code.
-        do uint::range_step(0, 64, 8) |t| {
+        for t in range_step(0u, 64, 8) {
             schedule_round!(t + 16);
             schedule_round!(t + 17);
             schedule_round!(t + 18);
@@ -129,10 +129,9 @@ macro_rules! sha2_round(
             sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
             sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
             sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
-            true
-        };
+        }
 
-        do uint::range_step(64, 80, 8) |t| {
+        for t in range_step(64u, 80, 8) {
             sha2_round!(a, b, c, d, e, f, g, h, K64, t);
             sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1);
             sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2);
@@ -141,8 +140,7 @@ macro_rules! sha2_round(
             sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
             sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
             sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
-            true
-        };
+        }
 
         self.H0 += a;
         self.H1 += b;
@@ -527,7 +525,7 @@ macro_rules! sha2_round(
 
         // Putting the message schedule inside the same loop as the round calculations allows for
         // the compiler to generate better code.
-        do uint::range_step(0, 48, 8) |t| {
+        for t in range_step(0u, 48, 8) {
             schedule_round!(t + 16);
             schedule_round!(t + 17);
             schedule_round!(t + 18);
@@ -545,10 +543,9 @@ macro_rules! sha2_round(
             sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
             sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
             sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
-            true
-        };
+        }
 
-        do uint::range_step(48, 64, 8) |t| {
+        for t in range_step(48u, 64, 8) {
             sha2_round!(a, b, c, d, e, f, g, h, K32, t);
             sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
             sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
@@ -557,8 +554,7 @@ macro_rules! sha2_round(
             sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
             sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
             sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
-            true
-        };
+        }
 
         self.H0 += a;
         self.H1 += b;
index 009198b9b6e8adc4c254ebd5711b7ea263c9676c..020da792ed7f3c9c29b495eb4e050c449b10d4e4 100644 (file)
@@ -417,20 +417,23 @@ mod test {
 
     use super::{FileInput, make_path_option_vec, input_vec, input_vec_state};
 
-    use std::io;
+    use std::rt::io;
+    use std::rt::io::Writer;
+    use std::rt::io::file;
     use std::uint;
     use std::vec;
 
     fn make_file(path : &Path, contents: &[~str]) {
-        let file = io::file_writer(path, [io::Create, io::Truncate]).unwrap();
+        let mut file = file::open(path, io::CreateOrTruncate, io::Write).unwrap();
 
         for str in contents.iter() {
-            file.write_str(*str);
-            file.write_char('\n');
+            file.write(str.as_bytes());
+            file.write(['\n' as u8]);
         }
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_make_path_option_vec() {
         let strs = [~"some/path",
                     ~"some/other/path"];
@@ -445,6 +448,7 @@ fn test_make_path_option_vec() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_fileinput_read_byte() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -475,6 +479,7 @@ fn test_fileinput_read_byte() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_fileinput_read() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -495,6 +500,7 @@ fn test_fileinput_read() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_input_vec() {
         let mut all_lines = ~[];
         let filenames = make_path_option_vec(vec::from_fn(
@@ -518,6 +524,7 @@ fn test_input_vec() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_input_vec_state() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -531,8 +538,8 @@ fn test_input_vec_state() {
 
         do input_vec_state(filenames) |line, state| {
             let nums: ~[&str] = line.split_iter(' ').collect();
-            let file_num = uint::from_str(nums[0]).unwrap();
-            let line_num = uint::from_str(nums[1]).unwrap();
+            let file_num = from_str::<uint>(nums[0]).unwrap();
+            let line_num = from_str::<uint>(nums[1]).unwrap();
             assert_eq!(line_num, state.line_num_file);
             assert_eq!(file_num * 3 + line_num, state.line_num);
             true
@@ -540,6 +547,7 @@ fn test_input_vec_state() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_empty_files() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -564,18 +572,21 @@ fn test_empty_files() {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_no_trailing_newline() {
         let f1 =
             Some(Path("tmp/lib-fileinput-test-no-trailing-newline-1.tmp"));
         let f2 =
             Some(Path("tmp/lib-fileinput-test-no-trailing-newline-2.tmp"));
 
-        let wr = io::file_writer(f1.get_ref(),
-                                 [io::Create, io::Truncate]).unwrap();
-        wr.write_str("1\n2");
-        let wr = io::file_writer(f2.get_ref(),
-                                 [io::Create, io::Truncate]).unwrap();
-        wr.write_str("3\n4");
+        {
+            let mut wr = file::open(f1.get_ref(), io::CreateOrTruncate,
+                                    io::Write).unwrap();
+            wr.write("1\n2".as_bytes());
+            let mut wr = file::open(f2.get_ref(), io::CreateOrTruncate,
+                                    io::Write).unwrap();
+            wr.write("3\n4".as_bytes());
+        }
 
         let mut lines = ~[];
         do input_vec(~[f1, f2]) |line| {
@@ -587,6 +598,7 @@ fn test_no_trailing_newline() {
 
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_next_file() {
         let filenames = make_path_option_vec(vec::from_fn(
             3,
@@ -618,6 +630,7 @@ fn test_next_file() {
 
     #[test]
     #[should_fail]
+    #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
     fn test_input_vec_missing_file() {
         do input_vec(make_path_option_vec([~"this/file/doesnt/exist"], true)) |line| {
             println(line);
index d82c1fd35c2ce8823aef51878db758038d1d0f3a..39a4ac618466cfebf469c2f830283821e63c6133 100644 (file)
@@ -137,7 +137,17 @@ fn list_dir_sorted(path: &Path) -> ~[Path] {
 /**
  * A compiled Unix shell style pattern.
  */
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Zero)]
+#[cfg(stage0)]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+pub struct Pattern {
+    priv tokens: ~[PatternToken]
+}
+
+/**
+ * A compiled Unix shell style pattern.
+ */
+#[cfg(not(stage0))]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
 pub struct Pattern {
     priv tokens: ~[PatternToken]
 }
@@ -147,8 +157,14 @@ enum PatternToken {
     Char(char),
     AnyChar,
     AnySequence,
-    AnyWithin(~[char]),
-    AnyExcept(~[char])
+    AnyWithin(~[CharSpecifier]),
+    AnyExcept(~[CharSpecifier])
+}
+
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+enum CharSpecifier {
+    SingleChar(char),
+    CharRange(char, char)
 }
 
 #[deriving(Eq)]
@@ -164,12 +180,15 @@ impl Pattern {
      * This function compiles Unix shell style patterns: `?` matches any single character,
      * `*` matches any (possibly empty) sequence of characters and `[...]` matches any character
      * inside the brackets, unless the first character is `!` in which case it matches any
-     * character except those between the `!` and the `]`.
+     * character except those between the `!` and the `]`. Character sequences can also specify
+     * ranges of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any character
+     * between 0 and 9 inclusive.
      *
      * The metacharacters `?`, `*`, `[`, `]` can be matched by using brackets (e.g. `[?]`).
      * When a `]` occurs immediately following `[` or `[!` then it is interpreted as
      * being part of, rather then ending, the character set, so `]` and NOT `]` can be
-     * matched by `[]]` and `[!]]` respectively.
+     * matched by `[]]` and `[!]]` respectively. The `-` character can be specified inside a
+     * character sequence pattern by placing it at the start or the end, e.g. `[abc-]`.
      *
      * When a `[` does not have a closing `]` before the end of the string then the `[` will
      * be treated literally.
@@ -199,7 +218,8 @@ pub fn new(pattern: &str) -> Pattern {
                         match chars.slice_from(i + 3).position_elem(&']') {
                             None => (),
                             Some(j) => {
-                                tokens.push(AnyExcept(chars.slice(i + 2, i + 3 + j).to_owned()));
+                                let cs = parse_char_specifiers(chars.slice(i + 2, i + 3 + j));
+                                tokens.push(AnyExcept(cs));
                                 i += j + 4;
                                 loop;
                             }
@@ -209,7 +229,8 @@ pub fn new(pattern: &str) -> Pattern {
                         match chars.slice_from(i + 2).position_elem(&']') {
                             None => (),
                             Some(j) => {
-                                tokens.push(AnyWithin(chars.slice(i + 1, i + 2 + j).to_owned()));
+                                let cs = parse_char_specifiers(chars.slice(i + 1, i + 2 + j));
+                                tokens.push(AnyWithin(cs));
                                 i += j + 3;
                                 loop;
                             }
@@ -301,7 +322,7 @@ fn matches_from(&self,
         let require_literal = |c| {
             (options.require_literal_separator && is_sep(c)) ||
             (options.require_literal_leading_dot && c == '.'
-             && is_sep(prev_char.unwrap_or_default('/')))
+             && is_sep(prev_char.unwrap_or('/')))
         };
 
         for (ti, token) in self.tokens.slice_from(i).iter().enumerate() {
@@ -335,15 +356,11 @@ fn matches_from(&self,
                         AnyChar => {
                             !require_literal(c)
                         }
-                        AnyWithin(ref chars) => {
-                            !require_literal(c) &&
-                            chars.iter()
-                                .rposition(|&e| chars_eq(e, c, options.case_sensitive)).is_some()
+                        AnyWithin(ref specifiers) => {
+                            !require_literal(c) && in_char_specifiers(*specifiers, c, options)
                         }
-                        AnyExcept(ref chars) => {
-                            !require_literal(c) &&
-                            chars.iter()
-                                .rposition(|&e| chars_eq(e, c, options.case_sensitive)).is_none()
+                        AnyExcept(ref specifiers) => {
+                            !require_literal(c) && !in_char_specifiers(*specifiers, c, options)
                         }
                         Char(c2) => {
                             chars_eq(c, c2, options.case_sensitive)
@@ -370,6 +387,63 @@ fn matches_from(&self,
 
 }
 
+fn parse_char_specifiers(s: &[char]) -> ~[CharSpecifier] {
+    let mut cs = ~[];
+    let mut i = 0;
+    while i < s.len() {
+        if i + 3 <= s.len() && s[i + 1] == '-' {
+            cs.push(CharRange(s[i], s[i + 2]));
+            i += 3;
+        } else {
+            cs.push(SingleChar(s[i]));
+            i += 1;
+        }
+    }
+    cs
+}
+
+fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptions) -> bool {
+
+    for &specifier in specifiers.iter() {
+        match specifier {
+            SingleChar(sc) => {
+                if chars_eq(c, sc, options.case_sensitive) {
+                    return true;
+                }
+            }
+            CharRange(start, end) => {
+
+                // FIXME: work with non-ascii chars properly (issue #1347)
+                if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() {
+
+                    let start = start.to_ascii().to_lower();
+                    let end = end.to_ascii().to_lower();
+
+                    let start_up = start.to_upper();
+                    let end_up = end.to_upper();
+
+                    // only allow case insensitive matching when
+                    // both start and end are within a-z or A-Z
+                    if start != start_up && end != end_up {
+                        let start = start.to_char();
+                        let end = end.to_char();
+                        let c = c.to_ascii().to_lower().to_char();
+                        if c >= start && c <= end {
+                            return true;
+                        }
+                    }
+                }
+
+                if c >= start && c <= end {
+                    return true;
+                }
+            }
+        }
+    }
+
+    false
+}
+
 /// A helper function to determine if two chars are (possibly case-insensitively) equal.
 fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
     if cfg!(windows) && path::windows::is_sep(a) && path::windows::is_sep(b) {
@@ -394,7 +468,37 @@ fn is_sep(c: char) -> bool {
 /**
  * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
  */
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Zero)]
+#[cfg(stage0)]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+pub struct MatchOptions {
+
+    /**
+     * Whether or not patterns should be matched in a case-sensitive manner. This
+     * currently only considers upper/lower case relationships between ASCII characters,
+     * but in future this might be extended to work with Unicode.
+     */
+    case_sensitive: bool,
+
+    /**
+     * If this is true then path-component separator characters (e.g. `/` on Posix)
+     * must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
+     */
+    require_literal_separator: bool,
+
+    /**
+     * If this is true then paths that contain components that start with a `.` will
+     * not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
+     * will not match. This is useful because such files are conventionally considered
+     * hidden on Unix systems and it might be desirable to skip them when listing files.
+     */
+    require_literal_leading_dot: bool
+}
+
+/**
+ * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
+ */
+#[cfg(not(stage0))]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
 pub struct MatchOptions {
 
     /**
@@ -452,194 +556,6 @@ mod test {
     use super::*;
     use tempfile;
 
-    #[test]
-    fn test_relative_pattern() {
-
-        fn change_then_remove(p: &Path, f: &fn()) {
-            do (|| {
-                unstable::change_dir_locked(p, || f());
-            }).finally {
-                os::remove_dir_recursive(p);
-            }
-        }
-
-        fn mk_file(path: &str, directory: bool) {
-            if directory {
-                os::make_dir(&Path(path), 0xFFFF);
-            } else {
-                io::mk_file_writer(&Path(path), [io::Create]);
-            }
-        }
-
-        fn abs_path(path: &str) -> Path {
-            os::getcwd().push_many(Path(path).components)
-        }
-
-        fn glob_vec(pattern: &str) -> ~[Path] {
-            glob(pattern).collect()
-        }
-
-        let root = tempfile::mkdtemp(&os::tmpdir(), "glob-tests");
-        let root = root.expect("Should have created a temp directory");
-
-        do change_then_remove(&root) {
-
-            mk_file("aaa", true);
-            mk_file("aaa/apple", true);
-            mk_file("aaa/orange", true);
-            mk_file("aaa/tomato", true);
-            mk_file("aaa/tomato/tomato.txt", false);
-            mk_file("aaa/tomato/tomoto.txt", false);
-            mk_file("bbb", true);
-            mk_file("bbb/specials", true);
-            mk_file("bbb/specials/!", false);
-
-            // windows does not allow `*` or `?` characters to exist in filenames
-            if os::consts::FAMILY != os::consts::windows::FAMILY {
-                mk_file("bbb/specials/*", false);
-                mk_file("bbb/specials/?", false);
-            }
-
-            mk_file("bbb/specials/[", false);
-            mk_file("bbb/specials/]", false);
-            mk_file("ccc", true);
-            mk_file("xyz", true);
-            mk_file("xyz/x", false);
-            mk_file("xyz/y", false);
-            mk_file("xyz/z", false);
-
-            assert_eq!(glob_vec(""), ~[]);
-            assert_eq!(glob_vec("."), ~[]);
-            assert_eq!(glob_vec(".."), ~[]);
-
-            assert_eq!(glob_vec("aaa"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("aaa/"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("a"), ~[]);
-            assert_eq!(glob_vec("aa"), ~[]);
-            assert_eq!(glob_vec("aaaa"), ~[]);
-
-            assert_eq!(glob_vec("aaa/apple"), ~[abs_path("aaa/apple")]);
-            assert_eq!(glob_vec("aaa/apple/nope"), ~[]);
-
-            // windows should support both / and \ as directory separators
-            if os::consts::FAMILY == os::consts::windows::FAMILY {
-                assert_eq!(glob_vec("aaa\\apple"), ~[abs_path("aaa/apple")]);
-            }
-
-            assert_eq!(glob_vec("???/"), ~[
-                abs_path("aaa"),
-                abs_path("bbb"),
-                abs_path("ccc"),
-                abs_path("xyz")]);
-
-            assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), ~[
-                abs_path("aaa/tomato/tomato.txt"),
-                abs_path("aaa/tomato/tomoto.txt")]);
-
-            assert_eq!(glob_vec("xyz/?"), ~[
-                abs_path("xyz/x"),
-                abs_path("xyz/y"),
-                abs_path("xyz/z")]);
-
-            assert_eq!(glob_vec("a*"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("*a*"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("a*a"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("aaa*"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("*aaa"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("*aaa*"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("*a*a*a*"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("aaa*/"), ~[abs_path("aaa")]);
-
-            assert_eq!(glob_vec("aaa/*"), ~[
-                abs_path("aaa/apple"),
-                abs_path("aaa/orange"),
-                abs_path("aaa/tomato")]);
-
-            assert_eq!(glob_vec("aaa/*a*"), ~[
-                abs_path("aaa/apple"),
-                abs_path("aaa/orange"),
-                abs_path("aaa/tomato")]);
-
-            assert_eq!(glob_vec("*/*/*.txt"), ~[
-                abs_path("aaa/tomato/tomato.txt"),
-                abs_path("aaa/tomato/tomoto.txt")]);
-
-            assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), ~[
-                abs_path("aaa/tomato/tomato.txt"),
-                abs_path("aaa/tomato/tomoto.txt")]);
-
-            assert_eq!(glob_vec("aa[a]"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("aa[abc]"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("a[bca]a"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("aa[b]"), ~[]);
-            assert_eq!(glob_vec("aa[xyz]"), ~[]);
-            assert_eq!(glob_vec("aa[]]"), ~[]);
-
-            assert_eq!(glob_vec("aa[!b]"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("aa[!bcd]"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("a[!bcd]a"), ~[abs_path("aaa")]);
-            assert_eq!(glob_vec("aa[!a]"), ~[]);
-            assert_eq!(glob_vec("aa[!abc]"), ~[]);
-
-            assert_eq!(glob_vec("bbb/specials/[[]"), ~[abs_path("bbb/specials/[")]);
-            assert_eq!(glob_vec("bbb/specials/!"), ~[abs_path("bbb/specials/!")]);
-            assert_eq!(glob_vec("bbb/specials/[]]"), ~[abs_path("bbb/specials/]")]);
-
-            if os::consts::FAMILY != os::consts::windows::FAMILY {
-                assert_eq!(glob_vec("bbb/specials/[*]"), ~[abs_path("bbb/specials/*")]);
-                assert_eq!(glob_vec("bbb/specials/[?]"), ~[abs_path("bbb/specials/?")]);
-            }
-
-            if os::consts::FAMILY == os::consts::windows::FAMILY {
-
-                assert_eq!(glob_vec("bbb/specials/[![]"), ~[
-                    abs_path("bbb/specials/!"),
-                    abs_path("bbb/specials/]")]);
-
-                assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
-                    abs_path("bbb/specials/!"),
-                    abs_path("bbb/specials/[")]);
-
-                assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
-                    abs_path("bbb/specials/["),
-                    abs_path("bbb/specials/]")]);
-
-            } else {
-
-                assert_eq!(glob_vec("bbb/specials/[![]"), ~[
-                    abs_path("bbb/specials/!"),
-                    abs_path("bbb/specials/*"),
-                    abs_path("bbb/specials/?"),
-                    abs_path("bbb/specials/]")]);
-
-                assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
-                    abs_path("bbb/specials/!"),
-                    abs_path("bbb/specials/*"),
-                    abs_path("bbb/specials/?"),
-                    abs_path("bbb/specials/[")]);
-
-                assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
-                    abs_path("bbb/specials/*"),
-                    abs_path("bbb/specials/?"),
-                    abs_path("bbb/specials/["),
-                    abs_path("bbb/specials/]")]);
-
-                assert_eq!(glob_vec("bbb/specials/[!*]"), ~[
-                    abs_path("bbb/specials/!"),
-                    abs_path("bbb/specials/?"),
-                    abs_path("bbb/specials/["),
-                    abs_path("bbb/specials/]")]);
-
-                assert_eq!(glob_vec("bbb/specials/[!?]"), ~[
-                    abs_path("bbb/specials/!"),
-                    abs_path("bbb/specials/*"),
-                    abs_path("bbb/specials/["),
-                    abs_path("bbb/specials/]")]);
-
-            }
-        };
-    }
-
     #[test]
     fn test_absolute_pattern() {
         // assume that the filesystem is not empty!
@@ -672,6 +588,54 @@ fn test_lots_of_files() {
         glob("/*/*/*/*").skip(10000).next();
     }
 
+    #[test]
+    fn test_range_pattern() {
+
+        let pat = Pattern::new("a[0-9]b");
+        for i in range(0, 10) {
+            assert!(pat.matches(fmt!("a%db", i)));
+        }
+        assert!(!pat.matches("a_b"));
+
+        let pat = Pattern::new("a[!0-9]b");
+        for i in range(0, 10) {
+            assert!(!pat.matches(fmt!("a%db", i)));
+        }
+        assert!(pat.matches("a_b"));
+
+        let pats = ["[a-z123]", "[1a-z23]", "[123a-z]"];
+        for &p in pats.iter() {
+            let pat = Pattern::new(p);
+            for c in "abcdefghijklmnopqrstuvwxyz".iter() {
+                assert!(pat.matches(c.to_str()));
+            }
+            for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".iter() {
+                let options = MatchOptions {case_sensitive: false, .. MatchOptions::new()};
+                assert!(pat.matches_with(c.to_str(), options));
+            }
+            assert!(pat.matches("1"));
+            assert!(pat.matches("2"));
+            assert!(pat.matches("3"));
+        }
+
+        let pats = ["[abc-]", "[-abc]", "[a-c-]"];
+        for &p in pats.iter() {
+            let pat = Pattern::new(p);
+            assert!(pat.matches("a"));
+            assert!(pat.matches("b"));
+            assert!(pat.matches("c"));
+            assert!(pat.matches("-"));
+            assert!(!pat.matches("d"));
+        }
+
+        let pat = Pattern::new("[2-1]");
+        assert!(!pat.matches("1"));
+        assert!(!pat.matches("2"));
+
+        assert!(Pattern::new("[-]").matches("-"));
+        assert!(!Pattern::new("[!-]").matches("-"));
+    }
+
     #[test]
     fn test_unclosed_bracket() {
         // unclosed `[` should be treated literally
index e9b267e95884ff0809b70c0cb49a266b3f00580d..24f44c8a2a8ec5ab7ca1b3e56ea727ffe1abb973 100644 (file)
@@ -23,6 +23,7 @@
 use std::int;
 use std::num;
 use std::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable};
+use std::rand::{Rng, RngUtil};
 use std::str;
 use std::uint;
 use std::vec;
@@ -502,7 +503,7 @@ 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
+        self.to_int_opt().expect("BigUint conversion would overflow int")
     }
 
     #[inline]
@@ -614,18 +615,43 @@ 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.
+    /// Converts this BigUint into a uint, failing if the conversion
+    /// would overflow.
     #[inline]
     pub fn to_uint(&self) -> uint {
+        self.to_uint_opt().expect("BigUint conversion would overflow uint")
+    }
+
+    /// Converts this BigUint into a uint, unless it would overflow.
+    #[inline]
+    pub fn to_uint_opt(&self) -> Option<uint> {
         match self.data.len() {
-            0 => 0,
-            1 => self.data[0] as uint,
-            2 => BigDigit::to_uint(self.data[1], self.data[0]),
-            _ => uint::max_value
+            0 => Some(0),
+            1 => Some(self.data[0] as uint),
+            2 => Some(BigDigit::to_uint(self.data[1], self.data[0])),
+            _ => None
         }
     }
 
+    // Converts this BigUint into an int, unless it would overflow.
+    pub fn to_int_opt(&self) -> Option<int> {
+        self.to_uint_opt().and_then(|n| {
+            // If top bit of uint is set, it's too large to convert to
+            // int.
+            if (n >> (2*BigDigit::bits - 1) != 0) {
+                None
+            } else {
+                Some(n as int)
+            }
+        })
+    }
+
+    /// Converts this BigUint into a BigInt.
+    #[inline]
+    pub fn to_bigint(&self) -> BigInt {
+        BigInt::from_biguint(Plus, self.clone())
+    }
+
     #[inline]
     fn shl_unit(&self, n_unit: uint) -> BigUint {
         if n_unit == 0 || self.is_zero() { return (*self).clone(); }
@@ -1047,12 +1073,7 @@ 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,
-            Zero  => 0,
-            Minus => num::min((-self).to_uint(),
-                               (int::max_value as uint) + 1) as int
-        }
+        self.to_int_opt().expect("BigInt conversion would overflow int")
     }
 
     #[inline]
@@ -1088,6 +1109,53 @@ fn from_str_radix(s: &str, radix: uint) -> Option<BigInt> {
     }
 }
 
+trait RandBigInt {
+    /// Generate a random BigUint of the given bit size.
+    fn gen_biguint(&mut self, bit_size: uint) -> BigUint;
+
+    /// Generate a random BigInt of the given bit size.
+    fn gen_bigint(&mut self, bit_size: uint) -> BigInt;
+}
+
+impl<R: Rng> RandBigInt for R {
+    /// Generate a random BigUint of the given bit size.
+    fn gen_biguint(&mut self, bit_size: uint) -> BigUint {
+        let (digits, rem) = bit_size.div_rem(&BigDigit::bits);
+        let mut data = vec::with_capacity(digits+1);
+        for _ in range(0, digits) {
+            data.push(self.gen());
+        }
+        if rem > 0 {
+            let final_digit: BigDigit = self.gen();
+            data.push(final_digit >> (BigDigit::bits - rem));
+        }
+        return BigUint::new(data);
+    }
+
+    /// Generate a random BigInt of the given bit size.
+    fn gen_bigint(&mut self, bit_size: uint) -> BigInt {
+        // Generate a random BigUint...
+        let biguint = self.gen_biguint(bit_size);
+        // ...and then randomly assign it a Sign...
+        let sign = if biguint.is_zero() {
+            // ...except that if the BigUint is zero, we need to try
+            // again with probability 0.5. This is because otherwise,
+            // the probability of generating a zero BigInt would be
+            // double that of any other number.
+            if self.gen() {
+                return self.gen_bigint(bit_size);
+            } else {
+                Zero
+            }
+        } else if self.gen() {
+            Plus
+        } else {
+            Minus
+        };
+        return BigInt::from_biguint(sign, biguint);
+    }
+}
+
 impl BigInt {
     /// Creates and initializes an BigInt.
     #[inline]
@@ -1131,12 +1199,55 @@ pub fn parse_bytes(buf: &[u8], radix: uint)
             .map_move(|bu| BigInt::from_biguint(sign, bu));
     }
 
+    /// Converts this BigInt into a uint, failing if the conversion
+    /// would overflow.
     #[inline]
     pub fn to_uint(&self) -> uint {
+        self.to_uint_opt().expect("BigInt conversion would overflow uint")
+    }
+
+    /// Converts this BigInt into a uint, unless it would overflow.
+    #[inline]
+    pub fn to_uint_opt(&self) -> Option<uint> {
         match self.sign {
-            Plus  => self.data.to_uint(),
-            Zero  => 0,
-            Minus => 0
+            Plus => self.data.to_uint_opt(),
+            Zero => Some(0),
+            Minus => None
+        }
+    }
+
+    /// Converts this BigInt into an int, unless it would overflow.
+    pub fn to_int_opt(&self) -> Option<int> {
+        match self.sign {
+            Plus  => self.data.to_int_opt(),
+            Zero  => Some(0),
+            Minus => self.data.to_uint_opt().and_then(|n| {
+                let m: uint = 1 << (2*BigDigit::bits-1);
+                if (n > m) {
+                    None
+                } else if (n == m) {
+                    Some(int::min_value)
+                } else {
+                    Some(-(n as int))
+                }
+            })
+        }
+    }
+
+    /// Converts this BigInt into a BigUint, failing if BigInt is
+    /// negative.
+    #[inline]
+    pub fn to_biguint(&self) -> BigUint {
+        self.to_biguint_opt().expect("negative BigInt cannot convert to BigUint")
+    }
+
+    /// Converts this BigInt into a BigUint, if it's not negative.
+    #[inline]
+    pub fn to_biguint_opt(&self) -> Option<BigUint> {
+        match self.sign {
+            Plus => Some(self.data.clone()),
+            Zero => Some(Zero::zero()),
+            Minus => None
         }
     }
 }
@@ -1149,6 +1260,7 @@ mod biguint_tests {
     use std::cmp::{Less, Equal, Greater};
     use std::int;
     use std::num::{IntConvertible, Zero, One, FromStrRadix};
+    use std::rand::{task_rng};
     use std::str;
     use std::uint;
     use std::vec;
@@ -1336,9 +1448,9 @@ fn check(v: ~[BigDigit], i: int) {
         check(~[ 0,  1], ((uint::max_value >> BigDigit::bits) + 1) as int);
         check(~[-1, -1 >> 1], int::max_value);
 
-        assert_eq!(BigUint::new(~[0, -1]).to_int(), int::max_value);
-        assert_eq!(BigUint::new(~[0, 0, 1]).to_int(), int::max_value);
-        assert_eq!(BigUint::new(~[0, 0, -1]).to_int(), int::max_value);
+        assert_eq!(BigUint::new(~[0, -1]).to_int_opt(), None);
+        assert_eq!(BigUint::new(~[0, 0, 1]).to_int_opt(), None);
+        assert_eq!(BigUint::new(~[0, 0, -1]).to_int_opt(), None);
     }
 
     #[test]
@@ -1356,8 +1468,19 @@ fn check(v: ~[BigDigit], u: uint) {
         check(~[ 0, -1], uint::max_value << BigDigit::bits);
         check(~[-1, -1], uint::max_value);
 
-        assert_eq!(BigUint::new(~[0, 0, 1]).to_uint(), uint::max_value);
-        assert_eq!(BigUint::new(~[0, 0, -1]).to_uint(), uint::max_value);
+        assert_eq!(BigUint::new(~[0, 0, 1]).to_uint_opt(), None);
+        assert_eq!(BigUint::new(~[0, 0, -1]).to_uint_opt(), None);
+    }
+
+    #[test]
+    fn test_convert_to_bigint() {
+        fn check(n: BigUint, ans: BigInt) {
+            assert_eq!(n.to_bigint(), ans);
+            assert_eq!(n.to_bigint().to_biguint(), n);
+        }
+        check(Zero::zero(), Zero::zero());
+        check(BigUint::new(~[1,2,3]),
+              BigInt::from_biguint(Plus, BigUint::new(~[1,2,3])));
     }
 
     static sum_triples: &'static [(&'static [BigDigit],
@@ -1656,6 +1779,13 @@ fn check(n: uint, s: &str) {
         check(20, "2432902008176640000");
         check(30, "265252859812191058636308480000000");
     }
+
+    #[test]
+    fn test_rand() {
+        let mut rng = task_rng();
+        let _n: BigUint = rng.gen_biguint(137);
+        assert!(rng.gen_biguint(0).is_zero());
+    }
 }
 
 #[cfg(test)]
@@ -1665,6 +1795,7 @@ mod bigint_tests {
     use std::cmp::{Less, Equal, Greater};
     use std::int;
     use std::num::{IntConvertible, Zero, One, FromStrRadix};
+    use std::rand::{task_rng};
     use std::uint;
 
     #[test]
@@ -1736,22 +1867,21 @@ fn check(b: BigInt, i: int) {
             Plus, BigUint::from_uint(int::max_value as uint)
         ), int::max_value);
 
-        assert!(BigInt::from_biguint(
+        assert_eq!(BigInt::from_biguint(
             Plus, BigUint::from_uint(int::max_value as uint + 1)
-        ).to_int() == int::max_value);
-        assert!(BigInt::from_biguint(
+        ).to_int_opt(), None);
+        assert_eq!(BigInt::from_biguint(
             Plus, BigUint::new(~[1, 2, 3])
-        ).to_int() == int::max_value);
+        ).to_int_opt(), None);
 
         check(BigInt::from_biguint(
-            Minus, BigUint::from_uint(-int::min_value as uint)
+            Minus, BigUint::new(~[0, 1<<(BigDigit::bits-1)])
         ), int::min_value);
-        assert!(BigInt::from_biguint(
-            Minus, BigUint::from_uint(-int::min_value as uint + 1)
-        ).to_int() == int::min_value);
-        assert!(BigInt::from_biguint(
-            Minus, BigUint::new(~[1, 2, 3])
-        ).to_int() == int::min_value);
+        assert_eq!(BigInt::from_biguint(
+            Minus, BigUint::new(~[1, 1<<(BigDigit::bits-1)])
+        ).to_int_opt(), None);
+        assert_eq!(BigInt::from_biguint(
+            Minus, BigUint::new(~[1, 2, 3])).to_int_opt(), None);
     }
 
     #[test]
@@ -1767,16 +1897,31 @@ fn check(b: BigInt, u: uint) {
         check(
             BigInt::from_biguint(Plus, BigUint::from_uint(uint::max_value)),
             uint::max_value);
-        assert!(BigInt::from_biguint(
-            Plus, BigUint::new(~[1, 2, 3])
-        ).to_uint() == uint::max_value);
+        assert_eq!(BigInt::from_biguint(
+            Plus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
+
+        assert_eq!(BigInt::from_biguint(
+            Minus, BigUint::from_uint(uint::max_value)).to_uint_opt(), None);
+        assert_eq!(BigInt::from_biguint(
+            Minus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
+    }
+
+    #[test]
+    fn test_convert_to_biguint() {
+        fn check(n: BigInt, ans_1: BigUint) {
+            assert_eq!(n.to_biguint(), ans_1);
+            assert_eq!(n.to_biguint().to_bigint(), n);
+        }
+        let zero: BigInt = Zero::zero();
+        let unsigned_zero: BigUint = Zero::zero();
+        let positive = BigInt::from_biguint(
+            Plus, BigUint::new(~[1,2,3]));
+        let negative = -positive;
+
+        check(zero, unsigned_zero);
+        check(positive, BigUint::new(~[1,2,3]));
 
-        assert!(BigInt::from_biguint(
-            Minus, BigUint::from_uint(uint::max_value)
-        ).to_uint() == 0);
-        assert!(BigInt::from_biguint(
-            Minus, BigUint::new(~[1, 2, 3])
-        ).to_uint() == 0);
+        assert_eq!(negative.to_biguint_opt(), None);
     }
 
     static sum_triples: &'static [(&'static [BigDigit],
@@ -2085,6 +2230,13 @@ fn test_neg() {
         let zero: BigInt = Zero::zero();
         assert_eq!(-zero, zero);
     }
+
+    #[test]
+    fn test_rand() {
+        let mut rng = task_rng();
+        let _n: BigInt = rng.gen_bigint(137);
+        assert!(rng.gen_bigint(0).is_zero());
+    }
 }
 
 #[cfg(test)]
index 41e9a488bf8ae8fa74149502dbe2f35eface48b0..1991d9f1b5bbc7486e4c16be06e27c36eacd7884 100644 (file)
@@ -273,9 +273,9 @@ fn from_str(s: &str) -> Option<Ratio<T>> {
             return None
         }
         let a_option: Option<T> = FromStr::from_str(split[0]);
-        do a_option.chain |a| {
+        do a_option.and_then |a| {
             let b_option: Option<T> = FromStr::from_str(split[1]);
-            do b_option.chain |b| {
+            do b_option.and_then |b| {
                 Some(Ratio::new(a.clone(), b.clone()))
             }
         }
@@ -291,10 +291,10 @@ fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
         } else {
             let a_option: Option<T> = FromStrRadix::from_str_radix(split[0],
                                                                    radix);
-            do a_option.chain |a| {
+            do a_option.and_then |a| {
                 let b_option: Option<T> =
                     FromStrRadix::from_str_radix(split[1], radix);
-                do b_option.chain |b| {
+                do b_option.and_then |b| {
                     Some(Ratio::new(a.clone(), b.clone()))
                 }
             }
index 09ef7f22be5912b4d34c9d3f22c13e68b05d6844..74b7aea99787794ad9735519ca9a49023b285d5d 100644 (file)
@@ -8,13 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// FIXME #3921. This is unsafe because linenoise uses global mutable
-// state without mutexes.
-
 use std::c_str::ToCStr;
 use std::libc::{c_char, c_int};
-use std::local_data;
-use std::str;
+use std::{local_data, str, rt};
+use std::unstable::finally::Finally;
 
 #[cfg(stage0)]
 pub mod rustrt {
@@ -28,6 +25,9 @@ pub mod rustrt {
         fn linenoiseHistoryLoad(file: *c_char) -> c_int;
         fn linenoiseSetCompletionCallback(callback: *u8);
         fn linenoiseAddCompletion(completions: *(), line: *c_char);
+
+        fn rust_take_linenoise_lock();
+        fn rust_drop_linenoise_lock();
     }
 }
 
@@ -42,65 +42,107 @@ pub mod rustrt {
     externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
     externfn!(fn linenoiseSetCompletionCallback(callback: extern "C" fn(*i8, *())))
     externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
+
+    externfn!(fn rust_take_linenoise_lock())
+    externfn!(fn rust_drop_linenoise_lock())
+}
+
+macro_rules! locked {
+    ($expr:expr) => {
+        unsafe {
+            // FIXME #9105: can't use a static mutex in pure Rust yet.
+            rustrt::rust_take_linenoise_lock();
+            let x = $expr;
+            rustrt::rust_drop_linenoise_lock();
+            x
+        }
+    }
 }
 
 /// Add a line to history
-pub unsafe fn add_history(line: &str) -> bool {
+pub fn add_history(line: &str) -> bool {
     do line.with_c_str |buf| {
-        rustrt::linenoiseHistoryAdd(buf) == 1 as c_int
+        (locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
     }
 }
 
 /// Set the maximum amount of lines stored
-pub unsafe fn set_history_max_len(len: int) -> bool {
-    rustrt::linenoiseHistorySetMaxLen(len as c_int) == 1 as c_int
+pub fn set_history_max_len(len: int) -> bool {
+    (locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1 as c_int
 }
 
 /// Save line history to a file
-pub unsafe fn save_history(file: &str) -> bool {
+pub fn save_history(file: &str) -> bool {
     do file.with_c_str |buf| {
-        rustrt::linenoiseHistorySave(buf) == 1 as c_int
+        // 0 on success, -1 on failure
+        (locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
     }
 }
 
 /// Load line history from a file
-pub unsafe fn load_history(file: &str) -> bool {
+pub fn load_history(file: &str) -> bool {
     do file.with_c_str |buf| {
-        rustrt::linenoiseHistoryLoad(buf) == 1 as c_int
+        // 0 on success, -1 on failure
+        (locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
     }
 }
 
 /// Print out a prompt and then wait for input and return it
-pub unsafe fn read(prompt: &str) -> Option<~str> {
+pub fn read(prompt: &str) -> Option<~str> {
     do prompt.with_c_str |buf| {
-        let line = rustrt::linenoise(buf);
+        let line = locked!(rustrt::linenoise(buf));
 
         if line.is_null() { None }
-        else { Some(str::raw::from_c_str(line)) }
+        else {
+            unsafe {
+                do (|| {
+                    Some(str::raw::from_c_str(line))
+                }).finally {
+                    // linenoise's return value is from strdup, so we
+                    // better not leak it.
+                    rt::global_heap::exchange_free(line);
+                }
+            }
+        }
     }
 }
 
 pub type CompletionCb = @fn(~str, @fn(~str));
 
-static complete_key: local_data::Key<@CompletionCb> = &local_data::Key;
-
-/// Bind to the main completion callback
-pub unsafe fn complete(cb: CompletionCb) {
-    local_data::set(complete_key, @cb);
-
-    extern fn callback(line: *c_char, completions: *()) {
-        do local_data::get(complete_key) |cb| {
-            let cb = **cb.unwrap();
-
-            unsafe {
-                do cb(str::raw::from_c_str(line)) |suggestion| {
-                    do suggestion.with_c_str |buf| {
-                        rustrt::linenoiseAddCompletion(completions, buf);
+static complete_key: local_data::Key<CompletionCb> = &local_data::Key;
+
+/// Bind to the main completion callback in the current task.
+///
+/// The completion callback should not call any `extra::rl` functions
+/// other than the closure that it receives as its second
+/// argument. Calling such a function will deadlock on the mutex used
+/// to ensure that the calls are thread-safe.
+pub fn complete(cb: CompletionCb) {
+    local_data::set(complete_key, cb);
+
+    extern fn callback(c_line: *c_char, completions: *()) {
+        do local_data::get(complete_key) |opt_cb| {
+            // only fetch completions if a completion handler has been
+            // registered in the current task.
+            match opt_cb {
+                None => {},
+                Some(cb) => {
+                    let line = unsafe { str::raw::from_c_str(c_line) };
+                    do (*cb)(line) |suggestion| {
+                        do suggestion.with_c_str |buf| {
+                            // This isn't locked, because `callback` gets
+                            // called inside `rustrt::linenoise`, which
+                            // *is* already inside the mutex, so
+                            // re-locking would be a deadlock.
+                            unsafe {
+                                rustrt::linenoiseAddCompletion(completions, buf);
+                            }
+                        }
                     }
                 }
             }
         }
     }
 
-    rustrt::linenoiseSetCompletionCallback(callback);
+    locked!(rustrt::linenoiseSetCompletionCallback(callback));
 }
index 8f7c6a03d1a7363ab7b3f4002f646497f83fdb88..9dabf17162d2bf810654b5bbed916c0df3de417e 100644 (file)
@@ -19,7 +19,6 @@
 use std::io;
 use std::option::{Option, Some, None};
 use std::to_str::ToStr;
-use std::uint;
 
 #[deriving(Clone, Eq)]
 pub enum Identifier {
@@ -140,7 +139,7 @@ fn take_nonempty_prefix(rdr: @io::Reader,
 
 fn take_num(rdr: @io::Reader, ch: char) -> (uint, char) {
     let (s, ch) = take_nonempty_prefix(rdr, ch, char::is_digit);
-    match uint::from_str(s) {
+    match from_str::<uint>(s) {
         None => { bad_parse::cond.raise(()); (0, ch) },
         Some(i) => (i, ch)
     }
@@ -149,7 +148,7 @@ fn take_num(rdr: @io::Reader, ch: char) -> (uint, char) {
 fn take_ident(rdr: @io::Reader, ch: char) -> (Identifier, char) {
     let (s,ch) = take_nonempty_prefix(rdr, ch, char::is_alphanumeric);
     if s.iter().all(char::is_digit) {
-        match uint::from_str(s) {
+        match from_str::<uint>(s) {
             None => { bad_parse::cond.raise(()); (Numeric(0), ch) },
             Some(i) => (Numeric(i), ch)
         }
index cb1bde140568667078bbb4d98b08798ea26e1dd6..9044c23ff7a40409fe075c8a20dad569097cc7d6 100644 (file)
@@ -28,97 +28,6 @@ pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option<Path> {
     None
 }
 
-#[cfg(test)]
-mod tests {
-
-    use tempfile::mkdtemp;
-
-    use std::os;
-
-    #[test]
-    fn test_mkdtemp() {
-        let p = mkdtemp(&Path("."), "foobar").unwrap();
-        os::remove_dir(&p);
-        assert!(p.to_str().ends_with("foobar"));
-    }
-
-    // Ideally these would be in std::os but then core would need
-    // to depend on std
-    #[test]
-    fn recursive_mkdir_rel() {
-        use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
-        use std::os;
-        use std::unstable::change_dir_locked;
-
-        let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel").
-            expect("recursive_mkdir_rel");
-        assert!(do change_dir_locked(&root) {
-            let path = Path("frob");
-            debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(),
-                   os::getcwd().to_str(),
-                   os::path_exists(&path));
-            assert!(os::mkdir_recursive(&path,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
-            assert!(os::path_is_dir(&path));
-            assert!(os::mkdir_recursive(&path,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
-            assert!(os::path_is_dir(&path));
-        });
-    }
-
-    #[test]
-    fn recursive_mkdir_dot() {
-        use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
-        use std::os;
-
-        let dot = Path(".");
-        assert!(os::mkdir_recursive(&dot,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
-        let dotdot = Path("..");
-        assert!(os::mkdir_recursive(&dotdot,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
-    }
-
-    #[test]
-    fn recursive_mkdir_rel_2() {
-        use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
-        use std::os;
-        use std::unstable::change_dir_locked;
-
-        let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2").
-            expect("recursive_mkdir_rel_2");
-        assert!(do change_dir_locked(&root) {
-            let path = Path("./frob/baz");
-            debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(),
-                   os::getcwd().to_str(), os::path_exists(&path));
-            assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
-                assert!(os::path_is_dir(&path));
-            assert!(os::path_is_dir(&path.pop()));
-            let path2 = Path("quux/blat");
-            debug!("recursive_mkdir_rel_2: Making: %s in cwd %s", path2.to_str(),
-                   os::getcwd().to_str());
-            assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
-                assert!(os::path_is_dir(&path2));
-            assert!(os::path_is_dir(&path2.pop()));
-        });
-    }
-
-    // Ideally this would be in core, but needs mkdtemp
-    #[test]
-    pub fn test_rmdir_recursive_ok() {
-        use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
-        use std::os;
-
-        let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
-
-        let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("test_rmdir_recursive_ok: \
-                                            couldn't create temp dir");
-        let root = tmpdir.push("foo");
-
-        debug!("making %s", root.to_str());
-        assert!(os::make_dir(&root, rwx));
-        assert!(os::make_dir(&root.push("foo"), rwx));
-        assert!(os::make_dir(&root.push("foo").push("bar"), rwx));
-        assert!(os::make_dir(&root.push("foo").push("bar").push("blat"), rwx));
-        assert!(os::remove_dir_recursive(&root));
-        assert!(!os::path_exists(&root));
-        assert!(!os::path_exists(&root.push("bar")));
-        assert!(!os::path_exists(&root.push("bar").push("blat")));
-    }
-}
+// the tests for this module need to change the path using change_dir,
+// and this doesn't play nicely with other tests so these unit tests are located
+// in src/test/run-pass/tempfile.rs
index 91db9302f6414dbc0549f54bb6b2457c5f6ea26e..4dcb48d27516e6661d368cb563f333506e6f3e28 100644 (file)
 use std::clone::Clone;
 use std::comm::{stream, SharedChan, GenericPort, GenericChan};
 use std::libc;
-use std::either;
 use std::io;
 use std::result;
 use std::task;
 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
@@ -127,8 +125,8 @@ pub enum MetricChange {
 pub fn test_main(args: &[~str], tests: ~[TestDescAndFn]) {
     let opts =
         match parse_opts(args) {
-          either::Left(o) => o,
-          either::Right(m) => fail!(m)
+            Ok(o) => o,
+            Err(msg) => fail!(msg)
         };
     if !run_tests_console(&opts, tests) { fail!("Some tests failed"); }
 }
@@ -169,7 +167,7 @@ pub struct TestOpts {
     logfile: Option<Path>
 }
 
-type OptRes = Either<TestOpts, ~str>;
+type OptRes = Result<TestOpts, ~str>;
 
 fn optgroups() -> ~[getopts::groups::OptGroup] {
     ~[groups::optflag("", "ignored", "Run ignored tests"),
@@ -228,7 +226,7 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
     let matches =
         match groups::getopts(args_, optgroups()) {
           Ok(m) => m,
-          Err(f) => return either::Right(getopts::fail_str(f))
+          Err(f) => return Err(getopts::fail_str(f))
         };
 
     if getopts::opt_present(&matches, "h") { usage(args[0], "h"); }
@@ -254,7 +252,7 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
     let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s));
 
     let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent");
-    let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| f64::from_str(s).unwrap());
+    let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| from_str::<f64>(s).unwrap());
 
     let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics");
     let save_metrics = save_metrics.map_move(|s| Path(s));
@@ -274,7 +272,7 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
         logfile: logfile
     };
 
-    either::Left(test_opts)
+    Ok(test_opts)
 }
 
 pub fn opt_shard(maybestr: Option<~str>) -> Option<(uint,uint)> {
@@ -282,7 +280,7 @@ pub fn opt_shard(maybestr: Option<~str>) -> Option<(uint,uint)> {
         None => None,
         Some(s) => {
             match s.split_iter('.').to_owned_vec() {
-                [a, b] => match (uint::from_str(a), uint::from_str(b)) {
+                [a, b] => match (from_str::<uint>(a), from_str::<uint>(b)) {
                     (Some(a), Some(b)) => Some((a,b)),
                     _ => None
                 },
@@ -1155,7 +1153,6 @@ mod tests {
                StaticTestName, DynTestName, DynTestFn};
     use test::{TestOpts, run_test};
 
-    use std::either;
     use std::comm::{stream, SharedChan};
     use tempfile;
     use std::os;
@@ -1236,8 +1233,8 @@ fn f() { }
     fn first_free_arg_should_be_a_filter() {
         let args = ~[~"progname", ~"filter"];
         let opts = match parse_opts(args) {
-          either::Left(o) => o,
-          _ => fail!("Malformed arg in first_free_arg_should_be_a_filter")
+            Ok(o) => o,
+            _ => fail!("Malformed arg in first_free_arg_should_be_a_filter")
         };
         assert!("filter" == opts.filter.clone().unwrap());
     }
@@ -1246,8 +1243,8 @@ fn first_free_arg_should_be_a_filter() {
     fn parse_ignored_flag() {
         let args = ~[~"progname", ~"filter", ~"--ignored"];
         let opts = match parse_opts(args) {
-          either::Left(o) => o,
-          _ => fail!("Malformed arg in parse_ignored_flag")
+            Ok(o) => o,
+            _ => fail!("Malformed arg in parse_ignored_flag")
         };
         assert!((opts.run_ignored));
     }
index 7515326a0dbb22ad3968ad0e3ad42fbee9169869..d51d1c217857140565bb8b144e4817b3a15041c2 100644 (file)
@@ -442,21 +442,21 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
           },
           'c' => {
             parse_type(s, pos, 'a', &mut *tm)
-                .chain(|pos| parse_char(s, pos, ' '))
-                .chain(|pos| parse_type(s, pos, 'b', &mut *tm))
-                .chain(|pos| parse_char(s, pos, ' '))
-                .chain(|pos| parse_type(s, pos, 'e', &mut *tm))
-                .chain(|pos| parse_char(s, pos, ' '))
-                .chain(|pos| parse_type(s, pos, 'T', &mut *tm))
-                .chain(|pos| parse_char(s, pos, ' '))
-                .chain(|pos| parse_type(s, pos, 'Y', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ' '))
+                .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ' '))
+                .and_then(|pos| parse_type(s, pos, 'e', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ' '))
+                .and_then(|pos| parse_type(s, pos, 'T', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ' '))
+                .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
           }
           'D' | 'x' => {
             parse_type(s, pos, 'm', &mut *tm)
-                .chain(|pos| parse_char(s, pos, '/'))
-                .chain(|pos| parse_type(s, pos, 'd', &mut *tm))
-                .chain(|pos| parse_char(s, pos, '/'))
-                .chain(|pos| parse_type(s, pos, 'y', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, '/'))
+                .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, '/'))
+                .and_then(|pos| parse_type(s, pos, 'y', &mut *tm))
           }
           'd' => match match_digits_in_range(s, pos, 2u, false, 1_i32,
                                              31_i32) {
@@ -475,10 +475,10 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
           }
           'F' => {
             parse_type(s, pos, 'Y', &mut *tm)
-                .chain(|pos| parse_char(s, pos, '-'))
-                .chain(|pos| parse_type(s, pos, 'm', &mut *tm))
-                .chain(|pos| parse_char(s, pos, '-'))
-                .chain(|pos| parse_type(s, pos, 'd', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, '-'))
+                .and_then(|pos| parse_type(s, pos, 'm', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, '-'))
+                .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
           }
           'H' => {
             match match_digits_in_range(s, pos, 2u, false, 0_i32, 23_i32) {
@@ -553,17 +553,17 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
           },
           'R' => {
             parse_type(s, pos, 'H', &mut *tm)
-                .chain(|pos| parse_char(s, pos, ':'))
-                .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ':'))
+                .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
           }
           'r' => {
             parse_type(s, pos, 'I', &mut *tm)
-                .chain(|pos| parse_char(s, pos, ':'))
-                .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
-                .chain(|pos| parse_char(s, pos, ':'))
-                .chain(|pos| parse_type(s, pos, 'S', &mut *tm))
-                .chain(|pos| parse_char(s, pos, ' '))
-                .chain(|pos| parse_type(s, pos, 'p', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ':'))
+                .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ':'))
+                .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ' '))
+                .and_then(|pos| parse_type(s, pos, 'p', &mut *tm))
           }
           'S' => {
             match match_digits_in_range(s, pos, 2u, false, 0_i32, 60_i32) {
@@ -578,10 +578,10 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
           //'s' {}
           'T' | 'X' => {
             parse_type(s, pos, 'H', &mut *tm)
-                .chain(|pos| parse_char(s, pos, ':'))
-                .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
-                .chain(|pos| parse_char(s, pos, ':'))
-                .chain(|pos| parse_type(s, pos, 'S', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ':'))
+                .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, ':'))
+                .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
           }
           't' => parse_char(s, pos, '\t'),
           'u' => {
@@ -596,10 +596,10 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
           }
           'v' => {
             parse_type(s, pos, 'e', &mut *tm)
-                .chain(|pos|  parse_char(s, pos, '-'))
-                .chain(|pos| parse_type(s, pos, 'b', &mut *tm))
-                .chain(|pos| parse_char(s, pos, '-'))
-                .chain(|pos| parse_type(s, pos, 'Y', &mut *tm))
+                .and_then(|pos|  parse_char(s, pos, '-'))
+                .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
+                .and_then(|pos| parse_char(s, pos, '-'))
+                .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
           }
           //'W' {}
           'w' => {
index b2c0f24824fce579c163afab16704f59532a85f6..2641c1379e4f60d8528d86e9d47356e91c567def 100644 (file)
@@ -417,6 +417,13 @@ pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
     }
 }
 
+impl Default for Uuid {
+    /// Returns the nil UUID, which is all zeroes
+    fn default() -> Uuid {
+        Uuid::new_nil()
+    }
+}
+
 impl Zero for Uuid {
     /// Returns the nil UUID, which is all zeroes
     fn zero() -> Uuid {
index bbb8dbfcbfe5378bad1ba379157259b7abdea46c..aeec4b4258b39084c6d6a136e1743535fbf379a9 100644 (file)
@@ -19,7 +19,6 @@
 use treemap::TreeMap;
 use std::cell::Cell;
 use std::comm::{PortOne, oneshot};
-use std::either::{Either, Left, Right};
 use std::{io, os, task};
 
 /**
@@ -252,9 +251,9 @@ struct Exec {
     discovered_outputs: WorkMap
 }
 
-struct Work<'self, T> {
-    prep: &'self Prep<'self>,
-    res: Option<Either<T,PortOne<(Exec,T)>>>
+enum Work<'self, T> {
+    WorkValue(T),
+    WorkFromTask(&'self Prep<'self>, PortOne<(Exec, T)>),
 }
 
 fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
@@ -426,7 +425,7 @@ fn exec_work<T:Send +
             db.prepare(self.fn_name, &self.declared_inputs)
         };
 
-        let res = match cached {
+        match cached {
             Some((ref disc_in, ref disc_out, ref res))
             if self.all_fresh("declared input",&self.declared_inputs) &&
                self.all_fresh("discovered input", disc_in) &&
@@ -434,7 +433,7 @@ fn exec_work<T:Send +
                 debug!("Cache hit!");
                 debug!("Trying to decode: %? / %? / %?",
                        disc_in, disc_out, *res);
-                Left(json_decode(*res))
+                Work::from_value(json_decode(*res))
             }
 
             _ => {
@@ -453,10 +452,9 @@ fn exec_work<T:Send +
                     let v = blk(&mut exe);
                     chan.send((exe, v));
                 }
-                Right(port)
+                Work::from_task(self, port)
             }
-        };
-        Work::new(self, res)
+        }
     }
 }
 
@@ -465,16 +463,18 @@ impl<'self, T:Send +
        Decodable<json::Decoder>>
     Work<'self, T> { // FIXME(#5121)
 
-    pub fn new(p: &'self Prep<'self>, e: Either<T,PortOne<(Exec,T)>>) -> Work<'self, T> {
-        Work { prep: p, res: Some(e) }
+    pub fn from_value(elt: T) -> Work<'self, T> {
+        WorkValue(elt)
+    }
+    pub fn from_task(prep: &'self Prep<'self>, port: PortOne<(Exec, T)>)
+        -> Work<'self, T> {
+        WorkFromTask(prep, port)
     }
 
     pub fn unwrap(self) -> T {
-        let Work { prep, res } = self;
-        match res {
-            None => fail!(),
-            Some(Left(v)) => v,
-            Some(Right(port)) => {
+        match self {
+            WorkValue(v) => v,
+            WorkFromTask(prep, port) => {
                 let (exe, v) = port.recv();
                 let s = json_encode(&v);
                 do prep.ctxt.db.write |db| {
index b44fb100000d6fadb7630456eed317a79d9b74b9..ffaa7f74800f6131b213dfa7724034df857bfc36 100644 (file)
@@ -60,20 +60,14 @@ struct Command<'self> {
     usage_full: UsageSource<'self>,
 }
 
-static NUM_OF_COMMANDS: uint = 7;
-
-// FIXME(#7617): should just be &'static [Command<'static>]
-// but mac os doesn't seem to like that and tries to loop
-// past the end of COMMANDS in usage thus passing garbage
-// to str::repeat and eventually malloc and crashing.
-static COMMANDS: [Command<'static>, .. NUM_OF_COMMANDS] = [
-    Command{
+static COMMANDS: &'static [Command<'static>] = &'static [
+    Command {
         cmd: "build",
         action: CallMain("rustc", rustc::main_args),
         usage_line: "compile rust source files",
         usage_full: UsgCall(rustc_help),
     },
-    Command{
+    Command {
         cmd: "run",
         action: Call(cmd_run),
         usage_line: "build an executable, and run it",
@@ -83,35 +77,36 @@ struct Command<'self> {
             \n\nUsage:\trust run <filename> [<arguments>...]"
         )
     },
-    Command{
+    Command {
         cmd: "test",
         action: Call(cmd_test),
         usage_line: "build a test executable, and run it",
         usage_full: UsgStr(
             "The test command is an shortcut for the command line \n\
             \"rustc --test <filename> -o <filestem>test~ && \
-            ./<filestem>test~\"\n\nUsage:\trust test <filename>"
+            ./<filestem>test~ [<arguments>...]\"\
+            \n\nUsage:\trust test <filename> [<arguments>...]"
         )
     },
-    Command{
+    Command {
         cmd: "doc",
         action: CallMain("rustdoc", rustdoc::main_args),
         usage_line: "generate documentation from doc comments",
         usage_full: UsgCall(rustdoc::config::usage),
     },
-    Command{
+    Command {
         cmd: "pkg",
         action: CallMain("rustpkg", rustpkg::main_args),
         usage_line: "download, build, install rust packages",
         usage_full: UsgCall(rustpkg::usage::general),
     },
-    Command{
+    Command {
         cmd: "sketch",
         action: CallMain("rusti", rusti::main_args),
         usage_line: "run a rust interpreter",
         usage_full: UsgStr("\nUsage:\trusti"),
     },
-    Command{
+    Command {
         cmd: "help",
         action: Call(cmd_help),
         usage_line: "show detailed usage of a command",
@@ -161,12 +156,12 @@ fn print_usage(command_string: ~str) -> ValidUsage {
 
 fn cmd_test(args: &[~str]) -> ValidUsage {
     match args {
-        [ref filename] => {
+        [ref filename, ..prog_args] => {
             let p = Path(*filename);
             let test_exec = p.filestem().unwrap() + "test~";
             invoke("rustc", &[~"--test", filename.to_owned(),
                               ~"-o", test_exec.to_owned()], rustc::main_args);
-            let exit_code = run::process_status(~"./" + test_exec, []);
+            let exit_code = run::process_status(~"./" + test_exec, prog_args);
             Valid(exit_code)
         }
         _ => Invalid
index 0fd93d65b70b8dcdfc15d459288341ca853ed478..5078d0ded18d129e225bf7d56ccf3031634d38e1 100644 (file)
@@ -681,9 +681,9 @@ fn set_llvm_debug() {
             link::output_type_bitcode
         } else { link::output_type_exe };
     let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
-    let target = getopts::opt_maybe_str(matches, "target").unwrap_or_default(host_triple());
-    let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or_default(~"generic");
-    let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or_default(~"");
+    let target = getopts::opt_maybe_str(matches, "target").unwrap_or(host_triple());
+    let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or(~"generic");
+    let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or(~"");
     let save_temps = getopts::opt_present(matches, "save-temps");
     let opt_level = {
         if (debugging_opts & session::no_opt) != 0 {
@@ -961,7 +961,7 @@ pub fn build_output_filenames(input: &input,
           if !linkage_metas.is_empty() {
               // But if a linkage meta is present, that overrides
               let maybe_name = linkage_metas.iter().find(|m| "name" == m.name());
-              match maybe_name.chain(|m| m.value_str()) {
+              match maybe_name.and_then(|m| m.value_str()) {
                   Some(s) => stem = s,
                   _ => ()
               }
index 2a5c3ae0f4f0519f99c462dfe82f6865f9a5086d..2c0068729a72e1ada4c46f16cee9587d56e59158 100644 (file)
@@ -58,7 +58,7 @@ fn filter_view_item<'r>(cx: @Context, view_item: &'r ast::view_item)-> Option<&'
 
 fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
     let filtered_items = do  m.items.iter().filter_map |a| {
-        filter_item(cx, *a).chain(|x| fld.fold_item(x))
+        filter_item(cx, *a).and_then(|x| fld.fold_item(x))
     }.collect();
     let filtered_view_items = do m.view_items.iter().filter_map |a| {
         do filter_view_item(cx, a).map_move |x| {
@@ -139,7 +139,7 @@ fn fold_block(
     fld: @fold::ast_fold
 ) -> ast::Block {
     let resulting_stmts = do b.stmts.iter().filter_map |a| {
-        filter_stmt(cx, *a).chain(|stmt| fld.fold_stmt(stmt))
+        filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt))
     }.collect();
     let filtered_view_items = do b.view_items.iter().filter_map |a| {
         filter_view_item(cx, a).map(|x| fld.fold_view_item(*x))
index 34c0dbb178872f27ca63b0317270be01ce23a719..beadcf3a19df8282bb06091ddf4f56c730703dab 100644 (file)
@@ -2109,6 +2109,17 @@ pub fn LLVMDIBuilderCreateComplexVariable(Builder: DIBuilderRef,
             ArgNo: c_uint)
             -> ValueRef;
 
+        #[fast_ffi]
+        pub fn LLVMDIBuilderCreateNameSpace(Builder: DIBuilderRef,
+                                            Scope: ValueRef,
+                                            Name: *c_char,
+                                            File: ValueRef,
+                                            LineNo: c_uint)
+                                            -> ValueRef;
+
+        #[fast_ffi]
+        pub fn LLVMDICompositeTypeSetTypeArray(CompositeType: ValueRef, TypeArray: ValueRef);
+
         #[fast_ffi]
         pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef;
 
index c463bd9bc033839da26dbdb77d4ffbc197bb716b..3b563e47426a3ce299763874430e05669a57331c 100644 (file)
@@ -184,7 +184,7 @@ fn visit_item(e: &Env, i: @ast::item) {
             ast::named => {
                 let link_name = i.attrs.iter()
                     .find(|at| "link_name" == at.name())
-                    .chain(|at| at.value_str());
+                    .and_then(|at| at.value_str());
 
                 let foreign_name = match link_name {
                         Some(nn) => {
index 18446acfef6b36d737a488f008b3aad6f6924def..c94151095a442fafbe916130de919ab95a2db5d7 100644 (file)
@@ -115,7 +115,8 @@ enum Family {
     Mod,                   // m
     ForeignMod,            // n
     Enum,                  // t
-    Variant,               // v
+    TupleVariant,          // v
+    StructVariant,         // V
     Impl,                  // i
     Trait,                 // I
     Struct,                // S
@@ -139,7 +140,8 @@ fn item_family(item: ebml::Doc) -> Family {
       'm' => Mod,
       'n' => ForeignMod,
       't' => Enum,
-      'v' => Variant,
+      'v' => TupleVariant,
+      'V' => StructVariant,
       'i' => Impl,
       'I' => Trait,
       'S' => Struct,
@@ -208,7 +210,7 @@ fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) -> bool {
 }
 
 fn variant_disr_val(d: ebml::Doc) -> Option<ty::Disr> {
-    do reader::maybe_get_doc(d, tag_disr_val).chain |val_doc| {
+    do reader::maybe_get_doc(d, tag_disr_val).and_then |val_doc| {
         do reader::with_doc_data(val_doc) |data| { u64::parse_bytes(data, 10u) }
     }
 }
@@ -361,9 +363,13 @@ fn item_to_def_like(item: ebml::Doc, did: ast::DefId, cnum: ast::CrateNum)
         Type | ForeignType => DlDef(ast::DefTy(did)),
         Mod => DlDef(ast::DefMod(did)),
         ForeignMod => DlDef(ast::DefForeignMod(did)),
-        Variant => {
+        StructVariant => {
             let enum_did = item_reqd_and_translated_parent_item(cnum, item);
-            DlDef(ast::DefVariant(enum_did, did))
+            DlDef(ast::DefVariant(enum_did, did, true))
+        }
+        TupleVariant => {
+            let enum_did = item_reqd_and_translated_parent_item(cnum, item);
+            DlDef(ast::DefVariant(enum_did, did, false))
         }
         Trait => DlDef(ast::DefTrait(did)),
         Enum => DlDef(ast::DefTy(did)),
@@ -575,8 +581,8 @@ fn process_item_and_pop_name(&mut self,
                 }
                 ImmStatic | MutStatic | Struct | UnsafeFn | Fn | ForeignFn |
                 UnsafeStaticMethod | StaticMethod | Type | ForeignType |
-                Variant | Enum | PublicField | PrivateField |
-                InheritedField => {}
+                TupleVariant | StructVariant | Enum | PublicField |
+                PrivateField | InheritedField => {}
             }
         }
 
@@ -1196,10 +1202,11 @@ pub fn get_struct_fields(intr: @ident_interner, cdata: Cmd, id: ast::NodeId)
     do reader::tagged_docs(item, tag_item_field) |an_item| {
         let f = item_family(an_item);
         if f == PublicField || f == PrivateField || f == InheritedField {
+            // FIXME #6993: name should be of type Name, not Ident
             let name = item_name(intr, an_item);
             let did = item_def_id(an_item, cdata);
             result.push(ty::field_ty {
-                ident: name,
+                name: name.name,
                 id: did, vis:
                 struct_field_family_to_visibility(f),
             });
@@ -1209,7 +1216,7 @@ pub fn get_struct_fields(intr: @ident_interner, cdata: Cmd, id: ast::NodeId)
     do reader::tagged_docs(item, tag_item_unnamed_field) |an_item| {
         let did = item_def_id(an_item, cdata);
         result.push(ty::field_ty {
-            ident: special_idents::unnamed_field,
+            name: special_idents::unnamed_field.name,
             id: did,
             vis: ast::inherited,
         });
@@ -1268,7 +1275,8 @@ fn item_family_to_str(fam: Family) -> ~str {
       Mod => ~"mod",
       ForeignMod => ~"foreign mod",
       Enum => ~"enum",
-      Variant => ~"variant",
+      StructVariant => ~"struct variant",
+      TupleVariant => ~"tuple variant",
       Impl => ~"impl",
       Trait => ~"trait",
       Struct => ~"struct",
index d1eb959055b331cca3a9b1abde3b11d2c4e41de6..98c7a7a126eb0fd223c9093188484611e6c6f0c6 100644 (file)
@@ -307,6 +307,27 @@ fn encode_parent_item(ebml_w: &mut writer::Encoder, id: DefId) {
     ebml_w.end_tag();
 }
 
+fn encode_struct_fields(ecx: &EncodeContext,
+                             ebml_w: &mut writer::Encoder,
+                             def: @struct_def) {
+    for f in def.fields.iter() {
+        match f.node.kind {
+            named_field(ident, vis) => {
+               ebml_w.start_tag(tag_item_field);
+               encode_struct_field_family(ebml_w, vis);
+               encode_name(ecx, ebml_w, ident);
+               encode_def_id(ebml_w, local_def(f.node.id));
+               ebml_w.end_tag();
+            }
+            unnamed_field => {
+                ebml_w.start_tag(tag_item_unnamed_field);
+                encode_def_id(ebml_w, local_def(f.node.id));
+                ebml_w.end_tag();
+            }
+        }
+    }
+}
+
 fn encode_enum_variant_info(ecx: &EncodeContext,
                             ebml_w: &mut writer::Encoder,
                             id: NodeId,
@@ -326,7 +347,10 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
                           pos: ebml_w.writer.tell()});
         ebml_w.start_tag(tag_items_data_item);
         encode_def_id(ebml_w, def_id);
-        encode_family(ebml_w, 'v');
+        match variant.node.kind {
+            ast::tuple_variant_kind(_) => encode_family(ebml_w, 'v'),
+            ast::struct_variant_kind(_) => encode_family(ebml_w, 'V')
+        }
         encode_name(ecx, ebml_w, variant.node.name);
         encode_parent_item(ebml_w, local_def(id));
         encode_visibility(ebml_w, variant.node.vis);
@@ -336,7 +360,14 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
                     if args.len() > 0 && generics.ty_params.len() == 0 => {
                 encode_symbol(ecx, ebml_w, variant.node.id);
             }
-            ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => {}
+            ast::tuple_variant_kind(_) => {},
+            ast::struct_variant_kind(def) => {
+                let idx = encode_info_for_struct(ecx, ebml_w, path,
+                                         def.fields, index);
+                encode_struct_fields(ecx, ebml_w, def);
+                let bkts = create_index(idx);
+                encode_index(ebml_w, bkts, write_i64);
+            }
         }
         if vi[i].disr_val != disr_val {
             encode_disr_val(ecx, ebml_w, vi[i].disr_val);
@@ -986,22 +1017,7 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
         /* Encode def_ids for each field and method
          for methods, write all the stuff get_trait_method
         needs to know*/
-        for f in struct_def.fields.iter() {
-            match f.node.kind {
-                named_field(ident, vis) => {
-                   ebml_w.start_tag(tag_item_field);
-                   encode_struct_field_family(ebml_w, vis);
-                   encode_name(ecx, ebml_w, ident);
-                   encode_def_id(ebml_w, local_def(f.node.id));
-                   ebml_w.end_tag();
-                }
-                unnamed_field => {
-                    ebml_w.start_tag(tag_item_unnamed_field);
-                    encode_def_id(ebml_w, local_def(f.node.id));
-                    ebml_w.end_tag();
-                }
-            }
-        }
+        encode_struct_fields(ecx, ebml_w, struct_def);
 
         // Encode inherent implementations for this structure.
         encode_inherent_implementations(ecx, ebml_w, def_id);
index 757c53354a24f20f1d05d9e9475f60e0a80115ae..892217988c7cb592a3139ec275c2b199377a3c20 100644 (file)
@@ -77,15 +77,15 @@ fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch) {
             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()));
+                    let tlib_path = make_rustpkg_target_lib_path(path, self.target_triple);
+                    debug!("is %s in visited_dirs? %?", tlib_path.to_str(),
+                            visited_dirs.contains(&tlib_path.to_str()));
 
-                    if !visited_dirs.contains(&path.push("lib").to_str()) {
-                        visited_dirs.insert(path.push("lib").to_str());
+                    if !visited_dirs.contains(&tlib_path.to_str()) {
+                        visited_dirs.insert(tlib_path.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")) {
+                        match f(&tlib_path) {
                            FileMatches => {
                                break;
                            }
@@ -145,6 +145,11 @@ fn make_target_lib_path(sysroot: &Path,
     sysroot.push_rel(&relative_target_lib_path(target_triple))
 }
 
+fn make_rustpkg_target_lib_path(dir: &Path,
+                        target_triple: &str) -> Path {
+    dir.push_rel(&Path(libdir()).push(target_triple.to_owned()))
+}
+
 fn get_or_default_sysroot() -> Path {
     match os::self_exe_path() {
       option::Some(ref p) => (*p).pop(),
index b6ccda5e1d1cab9a100df6725f9ba3f83f95ea13..bcc333afeec2056d45f868a26e581aaca03b7120 100644 (file)
@@ -396,8 +396,8 @@ fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::Def {
           ast::DefStatic(did, m) => { ast::DefStatic(did.tr(xcx), m) }
           ast::DefArg(nid, b) => { ast::DefArg(xcx.tr_id(nid), b) }
           ast::DefLocal(nid, b) => { ast::DefLocal(xcx.tr_id(nid), b) }
-          ast::DefVariant(e_did, v_did) => {
-            ast::DefVariant(e_did.tr(xcx), v_did.tr(xcx))
+          ast::DefVariant(e_did, v_did, is_s) => {
+            ast::DefVariant(e_did.tr(xcx), v_did.tr(xcx), is_s)
           },
           ast::DefTrait(did) => ast::DefTrait(did.tr(xcx)),
           ast::DefTy(did) => ast::DefTy(did.tr(xcx)),
index 2642764867486d68cf99efa1772c64c5601be6fb..fe5925f26f0ac206507734f27f46353339bd3818 100644 (file)
@@ -149,7 +149,7 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
             match def_map.find(&e.id) {
               Some(&DefStatic(*)) |
               Some(&DefFn(_, _)) |
-              Some(&DefVariant(_, _)) |
+              Some(&DefVariant(_, _, _)) |
               Some(&DefStruct(_)) => { }
 
               Some(&def) => {
index 581e203ae9ad10d5daca0a197f3a46a3945a267f..2a38492a6e58626800a41bd765f0e380c509aa68 100644 (file)
@@ -335,7 +335,7 @@ pub fn pat_ctor_id(cx: &MatchCheckCtxt, p: @Pat) -> Option<ctor> {
       PatWild => { None }
       PatIdent(_, _, _) | PatEnum(_, _) => {
         match cx.tcx.def_map.find(&pat.id) {
-          Some(&DefVariant(_, id)) => Some(variant(id)),
+          Some(&DefVariant(_, id, _)) => Some(variant(id)),
           Some(&DefStatic(did, false)) => {
             let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
             Some(val(eval_const_expr(cx.tcx, const_expr)))
@@ -349,7 +349,7 @@ pub fn pat_ctor_id(cx: &MatchCheckCtxt, p: @Pat) -> Option<ctor> {
       }
       PatStruct(*) => {
         match cx.tcx.def_map.find(&pat.id) {
-          Some(&DefVariant(_, id)) => Some(variant(id)),
+          Some(&DefVariant(_, id, _)) => Some(variant(id)),
           _ => Some(single)
         }
       }
@@ -371,7 +371,7 @@ pub fn is_wild(cx: &MatchCheckCtxt, p: @Pat) -> bool {
       PatWild => { true }
       PatIdent(_, _, _) => {
         match cx.tcx.def_map.find(&pat.id) {
-          Some(&DefVariant(_, _)) | Some(&DefStatic(*)) => { false }
+          Some(&DefVariant(_, _, _)) | Some(&DefStatic(*)) => { false }
           _ => { true }
         }
       }
@@ -547,7 +547,7 @@ pub fn specialize(cx: &MatchCheckCtxt,
             }
             PatIdent(_, _, _) => {
                 match cx.tcx.def_map.find(&pat_id) {
-                    Some(&DefVariant(_, id)) => {
+                    Some(&DefVariant(_, id, _)) => {
                         if variant(id) == *ctor_id {
                             Some(r.tail().to_owned())
                         } else {
@@ -639,14 +639,14 @@ pub fn specialize(cx: &MatchCheckCtxt,
                             None
                         }
                     }
-                    DefVariant(_, id) if variant(id) == *ctor_id => {
+                    DefVariant(_, id, _) if variant(id) == *ctor_id => {
                         let args = match args {
                             Some(args) => args,
                             None => vec::from_elem(arity, wild())
                         };
                         Some(vec::append(args, r.tail()))
                     }
-                    DefVariant(_, _) => None,
+                    DefVariant(_, _, _) => None,
 
                     DefFn(*) |
                     DefStruct(*) => {
@@ -664,7 +664,7 @@ pub fn specialize(cx: &MatchCheckCtxt,
             PatStruct(_, ref flds, _) => {
                 // Is this a struct or an enum variant?
                 match cx.tcx.def_map.get_copy(&pat_id) {
-                    DefVariant(_, variant_id) => {
+                    DefVariant(_, variant_id, _) => {
                         if variant(variant_id) == *ctor_id {
                             // FIXME #4731: Is this right? --pcw
                             let args = flds.map(|ty_field| {
@@ -700,7 +700,7 @@ pub fn specialize(cx: &MatchCheckCtxt,
                         }
                         let args = class_fields.iter().map(|class_field| {
                             match flds.iter().find(|f|
-                                            f.ident == class_field.ident) {
+                                            f.ident.name == class_field.name) {
                                 Some(f) => f.pat,
                                 _ => wild()
                             }
@@ -835,7 +835,7 @@ pub fn check_fn(v: &mut CheckMatchVisitor,
 
 pub fn is_refutable(cx: &MatchCheckCtxt, pat: &Pat) -> bool {
     match cx.tcx.def_map.find(&pat.id) {
-      Some(&DefVariant(enum_id, _)) => {
+      Some(&DefVariant(enum_id, _, _)) => {
         if ty::enum_variants(cx.tcx, enum_id).len() != 1u {
             return true;
         }
index ad9a3b2f4e7c18ee7a2b5883d96b1fe23799defb..2e5e87f225a2acd700a2d95aa9dafa94bbf19d45 100644 (file)
@@ -168,7 +168,7 @@ pub fn classify(e: &Expr,
 pub fn lookup_const(tcx: ty::ctxt, e: &Expr) -> Option<@Expr> {
     match tcx.def_map.find(&e.id) {
         Some(&ast::DefStatic(def_id, false)) => lookup_const_by_id(tcx, def_id),
-        Some(&ast::DefVariant(enum_def, variant_def)) => lookup_variant_by_id(tcx,
+        Some(&ast::DefVariant(enum_def, variant_def, _)) => lookup_variant_by_id(tcx,
                                                                                enum_def,
                                                                                variant_def),
         _ => None
index 160b03132e06f96c55b6218f32ce04c1c1a8b982..9c02f544fbaeb11e41a0c2726da6a188c32df1d0 100644 (file)
@@ -102,8 +102,10 @@ fn visit_fn(&mut self, fn_kind:&fn_kind, fn_decl:&fn_decl,
     fn visit_block(&mut self, block:&Block, _:()) {
 
             let old_unsafe_context = self.context.unsafe_context;
-            if block.rules == ast::UnsafeBlock &&
-                    self.context.unsafe_context == SafeContext {
+            let is_unsafe = match block.rules {
+                ast::UnsafeBlock(*) => true, ast::DefaultBlock => false
+            };
+            if is_unsafe && self.context.unsafe_context == SafeContext {
                 self.context.unsafe_context = UnsafeBlock(block.id)
             }
 
index d3b94e9f7c6f9509faa455a06c9404b566dd0a58..6ca8086efc253095bd1d9e94eee63db9b5cef869 100644 (file)
@@ -416,7 +416,7 @@ fn is_nullary_variant(cx: Context, ex: @Expr) -> bool {
     match ex.node {
       ExprPath(_) => {
         match cx.tcx.def_map.get_copy(&ex.id) {
-          DefVariant(edid, vdid) => {
+          DefVariant(edid, vdid, _) => {
               ty::enum_variant_with_id(cx.tcx, edid, vdid).args.is_empty()
           }
           _ => false
index 6f4d94e2a647a1c74f6c3492a046fa363067aa19..da181ff2eb6b60a1e1718e65e9bfe8887129dd42 100644 (file)
@@ -1131,8 +1131,11 @@ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
     fn visit_expr(&mut self, e:@ast::Expr, cx:@mut Context) {
 
             match e.node {
-                ast::ExprBlock(ref blk) if blk.rules == ast::UnsafeBlock => {
-                    if !cx.tcx.used_unsafe.contains(&blk.id) {
+                // Don't warn about generated blocks, that'll just pollute the
+                // output.
+                ast::ExprBlock(ref blk) => {
+                    if blk.rules == ast::UnsafeBlock(ast::UserProvided) &&
+                       !cx.tcx.used_unsafe.contains(&blk.id) {
                         cx.span_lint(unused_unsafe, blk.span,
                                      "unnecessary `unsafe` block");
                     }
index b284cd967a75b74c317294c93dd5bd3b78f54b11..0e3c10ef21471c00fd990b6cb22aa2165c760e39 100644 (file)
@@ -889,7 +889,7 @@ pub fn cat_pattern(&self,
           }
           ast::PatEnum(_, Some(ref subpats)) => {
             match self.tcx.def_map.find(&pat.id) {
-                Some(&ast::DefVariant(enum_did, _)) => {
+                Some(&ast::DefVariant(enum_did, _, _)) => {
                     // variant(x, y, z)
 
                     let downcast_cmt = {
@@ -1059,6 +1059,7 @@ pub fn region_to_str(&self, r: ty::Region) -> ~str {
 /// an enum to determine which variant is in use.
 pub fn field_mutbl(tcx: ty::ctxt,
                    base_ty: ty::t,
+                   // FIXME #6993: change type to Name
                    f_name: ast::Ident,
                    node_id: ast::NodeId)
                 -> Option<ast::Mutability> {
@@ -1067,17 +1068,17 @@ pub fn field_mutbl(tcx: ty::ctxt,
       ty::ty_struct(did, _) => {
         let r = ty::lookup_struct_fields(tcx, did);
         for fld in r.iter() {
-            if fld.ident == f_name {
+            if fld.name == f_name.name {
                 return Some(ast::MutImmutable);
             }
         }
       }
       ty::ty_enum(*) => {
         match tcx.def_map.get_copy(&node_id) {
-          ast::DefVariant(_, variant_id) => {
+          ast::DefVariant(_, variant_id, _) => {
             let r = ty::lookup_struct_fields(tcx, variant_id);
             for fld in r.iter() {
-                if fld.ident == f_name {
+                if fld.name == f_name.name {
                     return Some(ast::MutImmutable);
                 }
             }
index d6f61c6328a0bbf883506b948b3b1d624742b0eb..51fe2acc72ad45b79bbd0a99d07b6da3635d3ee0 100644 (file)
@@ -203,10 +203,11 @@ fn local_item_is_private(&mut self, span: Span, item_id: NodeId) -> bool {
     }
 
     // Checks that a private field is in scope.
+    // FIXME #6993: change type (and name) from Ident to Name
     fn check_field(&mut self, span: Span, id: ast::DefId, ident: ast::Ident) {
         let fields = ty::lookup_struct_fields(self.tcx, id);
         for field in fields.iter() {
-            if field.ident.name != ident.name { loop; }
+            if field.name != ident.name { loop; }
             if field.vis == private {
                 self.tcx.sess.span_err(span, fmt!("field `%s` is private",
                                              token::ident_to_str(&ident)));
@@ -220,8 +221,7 @@ fn check_method_common(&mut self, span: Span, method_id: DefId, name: &Ident) {
         // If the method is a default method, we need to use the def_id of
         // the default implementation.
         // Having to do this this is really unfortunate.
-        let method_id = ty::method(self.tcx, method_id).provided_source
-            .unwrap_or_default(method_id);
+        let method_id = ty::method(self.tcx, method_id).provided_source.unwrap_or(method_id);
 
         if method_id.crate == LOCAL_CRATE {
             let is_private = self.method_is_private(span, method_id.node);
@@ -455,7 +455,7 @@ fn visit_expr<'mm>(&mut self, expr:@Expr, method_map:&'mm method_map) {
                             if id.crate != LOCAL_CRATE ||
                                     !self.privileged_items.iter().any(|x| x == &(id.node)) {
                                 match self.tcx.def_map.get_copy(&expr.id) {
-                                    DefVariant(_, variant_id) => {
+                                    DefVariant(_, variant_id, _) => {
                                         for field in (*fields).iter() {
                                                 debug!("(privacy checking) \
                                                         checking field in \
@@ -522,7 +522,7 @@ fn visit_pat<'mm>(&mut self, pattern:@Pat, method_map:&'mm method_map) {
                             if enum_id.crate != LOCAL_CRATE ||
                                     !self.privileged_items.iter().any(|x| x == &enum_id.node) {
                                 match self.tcx.def_map.find(&pattern.id) {
-                                    Some(&DefVariant(_, variant_id)) => {
+                                    Some(&DefVariant(_, variant_id, _)) => {
                                         for field in fields.iter() {
                                             debug!("(privacy checking) \
                                                     checking field in \
index 335ea06eda98f6a12880677ae6a1116a98a17b3e..3a9ef3cf06f037140ab434d516ab61a9f482b9d1 100644 (file)
@@ -1474,7 +1474,7 @@ pub fn build_reduced_graph_for_variant(@mut self,
                                                 variant.span);
                 child.define_value(privacy,
                                    DefVariant(item_id,
-                                               local_def(variant.node.id)),
+                                               local_def(variant.node.id), false),
                                    variant.span);
             }
             struct_variant_kind(_) => {
@@ -1482,7 +1482,7 @@ pub fn build_reduced_graph_for_variant(@mut self,
                                                 variant.span);
                 child.define_type(privacy,
                                   DefVariant(item_id,
-                                              local_def(variant.node.id)),
+                                              local_def(variant.node.id), true),
                                   variant.span);
                 self.structs.insert(local_def(variant.node.id));
             }
@@ -1690,14 +1690,20 @@ fn handle_external_def(@mut self,
 
         match def {
           DefMod(_) | DefForeignMod(_) => {}
-          DefVariant(*) => {
+          DefVariant(_, variant_id, is_struct) => {
             debug!("(building reduced graph for external crate) building \
                     variant %s",
                    final_ident);
             // We assume the parent is visible, or else we wouldn't have seen
             // it.
             let privacy = variant_visibility_to_privacy(visibility, true);
-            child_name_bindings.define_value(privacy, def, dummy_sp());
+            if is_struct {
+                child_name_bindings.define_type(privacy, def, dummy_sp());
+                self.structs.insert(variant_id);
+            }
+            else {
+                child_name_bindings.define_value(privacy, def, dummy_sp());
+            }
           }
           DefFn(*) | DefStaticMethod(*) | DefStatic(*) => {
             debug!("(building reduced graph for external \
@@ -4507,7 +4513,7 @@ struct or const `%s`",
                             assert!(self.structs.contains(&class_id));
                             self.record_def(pattern.id, definition);
                         }
-                        Some(definition @ DefVariant(_, variant_id))
+                        Some(definition @ DefVariant(_, variant_id, _))
                                 if self.structs.contains(&variant_id) => {
                             self.record_def(pattern.id, definition);
                         }
@@ -5123,7 +5129,7 @@ pub fn resolve_expr(@mut self, expr: @Expr, visitor: &mut ResolveVisitor) {
                         let class_def = DefStruct(class_id);
                         self.record_def(expr.id, class_def);
                     }
-                    Some(definition @ DefVariant(_, class_id))
+                    Some(definition @ DefVariant(_, class_id, _))
                             if self.structs.contains(&class_id) => {
                         self.record_def(expr.id, definition);
                     }
index 569c6dfde0cab7c3c97374ea46fbedf85b1cdd24..7ab6cfcdf7bf5ec86a6675ee9e1f3856f45faa84 100644 (file)
@@ -80,6 +80,18 @@ fn stack_check_item(v: StackCheckVisitor,
                 visit::walk_method_helper(&mut v, method, new_cx);
             }
         }
+        ast::item_trait(_, _, ref methods) => {
+            for method in methods.iter() {
+                match *method {
+                    ast::provided(@ref method) => {
+                        let safe_stack = fixed_stack_segment(method.attrs);
+                        let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+                        visit::walk_method_helper(&mut v, method, new_cx);
+                    }
+                    ast::required(*) => ()
+                }
+            }
+        }
         _ => {
             visit::walk_item(&mut v, item, in_cx);
         }
index d54a079a2bfeb2f7a42b71179b4407c408faf2ef..62fbdc41b0e7046f34187a15e71b725ce7fd1d2d 100644 (file)
@@ -347,7 +347,7 @@ fn variant_opt(bcx: @mut Block, pat_id: ast::NodeId)
     -> Opt {
     let ccx = bcx.ccx();
     match ccx.tcx.def_map.get_copy(&pat_id) {
-        ast::DefVariant(enum_id, var_id) => {
+        ast::DefVariant(enum_id, var_id, _) => {
             let variants = ty::enum_variants(ccx.tcx, enum_id);
             for v in (*variants).iter() {
                 if var_id == v.id {
@@ -657,7 +657,7 @@ fn enter_opt<'r>(bcx: @mut Block,
                     // Look up the struct variant ID.
                     let struct_id;
                     match tcx.def_map.get_copy(&p.id) {
-                        ast::DefVariant(_, found_struct_id) => {
+                        ast::DefVariant(_, found_struct_id, _) => {
                             struct_id = found_struct_id;
                         }
                         _ => {
@@ -672,7 +672,7 @@ fn enter_opt<'r>(bcx: @mut Block,
                     let r = ty::lookup_struct_fields(tcx, struct_id);
                     for field in r.iter() {
                             match field_pats.iter().find(|p| p.ident.name
-                                                         == field.ident.name) {
+                                                         == field.name) {
                                 None => reordered_patterns.push(dummy),
                                 Some(fp) => reordered_patterns.push(fp.pat)
                             }
@@ -2113,7 +2113,7 @@ fn bind_irrefutable_pat(bcx: @mut Block,
         }
         ast::PatEnum(_, ref sub_pats) => {
             match bcx.tcx().def_map.find(&pat.id) {
-                Some(&ast::DefVariant(enum_id, var_id)) => {
+                Some(&ast::DefVariant(enum_id, var_id, _)) => {
                     let repr = adt::represent_node(bcx, pat.id);
                     let vinfo = ty::enum_variant_with_id(ccx.tcx,
                                                          enum_id,
index cb05b8bb7eb22b955865133bed3c0b9551f7f711..4d1ea783c3971025fed13861fdacd1b87644a800 100644 (file)
@@ -87,6 +87,7 @@
 use syntax::print::pprust::stmt_to_str;
 use syntax::{ast, ast_util, codemap, ast_map};
 use syntax::abi::{X86, X86_64, Arm, Mips};
+use syntax::visit;
 use syntax::visit::Visitor;
 
 pub use middle::trans::context::task_llcx;
@@ -824,7 +825,8 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t)
     };
 }
 
-pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef])
+pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
+              attributes: &[(uint, lib::llvm::Attribute)])
            -> (ValueRef, @mut Block) {
     let _icx = push_ctxt("invoke_");
     if bcx.unreachable {
@@ -864,7 +866,7 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef])
                 debug!("arg: %x", ::std::cast::transmute(llarg));
             }
         }
-        let llresult = Call(bcx, llfn, llargs);
+        let llresult = Call(bcx, llfn, llargs, attributes);
         return (llresult, bcx);
     }
 }
@@ -975,7 +977,7 @@ pub fn get_landing_pad(bcx: @mut Block) -> BasicBlockRef {
     // Because we may have unwound across a stack boundary, we must call into
     // the runtime to figure out which stack segment we are on and place the
     // stack limit back into the TLS.
-    Call(pad_bcx, bcx.ccx().upcalls.reset_stack_limit, []);
+    Call(pad_bcx, bcx.ccx().upcalls.reset_stack_limit, [], []);
 
     // We store the retval in a function-central alloca, so that calls to
     // Resume can find it.
@@ -1070,7 +1072,7 @@ pub fn trans_trace(bcx: @mut Block, sp_opt: Option<Span>, trace_str: @str) {
     let V_trace_str = PointerCast(bcx, V_trace_str, Type::i8p());
     let V_filename = PointerCast(bcx, V_filename, Type::i8p());
     let args = ~[V_trace_str, V_filename, C_int(ccx, V_line)];
-    Call(bcx, ccx.upcalls.trace, args);
+    Call(bcx, ccx.upcalls.trace, args, []);
 }
 
 pub fn ignore_lhs(_bcx: @mut Block, local: &ast::Local) -> bool {
@@ -1464,7 +1466,7 @@ pub fn call_memcpy(cx: @mut Block, dst: ValueRef, src: ValueRef, n_bytes: ValueR
     let size = IntCast(cx, n_bytes, ccx.int_type);
     let align = C_i32(align as i32);
     let volatile = C_i1(false);
-    Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile]);
+    Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile], []);
 }
 
 pub fn memcpy_ty(bcx: @mut Block, dst: ValueRef, src: ValueRef, t: ty::t) {
@@ -1509,7 +1511,7 @@ pub fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
     let size = machine::llsize_of(ccx, ty);
     let align = C_i32(llalign_of_min(ccx, ty) as i32);
     let volatile = C_i1(false);
-    b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
+    b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], []);
 }
 
 pub fn alloc_ty(bcx: @mut Block, t: ty::t, name: &str) -> ValueRef {
@@ -2239,6 +2241,14 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
             trans_struct_def(ccx, struct_def);
         }
       }
+      ast::item_trait(*) => {
+        // Inside of this trait definition, we won't be actually translating any
+        // functions, but the trait still needs to be walked. Otherwise default
+        // methods with items will not get translated and will cause ICE's when
+        // metadata time comes around.
+        let mut v = TransItemVisitor;
+        visit::walk_item(&mut v, item, ccx);
+      }
       _ => {/* fall through */ }
     }
 }
@@ -2344,7 +2354,7 @@ fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
             llvm::LLVMGetParam(llfdecl, env_arg as c_uint)
         };
         let args = ~[llenvarg];
-        Call(bcx, main_llfn, args);
+        Call(bcx, main_llfn, args, []);
 
         finish_fn(fcx, bcx);
         return llfdecl;
@@ -2799,7 +2809,7 @@ pub fn declare_dbg_intrinsics(llmod: ModuleRef, intrinsics: &mut HashMap<&'stati
 
 pub fn trap(bcx: @mut Block) {
     match bcx.ccx().intrinsics.find_equiv(& &"llvm.trap") {
-      Some(&x) => { Call(bcx, x, []); },
+      Some(&x) => { Call(bcx, x, [], []); },
       _ => bcx.sess().bug("unbound llvm.trap in trap")
     }
 }
@@ -3021,6 +3031,10 @@ pub fn trans_crate(sess: session::Session,
                                      link_meta,
                                      analysis.reachable);
 
+    if ccx.sess.opts.debuginfo {
+        debuginfo::initialize(ccx, crate);
+    }
+
     {
         let _icx = push_ctxt("text");
         trans_mod(ccx, &crate.module);
index acec33f7004b3046e88f0dda6c404205e18e8e3a..aabb389dde114b13d6fe22552a2e2e75d557c52f 100644 (file)
@@ -644,20 +644,16 @@ pub fn InlineAsmCall(cx: @mut Block, asm: *c_char, cons: *c_char,
     B(cx).inline_asm_call(asm, cons, inputs, output, volatile, alignstack, dia)
 }
 
-pub fn Call(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
+pub fn Call(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
+            attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
     if cx.unreachable { return _UndefReturn(cx, Fn); }
-    B(cx).call(Fn, Args)
+    B(cx).call(Fn, Args, attributes)
 }
 
-pub fn FastCall(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
+pub fn CallWithConv(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef], Conv: CallConv,
+                    attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
     if cx.unreachable { return _UndefReturn(cx, Fn); }
-    B(cx).call(Fn, Args)
-}
-
-pub fn CallWithConv(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
-                    Conv: CallConv) -> ValueRef {
-    if cx.unreachable { return _UndefReturn(cx, Fn); }
-    B(cx).call_with_conv(Fn, Args, Conv)
+    B(cx).call_with_conv(Fn, Args, Conv, attributes)
 }
 
 pub fn AtomicFence(cx: @mut Block, order: AtomicOrdering) {
index 6a1acf68efa534aec0f223ae0e9401de6d7a5502..85e45942b7981d7cfe4e62ac36f2f4b594106151 100644 (file)
@@ -747,7 +747,7 @@ pub fn add_comment(&self, text: &str) {
                                              c, noname(), False, False)
                 }
             };
-            self.call(asm, []);
+            self.call(asm, [], []);
         }
     }
 
@@ -772,43 +772,29 @@ pub fn inline_asm_call(&self, asm: *c_char, cons: *c_char,
         unsafe {
             let v = llvm::LLVMInlineAsm(
                 fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint);
-            self.call(v, inputs)
+            self.call(v, inputs, [])
         }
     }
 
-    pub fn call(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
+    pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
+                attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
         self.count_insn("call");
-
-        debug!("Call(llfn=%s, args=%?)",
-               self.ccx.tn.val_to_str(llfn),
-               args.map(|arg| self.ccx.tn.val_to_str(*arg)));
-
-        do args.as_imm_buf |ptr, len| {
-            unsafe {
-            llvm::LLVMBuildCall(self.llbuilder, llfn, ptr, len as c_uint, noname())
-            }
-        }
-    }
-
-    pub fn fastcall(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
-        self.count_insn("fastcall");
         unsafe {
             let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
                                         args.len() as c_uint, noname());
-            lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
+            for &(idx, attr) in attributes.iter() {
+                llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+            }
             v
         }
     }
 
     pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
-                        conv: CallConv) -> ValueRef {
+                          conv: CallConv, attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
         self.count_insn("callwithconv");
-        unsafe {
-            let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
-                                        args.len() as c_uint, noname());
-            lib::llvm::SetInstructionCallConv(v, conv);
-            v
-        }
+        let v = self.call(llfn, args, attributes);
+        lib::llvm::SetInstructionCallConv(v, conv);
+        v
     }
 
     pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef {
index 14be9bc2873c39f4772dd85640eb11322b0bca81..45da026afd06ac5d1df8bd7e9ec78102f6e5973d 100644 (file)
@@ -128,7 +128,7 @@ fn trans_def(bcx: @mut Block, def: ast::Def, ref_expr: @ast::Expr) -> Callee {
                                                                 trait_did,
                                                                 ref_expr.id))
             }
-            ast::DefVariant(tid, vid) => {
+            ast::DefVariant(tid, vid, _) => {
                 // nullary variants are not callable
                 assert!(ty::enum_variant_with_id(bcx.tcx(),
                                                       tid,
@@ -707,7 +707,7 @@ pub fn trans_call_inner(in_cx: @mut Block,
             }
 
             // Invoke the actual rust fn and update bcx/llresult.
-            let (llret, b) = base::invoke(bcx, llfn, llargs);
+            let (llret, b) = base::invoke(bcx, llfn, llargs, []);
             bcx = b;
             llresult = llret;
 
index 242b15fe5f0dc1b9c8cccc74eb87270204be31ab..b75b06f42b64986fec003a549512b26b1a65d976 100644 (file)
@@ -505,7 +505,7 @@ fn info(&self) -> Option<NodeInfo> {
 
 impl get_node_info for Option<@ast::Expr> {
     fn info(&self) -> Option<NodeInfo> {
-        self.chain_ref(|s| s.info())
+        self.and_then_ref(|s| s.info())
     }
 }
 
index 94f0b3735700101ab3a7066975ece2290edca1c3..78d2228ff041c4d8550140c1335957d808df4a88 100644 (file)
@@ -577,7 +577,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 Some(&ast::DefStatic(def_id, false)) => {
                     get_const_val(cx, def_id)
                 }
-                Some(&ast::DefVariant(enum_did, variant_did)) => {
+                Some(&ast::DefVariant(enum_did, variant_did, _)) => {
                     let ety = ty::expr_ty(cx.tcx, e);
                     let repr = adt::represent_type(cx, ety);
                     let vinfo = ty::enum_variant_with_id(cx.tcx,
@@ -604,7 +604,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                       let arg_vals = args.map(|a| const_expr(cx, *a));
                       adt::trans_const(cx, repr, 0, arg_vals)
                   }
-                  Some(&ast::DefVariant(enum_did, variant_did)) => {
+                  Some(&ast::DefVariant(enum_did, variant_did, _)) => {
                       let ety = ty::expr_ty(cx.tcx, e);
                       let repr = adt::represent_type(cx, ety);
                       let vinfo = ty::enum_variant_with_id(cx.tcx,
index 70630e3ee49b226b37a3494a323fa09aa815e417..272ce49a3779afaf4be0d3bc7b3a81c65cbc2b00 100644 (file)
 2. Module-internal metadata creation functions
 3. Minor utility functions
 
+
+## Recursive Types
+Some kinds of types, such as structs and enums can be recursive. That means that the type definition
+of some type X refers to some other type which in turn (transitively) refers to X. This introduces
+cycles into the type referral graph. A naive algorithm doing an on-demand, depth-first traversal of
+this graph when describing types, can get trapped in an endless loop when it reaches such a cycle.
+
+For example, the following simple type for a singly-linked list...
+
+```
+struct List {
+    value: int,
+    tail: Option<@List>,
+}
+```
+
+will generate the following callstack with a naive DFS algorithm:
+
+```
+describe(t = List)
+  describe(t = int)
+  describe(t = Option<@List>)
+    describe(t = @List)
+      describe(t = List) // at the beginning again...
+      ...
+```
+
+To break cycles like these, we use "forward declarations". That is, when the algorithm encounters a
+possibly recursive type (any struct or enum), it immediately creates a type description node and
+inserts it into the cache *before* describing the members of the type. This type description is just
+a stub (as type members are not described and added to it yet) but it allows the algorithm to
+already refer to the type. After the stub is inserted into the cache, the algorithm continues as
+before. If it now encounters a recursive reference, it will hit the cache and does not try to
+describe the type anew.
+
+This behaviour is encapsulated in the 'RecursiveTypeDescription' enum, which represents a kind of
+continuation, storing all state needed to continue traversal at the type members after the type has
+been registered with the cache. (This implementation approach might be a tad over-engineered and
+may change in the future)
+
 */
 
 
 use middle::trans;
 use middle::ty;
 use middle::pat_util;
-use util::ppaux::ty_to_str;
+use util::ppaux;
 
 use std::c_str::ToCStr;
 use std::hashmap::HashMap;
 use std::ptr;
 use std::vec;
 use syntax::codemap::Span;
-use syntax::{ast, codemap, ast_util, ast_map, opt_vec};
+use syntax::{ast, codemap, ast_util, ast_map, opt_vec, visit};
 use syntax::parse::token;
 use syntax::parse::token::special_idents;
 
 static DW_ATE_unsigned: c_uint = 0x07;
 static DW_ATE_unsigned_char: c_uint = 0x08;
 
-
-
-
 //=-------------------------------------------------------------------------------------------------
 //  Public Interface of debuginfo module
 //=-------------------------------------------------------------------------------------------------
@@ -96,9 +133,11 @@ pub struct CrateDebugContext {
     priv crate_file: ~str,
     priv llcontext: ContextRef,
     priv builder: DIBuilderRef,
-    priv curr_loc: DebugLocation,
+    priv current_debug_location: DebugLocation,
     priv created_files: HashMap<~str, DIFile>,
     priv created_types: HashMap<uint, DIType>,
+    priv local_namespace_map: HashMap<ast::NodeId, @NamespaceTreeNode>,
+    priv extern_namespaces: HashMap<~[ast::Ident], @NamespaceTreeNode>,
 }
 
 impl CrateDebugContext {
@@ -111,9 +150,11 @@ pub fn new(llmod: ModuleRef, crate: ~str) -> CrateDebugContext {
             crate_file: crate,
             llcontext: llcontext,
             builder: builder,
-            curr_loc: UnknownLocation,
+            current_debug_location: UnknownLocation,
             created_files: HashMap::new(),
             created_types: HashMap::new(),
+            local_namespace_map: HashMap::new(),
+            extern_namespaces: HashMap::new(),
         };
     }
 }
@@ -129,12 +170,10 @@ fn get_ref<'a>(&'a self, cx: &CrateContext, span: Span) -> &'a FunctionDebugCont
         match *self {
             FunctionDebugContext(~ref data) => data,
             DebugInfoDisabled => {
-                cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
-                                        although debug info is disabled!");
+                cx.sess.span_bug(span, FunctionDebugContext::debuginfo_disabled_message());
             }
             FunctionWithoutDebugInfo => {
-                cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
-                                        for function that should be ignored by debug info!");
+                cx.sess.span_bug(span, FunctionDebugContext::should_be_ignored_message());
             }
         }
     }
@@ -146,15 +185,22 @@ fn get_mut_ref<'a>(&'a mut self,
         match *self {
             FunctionDebugContext(~ref mut data) => data,
             DebugInfoDisabled => {
-                cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
-                                        although debug info is disabled!");
+                cx.sess.span_bug(span, FunctionDebugContext::debuginfo_disabled_message());
             }
             FunctionWithoutDebugInfo => {
-                cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
-                                        for function that should be ignored by debug info!");
+                cx.sess.span_bug(span, FunctionDebugContext::should_be_ignored_message());
             }
         }
     }
+
+    fn debuginfo_disabled_message() -> &'static str {
+        "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
+    }
+
+    fn should_be_ignored_message() -> &'static str {
+        "debuginfo: Error trying to access FunctionDebugContext for function that should be \
+         ignored by debug info!"
+    }
 }
 
 struct FunctionDebugContextData {
@@ -178,8 +224,22 @@ enum VariableKind {
     CapturedVariable,
 }
 
+pub fn initialize(cx: &mut CrateContext, crate: &ast::Crate) {
+    if cx.dbg_cx.is_none() {
+        return;
+    }
+
+    let crate_namespace_ident = token::str_to_ident(cx.link_meta.name);
+    let mut visitor = NamespaceVisitor::new_crate_visitor(cx, crate_namespace_ident);
+    visit::walk_crate(&mut visitor, crate, ());
+}
+
 /// Create any deferred debug metadata nodes
 pub fn finalize(cx: @mut CrateContext) {
+    if cx.dbg_cx.is_none() {
+        return;
+    }
+
     debug!("finalize");
     compile_unit_metadata(cx);
     unsafe {
@@ -490,7 +550,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
         ast_map::node_item(ref item, _) => {
             match item.node {
                 ast::item_fn(ref fn_decl, _, _, ref generics, ref top_level_block) => {
-                    (item.ident, fn_decl, generics, Some(top_level_block), item.span)
+                    (item.ident, fn_decl, generics, top_level_block, item.span)
                 }
                 _ => {
                     cx.sess.span_bug(item.span,
@@ -509,7 +569,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
             },
             _,
             _) => {
-            (ident, fn_decl, generics, Some(top_level_block), span)
+            (ident, fn_decl, generics, top_level_block, span)
         }
         ast_map::node_expr(ref expr) => {
             match expr.node {
@@ -520,7 +580,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
                         // This is not quite right. It should actually inherit the generics of the
                         // enclosing function.
                         &empty_generics,
-                        Some(top_level_block),
+                        top_level_block,
                         expr.span)
                 }
                 _ => cx.sess.span_bug(expr.span,
@@ -539,20 +599,10 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
                 }),
             _,
             _) => {
-            (ident, fn_decl, generics, Some(top_level_block), span)
-        }
-        ast_map::node_foreign_item(@ast::foreign_item {
-                ident: ident,
-                node: ast::foreign_item_fn(ref fn_decl, ref generics),
-                span: span,
-                _
-            },
-            _,
-            _,
-            _) => {
-            (ident, fn_decl, generics, None, span)
+            (ident, fn_decl, generics, top_level_block, span)
         }
-        ast_map::node_variant(*)     |
+        ast_map::node_foreign_item(@ast::foreign_item { _ }, _, _, _) |
+        ast_map::node_variant(*) |
         ast_map::node_struct_ctor(*) => {
             return FunctionWithoutDebugInfo;
         }
@@ -568,27 +618,42 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
     let file_metadata = file_metadata(cx, loc.file.name);
 
     let function_type_metadata = unsafe {
-        let fn_signature = get_function_signature(cx, fn_ast_id, fn_decl, param_substs);
+        let fn_signature = get_function_signature(cx, fn_ast_id, fn_decl, param_substs, span);
         llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
     };
 
     // get_template_parameters() will append a `<...>` clause to the function name if necessary.
-    let mut function_name = cx.sess.str_of(ident).to_owned();
-    let template_parameters = if cx.sess.opts.extra_debuginfo {
-        get_template_parameters(cx, generics, param_substs, file_metadata, &mut function_name)
-    } else {
-        ptr::null()
+    let mut function_name = token::ident_to_str(&ident).to_owned();
+    let template_parameters = get_template_parameters(cx,
+                                                      generics,
+                                                      param_substs,
+                                                      file_metadata,
+                                                      &mut function_name);
+
+    let namespace_node = debug_context(cx).local_namespace_map.find_copy(&fn_ast_id);
+    let (linkage_name, containing_scope) = match namespace_node {
+        Some(namespace_node) => {
+            (namespace_node.mangled_name_of_contained_item(function_name), namespace_node.scope)
+        }
+        None => {
+            // This branch is only hit when there is a bug in the NamespaceVisitor.
+            cx.sess.span_warn(span, fmt!("debuginfo: Could not find namespace node for function
+                                          with name %s. This is a bug! Please report this to
+                                          github.com/mozilla/rust/issues", function_name));
+            (function_name.clone(), file_metadata)
+        }
     };
 
     let scope_line = get_scope_line(cx, top_level_block, loc.line);
 
-    let fn_metadata = do function_name.to_c_str().with_ref |function_name| {
+    let fn_metadata = do function_name.with_c_str |function_name| {
+                      do linkage_name.with_c_str |linkage_name| {
         unsafe {
             llvm::LLVMDIBuilderCreateFunction(
                 DIB(cx),
-                file_metadata,
-                function_name,
+                containing_scope,
                 function_name,
+                linkage_name,
                 file_metadata,
                 loc.line as c_uint,
                 function_type_metadata,
@@ -601,9 +666,9 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
                 template_parameters,
                 ptr::null())
         }
-    };
+    }};
 
-    // Initialize fn debug context (including scope map)
+    // Initialize fn debug context (including scope map and namespace map)
     let mut fn_debug_context = ~FunctionDebugContextData {
         scope_map: HashMap::new(),
         fn_metadata: fn_metadata,
@@ -614,12 +679,23 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
     let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
     populate_scope_map(cx, arg_pats, top_level_block, fn_metadata, &mut fn_debug_context.scope_map);
 
+    // Create namespaces for the interior of this function
+    {
+        let mut namespace_visitor = NamespaceVisitor::new_function_visitor(cx,
+                                                                           function_name,
+                                                                           namespace_node,
+                                                                           file_metadata,
+                                                                           span);
+        visit::walk_block(&mut namespace_visitor, top_level_block, ());
+    }
+
     return FunctionDebugContext(fn_debug_context);
 
     fn get_function_signature(cx: &mut CrateContext,
                               fn_ast_id: ast::NodeId,
                               fn_decl: &ast::fn_decl,
-                              param_substs: Option<@param_substs>) -> DIArray {
+                              param_substs: Option<@param_substs>,
+                              error_span: Span) -> DIArray {
         if !cx.sess.opts.extra_debuginfo {
             return create_DIArray(DIB(cx), []);
         }
@@ -632,6 +708,8 @@ fn get_function_signature(cx: &mut CrateContext,
                 signature.push(ptr::null());
             }
             _ => {
+                assert_type_for_node_id(cx, fn_ast_id, error_span);
+
                 let return_type = ty::node_id_to_type(cx.tcx, fn_ast_id);
                 let return_type = match param_substs {
                     None => return_type,
@@ -644,8 +722,9 @@ fn get_function_signature(cx: &mut CrateContext,
             }
         }
 
-        // arguments types
+        // Arguments types
         for arg in fn_decl.inputs.iter() {
+            assert_type_for_node_id(cx, arg.pat.id, arg.pat.span);
             let arg_type = ty::node_id_to_type(cx.tcx, arg.pat.id);
             let arg_type = match param_substs {
                 None => arg_type,
@@ -675,7 +754,7 @@ fn get_template_parameters(cx: &mut CrateContext,
         let has_self_type = self_type.is_some();
 
         if !generics.is_type_parameterized() && !has_self_type {
-            return ptr::null();
+            return create_DIArray(DIB(cx), []);
         }
 
         name_to_append_suffix_to.push_char('<');
@@ -686,33 +765,37 @@ fn get_template_parameters(cx: &mut CrateContext,
         // Handle self type
         if has_self_type {
             let actual_self_type = self_type.unwrap();
-            let actual_self_type_metadata = type_metadata(cx,
-                                                          actual_self_type,
-                                                          codemap::dummy_sp());
-
             // Add self type name to <...> clause of function name
-            let actual_self_type_name = ty_to_str(cx.tcx, actual_self_type);
+            let actual_self_type_name = ppaux::ty_to_str(cx.tcx, actual_self_type);
             name_to_append_suffix_to.push_str(actual_self_type_name);
+
             if generics.is_type_parameterized() {
                 name_to_append_suffix_to.push_str(",");
             }
 
-            let ident = special_idents::type_self;
-
-            let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
-                unsafe {
-                    llvm::LLVMDIBuilderCreateTemplateTypeParameter(
-                        DIB(cx),
-                        file_metadata,
-                        name,
-                        actual_self_type_metadata,
-                        ptr::null(),
-                        0,
-                        0)
-                }
-            };
+            // Only create type information if extra_debuginfo is enabled
+            if cx.sess.opts.extra_debuginfo {
+                let actual_self_type_metadata = type_metadata(cx,
+                                                              actual_self_type,
+                                                              codemap::dummy_sp());
+
+                let ident = special_idents::type_self;
+
+                let param_metadata = do token::ident_to_str(&ident).to_c_str().with_ref |name| {
+                    unsafe {
+                        llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+                            DIB(cx),
+                            file_metadata,
+                            name,
+                            actual_self_type_metadata,
+                            ptr::null(),
+                            0,
+                            0)
+                    }
+                };
 
-            template_params.push(param_metadata);
+                template_params.push(param_metadata);
+            }
         }
 
         // Handle other generic parameters
@@ -725,30 +808,31 @@ fn get_template_parameters(cx: &mut CrateContext,
 
         for (index, &ast::TyParam{ ident: ident, _ }) in generics.ty_params.iter().enumerate() {
             let actual_type = actual_types[index];
-            let actual_type_metadata = type_metadata(cx, actual_type, codemap::dummy_sp());
-
             // Add actual type name to <...> clause of function name
-            let actual_type_name = ty_to_str(cx.tcx, actual_type);
+            let actual_type_name = ppaux::ty_to_str(cx.tcx, actual_type);
             name_to_append_suffix_to.push_str(actual_type_name);
 
             if index != generics.ty_params.len() - 1 {
                 name_to_append_suffix_to.push_str(",");
             }
 
-            let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
-                unsafe {
-                    llvm::LLVMDIBuilderCreateTemplateTypeParameter(
-                        DIB(cx),
-                        file_metadata,
-                        name,
-                        actual_type_metadata,
-                        ptr::null(),
-                        0,
-                        0)
-                }
-            };
-
-            template_params.push(param_metadata);
+            // Again, only create type information if extra_debuginfo is enabled
+            if cx.sess.opts.extra_debuginfo {
+                let actual_type_metadata = type_metadata(cx, actual_type, codemap::dummy_sp());
+                let param_metadata = do token::ident_to_str(&ident).to_c_str().with_ref |name| {
+                    unsafe {
+                        llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+                            DIB(cx),
+                            file_metadata,
+                            name,
+                            actual_type_metadata,
+                            ptr::null(),
+                            0,
+                            0)
+                    }
+                };
+                template_params.push(param_metadata);
+            }
         }
 
         name_to_append_suffix_to.push_char('>');
@@ -757,14 +841,14 @@ fn get_template_parameters(cx: &mut CrateContext,
     }
 
     fn get_scope_line(cx: &CrateContext,
-                      top_level_block: Option<&ast::Block>,
+                      top_level_block: &ast::Block,
                       default: uint)
                    -> uint {
-        match top_level_block {
-            Some(&ast::Block { stmts: ref statements, _ }) if statements.len() > 0 => {
+        match *top_level_block {
+            ast::Block { stmts: ref statements, _ } if statements.len() > 0 => {
                 span_start(cx, statements[0].span).line
             }
-            Some(&ast::Block { expr: Some(@ref expr), _ }) => {
+            ast::Block { expr: Some(@ref expr), _ } => {
                 span_start(cx, expr.span).line
             }
             _ => default
@@ -783,7 +867,7 @@ fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
 }
 
 fn compile_unit_metadata(cx: @mut CrateContext) {
-    let dcx = dbg_cx(cx);
+    let dcx = debug_context(cx);
     let crate_name: &str = dcx.crate_file;
 
     debug!("compile_unit_metadata: %?", crate_name);
@@ -823,7 +907,7 @@ fn declare_local(bcx: @mut Block,
     let filename = span_start(cx, span).file.name;
     let file_metadata = file_metadata(cx, filename);
 
-    let name: &str = cx.sess.str_of(variable_ident);
+    let name: &str = token::ident_to_str(&variable_ident);
     let loc = span_start(cx, span);
     let type_metadata = type_metadata(cx, variable_type, span);
 
@@ -886,12 +970,12 @@ fn declare_local(bcx: @mut Block,
             assert!(!bcx.fcx.debug_context.get_ref(cx, span).source_locations_enabled);
             set_debug_location(cx, UnknownLocation);
         }
-        _ => { /* fallthrough */ }
+        _ => { /* nothing to do */ }
     }
 }
 
 fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
-    match dbg_cx(cx).created_files.find_equiv(&full_path) {
+    match debug_context(cx).created_files.find_equiv(&full_path) {
         Some(file_metadata) => return *file_metadata,
         None => ()
     }
@@ -914,7 +998,7 @@ fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
             }
         }};
 
-    dbg_cx(cx).created_files.insert(full_path.to_owned(), file_metadata);
+    debug_context(cx).created_files.insert(full_path.to_owned(), file_metadata);
     return file_metadata;
 }
 
@@ -988,7 +1072,7 @@ fn pointer_type_metadata(cx: &mut CrateContext,
                       -> DIType {
     let pointer_llvm_type = type_of::type_of(cx, pointer_type);
     let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
-    let name = ty_to_str(cx.tcx, pointer_type);
+    let name = ppaux::ty_to_str(cx.tcx, pointer_type);
     let ptr_metadata = do name.with_c_str |name| {
         unsafe {
             llvm::LLVMDIBuilderCreatePointerType(
@@ -1002,91 +1086,179 @@ fn pointer_type_metadata(cx: &mut CrateContext,
     return ptr_metadata;
 }
 
-fn struct_metadata(cx: &mut CrateContext,
-                   struct_type: ty::t,
-                   fields: ~[ty::field],
-                   span: Span)
-                -> DICompositeType {
-    let struct_name = ty_to_str(cx.tcx, struct_type);
-    debug!("struct_metadata: %s", struct_name);
-
+fn prepare_struct_metadata(cx: &mut CrateContext,
+                           struct_type: ty::t,
+                           def_id: ast::DefId,
+                           substs: &ty::substs,
+                           span: Span)
+                        -> RecursiveTypeDescription {
+    let struct_name = ppaux::ty_to_str(cx.tcx, struct_type);
     let struct_llvm_type = type_of::type_of(cx, struct_type);
 
-    let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) };
-    let field_names = do fields.map |field| {
-        if field.ident.name == special_idents::unnamed_field.name {
-            ~""
-        } else {
-            cx.sess.str_of(field.ident).to_owned()
-        }
-    };
-    let field_types_metadata = do fields.map |field| {
-        type_metadata(cx, field.mt.ty, span)
-    };
+    let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id, span);
+
+    let file_name = span_start(cx, definition_span).file.name;
+    let file_metadata = file_metadata(cx, file_name);
+
+    let struct_metadata_stub = create_struct_stub(cx,
+                                                  struct_llvm_type,
+                                                  struct_name,
+                                                  containing_scope,
+                                                  file_metadata,
+                                                  definition_span);
+
+    let fields = ty::struct_fields(cx.tcx, def_id, substs);
+
+    UnfinishedMetadata {
+        cache_id: cache_id_for_type(struct_type),
+        metadata_stub: struct_metadata_stub,
+        llvm_type: struct_llvm_type,
+        file_metadata: file_metadata,
+        member_description_factory: |cx| {
+            do fields.map |field| {
+                let name = if field.ident.name == special_idents::unnamed_field.name {
+                    @""
+                } else {
+                    token::ident_to_str(&field.ident)
+                };
 
-    return composite_type_metadata(
-        cx,
-        struct_llvm_type,
-        struct_name,
-        field_llvm_types,
-        field_names,
-        field_types_metadata,
-        span);
+                MemberDescription {
+                    name: name,
+                    llvm_type: type_of::type_of(cx, field.mt.ty),
+                    type_metadata: type_metadata(cx, field.mt.ty, span),
+                    offset: ComputedMemberOffset,
+                }
+            }
+        }
+    }
 }
 
-fn tuple_metadata(cx: &mut CrateContext,
-                  tuple_type: ty::t,
-                  component_types: &[ty::t],
-                  span: Span)
-               -> DICompositeType {
+enum RecursiveTypeDescription {
+    UnfinishedMetadata {
+        cache_id: uint,
+        metadata_stub: DICompositeType,
+        llvm_type: Type,
+        file_metadata: DIFile,
+        member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription],
+    },
+    FinalMetadata(DICompositeType)
+}
 
-    let tuple_name = ty_to_str(cx.tcx, tuple_type);
-    let tuple_llvm_type = type_of::type_of(cx, tuple_type);
+impl RecursiveTypeDescription {
 
-    let component_names = do component_types.map |_| { ~"" };
-    let component_llvm_types = do component_types.map |it| { type_of::type_of(cx, *it) };
-    let component_types_metadata = do component_types.map |it| {
-        type_metadata(cx, *it, span)
-    };
+    fn metadata(&self) -> DICompositeType {
+        match *self {
+            UnfinishedMetadata { metadata_stub, _ } => metadata_stub,
+            FinalMetadata(metadata) => metadata
+        }
+    }
 
-    return composite_type_metadata(
-        cx,
-        tuple_llvm_type,
-        tuple_name,
-        component_llvm_types,
-        component_names,
-        component_types_metadata,
-        span);
+    fn finalize(&self, cx: &mut CrateContext) -> DICompositeType {
+        match *self {
+            FinalMetadata(metadata) => metadata,
+            UnfinishedMetadata {
+                cache_id,
+                metadata_stub,
+                llvm_type,
+                file_metadata,
+                member_description_factory
+            } => {
+                // Insert the stub into the cache in order to allow recursive references ...
+                debug_context(cx).created_types.insert(cache_id, metadata_stub);
+
+                // ... then create the member descriptions ...
+                let member_descriptions = member_description_factory(cx);
+
+                // ... and attach them to the stub to complete it.
+                set_members_of_composite_type(cx,
+                                              metadata_stub,
+                                              llvm_type,
+                                              member_descriptions,
+                                              file_metadata,
+                                              codemap::dummy_sp());
+                return metadata_stub;
+            }
+        }
+    }
 }
 
-fn enum_metadata(cx: &mut CrateContext,
-                 enum_type: ty::t,
-                 enum_def_id: ast::DefId,
-                 span: Span)
-              -> DIType {
+fn prepare_tuple_metadata(cx: &mut CrateContext,
+                          tuple_type: ty::t,
+                          component_types: &[ty::t],
+                          span: Span)
+                       -> RecursiveTypeDescription {
+    let tuple_name = ppaux::ty_to_str(cx.tcx, tuple_type);
+    let tuple_llvm_type = type_of::type_of(cx, tuple_type);
+
+    let loc = span_start(cx, span);
+    let file_metadata = file_metadata(cx, loc.file.name);
+    // Needs to be copied for closure below :(
+    let component_types = component_types.to_owned();
+
+    UnfinishedMetadata {
+        cache_id: cache_id_for_type(tuple_type),
+        metadata_stub: create_struct_stub(cx,
+                                          tuple_llvm_type,
+                                          tuple_name,
+                                          file_metadata,
+                                          file_metadata,
+                                          span),
+        llvm_type: tuple_llvm_type,
+        file_metadata: file_metadata,
+        member_description_factory: |cx| {
+            do component_types.map |&component_type| {
+                MemberDescription {
+                    name: @"",
+                    llvm_type: type_of::type_of(cx, component_type),
+                    type_metadata: type_metadata(cx, component_type, span),
+                    offset: ComputedMemberOffset,
+                }
+            }
+        }
+    }
+}
 
-    let enum_name = ty_to_str(cx.tcx, enum_type);
+fn prepare_enum_metadata(cx: &mut CrateContext,
+                         enum_type: ty::t,
+                         enum_def_id: ast::DefId,
+                         span: Span)
+                      -> RecursiveTypeDescription {
+    let enum_name = ppaux::ty_to_str(cx.tcx, enum_type);
+
+    let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx,
+                                                                              enum_def_id,
+                                                                              span);
+    let loc = span_start(cx, definition_span);
+    let file_metadata = file_metadata(cx, loc.file.name);
 
     // For empty enums there is an early exit. Just describe it as an empty struct with the
     // appropriate type name
     if ty::type_is_empty(cx.tcx, enum_type) {
-        return composite_type_metadata(cx, Type::nil(), enum_name, [], [], [], span);
+        let empty_type_metadata = composite_type_metadata(cx,
+                                                          Type::nil(),
+                                                          enum_name,
+                                                          [],
+                                                          containing_scope,
+                                                          file_metadata,
+                                                          definition_span);
+
+        return FinalMetadata(empty_type_metadata);
     }
 
-    // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be
+    // Prepare some data (llvm type, size, align, etc) about the discriminant. This data will be
     // needed in all of the following cases.
     let discriminant_llvm_type = Type::enum_discrim(cx);
     let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
 
     assert!(Type::enum_discrim(cx) == cx.int_type);
-    let discriminant_type_metadata = type_metadata(cx, ty::mk_int(), span);
+    let discriminant_base_type_metadata = type_metadata(cx, ty::mk_int(), codemap::dummy_sp());
 
-    let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
+    let variants = ty::enum_variants(cx.tcx, enum_def_id);
 
     let enumerators_metadata: ~[DIDescriptor] = variants
         .iter()
         .map(|v| {
-            let name: &str = cx.sess.str_of(v.name);
+            let name: &str = token::ident_to_str(&v.name);
             let discriminant_value = v.disr_val as c_ulonglong;
 
             do name.with_c_str |name| {
@@ -1100,155 +1272,265 @@ fn enum_metadata(cx: &mut CrateContext,
         })
         .collect();
 
-    let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, loc.file.name);
-
     let discriminant_type_metadata = do enum_name.with_c_str |enum_name| {
         unsafe {
             llvm::LLVMDIBuilderCreateEnumerationType(
                 DIB(cx),
-                file_metadata,
+                containing_scope,
                 enum_name,
                 file_metadata,
                 loc.line as c_uint,
                 bytes_to_bits(discriminant_size),
                 bytes_to_bits(discriminant_align),
                 create_DIArray(DIB(cx), enumerators_metadata),
-                discriminant_type_metadata)
+                discriminant_base_type_metadata)
         }
     };
 
     let type_rep = adt::represent_type(cx, enum_type);
 
-    match *type_rep {
+    return match *type_rep {
         adt::CEnum(*) => {
-            return discriminant_type_metadata;
+            FinalMetadata(discriminant_type_metadata)
         }
         adt::Univariant(ref struct_def, _) => {
             assert!(variants.len() == 1);
-            return adt_struct_metadata(cx, struct_def, variants[0], None, span);
+            let (metadata_stub,
+                 variant_llvm_type,
+                 member_description_factory) = describe_variant(cx,
+                                                                struct_def,
+                                                                variants[0],
+                                                                None,
+                                                                containing_scope,
+                                                                file_metadata,
+                                                                span);
+            UnfinishedMetadata {
+                cache_id: cache_id_for_type(enum_type),
+                metadata_stub: metadata_stub,
+                llvm_type: variant_llvm_type,
+                file_metadata: file_metadata,
+                member_description_factory: member_description_factory
+            }
         }
-        adt::General(ref struct_defs) => {
-            let variants_member_metadata: ~[DIDescriptor] = do struct_defs
-                .iter()
-                .enumerate()
-                .map |(i, struct_def)| {
-                    let variant_type_metadata = adt_struct_metadata(
-                        cx,
-                        struct_def,
-                        variants[i],
-                        Some(discriminant_type_metadata),
-                        span);
-
-                    do "".with_c_str |name| {
-                        unsafe {
-                            llvm::LLVMDIBuilderCreateMemberType(
-                                DIB(cx),
-                                file_metadata,
-                                name,
-                                file_metadata,
-                                loc.line as c_uint,
-                                bytes_to_bits(struct_def.size as uint),
-                                bytes_to_bits(struct_def.align as uint),
-                                bytes_to_bits(0),
-                                0,
-                                variant_type_metadata)
-                        }
-                    }
-            }.collect();
-
+        adt::General(_) => {
             let enum_llvm_type = type_of::type_of(cx, enum_type);
             let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
 
-            return do enum_name.with_c_str |enum_name| {
+            let enum_metadata = do enum_name.with_c_str |enum_name| {
                 unsafe {
                     llvm::LLVMDIBuilderCreateUnionType(
                     DIB(cx),
-                    file_metadata,
+                    containing_scope,
                     enum_name,
                     file_metadata,
                     loc.line as c_uint,
                     bytes_to_bits(enum_type_size),
                     bytes_to_bits(enum_type_align),
                     0, // Flags
-                    create_DIArray(DIB(cx), variants_member_metadata),
+                    ptr::null(),
                     0) // RuntimeLang
             }};
+
+            UnfinishedMetadata {
+                cache_id: cache_id_for_type(enum_type),
+                metadata_stub: enum_metadata,
+                llvm_type: enum_llvm_type,
+                file_metadata: file_metadata,
+                member_description_factory: |cx| {
+                    // Capture type_rep, so we don't have to copy the struct_defs array
+                    let struct_defs = match *type_rep {
+                        adt::General(ref struct_defs) => struct_defs,
+                        _ => cx.sess.bug("unreachable")
+                    };
+
+                    do struct_defs
+                        .iter()
+                        .enumerate()
+                        .map |(i, struct_def)| {
+                            let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
+                                describe_variant(cx,
+                                                 struct_def,
+                                                 variants[i],
+                                                 Some(discriminant_type_metadata),
+                                                 containing_scope,
+                                                 file_metadata,
+                                                 span);
+
+                            let member_descriptions = member_desc_factory(cx);
+
+                            set_members_of_composite_type(cx,
+                                                          variant_type_metadata,
+                                                          variant_llvm_type,
+                                                          member_descriptions,
+                                                          file_metadata,
+                                                          codemap::dummy_sp());
+                            MemberDescription {
+                                name: @"",
+                                llvm_type: variant_llvm_type,
+                                type_metadata: variant_type_metadata,
+                                offset: FixedMemberOffset { bytes: 0 },
+                            }
+                    }.collect()
+                }
+            }
         }
         adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => {
-            return adt_struct_metadata(cx, struct_def, variants[nndiscr], None, span);
+            let (metadata_stub,
+                 variant_llvm_type,
+                 member_description_factory) = describe_variant(cx,
+                                                                struct_def,
+                                                                variants[nndiscr],
+                                                                None,
+                                                                containing_scope,
+                                                                file_metadata,
+                                                                span);
+            UnfinishedMetadata {
+                cache_id: cache_id_for_type(enum_type),
+                metadata_stub: metadata_stub,
+                llvm_type: variant_llvm_type,
+                file_metadata: file_metadata,
+                member_description_factory: member_description_factory
+            }
         }
-    }
+    };
 
-    fn adt_struct_metadata(cx: &mut CrateContext,
-                                  struct_def: &adt::Struct,
-                                  variant_info: &ty::VariantInfo,
-                                  discriminant_type_metadata: Option<DIType>,
-                                  span: Span)
-                               -> DICompositeType
-    {
-        let arg_llvm_types: ~[Type] = do struct_def.fields.map |&ty| { type_of::type_of(cx, ty) };
-        let arg_metadata: ~[DIType] = do struct_def.fields.iter().enumerate()
-            .map |(i, &ty)| {
-                match discriminant_type_metadata {
-                    Some(metadata) if i == 0 => metadata,
-                    _                        => type_metadata(cx, ty, span)
+    fn describe_variant(cx: &mut CrateContext,
+                        struct_def: &adt::Struct,
+                        variant_info: &ty::VariantInfo,
+                        discriminant_type_metadata: Option<DIType>,
+                        containing_scope: DIScope,
+                        file_metadata: DIFile,
+                        span: Span)
+                     -> (DICompositeType, Type, @fn(&mut CrateContext) -> ~[MemberDescription]) {
+        let variant_name = token::ident_to_str(&variant_info.name);
+        let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
+                                              struct_def.packed);
+        // Could some consistency checks here: size, align, field count, discr type
+
+        // Find the source code location of the variant's definition
+        let variant_definition_span = if variant_info.id.crate == ast::LOCAL_CRATE {
+            match cx.tcx.items.find(&variant_info.id.node) {
+                Some(&ast_map::node_variant(ref variant, _, _)) => variant.span,
+                ref node => {
+                    cx.sess.span_warn(span,
+                        fmt!("debuginfo::enum_metadata()::adt_struct_metadata() - Unexpected node \
+                              type: %?. This is a bug.", node));
+                    codemap::dummy_sp()
                 }
-        }.collect();
+            }
+        } else {
+            // For definitions from other crates we have no location information available.
+            codemap::dummy_sp()
+        };
+
+        let metadata_stub = create_struct_stub(cx,
+                                               variant_llvm_type,
+                                               variant_name,
+                                               containing_scope,
+                                               file_metadata,
+                                               variant_definition_span);
 
+        // Get the argument names from the enum variant info
         let mut arg_names = match variant_info.arg_names {
-            Some(ref names) => do names.map |ident| { cx.sess.str_of(*ident).to_owned() },
-            None => do variant_info.args.map |_| { ~"" }
+            Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
+            None => do variant_info.args.map |_| { @"" }
         };
 
+        // If this is not a univariant enum, there is also the (unnamed) discriminant field
         if discriminant_type_metadata.is_some() {
-            arg_names.insert(0, ~"");
+            arg_names.insert(0, @"");
         }
 
-        let variant_llvm_type = Type::struct_(arg_llvm_types, struct_def.packed);
-        let variant_name: &str = cx.sess.str_of(variant_info.name);
+        // Build an array of (field name, field type) pairs to be captured in the factory closure.
+        let args: ~[(@str, ty::t)] = arg_names.iter()
+            .zip(struct_def.fields.iter())
+            .map(|(&s, &t)| (s, t))
+            .collect();
+
+        let member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription] = |cx| {
+            do args.iter().enumerate().map |(i, &(name, ty))| {
+                MemberDescription {
+                    name: name,
+                    llvm_type: type_of::type_of(cx, ty),
+                    type_metadata: match discriminant_type_metadata {
+                        Some(metadata) if i == 0 => metadata,
+                        _ => type_metadata(cx, ty, span)
+                    },
+                    offset: ComputedMemberOffset,
+                }
+            }.collect()
+        };
 
-        return composite_type_metadata(
-            cx,
-            variant_llvm_type,
-            variant_name,
-            arg_llvm_types,
-            arg_names,
-            arg_metadata,
-            span);
+        (metadata_stub, variant_llvm_type, member_description_factory)
     }
 }
 
+enum MemberOffset {
+    FixedMemberOffset { bytes: uint },
+    // For ComputedMemberOffset, the offset is read from the llvm type definition
+    ComputedMemberOffset
+}
+
+struct MemberDescription {
+    name: @str,
+    llvm_type: Type,
+    type_metadata: DIType,
+    offset: MemberOffset,
+}
+
 /// Creates debug information for a composite type, that is, anything that results in a LLVM struct.
 ///
 /// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
 fn composite_type_metadata(cx: &mut CrateContext,
                            composite_llvm_type: Type,
                            composite_type_name: &str,
-                           member_llvm_types: &[Type],
-                           member_names: &[~str],
-                           member_type_metadata: &[DIType],
-                           span: Span)
+                           member_descriptions: &[MemberDescription],
+                           containing_scope: DIScope,
+                           file_metadata: DIFile,
+                           definition_span: Span)
                         -> DICompositeType {
+    // Create the (empty) struct metadata node ...
+    let composite_type_metadata = create_struct_stub(cx,
+                                                     composite_llvm_type,
+                                                     composite_type_name,
+                                                     containing_scope,
+                                                     file_metadata,
+                                                     definition_span);
+
+    // ... and immediately create and add the member descriptions.
+    set_members_of_composite_type(cx,
+                                  composite_type_metadata,
+                                  composite_llvm_type,
+                                  member_descriptions,
+                                  file_metadata,
+                                  definition_span);
+
+    return composite_type_metadata;
+}
 
-    let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, loc.file.name);
-
-    let (composite_size, composite_align) = size_and_align_of(cx, composite_llvm_type);
+fn set_members_of_composite_type(cx: &mut CrateContext,
+                                 composite_type_metadata: DICompositeType,
+                                 composite_llvm_type: Type,
+                                 member_descriptions: &[MemberDescription],
+                                 file_metadata: DIFile,
+                                 definition_span: Span) {
+    let loc = span_start(cx, definition_span);
 
-    let member_metadata: ~[DIDescriptor] = member_llvm_types
+    let member_metadata: ~[DIDescriptor] = member_descriptions
         .iter()
         .enumerate()
-        .map(|(i, &member_llvm_type)| {
-            let (member_size, member_align) = size_and_align_of(cx, member_llvm_type);
-            let member_offset = machine::llelement_offset(cx, composite_llvm_type, i);
-            let member_name: &str = member_names[i];
+        .map(|(i, member_description)| {
+            let (member_size, member_align) = size_and_align_of(cx, member_description.llvm_type);
+            let member_offset = match member_description.offset {
+                FixedMemberOffset { bytes } => bytes,
+                ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
+            };
 
-            do member_name.with_c_str |member_name| {
+            do member_description.name.with_c_str |member_name| {
                 unsafe {
                     llvm::LLVMDIBuilderCreateMemberType(
                         DIB(cx),
-                        file_metadata,
+                        composite_type_metadata,
                         member_name,
                         file_metadata,
                         loc.line as c_uint,
@@ -1256,29 +1538,50 @@ fn composite_type_metadata(cx: &mut CrateContext,
                         bytes_to_bits(member_align),
                         bytes_to_bits(member_offset),
                         0,
-                        member_type_metadata[i])
+                        member_description.type_metadata)
                 }
             }
         })
         .collect();
 
-    return do composite_type_name.with_c_str |name| {
+    unsafe {
+        let type_array = create_DIArray(DIB(cx), member_metadata);
+        llvm::LLVMDICompositeTypeSetTypeArray(composite_type_metadata, type_array);
+    }
+}
+
+// A convenience wrapper around LLVMDIBuilderCreateStructType(). Does not do any caching, does not
+// add any fields to the struct. This can be done later with set_members_of_composite_type().
+fn create_struct_stub(cx: &mut CrateContext,
+                      struct_llvm_type: Type,
+                      struct_type_name: &str,
+                      containing_scope: DIScope,
+                      file_metadata: DIFile,
+                      definition_span: Span)
+                   -> DICompositeType {
+    let loc = span_start(cx, definition_span);
+    let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
+
+    return do struct_type_name.with_c_str |name| {
         unsafe {
+            // LLVMDIBuilderCreateStructType() wants an empty array. A null pointer will lead to
+            // hard to trace and debug LLVM assertions later on in llvm/lib/IR/Value.cpp
+            let empty_array = create_DIArray(DIB(cx), []);
+
             llvm::LLVMDIBuilderCreateStructType(
                 DIB(cx),
-                file_metadata,
+                containing_scope,
                 name,
                 file_metadata,
                 loc.line as c_uint,
-                bytes_to_bits(composite_size),
-                bytes_to_bits(composite_align),
+                bytes_to_bits(struct_size),
+                bytes_to_bits(struct_align),
                 0,
                 ptr::null(),
-                create_DIArray(DIB(cx), member_metadata),
+                empty_array,
                 0,
                 ptr::null())
-    }
-    };
+    }};
 }
 
 fn boxed_type_metadata(cx: &mut CrateContext,
@@ -1287,7 +1590,6 @@ fn boxed_type_metadata(cx: &mut CrateContext,
                        content_type_metadata: DIType,
                        span: Span)
                     -> DICompositeType {
-
     let box_type_name = match content_type_name {
         Some(content_type_name) => fmt!("Boxed<%s>", content_type_name),
         None                    => ~"BoxedType"
@@ -1295,28 +1597,55 @@ fn boxed_type_metadata(cx: &mut CrateContext,
 
     let box_llvm_type = Type::box(cx, &content_llvm_type);
     let member_llvm_types = box_llvm_type.field_types();
-    let member_names = [~"refcnt", ~"tydesc", ~"prev", ~"next", ~"val"];
-
     assert!(box_layout_is_correct(cx, member_llvm_types, content_llvm_type));
 
     let int_type = ty::mk_int();
     let nil_pointer_type = ty::mk_nil_ptr(cx.tcx);
-
-    let member_types_metadata = [
-        type_metadata(cx, int_type, span),
-        type_metadata(cx, nil_pointer_type, span),
-        type_metadata(cx, nil_pointer_type, span),
-        type_metadata(cx, nil_pointer_type, span),
-        content_type_metadata
+    let nil_pointer_type_metadata = type_metadata(cx, nil_pointer_type, codemap::dummy_sp());
+
+    let member_descriptions = [
+        MemberDescription {
+            name: @"refcnt",
+            llvm_type: member_llvm_types[0],
+            type_metadata: type_metadata(cx, int_type, codemap::dummy_sp()),
+            offset: ComputedMemberOffset,
+        },
+        MemberDescription {
+            name: @"tydesc",
+            llvm_type: member_llvm_types[1],
+            type_metadata: nil_pointer_type_metadata,
+            offset: ComputedMemberOffset,
+        },
+        MemberDescription {
+            name: @"prev",
+            llvm_type: member_llvm_types[2],
+            type_metadata: nil_pointer_type_metadata,
+            offset: ComputedMemberOffset,
+        },
+        MemberDescription {
+            name: @"next",
+            llvm_type: member_llvm_types[3],
+            type_metadata: nil_pointer_type_metadata,
+            offset: ComputedMemberOffset,
+        },
+        MemberDescription {
+            name: @"val",
+            llvm_type: member_llvm_types[4],
+            type_metadata: content_type_metadata,
+            offset: ComputedMemberOffset,
+        }
     ];
 
+    let loc = span_start(cx, span);
+    let file_metadata = file_metadata(cx, loc.file.name);
+
     return composite_type_metadata(
         cx,
         box_llvm_type,
         box_type_name,
-        member_llvm_types,
-        member_names,
-        member_types_metadata,
+        member_descriptions,
+        file_metadata,
+        file_metadata,
         span);
 
     // Unfortunately, we cannot assert anything but the correct types here---and not whether the
@@ -1371,10 +1700,9 @@ fn vec_metadata(cx: &mut CrateContext,
     let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
 
     let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
-    let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
+    let vec_type_name: &str = fmt!("[%s]", ppaux::ty_to_str(cx.tcx, element_type));
 
     let member_llvm_types = vec_llvm_type.field_types();
-    let member_names = &[~"fill", ~"alloc", ~"elements"];
 
     let int_type_metadata = type_metadata(cx, ty::mk_int(), span);
     let array_type_metadata = unsafe {
@@ -1386,16 +1714,39 @@ fn vec_metadata(cx: &mut CrateContext,
             create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)]))
     };
 
-    //                           fill               alloc              elements
-    let member_type_metadata = &[int_type_metadata, int_type_metadata, array_type_metadata];
+    let member_descriptions = [
+        MemberDescription {
+            name: @"fill",
+            llvm_type: member_llvm_types[0],
+            type_metadata: int_type_metadata,
+            offset: ComputedMemberOffset,
+        },
+        MemberDescription {
+            name: @"alloc",
+            llvm_type: member_llvm_types[1],
+            type_metadata: int_type_metadata,
+            offset: ComputedMemberOffset,
+        },
+        MemberDescription {
+            name: @"elements",
+            llvm_type: member_llvm_types[2],
+            type_metadata: array_type_metadata,
+            offset: ComputedMemberOffset,
+        }
+    ];
+
+    assert!(member_descriptions.len() == member_llvm_types.len());
+
+    let loc = span_start(cx, span);
+    let file_metadata = file_metadata(cx, loc.file.name);
 
     return composite_type_metadata(
         cx,
         vec_llvm_type,
         vec_type_name,
-        member_llvm_types,
-        member_names,
-        member_type_metadata,
+        member_descriptions,
+        file_metadata,
+        file_metadata,
         span);
 }
 
@@ -1403,10 +1754,9 @@ fn boxed_vec_metadata(cx: &mut CrateContext,
                       element_type: ty::t,
                       span: Span)
                    -> DICompositeType {
-
     let element_llvm_type = type_of::type_of(cx, element_type);
     let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
-    let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
+    let vec_type_name: &str = fmt!("[%s]", ppaux::ty_to_str(cx.tcx, element_type));
     let vec_metadata = vec_metadata(cx, element_type, span);
 
     return boxed_type_metadata(
@@ -1426,25 +1776,40 @@ fn vec_slice_metadata(cx: &mut CrateContext,
     debug!("vec_slice_metadata: %?", ty::get(vec_type));
 
     let slice_llvm_type = type_of::type_of(cx, vec_type);
-    let slice_type_name = ty_to_str(cx.tcx, vec_type);
+    let slice_type_name = ppaux::ty_to_str(cx.tcx, vec_type);
 
     let member_llvm_types = slice_llvm_type.field_types();
-    let member_names = &[~"data_ptr", ~"size_in_bytes"];
-
     assert!(slice_layout_is_correct(cx, member_llvm_types, element_type));
 
     let data_ptr_type = ty::mk_ptr(cx.tcx, ty::mt { ty: element_type, mutbl: ast::MutImmutable });
 
-    let member_type_metadata = &[type_metadata(cx, data_ptr_type, span),
-                                 type_metadata(cx, ty::mk_uint(), span)];
+    let member_descriptions = [
+        MemberDescription {
+            name: @"data_ptr",
+            llvm_type: member_llvm_types[0],
+            type_metadata: type_metadata(cx, data_ptr_type, span),
+            offset: ComputedMemberOffset,
+        },
+        MemberDescription {
+            name: @"size_in_bytes",
+            llvm_type: member_llvm_types[1],
+            type_metadata: type_metadata(cx, ty::mk_uint(), span),
+            offset: ComputedMemberOffset,
+        },
+    ];
+
+    assert!(member_descriptions.len() == member_llvm_types.len());
+
+    let loc = span_start(cx, span);
+    let file_metadata = file_metadata(cx, loc.file.name);
 
     return composite_type_metadata(
         cx,
         slice_llvm_type,
         slice_type_name,
-        member_llvm_types,
-        member_names,
-        member_type_metadata,
+        member_descriptions,
+        file_metadata,
+        file_metadata,
         span);
 
     fn slice_layout_is_correct(cx: &mut CrateContext,
@@ -1485,10 +1850,47 @@ fn subroutine_type_metadata(cx: &mut CrateContext,
     };
 }
 
+fn trait_metadata(cx: &mut CrateContext,
+                  def_id: ast::DefId,
+                  trait_type: ty::t,
+                  substs: &ty::substs,
+                  trait_store: ty::TraitStore,
+                  mutability: ast::Mutability,
+                  _: &ty::BuiltinBounds,
+                  usage_site_span: Span)
+               -> DIType {
+    // The implementation provided here is a stub. It makes sure that the trait type is
+    // assigned the correct name, size, namespace, and source location. But it does not describe
+    // the trait's methods.
+    let path = ty::item_path(cx.tcx, def_id);
+    let ident = path.last().ident();
+    let name = ppaux::trait_store_to_str(cx.tcx, trait_store) +
+               ppaux::mutability_to_str(mutability) +
+               token::ident_to_str(&ident);
+    // Add type and region parameters
+    let name = ppaux::parameterized(cx.tcx, name, &substs.regions, substs.tps);
+
+    let (containing_scope, definition_span) =
+        get_namespace_and_span_for_item(cx, def_id, usage_site_span);
+
+    let file_name = span_start(cx, definition_span).file.name;
+    let file_metadata = file_metadata(cx, file_name);
+
+    let trait_llvm_type = type_of::type_of(cx, trait_type);
+
+    return composite_type_metadata(cx,
+                                   trait_llvm_type,
+                                   name,
+                                   [],
+                                   containing_scope,
+                                   file_metadata,
+                                   definition_span);
+}
+
 fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
     debug!("unimplemented_type_metadata: %?", ty::get(t));
 
-    let name = ty_to_str(cx.tcx, t);
+    let name = ppaux::ty_to_str(cx.tcx, t);
     let metadata = do fmt!("NYI<%s>", name).with_c_str |name| {
         unsafe {
             llvm::LLVMDIBuilderCreateBasicType(
@@ -1503,12 +1905,16 @@ fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
     return metadata;
 }
 
+fn cache_id_for_type(t: ty::t) -> uint {
+    ty::type_id(t)
+}
+
 fn type_metadata(cx: &mut CrateContext,
                  t: ty::t,
-                 span: Span)
+                 usage_site_span: Span)
               -> DIType {
-    let type_id = ty::type_id(t);
-    match dbg_cx(cx).created_types.find(&type_id) {
+    let cache_id = cache_id_for_type(t);
+    match debug_context(cx).created_types.find(&cache_id) {
         Some(type_metadata) => return *type_metadata,
         None => ()
     }
@@ -1517,8 +1923,7 @@ fn create_pointer_to_box_metadata(cx: &mut CrateContext,
                                       pointer_type: ty::t,
                                       type_in_box: ty::t)
                                    -> DIType {
-
-        let content_type_name: &str = ty_to_str(cx.tcx, type_in_box);
+        let content_type_name: &str = ppaux::ty_to_str(cx.tcx, type_in_box);
         let content_llvm_type = type_of::type_of(cx, type_in_box);
         let content_type_metadata = type_metadata(
             cx,
@@ -1552,23 +1957,23 @@ fn create_pointer_to_box_metadata(cx: &mut CrateContext,
             let i8_t = ty::mk_i8();
             match *vstore {
                 ty::vstore_fixed(len) => {
-                    fixed_vec_metadata(cx, i8_t, len + 1, span)
+                    fixed_vec_metadata(cx, i8_t, len + 1, usage_site_span)
                 },
                 ty::vstore_uniq  => {
-                    let vec_metadata = vec_metadata(cx, i8_t, span);
+                    let vec_metadata = vec_metadata(cx, i8_t, usage_site_span);
                     pointer_type_metadata(cx, t, vec_metadata)
                 }
                 ty::vstore_box => {
-                    let boxed_vec_metadata = boxed_vec_metadata(cx, i8_t, span);
+                    let boxed_vec_metadata = boxed_vec_metadata(cx, i8_t, usage_site_span);
                     pointer_type_metadata(cx, t, boxed_vec_metadata)
                 }
                 ty::vstore_slice(_region) => {
-                    vec_slice_metadata(cx, t, i8_t, span)
+                    vec_slice_metadata(cx, t, i8_t, usage_site_span)
                 }
             }
         },
         ty::ty_enum(def_id, _) => {
-            enum_metadata(cx, t, def_id, span)
+            prepare_enum_metadata(cx, t, def_id, usage_site_span).finalize(cx)
         },
         ty::ty_box(ref mt) => {
             create_pointer_to_box_metadata(cx, t, mt.ty)
@@ -1576,22 +1981,22 @@ fn create_pointer_to_box_metadata(cx: &mut CrateContext,
         ty::ty_evec(ref mt, ref vstore) => {
             match *vstore {
                 ty::vstore_fixed(len) => {
-                    fixed_vec_metadata(cx, mt.ty, len, span)
+                    fixed_vec_metadata(cx, mt.ty, len, usage_site_span)
                 }
                 ty::vstore_uniq if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
-                    let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
+                    let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, usage_site_span);
                     pointer_type_metadata(cx, t, boxed_vec_metadata)
                 }
                 ty::vstore_uniq => {
-                    let vec_metadata = vec_metadata(cx, mt.ty, span);
+                    let vec_metadata = vec_metadata(cx, mt.ty, usage_site_span);
                     pointer_type_metadata(cx, t, vec_metadata)
                 }
                 ty::vstore_box => {
-                    let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
+                    let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, usage_site_span);
                     pointer_type_metadata(cx, t, boxed_vec_metadata)
                 }
                 ty::vstore_slice(_) => {
-                    vec_slice_metadata(cx, t, mt.ty, span)
+                    vec_slice_metadata(cx, t, mt.ty, usage_site_span)
                 }
             }
         },
@@ -1601,34 +2006,31 @@ fn create_pointer_to_box_metadata(cx: &mut CrateContext,
         ty::ty_uniq(ref mt)    |
         ty::ty_ptr(ref mt)     |
         ty::ty_rptr(_, ref mt) => {
-            let pointee = type_metadata(cx, mt.ty, span);
+            let pointee = type_metadata(cx, mt.ty, usage_site_span);
             pointer_type_metadata(cx, t, pointee)
         },
         ty::ty_bare_fn(ref barefnty) => {
-            subroutine_type_metadata(cx, &barefnty.sig, span)
+            subroutine_type_metadata(cx, &barefnty.sig, usage_site_span)
         },
         ty::ty_closure(ref closurety) => {
-            subroutine_type_metadata(cx, &closurety.sig, span)
+            subroutine_type_metadata(cx, &closurety.sig, usage_site_span)
         },
-        ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
-            cx.sess.span_note(span, "debuginfo for trait NYI");
-            unimplemented_type_metadata(cx, t)
+        ty::ty_trait(def_id, ref substs, trait_store, mutability, ref bounds) => {
+            trait_metadata(cx, def_id, t, substs, trait_store, mutability, bounds, usage_site_span)
         },
-        ty::ty_struct(did, ref substs) => {
-            let fields = ty::struct_fields(cx.tcx, did, substs);
-            struct_metadata(cx, t, fields, span)
+        ty::ty_struct(def_id, ref substs) => {
+            prepare_struct_metadata(cx, t, def_id, substs, usage_site_span).finalize(cx)
         },
         ty::ty_tup(ref elements) => {
-            tuple_metadata(cx, t, *elements, span)
+            prepare_tuple_metadata(cx, t, *elements, usage_site_span).finalize(cx)
         },
         ty::ty_opaque_box => {
-            cx.sess.span_note(span, "debuginfo for ty_opaque_box NYI");
-            unimplemented_type_metadata(cx, t)
+            create_pointer_to_box_metadata(cx, t, ty::mk_nil())
         }
         _ => cx.sess.bug(fmt!("debuginfo: unexpected type in type_metadata: %?", sty))
     };
 
-    dbg_cx(cx).created_types.insert(type_id, type_metadata);
+    debug_context(cx).created_types.insert(cache_id, type_metadata);
     return type_metadata;
 }
 
@@ -1649,7 +2051,7 @@ fn new(scope: DIScope, line: uint, col: uint) -> DebugLocation {
 }
 
 fn set_debug_location(cx: &mut CrateContext, debug_location: DebugLocation) {
-    if debug_location == dbg_cx(cx).curr_loc {
+    if debug_location == debug_context(cx).current_debug_location {
         return;
     }
 
@@ -1660,7 +2062,7 @@ fn set_debug_location(cx: &mut CrateContext, debug_location: DebugLocation) {
             debug!("setting debug location to %u %u", line, col);
             let elements = [C_i32(line as i32), C_i32(col as i32), scope, ptr::null()];
             unsafe {
-                metadata_node = llvm::LLVMMDNodeInContext(dbg_cx(cx).llcontext,
+                metadata_node = llvm::LLVMMDNodeInContext(debug_context(cx).llcontext,
                                                           vec::raw::to_ptr(elements),
                                                           elements.len() as c_uint);
             }
@@ -1675,7 +2077,7 @@ fn set_debug_location(cx: &mut CrateContext, debug_location: DebugLocation) {
         llvm::LLVMSetCurrentDebugLocation(cx.builder.B, metadata_node);
     }
 
-    dbg_cx(cx).curr_loc = debug_location;
+    debug_context(cx).current_debug_location = debug_location;
 }
 
 //=-------------------------------------------------------------------------------------------------
@@ -1701,7 +2103,7 @@ fn bytes_to_bits(bytes: uint) -> c_ulonglong {
 }
 
 #[inline]
-fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut CrateDebugContext {
+fn debug_context<'a>(cx: &'a mut CrateContext) -> &'a mut CrateDebugContext {
     cx.dbg_cx.get_mut_ref()
 }
 
@@ -1710,14 +2112,6 @@ fn DIB(cx: &CrateContext) -> DIBuilderRef {
     cx.dbg_cx.get_ref().builder
 }
 
-fn assert_fcx_has_span(fcx: &FunctionContext) {
-    if fcx.span.is_none() {
-        fcx.ccx.sess.bug(fmt!("debuginfo: Encountered function %s with invalid source span. \
-            This function should have been ignored by debuginfo generation.",
-            ast_map::path_to_str(fcx.path, fcx.ccx.sess.intr())));
-    }
-}
-
 fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
     match fcx.debug_context {
         FunctionDebugContext(_) => false,
@@ -1725,6 +2119,34 @@ fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
     }
 }
 
+fn assert_type_for_node_id(cx: &CrateContext, node_id: ast::NodeId, error_span: Span) {
+    if !cx.tcx.node_types.contains_key(&(node_id as uint)) {
+        cx.sess.span_bug(error_span, "debuginfo: Could not find type for node id!");
+    }
+}
+
+fn get_namespace_and_span_for_item(cx: &mut CrateContext,
+                                   def_id: ast::DefId,
+                                   warning_span: Span)
+                                -> (DIScope, Span) {
+    if def_id.crate == ast::LOCAL_CRATE {
+        let containing_scope = debug_context(cx).local_namespace_map.get_copy(&def_id.node).scope;
+        let definition_span = match cx.tcx.items.find(&def_id.node) {
+            Some(&ast_map::node_item(@ast::item { span, _ }, _)) => span,
+            ref node => {
+                cx.sess.span_warn(warning_span, fmt!("debuginfo::get_namespace_and_span_for_item() \
+                                                      - Unexpected node type: %?", *node));
+                codemap::dummy_sp()
+            }
+        };
+        (containing_scope, definition_span)
+    } else {
+        let item_path = ty::item_path(cx.tcx, def_id);
+        // For external items there is no span information
+        (namespace_for_external_item(cx, &item_path).scope, codemap::dummy_sp())
+    }
+}
+
 // This procedure builds the *scope map* for a given function, which maps any given ast::NodeId in
 // the function's AST to the correct DIScope metadata instance.
 //
@@ -1734,7 +2156,7 @@ fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
 // shadowing.
 fn populate_scope_map(cx: &mut CrateContext,
                       arg_pats: &[@ast::Pat],
-                      fn_entry_block: Option<&ast::Block>,
+                      fn_entry_block: &ast::Block,
                       fn_metadata: DISubprogram,
                       scope_map: &mut HashMap<ast::NodeId, DIScope>) {
     let def_map = cx.tcx.def_map;
@@ -1755,13 +2177,9 @@ struct ScopeStackEntry {
         }
     }
 
-    for &fn_entry_block in fn_entry_block.iter() {
-        walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
-    }
-
+    walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
 
     // local helper functions for walking the AST.
-
     fn with_new_scope(cx: &mut CrateContext,
                       scope_span: Span,
                       scope_stack: &mut ~[ScopeStackEntry],
@@ -2179,3 +2597,240 @@ fn walk_expr(cx: &mut CrateContext,
         }
     }
 }
+
+
+//=-------------------------------------------------------------------------------------------------
+// Namespace Handling
+//=-------------------------------------------------------------------------------------------------
+
+struct NamespaceTreeNode {
+    ident: ast::Ident,
+    scope: DIScope,
+    parent: Option<@NamespaceTreeNode>,
+}
+
+impl NamespaceTreeNode {
+    fn mangled_name_of_contained_item(&self, item_name: &str) -> ~str {
+        let mut name = ~"_ZN";
+        fill_nested(self, &mut name);
+
+        name.push_str(fmt!("%u%s", item_name.len(), item_name));
+        name.push_char('E');
+
+        return name;
+
+        fn fill_nested(node: &NamespaceTreeNode, output: &mut ~str) {
+            match node.parent {
+                Some(parent) => {
+                    fill_nested(parent, output);
+                }
+                None => {}
+            }
+            let name = token::ident_to_str(&node.ident);
+            output.push_str(fmt!("%u%s", name.len(), name));
+        }
+    }
+}
+
+fn namespace_for_external_item(cx: &mut CrateContext,
+                               item_path: &ast_map::path)
+                            -> @NamespaceTreeNode {
+    if item_path.len() < 2 {
+        cx.sess.bug(fmt!("debuginfo::namespace_for_external_item() - Invalid item_path: %s",
+            ast_map::path_to_str(*item_path, token::get_ident_interner())));
+    }
+
+    let path_excluding_item = item_path.slice_to(item_path.len() - 1);
+    let mut current_key = vec::with_capacity(path_excluding_item.len());
+    let mut parent_node: Option<@NamespaceTreeNode> = None;
+    let last_index = path_excluding_item.len() - 1;
+
+    for (i, &path_element) in path_excluding_item.iter().enumerate() {
+        let ident = match path_element {
+            ast_map::path_mod(ident)            |
+            ast_map::path_name(ident)           |
+            ast_map::path_pretty_name(ident, _) => ident
+        };
+
+        current_key.push(ident);
+
+        let existing_node = debug_context(cx).extern_namespaces.find_copy(&current_key);
+        let current_node = match existing_node {
+            Some(existing_node) => existing_node,
+            None => {
+                // create and insert
+                let parent_scope = match parent_node {
+                    Some(node) => node.scope,
+                    None => ptr::null()
+                };
+                let namespace_name = token::ident_to_str(&ident);
+
+                let namespace_metadata = unsafe {
+                    do namespace_name.with_c_str |namespace_name| {
+                        llvm::LLVMDIBuilderCreateNameSpace(
+                            DIB(cx),
+                            parent_scope,
+                            namespace_name,
+                            ptr::null(), // cannot reconstruct file ...
+                            0)           // ... or line information
+                    }
+                };
+
+                let node = @NamespaceTreeNode {
+                    ident: ident,
+                    scope: namespace_metadata,
+                    parent: parent_node,
+                };
+
+                debug_context(cx).extern_namespaces.insert(current_key.clone(), node);
+
+                node
+            }
+        };
+
+        if i == last_index {
+            return current_node;
+        } else {
+            parent_node = Some(current_node);
+        }
+    }
+
+    cx.sess.bug("debuginfo::namespace_for_external_item() - Code path should be unreachable");
+}
+
+struct NamespaceVisitor<'self> {
+    module_ident: ast::Ident,
+    scope_stack: ~[@NamespaceTreeNode],
+    crate_context: &'self mut CrateContext,
+}
+
+impl<'self> NamespaceVisitor<'self> {
+
+    fn new_crate_visitor<'a>(cx: &'a mut CrateContext,
+                             crate_ident: ast::Ident)
+                          -> NamespaceVisitor<'a> {
+        NamespaceVisitor {
+            module_ident: crate_ident,
+            scope_stack: ~[],
+            crate_context: cx,
+        }
+    }
+
+    fn new_function_visitor<'a>(cx: &'a mut CrateContext,
+                                function_name: &str,
+                                parent_node: Option<@NamespaceTreeNode>,
+                                file_metadata: DIFile,
+                                span: Span)
+                             -> NamespaceVisitor<'a> {
+        let companion_name = function_name + "()";
+        let companion_ident = token::str_to_ident(companion_name);
+        let parent_scope = match parent_node {
+            Some(parent_node) => parent_node.scope,
+            None => ptr::null()
+        };
+        let line = span_start(cx, span).line as c_uint;
+
+        let namespace_metadata = unsafe {
+            do companion_name.with_c_str |companion_name| {
+                llvm::LLVMDIBuilderCreateNameSpace(
+                    DIB(cx),
+                    parent_scope,
+                    companion_name,
+                    file_metadata,
+                    line)
+            }
+        };
+
+        let function_node = @NamespaceTreeNode {
+            scope: namespace_metadata,
+            ident: companion_ident,
+            parent: parent_node,
+        };
+
+        return NamespaceVisitor {
+            module_ident: special_idents::invalid,
+            scope_stack: ~[function_node],
+            crate_context: cx,
+        };
+    }
+}
+
+// Possible optimization: Only recurse if needed.
+impl<'self> visit::Visitor<()> for NamespaceVisitor<'self> {
+
+    fn visit_mod(&mut self,
+                 module: &ast::_mod,
+                 span: Span,
+                 _: ast::NodeId,
+                 _: ()) {
+        let module_name = token::ident_to_str(&self.module_ident);
+
+        let (parent_node, parent_scope) = if self.scope_stack.len() > 0 {
+            let parent_node = *self.scope_stack.last();
+            (Some(parent_node), parent_node.scope)
+        } else {
+            (None, ptr::null())
+        };
+
+        let loc = span_start(self.crate_context, span);
+        let file_metadata = file_metadata(self.crate_context, loc.file.name);
+
+        let namespace_metadata = unsafe {
+            do module_name.with_c_str |module_name| {
+                llvm::LLVMDIBuilderCreateNameSpace(
+                    DIB(self.crate_context),
+                    parent_scope,
+                    module_name,
+                    file_metadata,
+                    loc.line as c_uint)
+            }
+        };
+
+        let this_node = @NamespaceTreeNode {
+            scope: namespace_metadata,
+            ident: self.module_ident,
+            parent: parent_node,
+        };
+
+        self.scope_stack.push(this_node);
+
+        visit::walk_mod(self, module, ());
+
+        self.scope_stack.pop();
+    }
+
+    fn visit_item(&mut self, item: @ast::item, _: ()) {
+        match item.node {
+            ast::item_mod(*) => {
+                // always store the last module ident so visit_mod() has it available
+                self.module_ident = item.ident;
+            }
+            ast::item_fn(*) => { /* handled by visit_fn */ }
+            _ => {
+                debug_context(self.crate_context)
+                    .local_namespace_map
+                    .insert(item.id, *self.scope_stack.last());
+            }
+        }
+
+        visit::walk_item(self, item, ());
+    }
+
+    fn visit_foreign_item(&mut self, item: @ast::foreign_item, _: ()) {
+        debug_context(self.crate_context)
+            .local_namespace_map
+            .insert(item.id, *self.scope_stack.last());
+    }
+
+    fn visit_fn(&mut self,
+                _: &visit::fn_kind,
+                _: &ast::fn_decl,
+                _: &ast::Block,
+                _: Span,
+                node_id: ast::NodeId,
+                _: ()) {
+        debug_context(self.crate_context)
+            .local_namespace_map
+            .insert(node_id, *self.scope_stack.last());
+    }
+}
index ea9e47416c1c58b9e3d9818d881d3e5d8c72a21e..b351fe91e6f1c859c644272ce71d66437b9e80d1 100644 (file)
@@ -782,7 +782,7 @@ fn trans_def_dps_unadjusted(bcx: @mut Block, ref_expr: &ast::Expr,
     };
 
     match def {
-        ast::DefVariant(tid, vid) => {
+        ast::DefVariant(tid, vid, _) => {
             let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
             if variant_info.args.len() > 0u {
                 // N-ary variant.
@@ -1140,7 +1140,7 @@ pub fn with_field_tys<R>(tcx: ty::ctxt,
                 }
                 Some(node_id) => {
                     match tcx.def_map.get_copy(&node_id) {
-                        ast::DefVariant(enum_id, variant_id) => {
+                        ast::DefVariant(enum_id, variant_id, _) => {
                             let variant_info = ty::enum_variant_with_id(
                                 tcx, enum_id, variant_id);
                             op(variant_info.disr_val,
index 26968ce4881725e3cc81bfd9c006d428e9ebd9fd..87755b4431c0eb52bb059b479baac9c90ccbf4ba 100644 (file)
@@ -11,7 +11,7 @@
 
 use back::{link};
 use std::libc::c_uint;
-use lib::llvm::{ValueRef, Attribute, CallConv};
+use lib::llvm::{ValueRef, Attribute, CallConv, StructRetAttribute};
 use lib::llvm::llvm;
 use lib;
 use middle::trans::machine;
@@ -266,7 +266,13 @@ pub fn trans_native_call(bcx: @mut Block,
         }
     };
 
-    let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc);
+    let attrs;
+    if fn_type.sret {
+        attrs = &[(1, StructRetAttribute)];
+    } else {
+        attrs = &[];
+    }
+    let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc, attrs);
 
     // If the function we just called does not use an outpointer,
     // store the result into the rust outpointer. Cast the outpointer
index 910d743d182193e013ce5560ffa1a4fe696a0fb2..1958d3c9adb4f6b1f13101421061490d4712247c 100644 (file)
@@ -332,7 +332,7 @@ pub fn call_tydesc_glue_full(bcx: @mut Block,
         }
     };
 
-    Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr]);
+    Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr], []);
 }
 
 // See [Note-arg-mode]
@@ -424,7 +424,7 @@ pub fn trans_struct_drop_flag(bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did:
         let self_arg = PointerCast(bcx, v0, params[0]);
         let args = ~[self_arg];
 
-        Call(bcx, dtor_addr, args);
+        Call(bcx, dtor_addr, args, []);
 
         // Drop the fields
         let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
@@ -459,7 +459,7 @@ pub fn trans_struct_drop(mut bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did:
     let self_arg = PointerCast(bcx, v0, params[0]);
     let args = ~[self_arg];
 
-    Call(bcx, dtor_addr, args);
+    Call(bcx, dtor_addr, args, []);
 
     // Drop the fields
     let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
index 2232b8966b8695bd938e5e19e24e46570eb2fbbb..d17773d3302f1f480c949520c06c39548e1c6509 100644 (file)
@@ -49,7 +49,7 @@ fn simple_llvm_intrinsic(bcx: @mut Block, name: &'static str, num_args: uint) {
             args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
         }
         let llfn = bcx.ccx().intrinsics.get_copy(&name);
-        Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
+        Ret(bcx, Call(bcx, llfn, args.slice(0, num_args), []));
     }
 
     fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
@@ -59,7 +59,7 @@ fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
         let llfn = bcx.ccx().intrinsics.get_copy(&name);
 
         // convert `i1` to a `bool`, and write to the out parameter
-        let val = Call(bcx, llfn, [a, b]);
+        let val = Call(bcx, llfn, [a, b], []);
         let result = ExtractValue(bcx, val, 0);
         let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
         let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
@@ -87,7 +87,7 @@ fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits:
         let count = get_param(decl, first_real_arg + 2);
         let volatile = C_i1(false);
         let llfn = bcx.ccx().intrinsics.get_copy(&name);
-        Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
+        Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile], []);
         RetVoid(bcx);
     }
 
@@ -108,7 +108,7 @@ fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits:
         let count = get_param(decl, first_real_arg + 2);
         let volatile = C_i1(false);
         let llfn = bcx.ccx().intrinsics.get_copy(&name);
-        Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
+        Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile], []);
         RetVoid(bcx);
     }
 
@@ -116,7 +116,7 @@ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
         let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
         let y = C_i1(false);
         let llfn = bcx.ccx().intrinsics.get_copy(&name);
-        Ret(bcx, Call(bcx, llfn, [x, y]));
+        Ret(bcx, Call(bcx, llfn, [x, y], []));
     }
 
     let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
@@ -366,7 +366,7 @@ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
         }
         "frame_address" => {
             let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
-            let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)]);
+            let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)], []);
             let star_u8 = ty::mk_imm_ptr(
                 bcx.tcx(),
                 ty::mk_mach_uint(ast::ty_u8));
@@ -402,11 +402,6 @@ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
             Ret(bcx, morestack_addr);
         }
         "offset" => {
-            let ptr = get_param(decl, first_real_arg);
-            let offset = get_param(decl, first_real_arg + 1);
-            Ret(bcx, GEP(bcx, ptr, [offset]));
-        }
-        "offset_inbounds" => {
             let ptr = get_param(decl, first_real_arg);
             let offset = get_param(decl, first_real_arg + 1);
             Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
index 08b2db6eff9bc212e129c6e7c6e495fb3093301e..a33f2bd3a557ef9c5b891ff6cdaedb05c69fe804 100644 (file)
@@ -50,9 +50,9 @@ pub fn erase_from_parent(self) {
     /// must be the only user of this value, and there must not be any conditional
     /// branches between the store and the given block.
     pub fn get_dominating_store(self, bcx: @mut Block) -> Option<Value> {
-        match self.get_single_user().chain(|user| user.as_store_inst()) {
+        match self.get_single_user().and_then(|user| user.as_store_inst()) {
             Some(store) => {
-                do store.get_parent().chain |store_bb| {
+                do store.get_parent().and_then |store_bb| {
                     let mut bb = BasicBlock(bcx.llbb);
                     let mut ret = Some(store);
                     while *bb != *store_bb {
@@ -150,7 +150,7 @@ impl Iterator<Value> for UserIterator {
     fn next(&mut self) -> Option<Value> {
         let current = self.next;
 
-        self.next = do current.chain |u| { u.get_next_use() };
+        self.next = do current.and_then |u| { u.get_next_use() };
 
         do current.map |u| { u.get_user() }
     }
index a438953be4284eaf5a0db70d00dcd25329b0a66c..9abee133290f10ff5761d3d472135670e4cc8cb7 100644 (file)
@@ -156,7 +156,7 @@ pub enum SelfMode {
 }
 
 pub struct field_ty {
-    ident: Ident,
+    name: Name,
     id: DefId,
     vis: ast::visibility,
 }
@@ -1757,7 +1757,7 @@ fn type_is_newtype_immediate(cx: ctxt, ty: t) -> bool {
         ty_struct(def_id, ref substs) => {
             let fields = struct_fields(cx, def_id, substs);
             fields.len() == 1 &&
-                fields[0].ident == token::special_idents::unnamed_field &&
+                fields[0].ident.name == token::special_idents::unnamed_field.name &&
                 type_is_immediate(cx, fields[0].mt.ty)
         }
         _ => false
@@ -3630,7 +3630,7 @@ pub fn note_and_explain_type_err(cx: ctxt, err: &type_err) {
 
 pub fn def_has_ty_params(def: ast::Def) -> bool {
     match def {
-      ast::DefFn(_, _) | ast::DefVariant(_, _) | ast::DefStruct(_)
+      ast::DefFn(_, _) | ast::DefVariant(_, _, _) | ast::DefStruct(_)
         => true,
       _ => false
     }
@@ -3840,7 +3840,6 @@ impl VariantInfo {
     pub fn from_ast_variant(cx: ctxt,
                             ast_variant: &ast::variant,
                             discriminant: Disr) -> VariantInfo {
-
         let ctor_ty = node_id_to_type(cx, ast_variant.node.id);
 
         match ast_variant.node.kind {
@@ -4228,15 +4227,15 @@ fn struct_field_tys(fields: &[@struct_field]) -> ~[field_ty] {
         match field.node.kind {
             named_field(ident, visibility) => {
                 field_ty {
-                    ident: ident,
+                    name: ident.name,
                     id: ast_util::local_def(field.node.id),
                     vis: visibility,
                 }
             }
             unnamed_field => {
                 field_ty {
-                    ident:
-                        syntax::parse::token::special_idents::unnamed_field,
+                    name:
+                        syntax::parse::token::special_idents::unnamed_field.name,
                     id: ast_util::local_def(field.node.id),
                     vis: ast::public,
                 }
@@ -4251,7 +4250,8 @@ pub fn struct_fields(cx: ctxt, did: ast::DefId, substs: &substs)
                      -> ~[field] {
     do lookup_struct_fields(cx, did).map |f| {
        field {
-            ident: f.ident,
+            // FIXME #6993: change type of field to Name and get rid of new()
+            ident: ast::Ident::new(f.name),
             mt: mt {
                 ty: lookup_field_type(cx, did, f.id, substs),
                 mutbl: MutImmutable
@@ -4267,6 +4267,7 @@ pub fn is_binopable(cx: ctxt, ty: t, op: ast::BinOp) -> bool {
     static tycat_int: int = 3;
     static tycat_float: int = 4;
     static tycat_bot: int = 5;
+    static tycat_raw_ptr: int = 6;
 
     static opcat_add: int = 0;
     static opcat_sub: int = 1;
@@ -4310,6 +4311,7 @@ fn tycat(cx: ctxt, ty: t) -> int {
           ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
           ty_float(_) | ty_infer(FloatVar(_)) => tycat_float,
           ty_bot => tycat_bot,
+          ty_ptr(_) => tycat_raw_ptr,
           _ => tycat_other
         }
     }
@@ -4324,7 +4326,8 @@ fn tycat(cx: ctxt, ty: t) -> int {
     /*char*/    [f, f, f, f,     t,   t,  f,   f],
     /*int*/     [t, t, t, t,     t,   t,  t,   f],
     /*float*/   [t, t, t, f,     t,   t,  f,   f],
-    /*bot*/     [t, t, t, t,     f,   f,  t,   t]];
+    /*bot*/     [t, t, t, t,     t,   t,  t,   t],
+    /*raw ptr*/ [f, f, f, f,     t,   t,  f,   f]];
 
     return tbl[tycat(cx, ty)][opcat(op)];
 }
index c5f85d26e44673cb628cd24598d82d048c02f39f..36405136e630ffedc4a94503039cff61acdb86b4 100644 (file)
@@ -745,7 +745,7 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
                           RegionParamNames(bound_lifetime_names.clone()));
 
     let input_tys = do decl.inputs.iter().enumerate().map |(i, a)| {
-        let expected_arg_ty = do expected_sig.chain_ref |e| {
+        let expected_arg_ty = do expected_sig.and_then_ref |e| {
             // no guarantee that the correct number of expected args
             // were supplied
             if i < e.inputs.len() {Some(e.inputs[i])} else {None}
index d813f97312340d58b9a9ba721b897ddc46a42985..061921e60e1257602cc0b5fde6ea55c0fdd7dc21 100644 (file)
@@ -21,6 +21,7 @@
 use std::hashmap::{HashMap, HashSet};
 use syntax::ast;
 use syntax::ast_util;
+use syntax::parse::token;
 use syntax::codemap::Span;
 use syntax::print::pprust;
 
@@ -172,7 +173,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::Pat, path: &ast::Path,
                     fcx.write_error(pat.id);
                     kind_name = "[error]";
                     arg_types = (*subpats).clone()
-                                          .unwrap_or_default(~[])
+                                          .unwrap_or_default()
                                           .map(|_| ty::mk_err());
                 }
             }
@@ -221,7 +222,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::Pat, path: &ast::Path,
             fcx.write_error(pat.id);
             kind_name = "[error]";
             arg_types = (*subpats).clone()
-                                  .unwrap_or_default(~[])
+                                  .unwrap_or_default()
                                   .map(|_| ty::mk_err());
         }
     }
@@ -296,7 +297,7 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
     // Index the class fields.
     let mut field_map = HashMap::new();
     for (i, class_field) in class_fields.iter().enumerate() {
-        field_map.insert(class_field.ident.name, i);
+        field_map.insert(class_field.name, i);
     }
 
     // Typecheck each field.
@@ -333,7 +334,7 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
             }
             tcx.sess.span_err(span,
                               fmt!("pattern does not mention field `%s`",
-                                   tcx.sess.str_of(field.ident)));
+                                   token::interner_get(field.name)));
         }
     }
 }
@@ -384,7 +385,7 @@ pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
 
     // Find the variant that was specified.
     match tcx.def_map.find(&pat_id) {
-        Some(&ast::DefVariant(found_enum_id, variant_id))
+        Some(&ast::DefVariant(found_enum_id, variant_id, _))
                 if found_enum_id == enum_id => {
             // Get the struct fields from this struct-like enum variant.
             let class_fields = ty::lookup_struct_fields(tcx, variant_id);
index b6e0fd93fa9bb7f2d76c5f651c535c3247c8843a..b689090d3fd3e659a44ee8bd7fffa8d166a65db9 100644 (file)
@@ -200,7 +200,7 @@ pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
 
             purity => {
                 let (purity, def) = match blk.rules {
-                    ast::UnsafeBlock => (ast::unsafe_fn, blk.id),
+                    ast::UnsafeBlock(*) => (ast::unsafe_fn, blk.id),
                     ast::DefaultBlock => (purity, self.def),
                 };
                 PurityState{ def: def,
@@ -1120,7 +1120,7 @@ pub fn lookup_field_ty(tcx: ty::ctxt,
                        fieldname: ast::Name,
                        substs: &ty::substs) -> Option<ty::t> {
 
-    let o_field = items.iter().find(|f| f.ident.name == fieldname);
+    let o_field = items.iter().find(|f| f.name == fieldname);
     do o_field.map() |f| {
         ty::lookup_field_type(tcx, class_id, f.id, substs)
     }
@@ -2018,7 +2018,7 @@ fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
         let mut class_field_map = HashMap::new();
         let mut fields_found = 0;
         for field in field_types.iter() {
-            class_field_map.insert(field.ident.name, (field.id, false));
+            class_field_map.insert(field.name, (field.id, false));
         }
 
         let mut error_happened = false;
@@ -2070,7 +2070,7 @@ fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
             if fields_found < field_types.len() {
                 let mut missing_fields = ~[];
                 for class_field in field_types.iter() {
-                    let name = class_field.ident.name;
+                    let name = class_field.name;
                     let (_, seen) = *class_field_map.get(&name);
                     if !seen {
                         missing_fields.push(
@@ -2825,7 +2825,7 @@ fn types_compatible(fcx: @mut FnCtxt, sp: Span,
                 check_struct_constructor(fcx, id, expr.span, type_def_id,
                                          *fields, base_expr);
             }
-            Some(&ast::DefVariant(enum_id, variant_id)) => {
+            Some(&ast::DefVariant(enum_id, variant_id, _)) => {
                 check_struct_enum_variant(fcx, id, expr.span, enum_id,
                                           variant_id, *fields);
             }
@@ -3256,7 +3256,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
           return no_params(typ);
       }
       ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
-      ast::DefStatic(id, _) | ast::DefVariant(_, id) |
+      ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
       ast::DefStruct(id) => {
         return ty::lookup_item_type(fcx.ccx.tcx, id);
       }
index 9fc29250ed052f79f8ffa53aacded07236d875cd..cdfb8732a38aaa29962c1b1b27a5274409bf912e 100644 (file)
@@ -15,7 +15,7 @@
 // the trait `Combine` and contains methods for combining two
 // instances of various things and yielding a new instance.  These
 // combiner methods always yield a `result<T>`---failure is propagated
-// upward using `chain()` methods.  There is a lot of common code for
+// upward using `and_then()` methods.  There is a lot of common code for
 // these operations, implemented as default methods on the `Combine`
 // trait.
 //
@@ -108,7 +108,7 @@ fn self_tys(&self, a: Option<ty::t>, b: Option<ty::t>)
             (Some(a), Some(b)) => {
                 // FIXME(#5781) this should be eq_tys
                 // eq_tys(self, a, b).then(|| Ok(Some(a)) )
-                self.contratys(a, b).chain(|t| Ok(Some(t)))
+                self.contratys(a, b).and_then(|t| Ok(Some(t)))
             }
             (None, Some(_)) |
                 (Some(_), None) => {
@@ -162,13 +162,13 @@ fn relate_region_params<C:Combine>(
                                 }
 
                                 ty::rv_covariant => {
-                                    do this.regions(a_r, b_r).chain |r| {
+                                    do this.regions(a_r, b_r).and_then |r| {
                                         Ok(ty::NonerasedRegions(opt_vec::with(r)))
                                     }
                                 }
 
                                 ty::rv_contravariant => {
-                                    do this.contraregions(a_r, b_r).chain |r| {
+                                    do this.contraregions(a_r, b_r).and_then |r| {
                                         Ok(ty::NonerasedRegions(opt_vec::with(r)))
                                     }
                                 }
@@ -179,12 +179,12 @@ fn relate_region_params<C:Combine>(
             }
         }
 
-        do self.tps(as_.tps, bs.tps).chain |tps| {
-            do self.self_tys(as_.self_ty, bs.self_ty).chain |self_ty| {
+        do self.tps(as_.tps, bs.tps).and_then |tps| {
+            do self.self_tys(as_.self_ty, bs.self_ty).and_then |self_ty| {
                 do relate_region_params(self,
                                         generics,
                                         &as_.regions,
-                                        &bs.regions).chain |regions| {
+                                        &bs.regions).and_then |regions| {
                     Ok(substs {
                             regions: regions,
                             self_ty: self_ty,
@@ -227,8 +227,8 @@ fn closure_tys(&self, a: &ty::ClosureTy,
     fn flds(&self, a: ty::field, b: ty::field) -> cres<ty::field> {
         if a.ident == b.ident {
             self.mts(&a.mt, &b.mt)
-                .chain(|mt| Ok(ty::field {ident: a.ident, mt: mt}) )
-                .chain_err(|e| Err(ty::terr_in_field(@e, a.ident)) )
+                .and_then(|mt| Ok(ty::field {ident: a.ident, mt: mt}) )
+                .or_else(|e| Err(ty::terr_in_field(@e, a.ident)) )
         } else {
             Err(ty::terr_record_fields(
                                        expected_found(self,
@@ -238,7 +238,7 @@ fn flds(&self, a: ty::field, b: ty::field) -> cres<ty::field> {
     }
 
     fn args(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
-        do self.contratys(a, b).chain |t| {
+        do self.contratys(a, b).and_then |t| {
             Ok(t)
         }
     }
@@ -274,7 +274,7 @@ fn vstores(&self, vk: ty::terr_vstore_kind,
 
         match (a, b) {
             (ty::vstore_slice(a_r), ty::vstore_slice(b_r)) => {
-                do self.contraregions(a_r, b_r).chain |r| {
+                do self.contraregions(a_r, b_r).and_then |r| {
                     Ok(ty::vstore_slice(r))
                 }
             }
@@ -299,7 +299,7 @@ fn trait_stores(&self,
 
         match (a, b) {
             (ty::RegionTraitStore(a_r), ty::RegionTraitStore(b_r)) => {
-                do self.contraregions(a_r, b_r).chain |r| {
+                do self.contraregions(a_r, b_r).and_then |r| {
                     Ok(ty::RegionTraitStore(r))
                 }
             }
@@ -357,7 +357,7 @@ pub fn expected_found<C:Combine,T>(
 pub fn eq_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> ures {
     let suber = this.sub();
     do this.infcx().try {
-        do suber.tys(a, b).chain |_ok| {
+        do suber.tys(a, b).and_then |_ok| {
             suber.contratys(a, b)
         }.to_ures()
     }
@@ -371,10 +371,10 @@ pub fn eq_regions<C:Combine>(this: &C, a: ty::Region, b: ty::Region)
     let sub = this.sub();
     do indent {
         this.infcx().try(|| {
-            do sub.regions(a, b).chain |_r| {
+            do sub.regions(a, b).and_then |_r| {
                 sub.contraregions(a, b)
             }
-        }).chain_err(|e| {
+        }).or_else(|e| {
             // substitute a better error, but use the regions
             // found in the original error
             match e {
@@ -427,8 +427,8 @@ fn argvecs<C:Combine>(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<~[ty
     }
 
     do argvecs(this, a.inputs, b.inputs)
-            .chain |inputs| {
-        do this.tys(a.output, b.output).chain |output| {
+            .and_then |inputs| {
+        do this.tys(a.output, b.output).and_then |output| {
             Ok(FnSig {bound_lifetime_names: opt_vec::Empty, // FIXME(#4846)
                       inputs: inputs.clone(),
                       output: output})
@@ -508,7 +508,7 @@ pub fn super_tys<C:Combine>(
        &ty::ty_enum(b_id, ref b_substs))
       if a_id == b_id => {
           let type_def = ty::lookup_item_type(tcx, a_id);
-          do this.substs(&type_def.generics, a_substs, b_substs).chain |substs| {
+          do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| {
               Ok(ty::mk_enum(tcx, a_id, substs))
           }
       }
@@ -517,9 +517,9 @@ pub fn super_tys<C:Combine>(
        &ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds))
       if a_id == b_id && a_mutbl == b_mutbl => {
           let trait_def = ty::lookup_trait_def(tcx, a_id);
-          do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| {
-              do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| {
-                  do this.bounds(a_bounds, b_bounds).chain |bounds| {
+          do this.substs(&trait_def.generics, a_substs, b_substs).and_then |substs| {
+              do this.trait_stores(ty::terr_trait, a_store, b_store).and_then |s| {
+                  do this.bounds(a_bounds, b_bounds).and_then |bounds| {
                     Ok(ty::mk_trait(tcx,
                                     a_id,
                                     substs.clone(),
@@ -534,25 +534,25 @@ pub fn super_tys<C:Combine>(
       (&ty::ty_struct(a_id, ref a_substs), &ty::ty_struct(b_id, ref b_substs))
       if a_id == b_id => {
           let type_def = ty::lookup_item_type(tcx, a_id);
-          do this.substs(&type_def.generics, a_substs, b_substs).chain |substs| {
+          do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| {
               Ok(ty::mk_struct(tcx, a_id, substs))
           }
       }
 
       (&ty::ty_box(ref a_mt), &ty::ty_box(ref b_mt)) => {
-        do this.mts(a_mt, b_mt).chain |mt| {
+        do this.mts(a_mt, b_mt).and_then |mt| {
             Ok(ty::mk_box(tcx, mt))
         }
       }
 
       (&ty::ty_uniq(ref a_mt), &ty::ty_uniq(ref b_mt)) => {
-        do this.mts(a_mt, b_mt).chain |mt| {
+        do this.mts(a_mt, b_mt).and_then |mt| {
             Ok(ty::mk_uniq(tcx, mt))
         }
       }
 
       (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
-        do this.mts(a_mt, b_mt).chain |mt| {
+        do this.mts(a_mt, b_mt).and_then |mt| {
             Ok(ty::mk_ptr(tcx, mt))
         }
       }
@@ -564,15 +564,15 @@ pub fn super_tys<C:Combine>(
       }
 
       (&ty::ty_evec(ref a_mt, vs_a), &ty::ty_evec(ref b_mt, vs_b)) => {
-        do this.mts(a_mt, b_mt).chain |mt| {
-            do this.vstores(ty::terr_vec, vs_a, vs_b).chain |vs| {
+        do this.mts(a_mt, b_mt).and_then |mt| {
+            do this.vstores(ty::terr_vec, vs_a, vs_b).and_then |vs| {
                 Ok(ty::mk_evec(tcx, mt, vs))
             }
         }
       }
 
       (&ty::ty_estr(vs_a), &ty::ty_estr(vs_b)) => {
-        do this.vstores(ty::terr_str, vs_a, vs_b).chain |vs| {
+        do this.vstores(ty::terr_str, vs_a, vs_b).and_then |vs| {
             Ok(ty::mk_estr(tcx,vs))
         }
       }
@@ -581,7 +581,7 @@ pub fn super_tys<C:Combine>(
         if as_.len() == bs.len() {
             result::collect(as_.iter().zip(bs.iter())
                             .map(|(a, b)| this.tys(*a, *b)))
-                    .chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
+                    .and_then(|ts| Ok(ty::mk_tup(tcx, ts)) )
         } else {
             Err(ty::terr_tuple_size(
                 expected_found(this, as_.len(), bs.len())))
@@ -589,13 +589,13 @@ pub fn super_tys<C:Combine>(
       }
 
       (&ty::ty_bare_fn(ref a_fty), &ty::ty_bare_fn(ref b_fty)) => {
-        do this.bare_fn_tys(a_fty, b_fty).chain |fty| {
+        do this.bare_fn_tys(a_fty, b_fty).and_then |fty| {
             Ok(ty::mk_bare_fn(tcx, fty))
         }
       }
 
       (&ty::ty_closure(ref a_fty), &ty::ty_closure(ref b_fty)) => {
-        do this.closure_tys(a_fty, b_fty).chain |fty| {
+        do this.closure_tys(a_fty, b_fty).and_then |fty| {
             Ok(ty::mk_closure(tcx, fty))
         }
       }
index 1939987d7f0784885f2cc010526442867b3448ff..af62da5fde03333fb5475c8af3150dffce26eae9 100644 (file)
@@ -61,7 +61,7 @@ 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 `MutImmutable`.
           (MutImmutable, MutImmutable) => {
-            self.tys(a.ty, b.ty).chain(|t| {
+            self.tys(a.ty, b.ty).and_then(|t| {
                 Ok(ty::mt {ty: t, mutbl: MutImmutable})
             })
           }
index 0ed30bb61b9f364050315ece1603a85b27251ec8..4cbdf9fa1fb8bc2f9ece3c7e890b00de63701a46 100644 (file)
@@ -232,7 +232,7 @@ fn merge_bnd<T:Clone + InferStr + LatticeValue>(
             (&Some(_),       &None) => Ok((*a).clone()),
             (&None,          &Some(_)) => Ok((*b).clone()),
             (&Some(ref v_a), &Some(ref v_b)) => {
-                do lattice_op(self, v_a, v_b).chain |v| {
+                do lattice_op(self, v_a, v_b).and_then |v| {
                     Ok(Some(v))
                 }
             }
index db5873f09fe2ca70b616dae833927c9eae64d012..260bc93611e963ffef7f42fd93e0d1e0235cd1b1 100644 (file)
@@ -62,7 +62,7 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
         let m = a.mutbl;
         match m {
           MutImmutable => {
-            self.tys(a.ty, b.ty).chain(|t| Ok(ty::mt {ty: t, mutbl: m}) )
+            self.tys(a.ty, b.ty).and_then(|t| Ok(ty::mt {ty: t, mutbl: m}) )
           }
 
           MutMutable => {
@@ -70,7 +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| Err(e))
+            }).or_else(|e| Err(e))
           }
         }
     }
index a2d2cd92e135ab2d6976fd1c95911500f5c92bca..e73a36de143cca925f318e91ddfbb7bc21121d85 100644 (file)
@@ -451,7 +451,7 @@ fn then<T:Clone>(&self, f: &fn() -> Result<T,ty::type_err>)
 impl then for ures {
     fn then<T:Clone>(&self, f: &fn() -> Result<T,ty::type_err>)
         -> Result<T,ty::type_err> {
-        self.chain(|_i| f())
+        self.and_then(|_i| f())
     }
 }
 
@@ -474,7 +474,7 @@ trait CresCompare<T> {
 
 impl<T:Clone + Eq> CresCompare<T> for cres<T> {
     fn compare(&self, t: T, f: &fn() -> ty::type_err) -> cres<T> {
-        do (*self).clone().chain |s| {
+        do (*self).clone().and_then |s| {
             if s == t {
                 (*self).clone()
             } else {
index 36c5f8a50d28ab5c4ded6f1c5b432ed3cd002457..57ebb2185d16587f3bb395423206342a8f22f10c 100644 (file)
@@ -79,7 +79,7 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
           }
           MutImmutable => {
             // Otherwise we can be covariant:
-            self.tys(a.ty, b.ty).chain(|_t| Ok(*a) )
+            self.tys(a.ty, b.ty).and_then(|_t| Ok(*a) )
           }
         }
     }
index d3dc3d1fb1c9abf6a732a15dc59fbcf92cd963cf..1967122745dad5ebfaa98895dbebd991fd0fa8fd 100644 (file)
@@ -202,7 +202,7 @@ fn named_region(&self, span: Span, id: ast::Ident)
         if !self.region_param_names.has_ident(id) {
             return RegionParamNames::undeclared_name(None);
         }
-        do EmptyRscope.named_region(span, id).chain_err |_e| {
+        do EmptyRscope.named_region(span, id).or_else |_e| {
             result::Err(RegionError {
                 msg: ~"lifetime is not in scope",
                 replacement: ty::re_bound(ty::br_self)
@@ -251,7 +251,7 @@ fn self_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
     }
     fn named_region(&self, span: Span, id: ast::Ident)
                       -> Result<ty::Region, RegionError> {
-        do EmptyRscope.named_region(span, id).chain_err |_e| {
+        do EmptyRscope.named_region(span, id).or_else |_e| {
             result::Err(RegionError {
                 msg: ~"only 'self is allowed as part of a type declaration",
                 replacement: self.replacement()
@@ -310,7 +310,7 @@ fn named_region(&self,
                     span: Span,
                     id: ast::Ident) -> Result<ty::Region, RegionError>
     {
-        do self.base.named_region(span, id).chain_err |_e| {
+        do self.base.named_region(span, id).or_else |_e| {
             let result = ty::re_bound(ty::br_named(id));
             if self.region_param_names.has_ident(id) {
                 result::Ok(result)
index 8c1394618e3054976285dc08cb7b3d7c4a044640..9350bf8d3d9ad87b5b6e1c05187e6417ac6feec3 100644 (file)
@@ -235,7 +235,7 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st
     }
 }
 
-fn mutability_to_str(m: ast::Mutability) -> ~str {
+pub fn mutability_to_str(m: ast::Mutability) -> ~str {
     match m {
         ast::MutMutable => ~"mut ",
         ast::MutImmutable => ~"",
index 2e7c73d34215eafb33347b4b65a1f56d7ec47a19..bd8d9a65cd33d666037b54bcf1739ce88966777b 100644 (file)
@@ -68,7 +68,7 @@ fn fold_crate(
     doc::CrateDoc {
         topmod: doc::ModDoc {
             item: doc::ItemDoc {
-                name: attrs.name.clone().unwrap_or_default(doc.topmod.name_()),
+                name: attrs.name.clone().unwrap_or(doc.topmod.name_()),
                 .. doc.topmod.item.clone()
             },
             .. doc.topmod.clone()
index e6d80e1443bb92cea18a7f06300aed85418690d2..ff6401456b6b9965d37616b3d870ce698544606a 100644 (file)
@@ -138,18 +138,18 @@ fn config_from_opts(
 
     let config = default_config(input_crate);
     let result = result::Ok(config);
-    let result = do result.chain |config| {
+    let result = do result.and_then |config| {
         let output_dir = getopts::opt_maybe_str(matches, opt_output_dir());
         let output_dir = output_dir.map_move(|s| Path(s));
         result::Ok(Config {
-            output_dir: output_dir.unwrap_or_default(config.output_dir.clone()),
+            output_dir: output_dir.unwrap_or(config.output_dir.clone()),
             .. config
         })
     };
-    let result = do result.chain |config| {
+    let result = do result.and_then |config| {
         let output_format = getopts::opt_maybe_str(matches, opt_output_format());
         do output_format.map_move_default(result::Ok(config.clone())) |output_format| {
-            do parse_output_format(output_format).chain |output_format| {
+            do parse_output_format(output_format).and_then |output_format| {
                 result::Ok(Config {
                     output_format: output_format,
                     .. config.clone()
@@ -157,11 +157,11 @@ fn config_from_opts(
             }
         }
     };
-    let result = do result.chain |config| {
+    let result = do result.and_then |config| {
         let output_style =
             getopts::opt_maybe_str(matches, opt_output_style());
         do output_style.map_move_default(result::Ok(config.clone())) |output_style| {
-            do parse_output_style(output_style).chain |output_style| {
+            do parse_output_style(output_style).and_then |output_style| {
                 result::Ok(Config {
                     output_style: output_style,
                     .. config.clone()
@@ -170,11 +170,11 @@ fn config_from_opts(
         }
     };
     let process_output = Cell::new(process_output);
-    let result = do result.chain |config| {
+    let result = do result.and_then |config| {
         let pandoc_cmd = getopts::opt_maybe_str(matches, opt_pandoc_cmd());
         let pandoc_cmd = maybe_find_pandoc(
             &config, pandoc_cmd, process_output.take());
-        do pandoc_cmd.chain |pandoc_cmd| {
+        do pandoc_cmd.and_then |pandoc_cmd| {
             result::Ok(Config {
                 pandoc_cmd: pandoc_cmd,
                 .. config.clone()
index 5bd941759f4d7e81c1473dac3c66335500de2f8b..8d61a971157fc35e69687b423794dac6c797753e 100644 (file)
@@ -355,12 +355,12 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
 /// None if no input was read (e.g. EOF was reached).
 fn get_line(use_rl: bool, prompt: &str) -> Option<~str> {
     if use_rl {
-        let result = unsafe { rl::read(prompt) };
+        let result = rl::read(prompt);
 
         match result {
             None => None,
             Some(line) => {
-                unsafe { rl::add_history(line) };
+                rl::add_history(line);
                 Some(line)
             }
         }
@@ -525,14 +525,12 @@ pub fn main_args(args: &[~str]) {
         println("unstable. If you encounter problems, please use the");
         println("compiler instead. Type :help for help.");
 
-        unsafe {
-            do rl::complete |line, suggest| {
-                if line.starts_with(":") {
-                    suggest(~":clear");
-                    suggest(~":exit");
-                    suggest(~":help");
-                    suggest(~":load");
-                }
+        do rl::complete |line, suggest| {
+            if line.starts_with(":") {
+                suggest(~":clear");
+                suggest(~":exit");
+                suggest(~":help");
+                suggest(~":load");
             }
         }
     }
index 4de2572be7d5e2ac6c0bac04197552e7c40baacd..727bbcb30b4c51f6bf5a07430df1d5db126b311a 100644 (file)
@@ -29,6 +29,8 @@ pub fn default_context(p: Path) -> BuildContext {
 pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
     BuildContext {
         context: Context {
+            cfgs: ~[],
+            rustc_flags: RustcFlags::default(),
             use_rust_path_hack: false,
             sysroot: p
         },
@@ -44,7 +46,6 @@ fn binary_is_fresh(path: &str, in_hash: &str) -> bool {
     in_hash == digest_only_date(&Path(path))
 }
 
-
 pub fn new_workcache_context(p: &Path) -> workcache::Context {
     let db_file = p.push("rustpkg_db.json"); // ??? probably wrong
     debug!("Workcache database file: %s", db_file.to_str());
index 2c6454cd2c664f6d812adc19d3dd9cf9ae4b17b9..1b1f3f14214fdc69567c114cd8d56873176d3eb1 100644 (file)
 
 // Context data structure used by rustpkg
 
-use std::os;
+use std::{io, os};
 use extra::workcache;
+use rustc::driver::session::{OptLevel, No};
 
 #[deriving(Clone)]
 pub struct Context {
+    // Config strings that the user passed in with --cfg
+    cfgs: ~[~str],
+    // Flags to pass to rustc
+    rustc_flags: RustcFlags,
     // If use_rust_path_hack is true, rustpkg searches for sources
     // in *package* directories that are in the RUST_PATH (for example,
     // FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
@@ -40,15 +45,82 @@ pub fn sysroot(&self) -> Path {
     pub fn sysroot_to_use(&self) -> Path {
         self.context.sysroot_to_use()
     }
+
+    /// Returns the flags to pass to rustc, as a vector of strings
+    pub fn flag_strs(&self) -> ~[~str] {
+        self.context.flag_strs()
+    }
+
+    pub fn compile_upto(&self) -> StopBefore {
+        self.context.compile_upto()
+    }
+}
+
+/*
+Deliberately unsupported rustc flags:
+   --bin, --lib           inferred from crate file names
+   -L                     inferred from extern mods
+   --out-dir              inferred from RUST_PATH
+   --test                 use `rustpkg test`
+   -v -h --ls             don't make sense with rustpkg
+   -W -A -D -F -          use pragmas instead
+
+rustc flags that aren't implemented yet:
+   --passes
+   --llvm-arg
+   --target-feature
+   --android-cross-path
+*/
+pub struct RustcFlags {
+    compile_upto: StopBefore,
+    // Linker to use with the --linker flag
+    linker: Option<~str>,
+    // Extra arguments to pass to rustc with the --link-args flag
+    link_args: Option<~str>,
+    // Optimization level. 0 = default. -O = 2.
+    optimization_level: OptLevel,
+    // True if the user passed in --save-temps
+    save_temps: bool,
+    // Target (defaults to rustc's default target)
+    target: Option<~str>,
+    // Target CPU (defaults to rustc's default target CPU)
+    target_cpu: Option<~str>,
+    // Any -Z features
+    experimental_features: Option<~[~str]>
+}
+
+impl Clone for RustcFlags {
+    fn clone(&self) -> RustcFlags {
+        RustcFlags {
+            compile_upto: self.compile_upto,
+            linker: self.linker.clone(),
+            link_args: self.link_args.clone(),
+            optimization_level: self.optimization_level,
+            save_temps: self.save_temps,
+            target: self.target.clone(),
+            target_cpu: self.target_cpu.clone(),
+            experimental_features: self.experimental_features.clone()
+        }
+    }
+}
+
+#[deriving(Eq)]
+pub enum StopBefore {
+    Nothing,  // compile everything
+    Link,     // --no-link
+    LLVMCompileBitcode, // --emit-llvm without -S
+    LLVMAssemble, // -S --emit-llvm
+    Assemble, // -S without --emit-llvm
+    Trans,    // --no-trans
+    Pretty,   // --pretty
+    Analysis, // --parse-only
 }
 
 impl Context {
     pub fn sysroot(&self) -> Path {
         self.sysroot.clone()
     }
-}
 
-impl Context {
     /// Debugging
     pub fn sysroot_str(&self) -> ~str {
         self.sysroot.to_str()
@@ -63,6 +135,15 @@ pub fn sysroot_to_use(&self) -> Path {
             self.sysroot.pop().pop().pop()
         }
     }
+
+    /// Returns the flags to pass to rustc, as a vector of strings
+    pub fn flag_strs(&self) -> ~[~str] {
+        self.rustc_flags.flag_strs()
+    }
+
+    pub fn compile_upto(&self) -> StopBefore {
+        self.rustc_flags.compile_upto
+    }
 }
 
 /// We assume that if ../../rustc exists, then we're running
@@ -72,3 +153,141 @@ pub fn in_target(sysroot: &Path) -> bool {
     debug!("Checking whether %s is in target", sysroot.to_str());
     os::path_is_dir(&sysroot.pop().pop().push("rustc"))
 }
+
+impl RustcFlags {
+    fn flag_strs(&self) -> ~[~str] {
+        let linker_flag = match self.linker {
+            Some(ref l) => ~[~"--linker", l.clone()],
+            None    => ~[]
+        };
+        let link_args_flag = match self.link_args {
+            Some(ref l) => ~[~"--link-args", l.clone()],
+            None        => ~[]
+        };
+        let save_temps_flag = if self.save_temps { ~[~"--save-temps"] } else { ~[] };
+        let target_flag = match self.target {
+            Some(ref l) => ~[~"--target", l.clone()],
+            None        => ~[]
+        };
+        let target_cpu_flag = match self.target_cpu {
+            Some(ref l) => ~[~"--target-cpu", l.clone()],
+            None        => ~[]
+        };
+        let z_flags = match self.experimental_features {
+            Some(ref ls)    => ls.flat_map(|s| ~[~"-Z", s.clone()]),
+            None            => ~[]
+        };
+        linker_flag
+            + link_args_flag
+            + save_temps_flag
+            + target_flag
+            + target_cpu_flag
+            + z_flags + (match self.compile_upto {
+            LLVMCompileBitcode => ~[~"--emit-llvm"],
+            LLVMAssemble => ~[~"--emit-llvm", ~"-S"],
+            Link => ~[~"-c"],
+            Trans => ~[~"--no-trans"],
+            Assemble => ~[~"-S"],
+            // n.b. Doesn't support all flavors of --pretty (yet)
+            Pretty => ~[~"--pretty"],
+            Analysis => ~[~"--parse-only"],
+            Nothing => ~[]
+        })
+    }
+
+    pub fn default() -> RustcFlags {
+        RustcFlags {
+            linker: None,
+            link_args: None,
+            compile_upto: Nothing,
+            optimization_level: No,
+            save_temps: false,
+            target: None,
+            target_cpu: None,
+            experimental_features: None
+        }
+    }
+}
+
+/// Returns true if any of the flags given are incompatible with the cmd
+pub fn flags_ok_for_cmd(flags: &RustcFlags,
+                        cfgs: &[~str],
+                        cmd: &str, user_supplied_opt_level: bool) -> bool {
+    let complain = |s| {
+        io::println(fmt!("The %s option can only be used with the build command:
+                         rustpkg [options..] build %s [package-ID]", s, s));
+    };
+
+    if flags.linker.is_some() && cmd != "build" && cmd != "install" {
+        io::println("The --linker option can only be used with the build or install commands.");
+        return true;
+    }
+    if flags.link_args.is_some() && cmd != "build" && cmd != "install" {
+        io::println("The --link-args option can only be used with the build or install commands.");
+        return true;
+    }
+
+    if !cfgs.is_empty() && cmd != "build" && cmd != "install" {
+        io::println("The --cfg option can only be used with the build or install commands.");
+        return true;
+    }
+
+    if user_supplied_opt_level && cmd != "build" && cmd != "install" {
+        io::println("The -O and --opt-level options can only be used with the build \
+                    or install commands.");
+        return true;
+    }
+
+    if flags.save_temps  && cmd != "build" && cmd != "install" {
+        io::println("The --save-temps option can only be used with the build \
+                    or install commands.");
+        return true;
+    }
+
+    if flags.target.is_some()  && cmd != "build" && cmd != "install" {
+        io::println("The --target option can only be used with the build \
+                    or install commands.");
+        return true;
+    }
+    if flags.target_cpu.is_some()  && cmd != "build" && cmd != "install" {
+        io::println("The --target-cpu option can only be used with the build \
+                    or install commands.");
+        return true;
+    }
+    if flags.experimental_features.is_some() && cmd != "build" && cmd != "install" {
+        io::println("The -Z option can only be used with the build or install commands.");
+        return true;
+    }
+
+    match flags.compile_upto {
+        Link if cmd != "build" => {
+            complain("--no-link");
+            true
+        }
+        Trans if cmd != "build" => {
+            complain("--no-trans");
+            true
+        }
+        Assemble if cmd != "build" => {
+            complain("-S");
+            true
+        }
+        Pretty if cmd != "build" => {
+            complain("--pretty");
+            true
+        }
+        Analysis if cmd != "build" => {
+            complain("--parse-only");
+            true
+        }
+        LLVMCompileBitcode if cmd != "build" => {
+            complain("--emit-llvm");
+            true
+        }
+        LLVMAssemble if cmd != "build" => {
+            complain("--emit-llvm");
+            true
+        }
+        _ => false
+    }
+}
index f0f3673f1d030abdc2fe482fdd1befcbc1dc3c00..bc2fcdd7fe9b2b19b30d71b5a69fb34afb3bab40 100644 (file)
@@ -99,7 +99,35 @@ pub fn short_name_with_version(&self) -> ~str {
     /// True if the ID has multiple components
     pub fn is_complex(&self) -> bool {
         self.short_name != self.path.to_str()
-     }
+    }
+
+    pub fn prefixes_iter(&self) -> Prefixes {
+        Prefixes {
+            components: self.path.components().to_owned(),
+            remaining: ~[]
+        }
+    }
+
+}
+
+struct Prefixes {
+    priv components: ~[~str],
+    priv remaining: ~[~str]
+}
+
+impl Iterator<(Path, Path)> for Prefixes {
+    #[inline]
+    fn next(&mut self) -> Option<(Path, Path)> {
+        if self.components.len() <= 1 {
+            None
+        }
+        else {
+            let last = self.components.pop();
+            self.remaining.push(last);
+            // converting to str and then back is a little unfortunate
+            Some((Path(self.components.to_str()), Path(self.remaining.to_str())))
+        }
+    }
 }
 
 impl ToStr for PkgId {
@@ -119,3 +147,4 @@ pub fn hash(data: ~str) -> ~str {
     write(hasher, data);
     hasher.result_str()
 }
+
index 946707288c43deed901a4d5f269baeeda6f4c04b..b5ded6f3fafab0d209c3fc6ec9bad6c914e53478 100644 (file)
@@ -18,7 +18,7 @@
 use crate::Crate;
 use messages::*;
 use source_control::{git_clone, git_clone_general};
-use path_util::{find_dir_using_rust_path_hack, default_workspace};
+use path_util::{find_dir_using_rust_path_hack, default_workspace, make_dir_rwx_recursive};
 use util::compile_crate;
 use workspace::is_workspace;
 use workcache_support;
@@ -77,6 +77,33 @@ pub fn new(workspace: Path, use_rust_path_hack: bool, id: PkgId) -> PkgSrc {
         let dir: Path = match path {
             Some(d) => (*d).clone(),
             None => {
+                // See if any of the prefixes of this package ID form a valid package ID
+                // That is, is this a package ID that points into the middle of a workspace?
+                for (prefix, suffix) in id.prefixes_iter() {
+                    let package_id = PkgId::new(prefix.to_str());
+                    let path = workspace.push("src").push_rel(&package_id.path);
+                    debug!("in loop: checking if %s is a directory", path.to_str());
+                    if os::path_is_dir(&path) {
+                        let ps = PkgSrc::new(workspace.clone(),
+                                             use_rust_path_hack,
+                                             PkgId::new(prefix.to_str()));
+                        debug!("pkgsrc: Returning [%s|%s|%s]", workspace.to_str(),
+                               ps.start_dir.push_rel(&suffix).to_str(), ps.id.to_str());
+
+                        return PkgSrc {
+                            workspace: workspace,
+                            start_dir: ps.start_dir.push_rel(&suffix),
+                            id: ps.id,
+                            libs: ~[],
+                            mains: ~[],
+                            tests: ~[],
+                            benchs: ~[]
+                        }
+
+                    };
+                }
+
+                // Ok, no prefixes work, so try fetching from git
                 let mut ok_d = None;
                 for w in to_try.iter() {
                     debug!("Calling fetch_git on %s", w.to_str());
@@ -93,16 +120,17 @@ pub fn new(workspace: Path, use_rust_path_hack: bool, id: PkgId) -> PkgSrc {
                         if use_rust_path_hack {
                             match find_dir_using_rust_path_hack(&id) {
                                 Some(d) => d,
-                                None => cond.raise((id.clone(),
-                                    ~"supplied path for package dir does not \
-                                     exist, and couldn't interpret it as a URL fragment"))
+                                None => {
+                                    cond.raise((id.clone(),
+                                        ~"supplied path for package dir does not \
+                                        exist, and couldn't interpret it as a URL fragment"))
+                                }
                             }
                         }
                         else {
                             cond.raise((id.clone(),
-                                        ~"supplied path for package dir does not \
-                                        exist, and couldn't interpret it as a URL fragment"))
-
+                                ~"supplied path for package dir does not \
+                                exist, and couldn't interpret it as a URL fragment"))
                         }
                     }
                 }
@@ -115,6 +143,9 @@ pub fn new(workspace: Path, use_rust_path_hack: bool, id: PkgId) -> PkgSrc {
                                         non-directory"));
         }
 
+        debug!("pkgsrc: Returning {%s|%s|%s}", workspace.to_str(),
+               dir.to_str(), id.to_str());
+
         PkgSrc {
             workspace: workspace,
             start_dir: dir,
@@ -166,12 +197,14 @@ pub fn fetch_git(local: &Path, pkgid: &PkgId) -> Option<Path> {
                   url, clone_target.to_str(), pkgid.version.to_str());
 
         if git_clone_general(url, &clone_target, &pkgid.version) {
-            // since the operation succeeded, move clone_target to local
-            if !os::rename_file(&clone_target, local) {
-                 None
+            // Since the operation succeeded, move clone_target to local.
+            // First, create all ancestor directories.
+            if make_dir_rwx_recursive(&local.pop())
+                && os::rename_file(&clone_target, local) {
+                 Some(local.clone())
             }
             else {
-                 Some(local.clone())
+                 None
             }
         }
         else {
index 1b732354f11b8c985e5272375b2bb64271480718..92e5adf09f612abbe30b98890bcd15915e7716a0 100644 (file)
@@ -14,6 +14,7 @@
 pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
 pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
 pub use rustc::metadata::filesearch::rust_path;
+use rustc::driver::driver::host_triple;
 
 use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
 use std::os::mkdir_recursive;
@@ -43,20 +44,24 @@ pub fn in_rust_path(p: &Path) -> bool {
 /// succeeded.
 pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) }
 
+pub fn make_dir_rwx_recursive(p: &Path) -> bool { os::mkdir_recursive(p, U_RWX) }
+
 // n.b. The next three functions ignore the package version right
 // now. Should fix that.
 
 /// 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());
     workspace_contains_package_id_(pkgid, workspace, |p| { p.push("src") }).is_some()
 }
 
 pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
 // Returns the directory it was actually found in
              workspace_to_src_dir: &fn(&Path) -> Path) -> Option<Path> {
+    if !os::path_is_dir(workspace) {
+        return None;
+    }
+
     let src_dir = workspace_to_src_dir(workspace);
 
     let mut found = None;
@@ -90,10 +95,29 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
     found
 }
 
+/// Return the target-specific build subdirectory, pushed onto `base`;
+/// doesn't check that it exists or create it
+pub fn target_build_dir(workspace: &Path) -> Path {
+    workspace.push("build").push(host_triple())
+}
+
+/// Return the target-specific lib subdirectory, pushed onto `base`;
+/// doesn't check that it exists or create it
+fn target_lib_dir(workspace: &Path) -> Path {
+    workspace.push("lib").push(host_triple())
+}
+
+/// Return the bin subdirectory, pushed onto `base`;
+/// doesn't check that it exists or create it
+/// note: this isn't target-specific
+fn target_bin_dir(workspace: &Path) -> Path {
+    workspace.push("bin")
+}
+
 /// Figure out what the executable name for <pkgid> in <workspace>'s build
 /// directory is, and if the file exists, return it.
 pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
-    let mut result = workspace.push("build");
+    let mut result = target_build_dir(workspace);
     // should use a target-specific subdirectory
     result = mk_output_path(Main, Build, pkgid, result);
     debug!("built_executable_in_workspace: checking whether %s exists",
@@ -120,7 +144,7 @@ pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path>
 }
 
 fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> {
-    let mut result = workspace.push("build");
+    let mut result = target_build_dir(workspace);
     // should use a target-specific subdirectory
     result = mk_output_path(what, Build, pkgid, result);
     debug!("output_in_workspace: checking whether %s exists",
@@ -141,9 +165,17 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
 }
 
 /// Does the actual searching stuff
-pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> {
+pub fn installed_library_in_workspace(pkg_path: &Path, workspace: &Path) -> Option<Path> {
     // This could break once we're handling multiple versions better -- I should add a test for it
-    library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib", &NoVersion)
+    match pkg_path.filename() {
+        None => None,
+        Some(short_name) => library_in_workspace(pkg_path,
+                                                 short_name,
+                                                 Install,
+                                                 workspace,
+                                                 "lib",
+                                                 &NoVersion)
+    }
 }
 
 /// `workspace` is used to figure out the directory to search.
@@ -160,11 +192,21 @@ pub fn library_in_workspace(path: &Path, short_name: &str, where: Target,
             prefix = %s", short_name, where, workspace.to_str(), prefix);
 
     let dir_to_search = match where {
-        Build => workspace.push(prefix).push_rel(path),
-        Install => workspace.push(prefix)
+        Build => target_build_dir(workspace).push_rel(path),
+        Install => target_lib_dir(workspace)
     };
+
+    library_in(short_name, version, &dir_to_search)
+}
+
+// rustc doesn't use target-specific subdirectories
+pub fn system_library(sysroot: &Path, lib_name: &str) -> Option<Path> {
+    library_in(lib_name, &NoVersion, &sysroot.push("lib"))
+}
+
+fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option<Path> {
     debug!("Listing directory %s", dir_to_search.to_str());
-    let dir_contents = os::list_dir(&dir_to_search);
+    let dir_contents = os::list_dir(dir_to_search);
     debug!("dir has %? entries", dir_contents.len());
 
     let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, short_name);
@@ -286,9 +328,10 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
     };
     // Artifacts in the build directory live in a package-ID-specific subdirectory,
     // but installed ones don't.
-    let result = match where {
-                Build => workspace.push(subdir).push_rel(&pkgid.path),
-                _     => workspace.push(subdir)
+    let result = match (where, what) {
+                (Build, _)         => target_build_dir(workspace).push_rel(&pkgid.path),
+                (Install, Lib)     => target_lib_dir(workspace),
+                (Install, _)    => target_bin_dir(workspace)
     };
     if !os::path_exists(&result) && !mkdir_recursive(&result, U_RWX) {
         cond.raise((result.clone(), fmt!("target_file_in_workspace couldn't \
@@ -303,10 +346,10 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
 pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
     use conditions::bad_path::cond;
 
-    let mut result = workspace.push("build");
-    // n.b. Should actually use a target-specific
-    // subdirectory of build/
+    let mut result = target_build_dir(workspace);
     result = result.push_rel(&pkgid.path);
+    debug!("Creating build dir %s for package id %s", result.to_str(),
+           pkgid.to_str());
     if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) {
         result
     }
@@ -389,3 +432,12 @@ pub fn find_dir_using_rust_path_hack(p: &PkgId) -> Option<Path> {
     }
     None
 }
+
+/// True if the user set RUST_PATH to something non-empty --
+/// as opposed to the default paths that rustpkg adds automatically
+pub fn user_set_rust_path() -> bool {
+    match os::getenv("RUST_PATH") {
+        None | Some(~"") => false,
+        Some(_)         => true
+    }
+}
index 331dfcd692a19d2682ac3e78e8c8d18824ff18fd..eef1dcabfd0efd1c397981401b58135cb65227b3 100644 (file)
 use extra::{getopts};
 use syntax::{ast, diagnostic};
 use util::*;
-use messages::*;
+use messages::{error, warn, note};
 use path_util::build_pkg_id_in_workspace;
 use path_util::{U_RWX, in_rust_path};
 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, cwd_to_workspace};
-use context::{BuildContext, Context};
+use context::{Context, BuildContext,
+                       RustcFlags, Trans, Link, Nothing, Pretty, Analysis, Assemble,
+                       LLVMAssemble, LLVMCompileBitcode};
 use package_id::PkgId;
 use package_source::PkgSrc;
 use workcache_support::{discover_outputs, digest_only_date};
@@ -138,6 +140,7 @@ fn run_custom(&self, exec: &mut workcache::Exec, sysroot: &Path) -> (~[~str], Ex
         let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
         util::compile_crate_from_input(&self.input,
                                        exec,
+                                       Nothing,
                                        &self.build_dir,
                                        sess,
                                        crate);
@@ -178,7 +181,10 @@ pub trait CtxMethods {
     /// second is a list of declared and discovered inputs
     fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
     /// Returns a list of installed files
-    fn install_no_build(&self, workspace: &Path, id: &PkgId) -> ~[Path];
+    fn install_no_build(&self,
+                        source_workspace: &Path,
+                        target_workspace: &Path,
+                        id: &PkgId) -> ~[Path];
     fn prefer(&self, _id: &str, _vers: Option<~str>);
     fn test(&self);
     fn uninstall(&self, _id: &str, _vers: Option<~str>);
@@ -400,7 +406,7 @@ fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
                 debug!("No package script, continuing");
                 ~[]
             }
-        };
+        } + self.context.cfgs;
 
         // If there was a package script, it should have finished
         // the build already. Otherwise...
@@ -461,28 +467,40 @@ fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
                 // install to the first workspace in the RUST_PATH if there's
                 // a non-default RUST_PATH. This code installs to the same
                 // workspace the package was built in.
-                debug!("install: destination workspace = %s, id = %s",
-                       destination_workspace, id_str);
-                let result = subself.install_no_build(&Path(destination_workspace), &sub_id);
+                let actual_workspace = if path_util::user_set_rust_path() {
+                    default_workspace()
+                }
+                else {
+                    Path(destination_workspace)
+                };
+                debug!("install: destination workspace = %s, id = %s, installing to %s",
+                       destination_workspace, id_str, actual_workspace.to_str());
+                let result = subself.install_no_build(&Path(destination_workspace),
+                                                      &actual_workspace,
+                                                      &sub_id);
                 debug!("install: id = %s, about to call discover_outputs, %?",
                        id_str, result.to_str());
 
                 discover_outputs(exec, result.clone());
                 sub_files.write(|r| { *r = result.clone(); });
                 sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
+                note(fmt!("Installed package %s to %s", id_str, actual_workspace.to_str()));
             }
         };
         (installed_files.unwrap(), inputs.unwrap())
     }
 
-    fn install_no_build(&self, workspace: &Path, id: &PkgId) -> ~[Path] {
+    fn install_no_build(&self,
+                        source_workspace: &Path,
+                        target_workspace: &Path,
+                        id: &PkgId) -> ~[Path] {
         use conditions::copy_failed::cond;
 
         // Now copy stuff into the install dirs
-        let maybe_executable = built_executable_in_workspace(id, workspace);
-        let maybe_library = built_library_in_workspace(id, workspace);
-        let target_exec = target_executable_in_workspace(id, workspace);
-        let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, workspace));
+        let maybe_executable = built_executable_in_workspace(id, source_workspace);
+        let maybe_library = built_library_in_workspace(id, source_workspace);
+        let target_exec = target_executable_in_workspace(id, target_workspace);
+        let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
 
         debug!("target_exec = %s target_lib = %? \
                 maybe_executable = %? maybe_library = %?",
@@ -539,9 +557,25 @@ pub fn main() {
 
 pub fn main_args(args: &[~str]) {
     let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
+                                        getopts::optflag("no-link"),
+                                        getopts::optflag("no-trans"),
+                 // n.b. Ignores different --pretty options for now
+                                        getopts::optflag("pretty"),
+                                        getopts::optflag("parse-only"),
+                 getopts::optflag("S"), getopts::optflag("assembly"),
                  getopts::optmulti("c"), getopts::optmulti("cfg"),
                  getopts::optflag("v"), getopts::optflag("version"),
-                 getopts::optflag("r"), getopts::optflag("rust-path-hack")];
+                 getopts::optflag("r"), getopts::optflag("rust-path-hack"),
+                                        getopts::optopt("sysroot"),
+                                        getopts::optflag("emit-llvm"),
+                                        getopts::optopt("linker"),
+                                        getopts::optopt("link-args"),
+                                        getopts::optopt("opt-level"),
+                 getopts::optflag("O"),
+                                        getopts::optflag("save-temps"),
+                                        getopts::optopt("target"),
+                                        getopts::optopt("target-cpu"),
+                 getopts::optmulti("Z")                                   ];
     let matches = &match getopts::getopts(args, opts) {
         result::Ok(m) => m,
         result::Err(f) => {
@@ -550,8 +584,16 @@ pub fn main_args(args: &[~str]) {
             return;
         }
     };
-    let help = getopts::opt_present(matches, "h") ||
-               getopts::opt_present(matches, "help");
+    let mut help = getopts::opt_present(matches, "h") ||
+                   getopts::opt_present(matches, "help");
+    let no_link = getopts::opt_present(matches, "no-link");
+    let no_trans = getopts::opt_present(matches, "no-trans");
+    let supplied_sysroot = getopts::opt_val(matches, "sysroot");
+    let generate_asm = getopts::opt_present(matches, "S") ||
+        getopts::opt_present(matches, "assembly");
+    let parse_only = getopts::opt_present(matches, "parse-only");
+    let pretty = getopts::opt_present(matches, "pretty");
+    let emit_llvm = getopts::opt_present(matches, "emit-llvm");
 
     if getopts::opt_present(matches, "v") ||
        getopts::opt_present(matches, "version") {
@@ -562,6 +604,35 @@ pub fn main_args(args: &[~str]) {
     let use_rust_path_hack = getopts::opt_present(matches, "r") ||
                              getopts::opt_present(matches, "rust-path-hack");
 
+    let linker = getopts::opt_maybe_str(matches, "linker");
+    let link_args = getopts::opt_maybe_str(matches, "link-args");
+    let cfgs = getopts::opt_strs(matches, "cfg") + getopts::opt_strs(matches, "c");
+    let mut user_supplied_opt_level = true;
+    let opt_level = match getopts::opt_maybe_str(matches, "opt-level") {
+        Some(~"0") => session::No,
+        Some(~"1") => session::Less,
+        Some(~"2") => session::Default,
+        Some(~"3") => session::Aggressive,
+        _ if getopts::opt_present(matches, "O") => session::Default,
+        _ => {
+            user_supplied_opt_level = false;
+            session::No
+        }
+    };
+
+    let save_temps = getopts::opt_present(matches, "save-temps");
+    let target     = getopts::opt_maybe_str(matches, "target");
+    let target_cpu = getopts::opt_maybe_str(matches, "target-cpu");
+    let experimental_features = {
+        let strs = getopts::opt_strs(matches, "Z");
+        if getopts::opt_present(matches, "Z") {
+            Some(strs)
+        }
+        else {
+            None
+        }
+    };
+
     let mut args = matches.free.clone();
     args.shift();
 
@@ -569,6 +640,33 @@ pub fn main_args(args: &[~str]) {
         return usage::general();
     }
 
+    let rustc_flags = RustcFlags {
+        linker: linker,
+        link_args: link_args,
+        optimization_level: opt_level,
+        compile_upto: if no_trans {
+            Trans
+        } else if no_link {
+            Link
+        } else if pretty {
+            Pretty
+        } else if parse_only {
+            Analysis
+        } else if emit_llvm && generate_asm {
+            LLVMAssemble
+        } else if generate_asm {
+            Assemble
+        } else if emit_llvm {
+            LLVMCompileBitcode
+        } else {
+            Nothing
+        },
+        save_temps: save_temps,
+        target: target,
+        target_cpu: target_cpu,
+        experimental_features: experimental_features
+    };
+
     let mut cmd_opt = None;
     for a in args.iter() {
         if util::is_cmd(*a) {
@@ -578,23 +676,25 @@ pub fn main_args(args: &[~str]) {
     }
     let cmd = match cmd_opt {
         None => return usage::general(),
-        Some(cmd) => if help {
-            return match *cmd {
-                ~"build" => usage::build(),
-                ~"clean" => usage::clean(),
-                ~"do" => usage::do_cmd(),
-                ~"info" => usage::info(),
-                ~"install" => usage::install(),
-                ~"list"    => usage::list(),
-                ~"prefer" => usage::prefer(),
-                ~"test" => usage::test(),
-                ~"uninstall" => usage::uninstall(),
-                ~"unprefer" => usage::unprefer(),
-                _ => usage::general()
-            };
-        }
-        else {
-            cmd
+        Some(cmd) => {
+            help |= context::flags_ok_for_cmd(&rustc_flags, cfgs, *cmd, user_supplied_opt_level);
+            if help {
+                return match *cmd {
+                    ~"build" => usage::build(),
+                    ~"clean" => usage::clean(),
+                    ~"do" => usage::do_cmd(),
+                    ~"info" => usage::info(),
+                    ~"install" => usage::install(),
+                    ~"list"    => usage::list(),
+                    ~"prefer" => usage::prefer(),
+                    ~"test" => usage::test(),
+                    ~"uninstall" => usage::uninstall(),
+                    ~"unprefer" => usage::unprefer(),
+                    _ => usage::general()
+                };
+            } else {
+                cmd
+            }
         }
     };
 
@@ -603,14 +703,20 @@ pub fn main_args(args: &[~str]) {
     // I had to add this type annotation to get the code to typecheck
     let mut remaining_args: ~[~str] = remaining_args.map(|s| (*s).clone()).collect();
     remaining_args.shift();
-    let sroot = filesearch::get_or_default_sysroot();
+    let sroot = match supplied_sysroot {
+        Some(getopts::Val(s)) => Path(s),
+        _ => filesearch::get_or_default_sysroot()
+    };
+
     debug!("Using sysroot: %s", sroot.to_str());
     debug!("Will store workcache in %s", default_workspace().to_str());
     BuildContext {
         context: Context {
-            use_rust_path_hack: use_rust_path_hack,
-            sysroot: sroot, // Currently, only tests override this
-         },
+        cfgs: cfgs,
+        rustc_flags: rustc_flags,
+        use_rust_path_hack: use_rust_path_hack,
+        sysroot: sroot, // Currently, only tests override this
+    },
         workcache_context: api::default_context(default_workspace()).workcache_context
     }.run(*cmd, remaining_args)
 }
index e5e2a0dbd714f2a5e08727cb95944c648b484271..37976ea5c488d81174424120ed63916462460730 100644 (file)
 /// 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> {
+pub fn find_installed_library_in_rust_path(pkg_path: &Path, _version: &Version) -> Option<Path> {
     let rp = rust_path();
+    debug!("find_installed_library_in_rust_path: looking for path %s", pkg_path.to_str());
     for p in rp.iter() {
-        match installed_library_in_workspace(short_name, p) {
+        match installed_library_in_workspace(pkg_path, p) {
             Some(path) => return Some(path),
             None => ()
         }
index f4016d26a150e4576e2b329a6668ca653f0e3c03..83110e22ed55fa24112ba0b9b6b93db809730fd0 100644 (file)
@@ -10,7 +10,7 @@
 
 // rustpkg unit tests
 
-use context::{BuildContext, Context};
+use context::{BuildContext, Context, RustcFlags};
 use std::{io, libc, os, run, str, task};
 use extra::arc::Arc;
 use extra::arc::RWArc;
@@ -18,6 +18,7 @@
 use extra::workcache;
 use extra::workcache::{Database, Logger};
 use extra::treemap::TreeMap;
+use extra::getopts::groups::getopts;
 use std::run::ProcessOutput;
 use installed_packages::list_installed_packages;
 use package_id::{PkgId};
                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};
+               built_library_in_workspace, built_executable_in_workspace, target_build_dir};
+use rustc::back::link::get_cc_prog;
 use rustc::metadata::filesearch::rust_path;
-use rustc::driver::driver::host_triple;
+use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
+use syntax::diagnostic;
 use target::*;
 use package_source::PkgSrc;
 
@@ -45,6 +48,9 @@ fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
     BuildContext {
         workcache_context: context,
         context: Context {
+            cfgs: ~[],
+            rustc_flags: RustcFlags::default(),
+
             use_rust_path_hack: false,
             sysroot: sysroot
         }
@@ -89,17 +95,17 @@ fn mk_empty_workspace(short_name: &Path, version: &Version, tag: &str) -> Path {
 
 fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path {
     // include version number in directory name
-    let package_dir = workspace.push("src").push(fmt!("%s-%s",
-                                                      short_name.to_str(), version.to_str()));
+    let package_dir = workspace.push_many([~"src", fmt!("%s-%s",
+                                                      short_name.to_str(), version.to_str())]);
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
     package_dir
 }
 
 fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path {
     let package_dir = mk_empty_workspace(short_name,
-                          version, "temp_workspace").push("src").push(fmt!("%s-%s",
+                          version, "temp_workspace").push_many([~"src", fmt!("%s-%s",
                                                             short_name.to_str(),
-                                                            version.to_str()));
+                                                            version.to_str())]);
 
     debug!("Created %s and does it exist? %?", package_dir.to_str(),
           os::path_is_dir(&package_dir));
@@ -201,13 +207,13 @@ fn test_sysroot() -> Path {
 // Returns the path to rustpkg
 fn rustpkg_exec() -> Path {
     // Ugh
-    let first_try = test_sysroot().push("lib").push("rustc")
-        .push(host_triple()).push("bin").push("rustpkg");
+    let first_try = test_sysroot().push_many(
+        [~"lib", ~"rustc", host_triple(), ~"bin", ~"rustpkg"]);
     if is_executable(&first_try) {
         first_try
     }
     else {
-        let second_try = test_sysroot().push("bin").push("rustpkg");
+        let second_try = test_sysroot().push_many([~"bin", ~"rustpkg"]);
         if is_executable(&second_try) {
             second_try
         }
@@ -218,6 +224,10 @@ fn rustpkg_exec() -> Path {
 }
 
 fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
+    command_line_test_with_env(args, cwd, None).expect("Command line test failed")
+}
+
+fn command_line_test_partial(args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
     command_line_test_with_env(args, cwd, None)
 }
 
@@ -225,10 +235,13 @@ fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
 /// invoked from) with the given arguments, in the given working directory.
 /// Returns the process's output.
 fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
-    -> ProcessOutput {
+    -> Option<ProcessOutput> {
     let cmd = rustpkg_exec().to_str();
-    debug!("cd %s; %s %s",
-           cwd.to_str(), cmd, args.connect(" "));
+    let env_str = match env {
+        Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
+        None        => ~""
+    };
+    debug!("%s cd %s; %s %s", env_str, cwd.to_str(), cmd, args.connect(" "));
     assert!(os::path_is_dir(&*cwd));
     let cwd = (*cwd).clone();
     let mut prog = run::Process::new(cmd, args, run::ProcessOptions {
@@ -250,11 +263,14 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
 to make sure the command succeeded
 */
     if output.status != 0 {
-        fail!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
+        debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
               cmd, args, output.status,
               str::from_utf8(output.output) + str::from_utf8(output.error));
+        None
+    }
+    else {
+        Some(output)
     }
-    output
 }
 
 fn create_local_package(pkgid: &PkgId) -> Path {
@@ -265,7 +281,7 @@ fn create_local_package(pkgid: &PkgId) -> Path {
 
 fn create_local_package_in(pkgid: &PkgId, pkgdir: &Path) -> Path {
 
-    let package_dir = pkgdir.push("src").push(pkgid.to_str());
+    let package_dir = pkgdir.push_many([~"src", pkgid.to_str()]);
 
     // Create main, lib, test, and bench files
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
@@ -293,16 +309,12 @@ fn create_local_package_with_dep(pkgid: &PkgId, subord_pkgid: &PkgId) -> Path {
     let package_dir = create_local_package(pkgid);
     create_local_package_in(subord_pkgid, &package_dir);
     // Write a main.rs file into pkgid that references subord_pkgid
-    writeFile(&package_dir.push("src").push(pkgid.to_str()).push("main.rs"),
+    writeFile(&package_dir.push_many([~"src", pkgid.to_str(), ~"main.rs"]),
               fmt!("extern mod %s;\nfn main() {}",
                    subord_pkgid.short_name));
     // Write a lib.rs file into subord_pkgid that has something in it
-    writeFile(&package_dir.push("src").push(subord_pkgid.to_str()).push("lib.rs"),
+    writeFile(&package_dir.push_many([~"src", subord_pkgid.to_str(), ~"lib.rs"]),
               "pub fn f() {}");
-    debug!("Dry run -- would create packages %s and %s in %s",
-           pkgid.to_str(),
-           subord_pkgid.to_str(),
-           package_dir.to_str());
     package_dir
 }
 
@@ -315,13 +327,13 @@ fn create_local_package_with_custom_build_hook(pkgid: &PkgId,
 
 }
 
-fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) {
-    assert!(lib_exists(repo, short_name, v));
+fn assert_lib_exists(repo: &Path, pkg_path: &Path, v: Version) {
+    assert!(lib_exists(repo, pkg_path, v));
 }
 
-fn lib_exists(repo: &Path, short_name: &str, _v: Version) -> bool { // ??? version?
-    debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
-    let lib = installed_library_in_workspace(short_name, repo);
+fn lib_exists(repo: &Path, pkg_path: &Path, _v: Version) -> bool { // ??? version?
+    debug!("assert_lib_exists: repo = %s, pkg_path = %s", repo.to_str(), pkg_path.to_str());
+    let lib = installed_library_in_workspace(pkg_path, repo);
     debug!("assert_lib_exists: checking whether %? exists", lib);
     lib.is_some() && {
         let libname = lib.get_ref();
@@ -352,6 +364,27 @@ fn built_executable_exists(repo: &Path, short_name: &str) -> bool {
     }
 }
 
+fn object_file_exists(repo: &Path, short_name: &str) -> bool {
+    file_exists(repo, short_name, "o")
+}
+
+fn assembly_file_exists(repo: &Path, short_name: &str) -> bool {
+    file_exists(repo, short_name, "s")
+}
+
+fn llvm_assembly_file_exists(repo: &Path, short_name: &str) -> bool {
+    file_exists(repo, short_name, "ll")
+}
+
+fn llvm_bitcode_file_exists(repo: &Path, short_name: &str) -> bool {
+    file_exists(repo, short_name, "bc")
+}
+
+fn file_exists(repo: &Path, short_name: &str, extension: &str) -> bool {
+    os::path_exists(&target_build_dir(repo).push_many([short_name.to_owned(),
+                                     fmt!("%s.%s", short_name, extension)]))
+}
+
 fn assert_built_library_exists(repo: &Path, short_name: &str) {
     assert!(built_library_exists(repo, short_name));
 }
@@ -377,7 +410,8 @@ fn command_line_test_output(args: &[~str]) -> ~[~str] {
 
 fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
     let mut result = ~[];
-    let p_output = command_line_test_with_env(args, &os::getcwd(), Some(env));
+    let p_output = command_line_test_with_env(args,
+        &os::getcwd(), Some(env)).expect("Command-line test failed");
     let test_output = str::from_utf8(p_output.output);
     for s in test_output.split_iter('\n') {
         result.push(s.to_owned());
@@ -397,13 +431,13 @@ fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Pat
                          &NoVersion).expect("lib_output_file_name")
 }
 
-fn output_file_name(workspace: &Path, short_name: &str) -> Path {
-    workspace.push("build").push(short_name).push(fmt!("%s%s", short_name, os::EXE_SUFFIX))
+fn output_file_name(workspace: &Path, short_name: ~str) -> Path {
+    target_build_dir(workspace).push(short_name).push(fmt!("%s%s", short_name, os::EXE_SUFFIX))
 }
 
 fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
+    let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
     let contents = os::list_dir_path(&pkg_src_dir);
     for p in contents.iter() {
         if p.filetype() == Some(".rs") {
@@ -418,7 +452,7 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
 /// Add a comment at the end
 fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
+    let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
     let contents = os::list_dir_path(&pkg_src_dir);
     let mut maybe_p = None;
     for p in contents.iter() {
@@ -472,7 +506,7 @@ fn test_install_valid() {
     assert!(os::path_exists(&exec));
     assert!(is_rwx(&exec));
 
-    let lib = installed_library_in_workspace(temp_pkg_id.short_name, &temp_workspace);
+    let lib = installed_library_in_workspace(&temp_pkg_id.path, &temp_workspace);
     debug!("lib = %?", lib);
     assert!(lib.map_default(false, |l| os::path_exists(l)));
     assert!(lib.map_default(false, |l| is_rwx(l)));
@@ -509,7 +543,7 @@ fn test_install_git() {
     let temp_pkg_id = git_repo_pkg();
     let repo = init_git_repo(&temp_pkg_id.path);
     debug!("repo = %s", repo.to_str());
-    let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg");
+    let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test-pkg"]);
     debug!("repo_subdir = %s", repo_subdir.to_str());
 
     writeFile(&repo_subdir.push("main.rs"),
@@ -536,7 +570,7 @@ fn test_install_git() {
     let _built_lib =
         built_library_in_workspace(&temp_pkg_id,
                                    &ws).expect("test_install_git: built lib should exist");
-    assert_lib_exists(&ws, temp_pkg_id.short_name, temp_pkg_id.version.clone());
+    assert_lib_exists(&ws, &temp_pkg_id.path, temp_pkg_id.version.clone());
     let built_test = built_test_in_workspace(&temp_pkg_id,
                          &ws).expect("test_install_git: built test should exist");
     assert!(os::path_exists(&built_test));
@@ -597,7 +631,7 @@ fn test_package_ids_must_be_relative_path_like() {
 fn test_package_version() {
     let local_path = "mockgithub.com/catamorphism/test_pkg_version";
     let repo = init_git_repo(&Path(local_path));
-    let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg_version");
+    let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test_pkg_version"]);
     debug!("Writing files in: %s", repo_subdir.to_str());
     writeFile(&repo_subdir.push("main.rs"),
               "fn main() { let _x = (); }");
@@ -622,18 +656,17 @@ fn test_package_version() {
         None    => false
     });
     assert!(built_executable_in_workspace(&temp_pkg_id, &ws)
-            == Some(ws.push("build").
-                    push("mockgithub.com").
-                    push("catamorphism").
-                    push("test_pkg_version").
-                    push("test_pkg_version")));
+            == Some(target_build_dir(&ws).push_many([~"mockgithub.com",
+                                                    ~"catamorphism",
+                                                    ~"test_pkg_version",
+                                                    ~"test_pkg_version"])));
 }
 
 #[test]
 fn test_package_request_version() {
     let local_path = "mockgithub.com/catamorphism/test_pkg_version";
     let repo = init_git_repo(&Path(local_path));
-    let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg_version");
+    let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test_pkg_version"]);
     debug!("Writing files in: %s", repo_subdir.to_str());
     writeFile(&repo_subdir.push("main.rs"),
               "fn main() { let _x = (); }");
@@ -650,7 +683,7 @@ fn test_package_request_version() {
 
     command_line_test([~"install", fmt!("%s#0.3", local_path)], &repo);
 
-    assert!(match installed_library_in_workspace("test_pkg_version", &repo.push(".rust")) {
+    assert!(match installed_library_in_workspace(&Path("test_pkg_version"), &repo.push(".rust")) {
         Some(p) => {
             debug!("installed: %s", p.to_str());
             p.to_str().ends_with(fmt!("0.3%s", os::consts::DLL_SUFFIX))
@@ -659,16 +692,16 @@ fn test_package_request_version() {
     });
     let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3");
     assert!(target_executable_in_workspace(&temp_pkg_id, &repo.push(".rust"))
-            == repo.push(".rust").push("bin").push("test_pkg_version"));
+            == repo.push_many([~".rust", ~"bin", ~"test_pkg_version"]));
+
+    let dir = &repo.push_many([~".rust",
+                               ~"src",
+                               ~"mockgithub.com",
+                               ~"catamorphism",
+                               ~"test_pkg_version-0.3"]);
 
-    assert!(os::path_exists(&repo.push(".rust").push("src")
-                            .push("mockgithub.com").push("catamorphism")
-                            .push("test_pkg_version-0.3")
-                            .push("version-0.3-file.txt")));
-    assert!(!os::path_exists(&repo.push(".rust").push("src")
-                            .push("mockgithub.com").push("catamorphism")
-                             .push("test_pkg_version-0.3")
-                            .push("version-0.4-file.txt")));
+    assert!(os::path_exists(&dir.push("version-0.3-file.txt")));
+    assert!(!os::path_exists(&dir.push("version-0.4-file.txt")));
 }
 
 #[test]
@@ -696,7 +729,7 @@ fn rustpkg_library_target() {
 
     add_git_tag(&package_dir, ~"1.0");
     command_line_test([~"install", ~"foo"], &foo_repo);
-    assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0"));
+    assert_lib_exists(&foo_repo.push(".rust"), &Path("foo"), ExactRevision(~"1.0"));
 }
 
 #[test]
@@ -711,23 +744,23 @@ fn rustpkg_local_pkg() {
 fn package_script_with_default_build() {
     let dir = create_local_package(&PkgId::new("fancy-lib"));
     debug!("dir = %s", dir.to_str());
-    let source = test_sysroot().pop().pop().pop().push("src").push("librustpkg").
-        push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
+    let source = test_sysroot().pop().pop().pop().push_many(
+        [~"src", ~"librustpkg", ~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"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_many([~"src", ~"fancy-lib-0.1", ~"pkg.rs"])) {
         fail!("Couldn't copy file");
     }
     command_line_test([~"install", ~"fancy-lib"], &dir);
-    assert_lib_exists(&dir, "fancy-lib", NoVersion);
-    assert!(os::path_exists(&dir.push("build").push("fancy-lib").push("generated.rs")));
+    assert_lib_exists(&dir, &Path("fancy-lib"), NoVersion);
+    assert!(os::path_exists(&target_build_dir(&dir).push_many([~"fancy-lib", ~"generated.rs"])));
 }
 
 #[test]
 fn rustpkg_build_no_arg() {
     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");
+    let package_dir = tmp.push_many([~"src", ~"foo"]);
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
 
     writeFile(&package_dir.push("main.rs"),
@@ -742,20 +775,20 @@ fn rustpkg_install_no_arg() {
     let tmp = mkdtemp(&os::tmpdir(),
                       "rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed")
               .push(".rust");
-    let package_dir = tmp.push("src").push("foo");
+    let package_dir = tmp.push_many([~"src", ~"foo"]);
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
     writeFile(&package_dir.push("lib.rs"),
               "fn main() { let _x = (); }");
     debug!("install_no_arg: dir = %s", package_dir.to_str());
     command_line_test([~"install"], &package_dir);
-    assert_lib_exists(&tmp, "foo", NoVersion);
+    assert_lib_exists(&tmp, &Path("foo"), NoVersion);
 }
 
 #[test]
 fn rustpkg_clean_no_arg() {
     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");
+    let package_dir = tmp.push_many([~"src", ~"foo"]);
     assert!(os::mkdir_recursive(&package_dir, U_RWX));
 
     writeFile(&package_dir.push("main.rs"),
@@ -785,26 +818,25 @@ fn rust_path_test() {
 }
 
 #[test]
+#[ignore] // FIXME(#9184) tests can't change the cwd (other tests are sad then)
 fn rust_path_contents() {
-    use std::unstable::change_dir_locked;
-
     let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed");
-    let abc = &dir.push("A").push("B").push("C");
+    let abc = &dir.push_many([~"A", ~"B", ~"C"]);
     assert!(os::mkdir_recursive(&abc.push(".rust"), U_RWX));
     assert!(os::mkdir_recursive(&abc.pop().push(".rust"), U_RWX));
     assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), U_RWX));
-    assert!(do change_dir_locked(&dir.push("A").push("B").push("C")) {
-        let p = rust_path();
-        let cwd = os::getcwd().push(".rust");
-        let parent = cwd.pop().pop().push(".rust");
-        let grandparent = cwd.pop().pop().pop().push(".rust");
-        assert!(p.contains(&cwd));
-        assert!(p.contains(&parent));
-        assert!(p.contains(&grandparent));
-        for a_path in p.iter() {
-            assert!(!a_path.components.is_empty());
-        }
-    });
+    assert!(os::change_dir(abc));
+
+    let p = rust_path();
+    let cwd = os::getcwd().push(".rust");
+    let parent = cwd.pop().pop().push(".rust");
+    let grandparent = cwd.pop().pop().pop().push(".rust");
+    assert!(p.contains(&cwd));
+    assert!(p.contains(&parent));
+    assert!(p.contains(&grandparent));
+    for a_path in p.iter() {
+        assert!(!a_path.components.is_empty());
+    }
 }
 
 #[test]
@@ -830,7 +862,6 @@ fn test_list() {
 // list doesn't output very much right now...
     command_line_test([~"install", ~"foo"], &dir);
     let env_arg = ~[(~"RUST_PATH", dir.to_str())];
-    debug!("RUST_PATH = %s", dir.to_str());
     let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
     assert!(list_output.iter().any(|x| x.starts_with("foo")));
 
@@ -916,14 +947,14 @@ fn no_rebuilding_dep() {
     let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
                                                   ".rust",
                                                   "bar"));
-    let foo_date_1 = datestamp(&output_file_name(&workspace, "foo"));
+    let foo_date_1 = datestamp(&output_file_name(&workspace, ~"foo"));
 
     frob_source_file(&workspace, &p_id);
     command_line_test([~"build", ~"foo"], &workspace);
     let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
                                                   ".rust",
                                                   "bar"));
-    let foo_date_2 = datestamp(&output_file_name(&workspace, "foo"));
+    let foo_date_2 = datestamp(&output_file_name(&workspace, ~"foo"));
     assert_eq!(bar_date_1, bar_date_2);
     assert!(foo_date_1 < foo_date_2);
     assert!(foo_date_1 > bar_date_1);
@@ -1010,7 +1041,7 @@ fn test_uninstall() {
 fn test_non_numeric_tag() {
     let temp_pkg_id = git_repo_pkg();
     let repo = init_git_repo(&temp_pkg_id.path);
-    let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg");
+    let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test-pkg"]);
     writeFile(&repo_subdir.push("foo"), "foo");
     writeFile(&repo_subdir.push("lib.rs"),
               "pub fn f() { let _x = (); }");
@@ -1047,6 +1078,49 @@ fn test_extern_mod() {
 
     command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg"], &lib_depend_dir);
 
+    let exec_file = dir.push("out");
+    // Be sure to extend the existing environment
+    let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env());
+    let rustpkg_exec = rustpkg_exec();
+    let rustc = rustpkg_exec.with_filename("rustc");
+
+    let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
+                                                      ~"--sysroot", test_sysroot().to_str(),
+                                               ~"-o", exec_file.to_str()],
+                                     run::ProcessOptions {
+        env: env,
+        dir: Some(&dir),
+        in_fd: None,
+        out_fd: None,
+        err_fd: None
+    });
+    let outp = prog.finish_with_output();
+    if outp.status != 0 {
+        fail!("output was %s, error was %s",
+              str::from_utf8(outp.output),
+              str::from_utf8(outp.error));
+    }
+    assert!(os::path_exists(&exec_file) && is_executable(&exec_file));
+}
+
+#[test]
+fn test_extern_mod_simpler() {
+    let dir = mkdtemp(&os::tmpdir(), "test_extern_mod_simpler").expect("test_extern_mod_simpler");
+    let main_file = dir.push("main.rs");
+    let lib_depend_dir = mkdtemp(&os::tmpdir(), "foo").expect("test_extern_mod_simpler");
+    let aux_dir = lib_depend_dir.push_many(["src", "rust-awesomeness"]);
+    assert!(os::mkdir_recursive(&aux_dir, U_RWX));
+    let aux_pkg_file = aux_dir.push("lib.rs");
+
+    writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() {  assert!(true); } }\n");
+    assert!(os::path_exists(&aux_pkg_file));
+
+    writeFile(&main_file,
+              "extern mod test = \"rust-awesomeness\";\nuse test::bar;\
+               fn main() { bar::assert_true(); }\n");
+
+    command_line_test([~"install", ~"rust-awesomeness"], &lib_depend_dir);
+
     let exec_file = dir.push("out");
     // Be sure to extend the existing environment
     let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env());
@@ -1082,11 +1156,11 @@ fn test_extern_mod() {
 fn test_import_rustpkg() {
     let p_id = PkgId::new("foo");
     let workspace = create_local_package(&p_id);
-    writeFile(&workspace.push("src").push("foo-0.1").push("pkg.rs"),
+    writeFile(&workspace.push_many([~"src", ~"foo-0.1", ~"pkg.rs"]),
               "extern mod rustpkg; fn main() {}");
     command_line_test([~"build", ~"foo"], &workspace);
     debug!("workspace = %s", workspace.to_str());
-    assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s",
+    assert!(os::path_exists(&target_build_dir(&workspace).push("foo").push(fmt!("pkg%s",
         os::EXE_SUFFIX))));
 }
 
@@ -1094,11 +1168,11 @@ fn test_import_rustpkg() {
 fn test_macro_pkg_script() {
     let p_id = PkgId::new("foo");
     let workspace = create_local_package(&p_id);
-    writeFile(&workspace.push("src").push("foo-0.1").push("pkg.rs"),
+    writeFile(&workspace.push_many([~"src", ~"foo-0.1", ~"pkg.rs"]),
               "extern mod rustpkg; fn main() { debug!(\"Hi\"); }");
     command_line_test([~"build", ~"foo"], &workspace);
     debug!("workspace = %s", workspace.to_str());
-    assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s",
+    assert!(os::path_exists(&target_build_dir(&workspace).push("foo").push(fmt!("pkg%s",
         os::EXE_SUFFIX))));
 }
 
@@ -1133,15 +1207,13 @@ fn rust_path_hack_test(hack_flag: bool) {
    let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
    let rust_path = Some(~[(~"RUST_PATH",
        fmt!("%s:%s", dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str()))]);
-   debug!("declare -x RUST_PATH=%s:%s",
-       dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str());
    command_line_test_with_env(~[~"install"] + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } +
                                ~[~"foo"], &dest_workspace, rust_path);
-   assert_lib_exists(&dest_workspace, "foo", NoVersion);
+   assert_lib_exists(&dest_workspace, &Path("foo"), NoVersion);
    assert_executable_exists(&dest_workspace, "foo");
    assert_built_library_exists(&dest_workspace, "foo");
    assert_built_executable_exists(&dest_workspace, "foo");
-   assert!(!lib_exists(&workspace, "foo", NoVersion));
+   assert!(!lib_exists(&workspace, &Path("foo"), NoVersion));
    assert!(!executable_exists(&workspace, "foo"));
    assert!(!built_library_exists(&workspace, "foo"));
    assert!(!built_executable_exists(&workspace, "foo"));
@@ -1174,12 +1246,11 @@ fn rust_path_hack_cwd() {
 
    let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
-   debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
    command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
    debug!("Checking that foo exists in %s", dest_workspace.to_str());
-   assert_lib_exists(&dest_workspace, "foo", NoVersion);
+   assert_lib_exists(&dest_workspace, &Path("foo"), NoVersion);
    assert_built_library_exists(&dest_workspace, "foo");
-   assert!(!lib_exists(&cwd, "foo", NoVersion));
+   assert!(!lib_exists(&cwd, &Path("foo"), NoVersion));
    assert!(!built_library_exists(&cwd, "foo"));
 }
 
@@ -1194,12 +1265,11 @@ fn rust_path_hack_multi_path() {
 
    let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
-   debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
    command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
    debug!("Checking that %s exists in %s", name, dest_workspace.to_str());
-   assert_lib_exists(&dest_workspace, "quux", NoVersion);
+   assert_lib_exists(&dest_workspace, &Path("quux"), NoVersion);
    assert_built_library_exists(&dest_workspace, name);
-   assert!(!lib_exists(&subdir, "quux", NoVersion));
+   assert!(!lib_exists(&subdir, &Path("quux"), NoVersion));
    assert!(!built_library_exists(&subdir, name));
 }
 
@@ -1213,12 +1283,11 @@ fn rust_path_hack_install_no_arg() {
 
    let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
-   debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
    command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
    debug!("Checking that foo exists in %s", dest_workspace.to_str());
-   assert_lib_exists(&dest_workspace, "foo", NoVersion);
+   assert_lib_exists(&dest_workspace, &Path("foo"), NoVersion);
    assert_built_library_exists(&dest_workspace, "foo");
-   assert!(!lib_exists(&source_dir, "foo", NoVersion));
+   assert!(!lib_exists(&source_dir, &Path("foo"), NoVersion));
    assert!(!built_library_exists(&cwd, "foo"));
 }
 
@@ -1232,7 +1301,6 @@ fn rust_path_hack_build_no_arg() {
 
    let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
-   debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
    command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
    debug!("Checking that foo exists in %s", dest_workspace.to_str());
    assert_built_library_exists(&dest_workspace, "foo");
@@ -1254,8 +1322,6 @@ fn rust_path_install_target() {
     let rust_path = Some(~[(~"RUST_PATH", fmt!("%s:%s", dir_to_install_to.to_str(),
                                                dir.to_str()))]);
     let cwd = os::getcwd();
-
-    debug!("RUST_PATH=%s:%s", dir_to_install_to.to_str(), dir.to_str());
     command_line_test_with_env([~"install", ~"foo"],
                                &cwd,
                                rust_path);
@@ -1264,6 +1330,354 @@ fn rust_path_install_target() {
 
 }
 
+#[test]
+fn sysroot_flag() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    // no-op sysroot setting; I'm not sure how else to test this
+    command_line_test([~"--sysroot",
+                       test_sysroot().to_str(),
+                       ~"build",
+                       ~"foo"],
+                      &workspace);
+    assert_built_executable_exists(&workspace, "foo");
+}
+
+#[test]
+fn compile_flag_build() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"build",
+                       ~"--no-link",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(object_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn compile_flag_fail() {
+    // --no-link shouldn't be accepted for install
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"install",
+                       ~"--no-link",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(!object_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn notrans_flag_build() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    let flags_to_test = [~"--no-trans", ~"--parse-only",
+                         ~"--pretty", ~"-S"];
+
+    for flag in flags_to_test.iter() {
+        command_line_test([test_sysroot().to_str(),
+                           ~"build",
+                           flag.clone(),
+                           ~"foo"],
+                          &workspace);
+        // Ideally we'd test that rustpkg actually succeeds, but
+        // since task failure doesn't set the exit code properly,
+        // we can't tell
+        assert!(!built_executable_exists(&workspace, "foo"));
+        assert!(!object_file_exists(&workspace, "foo"));
+    }
+}
+
+#[test]
+fn notrans_flag_fail() {
+    // --no-trans shouldn't be accepted for install
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    let flags_to_test = [~"--no-trans", ~"--parse-only",
+                         ~"--pretty", ~"-S"];
+    for flag in flags_to_test.iter() {
+        command_line_test([test_sysroot().to_str(),
+                           ~"install",
+                           flag.clone(),
+                           ~"foo"],
+                          &workspace);
+        // Ideally we'd test that rustpkg actually fails, but
+        // since task failure doesn't set the exit code properly,
+        // we can't tell
+        assert!(!built_executable_exists(&workspace, "foo"));
+        assert!(!object_file_exists(&workspace, "foo"));
+        assert!(!lib_exists(&workspace, &Path("foo"), NoVersion));
+    }
+}
+
+#[test]
+fn dash_S() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"build",
+                       ~"-S",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(!object_file_exists(&workspace, "foo"));
+    assert!(assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn dash_S_fail() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"install",
+                       ~"-S",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(!object_file_exists(&workspace, "foo"));
+    assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_cfg_build() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    // If the cfg flag gets messed up, this won't compile
+    writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
+               "#[cfg(quux)] fn main() {}");
+    command_line_test([test_sysroot().to_str(),
+                       ~"build",
+                       ~"--cfg",
+                       ~"quux",
+                       ~"foo"],
+                      &workspace);
+    assert_built_executable_exists(&workspace, "foo");
+}
+
+#[test]
+fn test_cfg_fail() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
+               "#[cfg(quux)] fn main() {}");
+    assert!(command_line_test_partial([test_sysroot().to_str(),
+                       ~"build",
+                       ~"foo"],
+                      &workspace).is_none());
+}
+
+
+#[test]
+fn test_emit_llvm_S_build() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"build",
+                       ~"-S", ~"--emit-llvm",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(!object_file_exists(&workspace, "foo"));
+    assert!(llvm_assembly_file_exists(&workspace, "foo"));
+    assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_emit_llvm_S_fail() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"install",
+                       ~"-S", ~"--emit-llvm",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(!object_file_exists(&workspace, "foo"));
+    assert!(!llvm_assembly_file_exists(&workspace, "foo"));
+    assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_emit_llvm_build() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"build",
+                       ~"--emit-llvm",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(!object_file_exists(&workspace, "foo"));
+    assert!(llvm_bitcode_file_exists(&workspace, "foo"));
+    assert!(!assembly_file_exists(&workspace, "foo"));
+    assert!(!llvm_assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_emit_llvm_fail() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"install",
+                       ~"--emit-llvm",
+                       ~"foo"],
+                      &workspace);
+    assert!(!built_executable_exists(&workspace, "foo"));
+    assert!(!object_file_exists(&workspace, "foo"));
+    assert!(!llvm_bitcode_file_exists(&workspace, "foo"));
+    assert!(!llvm_assembly_file_exists(&workspace, "foo"));
+    assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_linker_build() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    let matches = getopts([], optgroups());
+    let options = build_session_options(@"rustpkg",
+                                        matches.get_ref(),
+                                        diagnostic::emit);
+    let sess = build_session(options, diagnostic::emit);
+    command_line_test([test_sysroot().to_str(),
+                       ~"install",
+                       ~"--linker",
+                       get_cc_prog(sess),
+                       ~"foo"],
+                      &workspace);
+    assert_executable_exists(&workspace, "foo");
+}
+
+#[test]
+fn test_build_install_flags_fail() {
+    // The following flags can only be used with build or install:
+    let forbidden = [~[~"--linker", ~"ld"],
+                     ~[~"--link-args", ~"quux"],
+                     ~[~"-O"],
+                     ~[~"--opt-level", ~"2"],
+                     ~[~"--save-temps"],
+                     ~[~"--target", host_triple()],
+                     ~[~"--target-cpu", ~"generic"],
+                     ~[~"-Z", ~"--time-passes"]];
+    for flag in forbidden.iter() {
+        let output = command_line_test_output([test_sysroot().to_str(),
+                           ~"list"] + *flag);
+        assert!(output.len() > 1);
+        assert!(output[1].find_str("can only be used with").is_some());
+    }
+}
+
+#[test]
+fn test_optimized_build() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"build",
+                       ~"-O",
+                       ~"foo"],
+                      &workspace);
+    assert!(built_executable_exists(&workspace, "foo"));
+}
+
+fn pkgid_pointing_to_subdir() {
+    // The actual repo is mockgithub.com/mozilla/some_repo
+    // rustpkg should recognize that and treat the part after some_repo/ as a subdir
+    let workspace = mkdtemp(&os::tmpdir(), "parent_repo").expect("Couldn't create temp dir");
+    assert!(os::mkdir_recursive(&workspace.push_many([~"src", ~"mockgithub.com",
+                                                     ~"mozilla", ~"some_repo"]), U_RWX));
+
+    let foo_dir = workspace.push_many([~"src", ~"mockgithub.com", ~"mozilla", ~"some_repo",
+                                       ~"extras", ~"foo"]);
+    let bar_dir = workspace.push_many([~"src", ~"mockgithub.com", ~"mozilla", ~"some_repo",
+                                       ~"extras", ~"bar"]);
+    assert!(os::mkdir_recursive(&foo_dir, U_RWX));
+    assert!(os::mkdir_recursive(&bar_dir, U_RWX));
+    writeFile(&foo_dir.push("lib.rs"), "pub fn f() {}");
+    writeFile(&bar_dir.push("lib.rs"), "pub fn g() {}");
+
+    debug!("Creating a file in %s", workspace.to_str());
+    let testpkg_dir = workspace.push_many([~"src", ~"testpkg-0.1"]);
+    assert!(os::mkdir_recursive(&testpkg_dir, U_RWX));
+
+    writeFile(&testpkg_dir.push("main.rs"),
+              "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo\";\n
+               extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar\";\n
+               use foo::f; use bar::g; \n
+               fn main() { f(); g(); }");
+
+    command_line_test([~"install", ~"testpkg"], &workspace);
+    assert_executable_exists(&workspace, "testpkg");
+}
+
+fn test_recursive_deps() {
+    let a_id = PkgId::new("a");
+    let b_id = PkgId::new("b");
+    let c_id = PkgId::new("c");
+    let b_workspace = create_local_package_with_dep(&b_id, &c_id);
+    writeFile(&b_workspace.push("src").push("c-0.1").push("lib.rs"),
+               "pub fn g() {}");
+    let a_workspace = create_local_package(&a_id);
+    writeFile(&a_workspace.push("src").push("a-0.1").push("main.rs"),
+               "extern mod b; use b::f; fn main() { f(); }");
+    writeFile(&b_workspace.push("src").push("b-0.1").push("lib.rs"),
+               "extern mod c; use c::g; pub fn f() { g(); }");
+    let environment = Some(~[(~"RUST_PATH", b_workspace.to_str())]);
+    debug!("RUST_PATH=%s", b_workspace.to_str());
+    command_line_test_with_env([~"install", ~"a"],
+                               &a_workspace,
+                               environment);
+    assert_lib_exists(&a_workspace, &Path("a"), NoVersion);
+    assert_lib_exists(&b_workspace, &Path("b"), NoVersion);
+    assert_lib_exists(&b_workspace, &Path("c"), NoVersion);
+}
+
+#[test]
+fn test_install_to_rust_path() {
+    let p_id = PkgId::new("foo");
+    let second_workspace = create_local_package(&p_id);
+    let first_workspace = mk_empty_workspace(&Path("p"), &NoVersion, "dest");
+    let rust_path = Some(~[(~"RUST_PATH",
+                            fmt!("%s:%s", first_workspace.to_str(),
+                                 second_workspace.to_str()))]);
+    debug!("RUST_PATH=%s:%s", first_workspace.to_str(), second_workspace.to_str());
+    command_line_test_with_env([test_sysroot().to_str(),
+                       ~"install",
+                       ~"foo"],
+                      &os::getcwd(), rust_path);
+    assert!(!built_executable_exists(&first_workspace, "foo"));
+    assert!(built_executable_exists(&second_workspace, "foo"));
+    assert_executable_exists(&first_workspace, "foo");
+    assert!(!executable_exists(&second_workspace, "foo"));
+}
+
+fn test_target_specific_build_dir() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"build",
+                       ~"foo"],
+                      &workspace);
+    assert!(os::path_is_dir(&target_build_dir(&workspace)));
+    assert!(built_executable_exists(&workspace, "foo"));
+    assert!(os::list_dir(&workspace.push("build")).len() == 1);
+}
+
+#[test]
+fn test_target_specific_install_dir() {
+    let p_id = PkgId::new("foo");
+    let workspace = create_local_package(&p_id);
+    command_line_test([test_sysroot().to_str(),
+                       ~"install",
+                       ~"foo"],
+                      &workspace);
+    assert!(os::path_is_dir(&workspace.push("lib").push(host_triple())));
+    assert_lib_exists(&workspace, &Path("foo"), NoVersion);
+    assert!(os::list_dir(&workspace.push("lib")).len() == 1);
+    assert!(os::path_is_dir(&workspace.push("bin")));
+    assert_executable_exists(&workspace, "foo");
+}
 
 /// Returns true if p exists and is executable
 fn is_executable(p: &Path) -> bool {
index f5ac82b5684a6d5399f434e8f3ff391d97a74038..dae949541b3a185a3272a7d9ba74db586ecafb35 100644 (file)
@@ -19,18 +19,34 @@ pub fn general() {
 Options:
 
     -h, --help                  Display this message
+    --sysroot PATH              Override the system root
     <cmd> -h, <cmd> --help      Display help for <cmd>");
 }
 
 pub fn build() {
-    io::println("rustpkg [options..] build [package-ID]
+    io::println("rustpkg build [options..] [package-ID]
 
 Build the given package ID if specified. With no package ID argument,
 build the package in the current directory. In that case, the current
 directory must be a direct child of an `src` directory in a workspace.
 
 Options:
-    -c, --cfg      Pass a cfg flag to the package script");
+    -c, --cfg      Pass a cfg flag to the package script
+    --no-link      Compile and assemble, but don't link (like -c in rustc)
+    --no-trans     Parse and translate, but don't generate any code
+    --pretty       Pretty-print the code, but don't generate output
+    --parse-only   Parse the code, but don't typecheck or generate code
+    -S             Generate assembly code, but don't assemble or link it
+    -S --emit-llvm Generate LLVM assembly code
+    --emit-llvm    Generate LLVM bitcode
+    --linker PATH  Use a linker other than the system linker
+    --link-args [ARG..] Extra arguments to pass to the linker
+    --opt-level=n  Set the optimization level (0 <= n <= 3)
+    -O             Equivalent to --opt-level=2
+    --save-temps   Don't delete temporary files
+    --target TRIPLE Set the target triple
+    --target-cpu CPU Set the target CPU
+    -Z FLAG        Enable an experimental rustc feature (see `rustc --help`)");
 }
 
 pub fn clean() {
@@ -63,7 +79,7 @@ pub fn list() {
 }
 
 pub fn install() {
-    io::println("rustpkg [options..] install [package-ID]
+    io::println("rustpkg install [options..] [package-ID]
 
 Install the given package ID if specified. With no package ID
 argument, install the package in the current directory.
@@ -76,7 +92,16 @@ pub fn install() {
     rustpkg install github.com/mozilla/servo#0.1.2
 
 Options:
-    -c, --cfg      Pass a cfg flag to the package script");
+    -c, --cfg      Pass a cfg flag to the package script
+    --emit-llvm    Generate LLVM bitcode
+    --linker PATH  Use a linker other than the system linker
+    --link-args [ARG..] Extra arguments to pass to the linker
+    --opt-level=n  Set the optimization level (0 <= n <= 3)
+    -O             Equivalent to --opt-level=2
+    --save-temps   Don't delete temporary files
+    --target TRIPLE Set the target triple
+    --target-cpu CPU Set the target CPU
+    -Z FLAG        Enable an experimental rustc feature (see `rustc --help`)");
 }
 
 pub fn uninstall() {
index 5e9fc6655a8ec4edcb1d3a31df59128821e3fbfc..71c4760f28d9e61dcb71c45e3435018697f84a9c 100644 (file)
 use syntax::ext::base::ExtCtxt;
 use syntax::{ast, attr, codemap, diagnostic, fold};
 use syntax::attr::AttrMetaMethods;
-use rustc::back::link::output_type_exe;
+use rustc::back::link;
 use rustc::driver::session::{lib_crate, bin_crate};
-use context::{in_target, BuildContext};
+use context::{in_target, StopBefore, Link, Assemble, BuildContext};
 use package_id::PkgId;
 use package_source::PkgSrc;
-use path_util::{installed_library_in_workspace, U_RWX};
+use workspace::pkg_parent_workspaces;
+use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
+use messages::error;
 
 pub use target::{OutputType, Main, Lib, Bench, Test};
 use workcache_support::{digest_file_with_date, digest_only_date};
@@ -153,7 +155,7 @@ pub fn ready_crate(sess: session::Session,
     @fold.fold_crate(crate)
 }
 
-pub fn compile_input(ctxt: &BuildContext,
+pub fn compile_input(context: &BuildContext,
                      exec: &mut workcache::Exec,
                      pkg_id: &PkgId,
                      in_file: &Path,
@@ -161,20 +163,20 @@ pub fn compile_input(ctxt: &BuildContext,
                      flags: &[~str],
                      cfgs: &[~str],
                      opt: bool,
-                     what: OutputType) -> Path {
+                     what: OutputType) -> Option<Path> {
     assert!(in_file.components.len() > 1);
     let input = driver::file_input((*in_file).clone());
     debug!("compile_input: %s / %?", in_file.to_str(), what);
     // tjc: by default, use the package ID name as the link name
     // not sure if we should support anything else
 
-    let out_dir = workspace.push("build").push_rel(&pkg_id.path);
+    let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path);
 
     let binary = os::args()[0].to_managed();
 
     debug!("flags: %s", flags.connect(" "));
     debug!("cfgs: %s", cfgs.connect(" "));
-    debug!("compile_input's sysroot = %s", ctxt.sysroot().to_str());
+    debug!("compile_input's sysroot = %s", context.sysroot().to_str());
 
     let crate_type = match what {
         Lib => lib_crate,
@@ -188,26 +190,38 @@ pub fn compile_input(ctxt: &BuildContext,
                               Main => ~[]
                           }
                           + flags
+                          + context.flag_strs()
                           + cfgs.flat_map(|c| { ~[~"--cfg", (*c).clone()] }),
                           driver::optgroups()).unwrap();
+    debug!("rustc flags: %?", matches);
+
     // Hack so that rustpkg can run either out of a rustc target dir,
     // or the host dir
-    let sysroot_to_use = @if !in_target(&ctxt.sysroot()) {
-        ctxt.sysroot()
+    let sysroot_to_use = @if !in_target(&context.sysroot()) {
+        context.sysroot()
     }
     else {
-        ctxt.sysroot().pop().pop().pop()
+        context.sysroot().pop().pop().pop()
     };
-    debug!("compile_input's sysroot = %s", ctxt.sysroot().to_str());
+    debug!("compile_input's sysroot = %s", context.sysroot().to_str());
     debug!("sysroot_to_use = %s", sysroot_to_use.to_str());
+
+    let output_type = match context.compile_upto() {
+        Assemble => link::output_type_assembly,
+        Link     => link::output_type_object,
+        Pretty | Trans | Analysis => link::output_type_none,
+        LLVMAssemble => link::output_type_llvm_assembly,
+        LLVMCompileBitcode => link::output_type_bitcode,
+        Nothing => link::output_type_exe
+    };
+
     let options = @session::options {
         crate_type: crate_type,
         optimize: if opt { session::Aggressive } else { session::No },
         test: what == Test || what == Bench,
         maybe_sysroot: Some(sysroot_to_use),
         addl_lib_search_paths: @mut (~[out_dir.clone()]),
-        // output_type should be conditional
-        output_type: output_type_exe, // Use this to get a library? That's weird
+        output_type: output_type,
         .. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
     };
 
@@ -231,9 +245,7 @@ pub fn compile_input(ctxt: &BuildContext,
     let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
     crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
 
-    // Not really right. Should search other workspaces too, and the installed
-    // database (which doesn't exist yet)
-    find_and_install_dependencies(ctxt, sess, exec, workspace, crate,
+    find_and_install_dependencies(context, pkg_id, sess, exec, crate,
                                   |p| {
                                       debug!("a dependency: %s", p.to_str());
                                       // Pass the directory containing a dependency
@@ -256,10 +268,8 @@ pub fn compile_input(ctxt: &BuildContext,
         let link_options =
             ~[attr::mk_name_value_item_str(@"name", name_to_use),
               attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())] +
-                        if pkg_id.is_complex() {
-                        ~[attr::mk_name_value_item_str(@"package_id",
-                                                       pkg_id.path.to_str().to_managed())]
-                } else { ~[] };
+            ~[attr::mk_name_value_item_str(@"package_id",
+                                           pkg_id.path.to_str().to_managed())];
 
         debug!("link options: %?", link_options);
         crate = @ast::Crate {
@@ -270,7 +280,7 @@ pub fn compile_input(ctxt: &BuildContext,
 
     debug!("calling compile_crate_from_input, workspace = %s,
            building_library = %?", out_dir.to_str(), sess.building_library);
-    compile_crate_from_input(in_file, exec, &out_dir, sess, crate)
+    compile_crate_from_input(in_file, exec, context.compile_upto(), &out_dir, sess, crate)
 }
 
 // Should use workcache to avoid recompiling when not necessary
@@ -280,10 +290,13 @@ pub fn compile_input(ctxt: &BuildContext,
 // also, too many arguments
 pub fn compile_crate_from_input(input: &Path,
                                 exec: &mut workcache::Exec,
+                                stop_before: StopBefore,
  // should be of the form <workspace>/build/<pkg id's path>
                                 out_dir: &Path,
                                 sess: session::Session,
-                                crate: @ast::Crate) -> Path {
+// Returns None if one of the flags that suppresses compilation output was
+// given
+                                crate: @ast::Crate) -> Option<Path> {
     debug!("Calling build_output_filenames with %s, building library? %?",
            out_dir.to_str(), sess.building_library);
 
@@ -302,17 +315,21 @@ pub fn compile_crate_from_input(input: &Path,
         debug!("an additional library: %s", lib.to_str());
     }
     let analysis = driver::phase_3_run_analysis_passes(sess, crate);
+    if driver::stop_after_phase_3(sess) { return None; }
     let translation = driver::phase_4_translate_to_llvm(sess, crate,
                                                         &analysis,
                                                         outputs);
     driver::phase_5_run_llvm_passes(sess, &translation, outputs);
-    if driver::stop_after_phase_5(sess) { return outputs.out_filename; }
+    // The second check shouldn't be necessary, but rustc seems to ignore
+    // -c
+    if driver::stop_after_phase_5(sess)
+        || stop_before == Link || stop_before == Assemble { return Some(outputs.out_filename); }
     driver::phase_6_link_output(sess, &translation, outputs);
 
     // Register dependency on the source file
     exec.discover_input("file", input.to_str(), digest_file_with_date(input));
 
-    outputs.out_filename
+    Some(outputs.out_filename)
 }
 
 #[cfg(windows)]
@@ -330,7 +347,7 @@ pub fn compile_crate(ctxt: &BuildContext,
                      pkg_id: &PkgId,
                      crate: &Path, workspace: &Path,
                      flags: &[~str], cfgs: &[~str], opt: bool,
-                     what: OutputType) -> Path {
+                     what: OutputType) -> Option<Path> {
     debug!("compile_crate: crate=%s, workspace=%s", crate.to_str(), workspace.to_str());
     debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
     for fl in flags.iter() {
@@ -343,15 +360,16 @@ pub fn compile_crate(ctxt: &BuildContext,
 /// Collect all `extern mod` directives in `c`, then
 /// try to install their targets, failing if any target
 /// can't be found.
-pub fn find_and_install_dependencies(ctxt: &BuildContext,
-                                 sess: session::Session,
-                                 exec: &mut workcache::Exec,
-                                 workspace: &Path,
-                                 c: &ast::Crate,
-                                 save: @fn(Path)
-                                ) {
-    debug!("Finding and installing dependencies...");
-    do c.each_view_item |vi| {
+pub fn find_and_install_dependencies(context: &BuildContext,
+                                     parent: &PkgId,
+                                     sess: session::Session,
+                                     exec: &mut workcache::Exec,
+                                     c: &ast::Crate,
+                                     save: @fn(Path)
+                                     ) {
+    use conditions::nonexistent_package::cond;
+
+    do c.each_view_item() |vi: &ast::view_item| {
         debug!("A view item!");
         match vi.node {
             // ignore metadata, I guess
@@ -360,7 +378,9 @@ pub fn find_and_install_dependencies(ctxt: &BuildContext,
                     Some(p) => p,
                     None => sess.str_of(lib_ident)
                 };
-                match installed_library_in_workspace(lib_name, &ctxt.sysroot()) {
+                debug!("Finding and installing... %s", lib_name);
+                // Check standard Rust library path first
+                match system_library(&context.sysroot(), lib_name) {
                     Some(ref installed_path) => {
                         debug!("It exists: %s", installed_path.to_str());
                         // Say that [path for c] has a discovered dependency on
@@ -378,8 +398,18 @@ pub fn find_and_install_dependencies(ctxt: &BuildContext,
                                lib_name.to_str());
                         // Try to install it
                         let pkg_id = PkgId::new(lib_name);
+                        let workspaces = pkg_parent_workspaces(&context.context, &pkg_id);
+                        let dep_workspace = if workspaces.is_empty() {
+                            error(fmt!("Couldn't find package %s, which is needed by %s, \
+                                            in any of the workspaces in the RUST_PATH (%?)",
+                                            lib_name, parent.to_str(), rust_path()));
+                            cond.raise((pkg_id.clone(), ~"Dependency not found"))
+                        }
+                        else {
+                            workspaces[0]
+                        };
                         let (outputs_disc, inputs_disc) =
-                            ctxt.install(PkgSrc::new(workspace.clone(), false, pkg_id));
+                            context.install(PkgSrc::new(dep_workspace.clone(), false, pkg_id));
                         debug!("Installed %s, returned %? dependencies and \
                                %? transitive dependencies",
                                lib_name, outputs_disc.len(), inputs_disc.len());
@@ -402,8 +432,9 @@ pub fn find_and_install_dependencies(ctxt: &BuildContext,
                             }
                         }
                         // Also, add an additional search path
+                        debug!("Adding additional search path: %s", lib_name);
                         let installed_library =
-                            installed_library_in_workspace(lib_name, workspace)
+                            installed_library_in_workspace(&Path(lib_name), &dep_workspace)
                                 .expect( fmt!("rustpkg failed to install dependency %s",
                                               lib_name));
                         let install_dir = installed_library.pop();
index c2d87ddeb82bdd4a331e545b8ab9794b58b174c0..6eb4cc56a2bdde1cd322831a7804f17a8f7d1e5e 100644 (file)
@@ -118,7 +118,7 @@ pub fn try_getting_local_version(local_path: &Path) -> Option<Version> {
         if !l.is_whitespace() {
             output = Some(l);
         }
-        match output.chain(try_parsing_version) {
+        match output.and_then(try_parsing_version) {
             Some(v) => return Some(v),
             None    => ()
         }
@@ -158,7 +158,7 @@ pub fn try_getting_version(remote_path: &Path) -> Option<Version> {
                 }
             }
 
-            output.chain(try_parsing_version)
+            output.and_then(try_parsing_version)
         }
         else {
             None
index d5dd87ee44228614a5f7636e6b948d0d19f9e17a..dfe548c298e8ed12a70b139c3c72b2e226c6b634 100644 (file)
@@ -38,6 +38,8 @@ pub fn each_pkg_parent_workspace(cx: &Context, pkgid: &PkgId, action: &fn(&Path)
     return true;
 }
 
+/// Given a package ID, return a vector of all of the workspaces in
+/// the RUST_PATH that contain it
 pub fn pkg_parent_workspaces(cx: &Context, pkgid: &PkgId) -> ~[Path] {
     let rs: ~[Path] = rust_path().move_iter()
         .filter(|ws| workspace_contains_package_id(pkgid, ws))
index a4e841f98f804aeff48c21e36a6013f88b64bdae..ce8e90e1a4324395f823a02201d7e223563b957c 100644 (file)
@@ -45,7 +45,7 @@ pub fn capacity<T>(v: @[T]) -> uint {
 #[inline]
 pub fn build<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> @[A] {
     let mut vec = @[];
-    unsafe { raw::reserve(&mut vec, size.unwrap_or_default(4)); }
+    unsafe { raw::reserve(&mut vec, size.unwrap_or(4)); }
     builder(|x| unsafe { raw::push(&mut vec, x) });
     vec
 }
index 926e6e1f6b6e350212aef66d1bc01c5291da742f..4ef50094139aa749bc5fe244bbefae4a9cde4fa9 100644 (file)
@@ -24,6 +24,7 @@
 * `Ord`
 * `TotalOrd`
 * `Eq`
+* `Default`
 * `Zero`
 
 ## Various functions to compare `bool`s
@@ -43,6 +44,7 @@
 
 #[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering};
 #[cfg(not(test))] use ops::Not;
+#[cfg(not(test))] use default::Default;
 #[cfg(not(test))] use num::Zero;
 
 /**
@@ -323,6 +325,11 @@ impl Eq for bool {
     fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
 }
 
+#[cfg(not(test))]
+impl Default for bool {
+    fn default() -> bool { false }
+}
+
 #[cfg(not(test))]
 impl Zero for bool {
     fn zero() -> bool { false }
index 7f043b2ecaab3d047d40b5aaed3b6e96271fb9d8..911d883f88ac98c1f537b6c768ec306706c9a2ce 100644 (file)
@@ -12,7 +12,7 @@
 
 use cast::transmute;
 use option::{None, Option, Some};
-use i32;
+use iter::{Iterator, range_step};
 use str::StrSlice;
 use unicode::{derived_property, general_category, decompose};
 use to_str::ToStr;
@@ -21,6 +21,7 @@
 #[cfg(test)] use str::OwnedStr;
 
 #[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use default::Default;
 #[cfg(not(test))] use num::Zero;
 
 // UTF-8 ranges and tags for encoding characters
@@ -285,15 +286,14 @@ pub fn escape_unicode(c: char, f: &fn(char)) {
         (c <= '\uffff') { f('u'); 4 }
         _               { f('U'); 8 }
     );
-    do i32::range_step(4 * (pad - 1), -1, -4) |offset| {
+    for offset in range_step::<i32>(4 * (pad - 1), -1, -4) {
         unsafe {
             match ((c as i32) >> offset) & 0xf {
                 i @ 0 .. 9 => { f(transmute('0' as i32 + i)); }
                 i => { f(transmute('a' as i32 + (i - 10))); }
             }
         }
-        true
-    };
+    }
 }
 
 ///
@@ -434,9 +434,18 @@ impl Ord for char {
     fn lt(&self, other: &char) -> bool { *self < *other }
 }
 
+#[cfg(not(test))]
+impl Default for char {
+    #[inline]
+    fn default() -> char { '\x00' }
+}
+
 #[cfg(not(test))]
 impl Zero for char {
+    #[inline]
     fn zero() -> char { '\x00' }
+
+    #[inline]
     fn is_zero(&self) -> bool { *self == '\x00' }
 }
 
index 18c7674873f1685f4ff7cbe823ab3bda5f51e1c7..ec8314795ac0ea76b195eddd14ec5e9279dcf8c7 100644 (file)
@@ -66,15 +66,6 @@ pub fn stream<T: Send>() -> (Port<T>, Chan<T>) {
     (Port { x: p }, Chan { x: c })
 }
 
-pub struct SharedChan<T> { x: rtcomm::SharedChan<T> }
-
-impl<T: Send> SharedChan<T> {
-    pub fn new(c: Chan<T>) -> SharedChan<T> {
-        let Chan { x: c } = c;
-        SharedChan { x: rtcomm::SharedChan::new(c) }
-    }
-}
-
 impl<T: Send> ChanOne<T> {
     pub fn send(self, val: T) {
         let ChanOne { x: c } = self;
@@ -161,6 +152,16 @@ fn peek(&self) -> bool {
     }
 }
 
+
+pub struct SharedChan<T> { x: rtcomm::SharedChan<T> }
+
+impl<T: Send> SharedChan<T> {
+    pub fn new(c: Chan<T>) -> SharedChan<T> {
+        let Chan { x: c } = c;
+        SharedChan { x: rtcomm::SharedChan::new(c) }
+    }
+}
+
 impl<T: Send> GenericChan<T> for SharedChan<T> {
     fn send(&self, val: T) {
         let &SharedChan { x: ref c } = self;
@@ -193,3 +194,31 @@ fn clone(&self) -> SharedChan<T> {
         SharedChan { x: c.clone() }
     }
 }
+
+pub struct SharedPort<T> { x: rtcomm::SharedPort<T> }
+
+impl<T: Send> SharedPort<T> {
+    pub fn new(p: Port<T>) -> SharedPort<T> {
+        let Port { x: p } = p;
+        SharedPort { x: rtcomm::SharedPort::new(p) }
+    }
+}
+
+impl<T: Send> GenericPort<T> for SharedPort<T> {
+    fn recv(&self) -> T {
+        let &SharedPort { x: ref p } = self;
+        p.recv()
+    }
+
+    fn try_recv(&self) -> Option<T> {
+        let &SharedPort { x: ref p } = self;
+        p.try_recv()
+    }
+}
+
+impl<T> Clone for SharedPort<T> {
+    fn clone(&self) -> SharedPort<T> {
+        let &SharedPort { x: ref p } = self;
+        SharedPort { x: p.clone() }
+    }
+}
index fbc60ffd01b3aab5a784d652d5d2d7f821db54eb..120cf3fa8013bbb4e3bd50df1bbc655165ef33c7 100644 (file)
@@ -15,3 +15,15 @@ pub trait Default {
     /// Return the "default value" for a type.
     fn default() -> Self;
 }
+
+impl<T: Default + 'static> Default for @mut T {
+    fn default() -> @mut T { @mut Default::default() }
+}
+
+impl<T: Default + 'static> Default for @T {
+    fn default() -> @T { @Default::default() }
+}
+
+impl<T: Default> Default for ~T {
+    fn default() -> ~T { ~Default::default() }
+}
index ec9e6d1ca4bc47ee3fc82a991da182027258f8e2..27381f64ad4a6b05a996e9e932ca35b9d9ff45a0 100644 (file)
@@ -13,6 +13,7 @@
 #[allow(missing_doc)];
 
 use option::{Some, None};
+use option;
 use clone::Clone;
 use container::Container;
 use cmp::Eq;
@@ -53,18 +54,6 @@ pub fn flip(self) -> Either<R, L> {
         }
     }
 
-    /// Converts a `Either` to a `Result`
-    ///
-    /// Converts an `Either` type to a `Result` type, making the "right" choice
-    /// an `Ok` result, and the "left" choice a `Err`
-    #[inline]
-    pub fn to_result(self) -> Result<R, L> {
-        match self {
-            Right(r) => result::Ok(r),
-            Left(l) => result::Err(l)
-        }
-    }
-
     /// Checks whether the given value is a `Left`
     #[inline]
     pub fn is_left(&self) -> bool {
@@ -116,6 +105,101 @@ pub fn unwrap_right(self) -> R {
     }
 }
 
+/// A generic trait for converting a value to a `Either`
+pub trait ToEither<L, R> {
+    /// Convert to the `either` type
+    fn to_either(&self) -> Either<L, R>;
+}
+
+/// A generic trait for converting a value to a `Either`
+pub trait IntoEither<L, R> {
+    /// Convert to the `either` type
+    fn into_either(self) -> Either<L, R>;
+}
+
+/// A generic trait for converting a value to a `Either`
+pub trait AsEither<L, R> {
+    /// Convert to the `either` type
+    fn as_either<'a>(&'a self) -> Either<&'a L, &'a R>;
+}
+
+impl<L, R: Clone> option::ToOption<R> for Either<L, R> {
+    #[inline]
+    fn to_option(&self)-> option::Option<R> {
+        match *self {
+            Left(_) => None,
+            Right(ref r) => Some(r.clone()),
+        }
+    }
+}
+
+impl<L, R> option::IntoOption<R> for Either<L, R> {
+    #[inline]
+    fn into_option(self)-> option::Option<R> {
+        match self {
+            Left(_) => None,
+            Right(r) => Some(r),
+        }
+    }
+}
+
+impl<L, R> option::AsOption<R> for Either<L, R> {
+    #[inline]
+    fn as_option<'a>(&'a self) -> option::Option<&'a R> {
+        match *self {
+            Left(_) => None,
+            Right(ref r) => Some(r),
+        }
+    }
+}
+
+impl<L: Clone, R: Clone> result::ToResult<R, L> for Either<L, R> {
+    #[inline]
+    fn to_result(&self)-> result::Result<R, L> {
+        match *self {
+            Left(ref l) => result::Err(l.clone()),
+            Right(ref r) => result::Ok(r.clone()),
+        }
+    }
+}
+
+impl<L, R> result::IntoResult<R, L> for Either<L, R> {
+    #[inline]
+    fn into_result(self)-> result::Result<R, L> {
+        match self {
+            Left(l) => result::Err(l),
+            Right(r) => result::Ok(r),
+        }
+    }
+}
+
+impl<L, R> result::AsResult<R, L> for Either<L, R> {
+    #[inline]
+    fn as_result<'a>(&'a self) -> result::Result<&'a R, &'a L> {
+        match *self {
+            Left(ref l) => result::Err(l),
+            Right(ref r) => result::Ok(r),
+        }
+    }
+}
+
+impl<L: Clone, R: Clone> ToEither<L, R> for Either<L, R> {
+    fn to_either(&self) -> Either<L, R> { self.clone() }
+}
+
+impl<L, R> IntoEither<L, R> for Either<L, R> {
+    fn into_either(self) -> Either<L, R> { self }
+}
+
+impl<L, R> AsEither<L, R> for Either<L, R> {
+    fn as_either<'a>(&'a self) -> Either<&'a L, &'a R> {
+        match *self {
+            Left(ref l) => Left(l),
+            Right(ref r) => Right(r),
+        }
+    }
+}
+
 /// An iterator yielding the `Left` values of its source
 pub type Lefts<L, R, Iter> = FilterMap<'static, Either<L, R>, L, Iter>;
 
@@ -167,6 +251,11 @@ pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) {
 mod tests {
     use super::*;
 
+    use option::{IntoOption, ToOption, AsOption};
+    use option;
+    use result::{IntoResult, ToResult, AsResult};
+    use result;
+
     #[test]
     fn test_either_left() {
         let val = Left(10);
@@ -260,4 +349,87 @@ fn test_partition_empty() {
         assert_eq!(rights.len(), 0u);
     }
 
+    #[test]
+    pub fn test_to_option() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.to_option(), option::Some(100));
+        assert_eq!(left.to_option(), option::None);
+    }
+
+    #[test]
+    pub fn test_into_option() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.into_option(), option::Some(100));
+        assert_eq!(left.into_option(), option::None);
+    }
+
+    #[test]
+    pub fn test_as_option() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.as_option().unwrap(), &100);
+        assert_eq!(left.as_option(), option::None);
+    }
+
+    #[test]
+    pub fn test_to_result() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.to_result(), result::Ok(100));
+        assert_eq!(left.to_result(), result::Err(404));
+    }
+
+    #[test]
+    pub fn test_into_result() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.into_result(), result::Ok(100));
+        assert_eq!(left.into_result(), result::Err(404));
+    }
+
+    #[test]
+    pub fn test_as_result() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        let x = 100;
+        assert_eq!(right.as_result(), result::Ok(&x));
+
+        let x = 404;
+        assert_eq!(left.as_result(), result::Err(&x));
+    }
+
+    #[test]
+    pub fn test_to_either() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.to_either(), Right(100));
+        assert_eq!(left.to_either(), Left(404));
+    }
+
+    #[test]
+    pub fn test_into_either() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.into_either(), Right(100));
+        assert_eq!(left.into_either(), Left(404));
+    }
+
+    #[test]
+    pub fn test_as_either() {
+        let right: Either<int, int> = Right(100);
+        let left: Either<int, int> = Left(404);
+
+        assert_eq!(right.as_either().unwrap_right(), &100);
+        assert_eq!(left.as_either().unwrap_left(), &404);
+    }
 }
index 7d5033e3a6ad1579339ffe7077db16d8c0c3cc52..cad9f14bda734bd9164ecd23b5b431544e61bf3c 100644 (file)
@@ -36,7 +36,7 @@
 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!("{:?}", ~[3, 4])          // => ~"~[3, 4]"
 format!("{value}", value=4)       // => ~"4"
 format!("{} {}", 1, 2)            // => ~"1 2"
 ~~~
 When implementing a format trait for your own time, you will have to implement a
 method of the signature:
 
-~~~
+~~~{.rust}
 fn fmt(value: &T, f: &mut std::fmt::Formatter);
 ~~~
 
 struct. In order to help with this, the `Formatter` struct also provides some
 helper methods.
 
+### Related macros
+
+There are a number of related macros in the `format!` family. The ones that are
+currently implemented are:
+
+~~~{.rust}
+format!      // described above
+write!       // first argument is a &mut rt::io::Writer, the destination
+writeln!     // same as write but appends a newline
+print!       // the format string is printed to the standard output
+println!     // same as print but appends a newline
+format_args! // described below.
+~~~
+
+
+#### `write!`
+
+This and `writeln` are two macros which are used to emit the format string to a
+specified stream. This is used to prevent intermediate allocations of format
+strings and instead directly write the output. Under the hood, this function is
+actually invoking the `write` function defined in this module. Example usage is:
+
+~~~{.rust}
+use std::rt::io;
+
+let mut w = io::mem::MemWriter::new();
+write!(&mut w as &mut io::Writer, "Hello {}!", "world");
+~~~
+
+#### `print!`
+
+This and `println` emit their output to stdout. Similarly to the `write!` macro,
+the goal of these macros is to avoid intermediate allocations when printing
+output. Example usage is:
+
+~~~{.rust}
+print!("Hello {}!", "world");
+println!("I have a newline {}", "character at the end");
+~~~
+
+#### `format_args!`
+This is a curious macro which is used to safely pass around
+an opaque object describing the format string. This object
+does not require any heap allocations to create, and it only
+references information on the stack. Under the hood, all of
+the related macros are implemented in terms of this. First
+off, some example usage is:
+
+~~~{.rust}
+use std::fmt;
+
+format_args!(fmt::format, "this returns {}", "~str");
+format_args!(|args| { fmt::write(my_writer, args) }, "some {}", "args");
+format_args!(my_fn, "format {}", "string");
+~~~
+
+The first argument of the `format_args!` macro is a function (or closure) which
+takes one argument of type `&fmt::Arguments`. This structure can then be
+passed to the `write` and `format` functions inside this module in order to
+process the format string. The goal of this macro is to even further prevent
+intermediate allocations when dealing formatting strings.
+
+For example, a logging library could use the standard formatting syntax, but it
+would internally pass around this structure until it has been determined where
+output should go to.
+
+It is unsafe to programmatically create an instance of `fmt::Arguments` because
+the operations performed when executing a format string require the compile-time
+checks provided by the compiler. The `format_args!` macro is the only method of
+safely creating these structures, but they can be unsafely created with the
+constructor provided.
+
 ## Internationalization
 
 The formatting syntax supported by the `format!` extension supports
 to reference the string value of the argument which was selected upon. As an
 example:
 
-~~~
+~~~{.rust}
 format!("{0, select, other{#}}", "hello") // => ~"hello"
 ~~~
 
@@ -363,6 +435,32 @@ pub struct Argument<'self> {
     priv value: &'self util::Void,
 }
 
+impl<'self> Arguments<'self> {
+    /// When using the format_args!() macro, this function is used to generate the
+    /// Arguments structure. The compiler inserts an `unsafe` block to call this,
+    /// which is valid because the compiler performs all necessary validation to
+    /// ensure that the resulting call to format/write would be safe.
+    #[doc(hidden)] #[inline]
+    pub unsafe fn new<'a>(fmt: &'static [rt::Piece<'static>],
+                          args: &'a [Argument<'a>]) -> Arguments<'a> {
+        Arguments{ fmt: cast::transmute(fmt), args: args }
+    }
+}
+
+/// This structure represents a safely precompiled version of a format string
+/// and its arguments. This cannot be generated at runtime because it cannot
+/// safely be done so, so no constructors are given and the fields are private
+/// to prevent modification.
+///
+/// The `format_args!` macro will safely create an instance of this structure
+/// and pass it to a user-supplied function. The macro validates the format
+/// string at compile-time so usage of the `write` and `format` functions can
+/// be safely performed.
+pub struct Arguments<'self> {
+    priv fmt: &'self [rt::Piece<'self>],
+    priv args: &'self [Argument<'self>],
+}
+
 /// When a format is not otherwise specified, types are formatted by ascribing
 /// to this trait. There is not an explicit way of selecting this trait to be
 /// used for formatting, it is only if no other format is specified.
@@ -410,6 +508,33 @@ pub struct Argument<'self> {
 /// and a list of arguments. The arguments will be formatted according to the
 /// specified format string into the output stream provided.
 ///
+/// # Arguments
+///
+///   * output - the buffer to write output to
+///   * args - the precompiled arguments generated by `format_args!`
+///
+/// # Example
+///
+/// ~~~{.rust}
+/// use std::fmt;
+/// let w: &mut io::Writer = ...;
+/// format_args!(|args| { fmt::write(w, args) }, "Hello, {}!", "world");
+/// ~~~
+pub fn write(output: &mut io::Writer, args: &Arguments) {
+    unsafe { write_unsafe(output, args.fmt, args.args) }
+}
+
+/// The `writeln` function takes the same arguments as `write`, except that it
+/// will also write a newline (`\n`) character at the end of the format string.
+pub fn writeln(output: &mut io::Writer, args: &Arguments) {
+    unsafe { write_unsafe(output, args.fmt, args.args) }
+    output.write(['\n' as u8]);
+}
+
+/// The `write_unsafe` 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.
 ///
@@ -426,8 +551,9 @@ pub struct Argument<'self> {
 ///
 /// 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]) {
+pub unsafe fn write_unsafe(output: &mut io::Writer,
+                           fmt: &[rt::Piece],
+                           args: &[Argument]) {
     let mut formatter = Formatter {
         flags: 0,
         width: None,
@@ -446,6 +572,25 @@ pub unsafe fn write(output: &mut io::Writer,
 /// The format function takes a precompiled format string and a list of
 /// arguments, to return the resulting formatted string.
 ///
+/// # Arguments
+///
+///   * args - a structure of arguments generated via the `format_args!` macro.
+///            Because this structure can only be safely generated at
+///            compile-time, this function is safe.
+///
+/// # Example
+///
+/// ~~~{.rust}
+/// use std::fmt;
+/// let s = format_args!(fmt::format, "Hello, {}!", "world");
+/// assert_eq!(s, "Hello, world!");
+/// ~~~
+pub fn format(args: &Arguments) -> ~str {
+    unsafe { format_unsafe(args.fmt, args.args) }
+}
+
+/// The unsafe version of the formatting function.
+///
 /// This is currently an unsafe function because the types of all arguments
 /// aren't verified by immediate callers of this function. This currently does
 /// not validate that the correct types of arguments are specified for each
@@ -465,9 +610,9 @@ pub unsafe fn write(output: &mut io::Writer,
 ///
 /// Note that this function assumes that there are enough arguments for the
 /// format string.
-pub unsafe fn format(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
+pub unsafe fn format_unsafe(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
     let mut output = MemWriter::new();
-    write(&mut output as &mut io::Writer, fmt, args);
+    write_unsafe(&mut output as &mut io::Writer, fmt, args);
     return str::from_utf8_owned(output.inner());
 }
 
@@ -740,7 +885,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 `format` function.
-#[doc(hidden)]
+#[doc(hidden)] #[inline]
 pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
                        t: &'a T) -> Argument<'a> {
     unsafe {
@@ -753,14 +898,14 @@ pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
 
 /// When the compiler determines that the type of an argument *must* be a string
 /// (such as for select), then it invokes this method.
-#[doc(hidden)]
+#[doc(hidden)] #[inline]
 pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> {
     argument(String::fmt, s)
 }
 
 /// When the compiler determines that the type of an argument *must* be a uint
 /// (such as for plural), then it invokes this method.
-#[doc(hidden)]
+#[doc(hidden)] #[inline]
 pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
     argument(Unsigned::fmt, s)
 }
@@ -899,14 +1044,8 @@ fn fmt(t: &*T, f: &mut Formatter) {
         }
     }
 }
-
 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);
-        }
-    }
+    fn fmt(t: &*mut T, f: &mut Formatter) { Pointer::fmt(&(*t as *T), f) }
 }
 
 // Implementation of Default for various core types
@@ -940,7 +1079,6 @@ fn fmt(me: &$ty, f: &mut Formatter) {
 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) }
 }
index fd0e86d7a3177b0ef92c77245f45d1ee82d0213d..9888af9313b9df01a756e914c04fec1577a0b7fa 100644 (file)
@@ -554,7 +554,7 @@ fn count(&mut self) -> Count {
     /// characters.
     fn word(&mut self) -> &'self str {
         let start = match self.cur.clone().next() {
-            Some((pos, c)) if char::is_alphabetic(c) => {
+            Some((pos, c)) if char::is_XID_start(c) => {
                 self.cur.next();
                 pos
             }
@@ -563,7 +563,7 @@ fn word(&mut self) -> &'self str {
         let mut end;
         loop {
             match self.cur.clone().next() {
-                Some((_, c)) if char::is_alphanumeric(c) => {
+                Some((_, c)) if char::is_XID_continue(c) => {
                     self.cur.next();
                 }
                 Some((pos, _)) => { end = pos; break }
index fab8299f7a75ded2ab35946c36413d88621ccf0b..6c0a6a4ea0a157b9b62624ddacbdafcc7a8ef8fe 100644 (file)
@@ -18,6 +18,7 @@
 use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
 use clone::Clone;
 use cmp::{Eq, Equiv};
+use default::Default;
 use hash::Hash;
 use iter::{Iterator, FromIterator, Extendable};
 use iter::{FilterMap, Chain, Repeat, Zip};
@@ -622,6 +623,10 @@ fn extend<T: Iterator<(K, V)>>(&mut self, iter: &mut T) {
     }
 }
 
+impl<K: Eq + Hash, V> Default for HashMap<K, V> {
+    fn default() -> HashMap<K, V> { HashMap::new() }
+}
+
 /// An implementation of a hash set using the underlying representation of a
 /// HashMap where the value is (). As with the `HashMap` type, a `HashSet`
 /// requires that the elements implement the `Eq` and `Hash` traits.
@@ -687,6 +692,17 @@ pub fn with_capacity(capacity: uint) -> HashSet<T> {
         HashSet { map: HashMap::with_capacity(capacity) }
     }
 
+    /// Create an empty HashSet with space for at least `capacity`
+    /// elements in the hash table, using `k0` and `k1` as the keys.
+    ///
+    /// Warning: `k0` and `k1` are normally randomly generated, and
+    /// are designed to allow HashSets to be resistant to attacks that
+    /// cause many collisions and very poor performance. Setting them
+    /// manually using this function can expose a DoS attack vector.
+    pub fn with_capacity_and_keys(k0: u64, k1: u64, capacity: uint) -> HashSet<T> {
+        HashSet { map: HashMap::with_capacity_and_keys(k0, k1, capacity) }
+    }
+
     /// Reserve space for at least `n` elements in the hash table.
     pub fn reserve_at_least(&mut self, n: uint) {
         self.map.reserve_at_least(n)
@@ -770,6 +786,10 @@ fn extend<T: Iterator<K>>(&mut self, iter: &mut T) {
     }
 }
 
+impl<K: Eq + Hash> Default for HashSet<K> {
+    fn default() -> HashSet<K> { HashSet::new() }
+}
+
 // `Repeat` is used to feed the filter closure an explicit capture
 // of a reference to the other set
 /// Set operations iterator
index e9b704c2686fb227ba9a937aa5c9cc3fb719840b..2ca36de4f49cce83a79c69e1736c49027abfca25 100644 (file)
@@ -1618,7 +1618,7 @@ fn write_i8(&self, n: i8) { self.write([n as u8]) }
 }
 
 pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> {
-    mk_file_writer(path, flags).chain(|w| Ok(w))
+    mk_file_writer(path, flags).and_then(|w| Ok(w))
 }
 
 
@@ -1779,7 +1779,7 @@ pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
 }
 
 pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
-    do read_whole_file(file).chain |bytes| {
+    do read_whole_file(file).and_then |bytes| {
         if str::is_utf8(bytes) {
             Ok(str::from_utf8(bytes))
         } else {
@@ -1791,7 +1791,7 @@ pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
 // FIXME (#2004): implement this in a low-level way. Going through the
 // abstractions is pointless.
 pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
-    do file_reader(file).chain |rdr| {
+    do file_reader(file).and_then |rdr| {
         Ok(rdr.read_whole_stream())
     }
 }
index 5ca827350d01eb4fccd0a0fb572742a02bd6a8f4..07d2aeac627b87be769bbaf7e2d143993f362b28 100644 (file)
@@ -21,7 +21,7 @@
 use num::{Zero, One, Integer, CheckedAdd, CheckedSub, Saturating};
 use option::{Option, Some, None};
 use ops::{Add, Mul, Sub};
-use cmp::Ord;
+use cmp::{Eq, Ord};
 use clone::Clone;
 use uint;
 use util;
@@ -1474,7 +1474,7 @@ pub struct Scan<'self, A, B, T, St> {
 impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for Scan<'self, A, B, T, St> {
     #[inline]
     fn next(&mut self) -> Option<B> {
-        self.iter.next().chain(|a| (self.f)(&mut self.state, a))
+        self.iter.next().and_then(|a| (self.f)(&mut self.state, a))
     }
 
     #[inline]
@@ -1494,8 +1494,7 @@ pub struct FlatMap<'self, A, T, U> {
     priv backiter: Option<U>,
 }
 
-impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for
-    FlatMap<'self, A, T, U> {
+impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for FlatMap<'self, A, T, U> {
     #[inline]
     fn next(&mut self) -> Option<B> {
         loop {
@@ -1505,7 +1504,7 @@ fn next(&mut self) -> Option<B> {
                 }
             }
             match self.iter.next().map_move(|x| (self.f)(x)) {
-                None => return self.backiter.chain_mut_ref(|it| it.next()),
+                None => return self.backiter.and_then_mut_ref(|it| it.next()),
                 next => self.frontiter = next,
             }
         }
@@ -1537,7 +1536,7 @@ fn next_back(&mut self) -> Option<B> {
                 }
             }
             match self.iter.next_back().map_move(|x| (self.f)(x)) {
-                None => return self.frontiter.chain_mut_ref(|it| it.next_back()),
+                None => return self.frontiter.and_then_mut_ref(|it| it.next_back()),
                 next => self.backiter = next,
             }
         }
@@ -1720,7 +1719,21 @@ pub fn count<A>(start: A, step: A) -> Counter<A> {
     Counter{state: start, step: step}
 }
 
-/// A range of numbers from [0, N)
+impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        let result = self.state.clone();
+        self.state = self.state + self.step;
+        Some(result)
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        (uint::max_value, None) // Too bad we can't specify an infinite lower bound
+    }
+}
+
+/// An iterator over the range [start, stop)
 #[deriving(Clone, DeepClone)]
 pub struct Range<A> {
     priv state: A,
@@ -1750,14 +1763,12 @@ fn next(&mut self) -> Option<A> {
     // Blocked on #8605 Need numeric trait for converting to `Option<uint>`
 }
 
-impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
+/// `Integer` is required to ensure the range will be the same regardless of
+/// the direction it is consumed.
+impl<A: Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
         if self.stop > self.state {
-            // Integer doesn't technically define this rule, but we're going to assume that every
-            // Integer is reachable from every other one by adding or subtracting enough Ones. This
-            // seems like a reasonable-enough rule that every Integer should conform to, even if it
-            // can't be statically checked.
             self.stop = self.stop - self.one;
             Some(self.stop.clone())
         } else {
@@ -1766,7 +1777,7 @@ fn next_back(&mut self) -> Option<A> {
     }
 }
 
-/// A range of numbers from [0, N]
+/// An iterator over the range [start, stop]
 #[deriving(Clone, DeepClone)]
 pub struct RangeInclusive<A> {
     priv range: Range<A>,
@@ -1779,17 +1790,17 @@ pub fn range_inclusive<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> R
     RangeInclusive{range: range(start, stop), done: false}
 }
 
-impl<A: Add<A, A> + Ord + Clone> Iterator<A> for RangeInclusive<A> {
+impl<A: Add<A, A> + Eq + Ord + Clone> Iterator<A> for RangeInclusive<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
         match self.range.next() {
             Some(x) => Some(x),
             None => {
-                if self.done {
-                    None
-                } else {
+                if !self.done && self.range.state == self.range.stop {
                     self.done = true;
                     Some(self.range.stop.clone())
+                } else {
+                    None
                 }
             }
         }
@@ -1818,26 +1829,79 @@ fn next_back(&mut self) -> Option<A> {
             let result = self.range.stop.clone();
             self.range.stop = self.range.stop - self.range.one;
             Some(result)
-        } else if self.done {
-            None
-        } else {
+        } else if !self.done && self.range.state == self.range.stop {
             self.done = true;
             Some(self.range.stop.clone())
+        } else {
+            None
         }
     }
 }
 
-impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
+/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[deriving(Clone, DeepClone)]
+pub struct RangeStep<A> {
+    priv state: A,
+    priv stop: A,
+    priv step: A,
+    priv rev: bool
+}
+
+/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step<A: CheckedAdd + Ord + Clone + Zero>(start: A, stop: A, step: A) -> RangeStep<A> {
+    let rev = step < Zero::zero();
+    RangeStep{state: start, stop: stop, step: step, rev: rev}
+}
+
+impl<A: CheckedAdd + Ord + Clone> Iterator<A> for RangeStep<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
-        let result = self.state.clone();
-        self.state = self.state + self.step;
-        Some(result)
+        if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) {
+            let result = self.state.clone();
+            match self.state.checked_add(&self.step) {
+                Some(x) => self.state = x,
+                None => self.state = self.stop.clone()
+            }
+            Some(result)
+        } else {
+            None
+        }
     }
+}
 
+/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[deriving(Clone, DeepClone)]
+pub struct RangeStepInclusive<A> {
+    priv state: A,
+    priv stop: A,
+    priv step: A,
+    priv rev: bool,
+    priv done: bool
+}
+
+/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step_inclusive<A: CheckedAdd + Ord + Clone + Zero>(start: A, stop: A,
+                                                                step: A) -> RangeStepInclusive<A> {
+    let rev = step < Zero::zero();
+    RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false}
+}
+
+impl<A: CheckedAdd + Ord + Clone + Eq> Iterator<A> for RangeStepInclusive<A> {
     #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        (uint::max_value, None) // Too bad we can't specify an infinite lower bound
+    fn next(&mut self) -> Option<A> {
+        if !self.done && ((self.rev && self.state >= self.stop) ||
+                          (!self.rev && self.state <= self.stop)) {
+            let result = self.state.clone();
+            match self.state.checked_add(&self.step) {
+                Some(x) => self.state = x,
+                None => self.done = true
+            }
+            Some(result)
+        } else {
+            None
+        }
     }
 }
 
@@ -2644,10 +2708,44 @@ fn test_double_ended_range() {
         }
     }
 
+    #[test]
+    fn test_range() {
+        assert_eq!(range(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4]);
+        assert_eq!(range(0i, 5).invert().collect::<~[int]>(), ~[4, 3, 2, 1, 0]);
+        assert_eq!(range(200, -5).collect::<~[int]>(), ~[]);
+        assert_eq!(range(200, -5).invert().collect::<~[int]>(), ~[]);
+        assert_eq!(range(200, 200).collect::<~[int]>(), ~[]);
+        assert_eq!(range(200, 200).invert().collect::<~[int]>(), ~[]);
+    }
+
     #[test]
     fn test_range_inclusive() {
         assert_eq!(range_inclusive(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4, 5]);
         assert_eq!(range_inclusive(0i, 5).invert().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]);
+        assert_eq!(range_inclusive(200, -5).collect::<~[int]>(), ~[]);
+        assert_eq!(range_inclusive(200, -5).invert().collect::<~[int]>(), ~[]);
+        assert_eq!(range_inclusive(200, 200).collect::<~[int]>(), ~[200]);
+        assert_eq!(range_inclusive(200, 200).invert().collect::<~[int]>(), ~[200]);
+    }
+
+    #[test]
+    fn test_range_step() {
+        assert_eq!(range_step(0i, 20, 5).collect::<~[int]>(), ~[0, 5, 10, 15]);
+        assert_eq!(range_step(20i, 0, -5).collect::<~[int]>(), ~[20, 15, 10, 5]);
+        assert_eq!(range_step(20i, 0, -6).collect::<~[int]>(), ~[20, 14, 8, 2]);
+        assert_eq!(range_step(200u8, 255, 50).collect::<~[u8]>(), ~[200u8, 250]);
+        assert_eq!(range_step(200, -5, 1).collect::<~[int]>(), ~[]);
+        assert_eq!(range_step(200, 200, 1).collect::<~[int]>(), ~[]);
+    }
+
+    #[test]
+    fn test_range_step_inclusive() {
+        assert_eq!(range_step_inclusive(0i, 20, 5).collect::<~[int]>(), ~[0, 5, 10, 15, 20]);
+        assert_eq!(range_step_inclusive(20i, 0, -5).collect::<~[int]>(), ~[20, 15, 10, 5, 0]);
+        assert_eq!(range_step_inclusive(20i, 0, -6).collect::<~[int]>(), ~[20, 14, 8, 2]);
+        assert_eq!(range_step_inclusive(200u8, 255, 50).collect::<~[u8]>(), ~[200u8, 250]);
+        assert_eq!(range_step_inclusive(200, -5, 1).collect::<~[int]>(), ~[]);
+        assert_eq!(range_step_inclusive(200, 200, 1).collect::<~[int]>(), ~[200]);
     }
 
     #[test]
index a13c75635dc412b00d8ccdbdaf2d07a0dc39dc8d..89bdb57e2bdb80fe5945971d6c8661b805319067 100644 (file)
 the TLS slot.  Useful for dynamic variables, singletons, and interfacing with
 foreign code with bad callback interfaces.
 
-To use, declare a static variable of the type you wish to store. The
-initialization should be `&local_data::Key`. This is then the key to what you
-wish to store.
+To declare a new key for storing local data of a particular type, use the
+`local_data_key!` macro. This macro will expand to a `static` item apppriately
+named and annotated. This name is then passed to the functions in this module to
+modify/read the slot specified by the key.
 
 ~~~{.rust}
 use std::local_data;
 local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
 
 local_data::set(key_vector, ~[4]);
-local_data::get(key_int, |opt| assert_eq!(opt, Some(&~[4])));
+local_data::get(key_vector, |opt| assert_eq!(opt, Some(&~[4])));
 ~~~
 
-Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
-magic.
-
 */
 
+// Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
+// magic.
+
 use cast;
 use libc;
 use prelude::*;
index 1b91276f904d6ee2a717215cce7586d0da20d416..db5edc2009e516353b910b2d9d0962ceae4e5ccb 100644 (file)
@@ -12,9 +12,8 @@
 
 use option::*;
 use os;
-use either::*;
 use rt;
-use rt::logging::{Logger, StdErrLogger};
+use rt::logging::{Logger, StdErrLogger, OwnedString};
 
 /// Turns on logging to stdout globally
 pub fn console_on() {
@@ -57,12 +56,12 @@ fn newsched_log_str(msg: ~str) {
         match optional_task {
             Some(local) => {
                 // Use the available logger
-                (*local).logger.log(Left(msg));
+                (*local).logger.log(OwnedString(msg));
             }
             None => {
                 // There is no logger anywhere, just write to stderr
                 let mut logger = StdErrLogger;
-                logger.log(Left(msg));
+                logger.log(OwnedString(msg));
             }
         }
     }
index 899d6236aaaaa109dc335c0f339a74c6c3ce4b7a..0addcce3eb608657b6a50ae2c438cee6d8f946f1 100644 (file)
@@ -12,6 +12,7 @@
 #[allow(missing_doc)];
 #[allow(non_uppercase_statics)];
 
+use default::Default;
 use libc::c_int;
 use num::{Zero, One, strconv};
 use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
@@ -237,6 +238,11 @@ fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
     }
 }
 
+impl Default for f32 {
+    #[inline]
+    fn default() -> f32 { 0.0 }
+}
+
 impl Zero for f32 {
     #[inline]
     fn zero() -> f32 { 0.0 }
index 6ab8350a11544e9ea2299f3820015372c5571e75..b0675278238e4c0e8fe92751cdd48e06c5bc9dbd 100644 (file)
@@ -13,6 +13,7 @@
 #[allow(missing_doc)];
 #[allow(non_uppercase_statics)];
 
+use default::Default;
 use libc::c_int;
 use num::{Zero, One, strconv};
 use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
@@ -260,6 +261,11 @@ fn clamp(&self, mn: &f64, mx: &f64) -> f64 {
     }
 }
 
+impl Default for f64 {
+    #[inline]
+    fn default() -> f64 { 0.0 }
+}
+
 impl Zero for f64 {
     #[inline]
     fn zero() -> f64 { 0.0 }
index df26fadae16588a09d07fdce90aad9444a2c0906..3952f5478f7fdb956963edddae97a2fe71c3f2e2 100644 (file)
@@ -23,6 +23,7 @@
 #[allow(missing_doc)];
 #[allow(non_uppercase_statics)];
 
+use default::Default;
 use num::{Zero, One, strconv};
 use num::FPCategory;
 use num;
@@ -382,6 +383,11 @@ fn clamp(&self, mn: &float, mx: &float) -> float {
     }
 }
 
+impl Default for float {
+    #[inline]
+    fn default() -> float { 0.0 }
+}
+
 impl Zero for float {
     #[inline]
     fn zero() -> float { 0.0 }
index 07cafb0a4f126877e86664f6edf357f19edbb5cd..3a43c3364c67bfe478ae70f514aed16d7c41d0b1 100644 (file)
@@ -16,6 +16,7 @@ macro_rules! int_module (($T:ty, $bits:expr) => (mod generated {
 
 #[allow(non_uppercase_statics)];
 
+use default::Default;
 use num::{ToStrRadix, FromStrRadix};
 use num::{CheckedDiv, Zero, One, strconv};
 use prelude::*;
@@ -40,101 +41,6 @@ fn checked_div(&self, v: &$T) -> Option<$T> {
     }
 }
 
-enum Range { Closed, HalfOpen }
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed;
-/// otherwise `term` denotes the half-open interval `[stop-step,stop)`.
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_j == start + step*j`, and `x_n` lies in the interval `term`.
-///
-/// If no such nonnegative integer `n` exists, then the iteration range
-/// is empty.
-///
-fn range_step_core(start: $T, stop: $T, step: $T, r: Range, it: &fn($T) -> bool) -> bool {
-    let mut i = start;
-    if step == 0 {
-        fail!(~"range_step called with step == 0");
-    } else if step == (1 as $T) { // elide bounds check to tighten loop
-        while i < stop {
-            if !it(i) { return false; }
-            // no need for overflow check;
-            // cannot have i + 1 > max_value because i < stop <= max_value
-            i += (1 as $T);
-        }
-    } else if step == (-1 as $T) { // elide bounds check to tighten loop
-        while i > stop {
-            if !it(i) { return false; }
-            // no need for underflow check;
-            // cannot have i - 1 < min_value because i > stop >= min_value
-            i -= (1 as $T);
-        }
-    } else if step > 0 { // ascending
-        while i < stop {
-            if !it(i) { return false; }
-            // avoiding overflow. break if i + step > max_value
-            if i > max_value - step { return true; }
-            i += step;
-        }
-    } else { // descending
-        while i > stop {
-            if !it(i) { return false; }
-            // avoiding underflow. break if i + step < min_value
-            if i < min_value - step { return true; }
-            i += step;
-        }
-    }
-    match r {
-        HalfOpen => return true,
-        Closed => return (i != stop || it(i))
-    }
-}
-
-#[inline]
-///
-/// Iterate through the range [`start`..`stop`) with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// * `x_i == start + step*i`, and
-/// * `n` is the greatest nonnegative integer such that `x_n < stop`
-///
-/// (If no such `n` exists, then the iteration range is empty.)
-///
-/// # Arguments
-///
-/// * `start` - lower bound, inclusive
-/// * `stop` - higher bound, exclusive
-///
-/// # Examples
-/// ~~~
-/// let mut sum = 0;
-/// for int::range(1, 5) |i| {
-///     sum += i;
-/// }
-/// assert!(sum == 10);
-/// ~~~
-///
-pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool {
-    range_step_core(start, stop, step, HalfOpen, it)
-}
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_i == start + step*i` and `x_n <= last < step + x_n`.
-///
-/// (If no such nonnegative integer `n` exists, then the iteration
-///  range is empty.)
-///
-pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool) -> bool {
-    range_step_core(start, last, step, Closed, it)
-}
-
 impl Num for $T {}
 
 #[cfg(not(test))]
@@ -167,6 +73,11 @@ fn clamp(&self, mn: &$T, mx: &$T) -> $T {
     }
 }
 
+impl Default for $T {
+    #[inline]
+    fn default() -> $T { 0 }
+}
+
 impl Zero for $T {
     #[inline]
     fn zero() -> $T { 0 }
@@ -472,20 +383,6 @@ fn bytes(_: Option<$T>) -> uint { bits / 8 }
 
 // String conversion functions and impl str -> num
 
-/// Parse a string as a number in base 10.
-#[inline]
-pub fn from_str(s: &str) -> Option<$T> {
-    strconv::from_str_common(s, 10u, true, false, false,
-                         strconv::ExpNone, false, false)
-}
-
-/// Parse a string as a number in the given base.
-#[inline]
-pub fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
-    strconv::from_str_common(s, radix, true, false, false,
-                         strconv::ExpNone, false, false)
-}
-
 /// Parse a byte slice as a number in the given base.
 #[inline]
 pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
@@ -496,14 +393,16 @@ pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
 impl FromStr for $T {
     #[inline]
     fn from_str(s: &str) -> Option<$T> {
-        from_str(s)
+        strconv::from_str_common(s, 10u, true, false, false,
+                             strconv::ExpNone, false, false)
     }
 }
 
 impl FromStrRadix for $T {
     #[inline]
     fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
-        from_str_radix(s, radix)
+        strconv::from_str_common(s, radix, true, false, false,
+                             strconv::ExpNone, false, false)
     }
 }
 
@@ -551,10 +450,7 @@ mod tests {
     use super::*;
 
     use int;
-    use i16;
     use i32;
-    use i64;
-    use i8;
     use num;
     use sys;
 
@@ -759,20 +655,20 @@ fn test_primitive() {
 
     #[test]
     fn test_from_str() {
-        assert_eq!(from_str("0"), Some(0 as $T));
-        assert_eq!(from_str("3"), Some(3 as $T));
-        assert_eq!(from_str("10"), Some(10 as $T));
-        assert_eq!(i32::from_str("123456789"), Some(123456789 as i32));
-        assert_eq!(from_str("00100"), Some(100 as $T));
+        assert_eq!(from_str::<$T>("0"), Some(0 as $T));
+        assert_eq!(from_str::<$T>("3"), Some(3 as $T));
+        assert_eq!(from_str::<$T>("10"), Some(10 as $T));
+        assert_eq!(from_str::<i32>("123456789"), Some(123456789 as i32));
+        assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
 
-        assert_eq!(from_str("-1"), Some(-1 as $T));
-        assert_eq!(from_str("-3"), Some(-3 as $T));
-        assert_eq!(from_str("-10"), Some(-10 as $T));
-        assert_eq!(i32::from_str("-123456789"), Some(-123456789 as i32));
-        assert_eq!(from_str("-00100"), Some(-100 as $T));
+        assert_eq!(from_str::<$T>("-1"), Some(-1 as $T));
+        assert_eq!(from_str::<$T>("-3"), Some(-3 as $T));
+        assert_eq!(from_str::<$T>("-10"), Some(-10 as $T));
+        assert_eq!(from_str::<i32>("-123456789"), Some(-123456789 as i32));
+        assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T));
 
-        assert!(from_str(" ").is_none());
-        assert!(from_str("x").is_none());
+        assert!(from_str::<$T>(" ").is_none());
+        assert!(from_str::<$T>("x").is_none());
     }
 
     #[test]
@@ -840,86 +736,36 @@ fn test_int_to_str_overflow() {
     #[test]
     fn test_int_from_str_overflow() {
         let mut i8_val: i8 = 127_i8;
-        assert_eq!(i8::from_str("127"), Some(i8_val));
-        assert!(i8::from_str("128").is_none());
+        assert_eq!(from_str::<i8>("127"), Some(i8_val));
+        assert!(from_str::<i8>("128").is_none());
 
         i8_val += 1 as i8;
-        assert_eq!(i8::from_str("-128"), Some(i8_val));
-        assert!(i8::from_str("-129").is_none());
+        assert_eq!(from_str::<i8>("-128"), Some(i8_val));
+        assert!(from_str::<i8>("-129").is_none());
 
         let mut i16_val: i16 = 32_767_i16;
-        assert_eq!(i16::from_str("32767"), Some(i16_val));
-        assert!(i16::from_str("32768").is_none());
+        assert_eq!(from_str::<i16>("32767"), Some(i16_val));
+        assert!(from_str::<i16>("32768").is_none());
 
         i16_val += 1 as i16;
-        assert_eq!(i16::from_str("-32768"), Some(i16_val));
-        assert!(i16::from_str("-32769").is_none());
+        assert_eq!(from_str::<i16>("-32768"), Some(i16_val));
+        assert!(from_str::<i16>("-32769").is_none());
 
         let mut i32_val: i32 = 2_147_483_647_i32;
-        assert_eq!(i32::from_str("2147483647"), Some(i32_val));
-        assert!(i32::from_str("2147483648").is_none());
+        assert_eq!(from_str::<i32>("2147483647"), Some(i32_val));
+        assert!(from_str::<i32>("2147483648").is_none());
 
         i32_val += 1 as i32;
-        assert_eq!(i32::from_str("-2147483648"), Some(i32_val));
-        assert!(i32::from_str("-2147483649").is_none());
+        assert_eq!(from_str::<i32>("-2147483648"), Some(i32_val));
+        assert!(from_str::<i32>("-2147483649").is_none());
 
         let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
-        assert_eq!(i64::from_str("9223372036854775807"), Some(i64_val));
-        assert!(i64::from_str("9223372036854775808").is_none());
+        assert_eq!(from_str::<i64>("9223372036854775807"), Some(i64_val));
+        assert!(from_str::<i64>("9223372036854775808").is_none());
 
         i64_val += 1 as i64;
-        assert_eq!(i64::from_str("-9223372036854775808"), Some(i64_val));
-        assert!(i64::from_str("-9223372036854775809").is_none());
-    }
-
-    #[test]
-    fn test_ranges() {
-        let mut l = ~[];
-
-        do range_step(20,26,2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(36,30,-2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(max_value - 2, max_value, 2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(max_value - 3, max_value, 2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(min_value + 2, min_value, -2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(min_value + 3, min_value, -2) |i| {
-            l.push(i);
-            true
-        };
-        assert_eq!(l, ~[20,22,24,
-                        36,34,32,
-                        max_value-2,
-                        max_value-3,max_value-1,
-                        min_value+2,
-                        min_value+3,min_value+1]);
-
-        // None of the `fail`s should execute.
-        do range_step(10,0,1) |_i| {
-            fail!(~"unreachable");
-        };
-        do range_step(0,10,-1) |_i| {
-            fail!(~"unreachable");
-        };
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_range_step_zero_step() {
-        do range_step(0,10,0) |_i| { true };
+        assert_eq!(from_str::<i64>("-9223372036854775808"), Some(i64_val));
+        assert!(from_str::<i64>("-9223372036854775809").is_none());
     }
 
     #[test]
index 135124b04c143a4bcb27cdcbf160618507f4ddd9..f0efeb762cce125f90c285a3144875da2e0196f7 100644 (file)
@@ -279,6 +279,7 @@ pub trait Primitive: Clone
                    + DeepClone
                    + Num
                    + NumCast
+                   + Orderable
                    + Bounded
                    + Neg<Self>
                    + Add<Self,Self>
@@ -438,6 +439,11 @@ pub trait FromStrRadix {
     fn from_str_radix(str: &str, radix: uint) -> Option<Self>;
 }
 
+/// A utility function that just calls FromStrRadix::from_str_radix
+pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
+    FromStrRadix::from_str_radix(str, radix)
+}
+
 /// Calculates a power to a given radix, optimized for uint `pow` and `radix`.
 ///
 /// Returns `radix^pow` as `T`.
index effeb60fc220d6fa5d7b8c5573b85aa6606c7e16..0a9c912a6e2acbe0bbc142dd820190adafea86ec 100644 (file)
@@ -16,6 +16,7 @@ macro_rules! uint_module (($T:ty, $T_SIGNED:ty, $bits:expr) => (mod generated {
 
 #[allow(non_uppercase_statics)];
 
+use default::Default;
 use num::BitCount;
 use num::{ToStrRadix, FromStrRadix};
 use num::{CheckedDiv, Zero, One, strconv};
@@ -41,101 +42,6 @@ fn checked_div(&self, v: &$T) -> Option<$T> {
     }
 }
 
-enum Range { Closed, HalfOpen }
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed;
-/// otherwise `term` denotes the half-open interval `[stop-step,stop)`.
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_j == start + step*j`, and `x_n` lies in the interval `term`.
-///
-/// If no such nonnegative integer `n` exists, then the iteration range
-/// is empty.
-///
-fn range_step_core(start: $T, stop: $T, step: $T_SIGNED, r: Range, it: &fn($T) -> bool) -> bool {
-    let mut i = start;
-    if step == 0 {
-        fail!("range_step called with step == 0");
-    } else if step == (1 as $T_SIGNED) { // elide bounds check to tighten loop
-        while i < stop {
-            if !it(i) { return false; }
-            // no need for overflow check;
-            // cannot have i + 1 > max_value because i < stop <= max_value
-            i += (1 as $T);
-        }
-    } else if step == (-1 as $T_SIGNED) { // elide bounds check to tighten loop
-        while i > stop {
-            if !it(i) { return false; }
-            // no need for underflow check;
-            // cannot have i - 1 < min_value because i > stop >= min_value
-            i -= (1 as $T);
-        }
-    } else if step > 0 { // ascending
-        while i < stop {
-            if !it(i) { return false; }
-            // avoiding overflow. break if i + step > max_value
-            if i > max_value - (step as $T) { return true; }
-            i += step as $T;
-        }
-    } else { // descending
-        while i > stop {
-            if !it(i) { return false; }
-            // avoiding underflow. break if i + step < min_value
-            if i < min_value + ((-step) as $T) { return true; }
-            i -= -step as $T;
-        }
-    }
-    match r {
-        HalfOpen => return true,
-        Closed => return (i != stop || it(i))
-    }
-}
-
-#[inline]
-///
-/// Iterate through the range [`start`..`stop`) with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// - `x_i == start + step*i`, and
-/// - `n` is the greatest nonnegative integer such that `x_n < stop`
-///
-/// (If no such `n` exists, then the iteration range is empty.)
-///
-/// # Arguments
-///
-/// * `start` - lower bound, inclusive
-/// * `stop` - higher bound, exclusive
-///
-/// # Examples
-/// ~~~ {.rust}
-/// let nums = [1,2,3,4,5,6,7];
-///
-/// for uint::range_step(0, nums.len() - 1, 2) |i| {
-///     printfln!("%d & %d", nums[i], nums[i+1]);
-/// }
-/// ~~~
-///
-pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool {
-    range_step_core(start, stop, step, HalfOpen, it)
-}
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_i == start + step*i` and `x_n <= last < step + x_n`.
-///
-/// (If no such nonnegative integer `n` exists, then the iteration
-///  range is empty.)
-///
-pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool {
-    range_step_core(start, last, step, Closed, it)
-}
-
 impl Num for $T {}
 
 #[cfg(not(test))]
@@ -172,6 +78,11 @@ fn clamp(&self, mn: &$T, mx: &$T) -> $T {
     }
 }
 
+impl Default for $T {
+    #[inline]
+    fn default() -> $T { 0 }
+}
+
 impl Zero for $T {
     #[inline]
     fn zero() -> $T { 0 }
@@ -327,20 +238,6 @@ impl Int for $T {}
 
 // String conversion functions and impl str -> num
 
-/// Parse a string as a number in base 10.
-#[inline]
-pub fn from_str(s: &str) -> Option<$T> {
-    strconv::from_str_common(s, 10u, false, false, false,
-                             strconv::ExpNone, false, false)
-}
-
-/// Parse a string as a number in the given base.
-#[inline]
-pub fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
-    strconv::from_str_common(s, radix, false, false, false,
-                             strconv::ExpNone, false, false)
-}
-
 /// Parse a byte slice as a number in the given base.
 #[inline]
 pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
@@ -351,14 +248,16 @@ pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
 impl FromStr for $T {
     #[inline]
     fn from_str(s: &str) -> Option<$T> {
-        from_str(s)
+        strconv::from_str_common(s, 10u, false, false, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
 impl FromStrRadix for $T {
     #[inline]
     fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
-        from_str_radix(s, radix)
+        strconv::from_str_common(s, radix, false, false, false,
+                                 strconv::ExpNone, false, false)
     }
 }
 
@@ -436,9 +335,6 @@ mod tests {
     use num;
     use sys;
     use u16;
-    use u32;
-    use u64;
-    use u8;
 
     #[test]
     fn test_num() {
@@ -548,15 +444,15 @@ pub fn test_to_str() {
 
     #[test]
     pub fn test_from_str() {
-        assert_eq!(from_str("0"), Some(0u as $T));
-        assert_eq!(from_str("3"), Some(3u as $T));
-        assert_eq!(from_str("10"), Some(10u as $T));
-        assert_eq!(u32::from_str("123456789"), Some(123456789 as u32));
-        assert_eq!(from_str("00100"), Some(100u as $T));
+        assert_eq!(from_str::<$T>("0"), Some(0u as $T));
+        assert_eq!(from_str::<$T>("3"), Some(3u as $T));
+        assert_eq!(from_str::<$T>("10"), Some(10u as $T));
+        assert_eq!(from_str::<u32>("123456789"), Some(123456789 as u32));
+        assert_eq!(from_str::<$T>("00100"), Some(100u as $T));
 
-        assert!(from_str("").is_none());
-        assert!(from_str(" ").is_none());
-        assert!(from_str("x").is_none());
+        assert!(from_str::<$T>("").is_none());
+        assert!(from_str::<$T>(" ").is_none());
+        assert!(from_str::<$T>("x").is_none());
     }
 
     #[test]
@@ -603,36 +499,36 @@ fn test_uint_to_str_overflow() {
     #[test]
     fn test_uint_from_str_overflow() {
         let mut u8_val: u8 = 255_u8;
-        assert_eq!(u8::from_str("255"), Some(u8_val));
-        assert!(u8::from_str("256").is_none());
+        assert_eq!(from_str::<u8>("255"), Some(u8_val));
+        assert!(from_str::<u8>("256").is_none());
 
         u8_val += 1 as u8;
-        assert_eq!(u8::from_str("0"), Some(u8_val));
-        assert!(u8::from_str("-1").is_none());
+        assert_eq!(from_str::<u8>("0"), Some(u8_val));
+        assert!(from_str::<u8>("-1").is_none());
 
         let mut u16_val: u16 = 65_535_u16;
-        assert_eq!(u16::from_str("65535"), Some(u16_val));
-        assert!(u16::from_str("65536").is_none());
+        assert_eq!(from_str::<u16>("65535"), Some(u16_val));
+        assert!(from_str::<u16>("65536").is_none());
 
         u16_val += 1 as u16;
-        assert_eq!(u16::from_str("0"), Some(u16_val));
-        assert!(u16::from_str("-1").is_none());
+        assert_eq!(from_str::<u16>("0"), Some(u16_val));
+        assert!(from_str::<u16>("-1").is_none());
 
         let mut u32_val: u32 = 4_294_967_295_u32;
-        assert_eq!(u32::from_str("4294967295"), Some(u32_val));
-        assert!(u32::from_str("4294967296").is_none());
+        assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
+        assert!(from_str::<u32>("4294967296").is_none());
 
         u32_val += 1 as u32;
-        assert_eq!(u32::from_str("0"), Some(u32_val));
-        assert!(u32::from_str("-1").is_none());
+        assert_eq!(from_str::<u32>("0"), Some(u32_val));
+        assert!(from_str::<u32>("-1").is_none());
 
         let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
-        assert_eq!(u64::from_str("18446744073709551615"), Some(u64_val));
-        assert!(u64::from_str("18446744073709551616").is_none());
+        assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
+        assert!(from_str::<u64>("18446744073709551616").is_none());
 
         u64_val += 1 as u64;
-        assert_eq!(u64::from_str("0"), Some(u64_val));
-        assert!(u64::from_str("-1").is_none());
+        assert_eq!(from_str::<u64>("0"), Some(u64_val));
+        assert!(from_str::<u64>("-1").is_none());
     }
 
     #[test]
@@ -647,62 +543,6 @@ pub fn to_str_radix37() {
         100u.to_str_radix(37u);
     }
 
-    #[test]
-    pub fn test_ranges() {
-        let mut l = ~[];
-
-        do range_step(20,26,2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(36,30,-2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(max_value - 2, max_value, 2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(max_value - 3, max_value, 2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(min_value + 2, min_value, -2) |i| {
-            l.push(i);
-            true
-        };
-        do range_step(min_value + 3, min_value, -2) |i| {
-            l.push(i);
-            true
-        };
-
-        assert_eq!(l, ~[20,22,24,
-                        36,34,32,
-                        max_value-2,
-                        max_value-3,max_value-1,
-                        min_value+2,
-                        min_value+3,min_value+1]);
-
-        // None of the `fail`s should execute.
-        do range_step(10,0,1) |_i| {
-            fail!("unreachable");
-        };
-        do range_step(0,1,-10) |_i| {
-            fail!("unreachable");
-        };
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_range_step_zero_step_up() {
-        do range_step(0,10,0) |_i| { true };
-    }
-    #[test]
-    #[should_fail]
-    fn test_range_step_zero_step_down() {
-        do range_step(0,-10,0) |_i| { true };
-    }
-
     #[test]
     fn test_unsigned_checked_div() {
         assert_eq!(10u.checked_div(&2), Some(5));
index b72046cce72173c5317ad28c394b10f6a23f4fcc..ce725257dfff03a4fefba00aa2df45b5172d15d5 100644 (file)
 
 use clone::Clone;
 use cmp::{Eq,Ord};
+use default::Default;
+use either;
 use util;
 use num::Zero;
 use iter;
 use iter::{Iterator, DoubleEndedIterator, ExactSize};
+use result;
 use str::{StrSlice, OwnedStr};
 use to_str::ToStr;
 use clone::DeepClone;
@@ -126,45 +129,64 @@ pub fn is_none(&self) -> bool {
     #[inline]
     pub fn is_some(&self) -> bool { !self.is_none() }
 
-    /// Update an optional value by optionally running its content through a
-    /// function that returns an option.
+    /// Returns `None` if the option is `None`, otherwise returns `optb`.
     #[inline]
-    pub fn chain<U>(self, f: &fn(t: T) -> Option<U>) -> Option<U> {
+    pub fn and(self, optb: Option<T>) -> Option<T> {
         match self {
-            Some(t) => f(t),
-            None => None
+            Some(_) => optb,
+            None => None,
         }
     }
 
-    /// Returns the leftmost Some() value, or None if both are None.
+    /// Returns `None` if the option is `None`, otherwise calls `f` with the
+    /// wrapped value and returns the result.
     #[inline]
-    pub fn or(self, optb: Option<T>) -> Option<T> {
+    pub fn and_then<U>(self, f: &fn(T) -> Option<U>) -> Option<U> {
         match self {
-            Some(opta) => Some(opta),
-            _ => optb
+            Some(x) => f(x),
+            None => None,
         }
     }
 
-    /// Update an optional value by optionally running its content by reference
-    /// through a function that returns an option.
+    /// Returns `None` if the option is `None`, otherwise calls `f` with a
+    /// reference to the wrapped value and returns the result.
     #[inline]
-    pub fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option<U>) -> Option<U> {
+    pub fn and_then_ref<'a, U>(&'a self, f: &fn(&'a T) -> Option<U>) -> Option<U> {
         match *self {
             Some(ref x) => f(x),
             None => None
         }
     }
 
-    /// Update an optional value by optionally running its content by mut reference
-    /// through a function that returns an option.
+    /// Returns `None` if the option is `None`, otherwise calls `f` with a
+    /// mutable reference to the wrapped value and returns the result.
     #[inline]
-    pub fn chain_mut_ref<'a, U>(&'a mut self, f: &fn(x: &'a mut T) -> Option<U>) -> Option<U> {
+    pub fn and_then_mut_ref<'a, U>(&'a mut self, f: &fn(&'a mut T) -> Option<U>) -> Option<U> {
         match *self {
             Some(ref mut x) => f(x),
             None => None
         }
     }
 
+    /// Returns the option if it contains a value, otherwise returns `optb`.
+    #[inline]
+    pub fn or(self, optb: Option<T>) -> Option<T> {
+        match self {
+            Some(_) => self,
+            None => optb
+        }
+    }
+
+    /// Returns the option if it contains a value, otherwise calls `f` and
+    /// returns the result.
+    #[inline]
+    pub fn or_else(self, f: &fn() -> Option<T>) -> Option<T> {
+        match self {
+            Some(_) => self,
+            None => f(),
+        }
+    }
+
     /// Filters an optional value using given function.
     #[inline(always)]
     pub fn filtered(self, f: &fn(t: &T) -> bool) -> Option<T> {
@@ -332,13 +354,22 @@ pub fn expect(self, reason: &str) -> T {
 
     /// Returns the contained value or a default
     #[inline]
-    pub fn unwrap_or_default(self, def: T) -> T {
+    pub fn unwrap_or(self, def: T) -> T {
         match self {
             Some(x) => x,
             None => def
         }
     }
 
+    /// Returns the contained value or computes it from a closure
+    #[inline]
+    pub fn unwrap_or_else(self, f: &fn() -> T) -> T {
+        match self {
+            Some(x) => x,
+            None => f()
+        }
+    }
+
     /// Applies a function zero or more times until the result is `None`.
     #[inline]
     pub fn while_some(self, blk: &fn(v: T) -> Option<T>) {
@@ -349,6 +380,109 @@ pub fn while_some(self, blk: &fn(v: T) -> Option<T>) {
     }
 }
 
+/// A generic trait for converting a value to a `Option`
+pub trait ToOption<T> {
+    /// Convert to the `option` type
+    fn to_option(&self) -> Option<T>;
+}
+
+/// A generic trait for converting a value to a `Option`
+pub trait IntoOption<T> {
+    /// Convert to the `option` type
+    fn into_option(self) -> Option<T>;
+}
+
+/// A generic trait for converting a value to a `Option`
+pub trait AsOption<T> {
+    /// Convert to the `option` type
+    fn as_option<'a>(&'a self) -> Option<&'a T>;
+}
+
+impl<T: Clone> ToOption<T> for Option<T> {
+    #[inline]
+    fn to_option(&self) -> Option<T> { self.clone() }
+}
+
+impl<T> IntoOption<T> for Option<T> {
+    #[inline]
+    fn into_option(self) -> Option<T> { self }
+}
+
+impl<T> AsOption<T> for Option<T> {
+    #[inline]
+    fn as_option<'a>(&'a self) -> Option<&'a T> {
+        match *self {
+            Some(ref x) => Some(x),
+            None => None,
+        }
+    }
+}
+
+impl<T: Clone> result::ToResult<T, ()> for Option<T> {
+    #[inline]
+    fn to_result(&self) -> result::Result<T, ()> {
+        match *self {
+            Some(ref x) => result::Ok(x.clone()),
+            None => result::Err(()),
+        }
+    }
+}
+
+impl<T> result::IntoResult<T, ()> for Option<T> {
+    #[inline]
+    fn into_result(self) -> result::Result<T, ()> {
+        match self {
+            Some(x) => result::Ok(x),
+            None => result::Err(()),
+        }
+    }
+}
+
+impl<T: Clone> either::ToEither<(), T> for Option<T> {
+    #[inline]
+    fn to_either(&self) -> either::Either<(), T> {
+        match *self {
+            Some(ref x) => either::Right(x.clone()),
+            None => either::Left(()),
+        }
+    }
+}
+
+impl<T> either::IntoEither<(), T> for Option<T> {
+    #[inline]
+    fn into_either(self) -> either::Either<(), T> {
+        match self {
+            Some(x) => either::Right(x),
+            None => either::Left(()),
+        }
+    }
+}
+
+impl<T: Default> Option<T> {
+    /// Returns the contained value or default (for this type)
+    #[inline]
+    pub fn unwrap_or_default(self) -> T {
+        match self {
+            Some(x) => x,
+            None => Default::default()
+        }
+    }
+
+    /// Returns self or `Some`-wrapped default value
+    #[inline]
+    pub fn or_default(self) -> Option<T> {
+        match self {
+            None => Some(Default::default()),
+            x => x,
+        }
+    }
+}
+
+impl<T> Default for Option<T> {
+    #[inline]
+    fn default() -> Option<T> { None }
+}
+
 impl<T:Zero> Option<T> {
     /// Returns the contained value or zero (for this type)
     #[inline]
@@ -369,11 +503,6 @@ pub fn or_zero(self) -> Option<T> {
     }
 }
 
-impl<T> Zero for Option<T> {
-    fn zero() -> Option<T> { None }
-    fn is_zero(&self) -> bool { self.is_none() }
-}
-
 /// An iterator that yields either one or zero elements
 #[deriving(Clone, DeepClone)]
 pub struct OptionIterator<A> {
@@ -407,6 +536,11 @@ impl<A> ExactSize<A> for OptionIterator<A> {}
 #[cfg(test)]
 mod tests {
     use super::*;
+
+    use either::{IntoEither, ToEither};
+    use either;
+    use result::{IntoResult, ToResult};
+    use result;
     use util;
 
     #[test]
@@ -475,6 +609,50 @@ fn test_option_too_much_dance() {
         let _y3 = y.take_unwrap();
     }
 
+    #[test]
+    fn test_and() {
+        let x: Option<int> = Some(1);
+        assert_eq!(x.and(Some(2)), Some(2));
+        assert_eq!(x.and(None), None);
+
+        let x: Option<int> = None;
+        assert_eq!(x.and(Some(2)), None);
+        assert_eq!(x.and(None), None);
+    }
+
+    #[test]
+    fn test_and_then() {
+        let x: Option<int> = Some(1);
+        assert_eq!(x.and_then(|x| Some(x + 1)), Some(2));
+        assert_eq!(x.and_then(|_| None::<int>), None);
+
+        let x: Option<int> = None;
+        assert_eq!(x.and_then(|x| Some(x + 1)), None);
+        assert_eq!(x.and_then(|_| None::<int>), None);
+    }
+
+    #[test]
+    fn test_or() {
+        let x: Option<int> = Some(1);
+        assert_eq!(x.or(Some(2)), Some(1));
+        assert_eq!(x.or(None), Some(1));
+
+        let x: Option<int> = None;
+        assert_eq!(x.or(Some(2)), Some(2));
+        assert_eq!(x.or(None), None);
+    }
+
+    #[test]
+    fn test_or_else() {
+        let x: Option<int> = Some(1);
+        assert_eq!(x.or_else(|| Some(2)), Some(1));
+        assert_eq!(x.or_else(|| None), Some(1));
+
+        let x: Option<int> = None;
+        assert_eq!(x.or_else(|| Some(2)), Some(2));
+        assert_eq!(x.or_else(|| None), None);
+    }
+
     #[test]
     fn test_option_while_some() {
         let mut i = 0;
@@ -489,6 +667,44 @@ fn test_option_while_some() {
         assert_eq!(i, 11);
     }
 
+    #[test]
+    fn test_unwrap() {
+        assert_eq!(Some(1).unwrap(), 1);
+        assert_eq!(Some(~"hello").unwrap(), ~"hello");
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_unwrap_fail1() {
+        let x: Option<int> = None;
+        x.unwrap();
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_unwrap_fail2() {
+        let x: Option<~str> = None;
+        x.unwrap();
+    }
+
+    #[test]
+    fn test_unwrap_or() {
+        let x: Option<int> = Some(1);
+        assert_eq!(x.unwrap_or(2), 1);
+
+        let x: Option<int> = None;
+        assert_eq!(x.unwrap_or(2), 2);
+    }
+
+    #[test]
+    fn test_unwrap_or_else() {
+        let x: Option<int> = Some(1);
+        assert_eq!(x.unwrap_or_else(|| 2), 1);
+
+        let x: Option<int> = None;
+        assert_eq!(x.unwrap_or_else(|| 2), 2);
+    }
+
     #[test]
     fn test_unwrap_or_zero() {
         let some_stuff = Some(42);
@@ -566,4 +782,67 @@ fn test_mutate() {
         assert!(!x.mutate_default(0i, |i| i+1));
         assert_eq!(x, Some(0i));
     }
+
+    #[test]
+    pub fn test_to_option() {
+        let some: Option<int> = Some(100);
+        let none: Option<int> = None;
+
+        assert_eq!(some.to_option(), Some(100));
+        assert_eq!(none.to_option(), None);
+    }
+
+    #[test]
+    pub fn test_into_option() {
+        let some: Option<int> = Some(100);
+        let none: Option<int> = None;
+
+        assert_eq!(some.into_option(), Some(100));
+        assert_eq!(none.into_option(), None);
+    }
+
+    #[test]
+    pub fn test_as_option() {
+        let some: Option<int> = Some(100);
+        let none: Option<int> = None;
+
+        assert_eq!(some.as_option().unwrap(), &100);
+        assert_eq!(none.as_option(), None);
+    }
+
+    #[test]
+    pub fn test_to_result() {
+        let some: Option<int> = Some(100);
+        let none: Option<int> = None;
+
+        assert_eq!(some.to_result(), result::Ok(100));
+        assert_eq!(none.to_result(), result::Err(()));
+    }
+
+    #[test]
+    pub fn test_into_result() {
+        let some: Option<int> = Some(100);
+        let none: Option<int> = None;
+
+        assert_eq!(some.into_result(), result::Ok(100));
+        assert_eq!(none.into_result(), result::Err(()));
+    }
+
+    #[test]
+    pub fn test_to_either() {
+        let some: Option<int> = Some(100);
+        let none: Option<int> = None;
+
+        assert_eq!(some.to_either(), either::Right(100));
+        assert_eq!(none.to_either(), either::Left(()));
+    }
+
+    #[test]
+    pub fn test_into_either() {
+        let some: Option<int> = Some(100);
+        let none: Option<int> = None;
+
+        assert_eq!(some.into_either(), either::Right(100));
+        assert_eq!(none.into_either(), either::Left(()));
+    }
 }
index ab1210aabadc69451fa4bdefb49b287e113d75b0..5269eca888af8c31c9ebf9cae452724a441a8f19 100644 (file)
@@ -569,7 +569,7 @@ fn secondary() -> Option<Path> {
 
     #[cfg(windows)]
     fn secondary() -> Option<Path> {
-        do getenv("USERPROFILE").chain |p| {
+        do getenv("USERPROFILE").and_then |p| {
             if !p.is_empty() {
                 Some(Path(p))
             } else {
@@ -611,7 +611,7 @@ fn lookup() -> Path {
         if cfg!(target_os = "android") {
             Path("/data/tmp")
         } else {
-            getenv_nonempty("TMPDIR").unwrap_or_default(Path("/tmp"))
+            getenv_nonempty("TMPDIR").unwrap_or(Path("/tmp"))
         }
     }
 
@@ -620,7 +620,7 @@ fn lookup() -> Path {
         getenv_nonempty("TMP").or(
             getenv_nonempty("TEMP").or(
                 getenv_nonempty("USERPROFILE").or(
-                   getenv_nonempty("WINDIR")))).unwrap_or_default(Path("C:\\Windows"))
+                   getenv_nonempty("WINDIR")))).unwrap_or(Path("C:\\Windows"))
     }
 }
 
@@ -1895,8 +1895,8 @@ fn homedir() {
         setenv("USERPROFILE", "/home/PaloAlto");
         assert_eq!(os::homedir(), Some(Path("/home/MountainView")));
 
-        oldhome.iter().advance(|s| { setenv("HOME", *s); true });
-        olduserprofile.iter().advance(|s| { setenv("USERPROFILE", *s); true });
+        for s in oldhome.iter() { setenv("HOME", *s) }
+        for s in olduserprofile.iter() { setenv("USERPROFILE", *s) }
     }
 
     #[test]
index fafb15119738a55ad9d6f271122b6f2e41046ee0..6e90e2a1070b59aea6aeb383f74262a666eb5ade 100644 (file)
@@ -383,7 +383,7 @@ unsafe fn offset(self, count: int) -> *mut T { mut_offset(self, count) }
 }
 
 // Equality for pointers
-#[cfg(not(test))]
+#[cfg(stage0, not(test))]
 impl<T> Eq for *T {
     #[inline]
     fn eq(&self, other: &*T) -> bool {
@@ -393,7 +393,17 @@ fn eq(&self, other: &*T) -> bool {
     fn ne(&self, other: &*T) -> bool { !self.eq(other) }
 }
 
-#[cfg(not(test))]
+#[cfg(not(stage0), not(test))]
+impl<T> Eq for *T {
+    #[inline]
+    fn eq(&self, other: &*T) -> bool {
+        *self == *other
+    }
+    #[inline]
+    fn ne(&self, other: &*T) -> bool { !self.eq(other) }
+}
+
+#[cfg(stage0, not(test))]
 impl<T> Eq for *mut T {
     #[inline]
     fn eq(&self, other: &*mut T) -> bool {
@@ -403,6 +413,16 @@ fn eq(&self, other: &*mut T) -> bool {
     fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
 }
 
+#[cfg(not(stage0), not(test))]
+impl<T> Eq for *mut T {
+    #[inline]
+    fn eq(&self, other: &*mut T) -> bool {
+        *self == *other
+    }
+    #[inline]
+    fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
+}
+
 // Equivalence for pointers
 #[cfg(not(test))]
 impl<T> Equiv<*mut T> for *T {
@@ -460,7 +480,7 @@ fn ne(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
 }
 
 // Comparison for pointers
-#[cfg(not(test))]
+#[cfg(stage0, not(test))]
 impl<T> Ord for *T {
     #[inline]
     fn lt(&self, other: &*T) -> bool {
@@ -480,7 +500,27 @@ fn gt(&self, other: &*T) -> bool {
     }
 }
 
-#[cfg(not(test))]
+#[cfg(not(stage0), not(test))]
+impl<T> Ord for *T {
+    #[inline]
+    fn lt(&self, other: &*T) -> bool {
+        *self < *other
+    }
+    #[inline]
+    fn le(&self, other: &*T) -> bool {
+        *self <= *other
+    }
+    #[inline]
+    fn ge(&self, other: &*T) -> bool {
+        *self >= *other
+    }
+    #[inline]
+    fn gt(&self, other: &*T) -> bool {
+        *self > *other
+    }
+}
+
+#[cfg(stage0, not(test))]
 impl<T> Ord for *mut T {
     #[inline]
     fn lt(&self, other: &*mut T) -> bool {
@@ -500,6 +540,26 @@ fn gt(&self, other: &*mut T) -> bool {
     }
 }
 
+#[cfg(not(stage0), not(test))]
+impl<T> Ord for *mut T {
+    #[inline]
+    fn lt(&self, other: &*mut T) -> bool {
+        *self < *other
+    }
+    #[inline]
+    fn le(&self, other: &*mut T) -> bool {
+        *self <= *other
+    }
+    #[inline]
+    fn ge(&self, other: &*mut T) -> bool {
+        *self >= *other
+    }
+    #[inline]
+    fn gt(&self, other: &*mut T) -> bool {
+        *self > *other
+    }
+}
+
 #[cfg(test)]
 pub mod ptr_tests {
     use super::*;
index 813901207bb2dcca86d6b83393c44acb78478561..1330096ee36a6f59fa475f0cb1a4ba57e0cc1b82 100644 (file)
@@ -48,7 +48,7 @@ fn main () {
 use cmp;
 use container::Container;
 use int;
-use iter::{Iterator, range};
+use iter::{Iterator, range, range_step};
 use local_data;
 use num;
 use prelude::*;
@@ -748,7 +748,7 @@ macro_rules! mix(
         if use_rsl {
             macro_rules! memloop (
                 ($arr:expr) => {{
-                    do u32::range_step(0, RAND_SIZE, 8) |i| {
+                    for i in range_step(0u32, RAND_SIZE, 8) {
                         a+=$arr[i  ]; b+=$arr[i+1];
                         c+=$arr[i+2]; d+=$arr[i+3];
                         e+=$arr[i+4]; f+=$arr[i+5];
@@ -758,22 +758,20 @@ macro_rules! memloop (
                         self.mem[i+2]=c; self.mem[i+3]=d;
                         self.mem[i+4]=e; self.mem[i+5]=f;
                         self.mem[i+6]=g; self.mem[i+7]=h;
-                        true
-                    };
+                    }
                 }}
             );
 
             memloop!(self.rsl);
             memloop!(self.mem);
         } else {
-            do u32::range_step(0, RAND_SIZE, 8) |i| {
+            for i in range_step(0u32, RAND_SIZE, 8) {
                 mix!();
                 self.mem[i  ]=a; self.mem[i+1]=b;
                 self.mem[i+2]=c; self.mem[i+3]=d;
                 self.mem[i+4]=e; self.mem[i+5]=f;
                 self.mem[i+6]=g; self.mem[i+7]=h;
-                true
-            };
+            }
         }
 
         self.isaac();
@@ -794,7 +792,7 @@ macro_rules! ind (($x:expr) => {
         });
         macro_rules! rngstep(
             ($j:expr, $shift:expr) => {{
-                let base = base + $j;
+                let base = $j;
                 let mix = if $shift < 0 {
                     a >> -$shift as uint
                 } else {
@@ -813,13 +811,12 @@ macro_rules! rngstep(
 
         let r = [(0, MIDPOINT), (MIDPOINT, 0)];
         for &(mr_offset, m2_offset) in r.iter() {
-            do uint::range_step(0, MIDPOINT, 4) |base| {
-                rngstep!(0, 13);
-                rngstep!(1, -6);
-                rngstep!(2, 2);
-                rngstep!(3, -16);
-                true
-            };
+            for i in range_step(0u, MIDPOINT, 4) {
+                rngstep!(i + 0, 13);
+                rngstep!(i + 1, -6);
+                rngstep!(i + 2, 2);
+                rngstep!(i + 3, -16);
+            }
         }
 
         self.a = a;
index 793086dca78dc044785fcea2faa1bf24ddb747cb..3811f34cec43c1d5f0d4ebe32501dfdfd5eaa18b 100644 (file)
@@ -17,6 +17,7 @@
 use either;
 use iter::Iterator;
 use option::{None, Option, Some, OptionIterator};
+use option;
 use vec;
 use vec::OwnedVector;
 use to_str::ToStr;
@@ -36,18 +37,6 @@ pub enum Result<T, E> {
 }
 
 impl<T, E: ToStr> Result<T, E> {
-    /// Convert to the `either` type
-    ///
-    /// `Ok` result variants are converted to `either::Right` variants, `Err`
-    /// result variants are converted to `either::Left`.
-    #[inline]
-    pub fn to_either(self)-> either::Either<E, T>{
-        match self {
-            Ok(t) => either::Right(t),
-            Err(e) => either::Left(e),
-        }
-    }
-
     /// Get a reference to the value out of a successful result
     ///
     /// # Failure
@@ -182,10 +171,22 @@ pub fn map_err_move<F>(self, op: &fn(E) -> F) -> Result<T,F> {
         }
     }
 
+    /// Call a method based on a previous result
+    ///
+    /// If `self` is `Ok`, then `res` it is returned. If `self` is `Err`,
+    /// then `self` is returned.
+    #[inline]
+    pub fn and(self, res: Result<T, E>) -> Result<T, E> {
+        match self {
+            Ok(_) => res,
+            Err(_) => self,
+        }
+    }
+
     /// Call a method based on a previous result
     ///
     /// If `self` is `Ok` then the value is extracted and passed to `op`
-    /// whereupon `op`s result is returned. if `self` is `Err` then it is
+    /// whereupon `op`s result is returned. If `self` is `Err` then it is
     /// immediately returned. This function can be used to compose the results
     /// of two functions.
     ///
@@ -195,13 +196,25 @@ pub fn map_err_move<F>(self, op: &fn(E) -> F) -> Result<T,F> {
     ///         Ok(parse_bytes(buf))
     ///     };
     #[inline]
-    pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
+    pub fn and_then<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
         match self {
             Ok(t) => op(t),
             Err(e) => Err(e),
         }
     }
 
+    /// Call a method based on a previous result
+    ///
+    /// If `self` is `Ok`, then `self` is returned. If `self` is `Err`
+    /// then `res` is returned.
+    #[inline]
+    pub fn or(self, res: Result<T, E>) -> Result<T, E> {
+        match self {
+            Ok(_) => self,
+            Err(_) => res,
+        }
+    }
+
     /// Call a function based on a previous result
     ///
     /// If `self` is `Err` then the value is extracted and passed to `op`
@@ -209,7 +222,7 @@ pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
     /// immediately returned.  This function can be used to pass through a
     /// successful result while handling an error.
     #[inline]
-    pub fn chain_err<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> {
+    pub fn or_else<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> {
         match self {
             Ok(t) => Ok(t),
             Err(e) => op(e),
@@ -255,6 +268,104 @@ pub fn map<U>(&self, op: &fn(&T) -> U) -> Result<U,E> {
     }
 }
 
+/// A generic trait for converting a value to a `Result`
+pub trait ToResult<T, E> {
+    /// Convert to the `result` type
+    fn to_result(&self) -> Result<T, E>;
+}
+
+/// A generic trait for converting a value to a `Result`
+pub trait IntoResult<T, E> {
+    /// Convert to the `result` type
+    fn into_result(self) -> Result<T, E>;
+}
+
+/// A generic trait for converting a value to a `Result`
+pub trait AsResult<T, E> {
+    /// Convert to the `result` type
+    fn as_result<'a>(&'a self) -> Result<&'a T, &'a E>;
+}
+
+impl<T: Clone, E> option::ToOption<T> for Result<T, E> {
+    #[inline]
+    fn to_option(&self)-> Option<T> {
+        match *self {
+            Ok(ref t) => Some(t.clone()),
+            Err(_) => None,
+        }
+    }
+}
+
+impl<T, E> option::IntoOption<T> for Result<T, E> {
+    #[inline]
+    fn into_option(self)-> Option<T> {
+        match self {
+            Ok(t) => Some(t),
+            Err(_) => None,
+        }
+    }
+}
+
+impl<T, E> option::AsOption<T> for Result<T, E> {
+    #[inline]
+    fn as_option<'a>(&'a self)-> Option<&'a T> {
+        match *self {
+            Ok(ref t) => Some(t),
+            Err(_) => None,
+        }
+    }
+}
+
+impl<T: Clone, E: Clone> ToResult<T, E> for Result<T, E> {
+    #[inline]
+    fn to_result(&self) -> Result<T, E> { self.clone() }
+}
+
+impl<T, E> IntoResult<T, E> for Result<T, E> {
+    #[inline]
+    fn into_result(self) -> Result<T, E> { self }
+}
+
+impl<T, E> AsResult<T, E> for Result<T, E> {
+    #[inline]
+    fn as_result<'a>(&'a self) -> Result<&'a T, &'a E> {
+        match *self {
+            Ok(ref t) => Ok(t),
+            Err(ref e) => Err(e),
+        }
+    }
+}
+
+impl<T: Clone, E: Clone> either::ToEither<E, T> for Result<T, E> {
+    #[inline]
+    fn to_either(&self)-> either::Either<E, T> {
+        match *self {
+            Ok(ref t) => either::Right(t.clone()),
+            Err(ref e) => either::Left(e.clone()),
+        }
+    }
+}
+
+impl<T, E> either::IntoEither<E, T> for Result<T, E> {
+    #[inline]
+    fn into_either(self)-> either::Either<E, T> {
+        match self {
+            Ok(t) => either::Right(t),
+            Err(e) => either::Left(e),
+        }
+    }
+}
+
+impl<T, E> either::AsEither<E, T> for Result<T, E> {
+    #[inline]
+    fn as_either<'a>(&'a self)-> either::Either<&'a E, &'a T> {
+        match *self {
+            Ok(ref t) => either::Right(t),
+            Err(ref e) => either::Left(e),
+        }
+    }
+}
+
 #[inline]
 #[allow(missing_doc)]
 pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>,
@@ -334,27 +445,51 @@ pub fn fold_<T, E, Iter: Iterator<Result<T, E>>>(
 mod tests {
     use super::*;
 
+    use either::{IntoEither, ToEither, AsEither};
     use either;
     use iter::range;
+    use option::{IntoOption, ToOption, AsOption};
+    use option;
     use str::OwnedStr;
     use vec::ImmutableVector;
 
     pub fn op1() -> Result<int, ~str> { Ok(666) }
+    pub fn op2() -> Result<int, ~str> { Err(~"sadface") }
+
+    #[test]
+    pub fn test_and() {
+        assert_eq!(op1().and(Ok(667)).unwrap(), 667);
+        assert_eq!(op1().and(Err(~"bad")).unwrap_err(), ~"bad");
 
-    pub fn op2(i: int) -> Result<uint, ~str> {
-        Ok(i as uint + 1u)
+        assert_eq!(op2().and(Ok(667)).unwrap_err(), ~"sadface");
+        assert_eq!(op2().and(Err(~"bad")).unwrap_err(), ~"sadface");
     }
 
-    pub fn op3() -> Result<int, ~str> { Err(~"sadface") }
+    #[test]
+    pub fn test_and_then() {
+        assert_eq!(op1().and_then(|i| Ok::<int, ~str>(i + 1)).unwrap(), 667);
+        assert_eq!(op1().and_then(|_| Err::<int, ~str>(~"bad")).unwrap_err(), ~"bad");
+
+        assert_eq!(op2().and_then(|i| Ok::<int, ~str>(i + 1)).unwrap_err(), ~"sadface");
+        assert_eq!(op2().and_then(|_| Err::<int, ~str>(~"bad")).unwrap_err(), ~"sadface");
+    }
 
     #[test]
-    pub fn chain_success() {
-        assert_eq!(op1().chain(op2).unwrap(), 667u);
+    pub fn test_or() {
+        assert_eq!(op1().or(Ok(667)).unwrap(), 666);
+        assert_eq!(op1().or(Err(~"bad")).unwrap(), 666);
+
+        assert_eq!(op2().or(Ok(667)).unwrap(), 667);
+        assert_eq!(op2().or(Err(~"bad")).unwrap_err(), ~"bad");
     }
 
     #[test]
-    pub fn chain_failure() {
-        assert_eq!(op3().chain( op2).unwrap_err(), ~"sadface");
+    pub fn test_or_else() {
+        assert_eq!(op1().or_else(|_| Ok::<int, ~str>(667)).unwrap(), 666);
+        assert_eq!(op1().or_else(|e| Err::<int, ~str>(e + "!")).unwrap(), 666);
+
+        assert_eq!(op2().or_else(|_| Ok::<int, ~str>(667)).unwrap(), 667);
+        assert_eq!(op2().or_else(|e| Err::<int, ~str>(e + "!")).unwrap_err(), ~"sadface!");
     }
 
     #[test]
@@ -412,15 +547,6 @@ pub fn test_get_ref_method() {
         assert_eq!(*foo.get_ref(), 100);
     }
 
-    #[test]
-    pub fn test_to_either() {
-        let r: Result<int, ()> = Ok(100);
-        let err: Result<(), int> = Err(404);
-
-        assert_eq!(r.to_either(), either::Right(100));
-        assert_eq!(err.to_either(), either::Left(404));
-    }
-
     #[test]
     fn test_collect() {
         assert_eq!(collect(range(0, 0)
@@ -460,4 +586,88 @@ fn test_fold() {
                         .map(|f| (*f)())),
                    Err(1));
     }
+
+    #[test]
+    pub fn test_to_option() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.to_option(), option::Some(100));
+        assert_eq!(err.to_option(), option::None);
+    }
+
+    #[test]
+    pub fn test_into_option() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.into_option(), option::Some(100));
+        assert_eq!(err.into_option(), option::None);
+    }
+
+    #[test]
+    pub fn test_as_option() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.as_option().unwrap(), &100);
+        assert_eq!(err.as_option(), option::None);
+    }
+
+    #[test]
+    pub fn test_to_result() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.to_result(), Ok(100));
+        assert_eq!(err.to_result(), Err(404));
+    }
+
+    #[test]
+    pub fn test_into_result() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.into_result(), Ok(100));
+        assert_eq!(err.into_result(), Err(404));
+    }
+
+    #[test]
+    pub fn test_as_result() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        let x = 100;
+        assert_eq!(ok.as_result(), Ok(&x));
+
+        let x = 404;
+        assert_eq!(err.as_result(), Err(&x));
+    }
+
+    #[test]
+    pub fn test_to_either() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.to_either(), either::Right(100));
+        assert_eq!(err.to_either(), either::Left(404));
+    }
+
+    #[test]
+    pub fn test_into_either() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.into_either(), either::Right(100));
+        assert_eq!(err.into_either(), either::Left(404));
+    }
+
+    #[test]
+    pub fn test_as_either() {
+        let ok: Result<int, int> = Ok(100);
+        let err: Result<int, int> = Err(404);
+
+        assert_eq!(ok.as_either().unwrap_right(), &100);
+        assert_eq!(err.as_either().unwrap_left(), &404);
+    }
 }
diff --git a/src/libstd/rt/crate_map.rs b/src/libstd/rt/crate_map.rs
new file mode 100644 (file)
index 0000000..270b5e5
--- /dev/null
@@ -0,0 +1,200 @@
+// 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 libc::{c_void, c_char};
+use ptr;
+use ptr::RawPtr;
+use vec;
+use hashmap::HashSet;
+use container::MutableSet;
+
+pub struct ModEntry{
+    name: *c_char,
+    log_level: *mut u32
+}
+struct CrateMapV0 {
+    entries: *ModEntry,
+    children: [*CrateMap, ..1]
+}
+
+struct CrateMap {
+    version: i32,
+    annihilate_fn: *c_void,
+    entries: *ModEntry,
+    /// a dynamically sized struct, where all pointers to children are listed adjacent
+    /// to the struct, terminated with NULL
+    children: [*CrateMap, ..1]
+}
+
+unsafe fn version(crate_map: *CrateMap) -> i32 {
+    match (*crate_map).version {
+        1 => return 1,
+        _ => return 0
+    }
+}
+
+/// Returns a pointer to the annihilate function of the CrateMap
+pub unsafe fn annihilate_fn(crate_map: *CrateMap) -> *c_void {
+    match version(crate_map) {
+        0 => return ptr::null(),
+        1 => return (*crate_map).annihilate_fn,
+        _ => fail!("Unknown crate map version!")
+    }
+}
+
+unsafe fn entries(crate_map: *CrateMap) -> *ModEntry {
+    match version(crate_map) {
+        0 => {
+            let v0 = crate_map as (*CrateMapV0);
+            return (*v0).entries;
+        }
+        1 => return (*crate_map).entries,
+        _ => fail!("Unknown crate map version!")
+    }
+}
+
+unsafe fn iterator(crate_map: *CrateMap) -> **CrateMap {
+    match version(crate_map) {
+        0 => {
+            let v0 = crate_map as (*CrateMapV0);
+            return vec::raw::to_ptr((*v0).children);
+        }
+        1 => return vec::raw::to_ptr((*crate_map).children),
+        _ => fail!("Unknown crate map version!")
+    }
+}
+
+unsafe fn iter_module_map(mod_entries: *ModEntry, f: &fn(*mut ModEntry)) {
+    let mut curr = mod_entries;
+
+    while !(*curr).name.is_null() {
+        f(curr as *mut ModEntry);
+        curr = curr.offset(1);
+    }
+}
+
+unsafe fn do_iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry),
+                            visited: &mut HashSet<*CrateMap>) {
+    if visited.insert(crate_map) {
+        iter_module_map(entries(crate_map), |x| f(x));
+        let child_crates = iterator(crate_map);
+        do ptr::array_each(child_crates) |child| {
+            do_iter_crate_map(child, |x| f(x), visited);
+        }
+    }
+}
+
+/// Iterates recursively over `crate_map` and all child crate maps
+pub unsafe fn iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry)) {
+    // XXX: use random numbers as keys from the OS-level RNG when there is a nice
+    //        way to do this
+    let mut v: HashSet<*CrateMap> = HashSet::with_capacity_and_keys(0, 0, 32);
+    do_iter_crate_map(crate_map, f, &mut v);
+}
+
+#[test]
+fn iter_crate_map_duplicates() {
+    use c_str::ToCStr;
+    use cast::transmute;
+
+    struct CrateMapT3 {
+        version: i32,
+        annihilate_fn: *c_void,
+        entries: *ModEntry,
+        children: [*CrateMap, ..3]
+    }
+
+    unsafe {
+        let mod_name1 = "c::m1".to_c_str();
+        let mut level3: u32 = 3;
+
+        let entries: ~[ModEntry] = ~[
+            ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level3},
+            ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+        ];
+        let child_crate = CrateMap {
+            version: 1,
+            annihilate_fn: ptr::null(),
+            entries: vec::raw::to_ptr(entries),
+            children: [ptr::null()]
+        };
+
+        let root_crate = CrateMapT3 {
+            version: 1, annihilate_fn: ptr::null(),
+            entries: vec::raw::to_ptr([ModEntry { name: ptr::null(), log_level: ptr::mut_null()}]),
+            children: [&child_crate as *CrateMap, &child_crate as *CrateMap, ptr::null()]
+        };
+
+        let mut cnt = 0;
+        do iter_crate_map(transmute(&root_crate)) |entry| {
+            assert!(*(*entry).log_level == 3);
+            cnt += 1;
+        }
+        assert!(cnt == 1);
+    }
+}
+
+#[test]
+fn iter_crate_map_follow_children() {
+    use c_str::ToCStr;
+    use cast::transmute;
+
+    struct CrateMapT2 {
+        version: i32,
+        annihilate_fn: *c_void,
+        entries: *ModEntry,
+        children: [*CrateMap, ..2]
+    }
+
+    unsafe {
+        let mod_name1 = "c::m1".to_c_str();
+        let mod_name2 = "c::m2".to_c_str();
+        let mut level2: u32 = 2;
+        let mut level3: u32 = 3;
+        let child_crate2 = CrateMap {
+            version: 1,
+            annihilate_fn: ptr::null(),
+            entries: vec::raw::to_ptr([
+                ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level2},
+                ModEntry { name: mod_name2.with_ref(|buf| buf), log_level: &mut level3},
+                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+            ]),
+            children: [ptr::null()]
+        };
+
+        let child_crate1 = CrateMapT2 {
+            version: 1,
+            annihilate_fn: ptr::null(),
+            entries: vec::raw::to_ptr([
+                ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 1},
+                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+            ]),
+            children: [&child_crate2 as *CrateMap, ptr::null()]
+        };
+
+        let child_crate1_ptr: *CrateMap = transmute(&child_crate1);
+        let root_crate = CrateMapT2 {
+            version: 1, annihilate_fn: ptr::null(),
+            entries: vec::raw::to_ptr([
+                ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 0},
+                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+            ]),
+            children: [child_crate1_ptr, ptr::null()]
+        };
+
+        let mut cnt = 0;
+        do iter_crate_map(transmute(&root_crate)) |entry| {
+            assert!(*(*entry).log_level == cnt);
+            cnt += 1;
+        }
+        assert!(cnt == 4);
+    }
+}
index 66446de4492c1467f1e31929a69605586ac26490..579e581d87e0957cbed13f9204d85d6d3ecc0623 100644 (file)
@@ -187,31 +187,37 @@ fn inner_mut_ref<'a>(&'a mut self) -> &'a mut W {
     }
 }
 
-struct InternalBufferedWriter<W>(BufferedWriter<W>);
+// FIXME #9155 this should be a newtype struct
+struct InternalBufferedWriter<W> {
+    inner: BufferedWriter<W>
+}
 
 impl<W: Reader> Reader for InternalBufferedWriter<W> {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        self.inner.read(buf)
+        self.inner.inner.read(buf)
     }
 
     fn eof(&mut self) -> bool {
-        self.inner.eof()
+        self.inner.inner.eof()
     }
 }
 
 /// Wraps a Stream and buffers input and output to and from it
 ///
 /// NOTE: `BufferedStream` will NOT flush its output buffer when dropped.
-pub struct BufferedStream<S>(BufferedReader<InternalBufferedWriter<S>>);
+// FIXME #9155 this should be a newtype struct
+pub struct BufferedStream<S> {
+    priv inner: BufferedReader<InternalBufferedWriter<S>>
+}
 
 impl<S: Stream> BufferedStream<S> {
     pub fn with_capacities(reader_cap: uint, writer_cap: uint, inner: S)
                            -> BufferedStream<S> {
         let writer = BufferedWriter::with_capacity(writer_cap, inner);
-        let internal_writer = InternalBufferedWriter(writer);
+        let internal_writer = InternalBufferedWriter { inner: writer };
         let reader = BufferedReader::with_capacity(reader_cap,
                                                    internal_writer);
-        BufferedStream(reader)
+        BufferedStream { inner: reader }
     }
 
     pub fn new(inner: S) -> BufferedStream<S> {
@@ -222,35 +228,35 @@ pub fn new(inner: S) -> BufferedStream<S> {
 
 impl<S: Stream> Reader for BufferedStream<S> {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        (**self).read(buf)
+        self.inner.read(buf)
     }
 
     fn eof(&mut self) -> bool {
-        (**self).eof()
+        self.inner.eof()
     }
 }
 
 impl<S: Stream> Writer for BufferedStream<S> {
     fn write(&mut self, buf: &[u8]) {
-        self.inner.write(buf)
+        self.inner.inner.inner.write(buf)
     }
 
     fn flush(&mut self) {
-        self.inner.flush()
+        self.inner.inner.inner.flush()
     }
 }
 
 impl<S: Stream> Decorator<S> for BufferedStream<S> {
     fn inner(self) -> S {
-        self.inner.inner()
+        self.inner.inner.inner.inner()
     }
 
     fn inner_ref<'a>(&'a self) -> &'a S {
-        self.inner.inner_ref()
+        self.inner.inner.inner.inner_ref()
     }
 
     fn inner_mut_ref<'a>(&'a mut self) -> &'a mut S {
-        self.inner.inner_mut_ref()
+        self.inner.inner.inner.inner_mut_ref()
     }
 }
 
index ad21dfea3cd183cb95803801ee5665bcfb8253e0..3bc0e74c7822a6565627396c29c9068dec7b0eda 100644 (file)
@@ -146,7 +146,7 @@ fn seek(&mut self, pos: i64, style: SeekStyle) {
 }
 
 fn file_test_smoke_test_impl() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let message = "it's alright. have a good time";
         let filename = &Path("./tmp/file_rt_io_file_test.txt");
         {
@@ -174,7 +174,7 @@ fn file_test_io_smoke_test() {
 }
 
 fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let filename = &Path("./tmp/file_that_does_not_exist.txt");
         let mut called = false;
         do io_error::cond.trap(|_| {
@@ -192,7 +192,7 @@ fn file_test_io_invalid_path_opened_without_create_should_raise_condition() {
 }
 
 fn file_test_unlinking_invalid_path_should_raise_condition_impl() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let filename = &Path("./tmp/file_another_file_that_does_not_exist.txt");
         let mut called = false;
         do io_error::cond.trap(|_| {
@@ -209,7 +209,7 @@ fn file_test_iounlinking_invalid_path_should_raise_condition() {
 }
 
 fn file_test_io_non_positional_read_impl() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         use str;
         let message = "ten-four";
         let mut read_mem = [0, .. 8];
@@ -242,7 +242,7 @@ fn file_test_io_non_positional_read() {
 }
 
 fn file_test_io_seeking_impl() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         use str;
         let message = "ten-four";
         let mut read_mem = [0, .. 4];
@@ -276,7 +276,7 @@ fn file_test_io_seek_and_tell_smoke_test() {
 
 fn file_test_io_seek_and_write_impl() {
     use io;
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         use str;
         let initial_msg =   "food-is-yummy";
         let overwrite_msg =    "-the-bar!!";
@@ -307,7 +307,7 @@ fn file_test_io_seek_and_write() {
 }
 
 fn file_test_io_seek_shakedown_impl() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         use str;          // 01234567890123
         let initial_msg =   "qwer-asdf-zxcv";
         let chunk_one = "qwer";
index b278f10aed083b4cbed031c45731d1b150db225c..808e9f3a383e1f03eb03d5dc6428e9daf2bf803a 100644 (file)
@@ -196,6 +196,14 @@ fn tell(&self) -> u64 { self.pos as u64 }
     fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
 }
 
+///Calls a function with a MemWriter and returns
+///the writer's stored vector.
+pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
+  let mut writer = MemWriter::new();
+  writeFn(&mut writer);
+  writer.inner()
+}
+
 #[cfg(test)]
 mod test {
     use prelude::*;
@@ -255,4 +263,10 @@ fn test_buf_reader() {
         assert_eq!(reader.read(buf), None);
         assert!(reader.eof());
     }
+
+    #[test]
+    fn test_with_mem_writer() {
+        let buf = with_mem_writer(|wr| wr.write([1,2,3,4,5,6,7]));
+        assert_eq!(buf, ~[1,2,3,4,5,6,7]);
+    }
 }
index 956dd08ac91f0ea553b62cbbe20e0237a843db1b..041253455f01a48cad69e6defa0159dc04bf57cb 100644 (file)
@@ -177,7 +177,7 @@ fn parse_digit(c: char, radix: u8) -> Option<u8> {
         }
 
         do self.read_atomically |p| {
-            p.read_char().chain(|c| parse_digit(c, radix))
+            p.read_char().and_then(|c| parse_digit(c, radix))
         }
     }
 
index b533ebe923b7c87d55cb4096d5233e6c252a3b8d..be8a051a0664d94165479a007d31cb1b95cdc19b 100644 (file)
@@ -93,7 +93,7 @@ fn write(&mut self, buf: &[u8]) {
         }
     }
 
-    fn flush(&mut self) { fail!() }
+    fn flush(&mut self) { /* no-op */ }
 }
 
 pub struct TcpListener(~RtioTcpListenerObject);
@@ -159,10 +159,11 @@ mod test {
     use rt::io::net::ip::{Ipv4Addr, SocketAddr};
     use rt::io::*;
     use prelude::*;
+    use rt::comm::oneshot;
 
     #[test] #[ignore]
     fn bind_error() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let mut called = false;
             do io_error::cond.trap(|e| {
                 assert!(e.kind == PermissionDenied);
@@ -179,7 +180,7 @@ fn bind_error() {
     #[test]
     #[ignore(cfg(windows))] // FIXME #8811
     fn connect_error() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let mut called = false;
             do io_error::cond.trap(|e| {
                 assert_eq!(e.kind, ConnectionRefused);
@@ -195,11 +196,15 @@ fn connect_error() {
 
     #[test]
     fn smoke_test_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip4();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let mut buf = [0];
                 stream.read(buf);
@@ -207,6 +212,7 @@ fn smoke_test_ip4() {
             }
 
             do spawntask {
+                port.take().recv();
                 let mut stream = TcpStream::connect(addr);
                 stream.write([99]);
             }
@@ -215,11 +221,15 @@ fn smoke_test_ip4() {
 
     #[test]
     fn smoke_test_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip6();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let mut buf = [0];
                 stream.read(buf);
@@ -227,6 +237,7 @@ fn smoke_test_ip6() {
             }
 
             do spawntask {
+                port.take().recv();
                 let mut stream = TcpStream::connect(addr);
                 stream.write([99]);
             }
@@ -235,11 +246,15 @@ fn smoke_test_ip6() {
 
     #[test]
     fn read_eof_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip4();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let mut buf = [0];
                 let nread = stream.read(buf);
@@ -247,6 +262,7 @@ fn read_eof_ip4() {
             }
 
             do spawntask {
+                port.take().recv();
                 let _stream = TcpStream::connect(addr);
                 // Close
             }
@@ -255,11 +271,15 @@ fn read_eof_ip4() {
 
     #[test]
     fn read_eof_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip6();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let mut buf = [0];
                 let nread = stream.read(buf);
@@ -267,6 +287,7 @@ fn read_eof_ip6() {
             }
 
             do spawntask {
+                port.take().recv();
                 let _stream = TcpStream::connect(addr);
                 // Close
             }
@@ -276,11 +297,15 @@ fn read_eof_ip6() {
     #[test]
     #[ignore(cfg(windows))] // FIXME #8811
     fn read_eof_twice_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip4();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let mut buf = [0];
                 let nread = stream.read(buf);
@@ -290,6 +315,7 @@ fn read_eof_twice_ip4() {
             }
 
             do spawntask {
+                port.take().recv();
                 let _stream = TcpStream::connect(addr);
                 // Close
             }
@@ -299,11 +325,15 @@ fn read_eof_twice_ip4() {
     #[test]
     #[ignore(cfg(windows))] // FIXME #8811
     fn read_eof_twice_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip6();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let mut buf = [0];
                 let nread = stream.read(buf);
@@ -313,6 +343,7 @@ fn read_eof_twice_ip6() {
             }
 
             do spawntask {
+                port.take().recv();
                 let _stream = TcpStream::connect(addr);
                 // Close
             }
@@ -322,11 +353,15 @@ fn read_eof_twice_ip6() {
     #[test]
     #[ignore(cfg(windows))] // FIXME #8811
     fn write_close_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip4();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let buf = [0];
                 loop {
@@ -343,6 +378,7 @@ fn write_close_ip4() {
             }
 
             do spawntask {
+                port.take().recv();
                 let _stream = TcpStream::connect(addr);
                 // Close
             }
@@ -352,11 +388,15 @@ fn write_close_ip4() {
     #[test]
     #[ignore(cfg(windows))] // FIXME #8811
     fn write_close_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip6();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 let mut stream = acceptor.accept();
                 let buf = [0];
                 loop {
@@ -373,6 +413,7 @@ fn write_close_ip6() {
             }
 
             do spawntask {
+                port.take().recv();
                 let _stream = TcpStream::connect(addr);
                 // Close
             }
@@ -381,12 +422,16 @@ fn write_close_ip6() {
 
     #[test]
     fn multiple_connect_serial_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip4();
             let max = 10;
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 for ref mut stream in acceptor.incoming().take(max) {
                     let mut buf = [0];
                     stream.read(buf);
@@ -395,6 +440,7 @@ fn multiple_connect_serial_ip4() {
             }
 
             do spawntask {
+                port.take().recv();
                 do max.times {
                     let mut stream = TcpStream::connect(addr);
                     stream.write([99]);
@@ -405,12 +451,16 @@ fn multiple_connect_serial_ip4() {
 
     #[test]
     fn multiple_connect_serial_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip6();
             let max = 10;
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 for ref mut stream in acceptor.incoming().take(max) {
                     let mut buf = [0];
                     stream.read(buf);
@@ -419,6 +469,7 @@ fn multiple_connect_serial_ip6() {
             }
 
             do spawntask {
+                port.take().recv();
                 do max.times {
                     let mut stream = TcpStream::connect(addr);
                     stream.write([99]);
@@ -429,12 +480,15 @@ fn multiple_connect_serial_ip6() {
 
     #[test]
     fn multiple_connect_interleaved_greedy_schedule_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip4();
             static MAX: int = 10;
+            let (port, chan) = oneshot();
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) {
                     let stream = Cell::new(stream);
                     // Start another task to handle the connection
@@ -448,6 +502,7 @@ fn multiple_connect_interleaved_greedy_schedule_ip4() {
                 }
             }
 
+            port.recv();
             connect(0, addr);
 
             fn connect(i: int, addr: SocketAddr) {
@@ -467,12 +522,15 @@ fn connect(i: int, addr: SocketAddr) {
 
     #[test]
     fn multiple_connect_interleaved_greedy_schedule_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip6();
             static MAX: int = 10;
+            let (port, chan) = oneshot();
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) {
                     let stream = Cell::new(stream);
                     // Start another task to handle the connection
@@ -486,6 +544,7 @@ fn multiple_connect_interleaved_greedy_schedule_ip6() {
                 }
             }
 
+            port.recv();
             connect(0, addr);
 
             fn connect(i: int, addr: SocketAddr) {
@@ -505,12 +564,15 @@ fn connect(i: int, addr: SocketAddr) {
 
     #[test]
     fn multiple_connect_interleaved_lazy_schedule_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip4();
             static MAX: int = 10;
+            let (port, chan) = oneshot();
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 for stream in acceptor.incoming().take(MAX as uint) {
                     let stream = Cell::new(stream);
                     // Start another task to handle the connection
@@ -524,6 +586,7 @@ fn multiple_connect_interleaved_lazy_schedule_ip4() {
                 }
             }
 
+            port.recv();
             connect(0, addr);
 
             fn connect(i: int, addr: SocketAddr) {
@@ -542,12 +605,15 @@ fn connect(i: int, addr: SocketAddr) {
     }
     #[test]
     fn multiple_connect_interleaved_lazy_schedule_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let addr = next_test_ip6();
             static MAX: int = 10;
+            let (port, chan) = oneshot();
+            let chan = Cell::new(chan);
 
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
                 for stream in acceptor.incoming().take(MAX as uint) {
                     let stream = Cell::new(stream);
                     // Start another task to handle the connection
@@ -561,6 +627,7 @@ fn multiple_connect_interleaved_lazy_schedule_ip6() {
                 }
             }
 
+            port.recv();
             connect(0, addr);
 
             fn connect(i: int, addr: SocketAddr) {
@@ -580,7 +647,7 @@ fn connect(i: int, addr: SocketAddr) {
 
     #[cfg(test)]
     fn socket_name(addr: SocketAddr) {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             do spawntask {
                 let mut listener = TcpListener::bind(addr).unwrap();
 
@@ -596,14 +663,20 @@ fn socket_name(addr: SocketAddr) {
 
     #[cfg(test)]
     fn peer_name(addr: SocketAddr) {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
+
             do spawntask {
                 let mut acceptor = TcpListener::bind(addr).listen();
+                chan.take().send(());
 
                 acceptor.accept();
             }
 
             do spawntask {
+                port.take().recv();
                 let stream = TcpStream::connect(addr);
 
                 assert!(stream.is_some());
index 132ca064515c1c867ecf141ad405750124b35dd5..a65c918351ad936e88335f0606ca640a4378896c 100644 (file)
@@ -112,10 +112,12 @@ mod test {
     use rt::io::net::ip::{Ipv4Addr, SocketAddr};
     use rt::io::*;
     use option::{Some, None};
+    use rt::comm::oneshot;
+    use cell::Cell;
 
     #[test]  #[ignore]
     fn bind_error() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let mut called = false;
             do io_error::cond.trap(|e| {
                 assert!(e.kind == PermissionDenied);
@@ -131,13 +133,17 @@ fn bind_error() {
 
     #[test]
     fn socket_smoke_test_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let server_ip = next_test_ip4();
             let client_ip = next_test_ip4();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 match UdpSocket::bind(server_ip) {
                     Some(ref mut server) => {
+                        chan.take().send(());
                         let mut buf = [0];
                         match server.recvfrom(buf) {
                             Some((nread, src)) => {
@@ -154,7 +160,10 @@ fn socket_smoke_test_ip4() {
 
             do spawntask {
                 match UdpSocket::bind(client_ip) {
-                    Some(ref mut client) => client.sendto([99], server_ip),
+                    Some(ref mut client) => {
+                        port.take().recv();
+                        client.sendto([99], server_ip)
+                    }
                     None => fail!()
                 }
             }
@@ -163,13 +172,17 @@ fn socket_smoke_test_ip4() {
 
     #[test]
     fn socket_smoke_test_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let server_ip = next_test_ip6();
             let client_ip = next_test_ip6();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 match UdpSocket::bind(server_ip) {
                     Some(ref mut server) => {
+                        chan.take().send(());
                         let mut buf = [0];
                         match server.recvfrom(buf) {
                             Some((nread, src)) => {
@@ -186,7 +199,10 @@ fn socket_smoke_test_ip6() {
 
             do spawntask {
                 match UdpSocket::bind(client_ip) {
-                    Some(ref mut client) => client.sendto([99], server_ip),
+                    Some(ref mut client) => {
+                        port.take().recv();
+                        client.sendto([99], server_ip)
+                    }
                     None => fail!()
                 }
             }
@@ -195,15 +211,19 @@ fn socket_smoke_test_ip6() {
 
     #[test]
     fn stream_smoke_test_ip4() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let server_ip = next_test_ip4();
             let client_ip = next_test_ip4();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 match UdpSocket::bind(server_ip) {
                     Some(server) => {
                         let server = ~server;
                         let mut stream = server.connect(client_ip);
+                        chan.take().send(());
                         let mut buf = [0];
                         match stream.read(buf) {
                             Some(nread) => {
@@ -222,6 +242,7 @@ fn stream_smoke_test_ip4() {
                     Some(client) => {
                         let client = ~client;
                         let mut stream = client.connect(server_ip);
+                        port.take().recv();
                         stream.write([99]);
                     }
                     None => fail!()
@@ -232,15 +253,19 @@ fn stream_smoke_test_ip4() {
 
     #[test]
     fn stream_smoke_test_ip6() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let server_ip = next_test_ip6();
             let client_ip = next_test_ip6();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
 
             do spawntask {
                 match UdpSocket::bind(server_ip) {
                     Some(server) => {
                         let server = ~server;
                         let mut stream = server.connect(client_ip);
+                        chan.take().send(());
                         let mut buf = [0];
                         match stream.read(buf) {
                             Some(nread) => {
@@ -259,6 +284,7 @@ fn stream_smoke_test_ip6() {
                     Some(client) => {
                         let client = ~client;
                         let mut stream = client.connect(server_ip);
+                        port.take().recv();
                         stream.write([99]);
                     }
                     None => fail!()
@@ -269,7 +295,7 @@ fn stream_smoke_test_ip6() {
 
     #[cfg(test)]
     fn socket_name(addr: SocketAddr) {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             do spawntask {
                 let server = UdpSocket::bind(addr);
 
index 098433f299c1744041bf743a435290fb38faa53b..2ea1b6154830a45f3f8742504bd474bc37717174 100644 (file)
@@ -95,7 +95,7 @@ mod test {
 
     #[test]
     fn test_option_writer() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let mut writer: Option<MemWriter> = Some(MemWriter::new());
             writer.write([0, 1, 2]);
             writer.flush();
@@ -105,7 +105,7 @@ fn test_option_writer() {
 
     #[test]
     fn test_option_writer_error() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let mut writer: Option<MemWriter> = None;
 
             let mut called = false;
@@ -130,7 +130,7 @@ fn test_option_writer_error() {
 
     #[test]
     fn test_option_reader() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3]));
             let mut buf = [0, 0];
             reader.read(buf);
index 7f2d88f994d8cc1fb891ecd438eb7f6e191a8014..53e4c4051e1c34b18e7d7dd0020026690a698975 100644 (file)
 
 pub struct Timer(~RtioTimerObject);
 
+/// Sleep the current task for `msecs` milliseconds.
+pub fn sleep(msecs: u64) {
+    let mut timer = Timer::new().expect("timer::sleep: could not create a Timer");
+
+    timer.sleep(msecs)
+}
+
 impl Timer {
 
     pub fn new() -> Option<Timer> {
@@ -47,9 +54,16 @@ mod test {
     use rt::test::*;
     #[test]
     fn test_io_timer_sleep_simple() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let timer = Timer::new();
             do timer.map_move |mut t| { t.sleep(1) };
         }
     }
+
+    #[test]
+    fn test_io_timer_sleep_standalone() {
+        do run_in_mt_newsched_task {
+            sleep(1)
+        }
+    }
 }
index 8a4aba3eb8792d0713df1ae62b02146e4325abed..54084bb14c08aa6164d4864e87e4340c039d3255 100644 (file)
@@ -7,71 +7,29 @@
 // <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 cast::transmute;
-use either::*;
-use libc::{c_void, uintptr_t, c_char, exit, STDERR_FILENO};
+use from_str::from_str;
+use libc::{uintptr_t, exit, STDERR_FILENO};
 use option::{Some, None, Option};
 use rt::util::dumb_println;
+use rt::crate_map::{ModEntry, iter_crate_map};
 use str::StrSlice;
 use str::raw::from_c_str;
 use u32;
-use unstable::raw::Closure;
 use vec::ImmutableVector;
-
+use cast::transmute;
 
 struct LogDirective {
     name: Option<~str>,
     level: u32
 }
 
-// This is the Rust representation of the mod_entry struct in src/rt/rust_crate_map.h
-struct ModEntry{
-    name: *c_char,
-    log_level: *mut u32
-}
-
 static MAX_LOG_LEVEL: u32 = 255;
 static DEFAULT_LOG_LEVEL: u32 = 1;
-
-fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
-    unsafe {
-        let closure : Closure = transmute(f);
-        let code = transmute(closure.code);
-        let env = transmute(closure.env);
-        rust_iter_crate_map(transmute(map), iter_cb, code, env);
-    }
-
-    extern fn iter_cb(code: *c_void, env: *c_void, entry: *ModEntry){
-         unsafe {
-            let closure: Closure = Closure {
-                code: transmute(code),
-                env: transmute(env),
-            };
-            let closure: &fn(*ModEntry) = transmute(closure);
-            return closure(entry);
-        }
-    }
-    extern {
-        #[cfg(not(stage0))]
-        #[rust_stack]
-        fn rust_iter_crate_map(map: *c_void,
-                    f: extern "C" fn(*c_void, *c_void, entry: *ModEntry),
-                    code: *c_void,
-                    data: *c_void);
-
-        #[cfg(stage0)]
-        #[rust_stack]
-        fn rust_iter_crate_map(map: *c_void,
-                    f: *u8,
-                    code: *c_void,
-                    data: *c_void);
-    }
-}
 static log_level_names : &'static[&'static str] = &'static["error", "warn", "info", "debug"];
 
 /// Parse an individual log level that is either a number or a symbolic log level
 fn parse_log_level(level: &str) -> Option<u32> {
-    let num = u32::from_str(level);
+    let num = from_str::<u32>(level);
     let mut log_level;
     match num {
         Some(num) => {
@@ -96,12 +54,10 @@ fn parse_log_level(level: &str) -> Option<u32> {
     log_level
 }
 
-
 /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
 /// and return a vector with log directives.
 /// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in std::).
 /// Also supports string log levels of error, warn, info, and debug
-
 fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
     let mut dirs = ~[];
     for s in spec.split_iter(',') {
@@ -186,12 +142,10 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
     if settings.len() > 0 {
         if settings == ~"::help" || settings == ~"?" {
             dumb_println("\nCrate log map:\n");
-            do iter_crate_map(crate_map) |entry: *mut ModEntry| {
-                unsafe {
+            unsafe {
+                do iter_crate_map(transmute(crate_map)) |entry: *mut ModEntry| {
                     dumb_println(" "+from_c_str((*entry).name));
                 }
-            }
-            unsafe {
                 exit(1);
             }
         }
@@ -199,9 +153,11 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
     }
 
     let mut n_matches: u32 = 0;
-    do iter_crate_map(crate_map) |entry: *mut ModEntry| {
-        let m = update_entry(dirs, entry);
-        n_matches += m;
+    unsafe {
+        do iter_crate_map(transmute(crate_map)) |entry: *mut ModEntry| {
+            let m = update_entry(dirs, entry);
+            n_matches += m;
+        }
     }
 
     if n_matches < (dirs.len() as u32) {
@@ -212,14 +168,20 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
     }
 }
 
+/// Represent a string with `Send` bound.
+pub enum SendableString {
+    OwnedString(~str),
+    StaticString(&'static str)
+}
+
 pub trait Logger {
-    fn log(&mut self, msg: Either<~str, &'static str>);
+    fn log(&mut self, msg: SendableString);
 }
 
 pub struct StdErrLogger;
 
 impl Logger for StdErrLogger {
-    fn log(&mut self, msg: Either<~str, &'static str>) {
+    fn log(&mut self, msg: SendableString) {
         use io::{Writer, WriterUtil};
 
         if !should_log_console() {
@@ -227,14 +189,11 @@ fn log(&mut self, msg: Either<~str, &'static str>) {
         }
 
         let s: &str = match msg {
-            Left(ref s) => {
-                let s: &str = *s;
-                s
-            }
-            Right(ref s) => {
-                let s: &str = *s;
-                s
-            }
+            OwnedString(ref s) => {
+                let slc: &str = *s;
+                slc
+            },
+            StaticString(s) => s,
         };
 
         // Truncate the string
index c9c3c4ec6daf328ca012b090f4252e9819be22de..53f62786b629dc17cfe714e538fd77f30b6046ad 100644 (file)
 /// The Logger trait and implementations
 pub mod logging;
 
+/// Crate map
+pub mod crate_map;
+
 /// Tools for testing the runtime
 pub mod test;
 
index f35fe1a1d04abe8dc004c9e13db3da1bad5ca652..e92accd283b7eb21dd27020d4a75a98e2fb6f0f8 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use libc;
-use uint;
 use option::{Some, None};
 use cell::Cell;
 use clone::Clone;
@@ -382,9 +381,10 @@ fn base_port() -> uint {
 /// stress tests. Default 1.
 pub fn stress_factor() -> uint {
     use os::getenv;
+    use from_str::from_str;
 
     match getenv("RUST_RT_STRESS") {
-        Some(val) => uint::from_str(val).unwrap(),
+        Some(val) => from_str::<uint>(val).unwrap(),
         None => 1
     }
 }
index 65910e5ad086c36b7e79934c23532cadc7f95633..e8af0c749a04dbfc49a9175792bf9136105a2cbd 100644 (file)
@@ -43,8 +43,9 @@
 #[cfg(test)] use unstable::run_in_bare_thread;
 #[cfg(test)] use rt::test::{spawntask,
                             next_test_ip4,
-                            run_in_newsched_task};
+                            run_in_mt_newsched_task};
 #[cfg(test)] use iter::{Iterator, range};
+#[cfg(test)] use rt::comm::oneshot;
 
 // XXX we should not be calling uvll functions in here.
 
@@ -377,7 +378,7 @@ mod test_remote {
 
     #[test]
     fn test_uv_remote() {
-        do run_in_newsched_task {
+        do run_in_mt_newsched_task {
             let mut tube = Tube::new();
             let tube_clone = tube.clone();
             let remote_cell = Cell::new_empty();
@@ -719,7 +720,9 @@ fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
 
 impl RtioTcpAcceptor for UvTcpAcceptor {
     fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> {
-        self.incoming.recv()
+        do self.home_for_io |self_| {
+            self_.incoming.recv()
+        }
     }
 
     fn accept_simultaneously(&mut self) -> Result<(), IoError> {
@@ -1301,7 +1304,7 @@ fn flush(&mut self) -> Result<(), IoError> {
 
 #[test]
 fn test_simple_io_no_connect() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         unsafe {
             let io: *mut IoFactoryObject = Local::unsafe_borrow();
             let addr = next_test_ip4();
@@ -1313,7 +1316,7 @@ fn test_simple_io_no_connect() {
 
 #[test]
 fn test_simple_udp_io_bind_only() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         unsafe {
             let io: *mut IoFactoryObject = Local::unsafe_borrow();
             let addr = next_test_ip4();
@@ -1477,8 +1480,11 @@ fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() {
 
 #[test]
 fn test_simple_tcp_server_and_client() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let addr = next_test_ip4();
+        let (port, chan) = oneshot();
+        let port = Cell::new(port);
+        let chan = Cell::new(chan);
 
         // Start the server first so it's listening when we connect
         do spawntask {
@@ -1486,6 +1492,7 @@ fn test_simple_tcp_server_and_client() {
                 let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let listener = (*io).tcp_bind(addr).unwrap();
                 let mut acceptor = listener.listen().unwrap();
+                chan.take().send(());
                 let mut stream = acceptor.accept().unwrap();
                 let mut buf = [0, .. 2048];
                 let nread = stream.read(buf).unwrap();
@@ -1499,6 +1506,7 @@ fn test_simple_tcp_server_and_client() {
 
         do spawntask {
             unsafe {
+                port.take().recv();
                 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]);
@@ -1591,14 +1599,18 @@ fn test_simple_tcp_server_and_client_on_diff_threads() {
 
 #[test]
 fn test_simple_udp_server_and_client() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let server_addr = next_test_ip4();
         let client_addr = next_test_ip4();
+        let (port, chan) = oneshot();
+        let port = Cell::new(port);
+        let chan = Cell::new(chan);
 
         do spawntask {
             unsafe {
                 let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut server_socket = (*io).udp_bind(server_addr).unwrap();
+                chan.take().send(());
                 let mut buf = [0, .. 2048];
                 let (nread,src) = server_socket.recvfrom(buf).unwrap();
                 assert_eq!(nread, 8);
@@ -1614,6 +1626,7 @@ fn test_simple_udp_server_and_client() {
             unsafe {
                 let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut client_socket = (*io).udp_bind(client_addr).unwrap();
+                port.take().recv();
                 client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr);
             }
         }
@@ -1622,13 +1635,17 @@ fn test_simple_udp_server_and_client() {
 
 #[test] #[ignore(reason = "busted")]
 fn test_read_and_block() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let addr = next_test_ip4();
+        let (port, chan) = oneshot();
+        let port = Cell::new(port);
+        let chan = Cell::new(chan);
 
         do spawntask {
             let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() };
             let listener = unsafe { (*io).tcp_bind(addr).unwrap() };
             let mut acceptor = listener.listen().unwrap();
+            chan.take().send(());
             let mut stream = acceptor.accept().unwrap();
             let mut buf = [0, .. 2048];
 
@@ -1663,6 +1680,7 @@ fn test_read_and_block() {
 
         do spawntask {
             unsafe {
+                port.take().recv();
                 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]);
@@ -1677,15 +1695,19 @@ fn test_read_and_block() {
 
 #[test]
 fn test_read_read_read() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let addr = next_test_ip4();
         static MAX: uint = 500000;
+        let (port, chan) = oneshot();
+        let port = Cell::new(port);
+        let chan = Cell::new(chan);
 
         do spawntask {
             unsafe {
                 let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let listener = (*io).tcp_bind(addr).unwrap();
                 let mut acceptor = listener.listen().unwrap();
+                chan.take().send(());
                 let mut stream = acceptor.accept().unwrap();
                 let buf = [1, .. 2048];
                 let mut total_bytes_written = 0;
@@ -1698,6 +1720,7 @@ fn test_read_read_read() {
 
         do spawntask {
             unsafe {
+                port.take().recv();
                 let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut stream = (*io).tcp_connect(addr).unwrap();
                 let mut buf = [0, .. 2048];
@@ -1719,14 +1742,18 @@ fn test_read_read_read() {
 #[test]
 #[ignore(cfg(windows))] // FIXME #8816
 fn test_udp_twice() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let server_addr = next_test_ip4();
         let client_addr = next_test_ip4();
+        let (port, chan) = oneshot();
+        let port = Cell::new(port);
+        let chan = Cell::new(chan);
 
         do spawntask {
             unsafe {
                 let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut client = (*io).udp_bind(client_addr).unwrap();
+                port.take().recv();
                 assert!(client.sendto([1], server_addr).is_ok());
                 assert!(client.sendto([2], server_addr).is_ok());
             }
@@ -1736,6 +1763,7 @@ fn test_udp_twice() {
             unsafe {
                 let io: *mut IoFactoryObject = Local::unsafe_borrow();
                 let mut server = (*io).udp_bind(server_addr).unwrap();
+                chan.take().send(());
                 let mut buf1 = [0];
                 let mut buf2 = [0];
                 let (nread1, src1) = server.recvfrom(buf1).unwrap();
@@ -1753,18 +1781,27 @@ fn test_udp_twice() {
 
 #[test]
 fn test_udp_many_read() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         let server_out_addr = next_test_ip4();
         let server_in_addr = next_test_ip4();
         let client_out_addr = next_test_ip4();
         let client_in_addr = next_test_ip4();
         static MAX: uint = 500_000;
 
+        let (p1, c1) = oneshot();
+        let (p2, c2) = oneshot();
+
+        let first = Cell::new((p1, c2));
+        let second = Cell::new((p2, c1));
+
         do spawntask {
             unsafe {
                 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 (port, chan) = first.take();
+                chan.send(());
+                port.recv();
                 let msg = [1, .. 2048];
                 let mut total_bytes_sent = 0;
                 let mut buf = [1];
@@ -1788,6 +1825,9 @@ fn test_udp_many_read() {
                 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 (port, chan) = second.take();
+                port.recv();
+                chan.send(());
                 let mut total_bytes_recv = 0;
                 let mut buf = [0, .. 2048];
                 while total_bytes_recv < MAX {
@@ -1812,7 +1852,7 @@ fn test_udp_many_read() {
 
 #[test]
 fn test_timer_sleep_simple() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         unsafe {
             let io: *mut IoFactoryObject = Local::unsafe_borrow();
             let timer = (*io).timer_init();
@@ -1854,7 +1894,7 @@ fn file_test_uvio_full_simple_impl() {
 #[test]
 #[ignore(cfg(windows))] // FIXME #8816
 fn file_test_uvio_full_simple() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         file_test_uvio_full_simple_impl();
     }
 }
@@ -1874,7 +1914,7 @@ fn uvio_naive_print(input: &str) {
 
 #[test]
 fn file_test_uvio_write_to_stdout() {
-    do run_in_newsched_task {
+    do run_in_mt_newsched_task {
         uvio_naive_print("jubilation\n");
     }
 }
index 4ef97677bd353b54b4118550d3cb469641c61e8e..5bf04110abf45c19b0971d0db1d3238d429418b1 100644 (file)
@@ -67,11 +67,20 @@ pub mod errors {
     pub static EPIPE: c_int = -libc::EPIPE;
 }
 
+// see libuv/include/uv-unix.h
+#[cfg(unix)]
 pub struct uv_buf_t {
     base: *u8,
     len: libc::size_t,
 }
 
+// see libuv/include/uv-win.h
+#[cfg(windows)]
+pub struct uv_buf_t {
+    len: u32,
+    base: *u8,
+}
+
 pub type uv_handle_t = c_void;
 pub type uv_loop_t = c_void;
 pub type uv_idle_t = c_void;
index c3a5afc1ec8d6f342a9a9a4d3890f82b0da106a0..f7f7fef6fa09320a7033599c912d5454360f8c80 100644 (file)
@@ -136,12 +136,11 @@ fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
 
 // FIXME #4427: Temporary until rt::rt_fail_ goes away
 pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
-    use either::Left;
     use option::{Some, None};
     use rt::in_green_task_context;
     use rt::task::Task;
     use rt::local::Local;
-    use rt::logging::Logger;
+    use rt::logging::{Logger, OwnedString};
     use str::Str;
 
     unsafe {
@@ -164,7 +163,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
                          msg, file, line as int)
                 };
 
-                task.logger.log(Left(msg));
+                task.logger.log(OwnedString(msg));
             }
         } else {
             rterrln!("failed in non-task context at '%s', %s:%i",
index 855cdfcb8517bbb3eeb4e4868603d2d2a24409f9..f47468e1ef8ca4dc73cc45efa23b5c34c4aab658 100644 (file)
@@ -383,5 +383,5 @@ mod test {
     #[test] fn iterbytes_compiles () {
         takes_iterbytes((3,4,5,false));
     }
-    fn takes_iterbytes<T : IterBytes>(x : T) {}
+    fn takes_iterbytes<T : IterBytes>(_x : T) {}
 }
index 32797216376bef0e6d6b8d67b1317b737fdd3df0..88a953a1601e92191fb9e251bd44c7900c4147b6 100644 (file)
@@ -520,6 +520,7 @@ pub fn check_integrity<T>(trie: &TrieNode<T>) {
 mod test_map {
     use super::*;
     use prelude::*;
+    use iter::range_step;
     use uint;
 
     #[test]
@@ -538,21 +539,19 @@ fn test_find_mut() {
     #[test]
     fn test_step() {
         let mut trie = TrieMap::new();
-        let n = 300;
+        let n = 300u;
 
-        do uint::range_step(1, n, 2) |x| {
+        for x in range_step(1u, n, 2) {
             assert!(trie.insert(x, x + 1));
             assert!(trie.contains_key(&x));
             check_integrity(&trie.root);
-            true
-        };
+        }
 
-        do uint::range_step(0, n, 2) |x| {
+        for x in range_step(0u, n, 2) {
             assert!(!trie.contains_key(&x));
             assert!(trie.insert(x, x + 1));
             check_integrity(&trie.root);
-            true
-        };
+        }
 
         for x in range(0u, n) {
             assert!(trie.contains_key(&x));
@@ -560,19 +559,17 @@ fn test_step() {
             check_integrity(&trie.root);
         }
 
-        do uint::range_step(1, n, 2) |x| {
+        for x in range_step(1u, n, 2) {
             assert!(trie.remove(&x));
             assert!(!trie.contains_key(&x));
             check_integrity(&trie.root);
-            true
-        };
+        }
 
-        do uint::range_step(0, n, 2) |x| {
+        for x in range_step(0u, n, 2) {
             assert!(trie.contains_key(&x));
             assert!(!trie.insert(x, x + 1));
             check_integrity(&trie.root);
-            true
-        };
+        }
     }
 
     #[test]
@@ -715,11 +712,10 @@ fn test_bound_iter() {
         let value = 42u;
 
         let mut map : TrieMap<uint> = TrieMap::new();
-        do uint::range_step(0u, last, step as int) |x| {
+        for x in range_step(0u, last, step) {
             assert!(x % step == 0);
             map.insert(x, value);
-            true
-        };
+        }
 
         for i in range(0u, last - step) {
             let mut lb = map.lower_bound_iter(i);
index 5d9ca6202e26293b47fef8cf4e0b26c6ec35a73c..2591131f21521e5020ac05aef287f63f07852bc9 100644 (file)
@@ -89,6 +89,7 @@ macro_rules! tuple_impls {
         pub mod inner {
             use clone::Clone;
             #[cfg(not(test))] use cmp::*;
+            #[cfg(not(test))] use default::Default;
             #[cfg(not(test))] use num::Zero;
 
             $(
@@ -172,6 +173,14 @@ fn cmp(&self, other: &($($T,)+)) -> Ordering {
                     }
                 }
 
+                #[cfg(not(test))]
+                impl<$($T:Default),+> Default for ($($T,)+) {
+                    #[inline]
+                    fn default() -> ($($T,)+) {
+                        ($({ let x: $T = Default::default(); x},)+)
+                    }
+                }
+
                 #[cfg(not(test))]
                 impl<$($T:Zero),+> Zero for ($($T,)+) {
                     #[inline]
index 3af0322df56da0a951d90a50fdbe7ef970a49695..dfe4abe54e5b5c236d337bb82e9fd8494064c5fe 100644 (file)
@@ -45,6 +45,12 @@ impl TotalEq for () {
     fn equals(&self, _other: &()) -> bool { true }
 }
 
+#[cfg(not(test))]
+impl Default for () {
+    #[inline]
+    fn default() -> () { () }
+}
+
 #[cfg(not(test))]
 impl Zero for () {
     #[inline]
@@ -52,8 +58,3 @@ fn zero() -> () { () }
     #[inline]
     fn is_zero(&self) -> bool { true }
 }
-
-#[cfg(not(test))]
-impl Default for () {
-    fn default() -> () { () }
-}
index db106de76d94e4ce5eb97d3097da2a2fdcd378ee..d8a07eeb8b7d3d1ff7b15179b04336624d67d12d 100644 (file)
@@ -90,7 +90,8 @@ mod test {
     use libc;
 
     #[test]
-    #[ignore(cfg(windows))] // FIXME #8818
+    // #[ignore(cfg(windows))] // FIXME #8818
+    #[ignore] // FIXME #9137 this library isn't thread-safe
     fn test_loading_cosine() {
         // The math library does not need to be loaded since it is already
         // statically linked in
@@ -121,6 +122,7 @@ fn test_loading_cosine() {
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "macos")]
     #[cfg(target_os = "freebsd")]
+    #[ignore] // FIXME #9137 this library isn't thread-safe
     fn test_errors_do_not_crash() {
         // Open /dev/null as a library to get an error, and make sure
         // that only causes an error, and not a crash.
index 51de3caf2aebb276a62cf7bb5ef8d33e59365528..e16e6384a4f16fd268c3a71abaa5f495c7eae441 100644 (file)
@@ -68,59 +68,6 @@ fn test_run_in_bare_thread_exchange() {
     }
 }
 
-
-/// Changes the current working directory to the specified
-/// path while acquiring a global lock, then calls `action`.
-/// If the change is successful, releases the lock and restores the
-/// CWD to what it was before, returning true.
-/// Returns false if the directory doesn't exist or if the directory change
-/// is otherwise unsuccessful.
-///
-/// This is used by test cases to avoid cwd races.
-///
-/// # Safety Note
-///
-/// This uses a pthread mutex so descheduling in the action callback
-/// can lead to deadlock. Calling change_dir_locked recursively will
-/// also deadlock.
-pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    use os;
-    use os::change_dir;
-    use unstable::sync::atomically;
-    use unstable::finally::Finally;
-
-    unsafe {
-        // This is really sketchy. Using a pthread mutex so descheduling
-        // in the `action` callback can cause deadlock. Doing it in
-        // `task::atomically` to try to avoid that, but ... I don't know
-        // this is all bogus.
-        return do atomically {
-            rust_take_change_dir_lock();
-
-            do (||{
-                let old_dir = os::getcwd();
-                if change_dir(p) {
-                    action();
-                    change_dir(&old_dir)
-                }
-                else {
-                    false
-                }
-            }).finally {
-                rust_drop_change_dir_lock();
-            }
-        }
-    }
-
-    extern {
-        fn rust_take_change_dir_lock();
-        fn rust_drop_change_dir_lock();
-    }
-}
-
-
 /// Dynamically inquire about whether we're running under V.
 /// You should usually not use this unless your test definitely
 /// can't run correctly un-altered. Valgrind is there to help
index 1ff5835188650c157bf16a6e2ed59d60cb6f28b6..47c3a07961444b90a20af13de4b8cb0533fcaa27 100644 (file)
 use container::{Container, Mutable};
 use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
 use cmp;
+use default::Default;
 use iter::*;
 use libc::c_void;
-use num::{Integer, Zero, CheckedAdd, Saturating};
+use num::{Integer, CheckedAdd, Saturating};
 use option::{None, Option, Some};
 use ptr::to_unsafe_ptr;
 use ptr;
@@ -205,7 +206,7 @@ pub fn with_capacity<T>(capacity: uint) -> ~[T] {
  */
 #[inline]
 pub fn build<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> ~[A] {
-    let mut vec = with_capacity(size.unwrap_or_default(4));
+    let mut vec = with_capacity(size.unwrap_or(4));
     builder(|x| vec.push(x));
     vec
 }
@@ -2237,19 +2238,16 @@ fn deep_clone(&self) -> ~[A] {
 }
 
 // This works because every lifetime is a sub-lifetime of 'static
-impl<'self, A> Zero for &'self [A] {
-    fn zero() -> &'self [A] { &'self [] }
-    fn is_zero(&self) -> bool { self.is_empty() }
+impl<'self, A> Default for &'self [A] {
+    fn default() -> &'self [A] { &'self [] }
 }
 
-impl<A> Zero for ~[A] {
-    fn zero() -> ~[A] { ~[] }
-    fn is_zero(&self) -> bool { self.len() == 0 }
+impl<A> Default for ~[A] {
+    fn default() -> ~[A] { ~[] }
 }
 
-impl<A> Zero for @[A] {
-    fn zero() -> @[A] { @[] }
-    fn is_zero(&self) -> bool { self.len() == 0 }
+impl<A> Default for @[A] {
+    fn default() -> @[A] { @[] }
 }
 
 macro_rules! iterator {
@@ -3588,13 +3586,12 @@ fn test_reverse_part() {
     }
 
     #[test]
-    fn test_vec_zero() {
-        use num::Zero;
+    fn test_vec_default() {
+        use default::Default;
         macro_rules! t (
             ($ty:ty) => {{
-                let v: $ty = Zero::zero();
+                let v: $ty = Default::default();
                 assert!(v.is_empty());
-                assert!(v.is_zero());
             }}
         );
 
index 8d557125d370010e6f06d02a75e5476715567ef5..7e4cbf8e97511b2931efeef21ef715601b17ae43 100644 (file)
@@ -47,7 +47,8 @@ fn eq(&self, other: &Ident) -> bool {
             // if it should be non-hygienic (most things are), just compare the
             // 'name' fields of the idents. Or, even better, replace the idents
             // with Name's.
-            fail!(fmt!("not allowed to compare these idents: %?, %?", self, other));
+            fail!(fmt!("not allowed to compare these idents: %?, %?. Probably \
+                       related to issue #6993", self, other));
         }
     }
     fn ne(&self, other: &Ident) -> bool {
@@ -233,7 +234,7 @@ pub enum Def {
     DefStatic(DefId, bool /* is_mutbl */),
     DefArg(NodeId, bool /* is_mutbl */),
     DefLocal(NodeId, bool /* is_mutbl */),
-    DefVariant(DefId /* enum */, DefId /* variant */),
+    DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
     DefTy(DefId),
     DefTrait(DefId),
     DefPrimTy(prim_ty),
@@ -479,7 +480,13 @@ pub struct Field {
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum BlockCheckMode {
     DefaultBlock,
-    UnsafeBlock,
+    UnsafeBlock(UnsafeSource),
+}
+
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
+pub enum UnsafeSource {
+    CompilerGenerated,
+    UserProvided,
 }
 
 #[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
index 16e80560cc85ca1f288d4690f573df64e1f926e4..1323db7acba51505a3cb010fe35fae38ac62e06a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -38,6 +38,16 @@ pub enum path_elt {
     path_pretty_name(Ident, u64),
 }
 
+impl path_elt {
+    pub fn ident(&self) -> Ident {
+        match *self {
+            path_mod(ident)            |
+            path_name(ident)           |
+            path_pretty_name(ident, _) => ident
+        }
+    }
+}
+
 pub type path = ~[path_elt];
 
 pub fn path_to_str_with_sep(p: &[path_elt], sep: &str, itr: @ident_interner)
@@ -362,85 +372,9 @@ fn visit_block(&mut self, block: &Block, _: ()) {
         self.map_block(block)
     }
 
-    // XXX: Methods below can become default methods.
-
-    fn visit_mod(&mut self, module: &_mod, _: Span, _: NodeId, _: ()) {
-        visit::walk_mod(self, module, ())
-    }
-
-    fn visit_view_item(&mut self, view_item: &view_item, _: ()) {
-        visit::walk_view_item(self, view_item, ())
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: @foreign_item, _: ()) {
-        visit::walk_foreign_item(self, foreign_item, ())
-    }
-
-    fn visit_local(&mut self, local: @Local, _: ()) {
-        visit::walk_local(self, local, ())
-    }
-
-    fn visit_arm(&mut self, arm: &Arm, _: ()) {
-        visit::walk_arm(self, arm, ())
-    }
-
-    fn visit_decl(&mut self, decl: @Decl, _: ()) {
-        visit::walk_decl(self, decl, ())
-    }
-
-    fn visit_expr_post(&mut self, _: @Expr, _: ()) {
-        // Empty!
-    }
-
     fn visit_ty(&mut self, typ: &Ty, _: ()) {
         visit::walk_ty(self, typ, ())
     }
-
-    fn visit_generics(&mut self, generics: &Generics, _: ()) {
-        visit::walk_generics(self, generics, ())
-    }
-
-    fn visit_fn(&mut self,
-                function_kind: &fn_kind,
-                function_declaration: &fn_decl,
-                block: &Block,
-                span: Span,
-                node_id: NodeId,
-                _: ()) {
-        visit::walk_fn(self,
-                        function_kind,
-                        function_declaration,
-                        block,
-                        span,
-                        node_id,
-                        ())
-    }
-
-    fn visit_ty_method(&mut self, ty_method: &TypeMethod, _: ()) {
-        visit::walk_ty_method(self, ty_method, ())
-    }
-
-    fn visit_trait_method(&mut self, trait_method: &trait_method, _: ()) {
-        visit::walk_trait_method(self, trait_method, ())
-    }
-
-    fn visit_struct_def(&mut self,
-                        struct_def: @struct_def,
-                        ident: Ident,
-                        generics: &Generics,
-                        node_id: NodeId,
-                        _: ()) {
-        visit::walk_struct_def(self,
-                                struct_def,
-                                ident,
-                                generics,
-                                node_id,
-                                ())
-    }
-
-    fn visit_struct_field(&mut self, struct_field: @struct_field, _: ()) {
-        visit::walk_struct_field(self, struct_field, ())
-    }
 }
 
 pub fn map_crate(diag: @mut span_handler, c: &Crate) -> map {
index 040c4cda4c7e59963ecf84d1d0eb829220ead381..67c47093ff62ca04794a12743bf7057b50dcdc1e 100644 (file)
@@ -52,7 +52,7 @@ pub fn stmt_id(s: &Stmt) -> NodeId {
 
 pub fn variant_def_ids(d: Def) -> Option<(DefId, DefId)> {
     match d {
-      DefVariant(enum_id, var_id) => {
+      DefVariant(enum_id, var_id, _) => {
           Some((enum_id, var_id))
       }
       _ => None
@@ -63,7 +63,7 @@ pub fn def_id_of_def(d: Def) -> DefId {
     match d {
       DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
       DefForeignMod(id) | DefStatic(id, _) |
-      DefVariant(_, id) | DefTy(id) | DefTyParam(id, _) |
+      DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) |
       DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
         id
       }
@@ -519,20 +519,11 @@ fn visit_stmt(&mut self, statement: @Stmt, env: ()) {
         visit::walk_stmt(self, statement, env)
     }
 
-    // XXX: Default
-    fn visit_arm(&mut self, arm: &Arm, env: ()) {
-        visit::walk_arm(self, arm, env)
-    }
-
     fn visit_pat(&mut self, pattern: @Pat, env: ()) {
         (self.visit_callback)(pattern.id);
         visit::walk_pat(self, pattern, env)
     }
 
-    // XXX: Default
-    fn visit_decl(&mut self, declaration: @Decl, env: ()) {
-        visit::walk_decl(self, declaration, env)
-    }
 
     fn visit_expr(&mut self, expression: @Expr, env: ()) {
         {
@@ -545,11 +536,6 @@ fn visit_expr(&mut self, expression: @Expr, env: ()) {
         visit::walk_expr(self, expression, env)
     }
 
-    // XXX: Default
-    fn visit_expr_post(&mut self, _: @Expr, _: ()) {
-        // Empty!
-    }
-
     fn visit_ty(&mut self, typ: &Ty, env: ()) {
         (self.visit_callback)(typ.id);
         match typ.node {
@@ -612,31 +598,6 @@ fn visit_fn(&mut self,
         }
     }
 
-    // XXX: Default
-    fn visit_ty_method(&mut self, type_method: &TypeMethod, env: ()) {
-        visit::walk_ty_method(self, type_method, env)
-    }
-
-    // XXX: Default
-    fn visit_trait_method(&mut self, trait_method: &trait_method, env: ()) {
-        visit::walk_trait_method(self, trait_method, env)
-    }
-
-    // XXX: Default
-    fn visit_struct_def(&mut self,
-                        struct_definition: @struct_def,
-                        identifier: Ident,
-                        generics: &Generics,
-                        node_id: NodeId,
-                        env: ()) {
-        visit::walk_struct_def(self,
-                                struct_definition,
-                                identifier,
-                                generics,
-                                node_id,
-                                env)
-    }
-
     fn visit_struct_field(&mut self, struct_field: @struct_field, env: ()) {
         (self.visit_callback)(struct_field.node.id);
         visit::walk_struct_field(self, struct_field, env)
index fd0887de7224b3f82faa8423953a98463337d4bc..295485d6f6efaa7a30a4e29a3baaafedec2e3e66 100644 (file)
@@ -187,12 +187,12 @@ pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str)
                                  -> Option<@str> {
     attrs.iter()
         .find(|at| name == at.name())
-        .chain(|at| at.value_str())
+        .and_then(|at| at.value_str())
 }
 
 pub fn last_meta_item_value_str_by_name(items: &[@MetaItem], name: &str)
                                      -> Option<@str> {
-    items.rev_iter().find(|mi| name == mi.name()).chain(|i| i.value_str())
+    items.rev_iter().find(|mi| name == mi.name()).and_then(|i| i.value_str())
 }
 
 /* Higher-level applications */
index 1c3a8e81e5527f0453b6e54f5ed3af61a7cebe67..c8e40b82e0c30b914d97efbb5575b48293f47891 100644 (file)
@@ -30,12 +30,12 @@ pub trait Pos {
 }
 
 /// A byte offset
-#[deriving(Clone, Eq, IterBytes)]
+#[deriving(Clone, Eq, IterBytes, Ord)]
 pub struct BytePos(uint);
 /// A character offset. Because of multibyte utf8 characters, a byte offset
 /// is not equivalent to a character offset. The CodeMap will convert BytePos
 /// values to CharPos values as necessary.
-#[deriving(Eq,IterBytes)]
+#[deriving(Eq,IterBytes, Ord)]
 pub struct CharPos(uint);
 
 // XXX: Lots of boilerplate in these impls, but so far my attempts to fix
@@ -46,13 +46,6 @@ fn from_uint(n: uint) -> BytePos { BytePos(n) }
     fn to_uint(&self) -> uint { **self }
 }
 
-impl cmp::Ord for BytePos {
-    fn lt(&self, other: &BytePos) -> bool { **self < **other }
-    fn le(&self, other: &BytePos) -> bool { **self <= **other }
-    fn ge(&self, other: &BytePos) -> bool { **self >= **other }
-    fn gt(&self, other: &BytePos) -> bool { **self > **other }
-}
-
 impl Add<BytePos, BytePos> for BytePos {
     fn add(&self, rhs: &BytePos) -> BytePos {
         BytePos(**self + **rhs)
@@ -70,13 +63,6 @@ fn from_uint(n: uint) -> CharPos { CharPos(n) }
     fn to_uint(&self) -> uint { **self }
 }
 
-impl cmp::Ord for CharPos {
-    fn lt(&self, other: &CharPos) -> bool { **self < **other }
-    fn le(&self, other: &CharPos) -> bool { **self <= **other }
-    fn ge(&self, other: &CharPos) -> bool { **self >= **other }
-    fn gt(&self, other: &CharPos) -> bool { **self > **other }
-}
-
 impl Add<CharPos,CharPos> for CharPos {
     fn add(&self, rhs: &CharPos) -> CharPos {
         CharPos(**self + **rhs)
index 48a1364668688a58c24937d8e1aa2478eb6f6395..2bcfafc3bb483ffb62c4501760f020c26d766ff7 100644 (file)
@@ -155,12 +155,8 @@ fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer {
                             @SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
     syntax_expanders.insert(intern(&"fmt"),
                             builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
-    syntax_expanders.insert(intern(&"format"),
-                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_format));
-    syntax_expanders.insert(intern(&"write"),
-                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_write));
-    syntax_expanders.insert(intern(&"writeln"),
-                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln));
+    syntax_expanders.insert(intern(&"format_args"),
+                            builtin_normal_tt_no_ctxt(ext::format::expand_args));
     syntax_expanders.insert(
         intern(&"auto_encode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs
new file mode 100644 (file)
index 0000000..0c7bbef
--- /dev/null
@@ -0,0 +1,79 @@
+// 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 ast::{MetaItem, item, Expr};
+use codemap::Span;
+use ext::base::ExtCtxt;
+use ext::build::AstBuilder;
+use ext::deriving::generic::*;
+
+use std::vec;
+
+pub fn expand_deriving_default(cx: @ExtCtxt,
+                            span: Span,
+                            mitem: @MetaItem,
+                            in_items: ~[@item])
+    -> ~[@item] {
+    let trait_def = TraitDef {
+        path: Path::new(~["std", "default", "Default"]),
+        additional_bounds: ~[],
+        generics: LifetimeBounds::empty(),
+        methods: ~[
+            MethodDef {
+                name: "default",
+                generics: LifetimeBounds::empty(),
+                explicit_self: None,
+                args: ~[],
+                ret_ty: Self,
+                const_nonmatching: false,
+                combine_substructure: default_substructure
+            },
+        ]
+    };
+    trait_def.expand(cx, span, mitem, in_items)
+}
+
+fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
+    let default_ident = ~[
+        cx.ident_of("std"),
+        cx.ident_of("default"),
+        cx.ident_of("Default"),
+        cx.ident_of("default")
+    ];
+    let default_call = || {
+        cx.expr_call_global(span, default_ident.clone(), ~[])
+    };
+
+    return match *substr.fields {
+        StaticStruct(_, ref summary) => {
+            match *summary {
+                Left(count) => {
+                    if count == 0 {
+                        cx.expr_ident(span, substr.type_ident)
+                    } else {
+                        let exprs = vec::from_fn(count, |_| default_call());
+                        cx.expr_call_ident(span, substr.type_ident, exprs)
+                    }
+                }
+                Right(ref fields) => {
+                    let default_fields = do fields.map |ident| {
+                        cx.field_imm(span, *ident, default_call())
+                    };
+                    cx.expr_struct_ident(span, substr.type_ident, default_fields)
+                }
+            }
+        }
+        StaticEnum(*) => {
+            cx.span_fatal(span, "`Default` cannot be derived for enums, \
+                                 only structs")
+        }
+        _ => cx.bug("Non-static method in `deriving(Default)`")
+    };
+}
index 7fd44bfad01f2eef961578f487ad28acc04f69cf..dfd4f79cd9e3e5a2c5055853230556a080a1ef45 100644 (file)
@@ -31,6 +31,7 @@
 pub mod rand;
 pub mod to_str;
 pub mod zero;
+pub mod default;
 
 #[path="cmp/eq.rs"]
 pub mod eq;
@@ -97,6 +98,7 @@ macro_rules! expand(($func:path) => ($func(cx, titem.span,
 
                             "ToStr" => expand!(to_str::expand_deriving_to_str),
                             "Zero" => expand!(zero::expand_deriving_zero),
+                            "Default" => expand!(default::expand_deriving_default),
 
                             ref tname => {
                                 cx.span_err(titem.span, fmt!("unknown \
index 2cebae550fd56e66216c9148aa9b22a46c234fed..ac094c27a8119780debbf58de5afefbd413d7dd4 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, NodeId, DeclLocal, Expr_, ExprMac, SyntaxContext};
+use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext};
 use ast::{Local, Ident, mac_invoc_tt};
 use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
 use ast::{token_tree};
@@ -76,8 +76,16 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                             // mark before:
                             let marked_before = mark_tts(*tts,fm);
                             let marked_ctxt = new_mark(fm, ctxt);
+
+                            // The span that we pass to the expanders we want to
+                            // be the root of the call stack. That's the most
+                            // relevant span and it's the actual invocation of
+                            // the macro.
+                            let mac_span = original_span(cx);
+
                             let expanded =
-                                match expandfun(cx, mac.span, marked_before, marked_ctxt) {
+                                match expandfun(cx, mac_span.call_site,
+                                                marked_before, marked_ctxt) {
                                     MRExpr(e) => e,
                                     MRAny(expr_maker,_,_) => expr_maker(),
                                     _ => {
@@ -331,11 +339,18 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
     };
 
     let maybe_it = match expanded {
-        MRItem(it) => mark_item(it,fm).chain(|i| {fld.fold_item(i)}),
-        MRExpr(_) => cx.span_fatal(pth.span,
-                                   fmt!("expr macro in item position: %s", extnamestr)),
-        MRAny(_, item_maker, _) => item_maker().chain(|i| {mark_item(i,fm)})
-                                      .chain(|i| {fld.fold_item(i)}),
+        MRItem(it) => {
+            mark_item(it,fm)
+                .and_then(|i| fld.fold_item(i))
+        }
+        MRExpr(_) => {
+            cx.span_fatal(pth.span, fmt!("expr macro in item position: %s", extnamestr))
+        }
+        MRAny(_, item_maker, _) => {
+            item_maker()
+                .and_then(|i| mark_item(i,fm))
+                .and_then(|i| fld.fold_item(i))
+        }
         MRDef(ref mdef) => {
             // yikes... no idea how to apply the mark to this. I'm afraid
             // we're going to have to wait-and-see on this one.
@@ -375,11 +390,11 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                 -> (Option<Stmt_>, Span) {
     // why the copying here and not in expand_expr?
     // looks like classic changed-in-only-one-place
-    let (mac, pth, tts, semi, ctxt) = match *s {
+    let (pth, tts, semi, ctxt) = match *s {
         StmtMac(ref mac, semi) => {
             match mac.node {
                 mac_invoc_tt(ref pth, ref tts, ctxt) => {
-                    ((*mac).clone(), pth, (*tts).clone(), semi, ctxt)
+                    (pth, (*tts).clone(), semi, ctxt)
                 }
             }
         }
@@ -406,7 +421,13 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
             // mark before expansion:
             let marked_tts = mark_tts(tts,fm);
             let marked_ctxt = new_mark(fm,ctxt);
-            let expanded = match expandfun(cx, mac.span, marked_tts, marked_ctxt) {
+
+            // See the comment in expand_expr for why we want the original span,
+            // not the current mac.span.
+            let mac_span = original_span(cx);
+
+            let expanded = match expandfun(cx, mac_span.call_site,
+                                           marked_tts, marked_ctxt) {
                 MRExpr(e) =>
                     @codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID),
                                         span: e.span},
@@ -553,107 +574,10 @@ fn visit_pat(&mut self, pattern: @ast::Pat, _: ()) {
         }
     }
 
-    // XXX: Methods below can become default methods.
-
-    fn visit_mod(&mut self, module: &ast::_mod, _: Span, _: NodeId, _: ()) {
-        visit::walk_mod(self, module, ())
-    }
-
-    fn visit_view_item(&mut self, view_item: &ast::view_item, _: ()) {
-        visit::walk_view_item(self, view_item, ())
-    }
-
-    fn visit_item(&mut self, item: @ast::item, _: ()) {
-        visit::walk_item(self, item, ())
-    }
-
-    fn visit_foreign_item(&mut self,
-                          foreign_item: @ast::foreign_item,
-                          _: ()) {
-        visit::walk_foreign_item(self, foreign_item, ())
-    }
-
-    fn visit_local(&mut self, local: @ast::Local, _: ()) {
-        visit::walk_local(self, local, ())
-    }
-
-    fn visit_block(&mut self, block: &ast::Block, _: ()) {
-        visit::walk_block(self, block, ())
-    }
-
-    fn visit_stmt(&mut self, stmt: @ast::Stmt, _: ()) {
-        visit::walk_stmt(self, stmt, ())
-    }
-
-    fn visit_arm(&mut self, arm: &ast::Arm, _: ()) {
-        visit::walk_arm(self, arm, ())
-    }
-
-    fn visit_decl(&mut self, decl: @ast::Decl, _: ()) {
-        visit::walk_decl(self, decl, ())
-    }
-
-    fn visit_expr(&mut self, expr: @ast::Expr, _: ()) {
-        visit::walk_expr(self, expr, ())
-    }
-
-    fn visit_expr_post(&mut self, _: @ast::Expr, _: ()) {
-        // Empty!
-    }
-
     fn visit_ty(&mut self, typ: &ast::Ty, _: ()) {
         visit::walk_ty(self, typ, ())
     }
 
-    fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
-        visit::walk_generics(self, generics, ())
-    }
-
-    fn visit_fn(&mut self,
-                function_kind: &visit::fn_kind,
-                function_declaration: &ast::fn_decl,
-                block: &ast::Block,
-                span: Span,
-                node_id: NodeId,
-                _: ()) {
-        visit::walk_fn(self,
-                        function_kind,
-                        function_declaration,
-                        block,
-                        span,
-                        node_id,
-                        ())
-    }
-
-    fn visit_ty_method(&mut self, ty_method: &ast::TypeMethod, _: ()) {
-        visit::walk_ty_method(self, ty_method, ())
-    }
-
-    fn visit_trait_method(&mut self,
-                          trait_method: &ast::trait_method,
-                          _: ()) {
-        visit::walk_trait_method(self, trait_method, ())
-    }
-
-    fn visit_struct_def(&mut self,
-                        struct_def: @ast::struct_def,
-                        ident: Ident,
-                        generics: &ast::Generics,
-                        node_id: NodeId,
-                        _: ()) {
-        visit::walk_struct_def(self,
-                                struct_def,
-                                ident,
-                                generics,
-                                node_id,
-                                ())
-    }
-
-    fn visit_struct_field(&mut self,
-                          struct_field: @ast::struct_field,
-                          _: ()) {
-        visit::walk_struct_field(self, struct_field, ())
-    }
 }
 
 // a visitor that extracts the paths
@@ -664,7 +588,6 @@ struct NewPathExprFinderContext {
     path_accumulator: @mut ~[ast::Path],
 }
 
-// XXX : YIKES a lot of boilerplate again....
 impl Visitor<()> for NewPathExprFinderContext {
 
     fn visit_expr(&mut self, expr: @ast::Expr, _: ()) {
@@ -677,108 +600,10 @@ fn visit_expr(&mut self, expr: @ast::Expr, _: ()) {
         }
     }
 
-
-    // XXX: Methods below can become default methods.
-
-    fn visit_pat(&mut self, pattern: @ast::Pat, _: ()) {
-        visit::walk_pat(self,pattern,())
-    }
-
-    fn visit_mod(&mut self, module: &ast::_mod, _: Span, _: NodeId, _: ()) {
-        visit::walk_mod(self, module, ())
-    }
-
-    fn visit_view_item(&mut self, view_item: &ast::view_item, _: ()) {
-        visit::walk_view_item(self, view_item, ())
-    }
-
-    fn visit_item(&mut self, item: @ast::item, _: ()) {
-        visit::walk_item(self, item, ())
-    }
-
-    fn visit_foreign_item(&mut self,
-                          foreign_item: @ast::foreign_item,
-                          _: ()) {
-        visit::walk_foreign_item(self, foreign_item, ())
-    }
-
-    fn visit_local(&mut self, local: @ast::Local, _: ()) {
-        visit::walk_local(self, local, ())
-    }
-
-    fn visit_block(&mut self, block: &ast::Block, _: ()) {
-        visit::walk_block(self, block, ())
-    }
-
-    fn visit_stmt(&mut self, stmt: @ast::Stmt, _: ()) {
-        visit::walk_stmt(self, stmt, ())
-    }
-
-    fn visit_arm(&mut self, arm: &ast::Arm, _: ()) {
-        visit::walk_arm(self, arm, ())
-    }
-
-    fn visit_decl(&mut self, decl: @ast::Decl, _: ()) {
-        visit::walk_decl(self, decl, ())
-    }
-
-    fn visit_expr_post(&mut self, _: @ast::Expr, _: ()) {
-        // Empty!
-    }
-
     fn visit_ty(&mut self, typ: &ast::Ty, _: ()) {
         visit::walk_ty(self, typ, ())
     }
 
-    fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
-        visit::walk_generics(self, generics, ())
-    }
-
-    fn visit_fn(&mut self,
-                function_kind: &visit::fn_kind,
-                function_declaration: &ast::fn_decl,
-                block: &ast::Block,
-                span: Span,
-                node_id: NodeId,
-                _: ()) {
-        visit::walk_fn(self,
-                        function_kind,
-                        function_declaration,
-                        block,
-                        span,
-                        node_id,
-                        ())
-    }
-
-    fn visit_ty_method(&mut self, ty_method: &ast::TypeMethod, _: ()) {
-        visit::walk_ty_method(self, ty_method, ())
-    }
-
-    fn visit_trait_method(&mut self,
-                          trait_method: &ast::trait_method,
-                          _: ()) {
-        visit::walk_trait_method(self, trait_method, ())
-    }
-
-    fn visit_struct_def(&mut self,
-                        struct_def: @ast::struct_def,
-                        ident: Ident,
-                        generics: &ast::Generics,
-                        node_id: NodeId,
-                        _: ()) {
-        visit::walk_struct_def(self,
-                                struct_def,
-                                ident,
-                                generics,
-                                node_id,
-                                ())
-    }
-
-    fn visit_struct_field(&mut self,
-                          struct_field: @ast::struct_field,
-                          _: ()) {
-        visit::walk_struct_field(self, struct_field, ())
-    }
 }
 
 // return a visitor that extracts the pat_ident paths
@@ -886,11 +711,11 @@ macro_rules! log(
             }
         })
     )
-    macro_rules! error( ($($arg:tt)+) => (log!(1u32, $($arg)+)) )
-    macro_rules! warn ( ($($arg:tt)+) => (log!(2u32, $($arg)+)) )
-    macro_rules! info ( ($($arg:tt)+) => (log!(3u32, $($arg)+)) )
-    macro_rules! debug( ($($arg:tt)+) => (
-        if cfg!(debug) { log!(4u32, $($arg)+) }
+    macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
+    macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
+    macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
+    macro_rules! debug( ($($arg:tt)*) => (
+        if cfg!(debug) { log!(4u32, $($arg)*) }
     ))
 
     macro_rules! log2(
@@ -901,11 +726,11 @@ macro_rules! log2(
             }
         })
     )
-    macro_rules! error2( ($($arg:tt)+) => (log2!(1u32, $($arg)+)) )
-    macro_rules! warn2 ( ($($arg:tt)+) => (log2!(2u32, $($arg)+)) )
-    macro_rules! info2 ( ($($arg:tt)+) => (log2!(3u32, $($arg)+)) )
-    macro_rules! debug2( ($($arg:tt)+) => (
-        if cfg!(debug) { log2!(4u32, $($arg)+) }
+    macro_rules! error2( ($($arg:tt)*) => (log2!(1u32, $($arg)*)) )
+    macro_rules! warn2 ( ($($arg:tt)*) => (log2!(2u32, $($arg)*)) )
+    macro_rules! info2 ( ($($arg:tt)*) => (log2!(3u32, $($arg)*)) )
+    macro_rules! debug2( ($($arg:tt)*) => (
+        if cfg!(debug) { log2!(4u32, $($arg)*) }
     ))
 
     macro_rules! fail(
@@ -924,8 +749,8 @@ macro_rules! fail2(
         () => (
             fail!(\"explicit failure\")
         );
-        ($($arg:tt)+) => (
-            ::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!())
+        ($($arg:tt)*) => (
+            ::std::sys::FailWithCause::fail_with(format!($($arg)*), file!(), line!())
         )
     )
 
@@ -1129,17 +954,25 @@ macro_rules! printfln (
         )
     )
 
+    macro_rules! format(($($arg:tt)*) => (
+        format_args!(::std::fmt::format, $($arg)*)
+    ))
+    macro_rules! write(($dst:expr, $($arg:tt)*) => (
+        format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
+    ))
+    macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
+        format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
+    ))
     // 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)+)))
+        ($($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)+) => (::std::io::println(format!($($arg)+)))
+        ($($arg:tt)*) => (::std::io::println(format!($($arg)*)))
     )
 
     // NOTE: use this after a snapshot lands to abstract the details
@@ -1433,6 +1266,20 @@ pub fn mtwt_cancel_outer_mark(tts: &[ast::token_tree], ctxt: ast::SyntaxContext)
     mark_tts(tts,outer_mark)
 }
 
+fn original_span(cx: @ExtCtxt) -> @codemap::ExpnInfo {
+    let mut relevant_info = cx.backtrace();
+    let mut einfo = relevant_info.unwrap();
+    loop {
+        match relevant_info {
+            None => { break }
+            Some(e) => {
+                einfo = e;
+                relevant_info = einfo.call_site.expn_info;
+            }
+        }
+    }
+    return einfo;
+}
 
 #[cfg(test)]
 mod test {
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
new file mode 100644 (file)
index 0000000..9f4e55b
--- /dev/null
@@ -0,0 +1,756 @@
+// 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.
+
+use ast;
+use codemap::{Span, respan};
+use ext::base::*;
+use ext::base;
+use ext::build::AstBuilder;
+use rsparse = parse;
+use parse::token;
+
+use std::fmt::parse;
+use std::hashmap::{HashMap, HashSet};
+use std::vec;
+
+#[deriving(Eq)]
+enum ArgumentType {
+    Unknown,
+    Known(@str),
+    Unsigned,
+    String,
+}
+
+struct Context {
+    ecx: @ExtCtxt,
+    fmtsp: Span,
+
+    // Parsed argument expressions and the types that we've found so far for
+    // them.
+    args: ~[@ast::Expr],
+    arg_types: ~[Option<ArgumentType>],
+    // Parsed named expressions and the types that we've found for them so far
+    names: HashMap<@str, @ast::Expr>,
+    name_types: HashMap<@str, ArgumentType>,
+
+    // Collection of the compiled `rt::Piece` structures
+    pieces: ~[@ast::Expr],
+    name_positions: HashMap<@str, uint>,
+    method_statics: ~[@ast::item],
+
+    // Updated as arguments are consumed or methods are entered
+    nest_level: uint,
+    next_arg: uint,
+}
+
+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]) -> (@ast::Expr, Option<@ast::Expr>) {
+        let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(),
+                                             self.ecx.cfg(),
+                                             tts.to_owned());
+        // Parse the leading function expression (maybe a block, maybe a path)
+        let extra = p.parse_expr();
+        if !p.eat(&token::COMMA) {
+            self.ecx.span_err(sp, "expected token: `,`");
+            return (extra, None);
+        }
+
+        if *p.token == token::EOF {
+            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 (extra, None);
+            }
+            if named || (token::is_ident(p.token) &&
+                         p.look_ahead(1, |t| *t == token::EQ)) {
+                named = true;
+                let ident = match *p.token {
+                    token::IDENT(i, _) => {
+                        p.bump();
+                        i
+                    }
+                    _ if named => {
+                        self.ecx.span_err(*p.span,
+                                          "expected ident, positional arguments \
+                                           cannot follow named arguments");
+                        return (extra, None);
+                    }
+                    _ => {
+                        self.ecx.span_err(*p.span,
+                                          fmt!("expected ident for named \
+                                                argument, but found `%s`",
+                                               p.this_token_to_str()));
+                        return (extra, None);
+                    }
+                };
+                let name = self.ecx.str_of(ident);
+                p.expect(&token::EQ);
+                let e = p.parse_expr();
+                match self.names.find(&name) {
+                    None => {}
+                    Some(prev) => {
+                        self.ecx.span_err(e.span, fmt!("duplicate argument \
+                                                        named `%s`", name));
+                        self.ecx.parse_sess.span_diagnostic.span_note(
+                            prev.span, "previously here");
+                        loop
+                    }
+                }
+                self.names.insert(name, e);
+            } else {
+                self.args.push(p.parse_expr());
+                self.arg_types.push(None);
+            }
+        }
+        return (extra, Some(fmtstr));
+    }
+
+    /// Verifies one piece of a parse string. All errors are not emitted as
+    /// fatal so we can continue giving errors about this and possibly other
+    /// format strings.
+    fn verify_piece(&mut self, p: &parse::Piece) {
+        match *p {
+            parse::String(*) => {}
+            parse::CurrentArgument => {
+                if self.nest_level == 0 {
+                    self.ecx.span_err(self.fmtsp,
+                                      "`#` reference used with nothing to \
+                                       reference back to");
+                }
+            }
+            parse::Argument(ref arg) => {
+                // width/precision first, if they have implicit positional
+                // parameters it makes more sense to consume them first.
+                self.verify_count(arg.format.width);
+                self.verify_count(arg.format.precision);
+
+                // argument second, if it's an implicit positional parameter
+                // it's written second, so it should come after width/precision.
+                let pos = match arg.position {
+                    parse::ArgumentNext => {
+                        let i = self.next_arg;
+                        if self.check_positional_ok() {
+                            self.next_arg += 1;
+                        }
+                        Left(i)
+                    }
+                    parse::ArgumentIs(i) => Left(i),
+                    parse::ArgumentNamed(s) => Right(s.to_managed()),
+                };
+                let ty = if arg.format.ty == "" {
+                    Unknown
+                } else { Known(arg.format.ty.to_managed()) };
+                self.verify_arg_type(pos, ty);
+
+                // and finally the method being applied
+                match arg.method {
+                    None => {}
+                    Some(ref method) => { self.verify_method(pos, *method); }
+                }
+            }
+        }
+    }
+
+    fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
+        for piece in pieces.iter() {
+            self.verify_piece(piece);
+        }
+    }
+
+    fn verify_count(&mut self, c: parse::Count) {
+        match c {
+            parse::CountImplied | parse::CountIs(*) => {}
+            parse::CountIsParam(i) => {
+                self.verify_arg_type(Left(i), Unsigned);
+            }
+            parse::CountIsNextParam => {
+                if self.check_positional_ok() {
+                    self.verify_arg_type(Left(self.next_arg), Unsigned);
+                    self.next_arg += 1;
+                }
+            }
+        }
+    }
+
+    fn check_positional_ok(&mut self) -> bool {
+        if self.nest_level != 0 {
+            self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
+                                           arguments nested inside methods");
+            false
+        } else {
+            true
+        }
+    }
+
+    fn verify_method(&mut self, pos: Either<uint, @str>, m: &parse::Method) {
+        self.nest_level += 1;
+        match *m {
+            parse::Plural(_, ref arms, ref default) => {
+                let mut seen_cases = HashSet::new();
+                self.verify_arg_type(pos, Unsigned);
+                for arm in arms.iter() {
+                    if !seen_cases.insert(arm.selector) {
+                        match arm.selector {
+                            Left(name) => {
+                                self.ecx.span_err(self.fmtsp,
+                                                  fmt!("duplicate selector \
+                                                       `%?`", name));
+                            }
+                            Right(idx) => {
+                                self.ecx.span_err(self.fmtsp,
+                                                  fmt!("duplicate selector \
+                                                       `=%u`", idx));
+                            }
+                        }
+                    }
+                    self.verify_pieces(arm.result);
+                }
+                self.verify_pieces(*default);
+            }
+            parse::Select(ref arms, ref default) => {
+                self.verify_arg_type(pos, String);
+                let mut seen_cases = HashSet::new();
+                for arm in arms.iter() {
+                    if !seen_cases.insert(arm.selector) {
+                        self.ecx.span_err(self.fmtsp,
+                                          fmt!("duplicate selector `%s`",
+                                               arm.selector));
+                    } else if arm.selector == "" {
+                        self.ecx.span_err(self.fmtsp,
+                                          "empty selector in `select`");
+                    }
+                    self.verify_pieces(arm.result);
+                }
+                self.verify_pieces(*default);
+            }
+        }
+        self.nest_level -= 1;
+    }
+
+    fn verify_arg_type(&mut self, arg: Either<uint, @str>, ty: ArgumentType) {
+        match arg {
+            Left(arg) => {
+                if arg < 0 || self.args.len() <= arg {
+                    let msg = fmt!("invalid reference to argument `%u` (there \
+                                    are %u arguments)", arg, self.args.len());
+                    self.ecx.span_err(self.fmtsp, msg);
+                    return;
+                }
+                self.verify_same(self.args[arg].span, ty, self.arg_types[arg]);
+                if ty != Unknown || self.arg_types[arg].is_none() {
+                    self.arg_types[arg] = Some(ty);
+                }
+            }
+
+            Right(name) => {
+                let span = match self.names.find(&name) {
+                    Some(e) => e.span,
+                    None => {
+                        let msg = fmt!("There is no argument named `%s`", name);
+                        self.ecx.span_err(self.fmtsp, msg);
+                        return;
+                    }
+                };
+                self.verify_same(span, ty,
+                                 self.name_types.find(&name).map(|&x| *x));
+                if ty != Unknown || !self.name_types.contains_key(&name) {
+                    self.name_types.insert(name, ty);
+                }
+                // Assign this named argument a slot in the arguments array if
+                // it hasn't already been assigned a slot.
+                if !self.name_positions.contains_key(&name) {
+                    let slot = self.name_positions.len();
+                    self.name_positions.insert(name, slot);
+                }
+            }
+        }
+    }
+
+    /// When we're keeping track of the types that are declared for certain
+    /// arguments, we assume that `None` means we haven't seen this argument
+    /// yet, `Some(None)` means that we've seen the argument, but no format was
+    /// specified, and `Some(Some(x))` means that the argument was declared to
+    /// have type `x`.
+    ///
+    /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
+    /// that: `Some(None) == Some(Some(x))`
+    fn verify_same(&self, sp: Span, ty: ArgumentType,
+                   before: Option<ArgumentType>) {
+        if ty == Unknown { return }
+        let cur = match before {
+            Some(Unknown) | None => return,
+            Some(t) => t,
+        };
+        if ty == cur { return }
+        match (cur, ty) {
+            (Known(cur), Known(ty)) => {
+                self.ecx.span_err(sp,
+                                  fmt!("argument redeclared with type `%s` when \
+                                        it was previously `%s`", ty, cur));
+            }
+            (Known(cur), _) => {
+                self.ecx.span_err(sp,
+                                  fmt!("argument used to format with `%s` was \
+                                        attempted to not be used for formatting",
+                                        cur));
+            }
+            (_, Known(ty)) => {
+                self.ecx.span_err(sp,
+                                  fmt!("argument previously used as a format \
+                                        argument attempted to be used as `%s`",
+                                        ty));
+            }
+            (_, _) => {
+                self.ecx.span_err(sp, "argument declared with multiple formats");
+            }
+        }
+    }
+
+    /// Translate a `parse::Piece` to a static `rt::Piece`
+    fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
+        let sp = self.fmtsp;
+        let parsepath = |s: &str| {
+            ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+              self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
+        };
+        let rtpath = |s: &str| {
+            ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+              self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
+        };
+        let ctpath = |s: &str| {
+            ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+              self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
+        };
+        let none = self.ecx.path_global(sp, ~[
+                self.ecx.ident_of("std"),
+                self.ecx.ident_of("option"),
+                self.ecx.ident_of("None")]);
+        let none = self.ecx.expr_path(none);
+        let some = |e: @ast::Expr| {
+            let p = self.ecx.path_global(sp, ~[
+                self.ecx.ident_of("std"),
+                self.ecx.ident_of("option"),
+                self.ecx.ident_of("Some")]);
+            let p = self.ecx.expr_path(p);
+            self.ecx.expr_call(sp, p, ~[e])
+        };
+        let trans_count = |c: parse::Count| {
+            match c {
+                parse::CountIs(i) => {
+                    self.ecx.expr_call_global(sp, ctpath("CountIs"),
+                                              ~[self.ecx.expr_uint(sp, i)])
+                }
+                parse::CountIsParam(i) => {
+                    self.ecx.expr_call_global(sp, ctpath("CountIsParam"),
+                                              ~[self.ecx.expr_uint(sp, i)])
+                }
+                parse::CountImplied => {
+                    let path = self.ecx.path_global(sp, ctpath("CountImplied"));
+                    self.ecx.expr_path(path)
+                }
+                parse::CountIsNextParam => {
+                    let path = self.ecx.path_global(sp, ctpath("CountIsNextParam"));
+                    self.ecx.expr_path(path)
+                }
+            }
+        };
+        let trans_method = |method: &parse::Method| {
+            let method = match *method {
+                parse::Select(ref arms, ref default) => {
+                    let arms = arms.iter().map(|arm| {
+                        let p = self.ecx.path_global(sp, rtpath("SelectArm"));
+                        let result = arm.result.iter().map(|p| {
+                            self.trans_piece(p)
+                        }).collect();
+                        let s = arm.selector.to_managed();
+                        let selector = self.ecx.expr_str(sp, s);
+                        self.ecx.expr_struct(sp, p, ~[
+                            self.ecx.field_imm(sp,
+                                               self.ecx.ident_of("selector"),
+                                               selector),
+                            self.ecx.field_imm(sp, self.ecx.ident_of("result"),
+                                               self.ecx.expr_vec_slice(sp, result)),
+                        ])
+                    }).collect();
+                    let default = default.iter().map(|p| {
+                        self.trans_piece(p)
+                    }).collect();
+                    self.ecx.expr_call_global(sp, rtpath("Select"), ~[
+                        self.ecx.expr_vec_slice(sp, arms),
+                        self.ecx.expr_vec_slice(sp, default),
+                    ])
+                }
+                parse::Plural(offset, ref arms, ref default) => {
+                    let offset = match offset {
+                        Some(i) => { some(self.ecx.expr_uint(sp, i)) }
+                        None => { none.clone() }
+                    };
+                    let arms = arms.iter().map(|arm| {
+                        let p = self.ecx.path_global(sp, rtpath("PluralArm"));
+                        let result = arm.result.iter().map(|p| {
+                            self.trans_piece(p)
+                        }).collect();
+                        let (lr, selarg) = match arm.selector {
+                            Left(t) => {
+                                let p = ctpath(fmt!("%?", t));
+                                let p = self.ecx.path_global(sp, p);
+                                (self.ecx.ident_of("Left"),
+                                 self.ecx.expr_path(p))
+                            }
+                            Right(i) => {
+                                (self.ecx.ident_of("Right"),
+                                 self.ecx.expr_uint(sp, i))
+                            }
+                        };
+                        let selector = self.ecx.expr_call_ident(sp,
+                                lr, ~[selarg]);
+                        self.ecx.expr_struct(sp, p, ~[
+                            self.ecx.field_imm(sp,
+                                               self.ecx.ident_of("selector"),
+                                               selector),
+                            self.ecx.field_imm(sp, self.ecx.ident_of("result"),
+                                               self.ecx.expr_vec_slice(sp, result)),
+                        ])
+                    }).collect();
+                    let default = default.iter().map(|p| {
+                        self.trans_piece(p)
+                    }).collect();
+                    self.ecx.expr_call_global(sp, rtpath("Plural"), ~[
+                        offset,
+                        self.ecx.expr_vec_slice(sp, arms),
+                        self.ecx.expr_vec_slice(sp, default),
+                    ])
+                }
+            };
+            let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
+            let ty = self.ecx.ty_path(self.ecx.path_all(
+                sp,
+                true,
+                rtpath("Method"),
+                Some(life),
+                ~[]
+            ), None);
+            let st = ast::item_static(ty, ast::MutImmutable, method);
+            let static_name = self.ecx.ident_of(fmt!("__static_method_%u",
+                                                     self.method_statics.len()));
+            // Flag these statics as `address_insignificant` so LLVM can
+            // merge duplicate globals as much as possible (which we're
+            // generating a whole lot of).
+            let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
+            let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+            let item = self.ecx.item(sp, static_name, ~[unnamed], st);
+            self.method_statics.push(item);
+            self.ecx.expr_ident(sp, static_name)
+        };
+
+        match *piece {
+            parse::String(s) => {
+                self.ecx.expr_call_global(sp, rtpath("String"),
+                                          ~[self.ecx.expr_str(sp, s.to_managed())])
+            }
+            parse::CurrentArgument => {
+                let nil = self.ecx.expr_lit(sp, ast::lit_nil);
+                self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil])
+            }
+            parse::Argument(ref arg) => {
+                // Translate the position
+                let pos = match arg.position {
+                    // These two have a direct mapping
+                    parse::ArgumentNext => {
+                        let path = self.ecx.path_global(sp,
+                                                        rtpath("ArgumentNext"));
+                        self.ecx.expr_path(path)
+                    }
+                    parse::ArgumentIs(i) => {
+                        self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
+                                                  ~[self.ecx.expr_uint(sp, i)])
+                    }
+                    // Named arguments are converted to positional arguments at
+                    // the end of the list of arguments
+                    parse::ArgumentNamed(n) => {
+                        let n = n.to_managed();
+                        let i = match self.name_positions.find_copy(&n) {
+                            Some(i) => i,
+                            None => 0, // error already emitted elsewhere
+                        };
+                        let i = i + self.args.len();
+                        self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
+                                                  ~[self.ecx.expr_uint(sp, i)])
+                    }
+                };
+
+                // Translate the format
+                let fill = match arg.format.fill { Some(c) => c, None => ' ' };
+                let fill = self.ecx.expr_lit(sp, ast::lit_char(fill as u32));
+                let align = match arg.format.align {
+                    parse::AlignLeft => {
+                        self.ecx.path_global(sp, parsepath("AlignLeft"))
+                    }
+                    parse::AlignRight => {
+                        self.ecx.path_global(sp, parsepath("AlignRight"))
+                    }
+                    parse::AlignUnknown => {
+                        self.ecx.path_global(sp, parsepath("AlignUnknown"))
+                    }
+                };
+                let align = self.ecx.expr_path(align);
+                let flags = self.ecx.expr_uint(sp, arg.format.flags);
+                let prec = trans_count(arg.format.precision);
+                let width = trans_count(arg.format.width);
+                let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
+                let fmt = self.ecx.expr_struct(sp, path, ~[
+                    self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
+                ]);
+
+                // Translate the method (if any)
+                let method = match arg.method {
+                    None => { none.clone() }
+                    Some(ref m) => {
+                        let m = trans_method(*m);
+                        some(self.ecx.expr_addr_of(sp, m))
+                    }
+                };
+                let path = self.ecx.path_global(sp, rtpath("Argument"));
+                let s = self.ecx.expr_struct(sp, path, ~[
+                    self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("method"), method),
+                ]);
+                self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s])
+            }
+        }
+    }
+
+    /// Actually builds the expression which the ifmt! block will be expanded
+    /// to
+    fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
+        let mut lets = ~[];
+        let mut locals = ~[];
+        let mut names = vec::from_fn(self.name_positions.len(), |_| None);
+
+        // First, declare all of our methods that are statics
+        for &method in self.method_statics.iter() {
+            let decl = respan(self.fmtsp, ast::DeclItem(method));
+            lets.push(@respan(self.fmtsp,
+                              ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
+        }
+
+        // Next, build up the static array which will become our precompiled
+        // format "string"
+        let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
+        let piece_ty = self.ecx.ty_path(self.ecx.path_all(
+                self.fmtsp,
+                true, ~[
+                    self.ecx.ident_of("std"),
+                    self.ecx.ident_of("fmt"),
+                    self.ecx.ident_of("rt"),
+                    self.ecx.ident_of("Piece"),
+                ],
+                Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))),
+                ~[]
+            ), None);
+        let ty = ast::ty_fixed_length_vec(
+            self.ecx.ty_mt(piece_ty.clone(), ast::MutImmutable),
+            self.ecx.expr_uint(self.fmtsp, self.pieces.len())
+        );
+        let ty = self.ecx.ty(self.fmtsp, ty);
+        let st = ast::item_static(ty, ast::MutImmutable, fmt);
+        let static_name = self.ecx.ident_of("__static_fmtstr");
+        // see above comment for `address_insignificant` and why we do it
+        let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
+        let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+        let item = self.ecx.item(self.fmtsp, static_name, ~[unnamed], st);
+        let decl = respan(self.fmtsp, ast::DeclItem(item));
+        lets.push(@respan(self.fmtsp, ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
+
+        // Right now there is a bug such that for the expression:
+        //      foo(bar(&1))
+        // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
+        // vald for the call to `foo`. To work around this all arguments to the
+        // fmt! string are shoved into locals. Furthermore, we shove the address
+        // of each variable because we don't want to move out of the arguments
+        // passed to this function.
+        for (i, &e) in self.args.iter().enumerate() {
+            if self.arg_types[i].is_none() { loop } // error already generated
+
+            let name = self.ecx.ident_of(fmt!("__arg%u", i));
+            let e = self.ecx.expr_addr_of(e.span, e);
+            lets.push(self.ecx.stmt_let(e.span, false, name, e));
+            locals.push(self.format_arg(e.span, Left(i),
+                                        self.ecx.expr_ident(e.span, name)));
+        }
+        for (&name, &e) in self.names.iter() {
+            if !self.name_types.contains_key(&name) { loop }
+
+            let lname = self.ecx.ident_of(fmt!("__arg%s", name));
+            let e = self.ecx.expr_addr_of(e.span, e);
+            lets.push(self.ecx.stmt_let(e.span, false, lname, e));
+            names[*self.name_positions.get(&name)] =
+                Some(self.format_arg(e.span, Right(name),
+                                     self.ecx.expr_ident(e.span, lname)));
+        }
+
+        // Now create the fmt::Arguments struct with all our locals we created.
+        let args = names.move_iter().map(|a| a.unwrap());
+        let mut args = locals.move_iter().chain(args);
+        let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
+        let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
+        let result = self.ecx.expr_call_global(self.fmtsp, ~[
+                self.ecx.ident_of("std"),
+                self.ecx.ident_of("fmt"),
+                self.ecx.ident_of("Arguments"),
+                self.ecx.ident_of("new"),
+            ], ~[fmt, args]);
+
+        // We did all the work of making sure that the arguments
+        // structure is safe, so we can safely have an unsafe block.
+        let result = self.ecx.expr_block(ast::Block {
+           view_items: ~[],
+           stmts: ~[],
+           expr: Some(result),
+           id: ast::DUMMY_NODE_ID,
+           rules: ast::UnsafeBlock(ast::CompilerGenerated),
+           span: self.fmtsp,
+        });
+        let resname = self.ecx.ident_of("__args");
+        lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
+        let res = self.ecx.expr_ident(self.fmtsp, resname);
+        let result = self.ecx.expr_call(extra.span, extra, ~[
+                            self.ecx.expr_addr_of(extra.span, res)]);
+        self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
+                                           Some(result)))
+    }
+
+    fn format_arg(&self, sp: Span, argno: Either<uint, @str>,
+                  arg: @ast::Expr) -> @ast::Expr {
+        let ty = match argno {
+            Left(i) => self.arg_types[i].unwrap(),
+            Right(s) => *self.name_types.get(&s)
+        };
+
+        let fmt_trait = match ty {
+            Unknown => "Default",
+            Known(tyname) => {
+                match tyname.as_slice() {
+                    "?" => "Poly",
+                    "b" => "Bool",
+                    "c" => "Char",
+                    "d" | "i" => "Signed",
+                    "f" => "Float",
+                    "o" => "Octal",
+                    "p" => "Pointer",
+                    "s" => "String",
+                    "t" => "Binary",
+                    "u" => "Unsigned",
+                    "x" => "LowerHex",
+                    "X" => "UpperHex",
+                    _ => {
+                        self.ecx.span_err(sp, fmt!("unknown format trait \
+                                                    `%s`", tyname));
+                        "Dummy"
+                    }
+                }
+            }
+            String => {
+                return self.ecx.expr_call_global(sp, ~[
+                        self.ecx.ident_of("std"),
+                        self.ecx.ident_of("fmt"),
+                        self.ecx.ident_of("argumentstr"),
+                    ], ~[arg])
+            }
+            Unsigned => {
+                return self.ecx.expr_call_global(sp, ~[
+                        self.ecx.ident_of("std"),
+                        self.ecx.ident_of("fmt"),
+                        self.ecx.ident_of("argumentuint"),
+                    ], ~[arg])
+            }
+        };
+
+        let format_fn = self.ecx.path_global(sp, ~[
+                self.ecx.ident_of("std"),
+                self.ecx.ident_of("fmt"),
+                self.ecx.ident_of(fmt_trait),
+                self.ecx.ident_of("fmt"),
+            ]);
+        self.ecx.expr_call_global(sp, ~[
+                self.ecx.ident_of("std"),
+                self.ecx.ident_of("fmt"),
+                self.ecx.ident_of("argument"),
+            ], ~[self.ecx.expr_path(format_fn), arg])
+    }
+}
+
+pub fn expand_args(ecx: @ExtCtxt, sp: Span,
+                   tts: &[ast::token_tree]) -> base::MacResult {
+    let mut cx = Context {
+        ecx: ecx,
+        args: ~[],
+        arg_types: ~[],
+        names: HashMap::new(),
+        name_positions: HashMap::new(),
+        name_types: HashMap::new(),
+        nest_level: 0,
+        next_arg: 0,
+        pieces: ~[],
+        method_statics: ~[],
+        fmtsp: sp,
+    };
+    let (extra, efmt) = match cx.parse_args(sp, 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,
+                          "format argument must be a string literal.");
+
+    let mut err = false;
+    do parse::parse_error::cond.trap(|m| {
+        if !err {
+            err = true;
+            ecx.span_err(efmt.span, m);
+        }
+    }).inside {
+        for piece in parse::Parser::new(fmt) {
+            if !err {
+                cx.verify_piece(&piece);
+                let piece = cx.trans_piece(&piece);
+                cx.pieces.push(piece);
+            }
+        }
+    }
+    if err { return MRExpr(efmt) }
+
+    // Make sure that all arguments were used and all arguments have types.
+    for (i, ty) in cx.arg_types.iter().enumerate() {
+        if ty.is_none() {
+            ecx.span_err(cx.args[i].span, "argument never used");
+        }
+    }
+    for (name, e) in cx.names.iter() {
+        if !cx.name_types.contains_key(name) {
+            ecx.span_err(e.span, "named argument never used");
+        }
+    }
+
+    MRExpr(cx.to_expr(extra))
+}
diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs
deleted file mode 100644 (file)
index b7722ff..0000000
+++ /dev/null
@@ -1,773 +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.
-
-use ast;
-use codemap::{Span, respan};
-use ext::base::*;
-use ext::base;
-use ext::build::AstBuilder;
-use rsparse = parse;
-use parse::token;
-
-use std::fmt::parse;
-use std::hashmap::{HashMap, HashSet};
-use std::vec;
-
-#[deriving(Eq)]
-enum ArgumentType {
-    Unknown,
-    Known(@str),
-    Unsigned,
-    String,
-}
-
-struct Context {
-    ecx: @ExtCtxt,
-    fmtsp: Span,
-
-    // Parsed argument expressions and the types that we've found so far for
-    // them.
-    args: ~[@ast::Expr],
-    arg_types: ~[Option<ArgumentType>],
-    // Parsed named expressions and the types that we've found for them so far
-    names: HashMap<@str, @ast::Expr>,
-    name_types: HashMap<@str, ArgumentType>,
-
-    // Collection of the compiled `rt::Piece` structures
-    pieces: ~[@ast::Expr],
-    name_positions: HashMap<@str, uint>,
-    method_statics: ~[@ast::item],
-
-    // Updated as arguments are consumed or methods are entered
-    nest_level: uint,
-    next_arg: uint,
-}
-
-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,
-                  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, "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 (extra, None);
-            }
-            if named || (token::is_ident(p.token) &&
-                         p.look_ahead(1, |t| *t == token::EQ)) {
-                named = true;
-                let ident = match *p.token {
-                    token::IDENT(i, _) => {
-                        p.bump();
-                        i
-                    }
-                    _ if named => {
-                        self.ecx.span_err(*p.span,
-                                          "expected ident, positional arguments \
-                                           cannot follow named arguments");
-                        return (extra, None);
-                    }
-                    _ => {
-                        self.ecx.span_err(*p.span,
-                                          fmt!("expected ident for named \
-                                                argument, but found `%s`",
-                                               p.this_token_to_str()));
-                        return (extra, None);
-                    }
-                };
-                let name = self.ecx.str_of(ident);
-                p.expect(&token::EQ);
-                let e = p.parse_expr();
-                match self.names.find(&name) {
-                    None => {}
-                    Some(prev) => {
-                        self.ecx.span_err(e.span, fmt!("duplicate argument \
-                                                        named `%s`", name));
-                        self.ecx.parse_sess.span_diagnostic.span_note(
-                            prev.span, "previously here");
-                        loop
-                    }
-                }
-                self.names.insert(name, e);
-            } else {
-                self.args.push(p.parse_expr());
-                self.arg_types.push(None);
-            }
-        }
-        return (extra, Some(fmtstr));
-    }
-
-    /// Verifies one piece of a parse string. All errors are not emitted as
-    /// fatal so we can continue giving errors about this and possibly other
-    /// format strings.
-    fn verify_piece(&mut self, p: &parse::Piece) {
-        match *p {
-            parse::String(*) => {}
-            parse::CurrentArgument => {
-                if self.nest_level == 0 {
-                    self.ecx.span_err(self.fmtsp,
-                                      "`#` reference used with nothing to \
-                                       reference back to");
-                }
-            }
-            parse::Argument(ref arg) => {
-                // width/precision first, if they have implicit positional
-                // parameters it makes more sense to consume them first.
-                self.verify_count(arg.format.width);
-                self.verify_count(arg.format.precision);
-
-                // argument second, if it's an implicit positional parameter
-                // it's written second, so it should come after width/precision.
-                let pos = match arg.position {
-                    parse::ArgumentNext => {
-                        let i = self.next_arg;
-                        if self.check_positional_ok() {
-                            self.next_arg += 1;
-                        }
-                        Left(i)
-                    }
-                    parse::ArgumentIs(i) => Left(i),
-                    parse::ArgumentNamed(s) => Right(s.to_managed()),
-                };
-                let ty = if arg.format.ty == "" {
-                    Unknown
-                } else { Known(arg.format.ty.to_managed()) };
-                self.verify_arg_type(pos, ty);
-
-                // and finally the method being applied
-                match arg.method {
-                    None => {}
-                    Some(ref method) => { self.verify_method(pos, *method); }
-                }
-            }
-        }
-    }
-
-    fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
-        for piece in pieces.iter() {
-            self.verify_piece(piece);
-        }
-    }
-
-    fn verify_count(&mut self, c: parse::Count) {
-        match c {
-            parse::CountImplied | parse::CountIs(*) => {}
-            parse::CountIsParam(i) => {
-                self.verify_arg_type(Left(i), Unsigned);
-            }
-            parse::CountIsNextParam => {
-                if self.check_positional_ok() {
-                    self.verify_arg_type(Left(self.next_arg), Unsigned);
-                    self.next_arg += 1;
-                }
-            }
-        }
-    }
-
-    fn check_positional_ok(&mut self) -> bool {
-        if self.nest_level != 0 {
-            self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
-                                           arguments nested inside methods");
-            false
-        } else {
-            true
-        }
-    }
-
-    fn verify_method(&mut self, pos: Either<uint, @str>, m: &parse::Method) {
-        self.nest_level += 1;
-        match *m {
-            parse::Plural(_, ref arms, ref default) => {
-                let mut seen_cases = HashSet::new();
-                self.verify_arg_type(pos, Unsigned);
-                for arm in arms.iter() {
-                    if !seen_cases.insert(arm.selector) {
-                        match arm.selector {
-                            Left(name) => {
-                                self.ecx.span_err(self.fmtsp,
-                                                  fmt!("duplicate selector \
-                                                       `%?`", name));
-                            }
-                            Right(idx) => {
-                                self.ecx.span_err(self.fmtsp,
-                                                  fmt!("duplicate selector \
-                                                       `=%u`", idx));
-                            }
-                        }
-                    }
-                    self.verify_pieces(arm.result);
-                }
-                self.verify_pieces(*default);
-            }
-            parse::Select(ref arms, ref default) => {
-                self.verify_arg_type(pos, String);
-                let mut seen_cases = HashSet::new();
-                for arm in arms.iter() {
-                    if !seen_cases.insert(arm.selector) {
-                        self.ecx.span_err(self.fmtsp,
-                                          fmt!("duplicate selector `%s`",
-                                               arm.selector));
-                    } else if arm.selector == "" {
-                        self.ecx.span_err(self.fmtsp,
-                                          "empty selector in `select`");
-                    }
-                    self.verify_pieces(arm.result);
-                }
-                self.verify_pieces(*default);
-            }
-        }
-        self.nest_level -= 1;
-    }
-
-    fn verify_arg_type(&mut self, arg: Either<uint, @str>, ty: ArgumentType) {
-        match arg {
-            Left(arg) => {
-                if arg < 0 || self.args.len() <= arg {
-                    let msg = fmt!("invalid reference to argument `%u` (there \
-                                    are %u arguments)", arg, self.args.len());
-                    self.ecx.span_err(self.fmtsp, msg);
-                    return;
-                }
-                self.verify_same(self.args[arg].span, ty, self.arg_types[arg]);
-                if ty != Unknown || self.arg_types[arg].is_none() {
-                    self.arg_types[arg] = Some(ty);
-                }
-            }
-
-            Right(name) => {
-                let span = match self.names.find(&name) {
-                    Some(e) => e.span,
-                    None => {
-                        let msg = fmt!("There is no argument named `%s`", name);
-                        self.ecx.span_err(self.fmtsp, msg);
-                        return;
-                    }
-                };
-                self.verify_same(span, ty,
-                                 self.name_types.find(&name).map(|&x| *x));
-                if ty != Unknown || !self.name_types.contains_key(&name) {
-                    self.name_types.insert(name, ty);
-                }
-                // Assign this named argument a slot in the arguments array if
-                // it hasn't already been assigned a slot.
-                if !self.name_positions.contains_key(&name) {
-                    let slot = self.name_positions.len();
-                    self.name_positions.insert(name, slot);
-                }
-            }
-        }
-    }
-
-    /// When we're keeping track of the types that are declared for certain
-    /// arguments, we assume that `None` means we haven't seen this argument
-    /// yet, `Some(None)` means that we've seen the argument, but no format was
-    /// specified, and `Some(Some(x))` means that the argument was declared to
-    /// have type `x`.
-    ///
-    /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
-    /// that: `Some(None) == Some(Some(x))`
-    fn verify_same(&self, sp: Span, ty: ArgumentType,
-                   before: Option<ArgumentType>) {
-        if ty == Unknown { return }
-        let cur = match before {
-            Some(Unknown) | None => return,
-            Some(t) => t,
-        };
-        if ty == cur { return }
-        match (cur, ty) {
-            (Known(cur), Known(ty)) => {
-                self.ecx.span_err(sp,
-                                  fmt!("argument redeclared with type `%s` when \
-                                        it was previously `%s`", ty, cur));
-            }
-            (Known(cur), _) => {
-                self.ecx.span_err(sp,
-                                  fmt!("argument used to format with `%s` was \
-                                        attempted to not be used for formatting",
-                                        cur));
-            }
-            (_, Known(ty)) => {
-                self.ecx.span_err(sp,
-                                  fmt!("argument previously used as a format \
-                                        argument attempted to be used as `%s`",
-                                        ty));
-            }
-            (_, _) => {
-                self.ecx.span_err(sp, "argument declared with multiple formats");
-            }
-        }
-    }
-
-    /// Translate a `parse::Piece` to a static `rt::Piece`
-    fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
-        let sp = self.fmtsp;
-        let parsepath = |s: &str| {
-            ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
-              self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
-        };
-        let rtpath = |s: &str| {
-            ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
-              self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
-        };
-        let ctpath = |s: &str| {
-            ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
-              self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
-        };
-        let none = || {
-            let p = self.ecx.path(sp, ~[self.ecx.ident_of("None")]);
-            self.ecx.expr_path(p)
-        };
-        let some = |e: @ast::Expr| {
-            self.ecx.expr_call_ident(sp, self.ecx.ident_of("Some"), ~[e])
-        };
-        let trans_count = |c: parse::Count| {
-            match c {
-                parse::CountIs(i) => {
-                    self.ecx.expr_call_global(sp, ctpath("CountIs"),
-                                              ~[self.ecx.expr_uint(sp, i)])
-                }
-                parse::CountIsParam(i) => {
-                    self.ecx.expr_call_global(sp, ctpath("CountIsParam"),
-                                              ~[self.ecx.expr_uint(sp, i)])
-                }
-                parse::CountImplied => {
-                    let path = self.ecx.path_global(sp, ctpath("CountImplied"));
-                    self.ecx.expr_path(path)
-                }
-                parse::CountIsNextParam => {
-                    let path = self.ecx.path_global(sp, ctpath("CountIsNextParam"));
-                    self.ecx.expr_path(path)
-                }
-            }
-        };
-        let trans_method = |method: &parse::Method| {
-            let method = match *method {
-                parse::Select(ref arms, ref default) => {
-                    let arms = arms.iter().map(|arm| {
-                        let p = self.ecx.path_global(sp, rtpath("SelectArm"));
-                        let result = arm.result.iter().map(|p| {
-                            self.trans_piece(p)
-                        }).collect();
-                        let s = arm.selector.to_managed();
-                        let selector = self.ecx.expr_str(sp, s);
-                        self.ecx.expr_struct(sp, p, ~[
-                            self.ecx.field_imm(sp,
-                                               self.ecx.ident_of("selector"),
-                                               selector),
-                            self.ecx.field_imm(sp, self.ecx.ident_of("result"),
-                                               self.ecx.expr_vec_slice(sp, result)),
-                        ])
-                    }).collect();
-                    let default = default.iter().map(|p| {
-                        self.trans_piece(p)
-                    }).collect();
-                    self.ecx.expr_call_global(sp, rtpath("Select"), ~[
-                        self.ecx.expr_vec_slice(sp, arms),
-                        self.ecx.expr_vec_slice(sp, default),
-                    ])
-                }
-                parse::Plural(offset, ref arms, ref default) => {
-                    let offset = match offset {
-                        Some(i) => { some(self.ecx.expr_uint(sp, i)) }
-                        None => { none() }
-                    };
-                    let arms = arms.iter().map(|arm| {
-                        let p = self.ecx.path_global(sp, rtpath("PluralArm"));
-                        let result = arm.result.iter().map(|p| {
-                            self.trans_piece(p)
-                        }).collect();
-                        let (lr, selarg) = match arm.selector {
-                            Left(t) => {
-                                let p = ctpath(fmt!("%?", t));
-                                let p = self.ecx.path_global(sp, p);
-                                (self.ecx.ident_of("Left"),
-                                 self.ecx.expr_path(p))
-                            }
-                            Right(i) => {
-                                (self.ecx.ident_of("Right"),
-                                 self.ecx.expr_uint(sp, i))
-                            }
-                        };
-                        let selector = self.ecx.expr_call_ident(sp,
-                                lr, ~[selarg]);
-                        self.ecx.expr_struct(sp, p, ~[
-                            self.ecx.field_imm(sp,
-                                               self.ecx.ident_of("selector"),
-                                               selector),
-                            self.ecx.field_imm(sp, self.ecx.ident_of("result"),
-                                               self.ecx.expr_vec_slice(sp, result)),
-                        ])
-                    }).collect();
-                    let default = default.iter().map(|p| {
-                        self.trans_piece(p)
-                    }).collect();
-                    self.ecx.expr_call_global(sp, rtpath("Plural"), ~[
-                        offset,
-                        self.ecx.expr_vec_slice(sp, arms),
-                        self.ecx.expr_vec_slice(sp, default),
-                    ])
-                }
-            };
-            let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
-            let ty = self.ecx.ty_path(self.ecx.path_all(
-                sp,
-                true,
-                rtpath("Method"),
-                Some(life),
-                ~[]
-            ), None);
-            let st = ast::item_static(ty, ast::MutImmutable, method);
-            let static_name = self.ecx.ident_of(fmt!("__static_method_%u",
-                                                     self.method_statics.len()));
-            // Flag these statics as `address_insignificant` so LLVM can
-            // merge duplicate globals as much as possible (which we're
-            // generating a whole lot of).
-            let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
-            let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
-            let item = self.ecx.item(sp, static_name, ~[unnamed], st);
-            self.method_statics.push(item);
-            self.ecx.expr_ident(sp, static_name)
-        };
-
-        match *piece {
-            parse::String(s) => {
-                self.ecx.expr_call_global(sp, rtpath("String"),
-                                          ~[self.ecx.expr_str(sp, s.to_managed())])
-            }
-            parse::CurrentArgument => {
-                let nil = self.ecx.expr_lit(sp, ast::lit_nil);
-                self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil])
-            }
-            parse::Argument(ref arg) => {
-                // Translate the position
-                let pos = match arg.position {
-                    // These two have a direct mapping
-                    parse::ArgumentNext => {
-                        let path = self.ecx.path_global(sp,
-                                                        rtpath("ArgumentNext"));
-                        self.ecx.expr_path(path)
-                    }
-                    parse::ArgumentIs(i) => {
-                        self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
-                                                  ~[self.ecx.expr_uint(sp, i)])
-                    }
-                    // Named arguments are converted to positional arguments at
-                    // the end of the list of arguments
-                    parse::ArgumentNamed(n) => {
-                        let n = n.to_managed();
-                        let i = match self.name_positions.find_copy(&n) {
-                            Some(i) => i,
-                            None => 0, // error already emitted elsewhere
-                        };
-                        let i = i + self.args.len();
-                        self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
-                                                  ~[self.ecx.expr_uint(sp, i)])
-                    }
-                };
-
-                // Translate the format
-                let fill = match arg.format.fill { Some(c) => c, None => ' ' };
-                let fill = self.ecx.expr_lit(sp, ast::lit_char(fill as u32));
-                let align = match arg.format.align {
-                    parse::AlignLeft => {
-                        self.ecx.path_global(sp, parsepath("AlignLeft"))
-                    }
-                    parse::AlignRight => {
-                        self.ecx.path_global(sp, parsepath("AlignRight"))
-                    }
-                    parse::AlignUnknown => {
-                        self.ecx.path_global(sp, parsepath("AlignUnknown"))
-                    }
-                };
-                let align = self.ecx.expr_path(align);
-                let flags = self.ecx.expr_uint(sp, arg.format.flags);
-                let prec = trans_count(arg.format.precision);
-                let width = trans_count(arg.format.width);
-                let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
-                let fmt = self.ecx.expr_struct(sp, path, ~[
-                    self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
-                ]);
-
-                // Translate the method (if any)
-                let method = match arg.method {
-                    None => { none() }
-                    Some(ref m) => {
-                        let m = trans_method(*m);
-                        some(self.ecx.expr_addr_of(sp, m))
-                    }
-                };
-                let path = self.ecx.path_global(sp, rtpath("Argument"));
-                let s = self.ecx.expr_struct(sp, path, ~[
-                    self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("method"), method),
-                ]);
-                self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s])
-            }
-        }
-    }
-
-    /// Actually builds the expression which the ifmt! block will be expanded
-    /// to
-    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);
-
-        // First, declare all of our methods that are statics
-        for &method in self.method_statics.iter() {
-            let decl = respan(self.fmtsp, ast::DeclItem(method));
-            lets.push(@respan(self.fmtsp,
-                              ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
-        }
-
-        // Next, build up the static array which will become our precompiled
-        // format "string"
-        let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
-        let ty = ast::ty_fixed_length_vec(
-            self.ecx.ty_mt(
-                self.ecx.ty_path(self.ecx.path_all(
-                    self.fmtsp,
-                    true, ~[
-                        self.ecx.ident_of("std"),
-                        self.ecx.ident_of("fmt"),
-                        self.ecx.ident_of("rt"),
-                        self.ecx.ident_of("Piece"),
-                    ],
-                    Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))),
-                    ~[]
-                ), None),
-                ast::MutImmutable
-            ),
-            self.ecx.expr_uint(self.fmtsp, self.pieces.len())
-        );
-        let ty = self.ecx.ty(self.fmtsp, ty);
-        let st = ast::item_static(ty, ast::MutImmutable, fmt);
-        let static_name = self.ecx.ident_of("__static_fmtstr");
-        // see above comment for `address_insignificant` and why we do it
-        let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
-        let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
-        let item = self.ecx.item(self.fmtsp, static_name, ~[unnamed], st);
-        let decl = respan(self.fmtsp, ast::DeclItem(item));
-        lets.push(@respan(self.fmtsp, ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
-
-        // Right now there is a bug such that for the expression:
-        //      foo(bar(&1))
-        // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
-        // vald for the call to `foo`. To work around this all arguments to the
-        // fmt! string are shoved into locals. Furthermore, we shove the address
-        // of each variable because we don't want to move out of the arguments
-        // passed to this function.
-        for (i, &e) in self.args.iter().enumerate() {
-            if self.arg_types[i].is_none() { loop } // error already generated
-
-            let name = self.ecx.ident_of(fmt!("__arg%u", i));
-            let e = self.ecx.expr_addr_of(e.span, e);
-            lets.push(self.ecx.stmt_let(e.span, false, name, e));
-            locals.push(self.format_arg(e.span, Left(i), name));
-        }
-        for (&name, &e) in self.names.iter() {
-            if !self.name_types.contains_key(&name) { loop }
-
-            let lname = self.ecx.ident_of(fmt!("__arg%s", name));
-            let e = self.ecx.expr_addr_of(e.span, e);
-            lets.push(self.ecx.stmt_let(e.span, false, lname, e));
-            names[*self.name_positions.get(&name)] =
-                Some(self.format_arg(e.span, Right(name), lname));
-        }
-
-        let args = names.move_iter().map(|a| a.unwrap());
-        let mut args = locals.move_iter().chain(args);
-
-        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(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
-        // user.
-        let result = self.ecx.expr_block(ast::Block {
-           view_items: ~[],
-           stmts: ~[],
-           expr: Some(result),
-           id: ast::DUMMY_NODE_ID,
-           rules: ast::UnsafeBlock,
-           span: self.fmtsp,
-        });
-
-        self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, Some(result)))
-    }
-
-    fn format_arg(&self, sp: Span, arg: Either<uint, @str>,
-                  ident: ast::Ident) -> @ast::Expr {
-        let ty = match arg {
-            Left(i) => self.arg_types[i].unwrap(),
-            Right(s) => *self.name_types.get(&s)
-        };
-
-        let argptr = self.ecx.expr_ident(sp, ident);
-        let fmt_trait = match ty {
-            Unknown => "Default",
-            Known(tyname) => {
-                match tyname.as_slice() {
-                    "?" => "Poly",
-                    "b" => "Bool",
-                    "c" => "Char",
-                    "d" | "i" => "Signed",
-                    "f" => "Float",
-                    "o" => "Octal",
-                    "p" => "Pointer",
-                    "s" => "String",
-                    "t" => "Binary",
-                    "u" => "Unsigned",
-                    "x" => "LowerHex",
-                    "X" => "UpperHex",
-                    _ => {
-                        self.ecx.span_err(sp, fmt!("unknown format trait \
-                                                    `%s`", tyname));
-                        "Dummy"
-                    }
-                }
-            }
-            String => {
-                return self.ecx.expr_call_global(sp, ~[
-                        self.ecx.ident_of("std"),
-                        self.ecx.ident_of("fmt"),
-                        self.ecx.ident_of("argumentstr"),
-                    ], ~[argptr])
-            }
-            Unsigned => {
-                return self.ecx.expr_call_global(sp, ~[
-                        self.ecx.ident_of("std"),
-                        self.ecx.ident_of("fmt"),
-                        self.ecx.ident_of("argumentuint"),
-                    ], ~[argptr])
-            }
-        };
-
-        let format_fn = self.ecx.path_global(sp, ~[
-                self.ecx.ident_of("std"),
-                self.ecx.ident_of("fmt"),
-                self.ecx.ident_of(fmt_trait),
-                self.ecx.ident_of("fmt"),
-            ]);
-        self.ecx.expr_call_global(sp, ~[
-                self.ecx.ident_of("std"),
-                self.ecx.ident_of("fmt"),
-                self.ecx.ident_of("argument"),
-            ], ~[self.ecx.expr_path(format_fn), argptr])
-    }
-}
-
-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: ~[],
-        arg_types: ~[],
-        names: HashMap::new(),
-        name_positions: HashMap::new(),
-        name_types: HashMap::new(),
-        nest_level: 0,
-        next_arg: 0,
-        pieces: ~[],
-        method_statics: ~[],
-        fmtsp: sp,
-    };
-    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,
-                          "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| {
-        if !err {
-            err = true;
-            ecx.span_err(efmt.span, m);
-        }
-    }).inside {
-        for piece in parse::Parser::new(fmt) {
-            if !err {
-                cx.verify_piece(&piece);
-                let piece = cx.trans_piece(&piece);
-                cx.pieces.push(piece);
-            }
-        }
-    }
-    if err { return MRExpr(efmt) }
-
-    // Make sure that all arguments were used and all arguments have types.
-    for (i, ty) in cx.arg_types.iter().enumerate() {
-        if ty.is_none() {
-            ecx.span_err(cx.args[i].span, "argument never used");
-        }
-    }
-    for (name, e) in cx.names.iter() {
-        if !cx.name_types.contains_key(name) {
-            ecx.span_err(e.span, "named argument never used");
-        }
-    }
-
-    MRExpr(cx.to_expr(extra, function))
-}
index c861c26b82eb3e057958434820cdceab28b41128..5472c61a155a8b89114ebb21afde3cd039dd00c7 100644 (file)
@@ -690,11 +690,19 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
         ExprBreak(ref opt_ident) => {
             // FIXME #6993: add fold_name to fold.... then cut out the
             // bogus Name->Ident->Name conversion.
-            ExprBreak(opt_ident.map_move(|x| fld.fold_ident(Ident::new(x)).name))
+            ExprBreak(opt_ident.map_move(|x| {
+                // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug
+                let newx = Ident::new(x);
+                fld.fold_ident(newx).name
+            }))
         }
         ExprAgain(ref opt_ident) => {
             // FIXME #6993: add fold_name to fold....
-            ExprAgain(opt_ident.map_move(|x| fld.fold_ident(Ident::new(x)).name))
+            ExprAgain(opt_ident.map_move(|x| {
+                // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug
+                let newx = Ident::new(x);
+                fld.fold_ident(newx).name
+            }))
         }
         ExprRet(ref e) => {
             ExprRet(e.map_move(|x| fld.fold_expr(x)))
diff --git a/src/libsyntax/oldvisit.rs b/src/libsyntax/oldvisit.rs
deleted file mode 100644 (file)
index 80e037b..0000000
+++ /dev/null
@@ -1,779 +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.
-
-use abi::AbiSet;
-use ast::*;
-use ast;
-use codemap::Span;
-use parse;
-use opt_vec;
-use opt_vec::OptVec;
-
-// Context-passing AST walker. Each overridden visit method has full control
-// over what happens with its node, it can do its own traversal of the node's
-// children (potentially passing in different contexts to each), call
-// visit::visit_* to apply the default traversal algorithm (again, it can
-// override the context), or prevent deeper traversal by doing nothing.
-//
-// Note: it is an important invariant that the default visitor walks the body
-// of a function in "execution order" (more concretely, reverse post-order
-// with respect to the CFG implied by the AST), meaning that if AST node A may
-// execute before AST node B, then A is visited first.  The borrow checker in
-// particular relies on this property.
-
-// Our typesystem doesn't do circular types, so the visitor record can not
-// hold functions that take visitors. A vt enum is used to break the cycle.
-pub enum vt<E> { mk_vt(visitor<E>), }
-
-pub enum fn_kind<'self> {
-    // fn foo() or extern "Abi" fn foo()
-    fk_item_fn(Ident, &'self Generics, purity, AbiSet),
-
-    // fn foo(&self)
-    fk_method(Ident, &'self Generics, &'self method),
-
-    // @fn(x, y) { ... }
-    fk_anon(ast::Sigil),
-
-    // |x, y| ...
-    fk_fn_block,
-}
-
-pub fn name_of_fn(fk: &fn_kind) -> Ident {
-    match *fk {
-      fk_item_fn(name, _, _, _) | fk_method(name, _, _) => {
-          name
-      }
-      fk_anon(*) | fk_fn_block(*) => parse::token::special_idents::anon,
-    }
-}
-
-pub fn generics_of_fn(fk: &fn_kind) -> Generics {
-    match *fk {
-        fk_item_fn(_, generics, _, _) |
-        fk_method(_, generics, _) => {
-            (*generics).clone()
-        }
-        fk_anon(*) | fk_fn_block(*) => {
-            Generics {
-                lifetimes: opt_vec::Empty,
-                ty_params: opt_vec::Empty,
-            }
-        }
-    }
-}
-
-pub struct Visitor<E> {
-    visit_mod: @fn(&_mod, Span, NodeId, (E, vt<E>)),
-    visit_view_item: @fn(&view_item, (E, vt<E>)),
-    visit_foreign_item: @fn(@foreign_item, (E, vt<E>)),
-    visit_item: @fn(@item, (E, vt<E>)),
-    visit_local: @fn(@Local, (E, vt<E>)),
-    visit_block: @fn(&Block, (E, vt<E>)),
-    visit_stmt: @fn(@Stmt, (E, vt<E>)),
-    visit_arm: @fn(&Arm, (E, vt<E>)),
-    visit_pat: @fn(@Pat, (E, vt<E>)),
-    visit_decl: @fn(@Decl, (E, vt<E>)),
-    visit_expr: @fn(@Expr, (E, vt<E>)),
-    visit_expr_post: @fn(@Expr, (E, vt<E>)),
-    visit_ty: @fn(&Ty, (E, vt<E>)),
-    visit_generics: @fn(&Generics, (E, vt<E>)),
-    visit_fn: @fn(&fn_kind, &fn_decl, &Block, Span, NodeId, (E, vt<E>)),
-    visit_ty_method: @fn(&TypeMethod, (E, vt<E>)),
-    visit_trait_method: @fn(&trait_method, (E, vt<E>)),
-    visit_struct_def: @fn(@struct_def, Ident, &Generics, NodeId, (E, vt<E>)),
-    visit_struct_field: @fn(@struct_field, (E, vt<E>)),
-}
-
-pub type visitor<E> = @Visitor<E>;
-
-pub fn default_visitor<E:Clone>() -> visitor<E> {
-    return @Visitor {
-        visit_mod: |a,b,c,d|visit_mod::<E>(a, b, c, d),
-        visit_view_item: |a,b|visit_view_item::<E>(a, b),
-        visit_foreign_item: |a,b|visit_foreign_item::<E>(a, b),
-        visit_item: |a,b|visit_item::<E>(a, b),
-        visit_local: |a,b|visit_local::<E>(a, b),
-        visit_block: |a,b|visit_block::<E>(a, b),
-        visit_stmt: |a,b|visit_stmt::<E>(a, b),
-        visit_arm: |a,b|visit_arm::<E>(a, b),
-        visit_pat: |a,b|visit_pat::<E>(a, b),
-        visit_decl: |a,b|visit_decl::<E>(a, b),
-        visit_expr: |a,b|visit_expr::<E>(a, b),
-        visit_expr_post: |_a,_b| (),
-        visit_ty: |a,b|skip_ty::<E>(a, b),
-        visit_generics: |a,b|visit_generics::<E>(a, b),
-        visit_fn: |a,b,c,d,e,f|visit_fn::<E>(a, b, c, d, e, f),
-        visit_ty_method: |a,b|visit_ty_method::<E>(a, b),
-        visit_trait_method: |a,b|visit_trait_method::<E>(a, b),
-        visit_struct_def: |a,b,c,d,e|visit_struct_def::<E>(a, b, c, d, e),
-        visit_struct_field: |a,b|visit_struct_field::<E>(a, b),
-    };
-}
-
-pub fn visit_crate<E:Clone>(c: &Crate, (e, v): (E, vt<E>)) {
-    (v.visit_mod)(&c.module, c.span, CRATE_NODE_ID, (e, v));
-}
-
-pub fn visit_mod<E:Clone>(m: &_mod,
-                          _sp: Span,
-                          _id: NodeId,
-                          (e, v): (E, vt<E>)) {
-    for vi in m.view_items.iter() {
-        (v.visit_view_item)(vi, (e.clone(), v));
-    }
-    for i in m.items.iter() {
-        (v.visit_item)(*i, (e.clone(), v));
-    }
-}
-
-pub fn visit_view_item<E>(_vi: &view_item, (_e, _v): (E, vt<E>)) { }
-
-pub fn visit_local<E:Clone>(loc: &Local, (e, v): (E, vt<E>)) {
-    (v.visit_pat)(loc.pat, (e.clone(), v));
-    (v.visit_ty)(&loc.ty, (e.clone(), v));
-    match loc.init {
-      None => (),
-      Some(ex) => (v.visit_expr)(ex, (e, v))
-    }
-}
-
-fn visit_trait_ref<E:Clone>(tref: &ast::trait_ref, (e, v): (E, vt<E>)) {
-    visit_path(&tref.path, (e, v));
-}
-
-pub fn visit_item<E:Clone>(i: &item, (e, v): (E, vt<E>)) {
-    match i.node {
-        item_static(ref t, _, ex) => {
-            (v.visit_ty)(t, (e.clone(), v));
-            (v.visit_expr)(ex, (e.clone(), v));
-        }
-        item_fn(ref decl, purity, abi, ref generics, ref body) => {
-            (v.visit_fn)(
-                &fk_item_fn(
-                    i.ident,
-                    generics,
-                    purity,
-                    abi
-                ),
-                decl,
-                body,
-                i.span,
-                i.id,
-                (e,
-                 v)
-            );
-        }
-        item_mod(ref m) => (v.visit_mod)(m, i.span, i.id, (e, v)),
-        item_foreign_mod(ref nm) => {
-            for vi in nm.view_items.iter() {
-                (v.visit_view_item)(vi, (e.clone(), v));
-            }
-            for ni in nm.items.iter() {
-                (v.visit_foreign_item)(*ni, (e.clone(), v));
-            }
-        }
-        item_ty(ref t, ref tps) => {
-            (v.visit_ty)(t, (e.clone(), v));
-            (v.visit_generics)(tps, (e, v));
-        }
-        item_enum(ref enum_definition, ref tps) => {
-            (v.visit_generics)(tps, (e.clone(), v));
-            visit_enum_def(
-                enum_definition,
-                tps,
-                (e, v)
-            );
-        }
-        item_impl(ref tps, ref traits, ref ty, ref methods) => {
-            (v.visit_generics)(tps, (e.clone(), v));
-            for p in traits.iter() {
-                visit_trait_ref(p, (e.clone(), v));
-            }
-            (v.visit_ty)(ty, (e.clone(), v));
-            for m in methods.iter() {
-                visit_method_helper(*m, (e.clone(), v))
-            }
-        }
-        item_struct(struct_def, ref generics) => {
-            (v.visit_generics)(generics, (e.clone(), v));
-            (v.visit_struct_def)(struct_def, i.ident, generics, i.id, (e, v));
-        }
-        item_trait(ref generics, ref traits, ref methods) => {
-            (v.visit_generics)(generics, (e.clone(), v));
-            for p in traits.iter() {
-                visit_path(&p.path, (e.clone(), v));
-            }
-            for m in methods.iter() {
-                (v.visit_trait_method)(m, (e.clone(), v));
-            }
-        }
-        item_mac(ref m) => visit_mac(m, (e, v))
-    }
-}
-
-pub fn visit_enum_def<E:Clone>(enum_definition: &ast::enum_def,
-                               tps: &Generics,
-                               (e, v): (E, vt<E>)) {
-    for vr in enum_definition.variants.iter() {
-        match vr.node.kind {
-            tuple_variant_kind(ref variant_args) => {
-                for va in variant_args.iter() {
-                    (v.visit_ty)(&va.ty, (e.clone(), v));
-                }
-            }
-            struct_variant_kind(struct_def) => {
-                (v.visit_struct_def)(struct_def, vr.node.name, tps,
-                                     vr.node.id, (e.clone(), v));
-            }
-        }
-        // Visit the disr expr if it exists
-        for ex in vr.node.disr_expr.iter() {
-            (v.visit_expr)(*ex, (e.clone(), v))
-        }
-    }
-}
-
-pub fn skip_ty<E>(_t: &Ty, (_e,_v): (E, vt<E>)) {}
-
-pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
-    match t.node {
-        ty_box(ref mt) | ty_uniq(ref mt) |
-        ty_vec(ref mt) | ty_ptr(ref mt) | ty_rptr(_, ref mt) => {
-            (v.visit_ty)(mt.ty, (e, v));
-        },
-        ty_tup(ref ts) => {
-            for tt in ts.iter() {
-                (v.visit_ty)(tt, (e.clone(), v));
-            }
-        },
-        ty_closure(ref f) => {
-            for a in f.decl.inputs.iter() {
-                (v.visit_ty)(&a.ty, (e.clone(), v));
-            }
-            (v.visit_ty)(&f.decl.output, (e.clone(), v));
-            do f.bounds.map |bounds| {
-                visit_ty_param_bounds(bounds, (e.clone(), v));
-            };
-        },
-        ty_bare_fn(ref f) => {
-            for a in f.decl.inputs.iter() {
-                (v.visit_ty)(&a.ty, (e.clone(), v));
-            }
-            (v.visit_ty)(&f.decl.output, (e, v));
-        },
-        ty_path(ref p, ref bounds, _) => {
-            visit_path(p, (e.clone(), v));
-            do bounds.map |bounds| {
-                visit_ty_param_bounds(bounds, (e.clone(), v));
-            };
-        },
-        ty_fixed_length_vec(ref mt, ex) => {
-            (v.visit_ty)(mt.ty, (e.clone(), v));
-            (v.visit_expr)(ex, (e.clone(), v));
-        },
-        ty_typeof(ex) => {
-            (v.visit_expr)(ex, (e.clone(), v));
-        }
-        ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
-    }
-}
-
-pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
-    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>)) {
-    match p.node {
-        PatEnum(ref path, ref children) => {
-            visit_path(path, (e.clone(), v));
-            for children in children.iter() {
-                for child in children.iter() {
-                    (v.visit_pat)(*child, (e.clone(), v));
-                }
-            }
-        }
-        PatStruct(ref path, ref fields, _) => {
-            visit_path(path, (e.clone(), v));
-            for f in fields.iter() {
-                (v.visit_pat)(f.pat, (e.clone(), v));
-            }
-        }
-        PatTup(ref elts) => {
-            for elt in elts.iter() {
-                (v.visit_pat)(*elt, (e.clone(), v))
-            }
-        },
-        PatBox(inner) | PatUniq(inner) | PatRegion(inner) => {
-            (v.visit_pat)(inner, (e, v))
-        },
-        PatIdent(_, ref path, ref inner) => {
-            visit_path(path, (e.clone(), v));
-            for subpat in inner.iter() {
-                (v.visit_pat)(*subpat, (e.clone(), v))
-            }
-        }
-        PatLit(ex) => (v.visit_expr)(ex, (e, v)),
-        PatRange(e1, e2) => {
-            (v.visit_expr)(e1, (e.clone(), v));
-            (v.visit_expr)(e2, (e, v));
-        }
-        PatWild => (),
-        PatVec(ref before, ref slice, ref after) => {
-            for elt in before.iter() {
-                (v.visit_pat)(*elt, (e.clone(), v));
-            }
-            for elt in slice.iter() {
-                (v.visit_pat)(*elt, (e.clone(), v));
-            }
-            for tail in after.iter() {
-                (v.visit_pat)(*tail, (e.clone(), v));
-            }
-        }
-    }
-}
-
-pub fn visit_foreign_item<E:Clone>(ni: &foreign_item, (e, v): (E, vt<E>)) {
-    match ni.node {
-        foreign_item_fn(ref fd, ref generics) => {
-            visit_fn_decl(fd, (e.clone(), v));
-            (v.visit_generics)(generics, (e, v));
-        }
-        foreign_item_static(ref t, _) => {
-            (v.visit_ty)(t, (e, v));
-        }
-    }
-}
-
-pub fn visit_ty_param_bounds<E:Clone>(bounds: &OptVec<TyParamBound>,
-                                      (e, v): (E, vt<E>)) {
-    for bound in bounds.iter() {
-        match *bound {
-            TraitTyParamBound(ref ty) => visit_trait_ref(ty, (e.clone(), v)),
-            RegionTyParamBound => {}
-        }
-    }
-}
-
-pub fn visit_generics<E:Clone>(generics: &Generics, (e, v): (E, vt<E>)) {
-    for tp in generics.ty_params.iter() {
-        visit_ty_param_bounds(&tp.bounds, (e.clone(), v));
-    }
-}
-
-pub fn visit_fn_decl<E:Clone>(fd: &fn_decl, (e, v): (E, vt<E>)) {
-    for a in fd.inputs.iter() {
-        (v.visit_pat)(a.pat, (e.clone(), v));
-        (v.visit_ty)(&a.ty, (e.clone(), v));
-    }
-    (v.visit_ty)(&fd.output, (e, v));
-}
-
-// Note: there is no visit_method() method in the visitor, instead override
-// visit_fn() and check for fk_method().  I named this visit_method_helper()
-// because it is not a default impl of any method, though I doubt that really
-// clarifies anything. - Niko
-pub fn visit_method_helper<E:Clone>(m: &method, (e, v): (E, vt<E>)) {
-    (v.visit_fn)(&fk_method(m.ident, &m.generics, m),
-                 &m.decl,
-                 &m.body,
-                 m.span,
-                 m.id,
-                 (e, v));
-}
-
-pub fn visit_fn<E:Clone>(fk: &fn_kind,
-                         decl: &fn_decl,
-                         body: &Block,
-                         _sp: Span,
-                         _id: NodeId,
-                         (e, v): (E, vt<E>)) {
-    visit_fn_decl(decl, (e.clone(), v));
-    let generics = generics_of_fn(fk);
-    (v.visit_generics)(&generics, (e.clone(), v));
-    (v.visit_block)(body, (e, v));
-}
-
-pub fn visit_ty_method<E:Clone>(m: &TypeMethod, (e, v): (E, vt<E>)) {
-    for a in m.decl.inputs.iter() {
-        (v.visit_ty)(&a.ty, (e.clone(), v));
-    }
-    (v.visit_generics)(&m.generics, (e.clone(), v));
-    (v.visit_ty)(&m.decl.output, (e, v));
-}
-
-pub fn visit_trait_method<E:Clone>(m: &trait_method, (e, v): (E, vt<E>)) {
-    match *m {
-      required(ref ty_m) => (v.visit_ty_method)(ty_m, (e, v)),
-      provided(m) => visit_method_helper(m, (e, v))
-    }
-}
-
-pub fn visit_struct_def<E:Clone>(
-    sd: @struct_def,
-    _nm: ast::Ident,
-    _generics: &Generics,
-    _id: NodeId,
-    (e, v): (E, vt<E>)
-) {
-    for f in sd.fields.iter() {
-        (v.visit_struct_field)(*f, (e.clone(), v));
-    }
-}
-
-pub fn visit_struct_field<E:Clone>(sf: &struct_field, (e, v): (E, vt<E>)) {
-    (v.visit_ty)(&sf.node.ty, (e, v));
-}
-
-pub fn visit_block<E:Clone>(b: &Block, (e, v): (E, vt<E>)) {
-    for vi in b.view_items.iter() {
-        (v.visit_view_item)(vi, (e.clone(), v));
-    }
-    for s in b.stmts.iter() {
-        (v.visit_stmt)(*s, (e.clone(), v));
-    }
-    visit_expr_opt(b.expr, (e, v));
-}
-
-pub fn visit_stmt<E>(s: &Stmt, (e, v): (E, vt<E>)) {
-    match s.node {
-      StmtDecl(d, _) => (v.visit_decl)(d, (e, v)),
-      StmtExpr(ex, _) => (v.visit_expr)(ex, (e, v)),
-      StmtSemi(ex, _) => (v.visit_expr)(ex, (e, v)),
-      StmtMac(ref mac, _) => visit_mac(mac, (e, v))
-    }
-}
-
-pub fn visit_decl<E:Clone>(d: &Decl, (e, v): (E, vt<E>)) {
-    match d.node {
-        DeclLocal(ref loc) => (v.visit_local)(*loc, (e, v)),
-        DeclItem(it) => (v.visit_item)(it, (e, v))
-    }
-}
-
-pub fn visit_expr_opt<E>(eo: Option<@Expr>, (e, v): (E, vt<E>)) {
-    match eo { None => (), Some(ex) => (v.visit_expr)(ex, (e, v)) }
-}
-
-pub fn visit_exprs<E:Clone>(exprs: &[@Expr], (e, v): (E, vt<E>)) {
-    for ex in exprs.iter() { (v.visit_expr)(*ex, (e.clone(), v)); }
-}
-
-pub fn visit_mac<E>(_m: &mac, (_e, _v): (E, vt<E>)) {
-    /* no user-serviceable parts inside */
-}
-
-pub fn visit_expr<E:Clone>(ex: @Expr, (e, v): (E, vt<E>)) {
-    match ex.node {
-        ExprVstore(x, _) => (v.visit_expr)(x, (e.clone(), v)),
-        ExprVec(ref es, _) => visit_exprs(*es, (e.clone(), v)),
-        ExprRepeat(element, count, _) => {
-            (v.visit_expr)(element, (e.clone(), v));
-            (v.visit_expr)(count, (e.clone(), v));
-        }
-        ExprStruct(ref p, ref flds, base) => {
-            visit_path(p, (e.clone(), v));
-            for f in flds.iter() {
-                (v.visit_expr)(f.expr, (e.clone(), v));
-            }
-            visit_expr_opt(base, (e.clone(), v));
-        }
-        ExprTup(ref elts) => {
-            for el in elts.iter() { (v.visit_expr)(*el, (e.clone(), v)) }
-        }
-        ExprCall(callee, ref args, _) => {
-            visit_exprs(*args, (e.clone(), v));
-            (v.visit_expr)(callee, (e.clone(), v));
-        }
-        ExprMethodCall(_, callee, _, ref tys, ref args, _) => {
-            visit_exprs(*args, (e.clone(), v));
-            for tp in tys.iter() {
-                (v.visit_ty)(tp, (e.clone(), v));
-            }
-            (v.visit_expr)(callee, (e.clone(), v));
-        }
-        ExprBinary(_, _, a, b) => {
-            (v.visit_expr)(a, (e.clone(), v));
-            (v.visit_expr)(b, (e.clone(), v));
-        }
-        ExprAddrOf(_, x) | ExprUnary(_, _, x) |
-        ExprDoBody(x) => (v.visit_expr)(x, (e.clone(), v)),
-        ExprLit(_) => (),
-        ExprCast(x, ref t) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            (v.visit_ty)(t, (e.clone(), v));
-        }
-        ExprIf(x, ref b, eo) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            (v.visit_block)(b, (e.clone(), v));
-            visit_expr_opt(eo, (e.clone(), v));
-        }
-        ExprWhile(x, ref b) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            (v.visit_block)(b, (e.clone(), v));
-        }
-        ExprForLoop(pattern, subexpression, ref block, _) => {
-            (v.visit_pat)(pattern, (e.clone(), v));
-            (v.visit_expr)(subexpression, (e.clone(), v));
-            (v.visit_block)(block, (e.clone(), v))
-        }
-        ExprLoop(ref b, _) => (v.visit_block)(b, (e.clone(), v)),
-        ExprMatch(x, ref arms) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            for a in arms.iter() { (v.visit_arm)(a, (e.clone(), v)); }
-        }
-        ExprFnBlock(ref decl, ref body) => {
-            (v.visit_fn)(
-                &fk_fn_block,
-                decl,
-                body,
-                ex.span,
-                ex.id,
-                (e.clone(), v)
-            );
-        }
-        ExprBlock(ref b) => (v.visit_block)(b, (e.clone(), v)),
-        ExprAssign(a, b) => {
-            (v.visit_expr)(b, (e.clone(), v));
-            (v.visit_expr)(a, (e.clone(), v));
-        }
-        ExprAssignOp(_, _, a, b) => {
-            (v.visit_expr)(b, (e.clone(), v));
-            (v.visit_expr)(a, (e.clone(), v));
-        }
-        ExprField(x, _, ref tys) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            for tp in tys.iter() {
-                (v.visit_ty)(tp, (e.clone(), v));
-            }
-        }
-        ExprIndex(_, a, b) => {
-            (v.visit_expr)(a, (e.clone(), v));
-            (v.visit_expr)(b, (e.clone(), v));
-        }
-        ExprPath(ref p) => visit_path(p, (e.clone(), v)),
-        ExprSelf => (),
-        ExprBreak(_) => (),
-        ExprAgain(_) => (),
-        ExprRet(eo) => visit_expr_opt(eo, (e.clone(), v)),
-        ExprLogLevel => (),
-        ExprMac(ref mac) => visit_mac(mac, (e.clone(), v)),
-        ExprParen(x) => (v.visit_expr)(x, (e.clone(), v)),
-        ExprInlineAsm(ref a) => {
-            for &(_, input) in a.inputs.iter() {
-                (v.visit_expr)(input, (e.clone(), v));
-            }
-            for &(_, out) in a.outputs.iter() {
-                (v.visit_expr)(out, (e.clone(), v));
-            }
-        }
-    }
-    (v.visit_expr_post)(ex, (e, v));
-}
-
-pub fn visit_arm<E:Clone>(a: &Arm, (e, v): (E, vt<E>)) {
-    for p in a.pats.iter() { (v.visit_pat)(*p, (e.clone(), v)); }
-    visit_expr_opt(a.guard, (e.clone(), v));
-    (v.visit_block)(&a.body, (e.clone(), v));
-}
-
-// Simpler, non-context passing interface. Always walks the whole tree, simply
-// calls the given functions on the nodes.
-
-pub struct SimpleVisitor {
-    visit_mod: @fn(&_mod, Span, NodeId),
-    visit_view_item: @fn(&view_item),
-    visit_foreign_item: @fn(@foreign_item),
-    visit_item: @fn(@item),
-    visit_local: @fn(@Local),
-    visit_block: @fn(&Block),
-    visit_stmt: @fn(@Stmt),
-    visit_arm: @fn(&Arm),
-    visit_pat: @fn(@Pat),
-    visit_decl: @fn(@Decl),
-    visit_expr: @fn(@Expr),
-    visit_expr_post: @fn(@Expr),
-    visit_ty: @fn(&Ty),
-    visit_generics: @fn(&Generics),
-    visit_fn: @fn(&fn_kind, &fn_decl, &Block, Span, NodeId),
-    visit_ty_method: @fn(&TypeMethod),
-    visit_trait_method: @fn(&trait_method),
-    visit_struct_def: @fn(@struct_def, Ident, &Generics, NodeId),
-    visit_struct_field: @fn(@struct_field),
-    visit_struct_method: @fn(@method)
-}
-
-pub type simple_visitor = @SimpleVisitor;
-
-pub fn simple_ignore_ty(_t: &Ty) {}
-
-pub fn default_simple_visitor() -> @SimpleVisitor {
-    @SimpleVisitor {
-        visit_mod: |_m, _sp, _id| { },
-        visit_view_item: |_vi| { },
-        visit_foreign_item: |_ni| { },
-        visit_item: |_i| { },
-        visit_local: |_l| { },
-        visit_block: |_b| { },
-        visit_stmt: |_s| { },
-        visit_arm: |_a| { },
-        visit_pat: |_p| { },
-        visit_decl: |_d| { },
-        visit_expr: |_e| { },
-        visit_expr_post: |_e| { },
-        visit_ty: simple_ignore_ty,
-        visit_generics: |_| {},
-        visit_fn: |_, _, _, _, _| {},
-        visit_ty_method: |_| {},
-        visit_trait_method: |_| {},
-        visit_struct_def: |_, _, _, _| {},
-        visit_struct_field: |_| {},
-        visit_struct_method: |_| {},
-    }
-}
-
-pub fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
-    fn v_mod(
-        f: @fn(&_mod, Span, NodeId),
-        m: &_mod,
-        sp: Span,
-        id: NodeId,
-        (e, v): ((), vt<()>)
-    ) {
-        f(m, sp, id);
-        visit_mod(m, sp, id, (e, v));
-    }
-    fn v_view_item(f: @fn(&view_item), vi: &view_item, (e, v): ((), vt<()>)) {
-        f(vi);
-        visit_view_item(vi, (e, v));
-    }
-    fn v_foreign_item(f: @fn(@foreign_item), ni: @foreign_item, (e, v): ((), vt<()>)) {
-        f(ni);
-        visit_foreign_item(ni, (e, v));
-    }
-    fn v_item(f: @fn(@item), i: @item, (e, v): ((), vt<()>)) {
-        f(i);
-        visit_item(i, (e, v));
-    }
-    fn v_local(f: @fn(@Local), l: @Local, (e, v): ((), vt<()>)) {
-        f(l);
-        visit_local(l, (e, v));
-    }
-    fn v_block(f: @fn(&ast::Block), bl: &ast::Block, (e, v): ((), vt<()>)) {
-        f(bl);
-        visit_block(bl, (e, v));
-    }
-    fn v_stmt(f: @fn(@Stmt), st: @Stmt, (e, v): ((), vt<()>)) {
-        f(st);
-        visit_stmt(st, (e, v));
-    }
-    fn v_arm(f: @fn(&Arm), a: &Arm, (e, v): ((), vt<()>)) {
-        f(a);
-        visit_arm(a, (e, v));
-    }
-    fn v_pat(f: @fn(@Pat), p: @Pat, (e, v): ((), vt<()>)) {
-        f(p);
-        visit_pat(p, (e, v));
-    }
-    fn v_decl(f: @fn(@Decl), d: @Decl, (e, v): ((), vt<()>)) {
-        f(d);
-        visit_decl(d, (e, v));
-    }
-    fn v_expr(f: @fn(@Expr), ex: @Expr, (e, v): ((), vt<()>)) {
-        f(ex);
-        visit_expr(ex, (e, v));
-    }
-    fn v_expr_post(f: @fn(@Expr), ex: @Expr, (_e, _v): ((), vt<()>)) {
-        f(ex);
-    }
-    fn v_ty(f: @fn(&Ty), ty: &Ty, (e, v): ((), vt<()>)) {
-        f(ty);
-        visit_ty(ty, (e, v));
-    }
-    fn v_ty_method(f: @fn(&TypeMethod), ty: &TypeMethod, (e, v): ((), vt<()>)) {
-        f(ty);
-        visit_ty_method(ty, (e, v));
-    }
-    fn v_trait_method(f: @fn(&trait_method),
-                      m: &trait_method,
-                      (e, v): ((), vt<()>)) {
-        f(m);
-        visit_trait_method(m, (e, v));
-    }
-    fn v_struct_def(
-        f: @fn(@struct_def, Ident, &Generics, NodeId),
-        sd: @struct_def,
-        nm: Ident,
-        generics: &Generics,
-        id: NodeId,
-        (e, v): ((), vt<()>)
-    ) {
-        f(sd, nm, generics, id);
-        visit_struct_def(sd, nm, generics, id, (e, v));
-    }
-    fn v_generics(
-        f: @fn(&Generics),
-        ps: &Generics,
-        (e, v): ((), vt<()>)
-    ) {
-        f(ps);
-        visit_generics(ps, (e, v));
-    }
-    fn v_fn(
-        f: @fn(&fn_kind, &fn_decl, &Block, Span, NodeId),
-        fk: &fn_kind,
-        decl: &fn_decl,
-        body: &Block,
-        sp: Span,
-        id: NodeId,
-        (e, v): ((), vt<()>)
-    ) {
-        f(fk, decl, body, sp, id);
-        visit_fn(fk, decl, body, sp, id, (e, v));
-    }
-    let visit_ty: @fn(&Ty, ((), vt<()>)) =
-        |a,b| v_ty(v.visit_ty, a, b);
-    fn v_struct_field(f: @fn(@struct_field), sf: @struct_field, (e, v): ((), vt<()>)) {
-        f(sf);
-        visit_struct_field(sf, (e, v));
-    }
-    return mk_vt(@Visitor {
-        visit_mod: |a,b,c,d|v_mod(v.visit_mod, a, b, c, d),
-        visit_view_item: |a,b| v_view_item(v.visit_view_item, a, b),
-        visit_foreign_item:
-            |a,b|v_foreign_item(v.visit_foreign_item, a, b),
-        visit_item: |a,b|v_item(v.visit_item, a, b),
-        visit_local: |a,b|v_local(v.visit_local, a, b),
-        visit_block: |a,b|v_block(v.visit_block, a, b),
-        visit_stmt: |a,b|v_stmt(v.visit_stmt, a, b),
-        visit_arm: |a,b|v_arm(v.visit_arm, a, b),
-        visit_pat: |a,b|v_pat(v.visit_pat, a, b),
-        visit_decl: |a,b|v_decl(v.visit_decl, a, b),
-        visit_expr: |a,b|v_expr(v.visit_expr, a, b),
-        visit_expr_post: |a,b| v_expr_post(v.visit_expr_post, a, b),
-        visit_ty: visit_ty,
-        visit_generics: |a,b|
-            v_generics(v.visit_generics, a, b),
-        visit_fn: |a,b,c,d,e,f|
-            v_fn(v.visit_fn, a, b, c, d, e, f),
-        visit_ty_method: |a,b|
-            v_ty_method(v.visit_ty_method, a, b),
-        visit_trait_method: |a,b|
-            v_trait_method(v.visit_trait_method, a, b),
-        visit_struct_def: |a,b,c,d,e|
-            v_struct_def(v.visit_struct_def, a, b, c, d, e),
-        visit_struct_field: |a,b|
-            v_struct_field(v.visit_struct_field, a, b),
-    });
-}
index 2d7801a22dedab7c4a2c02af0a99e13bdd42f408..46940d2d4daed1ebd843ececc3bbc8970b068534 100644 (file)
@@ -140,6 +140,10 @@ fn ne(&self, other: &OptVec<A>) -> bool {
     }
 }
 
+impl<T> Default for OptVec<T> {
+    fn default() -> OptVec<T> { Empty }
+}
+
 pub struct OptVecIterator<'self, T> {
     priv iter: Option<VecIterator<'self, T>>
 }
index 9dfea678b8703034a19400702a6d641b217b472f..c267a673fcedfababfb57c1f2cbeb7a0a75e42b2 100644 (file)
@@ -20,7 +20,7 @@
 use std::cast::transmute;
 use std::char;
 use std::either;
-use std::u64;
+use std::num::from_str_radix;
 use std::util;
 
 pub use ext::tt::transcribe::{TtReader, new_tt_reader};
@@ -444,7 +444,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
         if num_str.len() == 0u {
             rdr.fatal(~"no valid digits found for number");
         }
-        let parsed = match u64::from_str_radix(num_str, base as uint) {
+        let parsed = match from_str_radix::<u64>(num_str, base as uint) {
             Some(p) => p,
             None => rdr.fatal(~"int literal is too large")
         };
@@ -509,7 +509,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
         if num_str.len() == 0u {
             rdr.fatal(~"no valid digits found for number");
         }
-        let parsed = match u64::from_str_radix(num_str, base as uint) {
+        let parsed = match from_str_radix::<u64>(num_str, base as uint) {
             Some(p) => p,
             None => rdr.fatal(~"int literal is too large")
         };
index 4adc34d75a73ed0aed22e99004c5a404570c15f3..f05452bb6c504d584ece8c54484ecf5e0fa80940 100644 (file)
@@ -80,8 +80,6 @@
 use opt_vec;
 use opt_vec::OptVec;
 
-use std::either::Either;
-use std::either;
 use std::hashmap::HashSet;
 use std::util;
 use std::vec;
@@ -94,7 +92,6 @@ enum restriction {
     RESTRICT_NO_BAR_OR_DOUBLEBAR_OP,
 }
 
-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
@@ -802,7 +799,7 @@ pub fn parse_ty_bare_fn(&self) -> ty_ {
         */
 
         let opt_abis = self.parse_opt_abis();
-        let abis = opt_abis.unwrap_or_default(AbiSet::Rust());
+        let abis = opt_abis.unwrap_or(AbiSet::Rust());
         let purity = self.parse_unsafety();
         self.expect_keyword(keywords::Fn);
         let (decl, lifetimes) = self.parse_ty_fn_decl();
@@ -936,7 +933,7 @@ pub fn parse_trait_methods(&self) -> ~[trait_method] {
             let (explicit_self, d) = do self.parse_fn_decl_with_self() |p| {
                 // This is somewhat dubious; We don't want to allow argument
                 // names to be left off if there is a definition...
-                either::Left(p.parse_arg_general(false))
+                p.parse_arg_general(false)
             };
 
             let hi = p.last_span.hi;
@@ -1290,12 +1287,12 @@ pub fn parse_arg_general(&self, require_name: bool) -> arg {
     }
 
     // parse a single function argument
-    pub fn parse_arg(&self) -> arg_or_capture_item {
-        either::Left(self.parse_arg_general(true))
+    pub fn parse_arg(&self) -> arg {
+        self.parse_arg_general(true)
     }
 
     // parse an argument in a lambda header e.g. |arg, arg|
-    pub fn parse_fn_block_arg(&self) -> arg_or_capture_item {
+    pub fn parse_fn_block_arg(&self) -> arg {
         self.parse_arg_mode();
         let is_mutbl = self.eat_keyword(keywords::Mut);
         let pat = self.parse_pat();
@@ -1308,12 +1305,12 @@ pub fn parse_fn_block_arg(&self) -> arg_or_capture_item {
                 span: mk_sp(self.span.lo, self.span.hi),
             }
         };
-        either::Left(ast::arg {
+        ast::arg {
             is_mutbl: is_mutbl,
             ty: t,
             pat: pat,
             id: ast::DUMMY_NODE_ID
-        })
+        }
     }
 
     pub fn maybe_parse_fixed_vstore(&self) -> Option<@ast::Expr> {
@@ -1792,7 +1789,7 @@ pub fn parse_bottom_expr(&self) -> @Expr {
         } else if self.eat_keyword(keywords::Match) {
             return self.parse_match_expr();
         } else if self.eat_keyword(keywords::Unsafe) {
-            return self.parse_block_expr(lo, UnsafeBlock);
+            return self.parse_block_expr(lo, UnsafeBlock(ast::UserProvided));
         } else if *self.token == token::LBRACKET {
             self.bump();
             let mutbl = self.parse_mutability();
@@ -3461,7 +3458,7 @@ fn parse_ty_param(&self) -> TyParam {
         let ident = self.parse_ident();
         let opt_bounds = self.parse_optional_ty_param_bounds();
         // For typarams we don't care about the difference b/w "<T>" and "<T:>".
-        let bounds = opt_bounds.unwrap_or_default(opt_vec::Empty);
+        let bounds = opt_bounds.unwrap_or_default();
         ast::TyParam { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds }
     }
 
@@ -3500,7 +3497,7 @@ fn parse_generic_values_after_lt(&self) -> (OptVec<ast::Lifetime>, ~[Ty]) {
 
     // parse the argument list and result type of a function declaration
     pub fn parse_fn_decl(&self) -> fn_decl {
-        let args_or_capture_items: ~[arg_or_capture_item] =
+        let args: ~[arg] =
             self.parse_unspanned_seq(
                 &token::LPAREN,
                 &token::RPAREN,
@@ -3508,11 +3505,9 @@ pub fn parse_fn_decl(&self) -> fn_decl {
                 |p| p.parse_arg()
             );
 
-        let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
-
         let (ret_style, ret_ty) = self.parse_ret_ty();
         ast::fn_decl {
-            inputs: inputs,
+            inputs: args,
             output: ret_ty,
             cf: ret_style,
         }
@@ -3542,7 +3537,7 @@ fn expect_self_ident(&self) {
     fn parse_fn_decl_with_self(
         &self,
         parse_arg_fn:
-        &fn(&Parser) -> arg_or_capture_item
+        &fn(&Parser) -> arg
     ) -> (explicit_self, fn_decl) {
         fn maybe_parse_explicit_self(
             cnstr: &fn(v: Mutability) -> ast::explicit_self_,
@@ -3650,20 +3645,20 @@ fn maybe_parse_borrowed_explicit_self(this: &Parser) -> ast::explicit_self_ {
         };
 
         // If we parsed a self type, expect a comma before the argument list.
-        let args_or_capture_items;
+        let fn_inputs;
         if explicit_self != sty_static {
             match *self.token {
                 token::COMMA => {
                     self.bump();
                     let sep = seq_sep_trailing_disallowed(token::COMMA);
-                    args_or_capture_items = self.parse_seq_to_before_end(
+                    fn_inputs = self.parse_seq_to_before_end(
                         &token::RPAREN,
                         sep,
                         parse_arg_fn
                     );
                 }
                 token::RPAREN => {
-                    args_or_capture_items = ~[];
+                    fn_inputs = ~[];
                 }
                 _ => {
                     self.fatal(
@@ -3676,7 +3671,7 @@ fn maybe_parse_borrowed_explicit_self(this: &Parser) -> ast::explicit_self_ {
             }
         } else {
             let sep = seq_sep_trailing_disallowed(token::COMMA);
-            args_or_capture_items = self.parse_seq_to_before_end(
+            fn_inputs = self.parse_seq_to_before_end(
                 &token::RPAREN,
                 sep,
                 parse_arg_fn
@@ -3687,11 +3682,10 @@ fn maybe_parse_borrowed_explicit_self(this: &Parser) -> ast::explicit_self_ {
 
         let hi = self.span.hi;
 
-        let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
         let (ret_style, ret_ty) = self.parse_ret_ty();
 
         let fn_decl = ast::fn_decl {
-            inputs: inputs,
+            inputs: fn_inputs,
             output: ret_ty,
             cf: ret_style
         };
@@ -3720,7 +3714,7 @@ fn parse_fn_block_decl(&self) -> fn_decl {
         };
 
         ast::fn_decl {
-            inputs: either::lefts(inputs_captures.move_iter()).collect(),
+            inputs: inputs_captures,
             output: output,
             cf: return_val,
         }
@@ -4363,7 +4357,7 @@ fn parse_item_foreign_mod(&self,
                 self.obsolete(*self.last_span, ObsoleteExternVisibility);
             }
 
-            let abis = opt_abis.unwrap_or_default(AbiSet::C());
+            let abis = opt_abis.unwrap_or(AbiSet::C());
 
             let (inner, next) = self.parse_inner_attrs_and_next();
             let m = self.parse_foreign_mod_items(sort, abis, next);
@@ -4640,7 +4634,7 @@ fn parse_item_or_view_item(&self,
 
             if self.eat_keyword(keywords::Fn) {
                 // EXTERN FUNCTION ITEM
-                let abis = opt_abis.unwrap_or_default(AbiSet::C());
+                let abis = opt_abis.unwrap_or(AbiSet::C());
                 let (ident, item_, extra_attrs) =
                     self.parse_item_fn(extern_fn, abis);
                 return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
index 55f052d769dcedd371970936a47d9d85c330d7c0..ec84cbda97360392abce5a27964b7940a2f2894a 100644 (file)
@@ -586,11 +586,13 @@ pub fn print_item(s: @ps, item: &ast::item) {
         };
 
         print_type(s, ty);
-        space(s.s);
 
         if methods.len() == 0 {
             word(s.s, ";");
+            end(s); // end the head-ibox
+            end(s); // end the outer cbox
         } else {
+            space(s.s);
             bopen(s);
             for meth in methods.iter() {
                print_method(s, *meth);
@@ -951,7 +953,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
                                       attrs: &[ast::Attribute],
                                       close_box: bool) {
     match blk.rules {
-      ast::UnsafeBlock => word_space(s, "unsafe"),
+      ast::UnsafeBlock(*) => word_space(s, "unsafe"),
       ast::DefaultBlock => ()
     }
     maybe_print_comment(s, blk.span.lo);
index a5feb0483d894a24dbd75bcfa9b2a5c9818c6445..48270702e0dd51230748db4e9b6c13cc2422a4b6 100644 (file)
@@ -43,7 +43,6 @@ pub mod syntax {
 pub mod ast_map;
 pub mod visit;
 pub mod fold;
-pub mod oldvisit;
 
 
 pub mod parse;
@@ -73,7 +72,7 @@ pub mod tt {
 
     pub mod cfg;
     pub mod fmt;
-    pub mod ifmt;
+    pub mod format;
     pub mod env;
     pub mod bytes;
     pub mod concat_idents;
index 03a17d2c2ef97360a15c5850ea759147ff9f7c84..4b718303f2cb0f7da78d4da0f7783bb7e6f13b0f 100644 (file)
@@ -603,18 +603,6 @@ rust_get_global_args_ptr() {
     return &global_args_ptr;
 }
 
-static lock_and_signal change_dir_lock;
-
-extern "C" CDECL void
-rust_take_change_dir_lock() {
-    change_dir_lock.lock();
-}
-
-extern "C" CDECL void
-rust_drop_change_dir_lock() {
-    change_dir_lock.unlock();
-}
-
 // Used by i386 __morestack
 extern "C" CDECL uintptr_t
 rust_get_task() {
@@ -633,6 +621,18 @@ rust_drop_env_lock() {
     env_lock.unlock();
 }
 
+static lock_and_signal linenoise_lock;
+
+extern "C" CDECL void
+rust_take_linenoise_lock() {
+    linenoise_lock.lock();
+}
+
+extern "C" CDECL void
+rust_drop_linenoise_lock() {
+    linenoise_lock.unlock();
+}
+
 extern "C" CDECL unsigned int
 rust_valgrind_stack_register(void *start, void *end) {
   return VALGRIND_STACK_REGISTER(start, end);
diff --git a/src/rt/rust_crate_map.cpp b/src/rt/rust_crate_map.cpp
deleted file mode 100644 (file)
index e6206fd..0000000
+++ /dev/null
@@ -1,69 +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.
-
-#include "rust_crate_map.h"
-#include <set>
-
-void iter_module_map(const mod_entry* map,
-                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
-                    void* fptr,
-                    void* env
-                    ) {
-    for (const mod_entry* cur = map; cur->name; cur++) {
-        fn(fptr, env, cur);
-    }
-}
-
-void iter_crate_map(const cratemap* map,
-                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
-                    void *fptr,
-                    void *env,
-                    std::set<const cratemap*>& visited) {
-    if (visited.find(map) == visited.end()) {
-        // Mark this crate visited
-        visited.insert(map);
-        // First iterate this crate
-        iter_module_map(map->entries(), fn, fptr, env);
-        // Then recurse on linked crates
-        for (cratemap::iterator i = map->begin(),
-                e = map->end(); i != e; ++i) {
-            iter_crate_map(*i, fn, fptr, env, visited);
-        }
-    }
-}
-
-void iter_crate_map(const cratemap* map,
-                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
-                    void *fptr,
-                    void *env
-                    ) {
-    std::set<const cratemap*> visited;
-    iter_crate_map(map, fn, fptr, env, visited);
-}
-
-extern "C" CDECL void
-rust_iter_crate_map(const cratemap* map,
-                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
-                    void *fptr,
-                    void *env
-                    ) {
-    return iter_crate_map(map, fn, fptr, env);
-}
-
-
-//
-// 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_crate_map.h b/src/rt/rust_crate_map.h
deleted file mode 100644 (file)
index 1bcb2aa..0000000
+++ /dev/null
@@ -1,105 +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.
-
-#ifndef RUST_CRATE_MAP_H
-#define RUST_CRATE_MAP_H
-
-#include "rust_globals.h"
-#include <stdint.h>
-
-struct mod_entry {
-    const char* name;
-    uint32_t* log_level;
-};
-
-class cratemap;
-
-class cratemap_v0 {
-    friend class cratemap;
-    const mod_entry *m_entries;
-    const cratemap* m_children[1];
-};
-
-class cratemap {
-private:
-    int32_t m_version;
-    const void *m_annihilate_fn;
-    const mod_entry* m_entries;
-    const cratemap* m_children[1];
-
-    inline int32_t version() const {
-        switch (m_version) {
-        case 1:     return 1;
-        default:    return 0;
-        }
-    }
-
-public:
-    typedef const cratemap *const *iterator;
-
-    inline const void *annihilate_fn() const {
-        switch (version()) {
-        case 0: return NULL;
-        case 1: return m_annihilate_fn;
-        default: assert(false && "Unknown crate map version!");
-            return NULL; // Appease -Werror=return-type
-        }
-    }
-
-    inline const mod_entry *entries() const {
-        switch (version()) {
-        case 0: return reinterpret_cast<const cratemap_v0 *>(this)->m_entries;
-        case 1: return m_entries;
-        default: assert(false && "Unknown crate map version!");
-            return NULL; // Appease -Werror=return-type
-        }
-    }
-
-    inline const iterator begin() const {
-        switch (version()) {
-        case 0:
-            return &reinterpret_cast<const cratemap_v0 *>(this)->
-                m_children[0];
-        case 1:
-            return &m_children[0];
-        default: assert(false && "Unknown crate map version!");
-            return NULL; // Appease -Werror=return-type
-        }
-    }
-
-    inline const iterator end() const {
-        iterator i = begin();
-        while (*i)
-            i++;
-        return i;
-    }
-};
-
-void iter_module_map(const mod_entry* map,
-                     void (*fn)(void* fptr, void* env, const mod_entry *entry),
-                     void *fptr,
-                     void *env);
-
-void iter_crate_map(const cratemap* map,
-                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
-                    void *fptr,
-                    void *env);
-
-//
-// 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_CRATE_MAP_H */
index bf3500e4c724e12548cd245955d8a83ff8d5df1f..4cbee0dcbd0688b0d2403aed4f3cf5396b89191d 100644 (file)
@@ -181,14 +181,13 @@ rust_valgrind_stack_register
 rust_valgrind_stack_deregister
 rust_take_env_lock
 rust_drop_env_lock
-rust_iter_crate_map
 rust_running_on_valgrind
 rust_get_num_cpus
 rust_get_global_args_ptr
 rust_take_global_args_lock
 rust_drop_global_args_lock
-rust_take_change_dir_lock
-rust_drop_change_dir_lock
+rust_take_linenoise_lock
+rust_drop_linenoise_lock
 rust_get_test_int
 rust_get_task
 rust_uv_get_loop_from_getaddrinfo_req
index 226a7c34304f48ab74198265f58c67a1920bb7ef..63d42816207cd79dae5cd0713cd6233e2d0d4882 100644 (file)
@@ -727,9 +727,9 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateTemplateTypeParameter(
     LLVMValueRef Scope,
     const char* Name,
     LLVMValueRef Ty,
-    LLVMValueRef File = 0,
-    unsigned LineNo = 0,
-    unsigned ColumnNo = 0)
+    LLVMValueRef File,
+    unsigned LineNo,
+    unsigned ColumnNo)
 {
     return wrap(Builder->createTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope),
@@ -775,3 +775,24 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateComplexVariable(
         ArgNo
     ));
 }
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateNameSpace(
+    DIBuilderRef Builder,
+    LLVMValueRef Scope,
+    const char* Name,
+    LLVMValueRef File,
+    unsigned LineNo)
+{
+    return wrap(Builder->createNameSpace(
+        unwrapDI<DIDescriptor>(Scope),
+        Name,
+        unwrapDI<DIFile>(File),
+        LineNo));
+}
+
+extern "C" void LLVMDICompositeTypeSetTypeArray(
+    LLVMValueRef CompositeType,
+    LLVMValueRef TypeArray)
+{
+    unwrapDI<DICompositeType>(CompositeType).setTypeArray(unwrapDI<DIArray>(TypeArray));
+}
index d905370f5877adf5574cea64a979e903baada3dd..0162857e44e37f9b511e00bf09362e3f1e75522a 100644 (file)
@@ -611,6 +611,8 @@ LLVMDIBuilderCreateTemplateTypeParameter
 LLVMDIBuilderCreateOpDeref
 LLVMDIBuilderCreateOpPlus
 LLVMDIBuilderCreateComplexVariable
+LLVMDIBuilderCreateNameSpace
+LLVMDICompositeTypeSetTypeArray
 LLVMSetUnnamedAddr
 LLVMRustAddPass
 LLVMRustAddAnalysisPasses
diff --git a/src/test/auxiliary/issue_9123.rs b/src/test/auxiliary/issue_9123.rs
new file mode 100644 (file)
index 0000000..066909d
--- /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.
+
+#[crate_type = "lib"];
+
+pub trait X {
+    fn x() {
+        fn f() { }
+        f();
+    }
+}
+
index 180cb18c745966e87c3b0984221e32991d187164..6978b9209d8bcc97db065ecb7acb31d15b839480 100644 (file)
@@ -21,7 +21,7 @@ pub trait read {
 
 impl read for int {
     fn readMaybe(s: ~str) -> Option<int> {
-        int::from_str(s)
+        from_str::<int>(s)
     }
 }
 
diff --git a/src/test/auxiliary/struct_variant_xc_aux.rs b/src/test/auxiliary/struct_variant_xc_aux.rs
new file mode 100644 (file)
index 0000000..6d2c77f
--- /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.
+
+#[link(name = "struct_variant_xc_aux",
+       vers = "0.1")];
+#[crate_type = "lib"];
+
+pub enum Enum {
+    Variant { arg: u8 }
+}
index 2571d60145906db1d20da9a6723e14d1979c15a0..7077cee80e946df8e6679b515304d1dd154615ee 100644 (file)
@@ -97,7 +97,7 @@ fn main() {
     let args = os::args();
     let n_keys = {
         if args.len() == 2 {
-            uint::from_str(args[1]).unwrap()
+            from_str::<uint>(args[1]).unwrap()
         } else {
             1000000
         }
index fe77196e2b101512fc89c03a178e9d882b29572c..ead1128e99437882917f17ce4e478c272d827569 100644 (file)
@@ -157,7 +157,7 @@ fn main() {
     let args = os::args();
     let num_keys = {
         if args.len() == 2 {
-            uint::from_str(args[1]).unwrap()
+            from_str::<uint>(args[1]).unwrap()
         } else {
             100 // woefully inadequate for any real measurement
         }
index 4869c486e5ea9c6b13d0f8b6ae9e145b224cdc8f..6b1319aa0c90f75beb13c3457879ded2b274020c 100644 (file)
@@ -21,7 +21,7 @@ fn main() {
         args
     };
 
-    let n = uint::from_str(args[1]).unwrap();
+    let n = from_str::<uint>(args[1]).unwrap();
 
     for i in range(0u, n) {
         let x = i.to_str();
index 9725297bace53b12371bef8e7c5c9eabe9bf4980..ff66fd121d98cb899c4d5ad3acf758ddb20e5b12 100644 (file)
@@ -418,8 +418,8 @@ fn main() {
         args
     };
 
-    let scale = uint::from_str(args[1]).unwrap();
-    let num_keys = uint::from_str(args[2]).unwrap();
+    let scale = from_str::<uint>(args[1]).unwrap();
+    let num_keys = from_str::<uint>(args[2]).unwrap();
     let do_validate = false;
     let do_sequential = true;
 
index 4e9656afb813d253c50713163bdc3cfa4f8eae7a..af15acc15357999cfb4a0423038a4846c0533913 100644 (file)
@@ -59,8 +59,8 @@ fn run(args: &[~str]) {
 
     let to_child = SharedChan::new(to_child);
 
-    let size = uint::from_str(args[1]).unwrap();
-    let workers = uint::from_str(args[2]).unwrap();
+    let size = from_str::<uint>(args[1]).unwrap();
+    let workers = from_str::<uint>(args[2]).unwrap();
     let num_bytes = 100;
     let start = extra::time::precise_time_s();
     let mut worker_results = ~[];
index 470e23d63a514ff81f8bbd419c4b32fab03ff927..3b095650b7ed9e094f255eed8425553a002cdf99 100644 (file)
@@ -53,8 +53,8 @@ fn run(args: &[~str]) {
     let (from_parent, to_child) = stream();
     let to_child = SharedChan::new(to_child);
 
-    let size = uint::from_str(args[1]).unwrap();
-    let workers = uint::from_str(args[2]).unwrap();
+    let size = from_str::<uint>(args[1]).unwrap();
+    let workers = from_str::<uint>(args[2]).unwrap();
     let num_bytes = 100;
     let start = extra::time::precise_time_s();
     let mut worker_results = ~[];
index a5311d5c831342dcc45454a4dc2ab9d8ad65df09..dd56d550e61c29e0bd32a673473d7e1bb06469e9 100644 (file)
@@ -78,8 +78,8 @@ fn main() {
         args.clone()
     };
 
-    let num_tasks = uint::from_str(args[1]).unwrap();
-    let msg_per_task = uint::from_str(args[2]).unwrap();
+    let num_tasks = from_str::<uint>(args[1]).unwrap();
+    let msg_per_task = from_str::<uint>(args[2]).unwrap();
 
     let (num_chan, num_port) = init();
     let num_chan = Cell::new(num_chan);
index e25490bcd9ba88681b2224476ce5ef069408cdce..130bd4e7d16a11f81de9354f140a57b6a503b00d 100644 (file)
@@ -74,8 +74,8 @@ fn main() {
         args.clone()
     };
 
-    let num_tasks = uint::from_str(args[1]).unwrap();
-    let msg_per_task = uint::from_str(args[2]).unwrap();
+    let num_tasks = from_str::<uint>(args[1]).unwrap();
+    let msg_per_task = from_str::<uint>(args[2]).unwrap();
 
     let (num_chan, num_port) = init();
     let num_chan = Cell::new(num_chan);
index 6c482c6d207291941d899d3a83100ce7384a2d80..ec796713c21d180b6b80578a2283ab1ba1001cb4 100644 (file)
@@ -65,13 +65,13 @@ fn main() {
 
     let args = os::args();
     let n = if args.len() == 3 {
-        uint::from_str(args[1]).unwrap()
+        from_str::<uint>(args[1]).unwrap()
     } else {
         10000
     };
 
     let m = if args.len() == 3 {
-        uint::from_str(args[2]).unwrap()
+        from_str::<uint>(args[2]).unwrap()
     } else {
         4
     };
index 32f0a592273f5ef93d467209f6a8eeb1b4017ebd..3c981611e503912a1a58346df7f81830cfbe134e 100644 (file)
@@ -38,7 +38,7 @@ fn main() {
 
     let args = os::args();
     let n = if args.len() == 2 {
-        uint::from_str(args[1]).unwrap()
+        from_str::<uint>(args[1]).unwrap()
     } else {
         10
     };
index ff578ed70b9c1c8c26d6c2da65a561176b1bb947..6693e2e19853327426f7b8f0afbc549bd61b0665 100644 (file)
@@ -21,7 +21,7 @@ fn main() {
 
     let args = os::args();
     let n = if args.len() == 2 {
-        uint::from_str(args[1]).unwrap()
+        from_str::<uint>(args[1]).unwrap()
     } else {
         100000
     };
index 3ecb580874c4b33fed23afaac34dc8838c3d5863..3e7feb01c4acf39730576e809c39e4c7f87103cd 100644 (file)
@@ -34,6 +34,6 @@ fn main() {
     } else {
         args
     };
-    let n = int::from_str(args[1]).unwrap();
+    let n = from_str::<int>(args[1]).unwrap();
     printfln!("Ack(3,%d): %d\n", n, ack(3, n));
 }
index 8a2ae3e89952007903431e6484d1e70af1d7c366..e956beedaabe1d6d2a7f63e972052ac3d13814e3 100644 (file)
@@ -48,7 +48,7 @@ fn main() {
         args
     };
 
-    let n = int::from_str(args[1]).unwrap();
+    let n = from_str::<int>(args[1]).unwrap();
     let min_depth = 4;
     let mut max_depth;
     if min_depth + 2 > n {
index f82c5e692e44d21a796314875b1d2774cff9684c..e4f395e5eca1ba90d092bbce849f55aebece6a55 100644 (file)
@@ -212,7 +212,7 @@ fn main() {
         args
     };
 
-    let nn = uint::from_str(args[1]).unwrap();
+    let nn = from_str::<uint>(args[1]).unwrap();
 
     print_complements();
     io::println("");
index 9d47e7fed237bdd290b8262629231532973db718..402b3be9542f80c7e3eb937a8b218b515ce88ec1 100644 (file)
@@ -128,7 +128,7 @@ fn main() {
         io::stdout()
     };
 
-    let n = int::from_str(args[1]).unwrap();
+    let n = from_str::<int>(args[1]).unwrap();
 
     let iub: ~[AminoAcids] =
         make_cumulative(~[acid('a', 27u32), acid('c', 12u32), acid('g', 12u32),
index a367beface2173dd485e774bdb85633daa6271c4..f902a8b533903c72a70aefc0077ee7acca377a5d 100644 (file)
@@ -30,6 +30,6 @@ fn main() {
     } else {
         args
     };
-    let n = int::from_str(args[1]).unwrap();
+    let n = from_str::<int>(args[1]).unwrap();
     printfln!("%d\n", fib(n));
 }
index a035041a662dc73097c6a8bbd28430a6f99cc43a..6940c97d76e34e06d1471ab59c9f402066227f54 100644 (file)
@@ -39,8 +39,8 @@ fn main() {
     } else {
         args
     };
-    let max = uint::from_str(args[1]).unwrap();
-    let rep = uint::from_str(args[2]).unwrap();
+    let max = from_str::<uint>(args[1]).unwrap();
+    let rep = from_str::<uint>(args[2]).unwrap();
 
     let mut checkf = 0.0;
     let mut appendf = 0.0;
index 17fe1135fd985596c08296ab99c82967c8ba0406..2c5b434a4760f1fa21765ae9039e9e0a46e51b43 100644 (file)
@@ -74,9 +74,9 @@ pub fn read(reader: @io::Reader) -> Sudoku {
             let comps: ~[&str] = line.trim().split_iter(',').collect();
 
             if comps.len() == 3u {
-                let row     = uint::from_str(comps[0]).unwrap() as u8;
-                let col     = uint::from_str(comps[1]).unwrap() as u8;
-                g[row][col] = uint::from_str(comps[2]).unwrap() as u8;
+                let row     = from_str::<uint>(comps[0]).unwrap() as u8;
+                let col     = from_str::<uint>(comps[1]).unwrap() as u8;
+                g[row][col] = from_str::<uint>(comps[2]).unwrap() as u8;
             }
             else {
                 fail!("Invalid sudoku file");
index 0020a006e68d854a431f3a7767e2e8b6ba0a50d3..0827f7d34475b28aa683582dcdb335c7ab76e1d8 100644 (file)
@@ -52,7 +52,7 @@ fn main() {
     };
 
     let (p,c) = comm::stream();
-    child_generation(uint::from_str(args[1]).unwrap(), c);
+    child_generation(from_str::<uint>(args[1]).unwrap(), c);
     if p.try_recv().is_none() {
         fail!("it happened when we slumbered");
     }
index 7788005775f7897e20fbede324d5fb0318432326..5aeba3f415da35263e54e080dfe49c8971bc5124 100644 (file)
@@ -74,7 +74,7 @@ fn main() {
         args.clone()
     };
 
-    let num_tasks = uint::from_str(args[1]).unwrap();
+    let num_tasks = from_str::<uint>(args[1]).unwrap();
 
     // Main group #0 waits for unsupervised group #1.
     // Grandparent group #1 waits for middle group #2, then fails, killing #3.
index 5efe13f8bca6b1376b8d7f39ec1783db30d46f70..9e04ad65eb239142309dab9a9a7272513f1d3d96 100644 (file)
@@ -56,7 +56,7 @@ fn main() {
         args
     };
 
-    let children = uint::from_str(args[1]).get();
+    let children = from_str::<uint>(args[1]).get();
     let (wait_port, wait_chan) = stream();
     do task::spawn {
         calc(children, &wait_chan);
index 83116ae3c87deb07df1902da9201edb1ef55ea5e..80217da60f98ec739e906d7609e26abddc421bed 100644 (file)
@@ -31,7 +31,7 @@ fn main() {
     } else {
         args
     };
-    let n = uint::from_str(args[1]).unwrap();
+    let n = from_str::<uint>(args[1]).unwrap();
     let mut i = 0u;
     while i < n { task::spawn(|| f(n) ); i += 1u; }
 }
diff --git a/src/test/compile-fail/debug-correct-span.rs b/src/test/compile-fail/debug-correct-span.rs
new file mode 100644 (file)
index 0000000..f143e6c
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    debug!("%s %s", 3); //~ ERROR: not enough arguments
+}
index 5da73a495f6ed35b746cc3302d334869cf47193d..f9552725af345f4f9e45f8c909ded2503ab1f7a2 100644 (file)
@@ -11,7 +11,6 @@
 fn main() {
     // bad arguments to the format! call
 
-    format!();                //~ ERROR: requires at least a format string
     format!("{}");            //~ ERROR: invalid reference to argument
 
     format!("{1}", 1);        //~ ERROR: invalid reference to argument `1`
@@ -30,8 +29,6 @@ fn main() {
     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: `,`
 
     format!("{0, select, a{} a{} other{}}", "a");    //~ ERROR: duplicate selector
     format!("{0, plural, =1{} =1{} other{}}", 1u);   //~ ERROR: duplicate selector
@@ -74,4 +71,8 @@ fn main() {
 
     format!("foo } bar"); //~ ERROR: unmatched `}` found
     format!("foo }"); //~ ERROR: unmatched `}` found
+
+    format!();          //~ ERROR: requires at least a format string argument
+    format!("" 1);      //~ ERROR: expected token: `,`
+    format!("", 1 1);   //~ ERROR: expected token: `,`
 }
diff --git a/src/test/compile-fail/ifmt-bad-format-args.rs b/src/test/compile-fail/ifmt-bad-format-args.rs
new file mode 100644 (file)
index 0000000..d2a3fe2
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    format_args!("test"); //~ ERROR: expected token
+    format_args!("", || {}); //~ ERROR: must be a string literal
+}
diff --git a/src/test/compile-fail/ifmt-bad-format-args2.rs b/src/test/compile-fail/ifmt-bad-format-args2.rs
new file mode 100644 (file)
index 0000000..7bb8365
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    format_args!("{}", ""); //~ ERROR: expected function
+}
diff --git a/src/test/compile-fail/lint-cstack.rs b/src/test/compile-fail/lint-cstack.rs
new file mode 100644 (file)
index 0000000..11fe02e
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+extern {
+    fn rust_get_test_int() -> std::libc::intptr_t;
+}
+
+trait A {
+    fn foo() {
+        unsafe {
+            rust_get_test_int(); //~ ERROR invoking non-Rust fn
+        }
+    }
+}
+
+fn main() {
+}
index 5f769fceded9cdbfe8e7067d3d3d3cbce0a5af46..84d9c2c66cc6efc06fb8cb5b6103c13700c0bba6 100644 (file)
@@ -15,7 +15,7 @@
 // its numerical value.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break _zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print b
index 8c19225311a2166aa541a781aeabfdfe0c4b9007..b02b4be2fd9c03c34f3872ab7915763d66f5a6ee 100644 (file)
@@ -12,7 +12,7 @@
 // its numerical value.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print *bool_ref
index b947cd80984e4b39206ce0a0f5062ce652723395..2461eb4887eb5720ac277379bc7e469983ccb44c 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 6ac0239022520cb43c6f276a3f796eb2b2a6bfef..9a9e71c7068c40e460dee7d64fe7e286fe8e2d22 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index c91f64973ad81bdcc890ca17f1d561e100566138..35a222ffd044214aa1a0eaacae442a8f5935fb2b 100644 (file)
@@ -12,7 +12,7 @@
 // its numerical value.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print *bool_ref
index 75a47a0d8fea71ca0ade87199a31038dba668276..42f7ffd8777bc75aaa84ced1d2d3d1955adb81b2 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 493cd2ab3e15c4b40702655d6f92a805662cef40..bcf73bae5ec439965cc71b9e69b807d86426a162 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 50ac34cbcf6e191275a30a1eef48949aea8b733d..ac295783c9f94146906b2c90bb2002d71a795d76 100644 (file)
@@ -12,7 +12,7 @@
 // its numerical value.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print *bool_ref
index 1a87392e6af5a66c8a52384b1f581b6393d24a4c..60ff5f789a8fbd4b53b849c2fbacf58fdfa5d1c8 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break _zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print *a
index 03be8f7f220bf08d07508d2db6278a5032235e67..e996b249d369ee434dde633dc902264120579ee9 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index b08f549e129262d91ec7e74bafd74b3c4617af28..aa2a88afc465a9d5e6c4d22c7a39da4d2a40d2dd 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index da9c79a00ed470692dabcb3e9ad5bcd30d6cedf7..45f8c134f2c2ad993ce2df52bf5646dbb9d873dd 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 6e381c74a339e963e5d296458cad27a5016a04c3..75e65178546c5e82340c71b0c5ed1643bed1a375 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 8baca2baa4292c2c310378538b445640665c0f9b..d3e27c85b745af044589d162c3551803dcf0c65d 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index a60c28cedb4a0166e35ee0d56352905eb515ff84..f1bb42ac5f0f4775a781e9f470547a3e302e1106 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 37ad6f173d181740d2dc4b862cfa583d3ea9d8d5..83a2c456ae69784de3fe5ad601766ed4b407c405 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 63b46875a4947e99ee6f92d141c882702a834c3b..49bbb7ed2635a2aee6dc93099450fec71cd1b60d 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 424e195e681cc63995605de7ec008127a9773e45..8115d29857030b9849fb9ab99ab0720a633d9fd1 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index de556bb17728b0dbfa808fdb6de8989acbc1a16e..a00e1318967d224e550e4c0f2fa5c25b0aeab20d 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 5a410ef6462caf40fd9a80c3b9859f89f4b8083c..6ae7b027075da4f8b45510c70ab49ce3c0d9a00e 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
@@ -43,4 +43,4 @@ fn fun(x: int, y: bool) -> (int, bool) {
     (x, y)
 }
 
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
index 1bde5acd9f63e846e691637e51e73db1014c9544..22f565ceee5e3120e727db1e85b06cec212673c8 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 3151562f3f294ec8affba48e1e4e8a6dbea9bb22..051b2054219796b5a3562a65a46b86a010ae94fe 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 131f89c5a6da825c586726effb5f87d9625ca6a5..f97a3cea5660d4353987eb5788070b0f02e2e6fd 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index f7ecad0b095e7b6b8d1a1f2cafed62bffd1d52c9..8e82f0f27b9f98affcd128b99be787f5df5c582e 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STRUCT
index 6a8f81aa843024211e4920cc429ebd8a973a366a..81b12fe60ae3d7f5fabb6180d65b1ad1c6055b65 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index efc250018c116a6cb02868e06cc68ce9ee6b5c2f..cf6286e9541e8a2b6276e90dace61f7add838b7f 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 9dd6d1ef173df35359aa17cc1612d95fe65edca7..8523a947aac10ae6cb8f98b78fdd4fc1331ee719 100644 (file)
@@ -11,7 +11,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index b97fa7b636b397d2d4e128248d6a4ff0bf60de2b..0b9f93505476f6d5069243b482c4b30d24374433 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index ed2f9e1a0c460159e43e83dfb20fad223ab5a4eb..0a2cb953f007cc5930489de8b37cfe4f54ac719a 100644 (file)
@@ -11,7 +11,7 @@
 // xfail-win32
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // FIRST ITERATION
index cc637f55fee8a95df7c6f3445ac83227220f0018..89fd84daede532c6be9fbcb6fae089e897d552a2 100644 (file)
@@ -11,7 +11,7 @@
 // xfail-win32
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // BEFORE if
index 8af674d5ebd88ab3911a941796b2f563105bb4bb..96da78a9192983cf69aea31f57807d4f48ec1c80 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index fe57f1f588e127dfbc227b88ccb0ae7134b8579a..1216e9fde1e0ae50bd73b8799634e15125c0b0f8 100644 (file)
@@ -11,7 +11,7 @@
 // xfail-win32
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 101b076a460939e8c37d1e26ed6f46ccbbf09969..744c77b27358c197571eed6a5269347b6f597aee 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 6031a0ac714d0d5a12d42738d9fd7f61362e93fb..beb9211cc3291ac4673767658636e9147e6a1d3b 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // FIRST ITERATION
index e167d7637adcaa4adde11c7bbbc658da42c3a43c..6d8ca457efef5fa00c4a4e6de997b2685d098c92 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 2a3071ba496cef596d794c5932f1b4b6b18f17a5..80010bdd2628e6b95b502646f027ed3495d24c07 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // FIRST ITERATION
index 1223786eb18a9ffadfb6a75a98e22a61528964d6..9e87eee692dc2b880d29bcf8333d5901e431cca3 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index ea2a7f0d94a3448cd1dfed7648ce607e9a3b5b8c..652561c6aeffc107ffc07e893fe9860f5f35a522 100644 (file)
@@ -11,7 +11,7 @@
 // xfail-win32
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STRUCT EXPRESSION
index 99452dc255aff9c8648843b4608e9313295f72dd..87aa3d1dfc159e8249f941af6fcfea5fd6af8743 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 35df9454e1063315c094278e49fc0a7ad5d49520..d4ec7094e8c95a2f4ce82dcf5f2081fb2a6bce0b 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index e007f012ce2f6fb064346dd25ee53dadeb5022ae..9ea713c29823c0725591443d2fe9e12d5e5d065e 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index c68b4e7deedf4a5d0ea711e71a9c51a543aa18fc..d428d230d45c01486db7087561d0bf007cf840bc 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index 4c793a6d9c77ee45916a68eebc1260cc049f8a5b..63fd6c996ffa0793f0f4168088a1a1ab5434be8c 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index 5711c945b65caebb66d90822c51babc3b387a859..249c3a073a27bd969d17b31e58575c7f5846948f 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index c2f3a7f4324b33f6a963214739e3baf6d47457ac..07a29f3ece338e9c0dd11e0291fef48d20fbc3b7 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index e14880ae1a0d9ce3c7c990a5699dd9de7633b079..d4354709a86eefd14e8dbfd478f4ce81cba3c2cb 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index 32b3da074115eb4065a0fe12249e0c91ae690501..881e2547cfc68df64898ac4f68158bd94d0d92e1 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index be26af4fe2f86817c4c672d542abe55cca599cc6..880954ce5316771f5d8538157196013a12014f08 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 739d3aa78f45b6c969764a52280194486fcdcdaa..273ca255061c57e48702e9cea67734010f9a5871 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 94e5b706ac60ac3651223631763dc2dc4bab274d..9dc4edfb1599ba609f967443a566625d12bda59b 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index a75f4ff0086a5a40efe5709e63a2352cdcc43b56..5c0ffe24f0eaa7c818cdf73093dccb0c64ad47aa 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 90033b9c4e6e49cab72aa0f614a9d7c8e4154d4d..47e4a26ab4ba29d892c518161256aba0a9263155 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 203f6595a0492c0c8c9825b381672d803c107d82..8d3fc4babb86bfe02bdd0be2674c82f195d80aee 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
diff --git a/src/test/debug-info/recursive-struct.rs b/src/test/debug-info/recursive-struct.rs
new file mode 100644 (file)
index 0000000..b8a43d6
--- /dev/null
@@ -0,0 +1,314 @@
+// 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.
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print pretty off
+// debugger:rbreak zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print stack_unique.value
+// check:$1 = 0
+// debugger:print stack_unique.next.val->value
+// check:$2 = 1
+
+// debugger:print unique_unique->value
+// check:$3 = 2
+// debugger:print unique_unique->next.val->value
+// check:$4 = 3
+
+// debugger:print box_unique->val.value
+// check:$5 = 4
+// debugger:print box_unique->val.next.val->value
+// check:$6 = 5
+
+// debugger:print vec_unique[0].value
+// check:$7 = 6.5
+// debugger:print vec_unique[0].next.val->value
+// check:$8 = 7.5
+
+// debugger:print borrowed_unique->value
+// check:$9 = 8.5
+// debugger:print borrowed_unique->next.val->value
+// check:$10 = 9.5
+
+// MANAGED
+// debugger:print stack_managed.value
+// check:$11 = 10
+// debugger:print stack_managed.next.val->val.value
+// check:$12 = 11
+
+// debugger:print unique_managed->val.value
+// check:$13 = 12
+// debugger:print unique_managed->val.next.val->val.value
+// check:$14 = 13
+
+// debugger:print box_managed->val.value
+// check:$15 = 14
+// debugger:print box_managed->val.next.val->val.value
+// check:$16 = 15
+
+// debugger:print vec_managed[0].value
+// check:$17 = 16.5
+// debugger:print vec_managed[0].next.val->val.value
+// check:$18 = 17.5
+
+// debugger:print borrowed_managed->value
+// check:$19 = 18.5
+// debugger:print borrowed_managed->next.val->val.value
+// check:$20 = 19.5
+
+// LONG CYCLE
+// debugger:print long_cycle1.value
+// check:$21 = 20
+// debugger:print long_cycle1.next->value
+// check:$22 = 21
+// debugger:print long_cycle1.next->next->value
+// check:$23 = 22
+// debugger:print long_cycle1.next->next->next->value
+// check:$24 = 23
+
+// debugger:print long_cycle2.value
+// check:$25 = 24
+// debugger:print long_cycle2.next->value
+// check:$26 = 25
+// debugger:print long_cycle2.next->next->value
+// check:$27 = 26
+
+// debugger:print long_cycle3.value
+// check:$28 = 27
+// debugger:print long_cycle3.next->value
+// check:$29 = 28
+
+// debugger:print long_cycle4.value
+// check:$30 = 29.5
+
+// debugger:print (*****long_cycle_w_anonymous_types).value
+// check:$31 = 30
+
+// debugger:print (*****((*****long_cycle_w_anonymous_types).next.val)).value
+// check:$32 = 31
+
+// debugger:continue
+
+#[allow(unused_variable)];
+
+enum Opt<T> {
+    Empty,
+    Val { val: T }
+}
+
+struct UniqueNode<T> {
+    next: Opt<~UniqueNode<T>>,
+    value: T
+}
+
+struct ManagedNode<T> {
+    next: Opt<@ManagedNode<T>>,
+    value: T
+}
+
+struct LongCycle1<T> {
+    next: ~LongCycle2<T>,
+    value: T,
+}
+
+struct LongCycle2<T> {
+    next: ~LongCycle3<T>,
+    value: T,
+}
+
+struct LongCycle3<T> {
+    next: ~LongCycle4<T>,
+    value: T,
+}
+
+struct LongCycle4<T> {
+    next: Option<~LongCycle1<T>>,
+    value: T,
+}
+
+struct LongCycleWithAnonymousTypes {
+    next: Opt<~~~~~LongCycleWithAnonymousTypes>,
+    value: uint,
+}
+
+// This test case makes sure that recursive structs are properly described. The Node structs are
+// generic so that we can have a new type (that newly needs to be described) for the different
+// cases. The potential problem with recursive types is that the DI generation algorithm gets
+// trapped in an endless loop. To make sure, we actually test this in the different cases, we have
+// to operate on a new type each time, otherwise we would just hit the DI cache for all but the
+// first case.
+
+// The different cases below (stack_*, unique_*, box_*, etc) are set up so that the type description
+// algorithm will enter the type reference cycle that is created by a recursive definition from a
+// different context each time.
+
+// The "long cycle" cases are constructed to span a longer, indirect recursion cycle between types.
+// The different locals will cause the DI algorithm to enter the type reference cycle at different
+// points.
+
+fn main() {
+    let stack_unique: UniqueNode<u16> = UniqueNode {
+        next: Val {
+            val: ~UniqueNode {
+                next: Empty,
+                value: 1_u16,
+            }
+        },
+        value: 0_u16,
+    };
+
+    let unique_unique: ~UniqueNode<u32> = ~UniqueNode {
+        next: Val {
+            val: ~UniqueNode {
+                next: Empty,
+                value: 3,
+            }
+        },
+        value: 2,
+    };
+
+    let box_unique: @UniqueNode<u64> = @UniqueNode {
+        next: Val {
+            val: ~UniqueNode {
+                next: Empty,
+                value: 5,
+            }
+        },
+        value: 4,
+    };
+
+    let vec_unique: [UniqueNode<f32>, ..1] = [UniqueNode {
+        next: Val {
+            val: ~UniqueNode {
+                next: Empty,
+                value: 7.5,
+            }
+        },
+        value: 6.5,
+    }];
+
+    let borrowed_unique: &UniqueNode<f64> = &UniqueNode {
+        next: Val {
+            val: ~UniqueNode {
+                next: Empty,
+                value: 9.5,
+            }
+        },
+        value: 8.5,
+    };
+
+    let stack_managed: ManagedNode<u16> = ManagedNode {
+        next: Val {
+            val: @ManagedNode {
+                next: Empty,
+                value: 11,
+            }
+        },
+        value: 10,
+    };
+
+    let unique_managed: ~ManagedNode<u32> = ~ManagedNode {
+        next: Val {
+            val: @ManagedNode {
+                next: Empty,
+                value: 13,
+            }
+        },
+        value: 12,
+    };
+
+    let box_managed: @ManagedNode<u64> = @ManagedNode {
+        next: Val {
+            val: @ManagedNode {
+                next: Empty,
+                value: 15,
+            }
+        },
+        value: 14,
+    };
+
+    let vec_managed: [ManagedNode<f32>, ..1] = [ManagedNode {
+        next: Val {
+            val: @ManagedNode {
+                next: Empty,
+                value: 17.5,
+            }
+        },
+        value: 16.5,
+    }];
+
+    let borrowed_managed: &ManagedNode<f64> = &ManagedNode {
+        next: Val {
+            val: @ManagedNode {
+                next: Empty,
+                value: 19.5,
+            }
+        },
+        value: 18.5,
+    };
+
+    // LONG CYCLE
+    let long_cycle1: LongCycle1<u16> = LongCycle1 {
+        next: ~LongCycle2 {
+            next: ~LongCycle3 {
+                next: ~LongCycle4 {
+                    next: None,
+                    value: 23,
+                },
+                value: 22,
+            },
+            value: 21
+        },
+        value: 20
+    };
+
+    let long_cycle2: LongCycle2<u32> = LongCycle2 {
+        next: ~LongCycle3 {
+            next: ~LongCycle4 {
+                next: None,
+                value: 26,
+            },
+            value: 25,
+        },
+        value: 24
+    };
+
+    let long_cycle3: LongCycle3<u64> = LongCycle3 {
+        next: ~LongCycle4 {
+            next: None,
+            value: 28,
+        },
+        value: 27,
+    };
+
+    let long_cycle4: LongCycle4<f32> = LongCycle4 {
+        next: None,
+        value: 29.5,
+    };
+
+    // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the
+    // `~` chain.
+    let long_cycle_w_anonymous_types = ~~~~~LongCycleWithAnonymousTypes {
+        next: Val {
+            val: ~~~~~LongCycleWithAnonymousTypes {
+                next: Empty,
+                value: 31,
+            }
+        },
+        value: 30
+    };
+
+    zzz();
+}
+
+fn zzz() {()}
+
index 426d2f46e6b046b93ce08b642f722272c95da98f..53b2e9ee21de1692387cba6a6ef2c6a2b55d606e 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index 16a028808e7ccffa12f85122db8a929957e482ae..47f589307601f2ed24c334d2c08f8dc27bdd9e06 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STACK BY REF
index a6a7b34c87b1d3ab0744b4e8a7ed230bb504f8e3..adc240e40d5a9dd52618b96c943b12b835232043 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 9018e24691e57ebc21a6c408ad5d5bc7e70a3eba..acc8cf3b654d6ad0fadf548895da507909574a6d 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 11e890c44fa962bffc6190be942a92394c82980c..fbcee4f0ae2d6876e235cb9327b1dc7c7e11ad10 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
index 01cc163d7aad0ba4fb088526dfeba06a715887e6..a47472af1efa6eba7304d50d46b7462498c2eb3f 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index ee65e4dcb200a3835dca620957d71ea3544b05fe..1e4c53427b23a5df672060603697b1ade5379e46 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 5cf0bbdc8cf2e8c5bba962928410c413402ffd3b..0d1ce28094a5acff7ce80b02ec65a6d1fc9190c8 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // STRUCT
index 8542dd867f4a2d7810f81865c1885bae3238b6d3..a821ce21d50bfa26a1d13d66c714c7cb20c61964 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 307d141c3e27ebf5014504532d8f0afea977cb24..f1690fba354f0870905d46b42c6e4ea874306518 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index fe6845a9077c9a14f98faa420ed36de46aa57084..acd2526a68d6e66e9fa1833087cadd2599f8d38f 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 2dc1bfbf236c1ed23f7abbafb09049467134ad19..8994a582b58fc7cabd337939d60a6037e1a1aac7 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print simple
index 2d666bf4cf5aa7d483c879144b234f209e67735c..1f6e6992e2795af4de102bbb8f911f3023816bb0 100644 (file)
@@ -11,7 +11,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 
 // debugger:finish
diff --git a/src/test/debug-info/trait-pointers.rs b/src/test/debug-info/trait-pointers.rs
new file mode 100644 (file)
index 0000000..db02e69
--- /dev/null
@@ -0,0 +1,33 @@
+// 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.
+
+// compile-flags:-Z extra-debug-info
+// debugger:run
+
+#[allow(unused_variable)];
+
+trait Trait {
+    fn method(&self) -> int { 0 }
+}
+
+struct Struct {
+    a: int,
+    b: float
+}
+
+impl Trait for Struct {}
+
+// There is no real test here yet. Just make sure that it compiles without crashing.
+fn main() {
+    let stack_struct = Struct { a:0, b: 1.0 };
+    let reference: &Trait = &stack_struct as &Trait;
+    let managed: @Trait = @Struct { a:2, b: 3.0 } as @Trait;
+    let unique: ~Trait = ~Struct { a:2, b: 3.0 } as ~Trait;
+}
index e5844cd19a719f5beb3b36216ca4f2c8c611f3e0..25a08b3f57a777119d8b403c6f8eb1ab3f0c0c99 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 8a50760bcc27fcf5ff79526b43207fdfb3716de1..14dd671bb945e7c7501556690ff7253af581b8e6 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 762b8dcb38f45585205b9571e7343810fda1f6f5..63a74ecbe4a0895e9e346971bfd2fb8b78bba83d 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 29950e6c76669507c9028508e8441bcf95c40038..fef6b449a9bdeea88894c921b062917caabea42c 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 8c085b1c62bc07a3c3bf64cd5f9fab0fbefea8da..0995cec11a3b30a9aed1dfed83dab35f44f42746 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 002bfbd2242ae9089f41c316e999873eab4a89cf..b20f40378d3964f7430097adf2313cae94f9a0f6 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index cd20209ddfd0263594940b83715225ae69ad98eb..920052eb80ee70a1cf819b975514ab603dd76b2f 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 01839ea783533b8765d29eb9df358f888c6881ca..f113c6ea4be77210d2cab80e39ec1700ed5a4641 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 3ce7d6fd89bddbc40cc584019443839c5c1e7afb..e16539d3396a7663c0f6358c9aa33d0843a5bfa7 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 
index 95679f3a6163be1aa53954344c13f72b7defbb54..9e5fb9236db61545c17cb6ecfc756c7875e402e6 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print empty.size_in_bytes
index 0dc52c7b220e528e3efe3254d32c60095eae15e8..bc10b5ec8b70c3cef3cbbd1273e76106b09cc312 100644 (file)
@@ -10,7 +10,7 @@
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
 // debugger:run
 // debugger:finish
 // debugger:print a
diff --git a/src/test/pretty/empty-impl.pp b/src/test/pretty/empty-impl.pp
new file mode 100644 (file)
index 0000000..af401bd
--- /dev/null
@@ -0,0 +1,5 @@
+trait X { }
+impl X for uint;
+
+trait Y { }
+impl Y for uint;
diff --git a/src/test/pretty/empty-impl.rs b/src/test/pretty/empty-impl.rs
new file mode 100644 (file)
index 0000000..af401bd
--- /dev/null
@@ -0,0 +1,5 @@
+trait X { }
+impl X for uint;
+
+trait Y { }
+impl Y for uint;
diff --git a/src/test/run-fail/binop-fail-3.rs b/src/test/run-fail/binop-fail-3.rs
new file mode 100644 (file)
index 0000000..150544f
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:quux
+fn foo() -> ! { fail!("quux"); }
+fn main() { foo() == foo(); }
index aba23e53282c788e7a4902ca5b3c54fc5a644e87..fb4ffb2c3c15db232790e0af30e9b6f3f771fda7 100644 (file)
@@ -24,15 +24,13 @@ struct E { a: int, b: int }
 
 #[deriving(Zero)]
 struct Lots {
-    c: Option<util::NonCopyable>,
     d: u8,
     e: char,
     f: float,
     g: (f32, char),
-    h: ~[util::NonCopyable],
-    i: @mut (int, int),
-    j: bool,
-    k: (),
+    h: @mut (int, int),
+    i: bool,
+    j: (),
 }
 
 fn main() {
diff --git a/src/test/run-pass/glob-std.rs b/src/test/run-pass/glob-std.rs
new file mode 100644 (file)
index 0000000..e0c0fdd
--- /dev/null
@@ -0,0 +1,203 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast windows doesn't like 'extern mod extra'
+
+extern mod extra;
+
+use extra::glob::*;
+use extra::tempfile;
+use std::unstable::finally::Finally;
+use std::{io, os, unstable};
+
+pub fn main() {
+    fn change_then_remove(p: &Path, f: &fn()) {
+        assert!(os::change_dir(p));
+
+        do f.finally {
+            os::remove_dir_recursive(p);
+        }
+    }
+
+    fn mk_file(path: &str, directory: bool) {
+        if directory {
+            os::make_dir(&Path(path), 0xFFFF);
+        } else {
+            io::mk_file_writer(&Path(path), [io::Create]);
+        }
+    }
+
+    fn abs_path(path: &str) -> Path {
+        os::getcwd().push_many(Path(path).components)
+    }
+
+    fn glob_vec(pattern: &str) -> ~[Path] {
+        glob(pattern).collect()
+    }
+
+    let root = tempfile::mkdtemp(&os::tmpdir(), "glob-tests");
+    let root = root.expect("Should have created a temp directory");
+
+    do change_then_remove(&root) {
+        mk_file("aaa", true);
+        mk_file("aaa/apple", true);
+        mk_file("aaa/orange", true);
+        mk_file("aaa/tomato", true);
+        mk_file("aaa/tomato/tomato.txt", false);
+        mk_file("aaa/tomato/tomoto.txt", false);
+        mk_file("bbb", true);
+        mk_file("bbb/specials", true);
+        mk_file("bbb/specials/!", false);
+
+        // windows does not allow `*` or `?` characters to exist in filenames
+        if os::consts::FAMILY != os::consts::windows::FAMILY {
+            mk_file("bbb/specials/*", false);
+            mk_file("bbb/specials/?", false);
+        }
+
+        mk_file("bbb/specials/[", false);
+        mk_file("bbb/specials/]", false);
+        mk_file("ccc", true);
+        mk_file("xyz", true);
+        mk_file("xyz/x", false);
+        mk_file("xyz/y", false);
+        mk_file("xyz/z", false);
+
+        assert_eq!(glob_vec(""), ~[]);
+        assert_eq!(glob_vec("."), ~[]);
+        assert_eq!(glob_vec(".."), ~[]);
+
+        assert_eq!(glob_vec("aaa"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("aaa/"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("a"), ~[]);
+        assert_eq!(glob_vec("aa"), ~[]);
+        assert_eq!(glob_vec("aaaa"), ~[]);
+
+        assert_eq!(glob_vec("aaa/apple"), ~[abs_path("aaa/apple")]);
+        assert_eq!(glob_vec("aaa/apple/nope"), ~[]);
+
+        // windows should support both / and \ as directory separators
+        if os::consts::FAMILY == os::consts::windows::FAMILY {
+            assert_eq!(glob_vec("aaa\\apple"), ~[abs_path("aaa/apple")]);
+        }
+
+        assert_eq!(glob_vec("???/"), ~[
+            abs_path("aaa"),
+            abs_path("bbb"),
+            abs_path("ccc"),
+            abs_path("xyz")]);
+
+        assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), ~[
+            abs_path("aaa/tomato/tomato.txt"),
+            abs_path("aaa/tomato/tomoto.txt")]);
+
+        assert_eq!(glob_vec("xyz/?"), ~[
+            abs_path("xyz/x"),
+            abs_path("xyz/y"),
+            abs_path("xyz/z")]);
+
+        assert_eq!(glob_vec("a*"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("*a*"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("a*a"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("aaa*"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("*aaa"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("*aaa*"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("*a*a*a*"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("aaa*/"), ~[abs_path("aaa")]);
+
+        assert_eq!(glob_vec("aaa/*"), ~[
+            abs_path("aaa/apple"),
+            abs_path("aaa/orange"),
+            abs_path("aaa/tomato")]);
+
+        assert_eq!(glob_vec("aaa/*a*"), ~[
+            abs_path("aaa/apple"),
+            abs_path("aaa/orange"),
+            abs_path("aaa/tomato")]);
+
+        assert_eq!(glob_vec("*/*/*.txt"), ~[
+            abs_path("aaa/tomato/tomato.txt"),
+            abs_path("aaa/tomato/tomoto.txt")]);
+
+        assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), ~[
+            abs_path("aaa/tomato/tomato.txt"),
+            abs_path("aaa/tomato/tomoto.txt")]);
+
+        assert_eq!(glob_vec("aa[a]"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("aa[abc]"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("a[bca]a"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("aa[b]"), ~[]);
+        assert_eq!(glob_vec("aa[xyz]"), ~[]);
+        assert_eq!(glob_vec("aa[]]"), ~[]);
+
+        assert_eq!(glob_vec("aa[!b]"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("aa[!bcd]"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("a[!bcd]a"), ~[abs_path("aaa")]);
+        assert_eq!(glob_vec("aa[!a]"), ~[]);
+        assert_eq!(glob_vec("aa[!abc]"), ~[]);
+
+        assert_eq!(glob_vec("bbb/specials/[[]"), ~[abs_path("bbb/specials/[")]);
+        assert_eq!(glob_vec("bbb/specials/!"), ~[abs_path("bbb/specials/!")]);
+        assert_eq!(glob_vec("bbb/specials/[]]"), ~[abs_path("bbb/specials/]")]);
+
+        if os::consts::FAMILY != os::consts::windows::FAMILY {
+            assert_eq!(glob_vec("bbb/specials/[*]"), ~[abs_path("bbb/specials/*")]);
+            assert_eq!(glob_vec("bbb/specials/[?]"), ~[abs_path("bbb/specials/?")]);
+        }
+
+        if os::consts::FAMILY == os::consts::windows::FAMILY {
+
+            assert_eq!(glob_vec("bbb/specials/[![]"), ~[
+                abs_path("bbb/specials/!"),
+                abs_path("bbb/specials/]")]);
+
+            assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
+                abs_path("bbb/specials/!"),
+                abs_path("bbb/specials/[")]);
+
+            assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
+                abs_path("bbb/specials/["),
+                abs_path("bbb/specials/]")]);
+
+        } else {
+
+            assert_eq!(glob_vec("bbb/specials/[![]"), ~[
+                abs_path("bbb/specials/!"),
+                abs_path("bbb/specials/*"),
+                abs_path("bbb/specials/?"),
+                abs_path("bbb/specials/]")]);
+
+            assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
+                abs_path("bbb/specials/!"),
+                abs_path("bbb/specials/*"),
+                abs_path("bbb/specials/?"),
+                abs_path("bbb/specials/[")]);
+
+            assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
+                abs_path("bbb/specials/*"),
+                abs_path("bbb/specials/?"),
+                abs_path("bbb/specials/["),
+                abs_path("bbb/specials/]")]);
+
+            assert_eq!(glob_vec("bbb/specials/[!*]"), ~[
+                abs_path("bbb/specials/!"),
+                abs_path("bbb/specials/?"),
+                abs_path("bbb/specials/["),
+                abs_path("bbb/specials/]")]);
+
+            assert_eq!(glob_vec("bbb/specials/[!?]"), ~[
+                abs_path("bbb/specials/!"),
+                abs_path("bbb/specials/*"),
+                abs_path("bbb/specials/["),
+                abs_path("bbb/specials/]")]);
+
+        }
+    };
+}
index 3f0c7e0704161c1d1170ea2faa2013fc173e729f..351bad193da2dfc85249039f122df30e7a2241c2 100644 (file)
 
 // xfail-fast: check-fast screws up repr paths
 
+#[deny(warnings)];
+
 use std::fmt;
+use std::rt::io::Decorator;
+use std::rt::io::mem::MemWriter;
+use std::rt::io;
+use std::rt::io::Writer;
+use std::str;
 
 struct A;
 struct B;
@@ -80,6 +87,7 @@ pub fn main() {
     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");
+    t!(format!("{foo_bar}", foo_bar=1), "1");
 
     // Methods should probably work
     t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
@@ -226,16 +234,20 @@ pub fn main() {
     let a = ~3;
     format!("{:?}", a);
     format!("{:?}", a);
+
+    // make sure that format! doesn't cause spurious unused-unsafe warnings when
+    // it's inside of an outer unsafe block
+    unsafe {
+        let a: int = ::std::cast::transmute(3u);
+        format!("{}", a);
+    }
+
+    test_format_args();
 }
 
 // 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);
     {
@@ -259,3 +271,20 @@ fn test_print() {
     println!("this is a {}", "test");
     println!("{foo}", foo="bar");
 }
+
+// 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_format_args() {
+    let mut buf = MemWriter::new();
+    {
+        let w = &mut buf as &mut io::Writer;
+        format_args!(|args| { fmt::write(w, args) }, "{}", 1);
+        format_args!(|args| { fmt::write(w, args) }, "test");
+        format_args!(|args| { fmt::write(w, args) }, "{test}", test=3);
+    }
+    let s = str::from_utf8_owned(buf.inner());
+    t!(s, "1test3");
+
+    let s = format_args!(fmt::format, "hello {}", "world");
+    t!(s, "hello world");
+}
index e0f216c667cbc07e52e7b74505b5b116b5adb767..6df859d938b54f5f6566a224261d83d45f191fcc 100644 (file)
@@ -62,7 +62,7 @@ enum Result {
 }
 
 priv fn parse_bulk(io: @io::Reader) -> Result {
-    match int::from_str(chop(io.read_line())) {
+    match from_str::<int>(chop(io.read_line())) {
     None => fail!(),
     Some(-1) => Nil,
     Some(len) if len >= 0 => parse_data(len as uint, io),
@@ -71,7 +71,7 @@ enum Result {
 }
 
 priv fn parse_multi(io: @io::Reader) -> Result {
-    match int::from_str(chop(io.read_line())) {
+    match from_str::<int>(chop(io.read_line())) {
     None => fail!(),
     Some(-1) => Nil,
     Some(0) => List(~[]),
@@ -81,7 +81,7 @@ enum Result {
 }
 
 priv fn parse_int(io: @io::Reader) -> Result {
-    match int::from_str(chop(io.read_line())) {
+    match from_str::<int>(chop(io.read_line())) {
     None => fail!(),
     Some(i) => Int(i)
     }
diff --git a/src/test/run-pass/issue-9110.rs b/src/test/run-pass/issue-9110.rs
new file mode 100644 (file)
index 0000000..56f87f5
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! silly_macro(
+    () => (
+        pub mod Qux {
+            pub struct Foo { x : u8 }
+            pub fn bar(_foo : Foo) {}
+        }
+    );
+)
+
+silly_macro!()
+
+fn main() {}
diff --git a/src/test/run-pass/issue-9123.rs b/src/test/run-pass/issue-9123.rs
new file mode 100644 (file)
index 0000000..73a14de
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast windows doesn't like aux-build
+// aux-build:issue_9123.rs
+
+extern mod issue_9123;
+
+pub fn main() {}
diff --git a/src/test/run-pass/lint-cstack.rs b/src/test/run-pass/lint-cstack.rs
new file mode 100644 (file)
index 0000000..b9e61b4
--- /dev/null
@@ -0,0 +1,27 @@
+// 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::libc;
+
+extern {
+    fn rust_get_test_int() -> libc::intptr_t;
+}
+
+trait A {
+    #[fixed_stack_segment]
+    fn foo() {
+        unsafe {
+            rust_get_test_int();
+        }
+    }
+}
+
+fn main() {
+}
index 06d0b4a80ea01261a51e51679671a4f52840ecf8..1d9d8fa219fc33eb0167349a7912adf13b245817 100644 (file)
@@ -14,7 +14,7 @@ pub fn main() {
     // sometimes we have had trouble finding
     // the right type for f, as we unified
     // bot and u32 here
-    let f = match uint::from_str("1234") {
+    let f = match from_str::<uint>("1234") {
         None => return (),
         Some(num) => num as u32
     };
diff --git a/src/test/run-pass/num-range-rev.rs b/src/test/run-pass/num-range-rev.rs
deleted file mode 100644 (file)
index ea7d4a6..0000000
+++ /dev/null
@@ -1,126 +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 std::int;
-use std::uint;
-
-fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool {
-    range(lo, hi).advance(it)
-}
-
-fn int_range(lo: int,  hi: int, it: &fn(int) -> bool) -> bool {
-    range(lo, hi).advance(it)
-}
-
-fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool {
-    range(lo, hi).invert().advance(it)
-}
-
-fn int_range_rev(hi: int,  lo: int, it: &fn(int) -> bool) -> bool {
-    range(lo, hi).invert().advance(it)
-}
-
-fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {
-    int::range_step(a, b, step, it)
-}
-
-fn uint_range_step(a: uint, b: uint, step: int, it: &fn(uint) -> bool) -> bool {
-    uint::range_step(a, b, step, it)
-}
-
-
-pub fn main() {
-    // int and uint have same result for
-    //   Sum{100 > i >= 2} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99
-    let mut sum = 0u;
-    do uint_range_rev(100, 2) |i| {
-        sum += i;
-        true
-    };
-    assert_eq!(sum, 4949);
-
-    let mut sum = 0i;
-    do int_range_rev(100, 2) |i| {
-        sum += i;
-        true
-    };
-    assert_eq!(sum, 4949);
-
-
-    // elements are visited in correct order
-    let primes = [2,3,5,7,11];
-    let mut prod = 1i;
-    do uint_range_rev(5, 0) |i| {
-        printfln!("uint 4 downto 0: %u", i);
-        prod *= int::pow(primes[i], i);
-        true
-    };
-    assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1);
-    let mut prod = 1i;
-    do int_range_rev(5, 0) |i| {
-        printfln!("int 4 downto 0: %d", i);
-        prod *= int::pow(primes[i], i as uint);
-        true
-    };
-    assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1);
-
-
-    // range and range_rev are symmetric.
-    let mut sum_up = 0u;
-    do uint_range(10, 30) |i| {
-        sum_up += i;
-        true
-    };
-    let mut sum_down = 0u;
-    do uint_range_rev(30, 10) |i| {
-        sum_down += i;
-        true
-    };
-    assert_eq!(sum_up, sum_down);
-
-    let mut sum_up = 0;
-    do int_range(-20, 10) |i| {
-        sum_up += i;
-        true
-    };
-    let mut sum_down = 0;
-    do int_range_rev(10, -20) |i| {
-        sum_down += i;
-        true
-    };
-    assert_eq!(sum_up, sum_down);
-
-
-    // empty ranges
-    do int_range_rev(10, 10) |_| {
-        fail!("range should be empty when start == stop");
-        true
-    };
-
-    do uint_range_rev(0, 1) |_| {
-        fail!("range should be empty when start-1 underflows");
-        true
-    };
-
-    // range iterations do not wrap/underflow
-    let mut uflo_loop_visited = ~[];
-    do int_range_step(int::min_value+15, int::min_value, -4) |x| {
-        uflo_loop_visited.push(x - int::min_value);
-        true
-    };
-    assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]);
-
-    let mut uflo_loop_visited = ~[];
-    do uint_range_step(uint::min_value+15, uint::min_value, -4) |x| {
-        uflo_loop_visited.push(x - uint::min_value);
-        true
-    };
-    assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]);
-}
diff --git a/src/test/run-pass/num-range.rs b/src/test/run-pass/num-range.rs
deleted file mode 100644 (file)
index 7376ede..0000000
+++ /dev/null
@@ -1,132 +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 std::int;
-use std::uint;
-
-fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool {
-    range(lo, hi).advance(it)
-}
-
-fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool {
-    range(lo, hi).advance(it)
-}
-
-fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {
-    int::range_step(a, b, step, it)
-}
-
-fn uint_range_step(a: uint, b: uint, s: int, it: &fn(uint) -> bool) -> bool {
-    uint::range_step(a, b, s, it)
-}
-
-pub fn main() {
-    println("num-range start");
-    // int and uint have same result for
-    //   Sum{2 <= i < 100} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99
-    let mut sum = 0u;
-    do uint_range(2, 100) |i| {
-        sum += i;
-        true
-    };
-    assert_eq!(sum, 4949);
-
-    let mut sum = 0i;
-    do int_range(2, 100) |i| {
-        sum += i;
-        true
-    };
-    assert_eq!(sum, 4949);
-
-
-    // elements are visited in correct order
-    let primes = [2,3,5,7];
-    let mut prod = 1i;
-    do uint_range(0, 4) |i| {
-        prod *= int::pow(primes[i], i);
-        true
-    };
-    assert_eq!(prod, 1*3*5*5*7*7*7);
-    let mut prod = 1i;
-    do int_range(0, 4) |i| {
-        prod *= int::pow(primes[i], i as uint);
-        true
-    };
-    assert_eq!(prod, 1*3*5*5*7*7*7);
-
-
-    // empty ranges
-    do int_range(10, 10) |_| {
-        fail!("range should be empty when start == stop");
-        true
-    };
-
-    do uint_range(10, 10) |_| {
-        fail!("range should be empty when start == stop");
-        true
-    };
-
-
-    // range iterations do not wrap/overflow
-    let mut oflo_loop_visited = ~[];
-    do uint_range_step(uint::max_value-15, uint::max_value, 4) |x| {
-        oflo_loop_visited.push(uint::max_value - x);
-        true
-    };
-    assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]);
-
-    let mut oflo_loop_visited = ~[];
-    do int_range_step(int::max_value-15, int::max_value, 4) |x| {
-        oflo_loop_visited.push(int::max_value - x);
-        true
-    };
-    assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]);
-
-
-    // range_step never passes nor visits the stop element
-    do int_range_step(0, 21, 3) |x| {
-        assert!(x < 21);
-        true
-    };
-
-    // range_step_inclusive will never pass stop element, and may skip it.
-    let mut saw21 = false;
-    do uint::range_step_inclusive(0, 21, 4) |x| {
-        assert!(x <= 21);
-        if x == 21 { saw21 = true; }
-        true
-    };
-    assert!(!saw21);
-    let mut saw21 = false;
-    do int::range_step_inclusive(0, 21, 4) |x| {
-        assert!(x <= 21);
-        if x == 21 { saw21 = true; }
-        true
-    };
-    assert!(!saw21);
-
-    // range_step_inclusive will never pass stop element, but may visit it.
-    let mut saw21 = false;
-    do uint::range_step_inclusive(0, 21, 3) |x| {
-        assert!(x <= 21);
-        printfln!("saw: %u", x);
-        if x == 21 { saw21 = true; }
-        true
-    };
-    assert!(saw21);
-    let mut saw21 = false;
-    do int::range_step_inclusive(0, 21, 3) |x| {
-        assert!(x <= 21);
-        if x == 21 { saw21 = true; }
-        true
-    };
-    assert!(saw21);
-
-}
diff --git a/src/test/run-pass/rl-human-test.rs b/src/test/run-pass/rl-human-test.rs
new file mode 100644 (file)
index 0000000..558e0b6
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast no compile flags for check-fast
+
+// we want this to be compiled to avoid bitrot, but the actual test
+//has to be conducted by a human, i.e. someone (you?) compiling this
+//file with a plain rustc invocation and running it and checking it
+//works.
+
+// compile-flags: --cfg robot_mode
+
+extern mod extra;
+use extra::rl;
+
+static HISTORY_FILE: &'static str = "rl-human-test-history.txt";
+
+fn main() {
+    // don't run this in robot mode, but still typecheck it.
+    if !cfg!(robot_mode) {
+        println("~~ Welcome to the rl test \"suite\". ~~");
+        println!("Operations:
+ - restrict the history to 2 lines,
+ - set the tab-completion to suggest three copies of each of the last 3 letters (or 'empty'),
+ - add 'one' and 'two' to the history,
+ - save it to `{0}`,
+ - add 'three',
+ - prompt & save input (check the history & completion work and contains only 'two', 'three'),
+ - load from `{0}`
+ - prompt & save input (history should be 'one', 'two' again),
+ - prompt once more.
+
+The bool return values of each step are printed.",
+                 HISTORY_FILE);
+
+        println!("restricting history length: {}", rl::set_history_max_len(3));
+
+        do rl::complete |line, suggest| {
+            if line.is_empty() {
+                suggest(~"empty")
+            } else {
+                for c in line.rev_iter().take(3) {
+                    suggest(format!("{0}{1}{1}{1}", line, c))
+                }
+            }
+        }
+
+        println!("adding 'one': {}", rl::add_history("one"));
+        println!("adding 'two': {}", rl::add_history("two"));
+
+        println!("saving history: {}", rl::save_history(HISTORY_FILE));
+
+        println!("adding 'three': {}", rl::add_history("three"));
+
+        match rl::read("> ") {
+            Some(s) => println!("saving input: {}", rl::add_history(s)),
+            None => return
+        }
+        println!("loading history: {}", rl::load_history(HISTORY_FILE));
+
+        match rl::read("> ") {
+            Some(s) => println!("saving input: {}", rl::add_history(s)),
+            None => return
+        }
+
+        rl::read("> ");
+    }
+}
diff --git a/src/test/run-pass/struct_variant_xc.rs b/src/test/run-pass/struct_variant_xc.rs
new file mode 100644 (file)
index 0000000..2dd7887
--- /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.
+
+// xfail-fast - check-fast doesn't understand aux-build
+// aux-build:struct_variant_xc_aux.rs
+extern mod struct_variant_xc_aux;
+
+use struct_variant_xc_aux::Variant;
+
+fn main() {
+    let _ = Variant { arg: 1 };
+}
diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs
new file mode 100644 (file)
index 0000000..cde6cc1
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast windows doesn't like 'extern mod extra'
+
+// These tests are here to exercise the functionality of the `tempfile` module.
+// One might expect these tests to be located in that module, but sadly they
+// cannot. The tests need to invoke `os::change_dir` which cannot be done in the
+// normal test infrastructure. If the tests change the current working
+// directory, then *all* tests which require relative paths suddenly break b/c
+// they're in a different location than before. Hence, these tests are all run
+// serially here.
+
+extern mod extra;
+
+use extra::tempfile::mkdtemp;
+use std::os;
+use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
+
+fn test_mkdtemp() {
+    let p = mkdtemp(&Path("."), "foobar").unwrap();
+    os::remove_dir(&p);
+    assert!(p.to_str().ends_with("foobar"));
+}
+
+// Ideally these would be in std::os but then core would need
+// to depend on std
+fn recursive_mkdir_rel() {
+    let path = Path("frob");
+    debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(),
+           os::getcwd().to_str(),
+           os::path_exists(&path));
+    assert!(os::mkdir_recursive(&path,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+    assert!(os::path_is_dir(&path));
+    assert!(os::mkdir_recursive(&path,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+    assert!(os::path_is_dir(&path));
+}
+
+fn recursive_mkdir_dot() {
+    let dot = Path(".");
+    assert!(os::mkdir_recursive(&dot,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+    let dotdot = Path("..");
+    assert!(os::mkdir_recursive(&dotdot,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+}
+
+fn recursive_mkdir_rel_2() {
+    let path = Path("./frob/baz");
+    debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(),
+           os::getcwd().to_str(), os::path_exists(&path));
+    assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+        assert!(os::path_is_dir(&path));
+    assert!(os::path_is_dir(&path.pop()));
+    let path2 = Path("quux/blat");
+    debug!("recursive_mkdir_rel_2: Making: %s in cwd %s", path2.to_str(),
+           os::getcwd().to_str());
+    assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+        assert!(os::path_is_dir(&path2));
+    assert!(os::path_is_dir(&path2.pop()));
+}
+
+// Ideally this would be in core, but needs mkdtemp
+pub fn test_rmdir_recursive_ok() {
+    let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
+
+    let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("test_rmdir_recursive_ok: \
+                                        couldn't create temp dir");
+    let root = tmpdir.push("foo");
+
+    debug!("making %s", root.to_str());
+    assert!(os::make_dir(&root, rwx));
+    assert!(os::make_dir(&root.push("foo"), rwx));
+    assert!(os::make_dir(&root.push("foo").push("bar"), rwx));
+    assert!(os::make_dir(&root.push("foo").push("bar").push("blat"), rwx));
+    assert!(os::remove_dir_recursive(&root));
+    assert!(!os::path_exists(&root));
+    assert!(!os::path_exists(&root.push("bar")));
+    assert!(!os::path_exists(&root.push("bar").push("blat")));
+}
+
+fn in_tmpdir(f: &fn()) {
+    let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("can't make tmpdir");
+    assert!(os::change_dir(&tmpdir));
+
+    f();
+}
+
+fn main() {
+    in_tmpdir(test_mkdtemp);
+    in_tmpdir(recursive_mkdir_rel);
+    in_tmpdir(recursive_mkdir_dot);
+    in_tmpdir(recursive_mkdir_rel_2);
+    in_tmpdir(test_rmdir_recursive_ok);
+}