]> git.lizzy.rs Git - rust.git/commitdiff
rollup merge of #23619: steveklabnik/gh23220
authorAlex Crichton <alex@alexcrichton.com>
Mon, 23 Mar 2015 22:11:02 +0000 (15:11 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 23 Mar 2015 22:11:02 +0000 (15:11 -0700)
Fixes #23571

I _think_ this is better, but other suggestions welcome too.

199 files changed:
man/rustc.1
src/compiletest/compiletest.rs
src/compiletest/header.rs
src/compiletest/runtest.rs
src/doc/reference.md
src/doc/trpl/SUMMARY.md
src/doc/trpl/compound-data-types.md
src/doc/trpl/concurrency.md
src/doc/trpl/crates-and-modules.md
src/doc/trpl/documentation.md
src/doc/trpl/standard-input.md
src/liballoc/heap.rs
src/libcollections/bit.rs
src/libcollections/borrow.rs
src/libcollections/btree/map.rs
src/libcollections/btree/node.rs
src/libcollections/btree/set.rs
src/libcollections/lib.rs
src/libcollections/slice.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcollections/vec_map.rs
src/libcollectionstest/str.rs
src/libcore/convert.rs [new file with mode: 0644]
src/libcore/error.rs
src/libcore/lib.rs
src/libcore/marker.rs
src/libcore/ops.rs
src/libcore/option.rs
src/libcore/prelude.rs
src/libcore/result.rs
src/libcore/slice.rs
src/libcore/str/mod.rs
src/libcore/str/pattern.rs
src/libcoretest/str.rs
src/libgraphviz/lib.rs
src/liblibc/lib.rs
src/librustc/README.md [new file with mode: 0644]
src/librustc/README.txt [deleted file]
src/librustc/lib.rs
src/librustc/metadata/cstore.rs
src/librustc/metadata/encoder.rs
src/librustc/metadata/filesearch.rs
src/librustc/metadata/loader.rs
src/librustc/middle/astencode.rs
src/librustc/middle/check_match.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/dead.rs
src/librustc/middle/effect.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/infer/combine.rs
src/librustc/middle/infer/region_inference/mod.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/pat_util.rs
src/librustc/middle/reachable.rs
src/librustc/middle/stability.rs
src/librustc/middle/traits/error_reporting.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/traits/util.rs
src/librustc/middle/ty.rs
src/librustc/session/config.rs
src/librustc/session/search_paths.rs
src/librustc_back/archive.rs
src/librustc_back/fs.rs
src/librustc_back/lib.rs
src/librustc_back/rpath.rs
src/librustc_back/target/mod.rs
src/librustc_borrowck/borrowck/move_data.rs
src/librustc_borrowck/lib.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_lint/builtin.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_trans/README.txt
src/librustc_trans/back/link.rs
src/librustc_trans/lib.rs
src/librustc_trans/save/mod.rs
src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/asm.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/expr.rs
src/librustc_trans/trans/intrinsic.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/coherence/unsafety.rs
src/librustc_typeck/collect.rs
src/librustdoc/clean/mod.rs
src/librustdoc/externalfiles.rs
src/librustdoc/html/format.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/libserialize/json.rs
src/libserialize/lib.rs
src/libserialize/serialize.rs
src/libstd/collections/hash/map.rs
src/libstd/env.rs
src/libstd/ffi/c_str.rs
src/libstd/ffi/os_str.rs
src/libstd/fs/mod.rs
src/libstd/fs/tempdir.rs
src/libstd/io/buffered.rs
src/libstd/io/cursor.rs
src/libstd/lib.rs
src/libstd/macros.rs
src/libstd/net/ip.rs
src/libstd/os.rs
src/libstd/path.rs
src/libstd/prelude/v1.rs
src/libstd/process.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mutex.rs
src/libstd/sync/poison.rs
src/libstd/sys/common/thread_info.rs
src/libstd/sys/common/wtf8.rs
src/libstd/sys/unix/fs2.rs
src/libstd/sys/unix/os.rs
src/libstd/thread.rs [deleted file]
src/libstd/thread/local.rs [new file with mode: 0644]
src/libstd/thread/mod.rs [new file with mode: 0644]
src/libstd/thread/scoped.rs [new file with mode: 0644]
src/libstd/thread_local/mod.rs [deleted file]
src/libstd/thread_local/scoped.rs [deleted file]
src/libsyntax/codemap.rs
src/libsyntax/ext/format.rs
src/libsyntax/ext/source_util.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/lib.rs
src/libsyntax/parse/parser.rs
src/libterm/lib.rs
src/libterm/terminfo/searcher.rs
src/libtest/lib.rs
src/rustbook/book.rs
src/rustbook/build.rs
src/rustbook/error.rs
src/rustbook/main.rs
src/test/auxiliary/issue-2631-a.rs
src/test/auxiliary/procedural_mbe_matching.rs
src/test/compile-fail-fulldeps/gated-macro-reexports.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-overloaded-index-2.rs [deleted file]
src/test/compile-fail/borrowck-overloaded-index-and-overloaded-deref.rs
src/test/compile-fail/borrowck-overloaded-index-autoderef.rs
src/test/compile-fail/borrowck-overloaded-index-move-from-vec.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-overloaded-index-move-index.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-overloaded-index-ref-index.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-overloaded-index.rs [deleted file]
src/test/compile-fail/coherence-default-trait-impl.rs
src/test/compile-fail/dst-index.rs
src/test/compile-fail/gated-box-patterns.rs [new file with mode: 0644]
src/test/compile-fail/gated-box-syntax.rs [new file with mode: 0644]
src/test/compile-fail/gated-simd-ffi.rs [new file with mode: 0644]
src/test/compile-fail/issue-18400.rs
src/test/compile-fail/match-ref-mut-invariance.rs [new file with mode: 0644]
src/test/compile-fail/match-ref-mut-let-invariance.rs [new file with mode: 0644]
src/test/compile-fail/recursion_limit.rs
src/test/compile-fail/regions-trait-object-subtyping.rs [new file with mode: 0644]
src/test/run-fail/overflowing-lsh-1.rs [new file with mode: 0644]
src/test/run-fail/overflowing-lsh-2.rs [new file with mode: 0644]
src/test/run-fail/overflowing-lsh-3.rs [new file with mode: 0644]
src/test/run-fail/overflowing-lsh-4.rs [new file with mode: 0644]
src/test/run-fail/overflowing-rsh-1.rs [new file with mode: 0644]
src/test/run-fail/overflowing-rsh-2.rs [new file with mode: 0644]
src/test/run-fail/overflowing-rsh-3.rs [new file with mode: 0644]
src/test/run-fail/overflowing-rsh-4.rs [new file with mode: 0644]
src/test/run-make/rustdoc-default-impl/foo.rs
src/test/run-pass/dst-index.rs
src/test/run-pass/env-home-dir.rs
src/test/run-pass/issue-15734.rs
src/test/run-pass/issue-23550.rs [new file with mode: 0644]
src/test/run-pass/issue-2804-2.rs
src/test/run-pass/issue-2804.rs
src/test/run-pass/issue-5521.rs
src/test/run-pass/issue-7660.rs
src/test/run-pass/match-ref-unsized.rs [new file with mode: 0644]
src/test/run-pass/operator-overloading.rs
src/test/run-pass/over-constrained-vregs.rs
src/test/run-pass/overloaded-index-assoc-list.rs
src/test/run-pass/overloaded-index-autoderef.rs
src/test/run-pass/overloaded-index-in-field.rs
src/test/run-pass/overloaded-index.rs
src/test/run-pass/shift-near-oflo.rs [new file with mode: 0644]
src/test/run-pass/slice.rs

index 33ef3f9ee4acba4e3078a5a3afb8ac6ccf3849d5..b15829db431dfef89f5d7b6a4fb6217c98874b3b 100644 (file)
@@ -242,7 +242,7 @@ full debug info with variable and type information.
 \fBopt\-level\fR=\fIVAL\fR
 Optimize with possible levels 0\[en]3
 
-.SH ENVIRONMENT VARIABLES
+.SH ENVIRONMENT
 
 Some of these affect the output of the compiler, while others affect programs
 which link to the standard library.
index 01c4e99b77c70a25daa503a95ac2f1d45a093f0d..1ee5917ac9c91b7dbdc734d4f114ed9b2dea7454 100644 (file)
@@ -20,6 +20,8 @@
 #![feature(std_misc)]
 #![feature(test)]
 #![feature(path_ext)]
+#![feature(convert)]
+#![feature(str_char)]
 
 #![deny(warnings)]
 
@@ -115,7 +117,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
 
     fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
         match m.opt_str(nm) {
-            Some(s) => PathBuf::new(&s),
+            Some(s) => PathBuf::from(&s),
             None => panic!("no option (=path) found for {}", nm),
         }
     }
@@ -130,10 +132,10 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
         compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
         run_lib_path: matches.opt_str("run-lib-path").unwrap(),
         rustc_path: opt_path(matches, "rustc-path"),
-        clang_path: matches.opt_str("clang-path").map(|s| PathBuf::new(&s)),
+        clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)),
         valgrind_path: matches.opt_str("valgrind-path"),
         force_valgrind: matches.opt_present("force-valgrind"),
-        llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::new(&s)),
+        llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::from(&s)),
         src_base: opt_path(matches, "src-base"),
         build_base: opt_path(matches, "build-base"),
         aux_base: opt_path(matches, "aux-base"),
@@ -141,7 +143,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
         mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"),
         run_ignored: matches.opt_present("ignored"),
         filter: filter,
-        logfile: matches.opt_str("logfile").map(|s| PathBuf::new(&s)),
+        logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
         runtool: matches.opt_str("runtool"),
         host_rustcflags: matches.opt_str("host-rustcflags"),
         target_rustcflags: matches.opt_str("target-rustcflags"),
index 29123173f5baec5dbf3fa9c3a61065f0b009c503..e1ad66c69e44a27d72d525b9089751c366b6d6a9 100644 (file)
@@ -328,10 +328,10 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
 
 fn parse_pp_exact(line: &str, testfile: &Path) -> Option<PathBuf> {
     match parse_name_value_directive(line, "pp-exact") {
-      Some(s) => Some(PathBuf::new(&s)),
+      Some(s) => Some(PathBuf::from(&s)),
       None => {
         if parse_name_directive(line, "pp-exact") {
-            testfile.file_name().map(|s| PathBuf::new(s))
+            testfile.file_name().map(|s| PathBuf::from(s))
         } else {
             None
         }
index a754bd950f7f6006709fac0e228eda7cb706c8ec..319248cb8107d60ca3c18e59cf4f9eae31648285 100644 (file)
@@ -1440,7 +1440,7 @@ fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf {
 }
 
 fn output_testname(testfile: &Path) -> PathBuf {
-    PathBuf::new(testfile.file_stem().unwrap())
+    PathBuf::from(testfile.file_stem().unwrap())
 }
 
 fn output_base_name(config: &Config, testfile: &Path) -> PathBuf {
index 92573d792177362ad724278699f3d9d13cd2839c..415ec4e4fbf0a4bc661caa3ee26558908310b851 100644 (file)
@@ -1982,7 +1982,7 @@ the namespace hierarchy as it normally would.
 ## Attributes
 
 ```{.ebnf .gram}
-attribute : "#!" ? '[' meta_item ']' ;
+attribute : '#' '!' ? '[' meta_item ']' ;
 meta_item : ident [ '=' literal
                   | '(' meta_seq ')' ] ? ;
 meta_seq : meta_item [ ',' meta_seq ] ? ;
@@ -3158,7 +3158,7 @@ ten_times(|j| println!("hello, {}", j));
 ### While loops
 
 ```{.ebnf .gram}
-while_expr : "while" no_struct_literal_expr '{' block '}' ;
+while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
 ```
 
 A `while` loop begins by evaluating the boolean loop conditional expression.
@@ -3223,7 +3223,7 @@ A `continue` expression is only permitted in the body of a loop.
 ### For expressions
 
 ```{.ebnf .gram}
-for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ;
+for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
 ```
 
 A `for` expression is a syntactic construct for looping over elements provided
index 6ff51e8d1b92cb9af4426e41da40125362e1b150..76f8b6c97381818dc3a79b4e7aa87696d58a8377 100644 (file)
@@ -1,6 +1,6 @@
 # Summary
 
-* [I: The Basics](basic.md)
+* [The Basics](basic.md)
     * [Installing Rust](installing-rust.md)
     * [Hello, world!](hello-world.md)
     * [Hello, Cargo!](hello-cargo.md)
@@ -14,7 +14,7 @@
     * [Strings](strings.md)
     * [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
     * [Standard Input](standard-input.md)
-* [II: Intermediate Rust](intermediate.md)
+* [Intermediate Rust](intermediate.md)
     * [Crates and Modules](crates-and-modules.md)
     * [Testing](testing.md)
     * [Pointers](pointers.md)
@@ -31,7 +31,7 @@
     * [Concurrency](concurrency.md)
     * [Error Handling](error-handling.md)
     * [Documentation](documentation.md)
-* [III: Advanced Topics](advanced.md)
+* [Advanced Topics](advanced.md)
     * [FFI](ffi.md)
     * [Unsafe Code](unsafe.md)
     * [Advanced Macros](advanced-macros.md)
index e09922fd390a9b037cedaab162908449a42d2eb2..d531a22d0e0dd55d2b2a0d5d913b88f9d3912c73 100644 (file)
@@ -47,7 +47,7 @@ This pattern is very powerful, and we'll see it repeated more later.
 
 There are also a few things you can do with a tuple as a whole, without
 destructuring. You can assign one tuple into another, if they have the same
-contained types and arity. Tuples have the same arity when they have the same
+contained types and [arity]. Tuples have the same arity when they have the same
 length.
 
 ```rust
@@ -196,8 +196,9 @@ Now, we have actual names, rather than positions. Good names are important,
 and with a struct, we have actual names.
 
 There _is_ one case when a tuple struct is very useful, though, and that's a
-tuple struct with only one element. We call this a *newtype*, because it lets
-you create a new type that's similar to another one:
+tuple struct with only one element. We call this the *newtype* pattern, because
+it allows you to create a new type, distinct from that of its contained value
+and expressing its own semantic meaning:
 
 ```{rust}
 struct Inches(i32);
@@ -216,7 +217,7 @@ destructuring `let`, as we discussed previously in 'tuples.' In this case, the
 
 Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful
 feature of Rust, and are used throughout the standard library. An `enum` is
-a type which ties a set of alternates to a specific name. For example, below
+a type which relates a set of alternates to a specific name. For example, below
 we define `Character` to be either a `Digit` or something else. These
 can be used via their fully scoped names: `Character::Other` (more about `::`
 below).
@@ -228,8 +229,8 @@ enum Character {
 }
 ```
 
-An `enum` variant can be defined as most normal types. Below are some example
-types which also would be allowed in an `enum`.
+Most normal types are allowed as the variant components of an `enum`. Here are
+some examples:
 
 ```rust
 struct Empty;
@@ -239,15 +240,15 @@ struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
 struct HeightDatabase(Vec<i32>);
 ```
 
-So you see that depending on the sub-datastructure, the `enum` variant, same as
-a struct, may or may not hold data. That is, in `Character`, `Digit` is a name
-tied to an `i32` where `Other` is just a name. However, the fact that they are
-distinct makes this very useful.
+You see that, depending on its type, an `enum` variant may or may not hold data.
+In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
+value, where `Other` is only a name. However, the fact that they represent
+distinct categories of `Character` is a very useful property.
 
-As with structures, enums don't by default have access to operators such as
-compare ( `==` and `!=`), binary operations (`*` and `+`), and order
-(`<` and `>=`). As such, using the previous `Character` type, the
-following code is invalid:
+As with structures, the variants of an enum by default are not comparable with
+equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
+support other binary operations such as `*` and `+`. As such, the following code
+is invalid for the example `Character` type:
 
 ```{rust,ignore}
 // These assignments both succeed
@@ -265,9 +266,10 @@ let four_equals_ten = four == ten;
 ```
 
 This may seem rather limiting, but it's a limitation which we can overcome.
-There are two ways: by implementing equality ourselves, or by using the
-[`match`][match] keyword. We don't know enough about Rust to implement equality
-yet, but we can use the `Ordering` enum from the standard library, which does:
+There are two ways: by implementing equality ourselves, or by pattern matching
+variants with [`match`][match] expressions, which you'll learn in the next
+chapter. We don't know enough about Rust to implement equality yet, but we can
+use the `Ordering` enum from the standard library, which does:
 
 ```
 enum Ordering {
@@ -277,9 +279,8 @@ enum Ordering {
 }
 ```
 
-Because we did not define `Ordering`, we must import it (from the std
-library) with the `use` keyword. Here's an example of how `Ordering` is
-used:
+Because `Ordering` has already been defined for us, we will import it with the
+`use` keyword. Here's an example of how it is used:
 
 ```{rust}
 use std::cmp::Ordering;
@@ -313,17 +314,17 @@ the standard library if you need them.
 
 Okay, let's talk about the actual code in the example. `cmp` is a function that
 compares two things, and returns an `Ordering`. We return either
-`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on if
-the two values are less, greater, or equal. Note that each variant of the
-`enum` is namespaced under the `enum` itself: it's `Ordering::Greater` not
-`Greater`.
+`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
+whether the first value is less than, greater than, or equal to the second. Note
+that each variant of the `enum` is namespaced under the `enum` itself: it's
+`Ordering::Greater`, not `Greater`.
 
 The `ordering` variable has the type `Ordering`, and so contains one of the
 three values. We then do a bunch of `if`/`else` comparisons to check which
 one it is.
 
-This `Ordering::Greater` notation is too long. Let's use `use` to import the
-`enum` variants instead. This will avoid full scoping:
+This `Ordering::Greater` notation is too long. Let's use another form of `use`
+to import the `enum` variants instead. This will avoid full scoping:
 
 ```{rust}
 use std::cmp::Ordering::{self, Equal, Less, Greater};
@@ -347,16 +348,18 @@ fn main() {
 ```
 
 Importing variants is convenient and compact, but can also cause name conflicts,
-so do this with caution. It's considered good style to rarely import variants
-for this reason.
+so do this with caution. For this reason, it's normally considered better style
+to `use` an enum rather than its variants directly.
 
-As you can see, `enum`s are quite a powerful tool for data representation, and are
-even more useful when they're [generic][generics] across types. Before we
-get to generics, though, let's talk about how to use them with pattern matching, a
-tool that will let us deconstruct this sum type (the type theory term for enums)
-in a very elegant way and avoid all these messy `if`/`else`s.
+As you can see, `enum`s are quite a powerful tool for data representation, and
+are even more useful when they're [generic][generics] across types. Before we
+get to generics, though, let's talk about how to use enums with pattern
+matching, a tool that will let us deconstruct sum types (the type theory term
+for enums) like `Ordering` in a very elegant way that avoids all these messy
+and brittle `if`/`else`s.
 
 
+[arity]: ./glossary.html#arity
 [match]: ./match.html
 [game]: ./guessing-game.html#comparing-guesses
 [generics]: ./generics.html
index 4a16db63950ddd0ff76983b8df988bea5b5ffc91..5d301cc0aef6ebbd31d1b78148ade07f75cdfd80 100644 (file)
@@ -40,14 +40,14 @@ us enforce that it can't leave the current thread.
 
 ### `Sync`
 
-The second of these two trait is called [`Sync`](../std/marker/trait.Sync.html).
+The second of these traits is called [`Sync`](../std/marker/trait.Sync.html).
 When a type `T` implements `Sync`, it indicates to the compiler that something
 of this type has no possibility of introducing memory unsafety when used from
 multiple threads concurrently.
 
 For example, sharing immutable data with an atomic reference count is
 threadsafe. Rust provides a type like this, `Arc<T>`, and it implements `Sync`,
-so that it could be safely shared between threads.
+so it is safe to share between threads.
 
 These two traits allow you to use the type system to make strong guarantees
 about the properties of your code under concurrency. Before we demonstrate
@@ -69,7 +69,7 @@ fn main() {
 }
 ```
 
-The `Thread::scoped()` method accepts a closure, which is executed in a new
+The `thread::scoped()` method accepts a closure, which is executed in a new
 thread. It's called `scoped` because this thread returns a join guard:
 
 ```
@@ -208,10 +208,10 @@ Here's the error:
 
 ```text
 <anon>:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
-<anon>:11         Thread::spawn(move || {
+<anon>:11         thread::spawn(move || {
                   ^~~~~~~~~~~~~
 <anon>:11:9: 11:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
-<anon>:11         Thread::spawn(move || {
+<anon>:11         thread::spawn(move || {
                   ^~~~~~~~~~~~~
 ```
 
@@ -322,7 +322,6 @@ While this channel is just sending a generic signal, we can send any data that
 is `Send` over the channel!
 
 ```
-use std::sync::{Arc, Mutex};
 use std::thread;
 use std::sync::mpsc;
 
index 65ff42ffdcef411804fc99d4a1967b1632d0a637..0cc54c9b16598b10eb2e8b945cc6224b6fbea20b 100644 (file)
@@ -1,6 +1,6 @@
 % Crates and Modules
 
-When a project starts getting large, it's considered good software
+When a project starts getting large, it's considered good software
 engineering practice to split it up into a bunch of smaller pieces, and then
 fit them together. It's also important to have a well-defined interface, so
 that some of your functionality is private, and some is public. To facilitate
@@ -24,23 +24,23 @@ in different languages. To keep things simple, we'll stick to "greetings" and
 two languages for those phrases to be in. We'll use this module layout:
 
 ```text
-                                +-----------+
-                            +---| greetings |
-                            |   +-----------+
-              +---------+   |
-              | english |---+
-              +---------+   |   +-----------+
-              |             +---| farewells |
-+---------+   |                 +-----------+
+                                    +-----------+
+                                +---| greetings |
+                                |   +-----------+
+                  +---------+   |
+              +---| english |---+
+              |   +---------+   |   +-----------+
+              |                 +---| farewells |
++---------+   |                     +-----------+
 | phrases |---+
-+---------+   |                  +-----------+
-              |              +---| greetings |
-              +----------+   |   +-----------+
-              | japanese |---+
-              +----------+   |
-                             |   +-----------+
-                             +---| farewells |
-                                 +-----------+
++---------+   |                     +-----------+
+              |                 +---| greetings |
+              |   +----------+  |   +-----------+
+              +---| japanese |--+
+                  +----------+  |
+                                |   +-----------+
+                                +---| farewells |
+                                    +-----------+
 ```
 
 In this example, `phrases` is the name of our crate. All of the rest are
@@ -76,25 +76,19 @@ To define each of our modules, we use the `mod` keyword. Let's make our
 `src/lib.rs` look like this:
 
 ```
-// in src/lib.rs
-
 mod english {
     mod greetings {
-
     }
 
     mod farewells {
-
     }
 }
 
 mod japanese {
     mod greetings {
-
     }
 
     mod farewells {
-
     }
 }
 ```
@@ -145,11 +139,7 @@ mod english;
 ```
 
 If we do that, Rust will expect to find either a `english.rs` file, or a
-`english/mod.rs` file with the contents of our module:
-
-```{rust,ignore}
-// contents of our module go here
-```
+`english/mod.rs` file with the contents of our module.
 
 Note that in these files, you don't need to re-declare the module: that's
 already been done with the initial `mod` declaration.
@@ -181,10 +171,7 @@ $ tree .
 `src/lib.rs` is our crate root, and looks like this:
 
 ```{rust,ignore}
-// in src/lib.rs
-
 mod english;
-
 mod japanese;
 ```
 
@@ -195,10 +182,7 @@ chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
 like this:
 
 ```{rust,ignore}
-// both src/english/mod.rs and src/japanese/mod.rs
-
 mod greetings;
-
 mod farewells;
 ```
 
@@ -214,8 +198,6 @@ both empty at the moment. Let's add some functions.
 Put this in `src/english/greetings.rs`:
 
 ```rust
-// in src/english/greetings.rs
-
 fn hello() -> String {
     "Hello!".to_string()
 }
@@ -224,8 +206,6 @@ fn hello() -> String {
 Put this in `src/english/farewells.rs`:
 
 ```rust
-// in src/english/farewells.rs
-
 fn goodbye() -> String {
     "Goodbye.".to_string()
 }
@@ -248,8 +228,6 @@ about the module system.
 Put this in `src/japanese/farewells.rs`:
 
 ```rust
-// in src/japanese/farewells.rs
-
 fn goodbye() -> String {
     "さようなら".to_string()
 }
@@ -265,11 +243,9 @@ another crate.
 We have a library crate. Let's make an executable crate that imports and uses
 our library.
 
-Make a `src/main.rs` and put this in it: (it won't quite compile yet)
+Make a `src/main.rs` and put this in it (it won't quite compile yet):
 
 ```rust,ignore
-// in src/main.rs
-
 extern crate phrases;
 
 fn main() {
@@ -320,8 +296,6 @@ keyword. Let's focus on the `english` module first, so let's reduce our `src/mai
 to just this:
 
 ```{rust,ignore}
-// in src/main.rs
-
 extern crate phrases;
 
 fn main() {
@@ -333,28 +307,20 @@ fn main() {
 In our `src/lib.rs`, let's add `pub` to the `english` module declaration:
 
 ```{rust,ignore}
-// in src/lib.rs
-
 pub mod english;
-
 mod japanese;
 ```
 
 And in our `src/english/mod.rs`, let's make both `pub`:
 
 ```{rust,ignore}
-// in src/english/mod.rs
-
 pub mod greetings;
-
 pub mod farewells;
 ```
 
 In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration:
 
 ```{rust,ignore}
-// in src/english/greetings.rs
-
 pub fn hello() -> String {
     "Hello!".to_string()
 }
@@ -363,8 +329,6 @@ pub fn hello() -> String {
 And also in `src/english/farewells.rs`:
 
 ```{rust,ignore}
-// in src/english/farewells.rs
-
 pub fn goodbye() -> String {
     "Goodbye.".to_string()
 }
@@ -400,8 +364,6 @@ Rust has a `use` keyword, which allows us to import names into our local scope.
 Let's change our `src/main.rs` to look like this:
 
 ```{rust,ignore}
-// in src/main.rs
-
 extern crate phrases;
 
 use phrases::english::greetings;
@@ -430,7 +392,7 @@ fn main() {
 }
 ```
 
-But it is not idiomatic. This is significantly more likely to introducing a
+But it is not idiomatic. This is significantly more likely to introduce a
 naming conflict. In our short program, it's not a big deal, but as it grows, it
 becomes a problem. If we have conflicting names, Rust will give a compilation
 error. For example, if we made the `japanese` functions public, and tried to do
@@ -460,21 +422,19 @@ Could not compile `phrases`.
 ```
 
 If we're importing multiple names from the same module, we don't have to type it out
-twice. Rust has a shortcut syntax for writing this:
+twice. Instead of this:
 
 ```{rust,ignore}
 use phrases::english::greetings;
 use phrases::english::farewells;
 ```
 
-You use curly braces:
+We can use this shortcut:
 
 ```{rust,ignore}
 use phrases::english::{greetings, farewells};
 ```
 
-These two declarations are equivalent, but the second is a lot less typing.
-
 ## Re-exporting with `pub use`
 
 You don't just use `use` to shorten identifiers. You can also use it inside of your crate
@@ -484,8 +444,6 @@ interface that may not directly map to your internal code organization.
 Let's look at an example. Modify your `src/main.rs` to read like this:
 
 ```{rust,ignore}
-// in src/main.rs
-
 extern crate phrases;
 
 use phrases::english::{greetings,farewells};
@@ -503,18 +461,13 @@ fn main() {
 Then, modify your `src/lib.rs` to make the `japanese` mod public:
 
 ```{rust,ignore}
-// in src/lib.rs
-
 pub mod english;
-
 pub mod japanese;
 ```
 
 Next, make the two functions public, first in `src/japanese/greetings.rs`:
 
 ```{rust,ignore}
-// in src/japanese/greetings.rs
-
 pub fn hello() -> String {
     "こんにちは".to_string()
 }
@@ -523,8 +476,6 @@ pub fn hello() -> String {
 And then in `src/japanese/farewells.rs`:
 
 ```{rust,ignore}
-// in src/japanese/farewells.rs
-
 pub fn goodbye() -> String {
     "さようなら".to_string()
 }
@@ -533,13 +484,10 @@ pub fn goodbye() -> String {
 Finally, modify your `src/japanese/mod.rs` to read like this:
 
 ```{rust,ignore}
-// in src/japanese/mod.rs
-
 pub use self::greetings::hello;
 pub use self::farewells::goodbye;
 
 mod greetings;
-
 mod farewells;
 ```
 
index 8e5b3b6a7f0afa2f25c1b7938de9cf525d9ecd45..7300753cc66d0ea3363d9d638bc1a2d7c7199b63 100644 (file)
@@ -333,6 +333,41 @@ By repeating all parts of the example, you can ensure that your example still
 compiles, while only showing the parts that are relevant to that part of your
 explanation.
 
+### Documenting macros
+
+Here’s an example of documenting a macro:
+
+```
+/// Panic with a given message unless an expression evaluates to true.
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use] extern crate foo;
+/// # fn main() {
+/// panic_unless!(1 + 1 == 2, “Math is broken.”);
+/// # }
+/// ```
+///
+/// ```should_fail
+/// # #[macro_use] extern crate foo;
+/// # fn main() {
+/// panic_unless!(true == false, “I’m broken.”);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! panic_unless {
+    ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
+} 
+```
+
+You’ll note three things: we need to add our own `extern crate` line, so that
+we can add the `#[macro_use]` attribute. Second, we’ll need to add our own
+`main()` as well. Finally, a judicious use of `#` to comment out those two
+things, so they don’t show up in the output.
+
+### Running documentation tests
+
 To run the tests, either
 
 ```bash
index 794b1df7563de7cde12943cf122762f1265806e5..228891f9f052b3a33a59c5f5862155f933562ce8 100644 (file)
@@ -115,8 +115,9 @@ doesn't work, so we're okay with that. In most cases, we would want to handle
 the error case explicitly. `expect()` allows us to give an error message if
 this crash happens.
 
-We will cover the exact details of how all of this works later in the Guide.
-For now, this gives you enough of a basic understanding to work with.
+We will cover the exact details of how all of this works later in the Guide in
+[Error Handling]. For now, this gives you enough of a basic understanding to
+work with.
 
 Back to the code we were working on! Here's a refresher:
 
@@ -157,3 +158,6 @@ here.
 
 That's all you need to get basic input from the standard input! It's not too
 complicated, but there are a number of small parts.
+
+
+[Error Handling]: ./error-handling.html
index aaf6e76237ca5669b7d6266f4b4ff853ed7dfec0..3733350412e499a8c4d3623cf6fea8aeea403bc6 100644 (file)
@@ -26,6 +26,9 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
 ///
 /// On failure, return a null pointer and leave the original allocation intact.
 ///
+/// If the allocation was relocated, the memory at the passed-in pointer is
+/// undefined after the call.
+///
 /// Behavior is undefined if the requested size is 0 or the alignment is not a
 /// power of 2. The alignment must be no larger than the largest supported page
 /// size on the platform.
index 90fbe04d3482f9f73fbcea9d4c1d90bea4cb4207..e494527b6a67c921af62f1992a9595c7dab35124 100644 (file)
@@ -169,6 +169,8 @@ pub struct BitVec {
 impl Index<usize> for BitVec {
     type Output = bool;
 
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, i: &usize) -> &bool {
         if self.get(*i).expect("index out of bounds") {
@@ -177,6 +179,16 @@ fn index(&self, i: &usize) -> &bool {
             &FALSE
         }
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, i: usize) -> &bool {
+        if self.get(i).expect("index out of bounds") {
+            &TRUE
+        } else {
+            &FALSE
+        }
+    }
 }
 
 /// Computes how many blocks are needed to store that many bits
index 4bedbdeb368769a4b2565a184f4168ec85dfb0ec..88d59f699d183030c7c2f665ee3ecd2bd813813a 100644 (file)
@@ -14,6 +14,7 @@
 
 use core::clone::Clone;
 use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
+use core::convert::AsRef;
 use core::hash::{Hash, Hasher};
 use core::marker::Sized;
 use core::ops::Deref;
@@ -291,10 +292,9 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 }
 
 /// Trait for moving into a `Cow`
-#[stable(feature = "rust1", since = "1.0.0")]
+#[unstable(feature = "into_cow", reason = "may be replaced by `convert::Into`")]
 pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
     /// Moves `self` into `Cow`
-    #[stable(feature = "rust1", since = "1.0.0")]
     fn into_cow(self) -> Cow<'a, B>;
 }
 
@@ -304,3 +304,10 @@ fn into_cow(self) -> Cow<'a, B> {
         self
     }
 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T: Clone> AsRef<T> for Cow<'a, T> {
+    fn as_ref(&self) -> &T {
+        self
+    }
+}
index c7e1e3c91766ef297d71fbad17905910d2530c61..59fe74c255b9a446ed44e6dac495bd4b7ce0c806 100644 (file)
@@ -24,7 +24,7 @@
 use core::fmt::Debug;
 use core::hash::{Hash, Hasher};
 use core::iter::{Map, FromIterator, IntoIterator};
-use core::ops::{Index, IndexMut};
+use core::ops::{Index};
 use core::{iter, fmt, mem, usize};
 use Bound::{self, Included, Excluded, Unbounded};
 
@@ -78,6 +78,7 @@ pub struct BTreeMap<K, V> {
 }
 
 /// An abstract base over-which all other BTree iterators are built.
+#[derive(Clone)]
 struct AbsIter<T> {
     traversals: VecDeque<T>,
     size: usize,
@@ -264,7 +265,7 @@ pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool where K: Borrow<Q>, Q: Or
     ///     Some(x) => *x = "b",
     ///     None => (),
     /// }
-    /// assert_eq!(map[1], "b");
+    /// assert_eq!(map[&1], "b");
     /// ```
     // See `get` for implementation notes, this is basically a copy-paste with mut's added
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -326,7 +327,7 @@ pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V> where K: Borrow<
     ///
     /// map.insert(37, "b");
     /// assert_eq!(map.insert(37, "c"), Some("b"));
-    /// assert_eq!(map[37], "c");
+    /// assert_eq!(map[&37], "c");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, mut key: K, mut value: V) -> Option<V> {
@@ -914,23 +915,29 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+#[cfg(stage0)]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K: Ord, Q: ?Sized, V> Index<Q> for BTreeMap<K, V>
     where K: Borrow<Q>, Q: Ord
 {
     type Output = V;
 
+    #[inline]
     fn index(&self, key: &Q) -> &V {
         self.get(key).expect("no entry found for key")
     }
 }
 
+#[cfg(not(stage0))]
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<K: Ord, Q: ?Sized, V> IndexMut<Q> for BTreeMap<K, V>
+impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap<K, V>
     where K: Borrow<Q>, Q: Ord
 {
-    fn index_mut(&mut self, key: &Q) -> &mut V {
-        self.get_mut(key).expect("no entry found for key")
+    type Output = V;
+
+    #[inline]
+    fn index(&self, key: &Q) -> &V {
+        self.get(key).expect("no entry found for key")
     }
 }
 
@@ -1034,6 +1041,9 @@ fn next_back(&mut self) -> Option<(K, V)> {
     }
 }
 
+impl<'a, K, V> Clone for Iter<'a, K, V> {
+    fn clone(&self) -> Iter<'a, K, V> { Iter { inner: self.inner.clone() } }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Iter<'a, K, V> {
     type Item = (&'a K, &'a V);
@@ -1076,6 +1086,9 @@ fn next_back(&mut self) -> Option<(K, V)> { self.inner.next_back() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V> ExactSizeIterator for IntoIter<K, V> {}
 
+impl<'a, K, V> Clone for Keys<'a, K, V> {
+    fn clone(&self) -> Keys<'a, K, V> { Keys { inner: self.inner.clone() } }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Keys<'a, K, V> {
     type Item = &'a K;
@@ -1091,6 +1104,9 @@ fn next_back(&mut self) -> Option<(&'a K)> { self.inner.next_back() }
 impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {}
 
 
+impl<'a, K, V> Clone for Values<'a, K, V> {
+    fn clone(&self) -> Values<'a, K, V> { Values { inner: self.inner.clone() } }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Values<'a, K, V> {
     type Item = &'a V;
@@ -1105,6 +1121,9 @@ fn next_back(&mut self) -> Option<(&'a V)> { self.inner.next_back() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {}
 
+impl<'a, K, V> Clone for Range<'a, K, V> {
+    fn clone(&self) -> Range<'a, K, V> { Range { inner: self.inner.clone() } }
+}
 impl<'a, K, V> Iterator for Range<'a, K, V> {
     type Item = (&'a K, &'a V);
 
index bfac3b2df5a5cba8cc1a200ed9be1053bea87f53..23eafa41d8a01d4075737d74cae3b39171b6a5cd 100644 (file)
@@ -1326,6 +1326,7 @@ trait TraversalImpl {
 
 /// A `TraversalImpl` that actually is backed by two iterators. This works in the non-moving case,
 /// as no deallocation needs to be done.
+#[derive(Clone)]
 struct ElemsAndEdges<Elems, Edges>(Elems, Edges);
 
 impl<K, V, E, Elems: DoubleEndedIterator, Edges: DoubleEndedIterator>
@@ -1404,6 +1405,7 @@ fn drop(&mut self) {
 }
 
 /// An abstraction over all the different kinds of traversals a node supports
+#[derive(Clone)]
 struct AbsTraversal<Impl> {
     inner: Impl,
     head_is_edge: bool,
@@ -1522,6 +1524,7 @@ fn search_linear<Q: ?Sized>(&self, key: &Q) -> (usize, bool)
             }
 
             /// Returns a sub-slice with elements starting with `min_key`.
+            #[cfg(stage0)]
             pub fn slice_from(self, min_key: &K) -> $NodeSlice<'a, K, V> {
                 //  _______________
                 // |_1_|_3_|_5_|_7_|
@@ -1549,7 +1552,37 @@ pub fn slice_from(self, min_key: &K) -> $NodeSlice<'a, K, V> {
                 }
             }
 
+            /// Returns a sub-slice with elements starting with `min_key`.
+            #[cfg(not(stage0))]
+            pub fn slice_from(self, min_key: &K) -> $NodeSlice<'a, K, V> {
+                //  _______________
+                // |_1_|_3_|_5_|_7_|
+                // |   |   |   |   |
+                // 0 0 1 1 2 2 3 3 4  index
+                // |   |   |   |   |
+                // \___|___|___|___/  slice_from(&0); pos = 0
+                //     \___|___|___/  slice_from(&2); pos = 1
+                //     |___|___|___/  slice_from(&3); pos = 1; result.head_is_edge = false
+                //         \___|___/  slice_from(&4); pos = 2
+                //             \___/  slice_from(&6); pos = 3
+                //                \|/ slice_from(&999); pos = 4
+                let (pos, pos_is_kv) = self.search_linear(min_key);
+                $NodeSlice {
+                    has_edges: self.has_edges,
+                    edges: if !self.has_edges {
+                        self.edges
+                    } else {
+                        self.edges.$index(pos ..)
+                    },
+                    keys: &self.keys[pos ..],
+                    vals: self.vals.$index(pos ..),
+                    head_is_edge: !pos_is_kv,
+                    tail_is_edge: self.tail_is_edge,
+                }
+            }
+
             /// Returns a sub-slice with elements up to and including `max_key`.
+            #[cfg(stage0)]
             pub fn slice_to(self, max_key: &K) -> $NodeSlice<'a, K, V> {
                 //  _______________
                 // |_1_|_3_|_5_|_7_|
@@ -1577,6 +1610,36 @@ pub fn slice_to(self, max_key: &K) -> $NodeSlice<'a, K, V> {
                     tail_is_edge: !pos_is_kv,
                 }
             }
+
+            /// Returns a sub-slice with elements up to and including `max_key`.
+            #[cfg(not(stage0))]
+            pub fn slice_to(self, max_key: &K) -> $NodeSlice<'a, K, V> {
+                //  _______________
+                // |_1_|_3_|_5_|_7_|
+                // |   |   |   |   |
+                // 0 0 1 1 2 2 3 3 4  index
+                // |   |   |   |   |
+                //\|/  |   |   |   |  slice_to(&0); pos = 0
+                // \___/   |   |   |  slice_to(&2); pos = 1
+                // \___|___|   |   |  slice_to(&3); pos = 1; result.tail_is_edge = false
+                // \___|___/   |   |  slice_to(&4); pos = 2
+                // \___|___|___/   |  slice_to(&6); pos = 3
+                // \___|___|___|___/  slice_to(&999); pos = 4
+                let (pos, pos_is_kv) = self.search_linear(max_key);
+                let pos = pos + if pos_is_kv { 1 } else { 0 };
+                $NodeSlice {
+                    has_edges: self.has_edges,
+                    edges: if !self.has_edges {
+                        self.edges
+                    } else {
+                        self.edges.$index(.. (pos + 1))
+                    },
+                    keys: &self.keys[..pos],
+                    vals: self.vals.$index(.. pos),
+                    head_is_edge: self.head_is_edge,
+                    tail_is_edge: !pos_is_kv,
+                }
+            }
         }
 
         impl<'a, K: 'a, V: 'a> $NodeSlice<'a, K, V> {
index 5616d36ce0ba9ffadb9a1619b0616218a0fab4c7..c0e4a32eee09ec8511f97320115ba3636747fc16 100644 (file)
@@ -628,6 +628,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+impl<'a, T> Clone for Iter<'a, T> {
+    fn clone(&self) -> Iter<'a, T> { Iter { iter: self.iter.clone() } }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Iterator for Iter<'a, T> {
     type Item = &'a T;
@@ -658,6 +661,9 @@ fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
 
+impl<'a, T> Clone for Range<'a, T> {
+    fn clone(&self) -> Range<'a, T> { Range { iter: self.iter.clone() } }
+}
 impl<'a, T> Iterator for Range<'a, T> {
     type Item = &'a T;
 
@@ -677,6 +683,11 @@ fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
     }
 }
 
+impl<'a, T> Clone for Difference<'a, T> {
+    fn clone(&self) -> Difference<'a, T> {
+        Difference { a: self.a.clone(), b: self.b.clone() }
+    }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T: Ord> Iterator for Difference<'a, T> {
     type Item = &'a T;
@@ -692,6 +703,11 @@ fn next(&mut self) -> Option<&'a T> {
     }
 }
 
+impl<'a, T> Clone for SymmetricDifference<'a, T> {
+    fn clone(&self) -> SymmetricDifference<'a, T> {
+        SymmetricDifference { a: self.a.clone(), b: self.b.clone() }
+    }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
     type Item = &'a T;
@@ -707,6 +723,11 @@ fn next(&mut self) -> Option<&'a T> {
     }
 }
 
+impl<'a, T> Clone for Intersection<'a, T> {
+    fn clone(&self) -> Intersection<'a, T> {
+        Intersection { a: self.a.clone(), b: self.b.clone() }
+    }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T: Ord> Iterator for Intersection<'a, T> {
     type Item = &'a T;
@@ -728,6 +749,11 @@ fn next(&mut self) -> Option<&'a T> {
     }
 }
 
+impl<'a, T> Clone for Union<'a, T> {
+    fn clone(&self) -> Union<'a, T> {
+        Union { a: self.a.clone(), b: self.b.clone() }
+    }
+}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T: Ord> Iterator for Union<'a, T> {
     type Item = &'a T;
index c4a014967633321e10a765c2c9a53edfe87bb738..156c90f1e84012e552f4754453b1c2d81dcf5c6d 100644 (file)
@@ -36,6 +36,7 @@
 #![feature(unsafe_no_drop_flag)]
 #![feature(step_by)]
 #![feature(str_char)]
+#![feature(convert)]
 #![cfg_attr(test, feature(rand, rustc_private, test))]
 #![cfg_attr(test, allow(deprecated))] // rand
 
index 45864153dd799598783557075b2e5115be246e79..0a0307aef322e093dbd8b4ad7491edec6a085770 100644 (file)
@@ -88,6 +88,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use alloc::boxed::Box;
+use core::convert::AsRef;
 use core::clone::Clone;
 use core::cmp::Ordering::{self, Greater, Less};
 use core::cmp::{self, Ord, PartialEq};
@@ -1088,23 +1089,23 @@ pub trait SliceConcatExt<T: ?Sized, U> {
     fn connect(&self, sep: &T) -> U;
 }
 
-impl<T: Clone, V: AsSlice<T>> SliceConcatExt<T, Vec<T>> for [V] {
+impl<T: Clone, V: AsRef<[T]>> SliceConcatExt<T, Vec<T>> for [V] {
     fn concat(&self) -> Vec<T> {
-        let size = self.iter().fold(0, |acc, v| acc + v.as_slice().len());
+        let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len());
         let mut result = Vec::with_capacity(size);
         for v in self {
-            result.push_all(v.as_slice())
+            result.push_all(v.as_ref())
         }
         result
     }
 
     fn connect(&self, sep: &T) -> Vec<T> {
-        let size = self.iter().fold(0, |acc, v| acc + v.as_slice().len());
+        let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len());
         let mut result = Vec::with_capacity(size + self.len());
         let mut first = true;
         for v in self {
             if first { first = false } else { result.push(sep.clone()) }
-            result.push_all(v.as_slice())
+            result.push_all(v.as_ref())
         }
         result
     }
index 3a289e4ef37389b6838671f60aa0109bff6c6fda..ebd55aa7ce7048ee95b441a08250720e43775a6c 100644 (file)
 use core::iter::{Iterator, IteratorExt, Extend};
 use core::option::Option::{self, Some, None};
 use core::result::Result;
-use core::slice::AsSlice;
 use core::str as core_str;
 use unicode::str::{UnicodeStr, Utf16Encoder};
 
+use core::convert::AsRef;
 use vec_deque::VecDeque;
 use borrow::{Borrow, ToOwned};
 use string::String;
@@ -74,8 +74,8 @@
 
 pub use core::str::{FromStr, Utf8Error, Str};
 pub use core::str::{Lines, LinesAny, MatchIndices, SplitStr, CharRange};
-pub use core::str::{Split, SplitTerminator};
-pub use core::str::{SplitN, RSplitN};
+pub use core::str::{Split, SplitTerminator, SplitN};
+pub use core::str::{RSplit, RSplitN};
 pub use core::str::{from_utf8, CharEq, Chars, CharIndices, Bytes};
 pub use core::str::{from_utf8_unchecked, from_c_str, ParseBoolError};
 pub use unicode::str::{Words, Graphemes, GraphemeIndices};
 Section: Creating a string
 */
 
-impl<S: Str> SliceConcatExt<str, String> for [S] {
+impl<S: AsRef<str>> SliceConcatExt<str, String> for [S] {
     fn concat(&self) -> String {
-        let s = self.as_slice();
-
-        if s.is_empty() {
+        if self.is_empty() {
             return String::new();
         }
 
         // `len` calculation may overflow but push_str will check boundaries
-        let len = s.iter().map(|s| s.as_slice().len()).sum();
+        let len = self.iter().map(|s| s.as_ref().len()).sum();
         let mut result = String::with_capacity(len);
 
-        for s in s {
-            result.push_str(s.as_slice())
+        for s in self {
+            result.push_str(s.as_ref())
         }
 
         result
     }
 
     fn connect(&self, sep: &str) -> String {
-        let s = self.as_slice();
-
-        if s.is_empty() {
+        if self.is_empty() {
             return String::new();
         }
 
         // concat is faster
         if sep.is_empty() {
-            return s.concat();
+            return self.concat();
         }
 
         // this is wrong without the guarantee that `self` is non-empty
         // `len` calculation may overflow but push_str but will check boundaries
-        let len = sep.len() * (s.len() - 1)
-            + s.iter().map(|s| s.as_slice().len()).sum();
+        let len = sep.len() * (self.len() - 1)
+            + self.iter().map(|s| s.as_ref().len()).sum();
         let mut result = String::with_capacity(len);
         let mut first = true;
 
-        for s in s {
+        for s in self {
             if first {
                 first = false;
             } else {
                 result.push_str(sep);
             }
-            result.push_str(s.as_slice());
+            result.push_str(s.as_ref());
         }
         result
     }
@@ -699,23 +695,48 @@ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator
         core_str::StrExt::split_terminator(&self[..], pat)
     }
 
-    /// An iterator over substrings of `self`, separated by characters matched by a pattern,
+    /// An iterator over substrings of `self`, separated by a pattern,
     /// starting from the end of the string.
     ///
-    /// Restricted to splitting at most `count` times.
+    /// # Examples
     ///
-    /// The pattern can be a simple `&str`, or a closure that determines the split.
+    /// Simple patterns:
+    ///
+    /// ```
+    /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
+    /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
+    ///
+    /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
+    /// assert_eq!(v, ["leopard", "tiger", "lion"]);
+    /// ```
+    ///
+    /// More complex patterns with a lambda:
+    ///
+    /// ```
+    /// let v: Vec<&str> = "abc1def2ghi".rsplit(|c: char| c.is_numeric()).collect();
+    /// assert_eq!(v, ["ghi", "def", "abc"]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+        where P::Searcher: ReverseSearcher<'a>
+    {
+        core_str::StrExt::rsplit(&self[..], pat)
+    }
+
+    /// An iterator over substrings of `self`, separated by a pattern,
+    /// starting from the end of the string, restricted to splitting
+    /// at most `count` times.
     ///
     /// # Examples
     ///
-    /// Simple `&str` patterns:
+    /// Simple patterns:
     ///
     /// ```
     /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
     /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
     ///
-    /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect();
-    /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
+    /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect();
+    /// assert_eq!(v, ["leopard", "lion::tiger"]);
     /// ```
     ///
     /// More complex patterns with a lambda:
@@ -725,7 +746,9 @@ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator
     /// assert_eq!(v, ["ghi", "abc1def"]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
+    pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
+        where P::Searcher: ReverseSearcher<'a>
+    {
         core_str::StrExt::rsplitn(&self[..], count, pat)
     }
 
index cd6f27bf65f6e5ab2e96fae662080cce247f503e..0d55dc7dba95380025dc413e342372f549f542e2 100644 (file)
@@ -25,6 +25,7 @@
 use core::ops::{self, Deref, Add, Index};
 use core::ptr;
 use core::slice;
+use core::str::Pattern;
 use unicode::str as unicode_str;
 use unicode::str::Utf16Item;
 
@@ -765,6 +766,25 @@ fn extend<I: IntoIterator<Item=&'a str>>(&mut self, iterable: I) {
     }
 }
 
+/// A convenience impl that delegates to the impl for `&str`
+impl<'a, 'b> Pattern<'a> for &'b String {
+    type Searcher = <&'b str as Pattern<'a>>::Searcher;
+
+    fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
+        self[..].into_searcher(haystack)
+    }
+
+    #[inline]
+    fn is_contained_in(self, haystack: &'a str) -> bool {
+        self[..].is_contained_in(haystack)
+    }
+
+    #[inline]
+    fn is_prefix_of(self, haystack: &'a str) -> bool {
+        self[..].is_prefix_of(haystack)
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl PartialEq for String {
     #[inline]
@@ -814,6 +834,7 @@ fn ne(&self, other: &Cow<'a, str>) -> bool { PartialEq::ne(&**self, &**other) }
 }
 
 #[unstable(feature = "collections", reason = "waiting on Str stabilization")]
+#[allow(deprecated)]
 impl Str for String {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -870,34 +891,66 @@ fn add(mut self, other: &str) -> String {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Index<ops::Range<usize>> for String {
     type Output = str;
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::Range<usize>) -> &str {
         &self[..][*index]
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::Range<usize>) -> &str {
+        &self[..][index]
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Index<ops::RangeTo<usize>> for String {
     type Output = str;
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeTo<usize>) -> &str {
         &self[..][*index]
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeTo<usize>) -> &str {
+        &self[..][index]
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Index<ops::RangeFrom<usize>> for String {
     type Output = str;
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeFrom<usize>) -> &str {
         &self[..][*index]
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &str {
+        &self[..][index]
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Index<ops::RangeFull> for String {
     type Output = str;
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, _index: &ops::RangeFull) -> &str {
         unsafe { mem::transmute(&*self.vec) }
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &str {
+        unsafe { mem::transmute(&*self.vec) }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -973,6 +1026,27 @@ fn to_string(&self) -> String {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<str> for String {
+    fn as_ref(&self) -> &str {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a str> for String {
+    fn from(s: &'a str) -> String {
+        s.to_string()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Into<Vec<u8>> for String {
+    fn into(self) -> Vec<u8> {
+        self.into_bytes()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl IntoCow<'static, str> for String {
     #[inline]
@@ -989,6 +1063,7 @@ fn into_cow(self) -> Cow<'a, str> {
     }
 }
 
+#[allow(deprecated)]
 impl<'a> Str for Cow<'a, str> {
     #[inline]
     fn as_slice<'b>(&'b self) -> &'b str {
index b0e8dc7d0b6226d004480ffd3d7f85a2b6ff88c8..1d76224bd841955573eb0314129eb53a30f7ef37 100644 (file)
@@ -1323,90 +1323,178 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
 impl<T> Index<usize> for Vec<T> {
     type Output = T;
 
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &usize) -> &T {
         // NB built-in indexing via `&[T]`
         &(**self)[*index]
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: usize) -> &T {
+        // NB built-in indexing via `&[T]`
+        &(**self)[index]
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> IndexMut<usize> for Vec<T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &usize) -> &mut T {
         // NB built-in indexing via `&mut [T]`
         &mut (**self)[*index]
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut T {
+        // NB built-in indexing via `&mut [T]`
+        &mut (**self)[index]
+    }
 }
 
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::Range<usize>> for Vec<T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::Range<usize>) -> &[T] {
         Index::index(&**self, index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::Range<usize>) -> &[T] {
+        Index::index(&**self, index)
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::RangeTo<usize>> for Vec<T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
         Index::index(&**self, index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+        Index::index(&**self, index)
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::RangeFrom<usize>> for Vec<T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
         Index::index(&**self, index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+        Index::index(&**self, index)
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::RangeFull> for Vec<T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, _index: &ops::RangeFull) -> &[T] {
+        self
+    }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &[T] {
         self.as_slice()
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::Range<usize>) -> &mut [T] {
         IndexMut::index_mut(&mut **self, index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
+        IndexMut::index_mut(&mut **self, index)
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::RangeTo<usize>> for Vec<T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::RangeTo<usize>) -> &mut [T] {
         IndexMut::index_mut(&mut **self, index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
+        IndexMut::index_mut(&mut **self, index)
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Vec<T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::RangeFrom<usize>) -> &mut [T] {
         IndexMut::index_mut(&mut **self, index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
+        IndexMut::index_mut(&mut **self, index)
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, _index: &ops::RangeFull) -> &mut [T] {
         self.as_mut_slice()
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, _index: ops::RangeFull) -> &mut [T] {
+        self.as_mut_slice()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Deref for Vec<T> {
     type Target = [T];
 
-    fn deref(&self) -> &[T] { self.as_slice() }
+    fn deref(&self) -> &[T] {
+        unsafe {
+            let p = *self.ptr;
+            assume(p != 0 as *mut T);
+            slice::from_raw_parts(p, self.len)
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1548,6 +1636,7 @@ fn cmp(&self, other: &Vec<T>) -> Ordering {
     }
 }
 
+#[allow(deprecated)]
 impl<T> AsSlice<T> for Vec<T> {
     /// Returns a slice into `self`.
     ///
@@ -1562,11 +1651,7 @@ impl<T> AsSlice<T> for Vec<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_slice(&self) -> &[T] {
-        unsafe {
-            let p = *self.ptr;
-            assume(p != 0 as *mut T);
-            slice::from_raw_parts(p, self.len)
-        }
+        self
     }
 }
 
@@ -1614,6 +1699,41 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> AsRef<Vec<T>> for Vec<T> {
+    fn as_ref(&self) -> &Vec<T> {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Into<Vec<T>> for Vec<T> {
+    fn into(self) -> Vec<T> {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> AsRef<[T]> for Vec<T> {
+    fn as_ref(&self) -> &[T] {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
+    fn from(s: &'a [T]) -> Vec<T> {
+        s.to_vec()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a str> for Vec<u8> {
+    fn from(s: &'a str) -> Vec<u8> {
+        s.as_bytes().to_vec()
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Clone-on-write
 ////////////////////////////////////////////////////////////////////////////////
index 56ca74dab1f0fd6d040e3b6bb6ed92cb68b4676e..591ad48f57912316e9bccf26d97132862ce34706 100644 (file)
@@ -1689,18 +1689,32 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 impl<A> Index<usize> for VecDeque<A> {
     type Output = A;
 
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, i: &usize) -> &A {
         self.get(*i).expect("Out of bounds access")
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, i: usize) -> &A {
+        self.get(i).expect("Out of bounds access")
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A> IndexMut<usize> for VecDeque<A> {
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, i: &usize) -> &mut A {
         self.get_mut(*i).expect("Out of bounds access")
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, i: usize) -> &mut A {
+        self.get_mut(i).expect("Out of bounds access")
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 6e67d8763273d7c0156473b126b4662d061911f3..05693ec52756ad0e9a95505e603c75e456ebf987 100644 (file)
@@ -798,6 +798,7 @@ fn extend<I: IntoIterator<Item=(usize, V)>>(&mut self, iter: I) {
     }
 }
 
+#[cfg(stage0)]
 impl<V> Index<usize> for VecMap<V> {
     type Output = V;
 
@@ -807,10 +808,49 @@ fn index<'a>(&'a self, i: &usize) -> &'a V {
     }
 }
 
+#[cfg(not(stage0))]
+impl<V> Index<usize> for VecMap<V> {
+    type Output = V;
+
+    #[inline]
+    fn index<'a>(&'a self, i: usize) -> &'a V {
+        self.get(&i).expect("key not present")
+    }
+}
+
+#[cfg(not(stage0))]
+impl<'a,V> Index<&'a usize> for VecMap<V> {
+    type Output = V;
+
+    #[inline]
+    fn index(&self, i: &usize) -> &V {
+        self.get(i).expect("key not present")
+    }
+}
+
+#[cfg(stage0)]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<V> IndexMut<usize> for VecMap<V> {
+    #[inline]
+    fn index_mut(&mut self, i: &usize) -> &mut V {
+        self.get_mut(&i).expect("key not present")
+    }
+}
+
+#[cfg(not(stage0))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<V> IndexMut<usize> for VecMap<V> {
     #[inline]
-    fn index_mut<'a>(&'a mut self, i: &usize) -> &'a mut V {
+    fn index_mut(&mut self, i: usize) -> &mut V {
+        self.get_mut(&i).expect("key not present")
+    }
+}
+
+#[cfg(not(stage0))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, V> IndexMut<&'a usize> for VecMap<V> {
+    #[inline]
+    fn index_mut(&mut self, i: &usize) -> &mut V {
         self.get_mut(i).expect("key not present")
     }
 }
index 79c2d719862a9e014849518573432df247c6a32c..5cfa800905415dd855554be725c97731ac513448 100644 (file)
@@ -910,6 +910,34 @@ fn test_split_char_iterator_no_trailing() {
     assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
 }
 
+#[test]
+fn test_rsplit() {
+    let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+    let split: Vec<&str> = data.rsplit(' ').collect();
+    assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]);
+
+    let split: Vec<&str> = data.rsplit("lämb").collect();
+    assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]);
+
+    let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect();
+    assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]);
+}
+
+#[test]
+fn test_rsplitn() {
+    let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+    let split: Vec<&str> = data.rsplitn(1, ' ').collect();
+    assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]);
+
+    let split: Vec<&str> = data.rsplitn(1, "lämb").collect();
+    assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]);
+
+    let split: Vec<&str> = data.rsplitn(1, |c: char| c == 'ä').collect();
+    assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
+}
+
 #[test]
 fn test_words() {
     let data = "\n \tMäry   häd\tä  little lämb\nLittle lämb\n";
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
new file mode 100644 (file)
index 0000000..65a226d
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2014 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.
+
+//! Traits for conversions between types.
+//!
+//! The traits in this module provide a general way to talk about
+//! conversions from one type to another. They follow the standard
+//! Rust conventions of `as`/`to`/`into`/`from`.
+
+#![unstable(feature = "convert",
+            reason = "recently added, experimental traits")]
+
+use marker::Sized;
+
+/// A cheap, reference-to-reference conversion.
+pub trait AsRef<T: ?Sized> {
+    /// Perform the conversion.
+    fn as_ref(&self) -> &T;
+}
+
+/// A cheap, mutable reference-to-mutable reference conversion.
+pub trait AsMut<T: ?Sized> {
+    /// Perform the conversion.
+    fn as_mut(&mut self) -> &mut T;
+}
+
+/// A conversion that consumes `self`, which may or may not be
+/// expensive.
+pub trait Into<T>: Sized {
+    /// Perform the conversion.
+    fn into(self) -> T;
+}
+
+/// Construct `Self` via a conversion.
+pub trait From<T> {
+    /// Perform the conversion.
+    fn from(T) -> Self;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GENERIC IMPLS
+////////////////////////////////////////////////////////////////////////////////
+
+// As implies Into
+impl<'a, T: ?Sized, U: ?Sized> Into<&'a U> for &'a T where T: AsRef<U> {
+    fn into(self) -> &'a U {
+        self.as_ref()
+    }
+}
+
+// As lifts over &
+impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
+    fn as_ref(&self) -> &U {
+        <T as AsRef<U>>::as_ref(*self)
+    }
+}
+
+// As lifts over &mut
+impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
+    fn as_ref(&self) -> &U {
+        <T as AsRef<U>>::as_ref(*self)
+    }
+}
+
+// AsMut implies Into
+impl<'a, T: ?Sized, U: ?Sized> Into<&'a mut U> for &'a mut T where T: AsMut<U> {
+    fn into(self) -> &'a mut U {
+        (*self).as_mut()
+    }
+}
+
+// AsMut lifts over &mut
+impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
+    fn as_mut(&mut self) -> &mut U {
+        (*self).as_mut()
+    }
+}
+
+// From implies Into
+impl<T, U> Into<U> for T where U: From<T> {
+    fn into(self) -> U {
+        U::from(self)
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CONCRETE IMPLS
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> AsRef<[T]> for [T] {
+    fn as_ref(&self) -> &[T] {
+        self
+    }
+}
+
+impl<T> AsMut<[T]> for [T] {
+    fn as_mut(&mut self) -> &mut [T] {
+        self
+    }
+}
+
+impl AsRef<str> for str {
+    fn as_ref(&self) -> &str {
+        self
+    }
+}
index 161f6c78921630e68c952fdeb90de7fe4627620c..d29964d63a58ed95ab07cbd5d1a43947287e4058 100644 (file)
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use prelude::*;
-use fmt::Display;
+use fmt::{Debug, Display};
 
 /// Base functionality for all errors in Rust.
-#[unstable(feature = "core",
-           reason = "the exact API of this trait may change")]
-pub trait Error: Display {
-    /// A short description of the error; usually a static string.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait Error: Debug + Display + Send {
+    /// A short description of the error.
+    ///
+    /// The description should not contain newlines or sentence-ending
+    /// punctuation, to facilitate embedding in larger user-facing
+    /// strings.
+    #[stable(feature = "rust1", since = "1.0.0")]
     fn description(&self) -> &str;
 
     /// The lower-level cause of this error, if any.
+    #[stable(feature = "rust1", since = "1.0.0")]
     fn cause(&self) -> Option<&Error> { None }
 }
 
index 29cc11d5a60a18e7ad7062c4c36c6aa8f33bca1e..e31542c183a69122a65c3b8d0caa9e2c1179159d 100644 (file)
 pub mod cmp;
 pub mod clone;
 pub mod default;
+pub mod convert;
 
 /* Core types and methods on primitives */
 
index 1b866501b8ea1a3d0fb62d347f1af1af990ddabf..0197ee82c77407104edd4647c1a9816a4a8683fa 100644 (file)
@@ -39,6 +39,8 @@ pub unsafe trait Send : MarkerTrait {
     // empty.
 }
 
+unsafe impl Send for .. { }
+
 impl<T> !Send for *const T { }
 impl<T> !Send for *mut T { }
 impl !Send for Managed { }
@@ -203,6 +205,8 @@ pub unsafe trait Sync : MarkerTrait {
     // Empty
 }
 
+unsafe impl Sync for .. { }
+
 impl<T> !Sync for *const T { }
 impl<T> !Sync for *mut T { }
 impl !Sync for Managed { }
index 6324e8fa874439bf54d850809716a54146753534..6e6f97a7af7d9e1d2595309f78ef918885ba4965 100644 (file)
@@ -898,7 +898,7 @@ macro_rules! shr_impl_all {
 /// impl Index<Bar> for Foo {
 ///     type Output = Foo;
 ///
-///     fn index<'a>(&'a self, _index: &Bar) -> &'a Foo {
+///     fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
 ///         println!("Indexing!");
 ///         self
 ///     }
@@ -917,8 +917,14 @@ pub trait Index<Idx: ?Sized> {
     type Output: ?Sized;
 
     /// The method for the indexing (`Foo[Bar]`) operation
+    #[cfg(stage0)]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn index<'a>(&'a self, index: &Idx) -> &'a Self::Output;
+
+    /// The method for the indexing (`Foo[Bar]`) operation
+    #[cfg(not(stage0))]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn index<'a>(&'a self, index: Idx) -> &'a Self::Output;
 }
 
 /// The `IndexMut` trait is used to specify the functionality of indexing
@@ -939,13 +945,13 @@ pub trait Index<Idx: ?Sized> {
 /// impl Index<Bar> for Foo {
 ///     type Output = Foo;
 ///
-///     fn index<'a>(&'a self, _index: &Bar) -> &'a Foo {
+///     fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
 ///         self
 ///     }
 /// }
 ///
 /// impl IndexMut<Bar> for Foo {
-///     fn index_mut<'a>(&'a mut self, _index: &Bar) -> &'a mut Foo {
+///     fn index_mut<'a>(&'a mut self, _index: Bar) -> &'a mut Foo {
 ///         println!("Indexing!");
 ///         self
 ///     }
@@ -960,8 +966,14 @@ pub trait Index<Idx: ?Sized> {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
     /// The method for the indexing (`Foo[Bar]`) operation
+    #[cfg(stage0)]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn index_mut<'a>(&'a mut self, index: &Idx) -> &'a mut Self::Output;
+
+    /// The method for the indexing (`Foo[Bar]`) operation
+    #[cfg(not(stage0))]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn index_mut<'a>(&'a mut self, index: Idx) -> &'a mut Self::Output;
 }
 
 /// An unbounded range.
index 455c68d4319d670ae952fd374a0da4b307b65a4b..4a1e24c1f406d03b72d0f96f189ce518269c45ba 100644 (file)
 use ops::{Deref, FnOnce};
 use result::Result::{Ok, Err};
 use result::Result;
+#[allow(deprecated)]
 use slice::AsSlice;
 use slice;
 
@@ -701,6 +702,19 @@ pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
     pub fn take(&mut self) -> Option<T> {
         mem::replace(self, None)
     }
+
+    /// Convert from `Option<T>` to `&[T]` (without copying)
+    #[inline]
+    #[unstable(feature = "as_slice", since = "unsure of the utility here")]
+    pub fn as_slice<'a>(&'a self) -> &'a [T] {
+        match *self {
+            Some(ref x) => slice::ref_slice(x),
+            None => {
+                let result: &[_] = &[];
+                result
+            }
+        }
+    }
 }
 
 impl<'a, T: Clone, D: Deref<Target=T>> Option<D> {
@@ -752,6 +766,9 @@ pub fn unwrap_or_default(self) -> T {
 
 #[unstable(feature = "core",
            reason = "waiting on the stability of the trait itself")]
+#[deprecated(since = "1.0.0",
+             reason = "use the inherent method instead")]
+#[allow(deprecated)]
 impl<T> AsSlice<T> for Option<T> {
     /// Convert from `Option<T>` to `&[T]` (without copying)
     #[inline]
index 4bf7f85284cfe94148cef8507d7d80c415921bb0..424829939b92e89fbea8898bdcb7b71ff09dba54 100644 (file)
@@ -36,6 +36,7 @@
 pub use char::CharExt;
 pub use clone::Clone;
 pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
+pub use convert::{AsRef, AsMut, Into, From};
 pub use iter::{Extend, IteratorExt};
 pub use iter::{Iterator, DoubleEndedIterator};
 pub use iter::{ExactSizeIterator};
index bc8d53e2a5765efc6b7737b00d0e6acb3776eed0..4b3cda46c1df3c84e3a0e13406946d3917d43dc6 100644 (file)
            FromIterator, ExactSizeIterator, IntoIterator};
 use ops::{FnMut, FnOnce};
 use option::Option::{self, None, Some};
+#[allow(deprecated)]
 use slice::AsSlice;
 use slice;
 
@@ -408,6 +409,20 @@ pub fn as_mut(&mut self) -> Result<&mut T, &mut E> {
         }
     }
 
+    /// Convert from `Result<T, E>` to `&[T]` (without copying)
+    #[inline]
+    #[unstable(feature = "as_slice", since = "unsure of the utility here")]
+    pub fn as_slice(&self) -> &[T] {
+        match *self {
+            Ok(ref x) => slice::ref_slice(x),
+            Err(_) => {
+                // work around lack of implicit coercion from fixed-size array to slice
+                let emp: &[_] = &[];
+                emp
+            }
+        }
+    }
+
     /// Convert from `Result<T, E>` to `&mut [T]` (without copying)
     ///
     /// ```
@@ -788,10 +803,14 @@ pub fn unwrap_err(self) -> E {
 // Trait implementations
 /////////////////////////////////////////////////////////////////////////////
 
+#[unstable(feature = "core",
+           reason = "waiting on the stability of the trait itself")]
+#[deprecated(since = "1.0.0",
+             reason = "use inherent method instead")]
+#[allow(deprecated)]
 impl<T, E> AsSlice<T> for Result<T, E> {
     /// Convert from `Result<T, E>` to `&[T]` (without copying)
     #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
     fn as_slice<'a>(&'a self) -> &'a [T] {
         match *self {
             Ok(ref x) => slice::ref_slice(x),
index 907b2eba80c5b872a1f5fc1fb9964901c73c1251..8826cfc5ee35885d41d8d5078a2a330ad21a477f 100644 (file)
@@ -263,6 +263,7 @@ fn get_mut(&mut self, index: usize) -> Option<&mut T> {
     #[inline]
     fn as_mut_slice(&mut self) -> &mut [T] { self }
 
+    #[cfg(stage0)]
     #[inline]
     fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
         unsafe {
@@ -273,6 +274,17 @@ fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
         }
     }
 
+    #[cfg(not(stage0))]
+    #[inline]
+    fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
+        unsafe {
+            let self2: &mut [T] = mem::transmute_copy(&self);
+
+            (ops::IndexMut::index_mut(self, ops::RangeTo { end: mid } ),
+             ops::IndexMut::index_mut(self2, ops::RangeFrom { start: mid } ))
+        }
+    }
+
     #[inline]
     fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> {
         unsafe {
@@ -495,25 +507,45 @@ fn clone_from_slice(&mut self, src: &[T]) -> usize where T: Clone {
 impl<T> ops::Index<usize> for [T] {
     type Output = T;
 
+    #[cfg(stage0)]
     fn index(&self, &index: &usize) -> &T {
         assert!(index < self.len());
 
         unsafe { mem::transmute(self.repr().data.offset(index as isize)) }
     }
+
+    #[cfg(not(stage0))]
+    fn index(&self, index: usize) -> &T {
+        assert!(index < self.len());
+
+        unsafe { mem::transmute(self.repr().data.offset(index as isize)) }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<usize> for [T] {
+    #[cfg(stage0)]
+    #[inline]
     fn index_mut(&mut self, &index: &usize) -> &mut T {
         assert!(index < self.len());
 
         unsafe { mem::transmute(self.repr().data.offset(index as isize)) }
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: usize) -> &mut T {
+        assert!(index < self.len());
+
+        unsafe { mem::transmute(self.repr().data.offset(index as isize)) }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::Range<usize>> for [T] {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::Range<usize>) -> &[T] {
         assert!(index.start <= index.end);
@@ -525,34 +557,72 @@ fn index(&self, index: &ops::Range<usize>) -> &[T] {
             )
         }
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::Range<usize>) -> &[T] {
+        assert!(index.start <= index.end);
+        assert!(index.end <= self.len());
+        unsafe {
+            from_raw_parts (
+                self.as_ptr().offset(index.start as isize),
+                index.end - index.start
+            )
+        }
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::RangeTo<usize>> for [T] {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
         self.index(&ops::Range{ start: 0, end: index.end })
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+        self.index(ops::Range{ start: 0, end: index.end })
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<ops::RangeFrom<usize>> for [T] {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
         self.index(&ops::Range{ start: index.start, end: self.len() })
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+        self.index(ops::Range{ start: index.start, end: self.len() })
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::Index<RangeFull> for [T] {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, _index: &RangeFull) -> &[T] {
         self
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, _index: RangeFull) -> &[T] {
+        self
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::Range<usize>> for [T] {
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::Range<usize>) -> &mut [T] {
         assert!(index.start <= index.end);
@@ -564,28 +634,64 @@ fn index_mut(&mut self, index: &ops::Range<usize>) -> &mut [T] {
             )
         }
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
+        assert!(index.start <= index.end);
+        assert!(index.end <= self.len());
+        unsafe {
+            from_raw_parts_mut(
+                self.as_mut_ptr().offset(index.start as isize),
+                index.end - index.start
+            )
+        }
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] {
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::RangeTo<usize>) -> &mut [T] {
         self.index_mut(&ops::Range{ start: 0, end: index.end })
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
+        self.index_mut(ops::Range{ start: 0, end: index.end })
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<ops::RangeFrom<usize>> for [T] {
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::RangeFrom<usize>) -> &mut [T] {
         let len = self.len();
         self.index_mut(&ops::Range{ start: index.start, end: len })
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
+        let len = self.len();
+        self.index_mut(ops::Range{ start: index.start, end: len })
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::IndexMut<RangeFull> for [T] {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, _index: &RangeFull) -> &mut [T] {
         self
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, _index: RangeFull) -> &mut [T] {
+        self
+    }
 }
 
 
@@ -596,24 +702,29 @@ fn index_mut(&mut self, _index: &RangeFull) -> &mut [T] {
 /// Data that is viewable as a slice.
 #[unstable(feature = "core",
            reason = "will be replaced by slice syntax")]
+#[deprecated(since = "1.0.0",
+             reason = "use std::convert::AsRef<[T]> instead")]
 pub trait AsSlice<T> {
     /// Work with `self` as a slice.
     fn as_slice<'a>(&'a self) -> &'a [T];
 }
 
 #[unstable(feature = "core", reason = "trait is experimental")]
+#[allow(deprecated)]
 impl<T> AsSlice<T> for [T] {
     #[inline(always)]
     fn as_slice<'a>(&'a self) -> &'a [T] { self }
 }
 
 #[unstable(feature = "core", reason = "trait is experimental")]
+#[allow(deprecated)]
 impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a U {
     #[inline(always)]
     fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
 }
 
 #[unstable(feature = "core", reason = "trait is experimental")]
+#[allow(deprecated)]
 impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a mut U {
     #[inline(always)]
     fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
@@ -763,37 +874,69 @@ unsafe impl<'a, T: Sync> Send for Iter<'a, T> {}
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<ops::Range<usize>> for Iter<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::Range<usize>) -> &[T] {
         self.as_slice().index(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::Range<usize>) -> &[T] {
+        self.as_slice().index(index)
+    }
 }
 
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<ops::RangeTo<usize>> for Iter<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
         self.as_slice().index(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+        self.as_slice().index(index)
+    }
 }
 
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<ops::RangeFrom<usize>> for Iter<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
         self.as_slice().index(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+        self.as_slice().index(index)
+    }
 }
 
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<RangeFull> for Iter<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, _index: &RangeFull) -> &[T] {
         self.as_slice()
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, _index: RangeFull) -> &[T] {
+        self.as_slice()
+    }
 }
 
 impl<'a, T> Iter<'a, T> {
@@ -856,63 +999,126 @@ unsafe impl<'a, T: Send> Send for IterMut<'a, T> {}
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<ops::Range<usize>> for IterMut<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::Range<usize>) -> &[T] {
         self.index(&RangeFull).index(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::Range<usize>) -> &[T] {
+        self.index(RangeFull).index(index)
+    }
 }
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<ops::RangeTo<usize>> for IterMut<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeTo<usize>) -> &[T] {
         self.index(&RangeFull).index(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeTo<usize>) -> &[T] {
+        self.index(RangeFull).index(index)
+    }
 }
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<ops::RangeFrom<usize>> for IterMut<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, index: &ops::RangeFrom<usize>) -> &[T] {
         self.index(&RangeFull).index(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, index: ops::RangeFrom<usize>) -> &[T] {
+        self.index(RangeFull).index(index)
+    }
 }
 #[unstable(feature = "core")]
 impl<'a, T> ops::Index<RangeFull> for IterMut<'a, T> {
     type Output = [T];
+
+    #[cfg(stage0)]
     #[inline]
     fn index(&self, _index: &RangeFull) -> &[T] {
         make_slice!(T => &[T]: self.ptr, self.end)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index(&self, _index: RangeFull) -> &[T] {
+        make_slice!(T => &[T]: self.ptr, self.end)
+    }
 }
 
 #[unstable(feature = "core")]
 impl<'a, T> ops::IndexMut<ops::Range<usize>> for IterMut<'a, T> {
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::Range<usize>) -> &mut [T] {
         self.index_mut(&RangeFull).index_mut(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
+        self.index_mut(RangeFull).index_mut(index)
+    }
 }
 #[unstable(feature = "core")]
 impl<'a, T> ops::IndexMut<ops::RangeTo<usize>> for IterMut<'a, T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::RangeTo<usize>) -> &mut [T] {
         self.index_mut(&RangeFull).index_mut(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
+        self.index_mut(RangeFull).index_mut(index)
+    }
 }
 #[unstable(feature = "core")]
 impl<'a, T> ops::IndexMut<ops::RangeFrom<usize>> for IterMut<'a, T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, index: &ops::RangeFrom<usize>) -> &mut [T] {
         self.index_mut(&RangeFull).index_mut(index)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
+        self.index_mut(RangeFull).index_mut(index)
+    }
 }
 #[unstable(feature = "core")]
 impl<'a, T> ops::IndexMut<RangeFull> for IterMut<'a, T> {
+
+    #[cfg(stage0)]
     #[inline]
     fn index_mut(&mut self, _index: &RangeFull) -> &mut [T] {
         make_mut_slice!(T => &mut [T]: self.ptr, self.end)
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn index_mut(&mut self, _index: RangeFull) -> &mut [T] {
+        make_mut_slice!(T => &mut [T]: self.ptr, self.end)
+    }
 }
 
 
index e8181395b5c1e5a19538eb3eef1942014577daa4..b7285d30a7309cc9451a22aef5e4ba7170a3c250 100644 (file)
@@ -111,7 +111,24 @@ fn size_hint(&self) -> (usize, Option<usize>) {
                 self.0.size_hint()
             }
         }
-    }
+    };
+    (pattern reverse $te:ty : $ti:ty) => {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<'a, P: Pattern<'a>> Iterator for $ti
+            where P::Searcher: ReverseSearcher<'a>
+        {
+            type Item = $te;
+
+            #[inline]
+            fn next(&mut self) -> Option<$te> {
+                self.0.next()
+            }
+            #[inline]
+            fn size_hint(&self) -> (usize, Option<usize>) {
+                self.0.size_hint()
+            }
+        }
+    };
 }
 
 /// A trait to abstract the idea of creating a new instance of a type from a
@@ -550,7 +567,26 @@ struct CharSplitsN<'a, P: Pattern<'a>> {
     iter: CharSplits<'a, P>,
     /// The number of splits remaining
     count: usize,
-    invert: bool,
+}
+
+/// An iterator over the substrings of a string, separated by a
+/// pattern, in reverse order.
+struct RCharSplits<'a, P: Pattern<'a>> {
+    /// The slice remaining to be iterated
+    start: usize,
+    end: usize,
+    matcher: P::Searcher,
+    /// Whether an empty string at the end of iteration is allowed
+    allow_final_empty: bool,
+    finished: bool,
+}
+
+/// An iterator over the substrings of a string, separated by a
+/// pattern, splitting at most `count` times, in reverse order.
+struct RCharSplitsN<'a, P: Pattern<'a>> {
+    iter: RCharSplits<'a, P>,
+    /// The number of splits remaining
+    count: usize,
 }
 
 /// An iterator over the lines of a string, separated by `\n`.
@@ -631,21 +667,74 @@ fn next_back(&mut self) -> Option<&'a str> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P>
-where P::Searcher: DoubleEndedSearcher<'a> {
+impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> {
     type Item = &'a str;
 
     #[inline]
     fn next(&mut self) -> Option<&'a str> {
         if self.count != 0 {
             self.count -= 1;
-            if self.invert { self.iter.next_back() } else { self.iter.next() }
+            self.iter.next()
         } else {
             self.iter.get_end()
         }
     }
 }
 
+impl<'a, P: Pattern<'a>> RCharSplits<'a, P> {
+    #[inline]
+    fn get_remainder(&mut self) -> Option<&'a str> {
+        if !self.finished && (self.allow_final_empty || self.end - self.start > 0) {
+            self.finished = true;
+            unsafe {
+                let string = self.matcher.haystack().slice_unchecked(self.start, self.end);
+                Some(string)
+            }
+        } else {
+            None
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: Pattern<'a>> Iterator for RCharSplits<'a, P>
+    where P::Searcher: ReverseSearcher<'a>
+{
+    type Item = &'a str;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        if self.finished { return None }
+
+        let haystack = self.matcher.haystack();
+        match self.matcher.next_match_back() {
+            Some((a, b)) => unsafe {
+                let elt = haystack.slice_unchecked(b, self.end);
+                self.end = a;
+                Some(elt)
+            },
+            None => self.get_remainder(),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P>
+    where P::Searcher: ReverseSearcher<'a>
+{
+    type Item = &'a str;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        if self.count != 0 {
+            self.count -= 1;
+            self.iter.next()
+        } else {
+            self.iter.get_remainder()
+        }
+    }
+}
+
 /// The internal state of an iterator that searches for matches of a substring
 /// within a larger string using two-way search
 #[derive(Clone)]
@@ -1203,6 +1292,7 @@ fn partial_cmp(&self, other: &str) -> Option<Ordering> {
     /// // byte 100 is outside the string
     /// // &s[3 .. 100];
     /// ```
+    #[cfg(stage0)]
     #[stable(feature = "rust1", since = "1.0.0")]
     impl ops::Index<ops::Range<usize>> for str {
         type Output = str;
@@ -1219,6 +1309,49 @@ fn index(&self, index: &ops::Range<usize>) -> &str {
         }
     }
 
+    /// Returns a slice of the given string from the byte range
+    /// [`begin`..`end`).
+    ///
+    /// This operation is `O(1)`.
+    ///
+    /// Panics when `begin` and `end` do not point to valid characters
+    /// or point beyond the last character of the string.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let s = "Löwe 老虎 Léopard";
+    /// assert_eq!(&s[0 .. 1], "L");
+    ///
+    /// assert_eq!(&s[1 .. 9], "öwe 老");
+    ///
+    /// // these will panic:
+    /// // byte 2 lies within `ö`:
+    /// // &s[2 ..3];
+    ///
+    /// // byte 8 lies within `老`
+    /// // &s[1 .. 8];
+    ///
+    /// // byte 100 is outside the string
+    /// // &s[3 .. 100];
+    /// ```
+    #[cfg(not(stage0))]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    impl ops::Index<ops::Range<usize>> for str {
+        type Output = str;
+        #[inline]
+        fn index(&self, index: ops::Range<usize>) -> &str {
+            // is_char_boundary checks that the index is in [0, .len()]
+            if index.start <= index.end &&
+               self.is_char_boundary(index.start) &&
+               self.is_char_boundary(index.end) {
+                unsafe { self.slice_unchecked(index.start, index.end) }
+            } else {
+                super::slice_error_fail(self, index.start, index.end)
+            }
+        }
+    }
+
     /// Returns a slice of the string from the beginning to byte
     /// `end`.
     ///
@@ -1229,6 +1362,8 @@ fn index(&self, index: &ops::Range<usize>) -> &str {
     #[stable(feature = "rust1", since = "1.0.0")]
     impl ops::Index<ops::RangeTo<usize>> for str {
         type Output = str;
+
+        #[cfg(stage0)]
         #[inline]
         fn index(&self, index: &ops::RangeTo<usize>) -> &str {
             // is_char_boundary checks that the index is in [0, .len()]
@@ -1238,6 +1373,17 @@ fn index(&self, index: &ops::RangeTo<usize>) -> &str {
                 super::slice_error_fail(self, 0, index.end)
             }
         }
+
+        #[cfg(not(stage0))]
+        #[inline]
+        fn index(&self, index: ops::RangeTo<usize>) -> &str {
+            // is_char_boundary checks that the index is in [0, .len()]
+            if self.is_char_boundary(index.end) {
+                unsafe { self.slice_unchecked(0, index.end) }
+            } else {
+                super::slice_error_fail(self, 0, index.end)
+            }
+        }
     }
 
     /// Returns a slice of the string from `begin` to its end.
@@ -1249,6 +1395,8 @@ fn index(&self, index: &ops::RangeTo<usize>) -> &str {
     #[stable(feature = "rust1", since = "1.0.0")]
     impl ops::Index<ops::RangeFrom<usize>> for str {
         type Output = str;
+
+        #[cfg(stage0)]
         #[inline]
         fn index(&self, index: &ops::RangeFrom<usize>) -> &str {
             // is_char_boundary checks that the index is in [0, .len()]
@@ -1258,15 +1406,34 @@ fn index(&self, index: &ops::RangeFrom<usize>) -> &str {
                 super::slice_error_fail(self, index.start, self.len())
             }
         }
+
+        #[cfg(not(stage0))]
+        #[inline]
+        fn index(&self, index: ops::RangeFrom<usize>) -> &str {
+            // is_char_boundary checks that the index is in [0, .len()]
+            if self.is_char_boundary(index.start) {
+                unsafe { self.slice_unchecked(index.start, self.len()) }
+            } else {
+                super::slice_error_fail(self, index.start, self.len())
+            }
+        }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
     impl ops::Index<ops::RangeFull> for str {
         type Output = str;
+
+        #[cfg(stage0)]
         #[inline]
         fn index(&self, _index: &ops::RangeFull) -> &str {
             self
         }
+
+        #[cfg(not(stage0))]
+        #[inline]
+        fn index(&self, _index: ops::RangeFull) -> &str {
+            self
+        }
     }
 }
 
@@ -1275,16 +1442,20 @@ fn index(&self, _index: &ops::RangeFull) -> &str {
            reason = "Instead of taking this bound generically, this trait will be \
                      replaced with one of slicing syntax (&foo[..]), deref coercions, or \
                      a more generic conversion trait")]
+#[deprecated(since = "1.0.0",
+             reason = "use std::convert::AsRef<str> instead")]
 pub trait Str {
     /// Work with `self` as a slice.
     fn as_slice<'a>(&'a self) -> &'a str;
 }
 
+#[allow(deprecated)]
 impl Str for str {
     #[inline]
     fn as_slice<'a>(&'a self) -> &'a str { self }
 }
 
+#[allow(deprecated)]
 impl<'a, S: ?Sized> Str for &'a S where S: Str {
     #[inline]
     fn as_slice(&self) -> &str { Str::as_slice(*self) }
@@ -1293,23 +1464,7 @@ fn as_slice(&self) -> &str { Str::as_slice(*self) }
 /// Return type of `StrExt::split`
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Split<'a, P: Pattern<'a>>(CharSplits<'a, P>);
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: Pattern<'a>> Iterator for Split<'a, P> {
-    type Item = &'a str;
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        self.0.next()
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: Pattern<'a>> DoubleEndedIterator for Split<'a, P>
-where P::Searcher: DoubleEndedSearcher<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str> {
-        self.0.next_back()
-    }
-}
+delegate_iter!{pattern &'a str : Split<'a, P>}
 
 /// Return type of `StrExt::split_terminator`
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1321,10 +1476,15 @@ fn next_back(&mut self) -> Option<&'a str> {
 pub struct SplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
 delegate_iter!{pattern forward &'a str : SplitN<'a, P>}
 
+/// Return type of `StrExt::rsplit`
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RSplit<'a, P: Pattern<'a>>(RCharSplits<'a, P>);
+delegate_iter!{pattern reverse &'a str : RSplit<'a, P>}
+
 /// Return type of `StrExt::rsplitn`
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct RSplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
-delegate_iter!{pattern forward &'a str : RSplitN<'a, P>}
+pub struct RSplitN<'a, P: Pattern<'a>>(RCharSplitsN<'a, P>);
+delegate_iter!{pattern reverse &'a str : RSplitN<'a, P>}
 
 /// Methods for string slices
 #[allow(missing_docs)]
@@ -1340,7 +1500,10 @@ pub trait StrExt {
     fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>;
     fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>;
     fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>;
-    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>;
+    fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+        where P::Searcher: ReverseSearcher<'a>;
+    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
+        where P::Searcher: ReverseSearcher<'a>;
     fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
     #[allow(deprecated) /* for SplitStr */]
     fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P>;
@@ -1424,7 +1587,6 @@ fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
         SplitN(CharSplitsN {
             iter: self.split(pat).0,
             count: count,
-            invert: false,
         })
     }
 
@@ -1437,11 +1599,25 @@ fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a,
     }
 
     #[inline]
-    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
-        RSplitN(CharSplitsN {
-            iter: self.split(pat).0,
+    fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+        where P::Searcher: ReverseSearcher<'a>
+    {
+        RSplit(RCharSplits {
+            start: 0,
+            end: self.len(),
+            matcher: pat.into_searcher(self),
+            allow_final_empty: true,
+            finished: false,
+        })
+    }
+
+    #[inline]
+    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
+        where P::Searcher: ReverseSearcher<'a>
+    {
+        RSplitN(RCharSplitsN {
+            iter: self.rsplit(pat).0,
             count: count,
-            invert: true,
         })
     }
 
index 7bf248917a5cd20596312e917142777035701041..98b6533980dd913728ff45724e01793ee26d1122 100644 (file)
@@ -474,22 +474,16 @@ impl<'a, 'b> Pattern<'a> for &'b [char] {
                       s, CharEqPattern(s));
 }
 
+/// A convenience impl that delegates to the impl for `&str`
+impl<'a, 'b> Pattern<'a> for &'b &'b str {
+    type Searcher =   <&'b str as Pattern<'a>>::Searcher;
+    associated_items!(<&'b str as Pattern<'a>>::Searcher,
+                      s, (*s));
+}
+
 /// Searches for chars that match the given predicate
 impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
     type Searcher =   <CharEqPattern<Self> as Pattern<'a>>::Searcher;
     associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
                       s, CharEqPattern(s));
 }
-
-// Deref-forward impl
-
-use ops::Deref;
-
-/// Delegates to the next deref coercion of `Self` that implements `Pattern`
-impl<'a, 'b, P: 'b + ?Sized, T: Deref<Target = P> + ?Sized> Pattern<'a> for &'b T
-    where &'b P: Pattern<'a>
-{
-    type Searcher =   <&'b P as Pattern<'a>>::Searcher;
-    associated_items!(<&'b P as Pattern<'a>>::Searcher,
-                      s, (&**s));
-}
index cac78363dd53b8e83144b68bad4a38e2925d62a2..38cab4f0e0942440063c16e0bd3b1a3813fd9451 100644 (file)
@@ -13,9 +13,7 @@ fn test_pattern_deref_forward() {
     let data = "aabcdaa";
     assert!(data.contains("bcd"));
     assert!(data.contains(&"bcd"));
-    assert!(data.contains(&&"bcd"));
     assert!(data.contains(&"bcd".to_string()));
-    assert!(data.contains(&&"bcd".to_string()));
 }
 
 #[test]
index 0e0804593443d5d733bb4e16b51fa1939b31d937..6d95d5e07247c1f07209cb55a1da6e00e92d2b98 100644 (file)
        html_root_url = "http://doc.rust-lang.org/nightly/")]
 #![feature(int_uint)]
 #![feature(collections)]
+#![feature(into_cow)]
 
 use self::LabelText::*;
 
index 893781e6220908ae2823a6eda6ac3e86519fa8e1..f9783f40f7b668998c13c378549ec2fc32a929cb 100644 (file)
@@ -2495,10 +2495,24 @@ pub mod bsd44 {
 
             pub const TCP_NODELAY: c_int = 0x0001;
             pub const SOL_SOCKET: c_int = 0xffff;
-            pub const SO_KEEPALIVE: c_int = 8;
-            pub const SO_BROADCAST: c_int = 32;
-            pub const SO_REUSEADDR: c_int = 4;
+
+            pub const SO_DEBUG: c_int = 0x0001;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
+            pub const SO_BROADCAST: c_int = 0x0020;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
             pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
 
             pub const IFF_LOOPBACK: c_int = 4;
 
@@ -3441,10 +3455,24 @@ pub mod bsd44 {
 
             pub const TCP_NODELAY: c_int = 1;
             pub const SOL_SOCKET: c_int = 1;
-            pub const SO_KEEPALIVE: c_int = 9;
-            pub const SO_BROADCAST: c_int = 6;
+
+            pub const SO_DEBUG: c_int = 1;
             pub const SO_REUSEADDR: c_int = 2;
+            pub const SO_TYPE: c_int = 3;
             pub const SO_ERROR: c_int = 4;
+            pub const SO_DONTROUTE: c_int = 5;
+            pub const SO_BROADCAST: c_int = 6;
+            pub const SO_SNDBUF: c_int = 7;
+            pub const SO_RCVBUF: c_int = 8;
+            pub const SO_KEEPALIVE: c_int = 9;
+            pub const SO_OOBINLINE: c_int = 10;
+            pub const SO_LINGER: c_int = 13;
+            pub const SO_REUSEPORT: c_int = 15;
+            pub const SO_RCVLOWAT: c_int = 18;
+            pub const SO_SNDLOWAT: c_int = 19;
+            pub const SO_RCVTIMEO: c_int = 20;
+            pub const SO_SNDTIMEO: c_int = 21;
+            pub const SO_ACCEPTCONN: c_int = 30;
 
             pub const SHUT_RD: c_int = 0;
             pub const SHUT_WR: c_int = 1;
@@ -3487,10 +3515,24 @@ pub mod bsd44 {
 
             pub const TCP_NODELAY: c_int = 1;
             pub const SOL_SOCKET: c_int = 65535;
-            pub const SO_KEEPALIVE: c_int = 8;
-            pub const SO_BROADCAST: c_int = 32;
-            pub const SO_REUSEADDR: c_int = 4;
-            pub const SO_ERROR: c_int = 4103;
+
+            pub const SO_DEBUG: c_int = 0x0001;
+            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
+            pub const SO_BROADCAST: c_int = 0x0020;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
+            pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
+            pub const SO_ACCEPTCONN: c_int = 0x1009;
 
             pub const SHUT_RD: c_int = 0;
             pub const SHUT_WR: c_int = 1;
@@ -4002,10 +4044,24 @@ pub mod bsd44 {
             pub const TCP_NODELAY: c_int = 1;
             pub const TCP_KEEPIDLE: c_int = 256;
             pub const SOL_SOCKET: c_int = 0xffff;
+            pub const SO_DEBUG: c_int = 0x01;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
             pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
             pub const SO_BROADCAST: c_int = 0x0020;
-            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
             pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
 
             pub const IFF_LOOPBACK: c_int = 0x8;
 
@@ -4403,10 +4459,24 @@ pub mod bsd44 {
 
             pub const TCP_NODELAY: c_int = 0x01;
             pub const SOL_SOCKET: c_int = 0xffff;
+            pub const SO_DEBUG: c_int = 0x01;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
             pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
             pub const SO_BROADCAST: c_int = 0x0020;
-            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
             pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
 
             pub const IFF_LOOPBACK: c_int = 0x8;
 
@@ -4820,10 +4890,25 @@ pub mod bsd44 {
             pub const TCP_NODELAY: c_int = 0x01;
             pub const TCP_KEEPALIVE: c_int = 0x10;
             pub const SOL_SOCKET: c_int = 0xffff;
+
+            pub const SO_DEBUG: c_int = 0x01;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
             pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
             pub const SO_BROADCAST: c_int = 0x0020;
-            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
             pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
 
             pub const IFF_LOOPBACK: c_int = 0x8;
 
@@ -4849,6 +4934,15 @@ pub mod extra {
             pub const MAP_STACK : c_int = 0;
 
             pub const IPPROTO_RAW : c_int = 255;
+
+            pub const SO_NREAD: c_int = 0x1020;
+            pub const SO_NKE: c_int = 0x1021;
+            pub const SO_NOSIGPIPE: c_int = 0x1022;
+            pub const SO_NOADDRERR: c_int = 0x1023;
+            pub const SO_NWRITE: c_int = 0x1024;
+            pub const SO_DONTTRUNC: c_int = 0x2000;
+            pub const SO_WANTMORE: c_int = 0x4000;
+            pub const SO_WANTOOBFLAG: c_int = 0x8000;
         }
         pub mod sysconf {
             use types::os::arch::c95::c_int;
diff --git a/src/librustc/README.md b/src/librustc/README.md
new file mode 100644 (file)
index 0000000..31812e1
--- /dev/null
@@ -0,0 +1,128 @@
+An informal guide to reading and working on the rustc compiler.
+==================================================================
+
+If you wish to expand on this document, or have a more experienced
+Rust contributor add anything else to it, please get in touch:
+
+* http://internals.rust-lang.org/
+* https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
+
+or file a bug:
+
+https://github.com/rust-lang/rust/issues
+
+Your concerns are probably the same as someone else's.
+
+The crates of rustc
+===================
+
+Rustc consists of a number of crates, including `libsyntax`,
+`librustc`, `librustc_back`, `librustc_trans`, and `librustc_driver`
+(the names and divisions are not set in stone and may change;
+in general, a finer-grained division of crates is preferable):
+
+- `libsyntax` contains those things concerned purely with syntax –
+  that is, the AST, parser, pretty-printer, lexer, macro expander, and
+  utilities for traversing ASTs – are in a separate crate called
+  "syntax", whose files are in `./../libsyntax`, where `.` is the
+  current directory (that is, the parent directory of front/, middle/,
+  back/, and so on).
+
+- `librustc` (the current directory) contains the high-level analysis
+  passes, such as the type checker, borrow checker, and so forth.
+  It is the heart of the compiler.
+
+- `librustc_back` contains some very low-level details that are
+  specific to different LLVM targets and so forth.
+
+- `librustc_trans` contains the code to convert from Rust IR into LLVM
+  IR, and then from LLVM IR into machine code, as well as the main
+  driver that orchestrates all the other passes and various other bits
+  of miscellany. In general it contains code that runs towards the
+  end of the compilation process.
+
+- `librustc_driver` invokes the compiler from `libsyntax`, then the
+  analysis phases from `librustc`, and finally the lowering and
+  codegen passes from `librustc_trans`.
+
+Roughly speaking the "order" of the three crates is as follows:
+
+    libsyntax -> librustc -> librustc_trans
+    |                                     |
+    +-----------------+-------------------+
+                      |
+              librustc_driver
+
+
+Modules in the rustc crate
+==========================
+
+The rustc crate itself consists of the following submodules
+(mostly, but not entirely, in their own directories):
+
+- session: options and data that pertain to the compilation session as
+  a whole
+- middle: middle-end: name resolution, typechecking, LLVM code
+  generation
+- metadata: encoder and decoder for data required by separate
+  compilation
+- plugin: infrastructure for compiler plugins
+- lint: infrastructure for compiler warnings
+- util: ubiquitous types and helper functions
+- lib: bindings to LLVM
+
+The entry-point for the compiler is main() in the librustc_trans
+crate.
+
+The 3 central data structures:
+------------------------------
+
+1. `./../libsyntax/ast.rs` defines the AST. The AST is treated as
+   immutable after parsing, but it depends on mutable context data
+   structures (mainly hash maps) to give it meaning.
+
+   - Many – though not all – nodes within this data structure are
+     wrapped in the type `spanned<T>`, meaning that the front-end has
+     marked the input coordinates of that node. The member `node` is
+     the data itself, the member `span` is the input location (file,
+     line, column; both low and high).
+
+   - Many other nodes within this data structure carry a
+     `def_id`. These nodes represent the 'target' of some name
+     reference elsewhere in the tree. When the AST is resolved, by
+     `middle/resolve.rs`, all names wind up acquiring a def that they
+     point to. So anything that can be pointed-to by a name winds
+     up with a `def_id`.
+
+2. `middle/ty.rs` defines the datatype `sty`. This is the type that
+   represents types after they have been resolved and normalized by
+   the middle-end. The typeck phase converts every ast type to a
+   `ty::sty`, and the latter is used to drive later phases of
+   compilation. Most variants in the `ast::ty` tag have a
+   corresponding variant in the `ty::sty` tag.
+
+3. `./../librustc_llvm/lib.rs` defines the exported types
+   `ValueRef`, `TypeRef`, `BasicBlockRef`, and several others.
+   Each of these is an opaque pointer to an LLVM type,
+   manipulated through the `lib::llvm` interface.
+
+
+Control and information flow within the compiler:
+-------------------------------------------------
+
+- main() in lib.rs assumes control on startup. Options are
+  parsed, platform is detected, etc.
+
+- `./../libsyntax/parse/parser.rs` parses the input files and produces
+  an AST that represents the input crate.
+
+- Multiple middle-end passes (`middle/resolve.rs`, `middle/typeck.rs`)
+  analyze the semantics of the resulting AST. Each pass generates new
+  information about the AST and stores it in various environment data
+  structures. The driver passes environments to each compiler pass
+  that needs to refer to them.
+
+- Finally, the `trans` module in `librustc_trans` translates the Rust
+  AST to LLVM bitcode in a type-directed way. When it's finished
+  synthesizing LLVM values, rustc asks LLVM to write them out in some
+  form (`.bc`, `.o`) and possibly run the system linker.
diff --git a/src/librustc/README.txt b/src/librustc/README.txt
deleted file mode 100644 (file)
index 9b36476..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-An informal guide to reading and working on the rustc compiler.
-==================================================================
-
-If you wish to expand on this document, or have a more experienced
-Rust contributor add anything else to it, please get in touch:
-
-* http://internals.rust-lang.org/
-* https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
-
-or file a bug:
-
-https://github.com/rust-lang/rust/issues
-
-Your concerns are probably the same as someone else's.
-
-The crates of rustc
-===================
-
-Rustc consists of four crates altogether: `libsyntax`, `librustc`,
-`librustc_back`, and `librustc_trans` (the names and divisions are not
-set in stone and may change; in general, a finer-grained division of
-crates is preferable):
-
-- `libsyntax` contains those things concerned purely with syntax --
-  that is, the AST, parser, pretty-printer, lexer, macro expander, and
-  utilities for traversing ASTs -- are in a separate crate called
-  "syntax", whose files are in ./../libsyntax, where . is the current
-  directory (that is, the parent directory of front/, middle/, back/,
-  and so on).
-
-- `librustc` (the current directory) contains the high-level analysis
-  passes, such as the type checker, borrow checker, and so forth.
-  It is the heart of the compiler.
-
-- `librustc_back` contains some very low-level details that are
-  specific to different LLVM targets and so forth.
-
-- `librustc_trans` contains the code to convert from Rust IR into LLVM
-  IR, and then from LLVM IR into machine code, as well as the main
-  driver that orchestrates all the other passes and various other bits
-  of miscellany. In general it contains code that runs towards the
-  end of the compilation process.
-
-Roughly speaking the "order" of the three crates is as follows:
-
-    libsyntax -> librustc -> librustc_trans
-    |                                     |
-    +-----------------+-------------------+
-                      |
-             librustc_trans/driver
-
-Here the role of `librustc_trans/driver` is to invoke the compiler
-from libsyntax, then the analysis phases from librustc, and finally
-the lowering and codegen passes from librustc_trans.
-
-Modules in the rustc crate
-==========================
-
-The rustc crate itself consists of the following subdirectories
-(mostly, but not entirely, in their own directories):
-
-session  - options and data that pertain to the compilation session as a whole
-middle   - middle-end: name resolution, typechecking, LLVM code
-                  generation
-metadata - encoder and decoder for data required by
-                    separate compilation
-util     - ubiquitous types and helper functions
-lib      - bindings to LLVM
-
-The entry-point for the compiler is main() in the librustc_trans
-crate.
-
-The 3 central data structures:
-------------------------------
-
-#1: ./../libsyntax/ast.rs defines the AST. The AST is treated as immutable
-    after parsing, but it depends on mutable context data structures
-    (mainly hash maps) to give it meaning.
-
-      - Many -- though not all -- nodes within this data structure are
-        wrapped in the type `spanned<T>`, meaning that the front-end has
-        marked the input coordinates of that node. The member .node is
-        the data itself, the member .span is the input location (file,
-        line, column; both low and high).
-
-      - Many other nodes within this data structure carry a
-        def_id. These nodes represent the 'target' of some name
-        reference elsewhere in the tree. When the AST is resolved, by
-        middle/resolve.rs, all names wind up acquiring a def that they
-        point to. So anything that can be pointed-to by a name winds
-        up with a def_id.
-
-#2: middle/ty.rs defines the datatype sty.  This is the type that
-    represents types after they have been resolved and normalized by
-    the middle-end. The typeck phase converts every ast type to a
-    ty::sty, and the latter is used to drive later phases of
-    compilation.  Most variants in the ast::ty tag have a
-    corresponding variant in the ty::sty tag.
-
-#3: lib/llvm.rs (in librustc_trans) defines the exported types
-    ValueRef, TypeRef, BasicBlockRef, and several others. Each of
-    these is an opaque pointer to an LLVM type, manipulated through
-    the lib::llvm interface.
-
-
-Control and information flow within the compiler:
--------------------------------------------------
-
-- main() in lib.rs assumes control on startup. Options are
-  parsed, platform is detected, etc.
-
-- ./../libsyntax/parse/parser.rs parses the input files and produces an AST
-  that represents the input crate.
-
-- Multiple middle-end passes (middle/resolve.rs, middle/typeck.rs)
-  analyze the semantics of the resulting AST. Each pass generates new
-  information about the AST and stores it in various environment data
-  structures. The driver passes environments to each compiler pass
-  that needs to refer to them.
-
-- Finally, the `trans` module in `librustc_trans` translates the Rust
-  AST to LLVM bitcode in a type-directed way. When it's finished
-  synthesizing LLVM values, rustc asks LLVM to write them out in some
-  form (.bc, .o) and possibly run the system linker.
index 97ed391fdfc7842470d6ba283928c6f6bf0f6369..793eff6a9da6fc9763c02e68a72ee7ccecd5a5f6 100644 (file)
@@ -43,6 +43,8 @@
 #![feature(path_ext)]
 #![feature(str_words)]
 #![feature(str_char)]
+#![feature(convert)]
+#![feature(into_cow)]
 #![cfg_attr(test, feature(test))]
 
 extern crate arena;
index 47ec31c0f1ab7d0c26b7d366282cf54d368121b9..f201ff374ea0f058db497bebce436a4dc34d06ea 100644 (file)
@@ -111,7 +111,7 @@ pub fn next_crate_num(&self) -> ast::CrateNum {
     }
 
     pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
-        (*self.metas.borrow())[cnum].clone()
+        self.metas.borrow().get(&cnum).unwrap().clone()
     }
 
     pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
@@ -243,7 +243,7 @@ pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
 impl MetadataBlob {
     pub fn as_slice<'a>(&'a self) -> &'a [u8] {
         let slice = match *self {
-            MetadataVec(ref vec) => vec.as_slice(),
+            MetadataVec(ref vec) => &vec[..],
             MetadataArchive(ref ar) => ar.as_slice(),
         };
         if slice.len() < 4 {
index 10461e3d2aedfc38b2f51f9a0bd78f6fe97e5bde..fa8d0b2a56e4ee34b8e062ed0bac19948f730897 100644 (file)
@@ -375,7 +375,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
     match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) {
         Some(implementations) => {
             for base_impl_did in &**implementations {
-                for &method_did in &*(*impl_items)[*base_impl_did] {
+                for &method_did in impl_items.get(base_impl_did).unwrap() {
                     let impl_item = ty::impl_or_trait_item(
                         ecx.tcx,
                         method_did.def_id());
@@ -1175,7 +1175,7 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
         // We need to encode information about the default methods we
         // have inherited, so we drive this based on the impl structure.
         let impl_items = tcx.impl_items.borrow();
-        let items = &(*impl_items)[def_id];
+        let items = impl_items.get(&def_id).unwrap();
 
         add_to_index(item, rbml_w, index);
         rbml_w.start_tag(tag_items_data_item);
@@ -1816,7 +1816,7 @@ struct ImplVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
 impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
     fn visit_item(&mut self, item: &ast::Item) {
         if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node {
-            let def_id = self.ecx.tcx.def_map.borrow()[trait_ref.ref_id].def_id();
+            let def_id = self.ecx.tcx.def_map.borrow().get(&trait_ref.ref_id).unwrap().def_id();
 
             // Load eagerly if this is an implementation of the Drop trait
             // or if the trait is not defined in this crate.
index 22a4a6fc978dc055a9a79ae360b03c0d51feca7e..284e76b328a6912323692c82f0f6180e8f29f97e 100644 (file)
@@ -156,7 +156,7 @@ pub fn get_dylib_search_paths(&self) -> Vec<PathBuf> {
 
     // Returns a list of directories where target-specific tool binaries are located.
     pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
-        let mut p = PathBuf::new(self.sysroot);
+        let mut p = PathBuf::from(self.sysroot);
         p.push(&find_libdir(self.sysroot));
         p.push(&rustlibdir());
         p.push(&self.triple);
@@ -166,7 +166,7 @@ pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
 }
 
 pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
-    let mut p = PathBuf::new(&find_libdir(sysroot));
+    let mut p = PathBuf::from(&find_libdir(sysroot));
     assert!(p.is_relative());
     p.push(&rustlibdir());
     p.push(target_triple);
@@ -224,7 +224,7 @@ pub fn rust_path() -> Vec<PathBuf> {
         Some(env_path) => {
             let env_path_components =
                 env_path.split(PATH_ENTRY_SEPARATOR);
-            env_path_components.map(|s| PathBuf::new(s)).collect()
+            env_path_components.map(|s| PathBuf::from(s)).collect()
         }
         None => Vec::new()
     };
index e466dc8a3a0181db8a7a3b99983fdffe748e5ea4..7854db811466517bbd3f675ab3ac0e80b9edc643 100644 (file)
@@ -628,7 +628,7 @@ fn find_commandline_library(&mut self, locs: &[String]) -> Option<Library> {
         let mut rlibs = HashMap::new();
         let mut dylibs = HashMap::new();
         {
-            let locs = locs.iter().map(|l| PathBuf::new(&l[..])).filter(|loc| {
+            let locs = locs.iter().map(|l| PathBuf::from(l)).filter(|loc| {
                 if !loc.exists() {
                     sess.err(&format!("extern location for {} does not exist: {}",
                                      self.crate_name, loc.display()));
index bffcb93bc6d06382d7d5d20f71be447d7291d1cf..801350e8a1e9c1d50d29d9f28d66f9c7add566ad 100644 (file)
@@ -1228,7 +1228,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
                     var_id: var_id,
                     closure_expr_id: id
                 };
-                let upvar_capture = tcx.upvar_capture_map.borrow()[upvar_id].clone();
+                let upvar_capture = tcx.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone();
                 var_id.encode(rbml_w);
                 upvar_capture.encode(rbml_w);
             })
index 496c96c7c8adc1dd5bebd412b258c7a352db670d..97cd9456098b1bbab4fb5b8947975d9d46af1399 100644 (file)
@@ -874,7 +874,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         }
 
         ast::PatEnum(_, ref args) => {
-            let def = cx.tcx.def_map.borrow()[pat_id].full_def();
+            let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             match def {
                 DefConst(..) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
@@ -892,7 +892,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
 
         ast::PatStruct(_, ref pattern_fields, _) => {
             // Is this a struct or an enum variant?
-            let def = cx.tcx.def_map.borrow()[pat_id].full_def();
+            let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             let class_id = match def {
                 DefConst(..) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
index 96433729a9b96ff675d29d4d7f8183b3a380cf4c..f9598237ff460805cc0494475f97820ff385fb3d 100644 (file)
@@ -150,7 +150,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat>
             ast::PatTup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr, span)).collect()),
 
         ast::ExprCall(ref callee, ref args) => {
-            let def = tcx.def_map.borrow()[callee.id];
+            let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
             if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
                entry.insert(def);
             }
index 5efea66ab0c6cc751cff9f1550057df4657780f7..6d4d759476ed5330edde04b58b498f294dc99498 100644 (file)
@@ -158,7 +158,7 @@ fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: uint) {
 
     fn handle_field_pattern_match(&mut self, lhs: &ast::Pat,
                                   pats: &[codemap::Spanned<ast::FieldPat>]) {
-        let id = match self.tcx.def_map.borrow()[lhs.id].full_def() {
+        let id = match self.tcx.def_map.borrow().get(&lhs.id).unwrap().full_def() {
             def::DefVariant(_, id, _) => id,
             _ => {
                 match ty::ty_to_def_id(ty::node_id_to_type(self.tcx,
@@ -496,7 +496,7 @@ fn symbol_is_live(&mut self, id: ast::NodeId,
             None => (),
             Some(impl_list) => {
                 for impl_did in &**impl_list {
-                    for item_did in &(*impl_items)[*impl_did] {
+                    for item_did in &*impl_items.get(impl_did).unwrap() {
                         if self.live_symbols.contains(&item_did.def_id()
                                                                .node) {
                             return true;
index 378f3db0823391064cc40409021c97497134dddd..5d970c59f639bd5e3b4a289a7419ce7ddb52dfd0 100644 (file)
@@ -141,7 +141,7 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
         match expr.node {
             ast::ExprMethodCall(_, _, _) => {
                 let method_call = MethodCall::expr(expr.id);
-                let base_type = (*self.tcx.method_map.borrow())[method_call].ty;
+                let base_type = self.tcx.method_map.borrow().get(&method_call).unwrap().ty;
                 debug!("effect: method call case, base type is {}",
                        ppaux::ty_to_string(self.tcx, base_type));
                 if type_is_unsafe_function(base_type) {
index 6d2392054f9d578efd6786583c204d89302d00c0..97314b57ef656802a6b773495566051c7a27978c 100644 (file)
@@ -442,7 +442,7 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
                 if !self.walk_overloaded_operator(expr,
                                                   &**lhs,
                                                   vec![&**rhs],
-                                                  PassArgs::ByRef) {
+                                                  PassArgs::ByValue) {
                     self.select_from_expr(&**lhs);
                     self.consume_expr(&**rhs);
                 }
@@ -1012,7 +1012,7 @@ fn walk_pat(&mut self,
 
                 // Each match binding is effectively an assignment to the
                 // binding being produced.
-                let def = def_map.borrow()[pat.id].full_def();
+                let def = def_map.borrow().get(&pat.id).unwrap().full_def();
                 match mc.cat_def(pat.id, pat.span, pat_ty, def) {
                     Ok(binding_cmt) => {
                         delegate.mutate(pat.id, pat.span, binding_cmt, Init);
index 94c9699e30cc42ad73d545f3471c3a18b1a91616..930e95d1f939a474590138324dbacc9dd1b5dac7 100644 (file)
@@ -557,18 +557,7 @@ pub fn super_tys<'tcx, C>(this: &C,
 
         (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
             let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r));
-
-            // FIXME(14985)  If we have mutable references to trait objects, we
-            // used to use covariant subtyping. I have preserved this behaviour,
-            // even though it is probably incorrect. So don't go down the usual
-            // path which would require invariance.
-            let mt = match (&a_mt.ty.sty, &b_mt.ty.sty) {
-                (&ty::ty_trait(..), &ty::ty_trait(..)) if a_mt.mutbl == b_mt.mutbl => {
-                    let ty = try!(this.tys(a_mt.ty, b_mt.ty));
-                    ty::mt { ty: ty, mutbl: a_mt.mutbl }
-                }
-                _ => try!(this.mts(a_mt, b_mt))
-            };
+            let mt = try!(this.mts(a_mt, b_mt));
             Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
         }
 
index 759d7357df1931d71b0843e61594c2dd4624cbcb..553e3601806677ed1bc37f4ba22ddc4a9fbe7a3e 100644 (file)
@@ -1533,7 +1533,7 @@ fn process_edges<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
                     ConstrainVarSubReg(_, region) => {
                         state.result.push(RegionAndOrigin {
                             region: region,
-                            origin: this.constraints.borrow()[edge.data].clone()
+                            origin: this.constraints.borrow().get(&edge.data).unwrap().clone()
                         });
                     }
                 }
index 932c9c61ef1fbb53ef4006201de88feea96f0f31..705f20559afde27711c2c0934f7aba5c68aa5df0 100644 (file)
@@ -448,7 +448,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
     match expr.node {
       // live nodes required for uses or definitions of variables:
       ast::ExprPath(..) => {
-        let def = ir.tcx.def_map.borrow()[expr.id].full_def();
+        let def = ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def();
         debug!("expr {}: path that leads to {:?}", expr.id, def);
         if let DefLocal(..) = def {
             ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
@@ -1302,7 +1302,7 @@ fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
 
     fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
                    -> LiveNode {
-        match self.ir.tcx.def_map.borrow()[expr.id].full_def() {
+        match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
           DefLocal(nid) => {
             let ln = self.live_node(expr.id, expr.span);
             if acc != 0 {
@@ -1564,7 +1564,9 @@ fn check_ret(&self,
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
             ast::ExprPath(..) => {
-                if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].full_def() {
+                if let DefLocal(nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
+                                                                   .unwrap()
+                                                                   .full_def() {
                     // Assignment to an immutable variable or argument: only legal
                     // if there is no later assignment. If this local is actually
                     // mutable, then check for a reassignment to flag the mutability
index 5237a86ebb6300f5c76f16a32587b866d51edd34..bdcfc67f92b997a370cad0693f2eab1f729c626f 100644 (file)
@@ -531,7 +531,7 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
           }
 
           ast::ExprPath(..) => {
-            let def = self.tcx().def_map.borrow()[expr.id].full_def();
+            let def = self.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
             self.cat_def(expr.id, expr.span, expr_ty, def)
           }
 
index c5abff3b96360bceaa9ca8b8d8124e02ad4fb08e..4f365beed213f2a44f57d238779cb69d84cebcd7 100644 (file)
@@ -119,6 +119,24 @@ pub fn pat_contains_bindings(dm: &DefMap, pat: &ast::Pat) -> bool {
     contains_bindings
 }
 
+/// Checks if the pattern contains any `ref` or `ref mut` bindings.
+pub fn pat_contains_ref_binding(dm: &DefMap, pat: &ast::Pat) -> bool {
+    let mut result = false;
+    pat_bindings(dm, pat, |mode, _, _, _| {
+        match mode {
+            ast::BindingMode::BindByRef(_) => { result = true; }
+            ast::BindingMode::BindByValue(_) => { }
+        }
+    });
+    result
+}
+
+/// Checks if the patterns for this arm contain any `ref` or `ref mut`
+/// bindings.
+pub fn arm_contains_ref_binding(dm: &DefMap, arm: &ast::Arm) -> bool {
+    arm.pats.iter().any(|pat| pat_contains_ref_binding(dm, pat))
+}
+
 /// Checks if the pattern contains any patterns that bind something to
 /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
 pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
index 7ded344414ce698bf328818b6ea1ef645553bd0d..1bd45b5fc86017cd5a8afea2c994c2e181397d9e 100644 (file)
@@ -128,7 +128,7 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
             }
             ast::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                match (*self.tcx.method_map.borrow())[method_call].origin {
+                match (*self.tcx.method_map.borrow()).get(&method_call).unwrap().origin {
                     ty::MethodStatic(def_id) => {
                         if is_local(def_id) {
                             if self.def_id_represents_local_inlined_item(def_id) {
index 01766b0de085f0c4d32d5f2b70aec2a3d6257366..d12b737619c8db4d1086a2dab3422f346ff8bb39 100644 (file)
@@ -319,7 +319,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
         // individually as it's possible to have a stable trait with unstable
         // items.
         ast::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
-            let trait_did = tcx.def_map.borrow()[t.ref_id].def_id();
+            let trait_did = tcx.def_map.borrow().get(&t.ref_id).unwrap().def_id();
             let trait_items = ty::trait_items(tcx, trait_did);
 
             for impl_item in impl_items {
index d2b5b460d142002b174a88910a9972944f3f7316..d10ff060418ccb05cdca1061c2e816224c9fbacf 100644 (file)
@@ -12,6 +12,7 @@
     FulfillmentError,
     FulfillmentErrorCode,
     MismatchedProjectionTypes,
+    Obligation,
     ObligationCauseCode,
     OutputTypeParameterMismatch,
     PredicateObligation,
@@ -21,6 +22,7 @@
 use fmt_macros::{Parser, Piece, Position};
 use middle::infer::InferCtxt;
 use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
+use middle::ty_fold::TypeFoldable;
 use std::collections::HashMap;
 use syntax::codemap::{DUMMY_SP, Span};
 use syntax::attr::{AttributeMethods, AttrMetaMethods};
@@ -137,24 +139,36 @@ trait definition for {} must have a value, \
     report
 }
 
+/// Reports that an overflow has occurred and halts compilation. We
+/// halt compilation unconditionally because it is important that
+/// overflows never be masked -- they basically represent computations
+/// whose result could not be truly determined and thus we can't say
+/// if the program type checks or not -- and they are unusual
+/// occurrences in any case.
+pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
+                                          obligation: &Obligation<'tcx, T>)
+                                          -> !
+    where T: UserString<'tcx> + TypeFoldable<'tcx>
+{
+    let predicate =
+        infcx.resolve_type_vars_if_possible(&obligation.predicate);
+    span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
+              "overflow evaluating the requirement `{}`",
+              predicate.user_string(infcx.tcx));
+
+    suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
+
+    note_obligation_cause(infcx, obligation);
+
+    infcx.tcx.sess.abort_if_errors();
+    unreachable!();
+}
+
 pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                         obligation: &PredicateObligation<'tcx>,
                                         error: &SelectionError<'tcx>)
 {
     match *error {
-        SelectionError::Overflow => {
-            // We could track the stack here more precisely if we wanted, I imagine.
-            let predicate =
-                infcx.resolve_type_vars_if_possible(&obligation.predicate);
-            span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
-                    "overflow evaluating the requirement `{}`",
-                    predicate.user_string(infcx.tcx));
-
-            suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
-
-            note_obligation_cause(infcx, obligation);
-        }
-
         SelectionError::Unimplemented => {
             match &obligation.cause.code {
                 &ObligationCauseCode::CompareImplMethodObligation => {
@@ -309,8 +323,9 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
     }
 }
 
-fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
-                                   obligation: &PredicateObligation<'tcx>)
+fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
+                                      obligation: &Obligation<'tcx, T>)
+    where T: UserString<'tcx>
 {
     note_obligation_cause_code(infcx,
                                &obligation.predicate,
@@ -318,10 +333,11 @@ fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                &obligation.cause.code);
 }
 
-fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
-                                        predicate: &ty::Predicate<'tcx>,
-                                        cause_span: Span,
-                                        cause_code: &ObligationCauseCode<'tcx>)
+fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
+                                           predicate: &T,
+                                           cause_span: Span,
+                                           cause_code: &ObligationCauseCode<'tcx>)
+    where T: UserString<'tcx>
 {
     let tcx = infcx.tcx;
     match *cause_code {
index f46cac308287ba769d34378ddc19421d5aee3233..24b201c960f16ffe001b9914c2010b81170e4946 100644 (file)
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
-use util::ppaux::{Repr, UserString};
+use util::ppaux::Repr;
 
 pub use self::error_reporting::report_fulfillment_errors;
+pub use self::error_reporting::report_overflow_error;
 pub use self::error_reporting::suggest_new_overflow_limit;
 pub use self::coherence::orphan_check;
 pub use self::coherence::overlapping_impls;
@@ -151,7 +152,6 @@ pub struct DerivedObligationCause<'tcx> {
 #[derive(Clone,Debug)]
 pub enum SelectionError<'tcx> {
     Unimplemented,
-    Overflow,
     OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
                                 ty::PolyTraitRef<'tcx>,
                                 ty::type_err<'tcx>),
@@ -327,16 +327,9 @@ pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
     let result = match fulfill_cx.select_all_or_error(infcx, typer) {
         Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
         Err(errors) => {
-            // Check if overflow occurred anywhere and propagate that.
-            if errors.iter().any(
-                |err| match err.code { CodeSelectionError(Overflow) => true, _ => false })
-            {
-                return Err(Overflow);
-            }
-
-            // Otherwise, if there were any hard errors, propagate an
-            // arbitrary one of those. If no hard errors at all,
-            // report ambiguity.
+            // If there were any hard errors, propagate an arbitrary
+            // one of those. If no hard errors at all, report
+            // ambiguity.
             let sel_error =
                 errors.iter()
                       .filter_map(|err| {
@@ -384,16 +377,8 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
             // soldering on, so just treat this like not implemented
             false
         }
-        Err(Overflow) => {
-            span_err!(infcx.tcx.sess, span, E0285,
-                "overflow evaluating whether `{}` is `{}`",
-                      ty.user_string(infcx.tcx),
-                      bound.user_string(infcx.tcx));
-            suggest_new_overflow_limit(infcx.tcx, span);
-            false
-        }
         Err(_) => {
-            // other errors: not implemented.
+            // errors: not implemented.
             false
         }
     }
@@ -652,15 +637,6 @@ fn new(obligation: PredicateObligation<'tcx>,
     {
         FulfillmentError { obligation: obligation, code: code }
     }
-
-    pub fn is_overflow(&self) -> bool {
-        match self.code {
-            CodeAmbiguity => false,
-            CodeSelectionError(Overflow) => true,
-            CodeSelectionError(_) => false,
-            CodeProjectionError(_) => false,
-        }
-    }
 }
 
 impl<'tcx> TraitObligation<'tcx> {
index 6b66d7227d300d00ca6e4280ebf7ea778b69d18c..92d54887308d645e1de0e11c96b388aca2721060 100644 (file)
@@ -11,9 +11,9 @@
 //! Code for projecting associated types out of trait references.
 
 use super::elaborate_predicates;
+use super::report_overflow_error;
 use super::Obligation;
 use super::ObligationCause;
-use super::Overflow;
 use super::PredicateObligation;
 use super::SelectionContext;
 use super::SelectionError;
@@ -442,7 +442,7 @@ fn project_type<'cx,'tcx>(
     let recursion_limit = selcx.tcx().sess.recursion_limit.get();
     if obligation.recursion_depth >= recursion_limit {
         debug!("project: overflow!");
-        return Err(ProjectionTyError::TraitSelectionError(Overflow));
+        report_overflow_error(selcx.infcx(), &obligation);
     }
 
     let obligation_trait_ref =
@@ -854,10 +854,10 @@ fn confirm_impl_candidate<'cx,'tcx>(
     let impl_items_map = selcx.tcx().impl_items.borrow();
     let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
 
-    let impl_items = &impl_items_map[impl_vtable.impl_def_id];
+    let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap();
     let mut impl_ty = None;
     for impl_item in impl_items {
-        let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
+        let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
             ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
             ty::MethodTraitItem(..) => { continue; }
         };
index 7dfbccea0dccd160f4c8ecfb6a0470083d6c28c1..9878661c9f69c414221e9378eab8ba2d69812592 100644 (file)
@@ -21,8 +21,9 @@
 use super::project;
 use super::project::{normalize_with_depth, Normalized};
 use super::{PredicateObligation, TraitObligation, ObligationCause};
+use super::{report_overflow_error};
 use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
-use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
+use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
 use super::{Selection};
 use super::{SelectionResult};
 use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
@@ -561,10 +562,7 @@ fn candidate_from_obligation<'o>(&mut self,
         // not update) the cache.
         let recursion_limit = self.infcx.tcx.sess.recursion_limit.get();
         if stack.obligation.recursion_depth >= recursion_limit {
-            debug!("{} --> overflow (limit={})",
-                   stack.obligation.repr(self.tcx()),
-                   recursion_limit);
-            return Err(Overflow)
+            report_overflow_error(self.infcx(), &stack.obligation);
         }
 
         // Check the cache. Note that we skolemize the trait-ref
@@ -1762,7 +1760,7 @@ fn collect_predicates_for_types(&mut self,
 
         match obligations {
             Ok(mut obls) => {
-                obls.push_all(normalized.obligations.as_slice());
+                obls.push_all(&normalized.obligations);
                 obls
             },
             Err(ErrorReported) => Vec::new()
@@ -2582,11 +2580,13 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
 impl<'tcx> EvaluationResult<'tcx> {
     fn may_apply(&self) -> bool {
         match *self {
-            EvaluatedToOk
-            | EvaluatedToAmbig
-            | EvaluatedToErr(Overflow)
-            | EvaluatedToErr(OutputTypeParameterMismatch(..)) => true,
-            EvaluatedToErr(Unimplemented) => false,
+            EvaluatedToOk |
+            EvaluatedToAmbig |
+            EvaluatedToErr(OutputTypeParameterMismatch(..)) =>
+                true,
+
+            EvaluatedToErr(Unimplemented) =>
+                false,
         }
     }
 }
index 88b721ce958622c7b345dbe53c7c88b9e1b389b4..965aaf12044ec20692b20ca403d9234580c25a04 100644 (file)
@@ -514,9 +514,6 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
 impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
         match *self {
-            super::Overflow =>
-                format!("Overflow"),
-
             super::Unimplemented =>
                 format!("Unimplemented"),
 
index 99c35c6e5425824a20b3e8ba2144f5d885dd4aba..e5e89c3fbd4b9802ed729631f7ad8dbafec6195f 100644 (file)
@@ -52,6 +52,7 @@
 use middle::region;
 use middle::resolve_lifetime;
 use middle::infer;
+use middle::pat_util;
 use middle::stability;
 use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
 use middle::traits;
@@ -2667,7 +2668,7 @@ pub fn mk_region(&self, region: Region) -> &'tcx Region {
     }
 
     pub fn closure_kind(&self, def_id: ast::DefId) -> ty::ClosureKind {
-        self.closure_kinds.borrow()[def_id]
+        *self.closure_kinds.borrow().get(&def_id).unwrap()
     }
 
     pub fn closure_type(&self,
@@ -2675,14 +2676,22 @@ pub fn closure_type(&self,
                         substs: &subst::Substs<'tcx>)
                         -> ty::ClosureTy<'tcx>
     {
-        self.closure_tys.borrow()[def_id].subst(self, substs)
+        self.closure_tys.borrow().get(&def_id).unwrap().subst(self, substs)
     }
 
     pub fn type_parameter_def(&self,
                               node_id: ast::NodeId)
                               -> TypeParameterDef<'tcx>
     {
-        self.ty_param_defs.borrow()[node_id].clone()
+        self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
+    }
+
+    pub fn pat_contains_ref_binding(&self, pat: &ast::Pat) -> bool {
+        pat_util::pat_contains_ref_binding(&self.def_map, pat)
+    }
+
+    pub fn arm_contains_ref_binding(&self, arm: &ast::Arm) -> bool {
+        pat_util::arm_contains_ref_binding(&self.def_map, arm)
     }
 }
 
@@ -5980,10 +5989,7 @@ pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
 
 pub fn trait_has_default_impl(tcx: &ctxt, trait_def_id: DefId) -> bool {
     populate_implementations_for_trait_if_necessary(tcx, trait_def_id);
-    match tcx.lang_items.to_builtin_kind(trait_def_id) {
-        Some(BoundSend) | Some(BoundSync) => true,
-        _ => tcx.traits_with_default_impls.borrow().contains_key(&trait_def_id),
-    }
+    tcx.traits_with_default_impls.borrow().contains_key(&trait_def_id)
 }
 
 /// Records a trait-to-implementation mapping.
@@ -6540,7 +6546,7 @@ pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool {
     }
 
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
-        Some(self.upvar_capture_map.borrow()[upvar_id].clone())
+        Some(self.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone())
     }
 }
 
index e368a6691332caa6b78d96c546d28d894bbd6a82..a7c67a0863182e6af468f5e4ba104a01b3c5a50c 100644 (file)
@@ -907,7 +907,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let cg = build_codegen_options(matches);
 
-    let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::new(&m));
+    let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
     let target = matches.opt_str("target").unwrap_or(
         host_triple().to_string());
     let opt_level = {
index 3c5d97445058b2d7ed3743a35192bb3bf4d5c910..3dc31f9524effe1e5b32668c7c7d707bbf9ce1fb 100644 (file)
@@ -54,7 +54,7 @@ pub fn add_path(&mut self, path: &str) {
         if path.is_empty() {
             early_error("empty search path given via `-L`");
         }
-        self.paths.push((kind, PathBuf::new(path)));
+        self.paths.push((kind, PathBuf::from(path)));
     }
 
     pub fn iter(&self, kind: PathKind) -> Iter {
index aec8ac38a5ad3a48fc94aff7b690e14c32576621..2cc51a723f2370c96a362fb87b2de0e83ecd18ed 100644 (file)
@@ -319,7 +319,7 @@ fn add_archive<F>(&mut self, archive: &Path, name: &str,
             };
             let new_filename = self.work_dir.path().join(&filename[..]);
             try!(fs::rename(&file, &new_filename));
-            self.members.push(PathBuf::new(&filename));
+            self.members.push(PathBuf::from(filename));
         }
         Ok(())
     }
index c29cbb352a321ce44bc2a5b911474fbf4787eff1..6d8891dd4fe078f058ed3ed958ede8b891013147 100644 (file)
@@ -19,7 +19,7 @@
 pub fn realpath(original: &Path) -> io::Result<PathBuf> {
     let old = old_path::Path::new(original.to_str().unwrap());
     match old_realpath(&old) {
-        Ok(p) => Ok(PathBuf::new(p.as_str().unwrap())),
+        Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())),
         Err(e) => Err(io::Error::new(io::ErrorKind::Other,
                                      "realpath error",
                                      Some(e.to_string())))
index 99d24a6013078f90be120d67ffadaf33a0b168bc..086742f740cdb362e0394a7658a4eb7a5d4cc9ea 100644 (file)
@@ -49,6 +49,7 @@
 #![feature(std_misc)]
 #![feature(path_relative_from)]
 #![feature(step_by)]
+#![feature(convert)]
 
 extern crate syntax;
 extern crate serialize;
index 4f9f1447d8a731b918f765666306916435348de4..68d21abb50ef5e74fd21f4a071ac3efa413bfc92 100644 (file)
@@ -99,30 +99,58 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String
     lib.pop();
     let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap();
     output.pop();
-    let relative = relativize(&lib, &output);
+    let relative = path_relative_from(&lib, &output)
+        .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib));
     // FIXME (#9639): This needs to handle non-utf8 paths
     format!("{}/{}", prefix,
             relative.to_str().expect("non-utf8 component in path"))
 }
 
-fn relativize(path: &Path, rel: &Path) -> PathBuf {
-    let mut res = PathBuf::new("");
-    let mut cur = rel;
-    while !path.starts_with(cur) {
-        res.push("..");
-        match cur.parent() {
-            Some(p) => cur = p,
-            None => panic!("can't create relative paths across filesystems"),
+// This routine is adapted from the *old* Path's `path_relative_from`
+// function, which works differently from the new `relative_from` function.
+// In particular, this handles the case on unix where both paths are
+// absolute but with only the root as the common directory.
+fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
+    use std::path::Component;
+
+    if path.is_absolute() != base.is_absolute() {
+        if path.is_absolute() {
+            Some(PathBuf::new(path))
+        } else {
+            None
         }
+    } else {
+        let mut ita = path.components();
+        let mut itb = base.components();
+        let mut comps: Vec<Component> = vec![];
+        loop {
+            match (ita.next(), itb.next()) {
+                (None, None) => break,
+                (Some(a), None) => {
+                    comps.push(a);
+                    comps.extend(ita.by_ref());
+                    break;
+                }
+                (None, _) => comps.push(Component::ParentDir),
+                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
+                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
+                (Some(_), Some(b)) if b == Component::ParentDir => return None,
+                (Some(a), Some(_)) => {
+                    comps.push(Component::ParentDir);
+                    for _ in itb {
+                        comps.push(Component::ParentDir);
+                    }
+                    comps.push(a);
+                    comps.extend(ita.by_ref());
+                    break;
+                }
+            }
+        }
+        Some(comps.iter().map(|c| c.as_os_str()).collect())
     }
-    match path.relative_from(cur) {
-        Some(s) => { res.push(s); res }
-        None => panic!("couldn't create relative path from {:?} to {:?}",
-                       rel, path),
-    }
-
 }
 
+
 fn get_install_prefix_rpath(config: &mut RPathConfig) -> String {
     let path = (config.get_install_prefix_lib_path)();
     let path = env::current_dir().unwrap().join(&path);
index 4663901a7b4c1f84114586dc066bf05feecf5aac..c464658f447acd973d1568b93dca9285c59dd21b 100644 (file)
@@ -393,11 +393,11 @@ macro_rules! load_specific {
         let path = {
             let mut target = target.to_string();
             target.push_str(".json");
-            PathBuf::new(&target)
+            PathBuf::from(target)
         };
 
         let target_path = env::var_os("RUST_TARGET_PATH")
-                              .unwrap_or(OsString::from_str(""));
+                              .unwrap_or(OsString::new());
 
         // FIXME 16351: add a sane default search path?
 
index 8846f70fbd335febf9b005813b07dfc2b885bb03..2834fce5278c85ab7b3caf36f3de0a47425e6a30 100644 (file)
@@ -486,7 +486,7 @@ fn add_gen_kills(&self,
             match path.loan_path.kind {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
                     let kill_scope = path.loan_path.kill_scope(tcx);
-                    let path = self.path_map.borrow()[path.loan_path];
+                    let path = *self.path_map.borrow().get(&path.loan_path).unwrap();
                     self.kill_moves(path, kill_scope.node_id(), dfcx_moves);
                 }
                 LpExtend(..) => {}
index e09457970e12f776513d60245527aab02288f6c5..e927ea5b86cdd27bc3416ced57069c96bf3b5e22 100644 (file)
@@ -28,6 +28,7 @@
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(unsafe_destructor)]
+#![feature(into_cow)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
index dc27a30110950454f813cf5ac82003408a379e37..4c654cbf27de05fd5bfecd79ba31d0b91a3a857e 100644 (file)
@@ -468,7 +468,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
             // dependent dlls. Note that this uses cfg!(windows) as opposed to
             // targ_cfg because syntax extensions are always loaded for the host
             // compiler, not for the target.
-            let mut _old_path = OsString::from_str("");
+            let mut _old_path = OsString::new();
             if cfg!(windows) {
                 _old_path = env::var_os("PATH").unwrap_or(_old_path);
                 let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths();
@@ -752,7 +752,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 pub fn phase_6_link_output(sess: &Session,
                            trans: &trans::CrateTranslation,
                            outputs: &OutputFilenames) {
-    let old_path = env::var_os("PATH").unwrap_or(OsString::from_str(""));
+    let old_path = env::var_os("PATH").unwrap_or(OsString::new());
     let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
     new_path.extend(env::split_paths(&old_path));
     env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
@@ -927,7 +927,7 @@ pub fn build_output_filenames(input: &Input,
             // We want to toss everything after the final '.'
             let dirpath = match *odir {
                 Some(ref d) => d.clone(),
-                None => PathBuf::new("")
+                None => PathBuf::new()
             };
 
             // If a crate name is present, we use it as the link name
index 0071e4434efa4a5ae8cc1aff523c887388c41c67..5e6f2fb835bb2a01787ebf36f027bcf5e1a4ed58 100644 (file)
@@ -39,6 +39,7 @@
 #![feature(io)]
 #![feature(set_stdio)]
 #![feature(unicode)]
+#![feature(convert)]
 
 extern crate arena;
 extern crate flate;
@@ -163,8 +164,8 @@ macro_rules! do_or_return {($expr: expr) => {
 
 // Extract output directory and file from matches.
 fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
-    let odir = matches.opt_str("out-dir").map(|o| PathBuf::new(&o));
-    let ofile = matches.opt_str("o").map(|o| PathBuf::new(&o));
+    let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
+    let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
     (odir, ofile)
 }
 
@@ -177,7 +178,7 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> {
             io::stdin().read_to_string(&mut src).unwrap();
             Some((Input::Str(src), None))
         } else {
-            Some((Input::File(PathBuf::new(ifile)), Some(PathBuf::new(ifile))))
+            Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile))))
         }
     } else {
         None
@@ -858,9 +859,9 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry {
     use syntax::diagnostics::registry::Registry;
 
     let all_errors = Vec::new() +
-        rustc::diagnostics::DIAGNOSTICS.as_slice() +
-        rustc_typeck::diagnostics::DIAGNOSTICS.as_slice() +
-        rustc_resolve::diagnostics::DIAGNOSTICS.as_slice();
+        &rustc::diagnostics::DIAGNOSTICS[..] +
+        &rustc_typeck::diagnostics::DIAGNOSTICS[..] +
+        &rustc_resolve::diagnostics::DIAGNOSTICS[..];
 
     Registry::new(&*all_errors)
 }
index f6f82c65374bd2bf9f0f8f5c2be28576892d6c28..e65fe904dd29af28eb5e1a3e1dad8e836afde366 100644 (file)
@@ -418,7 +418,7 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     fn check_def(&mut self, sp: Span, id: ast::NodeId) {
-        match self.cx.tcx.def_map.borrow()[id].full_def() {
+        match self.cx.tcx.def_map.borrow().get(&id).unwrap().full_def() {
             def::DefPrimTy(ast::TyInt(ast::TyIs(_))) => {
                 self.cx.span_lint(IMPROPER_CTYPES, sp,
                                   "found rust type `isize` in foreign module, while \
@@ -2056,7 +2056,7 @@ fn check_item(&mut self, cx: &Context, it: &ast::Item) {
                 }
             },
             ast::ItemStatic(..) => {
-                if attr::contains_name(it.attrs.as_slice(), "no_mangle") &&
+                if attr::contains_name(&it.attrs, "no_mangle") &&
                        !cx.exported_items.contains(&it.id) {
                     let msg = format!("static {} is marked #[no_mangle], but not exported",
                                       it.ident);
@@ -2064,7 +2064,7 @@ fn check_item(&mut self, cx: &Context, it: &ast::Item) {
                 }
             },
             ast::ItemConst(..) => {
-                if attr::contains_name(it.attrs.as_slice(), "no_mangle") {
+                if attr::contains_name(&it.attrs, "no_mangle") {
                     // Const items do not refer to a particular location in memory, and therefore
                     // don't have anything to attach a symbol to
                     let msg = "const items should never be #[no_mangle], consider instead using \
index bfce2f0062de48f8591406f4af87b2f0a3d85a43..2e7fe91365a13475dabf5e99106be2e2b82421dd 100644 (file)
@@ -253,7 +253,7 @@ fn visit_item(&mut self, item: &ast::Item) {
             ast::ItemImpl(_, _, _, _, ref ty, ref impl_items) => {
                 let public_ty = match ty.node {
                     ast::TyPath(..) => {
-                        match self.tcx.def_map.borrow()[ty.id].full_def() {
+                        match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
                             def::DefPrimTy(..) => true,
                             def => {
                                 let did = def.def_id();
@@ -317,7 +317,7 @@ fn visit_item(&mut self, item: &ast::Item) {
 
             ast::ItemTy(ref ty, _) if public_first => {
                 if let ast::TyPath(..) = ty.node {
-                    match self.tcx.def_map.borrow()[ty.id].full_def() {
+                    match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
                         def::DefPrimTy(..) | def::DefTyParam(..) => {},
                         def => {
                             let did = def.def_id();
@@ -349,7 +349,7 @@ fn visit_mod(&mut self, m: &ast::Mod, _sp: Span, id: ast::NodeId) {
         // crate module gets processed as well.
         if self.prev_exported {
             assert!(self.export_map.contains_key(&id), "wut {}", id);
-            for export in &self.export_map[id] {
+            for export in self.export_map.get(&id).unwrap() {
                 if is_local(export.def_id) {
                     self.reexports.insert(export.def_id.node);
                 }
@@ -525,7 +525,7 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
             // if we've reached the root, then everything was allowable and this
             // access is public.
             if closest_private_id == ast::CRATE_NODE_ID { return Allowable }
-            closest_private_id = self.parents[closest_private_id];
+            closest_private_id = *self.parents.get(&closest_private_id).unwrap();
 
             // If we reached the top, then we were public all the way down and
             // we can allow this access.
@@ -543,7 +543,7 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
     /// whether the node is accessible by the current module that iteration is
     /// inside.
     fn private_accessible(&self, id: ast::NodeId) -> bool {
-        let parent = self.parents[id];
+        let parent = *self.parents.get(&id).unwrap();
         debug!("privacy - accessible parent {}", self.nodestr(parent));
 
         // After finding `did`'s closest private member, we roll ourselves back
@@ -567,7 +567,7 @@ fn private_accessible(&self, id: ast::NodeId) -> bool {
                 _ => {}
             }
 
-            cur = self.parents[cur];
+            cur = *self.parents.get(&cur).unwrap();
         }
     }
 
@@ -622,7 +622,7 @@ fn ensure_public(&self, span: Span, to_check: ast::DefId,
                             ast::TyPath(..) => {}
                             _ => return Some((err_span, err_msg, None)),
                         };
-                        let def = self.tcx.def_map.borrow()[ty.id].full_def();
+                        let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
                         let did = def.def_id();
                         assert!(is_local(did));
                         match self.tcx.map.get(did.node) {
@@ -708,7 +708,7 @@ fn check_static_method(&mut self,
     // Checks that a path is in scope.
     fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Ident) {
         debug!("privacy - path {}", self.nodestr(path_id));
-        let path_res = self.tcx.def_map.borrow()[path_id];
+        let path_res = *self.tcx.def_map.borrow().get(&path_id).unwrap();
         let ck = |tyname: &str| {
             let ck_public = |def: ast::DefId| {
                 debug!("privacy - ck_public {:?}", def);
@@ -881,7 +881,7 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
                         }
                     }
                     ty::ty_enum(_, _) => {
-                        match self.tcx.def_map.borrow()[expr.id].full_def() {
+                        match self.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
                             def::DefVariant(_, variant_id, _) => {
                                 for field in fields {
                                     self.check_field(expr.span, variant_id,
index b619c6a77d009597eef5b2f806a9ac4d0722d566..566af2590e6c07cd0ec1a256856951ee36478222 100644 (file)
@@ -900,7 +900,7 @@ fn record_import_use(&mut self, import_id: NodeId, name: Name) {
             return;
         }
         if self.glob_map.contains_key(&import_id) {
-            self.glob_map[import_id].insert(name);
+            self.glob_map.get_mut(&import_id).unwrap().insert(name);
             return;
         }
 
index 737ec71cab3da09273b69f94d3653d37674e91eb..46451019760dd478aa179449473532a32d15fe63 100644 (file)
@@ -603,7 +603,7 @@ fn get_binding(this: &mut Resolver,
 
         // We've successfully resolved the import. Write the results in.
         let mut import_resolutions = module_.import_resolutions.borrow_mut();
-        let import_resolution = &mut (*import_resolutions)[target];
+        let import_resolution = import_resolutions.get_mut(&target).unwrap();
 
         {
             let mut check_and_write_import = |namespace, result: &_, used_public: &mut bool| {
index 3904db4433c892a69bffc712ea2d01afa73788c0..1f416d5404d2778d0fdea4768371232068e2bae8 100644 (file)
@@ -1 +1 @@
-See the README.txt in ../librustc.
+See the README.md in ../librustc.
index 34a23f3efac42c3011bbb2773d05f58f01aea631..bb7880161d5d4e364b2ebc7701468e64d3820a77 100644 (file)
@@ -877,7 +877,7 @@ fn link_args(cmd: &mut Command,
         if t.options.is_like_osx {
             let morestack = lib_path.join("libmorestack.a");
 
-            let mut v = OsString::from_str("-Wl,-force_load,");
+            let mut v = OsString::from("-Wl,-force_load,");
             v.push(&morestack);
             cmd.arg(&v);
         } else {
@@ -1002,7 +1002,7 @@ fn link_args(cmd: &mut Command,
             cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
 
             if sess.opts.cg.rpath {
-                let mut v = OsString::from_str("-Wl,-install_name,@rpath/");
+                let mut v = OsString::from("-Wl,-install_name,@rpath/");
                 v.push(out_filename.file_name().unwrap());
                 cmd.arg(&v);
             }
@@ -1020,7 +1020,7 @@ fn link_args(cmd: &mut Command,
         let mut get_install_prefix_lib_path = || {
             let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");
             let tlib = filesearch::relative_target_lib_path(sysroot, target_triple);
-            let mut path = PathBuf::new(install_prefix);
+            let mut path = PathBuf::from(install_prefix);
             path.push(&tlib);
 
             path
@@ -1102,7 +1102,7 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
                                             &sess.target.target.options.staticlib_suffix,
                                             &search_path[..],
                                             &sess.diagnostic().handler);
-            let mut v = OsString::from_str("-Wl,-force_load,");
+            let mut v = OsString::from("-Wl,-force_load,");
             v.push(&lib);
             cmd.arg(&v);
         }
@@ -1141,9 +1141,9 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
     // involves just passing the right -l flag.
 
     let data = if dylib {
-        &trans.crate_formats[config::CrateTypeDylib]
+        trans.crate_formats.get(&config::CrateTypeDylib).unwrap()
     } else {
-        &trans.crate_formats[config::CrateTypeExecutable]
+        trans.crate_formats.get(&config::CrateTypeExecutable).unwrap()
     };
 
     // Invoke get_used_crates to ensure that we get a topological sorting of
index efc81da560b6e262e0cc9ed52f9eaa50fe4781ad..176e3805a311f3a0865b8b6cb65caba291ba9930 100644 (file)
@@ -41,6 +41,7 @@
 #![feature(path_ext)]
 #![feature(fs)]
 #![feature(hash)]
+#![feature(convert)]
 #![feature(path_relative_from)]
 
 extern crate arena;
index 83bb5efb425d26564f746145dcba376b4086f67b..53aa6d44fe7e86f014df2b7a65737af761883975 100644 (file)
@@ -219,7 +219,7 @@ fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
             self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
                                   ref_id));
         }
-        let def = self.analysis.ty_cx.def_map.borrow()[ref_id].full_def();
+        let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def();
         match def {
             def::DefPrimTy(_) => None,
             _ => Some(def.def_id()),
@@ -232,7 +232,7 @@ fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
             self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind",
                                              ref_id));
         }
-        let def = def_map[ref_id].full_def();
+        let def = def_map.get(&ref_id).unwrap().full_def();
         match def {
             def::DefMod(_) |
             def::DefForeignMod(_) => Some(recorder::ModRef),
@@ -269,8 +269,10 @@ fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) {
             self.collecting = false;
             let span_utils = self.span.clone();
             for &(id, ref p, _, _) in &self.collected_paths {
-                let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
-                    (*self.analysis.ty_cx.node_types.borrow())[id]);
+                let typ =
+                    ppaux::ty_to_string(
+                        &self.analysis.ty_cx,
+                        *self.analysis.ty_cx.node_types.borrow().get(&id).unwrap());
                 // get the span only for the name of the variable (I hope the path is only ever a
                 // variable name, but who knows?)
                 self.fmt.formal_str(p.span,
@@ -431,8 +433,10 @@ fn process_struct_field_def(&mut self,
             ast::NamedField(ident, _) => {
                 let name = get_ident(ident);
                 let qualname = format!("{}::{}", qualname, name);
-                let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
-                    (*self.analysis.ty_cx.node_types.borrow())[field.node.id]);
+                let typ =
+                    ppaux::ty_to_string(
+                        &self.analysis.ty_cx,
+                        *self.analysis.ty_cx.node_types.borrow().get(&field.node.id).unwrap());
                 match self.span.sub_span_before_token(field.span, token::Colon) {
                     Some(sub_span) => self.fmt.field_str(field.span,
                                                          Some(sub_span),
@@ -789,7 +793,7 @@ fn process_path(&mut self,
             self.sess.span_bug(span,
                                &format!("def_map has no key for {} in visit_expr", id));
         }
-        let def = def_map[id].full_def();
+        let def = def_map.get(&id).unwrap().full_def();
         let sub_span = self.span.span_for_last_ident(span);
         match def {
             def::DefUpvar(..) |
@@ -832,7 +836,8 @@ fn process_path(&mut self,
                                                  .ty_cx
                                                  .impl_items
                                                  .borrow();
-                            Some((*impl_items)[def_id]
+                            Some(impl_items.get(&def_id)
+                                           .unwrap()
                                            .iter()
                                            .find(|mr| {
                                                 ty::impl_or_trait_item(
@@ -941,7 +946,7 @@ fn process_method_call(&mut self,
                            ex: &ast::Expr,
                            args: &Vec<P<ast::Expr>>) {
         let method_map = self.analysis.ty_cx.method_map.borrow();
-        let method_callee = &(*method_map)[ty::MethodCall::expr(ex.id)];
+        let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
         let (def_id, decl_id) = match method_callee.origin {
             ty::MethodStatic(def_id) |
             ty::MethodStaticClosure(def_id) => {
@@ -1001,7 +1006,7 @@ fn process_pat(&mut self, p:&ast::Pat) {
                 self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef));
                 visit::walk_path(self, path);
 
-                let def = self.analysis.ty_cx.def_map.borrow()[p.id].full_def();
+                let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
                 let struct_def = match def {
                     def::DefConst(..) => None,
                     def::DefVariant(_, variant_id, _) => Some(variant_id),
@@ -1113,7 +1118,7 @@ fn visit_item(&mut self, item: &ast::Item) {
                         let glob_map = &self.analysis.glob_map;
                         let glob_map = glob_map.as_ref().unwrap();
                         if glob_map.contains_key(&item.id) {
-                            for n in &glob_map[item.id] {
+                            for n in glob_map.get(&item.id).unwrap() {
                                 if name_string.len() > 0 {
                                     name_string.push_str(", ");
                                 }
@@ -1406,7 +1411,7 @@ fn visit_arm(&mut self, arm: &ast::Arm) {
                                    &format!("def_map has no key for {} in visit_arm",
                                            id));
             }
-            let def = def_map[id].full_def();
+            let def = def_map.get(&id).unwrap().full_def();
             match def {
                 def::DefLocal(id)  => {
                     let value = if *immut {
@@ -1467,7 +1472,7 @@ fn visit_local(&mut self, l: &ast::Local) {
         for &(id, ref p, ref immut, _) in &self.collected_paths {
             let value = if *immut { value.to_string() } else { "<mutable>".to_string() };
             let types = self.analysis.ty_cx.node_types.borrow();
-            let typ = ppaux::ty_to_string(&self.analysis.ty_cx, (*types)[id]);
+            let typ = ppaux::ty_to_string(&self.analysis.ty_cx, *types.get(&id).unwrap());
             // Get the span only for the name of the variable (I hope the path
             // is only ever a variable name, but who knows?).
             let sub_span = self.span.span_for_last_ident(p.span);
@@ -1509,10 +1514,10 @@ pub fn process_crate(sess: &Session,
 
     // find a path to dump our data to
     let mut root_path = match env::var_os("DXR_RUST_TEMP_FOLDER") {
-        Some(val) => PathBuf::new(&val),
+        Some(val) => PathBuf::from(val),
         None => match odir {
             Some(val) => val.join("dxr"),
-            None => PathBuf::new("dxr-temp"),
+            None => PathBuf::from("dxr-temp"),
         },
     };
 
index 44f6d1bfd0b07fa1a5378096530191e45647a488..eb759393ac6eca125f2432641e792c9d37575c2d 100644 (file)
@@ -326,7 +326,7 @@ pub enum OptResult<'blk, 'tcx: 'blk> {
     LowerBound(Result<'blk, 'tcx>)
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 pub enum TransBindingMode {
     TrByCopy(/* llbinding */ ValueRef),
     TrByMove,
@@ -1017,9 +1017,14 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         None => {
             let data = &m[0].data;
             for &(ref ident, ref value_ptr) in &m[0].bound_ptrs {
-                let llmatch = data.bindings_map[*ident].llmatch;
-                call_lifetime_start(bcx, llmatch);
-                Store(bcx, *value_ptr, llmatch);
+                let binfo = *data.bindings_map.get(ident).unwrap();
+                call_lifetime_start(bcx, binfo.llmatch);
+                if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) {
+                    expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch);
+                }
+                else {
+                    Store(bcx, *value_ptr, binfo.llmatch);
+                }
             }
             match data.arm.guard {
                 Some(ref guard_expr) => {
@@ -1087,7 +1092,6 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             _ => None
         }
     };
-
     match adt_vals {
         Some(field_vals) => {
             let pats = enter_match(bcx, dm, m, col, val, |pats|
@@ -1694,8 +1698,14 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
                             ast::BindByRef(_) => {
                                 // By ref binding: the value of the variable
-                                // is the pointer `val` itself.
-                                Store(bcx, val, llval);
+                                // is the pointer `val` itself or fat pointer referenced by `val`
+                                if type_is_fat_ptr(bcx.tcx(), ty) {
+                                    expr::copy_fat_ptr(bcx, val, llval);
+                                }
+                                else {
+                                    Store(bcx, val, llval);
+                                }
+
                                 bcx
                             }
                         }
index a3bd0cf6b1a623bac1cf719408aa45f7d1696859..33817bb952e98967eb428e326b3654d173505839 100644 (file)
@@ -76,43 +76,33 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
     // no failure occurred preparing operands, no need to cleanup
     fcx.pop_custom_cleanup_scope(temp_scope);
 
-    let mut constraints = constraints.iter()
-                                     .map(|s| s.to_string())
-                                     .chain(ext_constraints.into_iter())
-                                     .collect::<Vec<String>>()
-                                     .connect(",");
-
-    let mut clobbers = ia.clobbers.iter()
-                                  .map(|s| format!("~{{{}}}", &s))
-                                  .collect::<Vec<String>>()
-                                  .connect(",");
-    let more_clobbers = get_clobbers();
-    if !more_clobbers.is_empty() {
-        if !clobbers.is_empty() {
-            clobbers.push(',');
-        }
-        clobbers.push_str(&more_clobbers[..]);
-    }
-
-    // Add the clobbers to our constraints list
-    if clobbers.len() != 0 && constraints.len() != 0 {
-        constraints.push(',');
-        constraints.push_str(&clobbers[..]);
-    } else {
-        constraints.push_str(&clobbers[..]);
-    }
+    let clobbers = ia.clobbers.iter()
+                              .map(|s| format!("~{{{}}}", &s));
+
+    // Default per-arch clobbers
+    // Basically what clang does
+    let arch_clobbers = match bcx.sess().target.target.arch.as_slice() {
+        "x86" | "x86_64" => vec!("~{dirflag}", "~{fpsr}", "~{flags}"),
+        _                => Vec::new()
+    };
 
-    debug!("Asm Constraints: {}", &constraints[..]);
+    let all_constraints= constraints.iter()
+                                    .map(|s| s.to_string())
+                                    .chain(ext_constraints.into_iter())
+                                    .chain(clobbers)
+                                    .chain(arch_clobbers.iter()
+                                               .map(|s| s.to_string()))
+                                    .collect::<Vec<String>>()
+                                    .connect(",");
 
-    let num_outputs = outputs.len();
+    debug!("Asm Constraints: {}", &all_constraints[..]);
 
     // Depending on how many outputs we have, the return type is different
-    let output_type = if num_outputs == 0 {
-        Type::void(bcx.ccx())
-    } else if num_outputs == 1 {
-        output_types[0]
-    } else {
-        Type::struct_(bcx.ccx(), &output_types[..], false)
+    let num_outputs = outputs.len();
+    let output_type = match num_outputs {
+        0 => Type::void(bcx.ccx()),
+        1 => output_types[0],
+        _ => Type::struct_(bcx.ccx(), &output_types[..], false)
     };
 
     let dialect = match ia.dialect {
@@ -121,10 +111,10 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
     };
 
     let asm = CString::new(ia.asm.as_bytes()).unwrap();
-    let constraints = CString::new(constraints).unwrap();
+    let constraint_cstr = CString::new(all_constraints).unwrap();
     let r = InlineAsmCall(bcx,
                           asm.as_ptr(),
-                          constraints.as_ptr(),
+                          constraint_cstr.as_ptr(),
                           &inputs,
                           output_type,
                           ia.volatile,
@@ -158,15 +148,3 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
 
 }
 
-// Default per-arch clobbers
-// Basically what clang does
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-fn get_clobbers() -> String {
-    "".to_string()
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn get_clobbers() -> String {
-    "~{dirflag},~{fpsr},~{flags}".to_string()
-}
index f584de7c47f3b88a22befaa1328e41c4d56053bb..e87c4e4af4a7aa9cfee760c31f24db1ce73aa6c6 100644 (file)
@@ -269,7 +269,7 @@ pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 }
 
 pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::ClosureKind {
-    ccx.tcx().closure_kinds.borrow()[closure_id]
+    *ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap()
 }
 
 pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -756,7 +756,7 @@ fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
 }
 
 pub fn cast_shift_expr_rhs(cx: Block,
-                           op: ast::BinOp,
+                           op: ast::BinOp_,
                            lhs: ValueRef,
                            rhs: ValueRef)
                            -> ValueRef {
@@ -765,24 +765,24 @@ pub fn cast_shift_expr_rhs(cx: Block,
                    |a,b| ZExt(cx, a, b))
 }
 
-pub fn cast_shift_const_rhs(op: ast::BinOp,
+pub fn cast_shift_const_rhs(op: ast::BinOp_,
                             lhs: ValueRef, rhs: ValueRef) -> ValueRef {
     cast_shift_rhs(op, lhs, rhs,
                    |a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) },
                    |a, b| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) })
 }
 
-pub fn cast_shift_rhs<F, G>(op: ast::BinOp,
-                            lhs: ValueRef,
-                            rhs: ValueRef,
-                            trunc: F,
-                            zext: G)
-                            -> ValueRef where
+fn cast_shift_rhs<F, G>(op: ast::BinOp_,
+                        lhs: ValueRef,
+                        rhs: ValueRef,
+                        trunc: F,
+                        zext: G)
+                        -> ValueRef where
     F: FnOnce(ValueRef, Type) -> ValueRef,
     G: FnOnce(ValueRef, Type) -> ValueRef,
 {
     // Shifts may have any size int on the rhs
-    if ast_util::is_shift_binop(op.node) {
+    if ast_util::is_shift_binop(op) {
         let mut rhs_llty = val_ty(rhs);
         let mut lhs_llty = val_ty(lhs);
         if rhs_llty.kind() == Vector { rhs_llty = rhs_llty.element_type() }
@@ -983,56 +983,72 @@ pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
 /// gives us better information about what we are loading.
 pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                            ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
-    if type_is_zero_size(cx.ccx(), t) {
-        C_undef(type_of::type_of(cx.ccx(), t))
-    } else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
-        // We want to pass small aggregates as immediate values, but using an aggregate LLVM type
-        // for this leads to bad optimizations, so its arg type is an appropriately sized integer
-        // and we have to convert it
-        Load(cx, BitCast(cx, ptr, type_of::arg_type_of(cx.ccx(), t).ptr_to()))
-    } else {
-        unsafe {
-            let global = llvm::LLVMIsAGlobalVariable(ptr);
-            if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
-                let val = llvm::LLVMGetInitializer(global);
-                if !val.is_null() {
-                    // This could go into its own function, for DRY.
-                    // (something like "pre-store packing/post-load unpacking")
-                    if ty::type_is_bool(t) {
-                        return Trunc(cx, val, Type::i1(cx.ccx()));
-                    } else {
-                        return val;
-                    }
-                }
+    if cx.unreachable.get() || type_is_zero_size(cx.ccx(), t) {
+        return C_undef(type_of::type_of(cx.ccx(), t));
+    }
+
+    let ptr = to_arg_ty_ptr(cx, ptr, t);
+
+    if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
+        return Load(cx, ptr);
+    }
+
+    unsafe {
+        let global = llvm::LLVMIsAGlobalVariable(ptr);
+        if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
+            let val = llvm::LLVMGetInitializer(global);
+            if !val.is_null() {
+                return from_arg_ty(cx, val, t);
             }
         }
-        if ty::type_is_bool(t) {
-            Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx()))
-        } else if ty::type_is_char(t) {
-            // a char is a Unicode codepoint, and so takes values from 0
-            // to 0x10FFFF inclusive only.
-            LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
-        } else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t))
-                  && !common::type_is_fat_ptr(cx.tcx(), t) {
-            LoadNonNull(cx, ptr)
-        } else {
-            Load(cx, ptr)
-        }
     }
+
+    let val =  if ty::type_is_bool(t) {
+        LoadRangeAssert(cx, ptr, 0, 2, llvm::False)
+    } else if ty::type_is_char(t) {
+        // a char is a Unicode codepoint, and so takes values from 0
+        // to 0x10FFFF inclusive only.
+        LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
+    } else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t))
+        && !common::type_is_fat_ptr(cx.tcx(), t) {
+            LoadNonNull(cx, ptr)
+    } else {
+        Load(cx, ptr)
+    };
+
+    from_arg_ty(cx, val, t)
 }
 
 /// Helper for storing values in memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values.
 pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
-    if ty::type_is_bool(t) {
-        Store(cx, ZExt(cx, v, Type::i8(cx.ccx())), dst);
-    } else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
+    Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
+}
+
+pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
+    if ty::type_is_bool(ty) {
+        ZExt(bcx, val, Type::i8(bcx.ccx()))
+    } else {
+        val
+    }
+}
+
+pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
+    if ty::type_is_bool(ty) {
+        Trunc(bcx, val, Type::i1(bcx.ccx()))
+    } else {
+        val
+    }
+}
+
+pub fn to_arg_ty_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef, ty: Ty<'tcx>) -> ValueRef {
+    if type_is_immediate(bcx.ccx(), ty) && type_of::type_of(bcx.ccx(), ty).is_aggregate() {
         // We want to pass small aggregates as immediate values, but using an aggregate LLVM type
         // for this leads to bad optimizations, so its arg type is an appropriately sized integer
         // and we have to convert it
-        Store(cx, v, BitCast(cx, dst, type_of::arg_type_of(cx.ccx(), t).ptr_to()));
+        BitCast(bcx, ptr, type_of::arg_type_of(bcx.ccx(), ty).ptr_to())
     } else {
-        Store(cx, v, dst);
+        ptr
     }
 }
 
@@ -1575,55 +1591,6 @@ fn copy_args_to_allocas<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     bcx
 }
 
-fn copy_closure_args_to_allocas<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                            arg_scope: cleanup::CustomScopeIndex,
-                                            args: &[ast::Arg],
-                                            arg_datums: Vec<RvalueDatum<'tcx>>,
-                                            monomorphized_arg_types: &[Ty<'tcx>])
-                                            -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("copy_closure_args_to_allocas");
-    let arg_scope_id = cleanup::CustomScope(arg_scope);
-
-    assert_eq!(arg_datums.len(), 1);
-
-    let arg_datum = arg_datums.into_iter().next().unwrap();
-
-    // Untuple the rest of the arguments.
-    let tuple_datum =
-        unpack_datum!(bcx,
-                      arg_datum.to_lvalue_datum_in_scope(bcx,
-                                                         "argtuple",
-                                                         arg_scope_id));
-    let untupled_arg_types = match monomorphized_arg_types[0].sty {
-        ty::ty_tup(ref types) => &types[..],
-        _ => {
-            bcx.tcx().sess.span_bug(args[0].pat.span,
-                                    "first arg to `rust-call` ABI function \
-                                     wasn't a tuple?!")
-        }
-    };
-    for j in 0..args.len() {
-        let tuple_element_type = untupled_arg_types[j];
-        let tuple_element_datum =
-            tuple_datum.get_element(bcx,
-                                    tuple_element_type,
-                                    |llval| GEPi(bcx, llval, &[0, j]));
-        let tuple_element_datum = tuple_element_datum.to_expr_datum();
-        let tuple_element_datum =
-            unpack_datum!(bcx,
-                          tuple_element_datum.to_rvalue_datum(bcx,
-                                                              "arg"));
-        bcx = _match::store_arg(bcx,
-                                &*args[j].pat,
-                                tuple_element_datum,
-                                arg_scope_id);
-
-        debuginfo::create_argument_metadata(bcx, &args[j]);
-    }
-
-    bcx
-}
-
 // Ties up the llstaticallocas -> llloadenv -> lltop edges,
 // and builds the return block.
 pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>,
@@ -1781,33 +1748,18 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     debug!("trans_closure: function lltype: {}",
            bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn));
 
-    let arg_datums = if abi != RustCall {
-        create_datums_for_fn_args(&fcx,
-                                  &monomorphized_arg_types[..])
-    } else {
-        create_datums_for_fn_args_under_call_abi(
-            bcx,
-            arg_scope,
-            &monomorphized_arg_types[..])
-    };
-
-    bcx = match closure_env {
-        closure::ClosureEnv::NotClosure => {
-            copy_args_to_allocas(bcx,
-                                 arg_scope,
-                                 &decl.inputs,
-                                 arg_datums)
+    let arg_datums = match closure_env {
+        closure::ClosureEnv::NotClosure if abi == RustCall => {
+            create_datums_for_fn_args_under_call_abi(bcx, arg_scope, &monomorphized_arg_types[..])
         }
-        closure::ClosureEnv::Closure(_) => {
-            copy_closure_args_to_allocas(
-                bcx,
-                arg_scope,
-                &decl.inputs,
-                arg_datums,
-                &monomorphized_arg_types[..])
+        _ => {
+            let arg_tys = untuple_arguments_if_necessary(ccx, &monomorphized_arg_types, abi);
+            create_datums_for_fn_args(&fcx, &arg_tys)
         }
     };
 
+    bcx = copy_args_to_allocas(bcx, arg_scope, &decl.inputs, arg_datums);
+
     bcx = closure_env.load(bcx, cleanup::CustomScope(arg_scope));
 
     // Up until here, IR instructions for this function have explicitly not been annotated with
@@ -2306,7 +2258,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
                                          static");
               }
 
-              let v = ccx.static_values().borrow()[item.id].clone();
+              let v = ccx.static_values().borrow().get(&item.id).unwrap().clone();
               unsafe {
                   if !(llvm::LLVMConstIntGetZExtValue(v) != 0) {
                       ccx.sess().span_fatal(expr.span, "static assertion failed");
index cf36ec1f3ed96f49954a1ec836a582ae23c6460c..088a34857e753a8991be403b55d93da17de960b4 100644 (file)
@@ -511,7 +511,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
             let ref_ty = match node {
                 ExprId(id) => ty::node_id_to_type(tcx, id),
                 MethodCallKey(method_call) => {
-                    (*tcx.method_map.borrow())[method_call].ty
+                    tcx.method_map.borrow().get(&method_call).unwrap().ty
                 }
             };
             let ref_ty = monomorphize::apply_param_substs(tcx,
index 8f5dbfe2ec000ad2a52fb2516c3ea76387ef03ee..61cdde3bfbecd775a24346f063341a12e8bff644 100644 (file)
@@ -709,7 +709,7 @@ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>
     }
 
     fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
-        Some(self.tcx().upvar_capture_map.borrow()[upvar_id].clone())
+        Some(self.tcx().upvar_capture_map.borrow().get(&upvar_id).unwrap().clone())
     }
 
     fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
@@ -1025,8 +1025,9 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // shallow result we are looking for -- that is, what specific impl.
     let typer = NormalizingClosureTyper::new(tcx);
     let mut selcx = traits::SelectionContext::new(&infcx, &typer);
-    let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
-                                             trait_ref.to_poly_trait_predicate());
+    let obligation =
+        traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
+                                trait_ref.to_poly_trait_predicate());
     let selection = match selcx.select(&obligation) {
         Ok(Some(selection)) => selection,
         Ok(None) => {
@@ -1081,7 +1082,7 @@ pub fn predicates_hold<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), predicate);
         fulfill_cx.register_predicate_obligation(&infcx, obligation);
     }
-    drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &()).is_ok()
+    drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
 }
 
 pub struct NormalizingClosureTyper<'a,'tcx:'a> {
@@ -1138,7 +1139,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
                                                 -> T
     where T : TypeFoldable<'tcx> + Repr<'tcx>
 {
-    match drain_fulfillment_cx(span, infcx, fulfill_cx, result) {
+    match drain_fulfillment_cx(infcx, fulfill_cx, result) {
         Ok(v) => v,
         Err(errors) => {
             infcx.tcx.sess.span_bug(
@@ -1156,8 +1157,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
 /// inference variables that appear in `result` to be unified, and
 /// hence we need to process those obligations to get the complete
 /// picture of the type.
-pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
-                                       infcx: &infer::InferCtxt<'a,'tcx>,
+pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>,
                                        fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                        result: &T)
                                        -> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
@@ -1173,14 +1173,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
     match fulfill_cx.select_all_or_error(infcx, &typer) {
         Ok(()) => { }
         Err(errors) => {
-            // We always want to surface any overflow errors, no matter what.
-            if errors.iter().all(|e| e.is_overflow()) {
-                infcx.tcx.sess.span_fatal(
-                    span,
-                    "reached the recursion limit during monomorphization");
-            } else {
-                return Err(errors);
-            }
+            return Err(errors);
         }
     }
 
@@ -1213,7 +1206,7 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             ty::node_id_item_substs(tcx, id).substs
         }
         MethodCallKey(method_call) => {
-            (*tcx.method_map.borrow())[method_call].substs.clone()
+            tcx.method_map.borrow().get(&method_call).unwrap().substs.clone()
         }
     };
 
index 2a3fcd66195b340e456ac5301002f19058a9506f..4b1a03e47e7aebb1f2ef30bf261659b61204e2b4 100644 (file)
@@ -187,7 +187,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // Special-case constants to cache a common global for all uses.
     match expr.node {
         ast::ExprPath(..) => {
-            let def = ccx.tcx().def_map.borrow()[expr.id].full_def();
+            let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
             match def {
                 def::DefConst(def_id) => {
                     if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
@@ -376,7 +376,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let signed = ty::type_is_signed(intype);
 
             let (te2, _) = const_expr(cx, &**e2, param_substs);
-            let te2 = base::cast_shift_const_rhs(b, te1, te2);
+            let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
 
             match b.node {
               ast::BiAdd   => {
@@ -665,7 +665,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }
           }
           ast::ExprPath(..) => {
-            let def = cx.tcx().def_map.borrow()[e.id].full_def();
+            let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
             match def {
                 def::DefFn(..) | def::DefMethod(..) => {
                     expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
@@ -751,7 +751,7 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
         let g = base::get_item_val(ccx, id);
         // At this point, get_item_val has already translated the
         // constant's initializer to determine its LLVM type.
-        let v = ccx.static_values().borrow()[id].clone();
+        let v = ccx.static_values().borrow().get(&id).unwrap().clone();
         // boolean SSA values are i1, but they have to be stored in i8 slots,
         // otherwise some LLVM optimization passes don't work as expected
         let v = if llvm::LLVMTypeOf(v) == Type::i1(ccx).to_ref() {
index 3e8cc46e2550107d9fede430516be79e4e3b289c..b9c59a0bc78d671f59e3b8a13b74a8b4612f9931 100644 (file)
@@ -1695,7 +1695,7 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     };
 
     let name = CString::new(name.as_bytes()).unwrap();
-    match (variable_access, [].as_slice()) {
+    match (variable_access, &[][..]) {
         (DirectVariable { alloca }, address_operations) |
         (IndirectVariable {alloca, address_operations}, _) => {
             let metadata = unsafe {
index c316308c618bcb42a12ec9646e99ffd7d1663ab8..ceb9a29efa8879a9d30ad4544d812c579e87f97f 100644 (file)
@@ -126,7 +126,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         return datum.store_to_dest(bcx, dest, expr.id);
     }
 
-    let qualif = bcx.tcx().const_qualif_map.borrow()[expr.id];
+    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
     if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) {
         if !qualif.intersects(check_const::PREFER_IN_PLACE) {
             if let SaveIn(lldest) = dest {
@@ -209,7 +209,7 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let mut bcx = bcx;
     let fcx = bcx.fcx;
-    let qualif = bcx.tcx().const_qualif_map.borrow()[expr.id];
+    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
     let adjusted_global = !qualif.intersects(check_const::NON_STATIC_BORROWS);
     let global = if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) {
         let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
@@ -285,6 +285,11 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
     GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR])
 }
 
+pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
+    Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
+    Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
+}
+
 // Retrieve the information we are losing (making dynamic) in an unsizing
 // adjustment.
 //
@@ -838,7 +843,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                base_datum,
                                                vec![(ix_datum, idx.id)],
                                                Some(SaveIn(scratch.val)),
-                                               true));
+                                               false));
             let datum = scratch.to_expr_datum();
             if type_is_sized(bcx.tcx(), elt_ty) {
                 Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
@@ -1400,7 +1405,7 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
                         ty.repr(tcx)));
                 }
                 Some(node_id) => {
-                    let def = tcx.def_map.borrow()[node_id].full_def();
+                    let def = tcx.def_map.borrow().get(&node_id).unwrap().full_def();
                     match def {
                         def::DefVariant(enum_id, variant_id, _) => {
                             let variant_info = ty::enum_variant_with_id(tcx, enum_id, variant_id);
@@ -1765,7 +1770,6 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     };
     let is_float = ty::type_is_fp(intype);
     let is_signed = ty::type_is_signed(intype);
-    let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
     let info = expr_info(binop_expr);
 
     let binop_debug_loc = binop_expr.debug_loc();
@@ -1838,13 +1842,17 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
       ast::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc),
       ast::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc),
       ast::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc),
-      ast::BiShl => Shl(bcx, lhs, rhs, binop_debug_loc),
+      ast::BiShl => {
+          let (newbcx, res) = with_overflow_check(
+              bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc);
+          bcx = newbcx;
+          res
+      }
       ast::BiShr => {
-        if is_signed {
-            AShr(bcx, lhs, rhs, binop_debug_loc)
-        } else {
-            LShr(bcx, lhs, rhs, binop_debug_loc)
-        }
+          let (newbcx, res) = with_overflow_check(
+              bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc);
+          bcx = newbcx;
+          res
       }
       ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
         if is_simd {
@@ -1956,7 +1964,7 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    dest: Option<Dest>,
                                    autoref: bool)
                                    -> Result<'blk, 'tcx> {
-    let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty;
+    let method_ty = bcx.tcx().method_map.borrow().get(&method_call).unwrap().ty;
     callee::trans_call_inner(bcx,
                              expr.debug_loc(),
                              monomorphize_type(bcx, method_ty),
@@ -1977,10 +1985,12 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                          dest: Option<Dest>)
                                          -> Block<'blk, 'tcx> {
     let method_call = MethodCall::expr(expr.id);
-    let method_type = (*bcx.tcx()
-                           .method_map
-                           .borrow())[method_call]
-                           .ty;
+    let method_type = bcx.tcx()
+                         .method_map
+                         .borrow()
+                         .get(&method_call)
+                         .unwrap()
+                         .ty;
     let mut all_args = vec!(callee);
     all_args.extend(args.iter().map(|e| &**e));
     unpack_result!(bcx,
@@ -2384,9 +2394,38 @@ enum OverflowOp {
     Add,
     Sub,
     Mul,
+    Shl,
+    Shr,
 }
 
 impl OverflowOp {
+    fn codegen_strategy(&self) -> OverflowCodegen {
+        use self::OverflowCodegen::{ViaIntrinsic, ViaInputCheck};
+        match *self {
+            OverflowOp::Add => ViaIntrinsic(OverflowOpViaIntrinsic::Add),
+            OverflowOp::Sub => ViaIntrinsic(OverflowOpViaIntrinsic::Sub),
+            OverflowOp::Mul => ViaIntrinsic(OverflowOpViaIntrinsic::Mul),
+
+            OverflowOp::Shl => ViaInputCheck(OverflowOpViaInputCheck::Shl),
+            OverflowOp::Shr => ViaInputCheck(OverflowOpViaInputCheck::Shr),
+        }
+    }
+}
+
+enum OverflowCodegen {
+    ViaIntrinsic(OverflowOpViaIntrinsic),
+    ViaInputCheck(OverflowOpViaInputCheck),
+}
+
+enum OverflowOpViaInputCheck { Shl, Shr, }
+
+enum OverflowOpViaIntrinsic { Add, Sub, Mul, }
+
+impl OverflowOpViaIntrinsic {
+    fn to_intrinsic<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>, lhs_ty: Ty) -> ValueRef {
+        let name = self.to_intrinsic_name(bcx.tcx(), lhs_ty);
+        bcx.ccx().get_intrinsic(&name)
+    }
     fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
         use syntax::ast::IntTy::*;
         use syntax::ast::UintTy::*;
@@ -2408,7 +2447,7 @@ fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
         };
 
         match *self {
-            OverflowOp::Add => match new_sty {
+            OverflowOpViaIntrinsic::Add => match new_sty {
                 ty_int(TyI8) => "llvm.sadd.with.overflow.i8",
                 ty_int(TyI16) => "llvm.sadd.with.overflow.i16",
                 ty_int(TyI32) => "llvm.sadd.with.overflow.i32",
@@ -2421,7 +2460,7 @@ fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
 
                 _ => unreachable!(),
             },
-            OverflowOp::Sub => match new_sty {
+            OverflowOpViaIntrinsic::Sub => match new_sty {
                 ty_int(TyI8) => "llvm.ssub.with.overflow.i8",
                 ty_int(TyI16) => "llvm.ssub.with.overflow.i16",
                 ty_int(TyI32) => "llvm.ssub.with.overflow.i32",
@@ -2434,7 +2473,7 @@ fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
 
                 _ => unreachable!(),
             },
-            OverflowOp::Mul => match new_sty {
+            OverflowOpViaIntrinsic::Mul => match new_sty {
                 ty_int(TyI8) => "llvm.smul.with.overflow.i8",
                 ty_int(TyI16) => "llvm.smul.with.overflow.i16",
                 ty_int(TyI32) => "llvm.smul.with.overflow.i32",
@@ -2449,16 +2488,14 @@ fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
             },
         }
     }
-}
-
 
-fn with_overflow_check<'a, 'b>(bcx: Block<'a, 'b>, oop: OverflowOp, info: NodeIdAndSpan,
-                               lhs_t: Ty, lhs: ValueRef, rhs: ValueRef, binop_debug_loc: DebugLoc)
-                               -> (Block<'a, 'b>, ValueRef) {
-    if bcx.unreachable.get() { return (bcx, _Undef(lhs)); }
-    if bcx.ccx().check_overflow() {
-        let name = oop.to_intrinsic_name(bcx.tcx(), lhs_t);
-        let llfn = bcx.ccx().get_intrinsic(&name);
+    fn build_intrinsic_call<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>,
+                                        info: NodeIdAndSpan,
+                                        lhs_t: Ty<'tcx>, lhs: ValueRef,
+                                        rhs: ValueRef,
+                                        binop_debug_loc: DebugLoc)
+                                        -> (Block<'blk, 'tcx>, ValueRef) {
+        let llfn = self.to_intrinsic(bcx, lhs_t);
 
         let val = Call(bcx, llfn, &[lhs, rhs], None, binop_debug_loc);
         let result = ExtractValue(bcx, val, 0); // iN operation result
@@ -2477,11 +2514,118 @@ fn with_overflow_check<'a, 'b>(bcx: Block<'a, 'b>, oop: OverflowOp, info: NodeId
                     InternedString::new("arithmetic operation overflowed")));
 
         (bcx, result)
+    }
+}
+
+impl OverflowOpViaInputCheck {
+    fn build_with_input_check<'blk, 'tcx>(&self,
+                                          bcx: Block<'blk, 'tcx>,
+                                          info: NodeIdAndSpan,
+                                          lhs_t: Ty<'tcx>,
+                                          lhs: ValueRef,
+                                          rhs: ValueRef,
+                                          binop_debug_loc: DebugLoc)
+                                          -> (Block<'blk, 'tcx>, ValueRef)
+    {
+        let lhs_llty = val_ty(lhs);
+        let rhs_llty = val_ty(rhs);
+
+        // Panic if any bits are set outside of bits that we always
+        // mask in.
+        //
+        // Note that the mask's value is derived from the LHS type
+        // (since that is where the 32/64 distinction is relevant) but
+        // the mask's type must match the RHS type (since they will
+        // both be fed into a and-binop)
+        let invert_mask = !shift_mask_val(lhs_llty);
+        let invert_mask = C_integral(rhs_llty, invert_mask, true);
+
+        let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
+        let cond = ICmp(bcx, llvm::IntNE, outer_bits,
+                        C_integral(rhs_llty, 0, false), binop_debug_loc);
+        let result = match *self {
+            OverflowOpViaInputCheck::Shl =>
+                build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
+            OverflowOpViaInputCheck::Shr =>
+                build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
+        };
+        let bcx =
+            base::with_cond(bcx, cond, |bcx|
+                controlflow::trans_fail(bcx, info,
+                    InternedString::new("shift operation overflowed")));
+
+        (bcx, result)
+    }
+}
+
+fn shift_mask_val(llty: Type) -> u64 {
+    // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
+    llty.int_width() - 1
+}
+
+// To avoid UB from LLVM, these two functions mask RHS with an
+// appropriate mask unconditionally (i.e. the fallback behavior for
+// all shifts). For 32- and 64-bit types, this matches the semantics
+// of Java. (See related discussion on #1877 and #10183.)
+
+fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                      lhs: ValueRef,
+                                      rhs: ValueRef,
+                                      binop_debug_loc: DebugLoc) -> ValueRef {
+    let rhs = base::cast_shift_expr_rhs(bcx, ast::BinOp_::BiShl, lhs, rhs);
+    // #1877, #10183: Ensure that input is always valid
+    let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
+    Shl(bcx, lhs, rhs, binop_debug_loc)
+}
+
+fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                      lhs_t: Ty<'tcx>,
+                                      lhs: ValueRef,
+                                      rhs: ValueRef,
+                                      binop_debug_loc: DebugLoc) -> ValueRef {
+    let rhs = base::cast_shift_expr_rhs(bcx, ast::BinOp_::BiShr, lhs, rhs);
+    // #1877, #10183: Ensure that input is always valid
+    let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
+    let is_signed = ty::type_is_signed(lhs_t);
+    if is_signed {
+        AShr(bcx, lhs, rhs, binop_debug_loc)
+    } else {
+        LShr(bcx, lhs, rhs, binop_debug_loc)
+    }
+}
+
+fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                              rhs: ValueRef,
+                              debug_loc: DebugLoc) -> ValueRef {
+    let rhs_llty = val_ty(rhs);
+    let mask = shift_mask_val(rhs_llty);
+    And(bcx, rhs, C_integral(rhs_llty, mask, false), debug_loc)
+}
+
+fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
+                                   lhs_t: Ty<'tcx>, lhs: ValueRef,
+                                   rhs: ValueRef,
+                                   binop_debug_loc: DebugLoc)
+                                   -> (Block<'blk, 'tcx>, ValueRef) {
+    if bcx.unreachable.get() { return (bcx, _Undef(lhs)); }
+    if bcx.ccx().check_overflow() {
+
+        match oop.codegen_strategy() {
+            OverflowCodegen::ViaIntrinsic(oop) =>
+                oop.build_intrinsic_call(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
+            OverflowCodegen::ViaInputCheck(oop) =>
+                oop.build_with_input_check(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
+        }
     } else {
         let res = match oop {
             OverflowOp::Add => Add(bcx, lhs, rhs, binop_debug_loc),
             OverflowOp::Sub => Sub(bcx, lhs, rhs, binop_debug_loc),
             OverflowOp::Mul => Mul(bcx, lhs, rhs, binop_debug_loc),
+
+            OverflowOp::Shl =>
+                build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
+            OverflowOp::Shr =>
+                build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
         };
         (bcx, res)
     }
index 69ca9a5e81cbc81b933e4ac5ed62022cdb261787..d158cfa7b88765b77f12dba0808328ebd9ef630b 100644 (file)
@@ -446,10 +446,15 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                              call_debug_location)
         }
         (_, "volatile_load") => {
-            VolatileLoad(bcx, llargs[0])
+            let tp_ty = *substs.types.get(FnSpace, 0);
+            let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+            from_arg_ty(bcx, VolatileLoad(bcx, ptr), tp_ty)
         },
         (_, "volatile_store") => {
-            VolatileStore(bcx, llargs[1], llargs[0]);
+            let tp_ty = *substs.types.get(FnSpace, 0);
+            let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+            let val = to_arg_ty(bcx, llargs[1], tp_ty);
+            VolatileStore(bcx, val, ptr);
             C_nil(ccx)
         },
 
@@ -709,8 +714,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                             llvm::SequentiallyConsistent
                     };
 
-                    let res = AtomicCmpXchg(bcx, llargs[0], llargs[1],
-                                            llargs[2], order,
+                    let tp_ty = *substs.types.get(FnSpace, 0);
+                    let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+                    let cmp = to_arg_ty(bcx, llargs[1], tp_ty);
+                    let src = to_arg_ty(bcx, llargs[2], tp_ty);
+                    let res = AtomicCmpXchg(bcx, ptr, cmp, src, order,
                                             strongest_failure_ordering);
                     if unsafe { llvm::LLVMVersionMinor() >= 5 } {
                         ExtractValue(bcx, res, 0)
@@ -720,10 +728,15 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 }
 
                 "load" => {
-                    AtomicLoad(bcx, llargs[0], order)
+                    let tp_ty = *substs.types.get(FnSpace, 0);
+                    let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+                    from_arg_ty(bcx, AtomicLoad(bcx, ptr, order), tp_ty)
                 }
                 "store" => {
-                    AtomicStore(bcx, llargs[1], llargs[0], order);
+                    let tp_ty = *substs.types.get(FnSpace, 0);
+                    let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+                    let val = to_arg_ty(bcx, llargs[1], tp_ty);
+                    AtomicStore(bcx, val, ptr, order);
                     C_nil(ccx)
                 }
 
@@ -749,7 +762,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                         _ => ccx.sess().fatal("unknown atomic operation")
                     };
 
-                    AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order)
+                    let tp_ty = *substs.types.get(FnSpace, 0);
+                    let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
+                    let val = to_arg_ty(bcx, llargs[1], tp_ty);
+                    AtomicRMW(bcx, atom_op, ptr, val, order)
                 }
             }
 
index 28e7027b2124a2e2135e7d0b4007851de08b46ff..71900855266e9f4e7fc1b411d13cd65909460e11 100644 (file)
@@ -1046,7 +1046,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
         return (tcx.types.err, ty_path_def);
     };
 
-    let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name;
+    let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name;
 
     let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
         Ok(v) => v,
index 8e2f4dcefa02231db95ee7d5d576e8dc7df057b7..e8da19efa06afd790bb966de830e877e5f9e498f 100644 (file)
@@ -119,7 +119,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             demand::eqtype(fcx, pat.span, expected, lhs_ty);
         }
         ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
-            let const_did = tcx.def_map.borrow()[pat.id].def_id();
+            let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
             let const_scheme = ty::lookup_item_type(tcx, const_did);
             assert!(const_scheme.generics.is_empty());
             let const_ty = pcx.fcx.instantiate_type_scheme(pat.span,
@@ -163,7 +163,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
 
             // if there are multiple arms, make sure they all agree on
             // what the type of the binding `x` ought to be
-            let canon_id = pcx.map[path.node];
+            let canon_id = *pcx.map.get(&path.node).unwrap();
             if canon_id != pat.id {
                 let ct = fcx.local_ty(pat.span, canon_id);
                 demand::eqtype(fcx, pat.span, ct, typ);
@@ -287,10 +287,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     // (nmatsakis) an hour or two debugging to remember, so I thought
     // I'd write them down this time.
     //
-    // 1. Most importantly, there is no loss of expressiveness
-    // here. What we are saying is that the type of `x`
-    // becomes *exactly* what is expected. This might seem
-    // like it will cause errors in a case like this:
+    // 1. There is no loss of expressiveness here, though it does
+    // cause some inconvenience. What we are saying is that the type
+    // of `x` becomes *exactly* what is expected. This can cause unnecessary
+    // errors in some cases, such as this one:
+    // it will cause errors in a case like this:
     //
     // ```
     // fn foo<'x>(x: &'x int) {
@@ -361,8 +362,21 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                              match_src: ast::MatchSource) {
     let tcx = fcx.ccx.tcx;
 
-    let discrim_ty = fcx.infcx().next_ty_var();
-    check_expr_has_type(fcx, discrim, discrim_ty);
+    // Not entirely obvious: if matches may create ref bindings, we
+    // want to use the *precise* type of the discriminant, *not* some
+    // supertype, as the "discriminant type" (issue #23116).
+    let contains_ref_bindings = arms.iter().any(|a| tcx.arm_contains_ref_binding(a));
+    let discrim_ty;
+    if contains_ref_bindings {
+        check_expr(fcx, discrim);
+        discrim_ty = fcx.expr_ty(discrim);
+    } else {
+        // ...but otherwise we want to use any supertype of the
+        // discriminant. This is sort of a workaround, see note (*) in
+        // `check_pat` for some details.
+        discrim_ty = fcx.infcx().next_ty_var();
+        check_expr_has_type(fcx, discrim, discrim_ty);
+    };
 
     // Typecheck the patterns first, so that we get types for all the
     // bindings.
@@ -449,7 +463,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat,
     let fcx = pcx.fcx;
     let tcx = pcx.fcx.ccx.tcx;
 
-    let def = tcx.def_map.borrow()[pat.id].full_def();
+    let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
     let (enum_def_id, variant_def_id) = match def {
         def::DefTrait(_) => {
             let name = pprust::path_to_string(path);
@@ -518,7 +532,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     let fcx = pcx.fcx;
     let tcx = pcx.fcx.ccx.tcx;
 
-    let def = tcx.def_map.borrow()[pat.id].full_def();
+    let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
     let enum_def = def.variant_def_ids()
         .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
 
index a82ebcd9175fa43d9be6d03ede273282c3134d8c..f731507ba906dbeb7f0af6bfbc8bf6ea17ac875b 100644 (file)
@@ -92,6 +92,12 @@ fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
         Ok(None) // No coercion required.
     }
 
+    fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> {
+        let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
+        try!(sub.regions(b, a));
+        Ok(())
+    }
+
     fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
         F: FnOnce(Ty<'tcx>) -> T,
     {
@@ -340,21 +346,40 @@ fn unsize_ty(&self,
                     Some((ty, ty::UnsizeLength(len)))
                 }
                 (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
-                    // For now, we only support upcasts from
-                    // `Foo+Send` to `Foo` (really, any time there are
-                    // fewer builtin bounds then before). These are
-                    // convenient because they don't require any sort
-                    // of change to the vtable at runtime.
-                    if data_a.bounds.builtin_bounds != data_b.bounds.builtin_bounds &&
-                        data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds)
-                    {
+                    // Upcasts permit two things:
+                    //
+                    // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
+                    // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
+                    //
+                    // Note that neither of these changes requires any
+                    // change at runtime.  Eventually this will be
+                    // generalized.
+                    //
+                    // We always upcast when we can because of reason
+                    // #2 (region bounds).
+                    if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
+                        // construct a type `a1` which is a version of
+                        // `a` using the upcast bounds from `b`
                         let bounds_a1 = ty::ExistentialBounds {
-                            region_bound: data_a.bounds.region_bound,
+                            // From type b
+                            region_bound: data_b.bounds.region_bound,
                             builtin_bounds: data_b.bounds.builtin_bounds,
+
+                            // From type a
                             projection_bounds: data_a.bounds.projection_bounds.clone(),
                         };
                         let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
-                        match self.fcx.infcx().try(|_| self.subtype(ty_a1, ty_b)) {
+
+                        // relate `a1` to `b`
+                        let result = self.fcx.infcx().try(|_| {
+                            // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
+                            try!(self.outlives(data_a.bounds.region_bound,
+                                               data_b.bounds.region_bound));
+                            self.subtype(ty_a1, ty_b)
+                        });
+
+                        // if that was successful, we have a coercion
+                        match result {
                             Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
                             Err(_) => None,
                         }
index 45d4a1edc6b2414074ecc573012ad832a40e819d..0eb71244ac075fe661dbcc224e643b190d8d696b 100644 (file)
@@ -368,7 +368,7 @@ fn closure_type(&self,
                     substs: &subst::Substs<'tcx>)
                     -> ty::ClosureTy<'tcx>
     {
-        self.inh.closure_tys.borrow()[def_id].subst(self.tcx(), substs)
+        self.inh.closure_tys.borrow().get(&def_id).unwrap().subst(self.tcx(), substs)
     }
 
     fn closure_upvars(&self,
@@ -549,7 +549,7 @@ fn visit_local(&mut self, local: &'tcx ast::Local) {
         debug!("Local variable {} is assigned type {}",
                self.fcx.pat_to_string(&*local.pat),
                self.fcx.infcx().ty_to_string(
-                   self.fcx.inh.locals.borrow()[local.id].clone()));
+                   self.fcx.inh.locals.borrow().get(&local.id).unwrap().clone()));
         visit::walk_local(self, local);
     }
 
@@ -565,7 +565,7 @@ fn visit_pat(&mut self, p: &'tcx ast::Pat) {
                 debug!("Pattern binding {} is assigned to {} with type {}",
                        token::get_ident(path1.node),
                        self.fcx.infcx().ty_to_string(
-                           self.fcx.inh.locals.borrow()[p.id].clone()),
+                           self.fcx.inh.locals.borrow().get(&p.id).unwrap().clone()),
                        var_ty.repr(self.fcx.tcx()));
             }
         }
@@ -3327,7 +3327,7 @@ fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 let mut missing_fields = Vec::new();
                 for class_field in field_types {
                     let name = class_field.name;
-                    let (_, seen) = class_field_map[name];
+                    let (_, seen) = *class_field_map.get(&name).unwrap();
                     if !seen {
                         missing_fields.push(
                             format!("`{}`", &token::get_name(name)))
@@ -4242,11 +4242,27 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
 }
 
 pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                       nid: ast::NodeId,
+                                       local: &'tcx ast::Local,
                                        init: &'tcx ast::Expr)
 {
-    let local_ty = fcx.local_ty(init.span, nid);
-    check_expr_coercable_to_type(fcx, init, local_ty)
+    let ref_bindings = fcx.tcx().pat_contains_ref_binding(&local.pat);
+
+    let local_ty = fcx.local_ty(init.span, local.id);
+    if !ref_bindings {
+        check_expr_coercable_to_type(fcx, init, local_ty)
+    } else {
+        // Somewhat subtle: if we have a `ref` binding in the pattern,
+        // we want to avoid introducing coercions for the RHS. This is
+        // both because it helps preserve sanity and, in the case of
+        // ref mut, for soundness (issue #23116). In particular, in
+        // the latter case, we need to be clear that the type of the
+        // referent for the reference that results is *equal to* the
+        // type of the lvalue it is referencing, and not some
+        // supertype thereof.
+        check_expr(fcx, init);
+        let init_ty = fcx.expr_ty(init);
+        demand::eqtype(fcx, init.span, init_ty, local_ty);
+    };
 }
 
 pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local)  {
@@ -4256,7 +4272,7 @@ pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local)
     fcx.write_ty(local.id, t);
 
     if let Some(ref init) = local.init {
-        check_decl_initializer(fcx, local.id, &**init);
+        check_decl_initializer(fcx, local, &**init);
         let init_ty = fcx.expr_ty(&**init);
         if ty::type_is_error(init_ty) {
             fcx.write_ty(local.id, init_ty);
@@ -4428,7 +4444,7 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     let inh = static_inherited_fields(ccx);
     let rty = ty::node_id_to_type(ccx.tcx, id);
     let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
-    let declty = (*fcx.ccx.tcx.tcache.borrow())[local_def(id)].ty;
+    let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).unwrap().ty;
     check_const_with_ty(&fcx, sp, e, declty);
 }
 
index 09592db8a116d399abd4bf2d815942672ff56e9c..340cca7d47e7a395619bb5ae60ce9d1724e800a6 100644 (file)
@@ -380,7 +380,7 @@ fn try_adjust_upvar_deref(&self,
                 // borrow_kind of the upvar to make sure it
                 // is inferred to mutable if necessary
                 let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
-                let ub = &mut upvar_capture_map[upvar_id];
+                let ub = upvar_capture_map.get_mut(&upvar_id).unwrap();
                 self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
 
                 // also need to be in an FnMut closure since this is not an ImmBorrow
@@ -448,7 +448,7 @@ fn adjust_closure_kind(&self,
 
         let closure_def_id = ast_util::local_def(closure_id);
         let mut closure_kinds = self.fcx.inh.closure_kinds.borrow_mut();
-        let existing_kind = closure_kinds[closure_def_id];
+        let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
 
         debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
                closure_id, existing_kind, new_kind);
index 6b0fb8ac71af0479f8b3ab85cc304448da19fac6..ffd99ff2eece081f7390195ea24506fe83ebb302 100644 (file)
@@ -269,7 +269,7 @@ fn add_trait_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
 
     fn get_self_type_for_implementation(&self, impl_did: DefId)
                                         -> TypeScheme<'tcx> {
-        self.crate_context.tcx.tcache.borrow()[impl_did].clone()
+        self.crate_context.tcx.tcache.borrow().get(&impl_did).unwrap().clone()
     }
 
     // Converts an implementation in the AST to a vector of items.
@@ -387,7 +387,7 @@ fn populate_destructor_table(&self) {
         };
 
         for &impl_did in &*trait_impls.borrow() {
-            let items = &(*impl_items)[impl_did];
+            let items = impl_items.get(&impl_did).unwrap();
             if items.len() < 1 {
                 // We'll error out later. For now, just don't ICE.
                 continue;
index 867dea9588568b515c68d7f699b258505e9da37c..e4926b119d5dbe551808b3e8bb2db99d0afd7d12 100644 (file)
@@ -27,55 +27,66 @@ struct UnsafetyChecker<'cx, 'tcx:'cx> {
     tcx: &'cx ty::ctxt<'tcx>
 }
 
-impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
-    fn visit_item(&mut self, item: &'v ast::Item) {
-        match item.node {
-            ast::ItemImpl(unsafety, polarity, _, _, _, _) => {
-                match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
-                    None => {
-                        // Inherent impl.
-                        match unsafety {
-                            ast::Unsafety::Normal => { /* OK */ }
-                            ast::Unsafety::Unsafe => {
-                                span_err!(self.tcx.sess, item.span, E0197,
-                                    "inherent impls cannot be declared as unsafe");
-                            }
-                        }
+impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
+    fn check_unsafety_coherence(&mut self, item: &'v ast::Item,
+                                unsafety: ast::Unsafety,
+                                polarity: ast::ImplPolarity) {
+        match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
+            None => {
+                // Inherent impl.
+                match unsafety {
+                    ast::Unsafety::Normal => { /* OK */ }
+                    ast::Unsafety::Unsafe => {
+                        span_err!(self.tcx.sess, item.span, E0197,
+                                  "inherent impls cannot be declared as unsafe");
                     }
+                }
+            }
 
-                    Some(trait_ref) => {
-                        let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
-                        match (trait_def.unsafety, unsafety, polarity) {
-                            (ast::Unsafety::Unsafe,
-                             ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => {
-                                span_err!(self.tcx.sess, item.span, E0198,
-                                    "negative implementations are not unsafe");
-                            }
+            Some(trait_ref) => {
+                let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
+                match (trait_def.unsafety, unsafety, polarity) {
+                    (ast::Unsafety::Unsafe,
+                     ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => {
+                        span_err!(self.tcx.sess, item.span, E0198,
+                                  "negative implementations are not unsafe");
+                    }
 
-                            (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
-                                span_err!(self.tcx.sess, item.span, E0199,
-                                    "implementing the trait `{}` is not unsafe",
-                                            trait_ref.user_string(self.tcx));
-                            }
+                    (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
+                        span_err!(self.tcx.sess, item.span, E0199,
+                                  "implementing the trait `{}` is not unsafe",
+                                  trait_ref.user_string(self.tcx));
+                    }
 
-                            (ast::Unsafety::Unsafe,
-                             ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
-                                span_err!(self.tcx.sess, item.span, E0200,
-                                    "the trait `{}` requires an `unsafe impl` declaration",
-                                            trait_ref.user_string(self.tcx));
-                            }
+                    (ast::Unsafety::Unsafe,
+                     ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
+                        span_err!(self.tcx.sess, item.span, E0200,
+                                  "the trait `{}` requires an `unsafe impl` declaration",
+                                  trait_ref.user_string(self.tcx));
+                    }
 
-                            (ast::Unsafety::Unsafe,
-                             ast::Unsafety::Normal, ast::ImplPolarity::Negative) |
-                            (ast::Unsafety::Unsafe,
-                             ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) |
-                            (ast::Unsafety::Normal, ast::Unsafety::Normal, _) => {
-                                /* OK */
-                            }
-                        }
+                    (ast::Unsafety::Unsafe,
+                     ast::Unsafety::Normal, ast::ImplPolarity::Negative) |
+                    (ast::Unsafety::Unsafe,
+                     ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) |
+                    (ast::Unsafety::Normal, ast::Unsafety::Normal, _) => {
+                        /* OK */
                     }
                 }
             }
+        }
+    }
+}
+
+impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
+    fn visit_item(&mut self, item: &'v ast::Item) {
+        match item.node {
+            ast::ItemDefaultImpl(unsafety, _) => {
+                self.check_unsafety_coherence(item, unsafety, ast::ImplPolarity::Positive);
+            }
+            ast::ItemImpl(unsafety, polarity, _, _, _, _) => {
+                self.check_unsafety_coherence(item, unsafety, polarity);
+            }
             _ => { }
         }
 
index 97cc3ac7c48a78aa2a79c1051be851fbf0e93b5e..5efc26825eab19ef63b9c939aa5ee9c2ad588980 100644 (file)
@@ -194,7 +194,7 @@ fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,
 
     fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
         let def_id = local_def(method_id);
-        match self.tcx.impl_or_trait_items.borrow()[def_id] {
+        match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
             ty::MethodTraitItem(ref mty) => mty.clone(),
             ty::TypeTraitItem(..) => {
                 self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
@@ -545,7 +545,7 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
                   -> bool
 {
     if let ast::TyPath(None, _) = ast_ty.node {
-        let path_res = tcx.def_map.borrow()[ast_ty.id];
+        let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
         match path_res.base_def {
             def::DefSelfTy(node_id) =>
                 path_res.depth == 0 && node_id == param_id,
@@ -690,7 +690,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                      container: ImplOrTraitItemContainer,
                                      ident: ast::Ident,
                                      id: ast::NodeId,
@@ -835,7 +835,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                                               "associated items are not allowed in inherent impls");
                         }
 
-                        convert_associated_type(ccx, ImplContainer(local_def(it.id)),
+                        as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
                                                 impl_item.ident, impl_item.id, impl_item.vis);
 
                         let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
@@ -917,7 +917,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                 match trait_item.node {
                     ast::MethodTraitItem(..) => {}
                     ast::TypeTraitItem(..) => {
-                        convert_associated_type(ccx, TraitContainer(local_def(it.id)),
+                        as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
                                                 trait_item.ident, trait_item.id, ast::Public);
                     }
                 }
@@ -1040,9 +1040,13 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates);
             } else if struct_def.fields[0].node.kind.is_unnamed() {
                 // Tuple-like.
-                let inputs: Vec<_> = struct_def.fields.iter().map(
-                        |field| (*tcx.tcache.borrow())[
-                            local_def(field.node.id)].ty).collect();
+                let inputs: Vec<_> =
+                    struct_def.fields
+                              .iter()
+                              .map(|field| tcx.tcache.borrow().get(&local_def(field.node.id))
+                                                              .unwrap()
+                                                              .ty)
+                              .collect();
                 let ctor_fn_ty = ty::mk_ctor_fn(tcx,
                                                 local_def(ctor_id),
                                                 &inputs[..],
@@ -1987,7 +1991,7 @@ fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>,
         builtin_bounds,
         trait_bounds,
         region_bounds
-    } = astconv::partition_bounds(tcx, span, ast_bounds.as_slice());
+    } = astconv::partition_bounds(tcx, span, &ast_bounds);
 
     let mut projection_bounds = Vec::new();
 
index 421549f8b7ecb8ab838ed60dfeec7ea940299e39..8e9408c9ebc48e3d111431fbadab122279935d2a 100644 (file)
@@ -188,7 +188,7 @@ fn clean(&self, cx: &DocContext) -> Crate {
 
         let src = match cx.input {
             Input::File(ref path) => path.clone(),
-            Input::Str(_) => PathBuf::new("") // FIXME: this is wrong
+            Input::Str(_) => PathBuf::new() // FIXME: this is wrong
         };
 
         Crate {
index c2b6c940caea29291b36fa179c28d706e05b315c..57cb87e1b2d011fb7a4c08147bfc1a491e687f8c 100644 (file)
@@ -47,7 +47,7 @@ pub fn load_string(input: &Path) -> io::Result<Option<String>> {
 macro_rules! load_or_return {
     ($input: expr, $cant_read: expr, $not_utf8: expr) => {
         {
-            let input = PathBuf::new($input);
+            let input = PathBuf::from(&$input[..]);
             match ::externalfiles::load_string(&input) {
                 Err(e) => {
                     let _ = writeln!(&mut io::stderr(),
index 03a2d708ee43aa5b742c2efc9c19aacdf4764ecf..4d15abb91dc148f5044498eae7a42de4ded5e3d9 100644 (file)
@@ -290,7 +290,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path,
             if ast_util::is_local(did) || cache.inlined.contains(&did) {
                 Some(repeat("../").take(loc.len()).collect::<String>())
             } else {
-                match cache.extern_locations[did.krate] {
+                match cache.extern_locations[&did.krate] {
                     render::Remote(ref s) => Some(s.to_string()),
                     render::Local => {
                         Some(repeat("../").take(loc.len()).collect::<String>())
@@ -404,11 +404,11 @@ fn primitive_link(f: &mut fmt::Formatter,
             needs_termination = true;
         }
         Some(&cnum) => {
-            let path = &m.paths[ast::DefId {
+            let path = &m.paths[&ast::DefId {
                 krate: cnum,
                 node: ast::CRATE_NODE_ID,
             }];
-            let loc = match m.extern_locations[cnum] {
+            let loc = match m.extern_locations[&cnum] {
                 render::Remote(ref s) => Some(s.to_string()),
                 render::Local => {
                     let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
index 81daac7b90f0d018fb86ed71288a9f088ce8fffe..1b2fc5964ab9802e24dfe83f1f9b7fbe1acf2983 100644 (file)
@@ -300,7 +300,7 @@ pub fn run(mut krate: clean::Crate,
            passes: HashSet<String>) -> io::Result<()> {
     let src_root = match krate.src.parent() {
         Some(p) => p.to_path_buf(),
-        None => PathBuf::new(""),
+        None => PathBuf::new(),
     };
     let mut cx = Context {
         dst: dst,
@@ -784,7 +784,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 impl<'a> SourceCollector<'a> {
     /// Renders the given filename into its corresponding HTML source file.
     fn emit_source(&mut self, filename: &str) -> io::Result<()> {
-        let p = PathBuf::new(filename);
+        let p = PathBuf::from(filename);
 
         // If we couldn't open this file, then just returns because it
         // probably means that it's some standard library macro thing and we
@@ -819,7 +819,7 @@ fn emit_source(&mut self, filename: &str) -> io::Result<()> {
         let mut fname = p.file_name().expect("source has no filename")
                          .to_os_string();
         fname.push(".html");
-        cur.push(&fname);
+        cur.push(&fname[..]);
         let mut w = BufWriter::new(try!(File::create(&cur)));
 
         let title = format!("{} -- source", cur.file_name().unwrap()
@@ -1404,8 +1404,8 @@ fn href(&self, cx: &Context) -> Option<String> {
         // located, then we return `None`.
         } else {
             let cache = cache();
-            let path = &cache.external_paths[self.item.def_id];
-            let root = match cache.extern_locations[self.item.def_id.krate] {
+            let path = &cache.external_paths[&self.item.def_id];
+            let root = match cache.extern_locations[&self.item.def_id.krate] {
                 Remote(ref s) => s.to_string(),
                 Local => self.cx.root_path.clone(),
                 Unknown => return None,
@@ -1863,7 +1863,7 @@ fn trait_item(w: &mut fmt::Formatter, m: &clean::Item)
                 path = if ast_util::is_local(it.def_id) {
                     cx.current.connect("/")
                 } else {
-                    let path = &cache.external_paths[it.def_id];
+                    let path = &cache.external_paths[&it.def_id];
                     path[..path.len() - 1].connect("/")
                 },
                 ty = shortty(it).to_static_str(),
index d747ed3f119c2df095e443daefd785696bc11d0f..12baa849cc94d10086e6722cea4a362f7ac38398 100644 (file)
@@ -38,6 +38,7 @@
 #![feature(file_path)]
 #![feature(path_ext)]
 #![feature(path_relative_from)]
+#![feature(convert)]
 
 extern crate arena;
 extern crate getopts;
@@ -251,7 +252,7 @@ pub fn main_args(args: &[String]) -> int {
     let should_test = matches.opt_present("test");
     let markdown_input = input.ends_with(".md") || input.ends_with(".markdown");
 
-    let output = matches.opt_str("o").map(|s| PathBuf::new(&s));
+    let output = matches.opt_str("o").map(|s| PathBuf::from(&s));
     let cfgs = matches.opt_strs("cfg");
 
     let external_html = match ExternalHtml::load(
@@ -271,7 +272,7 @@ pub fn main_args(args: &[String]) -> int {
             return test::run(input, cfgs, libs, externs, test_args, crate_name)
         }
         (false, true) => return markdown::render(input,
-                                                 output.unwrap_or(PathBuf::new("doc")),
+                                                 output.unwrap_or(PathBuf::from("doc")),
                                                  &matches, &external_html,
                                                  !matches.opt_present("markdown-no-toc")),
         (false, false) => {}
@@ -289,7 +290,7 @@ pub fn main_args(args: &[String]) -> int {
     match matches.opt_str("w").as_ref().map(|s| &**s) {
         Some("html") | None => {
             match html::render::run(krate, &external_html,
-                                    output.unwrap_or(PathBuf::new("doc")),
+                                    output.unwrap_or(PathBuf::from("doc")),
                                     passes.into_iter().collect()) {
                 Ok(()) => {}
                 Err(e) => panic!("failed to generate documentation: {}", e),
@@ -297,7 +298,7 @@ pub fn main_args(args: &[String]) -> int {
         }
         Some("json") => {
             match json_output(krate, json_plugins,
-                              output.unwrap_or(PathBuf::new("doc.json"))) {
+                              output.unwrap_or(PathBuf::from("doc.json"))) {
                 Ok(()) => {}
                 Err(e) => panic!("failed to write json: {}", e),
             }
@@ -376,7 +377,7 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
     let cfgs = matches.opt_strs("cfg");
     let triple = matches.opt_str("target");
 
-    let cr = PathBuf::new(cratefile);
+    let cr = PathBuf::from(cratefile);
     info!("starting to run rustc");
 
     let (tx, rx) = channel();
index e2f8a6f82c6442df51e271223ddc4e82b91fa95b..0b79fa7970dfd745e19a73df778d155cb4804141 100644 (file)
@@ -46,7 +46,7 @@ pub fn run(input: &str,
            mut test_args: Vec<String>,
            crate_name: Option<String>)
            -> int {
-    let input_path = PathBuf::new(input);
+    let input_path = PathBuf::from(input);
     let input = config::Input::File(input_path.clone());
 
     let sessopts = config::Options {
index d53954b29b585422bc3305b821476fa41e8e45e8..11e10cc2aa7a16cf004fdb8933d7e47283df978d 100644 (file)
@@ -196,7 +196,7 @@ fn resolve_id(&mut self, id: ast::NodeId, renamed: Option<ast::Ident>,
             Some(tcx) => tcx,
             None => return false
         };
-        let def = tcx.def_map.borrow()[id].def_id();
+        let def = tcx.def_map.borrow()[&id].def_id();
         if !ast_util::is_local(def) { return false }
         let analysis = match self.analysis {
             Some(analysis) => analysis, None => return false
index 096c72e6af2db0fb660c0002aa43c288d5dfe524..abbfc82319f5b30e24035442aedaaa532c0e80a4 100644 (file)
@@ -1218,6 +1218,7 @@ pub fn as_null(&self) -> Option<()> {
     }
 }
 
+#[cfg(stage0)]
 impl<'a> Index<&'a str>  for Json {
     type Output = Json;
 
@@ -1226,6 +1227,16 @@ fn index(&self, idx: & &str) -> &Json {
     }
 }
 
+#[cfg(not(stage0))]
+impl<'a> Index<&'a str>  for Json {
+    type Output = Json;
+
+    fn index(&self, idx: &'a str) -> &Json {
+        self.find(idx).unwrap()
+    }
+}
+
+#[cfg(stage0)]
 impl Index<uint> for Json {
     type Output = Json;
 
@@ -1237,6 +1248,18 @@ fn index<'a>(&'a self, idx: &uint) -> &'a Json {
     }
 }
 
+#[cfg(not(stage0))]
+impl Index<uint> for Json {
+    type Output = Json;
+
+    fn index<'a>(&'a self, idx: uint) -> &'a Json {
+        match self {
+            &Json::Array(ref v) => &v[idx],
+            _ => panic!("can only index Json with uint if it is an array")
+        }
+    }
+}
+
 /// The output of the streaming parser.
 #[derive(PartialEq, Clone, Debug)]
 pub enum JsonEvent {
index 90cb88046e53d008416577d3934a927888b6dbe9..f320f723c2ed6286bf6656819729de2c2ba57cdb 100644 (file)
@@ -37,6 +37,7 @@
 #![feature(std_misc)]
 #![feature(unicode)]
 #![feature(str_char)]
+#![feature(convert)]
 #![cfg_attr(test, feature(test))]
 
 // test harness access
index 71f9e01706dab1eb2d93f2207d86fd1546c234dd..5e9baa9b9e903557236e407db817a01b0790fe3b 100644 (file)
@@ -579,7 +579,7 @@ fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
 impl Decodable for path::PathBuf {
     fn decode<D: Decoder>(d: &mut D) -> Result<path::PathBuf, D::Error> {
         let bytes: String = try!(Decodable::decode(d));
-        Ok(path::PathBuf::new(&bytes))
+        Ok(path::PathBuf::from(bytes))
     }
 }
 
index 60b1738d2c98918351082c0da31efbfc78b08aed..86664d7eb0cf14ad9b81eaba3c3fe7a5be344bd0 100644 (file)
@@ -23,7 +23,7 @@
 use iter::{self, Iterator, ExactSizeIterator, IntoIterator, IteratorExt, FromIterator, Extend, Map};
 use marker::Sized;
 use mem::{self, replace};
-use ops::{Deref, FnMut, Index, IndexMut};
+use ops::{Deref, FnMut, Index};
 use option::Option::{self, Some, None};
 use rand::{self, Rng};
 use result::Result::{self, Ok, Err};
@@ -1088,7 +1088,7 @@ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
     ///     Some(x) => *x = "b",
     ///     None => (),
     /// }
-    /// assert_eq!(map[1], "b");
+    /// assert_eq!(map[&1], "b");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
@@ -1111,7 +1111,7 @@ pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
     ///
     /// map.insert(37, "b");
     /// assert_eq!(map.insert(37, "c"), Some("b"));
-    /// assert_eq!(map[37], "c");
+    /// assert_eq!(map[&37], "c");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, k: K, v: V) -> Option<V> {
@@ -1244,6 +1244,7 @@ fn default() -> HashMap<K, V, S> {
     }
 }
 
+#[cfg(stage0)]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K, Q: ?Sized, V, S> Index<Q> for HashMap<K, V, S>
     where K: Eq + Hash + Borrow<Q>,
@@ -1258,15 +1259,18 @@ fn index<'a>(&'a self, index: &Q) -> &'a V {
     }
 }
 
+#[cfg(not(stage0))]
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<K, V, S, Q: ?Sized> IndexMut<Q> for HashMap<K, V, S>
+impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
     where K: Eq + Hash + Borrow<Q>,
           Q: Eq + Hash,
           S: HashState,
 {
+    type Output = V;
+
     #[inline]
-    fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V {
-        self.get_mut(index).expect("no entry found for key")
+    fn index(&self, index: &Q) -> &V {
+        self.get(index).expect("no entry found for key")
     }
 }
 
@@ -2197,7 +2201,7 @@ fn test_index() {
         map.insert(2, 1);
         map.insert(3, 4);
 
-        assert_eq!(map[2], 1);
+        assert_eq!(map[&2], 1);
     }
 
     #[test]
@@ -2209,7 +2213,7 @@ fn test_index_nonexistent() {
         map.insert(2, 1);
         map.insert(3, 4);
 
-        map[4];
+        map[&4];
     }
 
     #[test]
index 24882c7f7abfd099c8703909c04c6ed3563247ac..9d6933ce9c89c673d008f103e9bbca800e853280 100644 (file)
@@ -23,7 +23,7 @@
 use ffi::{OsString, AsOsStr};
 use fmt;
 use io;
-use path::{AsPath, PathBuf};
+use path::{self, Path, PathBuf};
 use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
 use sync::{StaticMutex, MUTEX_INIT};
 use sys::os as os_imp;
@@ -67,8 +67,8 @@ pub fn current_dir() -> io::Result<PathBuf> {
 /// println!("Successfully changed working directory to {}!", root.display());
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
-pub fn set_current_dir<P: AsPath + ?Sized>(p: &P) -> io::Result<()> {
-    os_imp::chdir(p.as_path())
+pub fn set_current_dir<P: AsRef<Path> + ?Sized>(p: &P) -> io::Result<()> {
+    os_imp::chdir(p.as_ref())
 }
 
 static ENV_LOCK: StaticMutex = MUTEX_INIT;
index fc4f03ff3a54a808d3a28a27a6074a57caa29ddd..1760445a0fcd4ec7c4693150f734711dc4ec1967 100644 (file)
@@ -10,6 +10,7 @@
 
 #![unstable(feature = "std_misc")]
 
+use convert::Into;
 use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
 use error::{Error, FromError};
 use fmt;
@@ -130,6 +131,8 @@ pub struct CStr {
 
 /// A conversion trait used by the constructor of `CString` for types that can
 /// be converted to a vector of bytes.
+#[deprecated(since = "1.0.0", reason = "use std::convert::Into<Vec<u8>> instead")]
+#[unstable(feature = "std_misc")]
 pub trait IntoBytes {
     /// Consumes this container, returning a vector of bytes.
     fn into_bytes(self) -> Vec<u8>;
@@ -163,8 +166,8 @@ impl CString {
     /// internal 0 byte. The error returned will contain the bytes as well as
     /// the position of the nul byte.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new<T: IntoBytes>(t: T) -> Result<CString, NulError> {
-        let bytes = t.into_bytes();
+    pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
+        let bytes = t.into();
         match bytes.iter().position(|x| *x == 0) {
             Some(i) => Err(NulError(i, bytes)),
             None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
@@ -433,15 +436,19 @@ pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char)
     slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize)
 }
 
+#[allow(deprecated)]
 impl<'a> IntoBytes for &'a str {
     fn into_bytes(self) -> Vec<u8> { self.as_bytes().to_vec() }
 }
+#[allow(deprecated)]
 impl<'a> IntoBytes for &'a [u8] {
     fn into_bytes(self) -> Vec<u8> { self.to_vec() }
 }
+#[allow(deprecated)]
 impl IntoBytes for String {
     fn into_bytes(self) -> Vec<u8> { self.into_bytes() }
 }
+#[allow(deprecated)]
 impl IntoBytes for Vec<u8> {
     fn into_bytes(self) -> Vec<u8> { self }
 }
index feacbf1e98b81e9fe0e3a9cec8b1975a606041fd..5851c6e2998095923c744da0d01fceeb6556355b 100644 (file)
@@ -63,16 +63,18 @@ pub struct OsStr {
 impl OsString {
     /// Constructs an `OsString` at no cost by consuming a `String`.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[deprecated(since = "1.0.0", reason = "use `from` instead")]
     pub fn from_string(s: String) -> OsString {
-        OsString { inner: Buf::from_string(s) }
+        OsString::from(s)
     }
 
     /// Constructs an `OsString` by copying from a `&str` slice.
     ///
     /// Equivalent to: `OsString::from_string(String::from_str(s))`.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[deprecated(since = "1.0.0", reason = "use `from` instead")]
     pub fn from_str(s: &str) -> OsString {
-        OsString { inner: Buf::from_str(s) }
+        OsString::from(s)
     }
 
     /// Constructs a new empty `OsString`.
@@ -98,11 +100,40 @@ pub fn push_os_str(&mut self, s: &OsStr) {
 
     /// Extend the string with the given `&OsStr` slice.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn push<T: AsOsStr + ?Sized>(&mut self, s: &T) {
-        self.inner.push_slice(&s.as_os_str().inner)
+    pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
+        self.inner.push_slice(&s.as_ref().inner)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<String> for OsString {
+    fn from(s: String) -> OsString {
+        OsString { inner: Buf::from_string(s) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a String> for OsString {
+    fn from(s: &'a String) -> OsString {
+        OsString { inner: Buf::from_str(s) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a str> for OsString {
+    fn from(s: &'a str) -> OsString {
+        OsString { inner: Buf::from_str(s) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a OsStr> for OsString {
+    fn from(s: &'a OsStr) -> OsString {
+        OsString { inner: s.inner.to_owned() }
     }
 }
 
+#[cfg(stage0)]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Index<ops::RangeFull> for OsString {
     type Output = OsStr;
@@ -113,6 +144,17 @@ fn index(&self, _index: &ops::RangeFull) -> &OsStr {
     }
 }
 
+#[cfg(not(stage0))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ops::Index<ops::RangeFull> for OsString {
+    type Output = OsStr;
+
+    #[inline]
+    fn index(&self, _index: ops::RangeFull) -> &OsStr {
+        unsafe { mem::transmute(self.inner.as_slice()) }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Deref for OsString {
     type Target = OsStr;
@@ -316,37 +358,76 @@ fn to_owned(&self) -> OsString { self.to_os_string() }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl<'a, T: AsOsStr + ?Sized> AsOsStr for &'a T {
     fn as_os_str(&self) -> &OsStr {
         (*self).as_os_str()
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl AsOsStr for OsStr {
     fn as_os_str(&self) -> &OsStr {
         self
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl AsOsStr for OsString {
     fn as_os_str(&self) -> &OsStr {
         &self[..]
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl AsOsStr for str {
     fn as_os_str(&self) -> &OsStr {
         OsStr::from_str(self)
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl AsOsStr for String {
     fn as_os_str(&self) -> &OsStr {
         OsStr::from_str(&self[..])
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for OsStr {
+    fn as_ref(&self) -> &OsStr {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for OsString {
+    fn as_ref(&self) -> &OsStr {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for str {
+    fn as_ref(&self) -> &OsStr {
+        OsStr::from_str(self)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for String {
+    fn as_ref(&self) -> &OsStr {
+        OsStr::from_str(&self[..])
+    }
+}
+
 #[allow(deprecated)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl AsOsStr for Path {
     #[cfg(unix)]
     fn as_os_str(&self) -> &OsStr {
index 7df6d6887a25892e564dbeb2a11ff0207165bbc6..ab65004f5d1f9984d7f869857db0f6e4964e21c7 100644 (file)
@@ -20,7 +20,7 @@
 use core::prelude::*;
 
 use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
-use path::{AsPath, Path, PathBuf};
+use path::{Path, PathBuf};
 use sys::fs2 as fs_imp;
 use sys_common::{AsInnerMut, FromInner, AsInner};
 use vec::Vec;
@@ -129,7 +129,7 @@ impl File {
     /// This function will return an error if `path` does not already exist.
     /// Other errors may also be returned according to `OpenOptions::open`.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn open<P: AsPath>(path: P) -> io::Result<File> {
+    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
         OpenOptions::new().read(true).open(path)
     }
 
@@ -140,7 +140,7 @@ pub fn open<P: AsPath>(path: P) -> io::Result<File> {
     ///
     /// See the `OpenOptions::open` function for more details.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn create<P: AsPath>(path: P) -> io::Result<File> {
+    pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
         OpenOptions::new().write(true).create(true).truncate(true).open(path)
     }
 
@@ -302,8 +302,8 @@ pub fn create(&mut self, create: bool) -> &mut OpenOptions {
     ///   permissions for
     /// * Filesystem-level errors (full disk, etc)
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn open<P: AsPath>(&self, path: P) -> io::Result<File> {
-        let path = path.as_path();
+    pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
+        let path = path.as_ref();
         let inner = try!(fs_imp::File::open(path, &self.0));
         Ok(File { path: path.to_path_buf(), inner: inner })
     }
@@ -415,8 +415,8 @@ pub fn path(&self) -> PathBuf { self.0.path() }
 /// user lacks permissions to remove the file, or if some other filesystem-level
 /// error occurs.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
-    fs_imp::unlink(path.as_path())
+pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    fs_imp::unlink(path.as_ref())
 }
 
 /// Given a path, query the file system to get information about a file,
@@ -443,8 +443,8 @@ pub fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
 /// permissions to perform a `metadata` call on the given `path` or if there
 /// is no entry in the filesystem at the provided path.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn metadata<P: AsPath>(path: P) -> io::Result<Metadata> {
-    fs_imp::stat(path.as_path()).map(Metadata)
+pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+    fs_imp::stat(path.as_ref()).map(Metadata)
 }
 
 /// Rename a file or directory to a new name.
@@ -464,8 +464,8 @@ pub fn metadata<P: AsPath>(path: P) -> io::Result<Metadata> {
 /// reside on separate filesystems, or if some other intermittent I/O error
 /// occurs.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
-    fs_imp::rename(from.as_path(), to.as_path())
+pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+    fs_imp::rename(from.as_ref(), to.as_ref())
 }
 
 /// Copies the contents of one file to another. This function will also
@@ -494,9 +494,9 @@ pub fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
 /// * The current process does not have the permission rights to access
 ///   `from` or write `to`
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
-    let from = from.as_path();
-    let to = to.as_path();
+pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
+    let from = from.as_ref();
+    let to = to.as_ref();
     if !from.is_file() {
         return Err(Error::new(ErrorKind::InvalidInput,
                               "the source path is not an existing file",
@@ -517,16 +517,16 @@ pub fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
 /// The `dst` path will be a link pointing to the `src` path. Note that systems
 /// often require these two paths to both be located on the same filesystem.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn hard_link<P: AsPath, Q: AsPath>(src: P, dst: Q) -> io::Result<()> {
-    fs_imp::link(src.as_path(), dst.as_path())
+pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+    fs_imp::link(src.as_ref(), dst.as_ref())
 }
 
 /// Creates a new soft link on the filesystem.
 ///
 /// The `dst` path will be a soft link pointing to the `src` path.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn soft_link<P: AsPath, Q: AsPath>(src: P, dst: Q) -> io::Result<()> {
-    fs_imp::symlink(src.as_path(), dst.as_path())
+pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+    fs_imp::symlink(src.as_ref(), dst.as_ref())
 }
 
 /// Reads a soft link, returning the file that the link points to.
@@ -537,8 +537,8 @@ pub fn soft_link<P: AsPath, Q: AsPath>(src: P, dst: Q) -> io::Result<()> {
 /// reading a file that does not exist or reading a file that is not a soft
 /// link.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
-    fs_imp::readlink(path.as_path())
+pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    fs_imp::readlink(path.as_ref())
 }
 
 /// Create a new, empty directory at the provided path
@@ -556,8 +556,8 @@ pub fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
 /// This function will return an error if the user lacks permissions to make a
 /// new directory at the provided `path`, or if the directory already exists.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn create_dir<P: AsPath>(path: P) -> io::Result<()> {
-    fs_imp::mkdir(path.as_path())
+pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    fs_imp::mkdir(path.as_ref())
 }
 
 /// Recursively create a directory and all of its parent components if they
@@ -570,8 +570,8 @@ pub fn create_dir<P: AsPath>(path: P) -> io::Result<()> {
 /// error conditions for when a directory is being created (after it is
 /// determined to not exist) are outlined by `fs::create_dir`.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn create_dir_all<P: AsPath>(path: P) -> io::Result<()> {
-    let path = path.as_path();
+pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    let path = path.as_ref();
     if path.is_dir() { return Ok(()) }
     if let Some(p) = path.parent() { try!(create_dir_all(p)) }
     create_dir(path)
@@ -592,8 +592,8 @@ pub fn create_dir_all<P: AsPath>(path: P) -> io::Result<()> {
 /// This function will return an error if the user lacks permissions to remove
 /// the directory at the provided `path`, or if the directory isn't empty.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
-    fs_imp::rmdir(path.as_path())
+pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    fs_imp::rmdir(path.as_ref())
 }
 
 /// Removes a directory at this path, after removing all its contents. Use
@@ -606,8 +606,8 @@ pub fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
 ///
 /// See `file::remove_file` and `fs::remove_dir`
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
-    let path = path.as_path();
+pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+    let path = path.as_ref();
     for child in try!(read_dir(path)) {
         let child = try!(child).path();
         let stat = try!(lstat(&*child));
@@ -659,8 +659,8 @@ fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::stat(path) }
 /// the process lacks permissions to view the contents or if the `path` points
 /// at a non-directory file
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
-    fs_imp::readdir(path.as_path()).map(ReadDir)
+pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
+    fs_imp::readdir(path.as_ref()).map(ReadDir)
 }
 
 /// Returns an iterator that will recursively walk the directory structure
@@ -675,7 +675,7 @@ pub fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
            reason = "the precise semantics and defaults for a recursive walk \
                      may change and this may end up accounting for files such \
                      as symlinks differently")]
-pub fn walk_dir<P: AsPath>(path: P) -> io::Result<WalkDir> {
+pub fn walk_dir<P: AsRef<Path>>(path: P) -> io::Result<WalkDir> {
     let start = try!(read_dir(path));
     Ok(WalkDir { cur: Some(start), stack: Vec::new() })
 }
@@ -761,9 +761,9 @@ fn is_dir(&self) -> bool {
            reason = "the argument type of u64 is not quite appropriate for \
                      this function and may change if the standard library \
                      gains a type to represent a moment in time")]
-pub fn set_file_times<P: AsPath>(path: P, accessed: u64,
+pub fn set_file_times<P: AsRef<Path>>(path: P, accessed: u64,
                                  modified: u64) -> io::Result<()> {
-    fs_imp::utimes(path.as_path(), accessed, modified)
+    fs_imp::utimes(path.as_ref(), accessed, modified)
 }
 
 /// Changes the permissions found on a file or a directory.
@@ -790,8 +790,8 @@ pub fn set_file_times<P: AsPath>(path: P, accessed: u64,
            reason = "a more granual ability to set specific permissions may \
                      be exposed on the Permissions structure itself and this \
                      method may not always exist")]
-pub fn set_permissions<P: AsPath>(path: P, perm: Permissions) -> io::Result<()> {
-    fs_imp::set_perm(path.as_path(), perm.0)
+pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
+    fs_imp::set_perm(path.as_ref(), perm.0)
 }
 
 #[cfg(test)]
index 8f32d7a586459241324a3a249a6ede228c4bce55..a9717e36323392a74e55325916a306f9b52bd503 100644 (file)
@@ -18,7 +18,7 @@
 use env;
 use io::{self, Error, ErrorKind};
 use fs;
-use path::{self, PathBuf, AsPath};
+use path::{self, PathBuf};
 use rand::{thread_rng, Rng};
 
 /// A wrapper for a path to temporary directory implementing automatic
@@ -43,10 +43,9 @@ impl TempDir {
     ///
     /// If no directory can be created, `Err` is returned.
     #[allow(deprecated)] // rand usage
-    pub fn new_in<P: AsPath + ?Sized>(tmpdir: &P, prefix: &str)
-                                      -> io::Result<TempDir> {
+    pub fn new_in<P: AsRef<path::Path>>(tmpdir: P, prefix: &str) -> io::Result<TempDir> {
         let storage;
-        let mut tmpdir = tmpdir.as_path();
+        let mut tmpdir = tmpdir.as_ref();
         if !tmpdir.is_absolute() {
             let cur_dir = try!(env::current_dir());
             storage = cur_dir.join(tmpdir);
index 43eec695274208213e2a1f4e9850a2c58879037f..4def601f1c0e7657f6a3e7da1c057ec3c53da99a 100644 (file)
@@ -258,7 +258,7 @@ fn from_error(iie: IntoInnerError<W>) -> Error { iie.1 }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W> error::Error for IntoInnerError<W> {
+impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
     fn description(&self) -> &str {
         error::Error::description(self.error())
     }
index 87e5a2a448855f97da265eeeccc38aa1c2ae16fe..79f0af670b44624ea031136bf95654877ed3bcdb 100644 (file)
 use num::Int;
 use slice;
 
-/// A `Cursor` is a type which wraps another I/O object to provide a `Seek`
+/// A `Cursor` is a type which wraps a non-I/O object to provide a `Seek`
 /// implementation.
 ///
-/// Cursors are currently typically used with memory buffer objects in order to
-/// allow `Seek` plus `Read` and `Write` implementations. For example, common
-/// cursor types include:
+/// Cursors are typically used with memory buffer objects in order to allow
+/// `Seek`, `Read`, and `Write` implementations. For example, common cursor types
+/// include `Cursor<Vec<u8>>` and `Cursor<&[u8]>`.
 ///
-/// * `Cursor<Vec<u8>>`
-/// * `Cursor<&[u8]>`
-///
-/// Implementations of the I/O traits for `Cursor<T>` are not currently generic
+/// Implementations of the I/O traits for `Cursor<T>` are currently not generic
 /// over `T` itself. Instead, specific implementations are provided for various
 /// in-memory buffer types like `Vec<u8>` and `&[u8]`.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone, Debug)]
 pub struct Cursor<T> {
     inner: T,
     pos: u64,
index b055796ba547fefc9ce9ea8df62d797373d89cc9..fbec96e9310f16c442695ba2a0c297a74f7f7d9b 100644 (file)
 #![feature(hash)]
 #![feature(int_uint)]
 #![feature(unique)]
+#![feature(convert)]
 #![feature(allow_internal_unstable)]
 #![feature(str_char)]
+#![feature(into_cow)]
 #![cfg_attr(test, feature(test, rustc_private))]
 
 // Don't link to std. We are std.
 pub use core::cell;
 pub use core::clone;
 #[cfg(not(test))] pub use core::cmp;
+pub use core::convert;
 pub use core::default;
 #[allow(deprecated)]
 pub use core::finally;
 /* Runtime and platform support */
 
 #[macro_use]
-pub mod thread_local;
+pub mod thread;
 
+pub mod collections;
 pub mod dynamic_lib;
+pub mod env;
 pub mod ffi;
-pub mod old_io;
-pub mod io;
 pub mod fs;
+pub mod io;
 pub mod net;
+pub mod old_io;
+pub mod old_path;
 pub mod os;
-pub mod env;
 pub mod path;
-pub mod old_path;
 pub mod process;
 pub mod rand;
-pub mod time;
-
-/* Common data structures */
-
-pub mod collections;
-
-/* Threads and communication */
-
-pub mod thread;
 pub mod sync;
+pub mod time;
 
 #[macro_use]
 #[path = "sys/common/mod.rs"] mod sys_common;
@@ -305,7 +301,7 @@ mod std {
     pub use rt; // used for panic!()
     pub use vec; // used for vec![]
     pub use cell; // used for tls!
-    pub use thread_local; // used for thread_local!
+    pub use thread; // used for thread_local!
     pub use marker;  // used for tls!
     pub use ops; // used for bitflags!
 
index f4a7e8b1b982441654b505b96fefdd654a38c594..0b9cb14e04c1b236e87523e9ff431cc7cff07d84 100644 (file)
@@ -90,8 +90,7 @@ macro_rules! println {
 }
 
 /// Helper macro for unwrapping `Result` values while returning early with an
-/// error if the value of the expression is `Err`. For more information, see
-/// `std::io`.
+/// error if the value of the expression is `Err`.
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 macro_rules! try {
index 73c2464a6b2cb9b33449568b3149c34a3e0e3a9e..d737ad17ff8ecf7220cdb3d894b735ef3246b151 100644 (file)
@@ -374,7 +374,6 @@ fn fmt_subslice(segments: &[u16]) -> String {
                             .iter()
                             .map(|&seg| format!("{:x}", seg))
                             .collect::<Vec<String>>()
-                            .as_slice()
                             .connect(":")
                     }
 
index 3870b8614ffdfe05fbdaafc4c698bb4b34d26dc9..72f9338b456718faa8610acbd52d4a5f9929d7cf 100644 (file)
@@ -38,6 +38,7 @@
 
 use boxed::Box;
 use clone::Clone;
+use convert::From;
 use env;
 use error::{FromError, Error};
 use ffi::{OsString, OsStr};
@@ -79,12 +80,12 @@ fn err2old(new: ::io::Error) -> IoError {
 
 #[cfg(windows)]
 fn path2new(path: &Path) -> PathBuf {
-    PathBuf::new(path.as_str().unwrap())
+    PathBuf::from(path.as_str().unwrap())
 }
 #[cfg(unix)]
 fn path2new(path: &Path) -> PathBuf {
     use os::unix::prelude::*;
-    PathBuf::new(<OsStr as OsStrExt>::from_bytes(path.as_vec()))
+    PathBuf::from(<OsStr as OsStrExt>::from_bytes(path.as_vec()))
 }
 
 #[cfg(unix)]
index ddceed14cc6ce51a49ea3bbb680be1a71d56fd97..8ee33e94fe7276f9404a65b2e5cdb202a340b9bb 100644 (file)
 use iter::{self, IntoIterator};
 use mem;
 use ops::{self, Deref};
+use string::String;
 use vec::Vec;
 use fmt;
 
@@ -527,6 +528,13 @@ pub fn as_os_str(self) -> &'a OsStr {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<OsStr> for Component<'a> {
+    fn as_ref(&self) -> &OsStr {
+        self.as_os_str()
+    }
+}
+
 /// The core iterator giving the components of a path.
 ///
 /// See the module documentation for an in-depth explanation of components and
@@ -601,6 +609,7 @@ fn is_sep_byte(&self, b: u8) -> bool {
     }
 
     /// Extract a slice corresponding to the portion of the path remaining for iteration.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_path(&self) -> &'a Path {
         let mut comps = self.clone();
         if comps.front == State::Body { comps.trim_left(); }
@@ -695,6 +704,20 @@ pub fn peek(&self) -> Option<Component<'a>> {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<Path> for Components<'a> {
+    fn as_ref(&self) -> &Path {
+        self.as_path()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<OsStr> for Components<'a> {
+    fn as_ref(&self) -> &OsStr {
+        self.as_path().as_os_str()
+    }
+}
+
 impl<'a> Iter<'a> {
     /// Extract a slice corresponding to the portion of the path remaining for iteration.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -703,6 +726,20 @@ pub fn as_path(&self) -> &'a Path {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<Path> for Iter<'a> {
+    fn as_ref(&self) -> &Path {
+        self.as_path()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> AsRef<OsStr> for Iter<'a> {
+    fn as_ref(&self) -> &OsStr {
+        self.as_path().as_os_str()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Iterator for Iter<'a> {
     type Item = &'a OsStr;
@@ -873,11 +910,10 @@ fn as_mut_vec(&mut self) -> &mut Vec<u8> {
         unsafe { mem::transmute(self) }
     }
 
-    /// Allocate a `PathBuf` with initial contents given by the
-    /// argument.
+    /// Allocate an empty `PathBuf`.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new<S: AsOsStr>(s: S) -> PathBuf {
-        PathBuf { inner: s.as_os_str().to_os_string() }
+    pub fn new() -> PathBuf {
+        PathBuf { inner: OsString::new() }
     }
 
     /// Extend `self` with `path`.
@@ -890,8 +926,8 @@ pub fn new<S: AsOsStr>(s: S) -> PathBuf {
     ///   replaces everything except for the prefix (if any) of `self`.
     /// * if `path` has a prefix but no root, it replaces `self.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn push<P: AsPath>(&mut self, path: P) {
-        let path = path.as_path();
+    pub fn push<P: AsRef<Path>>(&mut self, path: P) {
+        let path = path.as_ref();
 
         // in general, a separator is needed if the rightmost byte is not a separator
         let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false);
@@ -958,12 +994,12 @@ pub fn pop(&mut self) -> bool {
     /// assert!(buf == PathBuf::new("/baz.txt"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn set_file_name<S: AsOsStr>(&mut self, file_name: S) {
+    pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
         if self.file_name().is_some() {
             let popped = self.pop();
             debug_assert!(popped);
         }
-        self.push(file_name.as_os_str());
+        self.push(file_name.as_ref());
     }
 
     /// Updates `self.extension()` to `extension`.
@@ -973,15 +1009,15 @@ pub fn set_file_name<S: AsOsStr>(&mut self, file_name: S) {
     /// Otherwise, returns `true`; if `self.extension()` is `None`, the extension
     /// is added; otherwise it is replaced.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn set_extension<S: AsOsStr>(&mut self, extension: S) -> bool {
+    pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
         if self.file_name().is_none() { return false; }
 
         let mut stem = match self.file_stem() {
             Some(stem) => stem.to_os_string(),
-            None => OsString::from_str(""),
+            None => OsString::new(),
         };
 
-        let extension = extension.as_os_str();
+        let extension = extension.as_ref();
         if os_str_as_u8_slice(extension).len() > 0 {
             stem.push(".");
             stem.push(extension);
@@ -999,16 +1035,65 @@ pub fn into_os_string(self) -> OsString {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<P: AsPath> iter::FromIterator<P> for PathBuf {
+impl<'a> From<&'a Path> for PathBuf {
+    fn from(s: &'a Path) -> PathBuf {
+        s.to_path_buf()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a str> for PathBuf {
+    fn from(s: &'a str) -> PathBuf {
+        PathBuf::from(OsString::from(s))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a String> for PathBuf {
+    fn from(s: &'a String) -> PathBuf {
+        PathBuf::from(OsString::from(s))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<String> for PathBuf {
+    fn from(s: String) -> PathBuf {
+        PathBuf::from(OsString::from(s))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a OsStr> for PathBuf {
+    fn from(s: &'a OsStr) -> PathBuf {
+        PathBuf::from(OsString::from(s))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&'a OsString> for PathBuf {
+    fn from(s: &'a OsString) -> PathBuf {
+        PathBuf::from(s.to_os_string())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<OsString> for PathBuf {
+    fn from(s: OsString) -> PathBuf {
+        PathBuf { inner: s }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf {
     fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
-        let mut buf = PathBuf::new("");
+        let mut buf = PathBuf::new();
         buf.extend(iter);
         buf
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<P: AsPath> iter::Extend<P> for PathBuf {
+impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
     fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
         for p in iter {
             self.push(p)
@@ -1084,12 +1169,27 @@ fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for PathBuf {
+    fn as_ref(&self) -> &OsStr {
+        &self.inner[..]
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl AsOsStr for PathBuf {
     fn as_os_str(&self) -> &OsStr {
         &self.inner[..]
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Into<OsString> for PathBuf {
+    fn into(self) -> OsString {
+        self.inner
+    }
+}
+
 /// A slice of a path (akin to `str`).
 ///
 /// This type supports a number of operations for inspecting a path, including
@@ -1133,8 +1233,14 @@ fn as_u8_slice(&self) -> &[u8] {
     ///
     /// This is a cost-free conversion.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new<S: ?Sized + AsOsStr>(s: &S) -> &Path {
-        unsafe { mem::transmute(s.as_os_str()) }
+    pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
+        unsafe { mem::transmute(s.as_ref()) }
+    }
+
+    /// Yield the underlying `OsStr` slice.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn as_os_str(&self) -> &OsStr {
+        &self.inner
     }
 
     /// Yield a `&str` slice if the `Path` is valid unicode.
@@ -1156,7 +1262,7 @@ pub fn to_string_lossy(&self) -> Cow<str> {
     /// Convert a `Path` to an owned `PathBuf`.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn to_path_buf(&self) -> PathBuf {
-        PathBuf::new(self)
+        PathBuf::from(self.inner.to_os_string())
     }
 
     /// A path is *absolute* if it is independent of the current directory.
@@ -1243,23 +1349,25 @@ pub fn file_name(&self) -> Option<&OsStr> {
     }
 
     /// Returns a path that, when joined onto `base`, yields `self`.
+    ///
+    /// If `base` is not a prefix of `self` (i.e. `starts_with`
+    /// returns false), then `relative_from` returns `None`.
     #[unstable(feature = "path_relative_from", reason = "see #23284")]
-    pub fn relative_from<'a, P: ?Sized>(&'a self, base: &'a P) -> Option<&Path> where
-        P: AsPath
+    pub fn relative_from<'a, P: ?Sized + AsRef<Path>>(&'a self, base: &'a P) -> Option<&Path>
     {
-        iter_after(self.components(), base.as_path().components()).map(|c| c.as_path())
+        iter_after(self.components(), base.as_ref().components()).map(|c| c.as_path())
     }
 
     /// Determines whether `base` is a prefix of `self`.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn starts_with<P: AsPath>(&self, base: P) -> bool {
-        iter_after(self.components(), base.as_path().components()).is_some()
+    pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
+        iter_after(self.components(), base.as_ref().components()).is_some()
     }
 
     /// Determines whether `child` is a suffix of `self`.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ends_with<P: AsPath>(&self, child: P) -> bool {
-        iter_after(self.components().rev(), child.as_path().components().rev()).is_some()
+    pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
+        iter_after(self.components().rev(), child.as_ref().components().rev()).is_some()
     }
 
     /// Extract the stem (non-extension) portion of `self.file()`.
@@ -1292,7 +1400,7 @@ pub fn extension(&self) -> Option<&OsStr> {
     ///
     /// See `PathBuf::push` for more details on what it means to adjoin a path.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn join<P: AsPath>(&self, path: P) -> PathBuf {
+    pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
         let mut buf = self.to_path_buf();
         buf.push(path);
         buf
@@ -1302,7 +1410,7 @@ pub fn join<P: AsPath>(&self, path: P) -> PathBuf {
     ///
     /// See `PathBuf::set_file_name` for more details.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_file_name<S: AsOsStr>(&self, file_name: S) -> PathBuf {
+    pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
         let mut buf = self.to_path_buf();
         buf.set_file_name(file_name);
         buf
@@ -1312,7 +1420,7 @@ pub fn with_file_name<S: AsOsStr>(&self, file_name: S) -> PathBuf {
     ///
     /// See `PathBuf::set_extension` for more details.
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_extension<S: AsOsStr>(&self, extension: S) -> PathBuf {
+    pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
         let mut buf = self.to_path_buf();
         buf.set_extension(extension);
         buf
@@ -1346,6 +1454,14 @@ pub fn display(&self) -> Display {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<OsStr> for Path {
+    fn as_ref(&self) -> &OsStr {
+        &self.inner
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
 impl AsOsStr for Path {
     fn as_os_str(&self) -> &OsStr {
         &self.inner
@@ -1405,6 +1521,7 @@ fn cmp(&self, other: &Path) -> cmp::Ordering {
 
 /// Freely convertible to a `Path`.
 #[unstable(feature = "std_misc")]
+#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef<Path> instead")]
 pub trait AsPath {
     /// Convert to a `Path`.
     #[unstable(feature = "std_misc")]
@@ -1412,10 +1529,42 @@ pub trait AsPath {
 }
 
 #[unstable(feature = "std_misc")]
+#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef<Path> instead")]
+#[allow(deprecated)]
 impl<T: AsOsStr + ?Sized> AsPath for T {
     fn as_path(&self) -> &Path { Path::new(self.as_os_str()) }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for Path {
+    fn as_ref(&self) -> &Path { self }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for OsStr {
+    fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for OsString {
+    fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for str {
+    fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for String {
+    fn as_ref(&self) -> &Path { Path::new(self) }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<Path> for PathBuf {
+    fn as_ref(&self) -> &Path { self }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
index a0b4c80e9f3fa47e886a8434064e9621662f713c..6e12ac1a226592b864354231aed50703fd0f8e4f 100644 (file)
@@ -29,6 +29,8 @@
 #[doc(no_inline)] pub use clone::Clone;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
+#[unstable(feature = "convert")]
+#[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From};
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)] pub use iter::DoubleEndedIterator;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)] pub use result::Result::{self, Ok, Err};
 #[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
 #[doc(no_inline)] pub use slice::{SliceConcatExt, AsSlice};
 #[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
 #[doc(no_inline)] pub use str::Str;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)] pub use string::{String, ToString};
index 6b09636c1df1e8a370621a854db33ff569dbd05e..d11c3d221445f3220aedc8881d494a770c1c35df 100644 (file)
@@ -19,8 +19,8 @@
 use ffi::AsOsStr;
 use fmt;
 use io::{self, Error, ErrorKind};
-use path::AsPath;
 use libc;
+use path;
 use sync::mpsc::{channel, Receiver};
 use sys::pipe2::{self, AnonPipe};
 use sys::process2::Process as ProcessImp;
@@ -198,8 +198,8 @@ pub fn env_clear(&mut self) -> &mut Command {
 
     /// Set the working directory for the child process.
     #[stable(feature = "process", since = "1.0.0")]
-    pub fn current_dir<P: AsPath>(&mut self, dir: P) -> &mut Command {
-        self.inner.cwd(dir.as_path().as_os_str());
+    pub fn current_dir<P: AsRef<path::Path>>(&mut self, dir: P) -> &mut Command {
+        self.inner.cwd(dir.as_ref().as_os_str());
         self
     }
 
index 123dad978f55ad4d30748650f6bfe05b7c840e66..35125125d141d721618115c0e29b8695ed63756c 100644 (file)
@@ -977,7 +977,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> error::Error for SendError<T> {
+impl<T: Send> error::Error for SendError<T> {
 
     fn description(&self) -> &str {
         "sending on a closed channel"
@@ -1013,7 +1013,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> error::Error for TrySendError<T> {
+impl<T: Send> error::Error for TrySendError<T> {
 
     fn description(&self) -> &str {
         match *self {
index 1cbfbbf29278f1b03663400c2ea0fddc459c0a8a..130fd1d7dc83b36841ee5ca4afbf89ec575188f5 100644 (file)
@@ -40,7 +40,7 @@
 /// among threads to ensure that a possibly invalid invariant is not witnessed.
 ///
 /// A poisoned mutex, however, does not prevent all access to the underlying
-/// data. The `PoisonError` type has an `into_guard` method which will return
+/// data. The `PoisonError` type has an `into_inner` method which will return
 /// the guard that would have otherwise been returned on a successful lock. This
 /// allows access to the data, despite the lock being poisoned.
 ///
 /// // pattern matched on to return the underlying guard on both branches.
 /// let mut guard = match lock.lock() {
 ///     Ok(guard) => guard,
-///     Err(poisoned) => poisoned.into_guard(),
+///     Err(poisoned) => poisoned.into_inner(),
 /// };
 ///
 /// *guard += 1;
index 2587ff5238ea7b86eb29d107856be5ed31629198..c07c83d37f48881b041966d9c9cfbf48d82f5d8a 100644 (file)
@@ -105,11 +105,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> fmt::Display for PoisonError<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.description().fmt(f)
+        "poisoned lock: another task failed inside".fmt(f)
     }
 }
 
-impl<T> Error for PoisonError<T> {
+impl<T: Send> Error for PoisonError<T> {
     fn description(&self) -> &str {
         "poisoned lock: another task failed inside"
     }
@@ -161,13 +161,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> fmt::Display for TryLockError<T> {
+impl<T: Send> fmt::Display for TryLockError<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         self.description().fmt(f)
     }
 }
 
-impl<T> Error for TryLockError<T> {
+impl<T: Send> Error for TryLockError<T> {
     fn description(&self) -> &str {
         match *self {
             TryLockError::Poisoned(ref p) => p.description(),
index e4985e703ba7645243ec3efd7e41a407eefa47c3..90526b8f4f318faa941d26c8cdd9be788e2be001 100644 (file)
@@ -15,7 +15,7 @@
 use cell::RefCell;
 use string::String;
 use thread::Thread;
-use thread_local::State;
+use thread::LocalKeyState;
 
 struct ThreadInfo {
     stack_guard: uint,
@@ -26,7 +26,7 @@ struct ThreadInfo {
 
 impl ThreadInfo {
     fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
-        if THREAD_INFO.state() == State::Destroyed {
+        if THREAD_INFO.state() == LocalKeyState::Destroyed {
             panic!("Use of std::thread::current() is not possible after \
                     the thread's local data has been destroyed");
         }
index 3cc91bf54b4d92dec95082b79f2f223acba8b81e..9f3dae34c7a4bff3a127111110fa955d335748e3 100644 (file)
@@ -634,6 +634,7 @@ fn initial_trail_surrogate(&self) -> Option<u16> {
 ///
 /// Panics when `begin` and `end` do not point to code point boundaries,
 /// or point beyond the end of the string.
+#[cfg(stage0)]
 impl ops::Index<ops::Range<usize>> for Wtf8 {
     type Output = Wtf8;
 
@@ -650,12 +651,36 @@ fn index(&self, range: &ops::Range<usize>) -> &Wtf8 {
     }
 }
 
+/// Return a slice of the given string for the byte range [`begin`..`end`).
+///
+/// # Panics
+///
+/// Panics when `begin` and `end` do not point to code point boundaries,
+/// or point beyond the end of the string.
+#[cfg(not(stage0))]
+impl ops::Index<ops::Range<usize>> for Wtf8 {
+    type Output = Wtf8;
+
+    #[inline]
+    fn index(&self, range: ops::Range<usize>) -> &Wtf8 {
+        // is_code_point_boundary checks that the index is in [0, .len()]
+        if range.start <= range.end &&
+           is_code_point_boundary(self, range.start) &&
+           is_code_point_boundary(self, range.end) {
+            unsafe { slice_unchecked(self, range.start, range.end) }
+        } else {
+            slice_error_fail(self, range.start, range.end)
+        }
+    }
+}
+
 /// Return a slice of the given string from byte `begin` to its end.
 ///
 /// # Panics
 ///
 /// Panics when `begin` is not at a code point boundary,
 /// or is beyond the end of the string.
+#[cfg(stage0)]
 impl ops::Index<ops::RangeFrom<usize>> for Wtf8 {
     type Output = Wtf8;
 
@@ -670,12 +695,34 @@ fn index(&self, range: &ops::RangeFrom<usize>) -> &Wtf8 {
     }
 }
 
+/// Return a slice of the given string from byte `begin` to its end.
+///
+/// # Panics
+///
+/// Panics when `begin` is not at a code point boundary,
+/// or is beyond the end of the string.
+#[cfg(not(stage0))]
+impl ops::Index<ops::RangeFrom<usize>> for Wtf8 {
+    type Output = Wtf8;
+
+    #[inline]
+    fn index(&self, range: ops::RangeFrom<usize>) -> &Wtf8 {
+        // is_code_point_boundary checks that the index is in [0, .len()]
+        if is_code_point_boundary(self, range.start) {
+            unsafe { slice_unchecked(self, range.start, self.len()) }
+        } else {
+            slice_error_fail(self, range.start, self.len())
+        }
+    }
+}
+
 /// Return a slice of the given string from its beginning to byte `end`.
 ///
 /// # Panics
 ///
 /// Panics when `end` is not at a code point boundary,
 /// or is beyond the end of the string.
+#[cfg(stage0)]
 impl ops::Index<ops::RangeTo<usize>> for Wtf8 {
     type Output = Wtf8;
 
@@ -690,6 +737,28 @@ fn index(&self, range: &ops::RangeTo<usize>) -> &Wtf8 {
     }
 }
 
+/// Return a slice of the given string from its beginning to byte `end`.
+///
+/// # Panics
+///
+/// Panics when `end` is not at a code point boundary,
+/// or is beyond the end of the string.
+#[cfg(not(stage0))]
+impl ops::Index<ops::RangeTo<usize>> for Wtf8 {
+    type Output = Wtf8;
+
+    #[inline]
+    fn index(&self, range: ops::RangeTo<usize>) -> &Wtf8 {
+        // is_code_point_boundary checks that the index is in [0, .len()]
+        if is_code_point_boundary(self, range.end) {
+            unsafe { slice_unchecked(self, 0, range.end) }
+        } else {
+            slice_error_fail(self, 0, range.end)
+        }
+    }
+}
+
+#[cfg(stage0)]
 impl ops::Index<ops::RangeFull> for Wtf8 {
     type Output = Wtf8;
 
@@ -699,6 +768,16 @@ fn index(&self, _range: &ops::RangeFull) -> &Wtf8 {
     }
 }
 
+#[cfg(not(stage0))]
+impl ops::Index<ops::RangeFull> for Wtf8 {
+    type Output = Wtf8;
+
+    #[inline]
+    fn index(&self, _range: ops::RangeFull) -> &Wtf8 {
+        self
+    }
+}
+
 #[inline]
 fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 {
     // The first byte is assumed to be 0xED
index ea74aab3331ae5e49c12b76e6f89b999de9ace63..202e5ddaec42bd01c77eda25d11acdba21c902fd 100644 (file)
@@ -338,8 +338,7 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> {
         }));
         buf.set_len(n as usize);
     }
-    let s: OsString = OsStringExt::from_vec(buf);
-    Ok(PathBuf::new(&s))
+    Ok(PathBuf::from(OsString::from_vec(buf)))
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
index a5a2f71acb7e0db572dd89fee95e1b3df3b5f715..6c191689255bc123ac0517fa676300ef5051f128 100644 (file)
@@ -36,7 +36,7 @@
 const TMPBUF_SZ: usize = 128;
 
 fn bytes2path(b: &[u8]) -> PathBuf {
-    PathBuf::new(<OsStr as OsStrExt>::from_bytes(b))
+    PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
 }
 
 fn os2path(os: OsString) -> PathBuf {
@@ -253,7 +253,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
         let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
         if err != 0 { return Err(io::Error::last_os_error()); }
         v.set_len(sz as uint - 1); // chop off trailing NUL
-        Ok(PathBuf::new(OsString::from_vec(v)))
+        Ok(PathBuf::from(OsString::from_vec(v)))
     }
 }
 
@@ -466,9 +466,9 @@ pub fn page_size() -> usize {
 pub fn temp_dir() -> PathBuf {
     getenv("TMPDIR".as_os_str()).map(os2path).unwrap_or_else(|| {
         if cfg!(target_os = "android") {
-            PathBuf::new("/data/local/tmp")
+            PathBuf::from("/data/local/tmp")
         } else {
-            PathBuf::new("/tmp")
+            PathBuf::from("/tmp")
         }
     })
 }
diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs
deleted file mode 100644 (file)
index ab74442..0000000
+++ /dev/null
@@ -1,960 +0,0 @@
-// Copyright 2014 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.
-
-//! Native threads
-//!
-//! ## The threading model
-//!
-//! An executing Rust program consists of a collection of native OS threads,
-//! each with their own stack and local state.
-//!
-//! Communication between threads can be done through
-//! [channels](../../std/sync/mpsc/index.html), Rust's message-passing
-//! types, along with [other forms of thread
-//! synchronization](../../std/sync/index.html) and shared-memory data
-//! structures. In particular, types that are guaranteed to be
-//! threadsafe are easily shared between threads using the
-//! atomically-reference-counted container,
-//! [`Arc`](../../std/sync/struct.Arc.html).
-//!
-//! Fatal logic errors in Rust cause *thread panic*, during which
-//! a thread will unwind the stack, running destructors and freeing
-//! owned resources. Thread panic is unrecoverable from within
-//! the panicking thread (i.e. there is no 'try/catch' in Rust), but
-//! the panic may optionally be detected from a different thread. If
-//! the main thread panics, the application will exit with a non-zero
-//! exit code.
-//!
-//! When the main thread of a Rust program terminates, the entire program shuts
-//! down, even if other threads are still running. However, this module provides
-//! convenient facilities for automatically waiting for the termination of a
-//! child thread (i.e., join).
-//!
-//! ## The `Thread` type
-//!
-//! Threads are represented via the `Thread` type, which you can
-//! get in one of two ways:
-//!
-//! * By spawning a new thread, e.g. using the `thread::spawn` function.
-//! * By requesting the current thread, using the `thread::current` function.
-//!
-//! Threads can be named, and provide some built-in support for low-level
-//! synchronization (described below).
-//!
-//! The `thread::current()` function is available even for threads not spawned
-//! by the APIs of this module.
-//!
-//! ## Spawning a thread
-//!
-//! A new thread can be spawned using the `thread::spawn` function:
-//!
-//! ```rust
-//! use std::thread;
-//!
-//! thread::spawn(move || {
-//!     // some work here
-//! });
-//! ```
-//!
-//! In this example, the spawned thread is "detached" from the current
-//! thread. This means that it can outlive its parent (the thread that spawned
-//! it), unless this parent is the main thread.
-//!
-//! ## Scoped threads
-//!
-//! Often a parent thread uses a child thread to perform some particular task,
-//! and at some point must wait for the child to complete before continuing.
-//! For this scenario, use the `thread::scoped` function:
-//!
-//! ```rust
-//! use std::thread;
-//!
-//! let guard = thread::scoped(move || {
-//!     // some work here
-//! });
-//!
-//! // do some other work in the meantime
-//! let output = guard.join();
-//! ```
-//!
-//! The `scoped` function doesn't return a `Thread` directly; instead,
-//! it returns a *join guard*. The join guard is an RAII-style guard
-//! that will automatically join the child thread (block until it
-//! terminates) when it is dropped. You can join the child thread in
-//! advance by calling the `join` method on the guard, which will also
-//! return the result produced by the thread.  A handle to the thread
-//! itself is available via the `thread` method of the join guard.
-//!
-//! ## Configuring threads
-//!
-//! A new thread can be configured before it is spawned via the `Builder` type,
-//! which currently allows you to set the name, stack size, and writers for
-//! `println!` and `panic!` for the child thread:
-//!
-//! ```rust
-//! use std::thread;
-//!
-//! thread::Builder::new().name("child1".to_string()).spawn(move || {
-//!     println!("Hello, world!");
-//! });
-//! ```
-//!
-//! ## Blocking support: park and unpark
-//!
-//! Every thread is equipped with some basic low-level blocking support, via the
-//! `park` and `unpark` functions.
-//!
-//! Conceptually, each `Thread` handle has an associated token, which is
-//! initially not present:
-//!
-//! * The `thread::park()` function blocks the current thread unless or until
-//!   the token is available for its thread handle, at which point it atomically
-//!   consumes the token. It may also return *spuriously*, without consuming the
-//!   token. `thread::park_timeout()` does the same, but allows specifying a
-//!   maximum time to block the thread for.
-//!
-//! * The `unpark()` method on a `Thread` atomically makes the token available
-//!   if it wasn't already.
-//!
-//! In other words, each `Thread` acts a bit like a semaphore with initial count
-//! 0, except that the semaphore is *saturating* (the count cannot go above 1),
-//! and can return spuriously.
-//!
-//! The API is typically used by acquiring a handle to the current thread,
-//! placing that handle in a shared data structure so that other threads can
-//! find it, and then `park`ing. When some desired condition is met, another
-//! thread calls `unpark` on the handle.
-//!
-//! The motivation for this design is twofold:
-//!
-//! * It avoids the need to allocate mutexes and condvars when building new
-//!   synchronization primitives; the threads already provide basic blocking/signaling.
-//!
-//! * It can be implemented very efficiently on many platforms.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use prelude::v1::*;
-
-use any::Any;
-use cell::UnsafeCell;
-use fmt;
-use io;
-use marker::PhantomData;
-use rt::{self, unwind};
-use sync::{Mutex, Condvar, Arc};
-use sys::thread as imp;
-use sys_common::{stack, thread_info};
-use thunk::Thunk;
-use time::Duration;
-
-#[allow(deprecated)] use old_io::Writer;
-
-/// Thread configuration. Provides detailed control over the properties
-/// and behavior of new threads.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Builder {
-    // A name for the thread-to-be, for identification in panic messages
-    name: Option<String>,
-    // The size of the stack for the spawned thread
-    stack_size: Option<usize>,
-}
-
-impl Builder {
-    /// Generate the base configuration for spawning a thread, from which
-    /// configuration methods can be chained.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new() -> Builder {
-        Builder {
-            name: None,
-            stack_size: None,
-        }
-    }
-
-    /// Name the thread-to-be. Currently the name is used for identification
-    /// only in panic messages.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn name(mut self, name: String) -> Builder {
-        self.name = Some(name);
-        self
-    }
-
-    /// Set the size of the stack for the new thread.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn stack_size(mut self, size: usize) -> Builder {
-        self.stack_size = Some(size);
-        self
-    }
-
-    /// Redirect thread-local stdout.
-    #[unstable(feature = "std_misc",
-               reason = "Will likely go away after proc removal")]
-    #[deprecated(since = "1.0.0",
-                 reason = "the old I/O module is deprecated and this function \
-                           will be removed with no replacement")]
-    #[allow(deprecated)]
-    pub fn stdout(self, _stdout: Box<Writer + Send + 'static>) -> Builder {
-        self
-    }
-
-    /// Redirect thread-local stderr.
-    #[unstable(feature = "std_misc",
-               reason = "Will likely go away after proc removal")]
-    #[deprecated(since = "1.0.0",
-                 reason = "the old I/O module is deprecated and this function \
-                           will be removed with no replacement")]
-    #[allow(deprecated)]
-    pub fn stderr(self, _stderr: Box<Writer + Send + 'static>) -> Builder {
-        self
-    }
-
-    /// Spawn a new thread, and return a join handle for it.
-    ///
-    /// The child thread may outlive the parent (unless the parent thread
-    /// is the main thread; the whole process is terminated when the main
-    /// thread finishes.) The join handle can be used to block on
-    /// termination of the child thread, including recovering its panics.
-    ///
-    /// # Errors
-    ///
-    /// Unlike the `spawn` free function, this method yields an
-    /// `io::Result` to capture any failure to create the thread at
-    /// the OS level.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn spawn<F>(self, f: F) -> io::Result<JoinHandle> where
-        F: FnOnce(), F: Send + 'static
-    {
-        self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i))
-    }
-
-    /// Spawn a new child thread that must be joined within a given
-    /// scope, and return a `JoinGuard`.
-    ///
-    /// The join guard can be used to explicitly join the child thread (via
-    /// `join`), returning `Result<T>`, or it will implicitly join the child
-    /// upon being dropped. Because the child thread may refer to data on the
-    /// current thread's stack (hence the "scoped" name), it cannot be detached;
-    /// it *must* be joined before the relevant stack frame is popped. See the
-    /// module documentation for additional details.
-    ///
-    /// # Errors
-    ///
-    /// Unlike the `scoped` free function, this method yields an
-    /// `io::Result` to capture any failure to create the thread at
-    /// the OS level.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
-        T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
-    {
-        self.spawn_inner(Thunk::new(f)).map(|inner| {
-            JoinGuard { inner: inner, _marker: PhantomData }
-        })
-    }
-
-    fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
-        let Builder { name, stack_size } = self;
-
-        let stack_size = stack_size.unwrap_or(rt::min_stack());
-
-        let my_thread = Thread::new(name);
-        let their_thread = my_thread.clone();
-
-        let my_packet = Packet(Arc::new(UnsafeCell::new(None)));
-        let their_packet = Packet(my_packet.0.clone());
-
-        // Spawning a new OS thread guarantees that __morestack will never get
-        // triggered, but we must manually set up the actual stack bounds once
-        // this function starts executing. This raises the lower limit by a bit
-        // because by the time that this function is executing we've already
-        // consumed at least a little bit of stack (we don't know the exact byte
-        // address at which our stack started).
-        let main = move || {
-            let something_around_the_top_of_the_stack = 1;
-            let addr = &something_around_the_top_of_the_stack as *const i32;
-            let my_stack_top = addr as usize;
-            let my_stack_bottom = my_stack_top - stack_size + 1024;
-            unsafe {
-                if let Some(name) = their_thread.name() {
-                    imp::set_name(name);
-                }
-                stack::record_os_managed_stack_bounds(my_stack_bottom,
-                                                      my_stack_top);
-                thread_info::set(imp::guard::current(), their_thread);
-            }
-
-            let mut output = None;
-            let try_result = {
-                let ptr = &mut output;
-
-                // There are two primary reasons that general try/catch is
-                // unsafe. The first is that we do not support nested
-                // try/catch. The fact that this is happening in a newly-spawned
-                // thread suffices. The second is that unwinding while unwinding
-                // is not defined.  We take care of that by having an
-                // 'unwinding' flag in the thread itself. For these reasons,
-                // this unsafety should be ok.
-                unsafe {
-                    unwind::try(move || *ptr = Some(f.invoke(())))
-                }
-            };
-            unsafe {
-                *their_packet.0.get() = Some(match (output, try_result) {
-                    (Some(data), Ok(_)) => Ok(data),
-                    (None, Err(cause)) => Err(cause),
-                    _ => unreachable!()
-                });
-            }
-        };
-
-        Ok(JoinInner {
-            native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }),
-            thread: my_thread,
-            packet: my_packet,
-            joined: false,
-        })
-    }
-}
-
-/// Spawn a new thread, returning a `JoinHandle` for it.
-///
-/// The join handle will implicitly *detach* the child thread upon being
-/// dropped. In this case, the child thread may outlive the parent (unless
-/// the parent thread is the main thread; the whole process is terminated when
-/// the main thread finishes.) Additionally, the join handle provides a `join`
-/// method that can be used to join the child thread. If the child thread
-/// panics, `join` will return an `Err` containing the argument given to
-/// `panic`.
-///
-/// # Panics
-///
-/// Panicks if the OS fails to create a thread; use `Builder::spawn`
-/// to recover from such errors.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
-    Builder::new().spawn(f).unwrap()
-}
-
-/// Spawn a new *scoped* thread, returning a `JoinGuard` for it.
-///
-/// The join guard can be used to explicitly join the child thread (via
-/// `join`), returning `Result<T>`, or it will implicitly join the child
-/// upon being dropped. Because the child thread may refer to data on the
-/// current thread's stack (hence the "scoped" name), it cannot be detached;
-/// it *must* be joined before the relevant stack frame is popped. See the
-/// module documentation for additional details.
-///
-/// # Panics
-///
-/// Panicks if the OS fails to create a thread; use `Builder::scoped`
-/// to recover from such errors.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
-    T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
-{
-    Builder::new().scoped(f).unwrap()
-}
-
-/// Gets a handle to the thread that invokes it.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn current() -> Thread {
-    thread_info::current_thread()
-}
-
-/// Cooperatively give up a timeslice to the OS scheduler.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn yield_now() {
-    unsafe { imp::yield_now() }
-}
-
-/// Determines whether the current thread is unwinding because of panic.
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn panicking() -> bool {
-    unwind::panicking()
-}
-
-/// Put the current thread to sleep for the specified amount of time.
-///
-/// The thread may sleep longer than the duration specified due to scheduling
-/// specifics or platform-dependent functionality. Note that on unix platforms
-/// this function will not return early due to a signal being received or a
-/// spurious wakeup.
-#[unstable(feature = "thread_sleep",
-           reason = "recently added, needs an RFC, and `Duration` itself is \
-                     unstable")]
-pub fn sleep(dur: Duration) {
-    imp::sleep(dur)
-}
-
-/// Block unless or until the current thread's token is made available (may wake spuriously).
-///
-/// See the module doc for more detail.
-//
-// The implementation currently uses the trivial strategy of a Mutex+Condvar
-// with wakeup flag, which does not actually allow spurious wakeups. In the
-// future, this will be implemented in a more efficient way, perhaps along the lines of
-//   http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
-// or futuxes, and in either case may allow spurious wakeups.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn park() {
-    let thread = current();
-    let mut guard = thread.inner.lock.lock().unwrap();
-    while !*guard {
-        guard = thread.inner.cvar.wait(guard).unwrap();
-    }
-    *guard = false;
-}
-
-/// Block unless or until the current thread's token is made available or
-/// the specified duration has been reached (may wake spuriously).
-///
-/// The semantics of this function are equivalent to `park()` except that the
-/// thread will be blocked for roughly no longer than *duration*. This method
-/// should not be used for precise timing due to anomalies such as
-/// preemption or platform differences that may not cause the maximum
-/// amount of time waited to be precisely *duration* long.
-///
-/// See the module doc for more detail.
-#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")]
-pub fn park_timeout(duration: Duration) {
-    let thread = current();
-    let mut guard = thread.inner.lock.lock().unwrap();
-    if !*guard {
-        let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap();
-        guard = g;
-    }
-    *guard = false;
-}
-
-/// The internal representation of a `Thread` handle
-struct Inner {
-    name: Option<String>,
-    lock: Mutex<bool>,          // true when there is a buffered unpark
-    cvar: Condvar,
-}
-
-unsafe impl Sync for Inner {}
-
-#[derive(Clone)]
-#[stable(feature = "rust1", since = "1.0.0")]
-/// A handle to a thread.
-pub struct Thread {
-    inner: Arc<Inner>,
-}
-
-impl Thread {
-    // Used only internally to construct a thread object without spawning
-    fn new(name: Option<String>) -> Thread {
-        Thread {
-            inner: Arc::new(Inner {
-                name: name,
-                lock: Mutex::new(false),
-                cvar: Condvar::new(),
-            })
-        }
-    }
-
-    /// Deprecated: use module-level free function.
-    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
-    #[unstable(feature = "std_misc",
-               reason = "may change with specifics of new Send semantics")]
-    pub fn spawn<F>(f: F) -> Thread where F: FnOnce(), F: Send + 'static {
-        Builder::new().spawn(f).unwrap().thread().clone()
-    }
-
-    /// Deprecated: use module-level free function.
-    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
-    #[unstable(feature = "std_misc",
-               reason = "may change with specifics of new Send semantics")]
-    pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
-        T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
-    {
-        Builder::new().scoped(f).unwrap()
-    }
-
-    /// Deprecated: use module-level free function.
-    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn current() -> Thread {
-        thread_info::current_thread()
-    }
-
-    /// Deprecated: use module-level free function.
-    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
-    #[unstable(feature = "std_misc", reason = "name may change")]
-    pub fn yield_now() {
-        unsafe { imp::yield_now() }
-    }
-
-    /// Deprecated: use module-level free function.
-    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn panicking() -> bool {
-        unwind::panicking()
-    }
-
-    /// Deprecated: use module-level free function.
-    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
-    #[unstable(feature = "std_misc", reason = "recently introduced")]
-    pub fn park() {
-        let thread = current();
-        let mut guard = thread.inner.lock.lock().unwrap();
-        while !*guard {
-            guard = thread.inner.cvar.wait(guard).unwrap();
-        }
-        *guard = false;
-    }
-
-    /// Deprecated: use module-level free function.
-    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
-    #[unstable(feature = "std_misc", reason = "recently introduced")]
-    pub fn park_timeout(duration: Duration) {
-        let thread = current();
-        let mut guard = thread.inner.lock.lock().unwrap();
-        if !*guard {
-            let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap();
-            guard = g;
-        }
-        *guard = false;
-    }
-
-    /// Atomically makes the handle's token available if it is not already.
-    ///
-    /// See the module doc for more detail.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unpark(&self) {
-        let mut guard = self.inner.lock.lock().unwrap();
-        if !*guard {
-            *guard = true;
-            self.inner.cvar.notify_one();
-        }
-    }
-
-    /// Get the thread's name.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn name(&self) -> Option<&str> {
-        self.inner.name.as_ref().map(|s| &**s)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Thread {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.name(), f)
-    }
-}
-
-// a hack to get around privacy restrictions
-impl thread_info::NewThread for Thread {
-    fn new(name: Option<String>) -> Thread { Thread::new(name) }
-}
-
-/// Indicates the manner in which a thread exited.
-///
-/// A thread that completes without panicking is considered to exit successfully.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>;
-
-struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
-
-unsafe impl<T:Send> Send for Packet<T> {}
-unsafe impl<T> Sync for Packet<T> {}
-
-/// Inner representation for JoinHandle and JoinGuard
-struct JoinInner<T> {
-    native: imp::rust_thread,
-    thread: Thread,
-    packet: Packet<T>,
-    joined: bool,
-}
-
-impl<T> JoinInner<T> {
-    fn join(&mut self) -> Result<T> {
-        assert!(!self.joined);
-        unsafe { imp::join(self.native) };
-        self.joined = true;
-        unsafe {
-            (*self.packet.0.get()).take().unwrap()
-        }
-    }
-}
-
-/// An owned permission to join on a thread (block on its termination).
-///
-/// Unlike a `JoinGuard`, a `JoinHandle` *detaches* the child thread
-/// when it is dropped, rather than automatically joining on drop.
-///
-/// Due to platform restrictions, it is not possible to `Clone` this
-/// handle: the ability to join a child thread is a uniquely-owned
-/// permission.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct JoinHandle(JoinInner<()>);
-
-impl JoinHandle {
-    /// Extract a handle to the underlying thread
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn thread(&self) -> &Thread {
-        &self.0.thread
-    }
-
-    /// Wait for the associated thread to finish.
-    ///
-    /// If the child thread panics, `Err` is returned with the parameter given
-    /// to `panic`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn join(mut self) -> Result<()> {
-        self.0.join()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Drop for JoinHandle {
-    fn drop(&mut self) {
-        if !self.0.joined {
-            unsafe { imp::detach(self.0.native) }
-        }
-    }
-}
-
-/// An RAII-style guard that will block until thread termination when dropped.
-///
-/// The type `T` is the return type for the thread's main function.
-///
-/// Joining on drop is necessary to ensure memory safety when stack
-/// data is shared between a parent and child thread.
-///
-/// Due to platform restrictions, it is not possible to `Clone` this
-/// handle: the ability to join a child thread is a uniquely-owned
-/// permission.
-#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct JoinGuard<'a, T: 'a> {
-    inner: JoinInner<T>,
-    _marker: PhantomData<&'a T>,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {}
-
-impl<'a, T: Send + 'a> JoinGuard<'a, T> {
-    /// Extract a handle to the thread this guard will join on.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn thread(&self) -> &Thread {
-        &self.inner.thread
-    }
-
-    /// Wait for the associated thread to finish, returning the result of the thread's
-    /// calculation.
-    ///
-    /// # Panics
-    ///
-    /// Panics on the child thread are propagated by panicking the parent.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn join(mut self) -> T {
-        match self.inner.join() {
-            Ok(res) => res,
-            Err(_) => panic!("child thread {:?} panicked", self.thread()),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> JoinGuard<'static, T> {
-    /// Detaches the child thread, allowing it to outlive its parent.
-    #[deprecated(since = "1.0.0", reason = "use spawn instead")]
-    #[unstable(feature = "std_misc")]
-    pub fn detach(mut self) {
-        unsafe { imp::detach(self.inner.native) };
-        self.inner.joined = true; // avoid joining in the destructor
-    }
-}
-
-#[unsafe_destructor]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
-    fn drop(&mut self) {
-        if !self.inner.joined {
-            if self.inner.join().is_err() {
-                panic!("child thread {:?} panicked", self.thread());
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use prelude::v1::*;
-
-    use any::Any;
-    use sync::mpsc::{channel, Sender};
-    use boxed::BoxAny;
-    use result;
-    use std::old_io::{ChanReader, ChanWriter};
-    use super::{Builder};
-    use thread;
-    use thunk::Thunk;
-    use time::Duration;
-
-    // !!! These tests are dangerous. If something is buggy, they will hang, !!!
-    // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
-
-    #[test]
-    fn test_unnamed_thread() {
-        thread::spawn(move|| {
-            assert!(thread::current().name().is_none());
-        }).join().ok().unwrap();
-    }
-
-    #[test]
-    fn test_named_thread() {
-        Builder::new().name("ada lovelace".to_string()).scoped(move|| {
-            assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
-        }).unwrap().join();
-    }
-
-    #[test]
-    fn test_run_basic() {
-        let (tx, rx) = channel();
-        thread::spawn(move|| {
-            tx.send(()).unwrap();
-        });
-        rx.recv().unwrap();
-    }
-
-    #[test]
-    fn test_join_success() {
-        assert!(thread::scoped(move|| -> String {
-            "Success!".to_string()
-        }).join() == "Success!");
-    }
-
-    #[test]
-    fn test_join_panic() {
-        match thread::spawn(move|| {
-            panic!()
-        }).join() {
-            result::Result::Err(_) => (),
-            result::Result::Ok(()) => panic!()
-        }
-    }
-
-    #[test]
-    fn test_scoped_success() {
-        let res = thread::scoped(move|| -> String {
-            "Success!".to_string()
-        }).join();
-        assert!(res == "Success!");
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_scoped_panic() {
-        thread::scoped(|| panic!()).join();
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_scoped_implicit_panic() {
-        let _ = thread::scoped(|| panic!());
-    }
-
-    #[test]
-    fn test_spawn_sched() {
-        use clone::Clone;
-
-        let (tx, rx) = channel();
-
-        fn f(i: i32, tx: Sender<()>) {
-            let tx = tx.clone();
-            thread::spawn(move|| {
-                if i == 0 {
-                    tx.send(()).unwrap();
-                } else {
-                    f(i - 1, tx);
-                }
-            });
-
-        }
-        f(10, tx);
-        rx.recv().unwrap();
-    }
-
-    #[test]
-    fn test_spawn_sched_childs_on_default_sched() {
-        let (tx, rx) = channel();
-
-        thread::spawn(move|| {
-            thread::spawn(move|| {
-                tx.send(()).unwrap();
-            });
-        });
-
-        rx.recv().unwrap();
-    }
-
-    fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Thunk<'static>) {
-        let (tx, rx) = channel();
-
-        let x: Box<_> = box 1;
-        let x_in_parent = (&*x) as *const i32 as usize;
-
-        spawnfn(Thunk::new(move|| {
-            let x_in_child = (&*x) as *const i32 as usize;
-            tx.send(x_in_child).unwrap();
-        }));
-
-        let x_in_child = rx.recv().unwrap();
-        assert_eq!(x_in_parent, x_in_child);
-    }
-
-    #[test]
-    fn test_avoid_copying_the_body_spawn() {
-        avoid_copying_the_body(|v| {
-            thread::spawn(move || v.invoke(()));
-        });
-    }
-
-    #[test]
-    fn test_avoid_copying_the_body_thread_spawn() {
-        avoid_copying_the_body(|f| {
-            thread::spawn(move|| {
-                f.invoke(());
-            });
-        })
-    }
-
-    #[test]
-    fn test_avoid_copying_the_body_join() {
-        avoid_copying_the_body(|f| {
-            let _ = thread::spawn(move|| {
-                f.invoke(())
-            }).join();
-        })
-    }
-
-    #[test]
-    fn test_child_doesnt_ref_parent() {
-        // If the child refcounts the parent task, this will stack overflow when
-        // climbing the task tree to dereference each ancestor. (See #1789)
-        // (well, it would if the constant were 8000+ - I lowered it to be more
-        // valgrind-friendly. try this at home, instead..!)
-        const GENERATIONS: u32 = 16;
-        fn child_no(x: u32) -> Thunk<'static> {
-            return Thunk::new(move|| {
-                if x < GENERATIONS {
-                    thread::spawn(move|| child_no(x+1).invoke(()));
-                }
-            });
-        }
-        thread::spawn(|| child_no(0).invoke(()));
-    }
-
-    #[test]
-    fn test_simple_newsched_spawn() {
-        thread::spawn(move || {});
-    }
-
-    #[test]
-    fn test_try_panic_message_static_str() {
-        match thread::spawn(move|| {
-            panic!("static string");
-        }).join() {
-            Err(e) => {
-                type T = &'static str;
-                assert!(e.is::<T>());
-                assert_eq!(*e.downcast::<T>().unwrap(), "static string");
-            }
-            Ok(()) => panic!()
-        }
-    }
-
-    #[test]
-    fn test_try_panic_message_owned_str() {
-        match thread::spawn(move|| {
-            panic!("owned string".to_string());
-        }).join() {
-            Err(e) => {
-                type T = String;
-                assert!(e.is::<T>());
-                assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
-            }
-            Ok(()) => panic!()
-        }
-    }
-
-    #[test]
-    fn test_try_panic_message_any() {
-        match thread::spawn(move|| {
-            panic!(box 413u16 as Box<Any + Send>);
-        }).join() {
-            Err(e) => {
-                type T = Box<Any + Send>;
-                assert!(e.is::<T>());
-                let any = e.downcast::<T>().unwrap();
-                assert!(any.is::<u16>());
-                assert_eq!(*any.downcast::<u16>().unwrap(), 413);
-            }
-            Ok(()) => panic!()
-        }
-    }
-
-    #[test]
-    fn test_try_panic_message_unit_struct() {
-        struct Juju;
-
-        match thread::spawn(move|| {
-            panic!(Juju)
-        }).join() {
-            Err(ref e) if e.is::<Juju>() => {}
-            Err(_) | Ok(()) => panic!()
-        }
-    }
-
-    #[test]
-    fn test_park_timeout_unpark_before() {
-        for _ in 0..10 {
-            thread::current().unpark();
-            thread::park_timeout(Duration::seconds(10_000_000));
-        }
-    }
-
-    #[test]
-    fn test_park_timeout_unpark_not_called() {
-        for _ in 0..10 {
-            thread::park_timeout(Duration::milliseconds(10));
-        }
-    }
-
-    #[test]
-    fn test_park_timeout_unpark_called_other_thread() {
-        use std::old_io;
-
-        for _ in 0..10 {
-            let th = thread::current();
-
-            let _guard = thread::spawn(move || {
-                old_io::timer::sleep(Duration::milliseconds(50));
-                th.unpark();
-            });
-
-            thread::park_timeout(Duration::seconds(10_000_000));
-        }
-    }
-
-    #[test]
-    fn sleep_smoke() {
-        thread::sleep(Duration::milliseconds(2));
-        thread::sleep(Duration::milliseconds(-2));
-    }
-
-    // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
-    // to the test harness apparently interfering with stderr configuration.
-}
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
new file mode 100644 (file)
index 0000000..1bf1b09
--- /dev/null
@@ -0,0 +1,733 @@
+// Copyright 2014-2015 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.
+
+//! Thread local storage
+
+#![unstable(feature = "thread_local_internals")]
+
+use prelude::v1::*;
+
+use cell::UnsafeCell;
+
+// Sure wish we had macro hygiene, no?
+#[doc(hidden)]
+#[unstable(feature = "thread_local_internals")]
+pub mod __impl {
+    pub use super::imp::Key as KeyInner;
+    pub use super::imp::destroy_value;
+    pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER;
+    pub use sys_common::thread_local::StaticKey as OsStaticKey;
+}
+
+/// A thread local storage key which owns its contents.
+///
+/// This key uses the fastest possible implementation available to it for the
+/// target platform. It is instantiated with the `thread_local!` macro and the
+/// primary method is the `with` method.
+///
+/// The `with` method yields a reference to the contained value which cannot be
+/// sent across tasks or escape the given closure.
+///
+/// # Initialization and Destruction
+///
+/// Initialization is dynamically performed on the first call to `with()`
+/// within a thread, and values support destructors which will be run when a
+/// thread exits.
+///
+/// # Examples
+///
+/// ```
+/// use std::cell::RefCell;
+/// use std::thread;
+///
+/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
+///
+/// FOO.with(|f| {
+///     assert_eq!(*f.borrow(), 1);
+///     *f.borrow_mut() = 2;
+/// });
+///
+/// // each thread starts out with the initial value of 1
+/// thread::spawn(move|| {
+///     FOO.with(|f| {
+///         assert_eq!(*f.borrow(), 1);
+///         *f.borrow_mut() = 3;
+///     });
+/// });
+///
+/// // we retain our original value of 2 despite the child thread
+/// FOO.with(|f| {
+///     assert_eq!(*f.borrow(), 2);
+/// });
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct LocalKey<T> {
+    // The key itself may be tagged with #[thread_local], and this `Key` is
+    // stored as a `static`, and it's not valid for a static to reference the
+    // address of another thread_local static. For this reason we kinda wonkily
+    // work around this by generating a shim function which will give us the
+    // address of the inner TLS key at runtime.
+    //
+    // This is trivially devirtualizable by LLVM because we never store anything
+    // to this field and rustc can declare the `static` as constant as well.
+    #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
+    pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
+
+    // initialization routine to invoke to create a value
+    #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
+    pub init: fn() -> T,
+}
+
+/// Declare a new thread local storage key of type `std::thread::LocalKey`.
+#[macro_export]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable]
+macro_rules! thread_local {
+    (static $name:ident: $t:ty = $init:expr) => (
+        static $name: ::std::thread::LocalKey<$t> = {
+            use std::cell::UnsafeCell as __UnsafeCell;
+            use std::thread::__local::__impl::KeyInner as __KeyInner;
+            use std::option::Option as __Option;
+            use std::option::Option::None as __None;
+
+            __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
+                __UnsafeCell { value: __None }
+            });
+            fn __init() -> $t { $init }
+            fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
+                &__KEY
+            }
+            ::std::thread::LocalKey { inner: __getit, init: __init }
+        };
+    );
+    (pub static $name:ident: $t:ty = $init:expr) => (
+        pub static $name: ::std::thread::LocalKey<$t> = {
+            use std::cell::UnsafeCell as __UnsafeCell;
+            use std::thread::__local::__impl::KeyInner as __KeyInner;
+            use std::option::Option as __Option;
+            use std::option::Option::None as __None;
+
+            __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
+                __UnsafeCell { value: __None }
+            });
+            fn __init() -> $t { $init }
+            fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
+                &__KEY
+            }
+            ::std::thread::LocalKey { inner: __getit, init: __init }
+        };
+    );
+}
+
+// Macro pain #4586:
+//
+// When cross compiling, rustc will load plugins and macros from the *host*
+// platform before search for macros from the target platform. This is primarily
+// done to detect, for example, plugins. Ideally the macro below would be
+// defined once per module below, but unfortunately this means we have the
+// following situation:
+//
+// 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro
+//    will inject #[thread_local] statics.
+// 2. We then try to compile a program for arm-linux-androideabi
+// 3. The compiler has a host of linux and a target of android, so it loads
+//    macros from the *linux* libstd.
+// 4. The macro generates a #[thread_local] field, but the android libstd does
+//    not use #[thread_local]
+// 5. Compile error about structs with wrong fields.
+//
+// To get around this, we're forced to inject the #[cfg] logic into the macro
+// itself. Woohoo.
+
+#[macro_export]
+#[doc(hidden)]
+#[allow_internal_unstable]
+macro_rules! __thread_local_inner {
+    (static $name:ident: $t:ty = $init:expr) => (
+        #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
+                       not(target_arch = "aarch64")),
+                   thread_local)]
+        static $name: ::std::thread::__local::__impl::KeyInner<$t> =
+            __thread_local_inner!($init, $t);
+    );
+    (pub static $name:ident: $t:ty = $init:expr) => (
+        #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
+                       not(target_arch = "aarch64")),
+                   thread_local)]
+        pub static $name: ::std::thread::__local::__impl::KeyInner<$t> =
+            __thread_local_inner!($init, $t);
+    );
+    ($init:expr, $t:ty) => ({
+        #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
+        const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
+            ::std::thread::__local::__impl::KeyInner {
+                inner: ::std::cell::UnsafeCell { value: $init },
+                dtor_registered: ::std::cell::UnsafeCell { value: false },
+                dtor_running: ::std::cell::UnsafeCell { value: false },
+            }
+        };
+
+        #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
+        const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
+            ::std::thread::__local::__impl::KeyInner {
+                inner: ::std::cell::UnsafeCell { value: $init },
+                os: ::std::thread::__local::__impl::OsStaticKey {
+                    inner: ::std::thread::__local::__impl::OS_INIT_INNER,
+                    dtor: ::std::option::Option::Some(
+                        ::std::thread::__local::__impl::destroy_value::<$t>
+                    ),
+                },
+            }
+        };
+
+        _INIT
+    });
+}
+
+/// Indicator of the state of a thread local storage key.
+#[unstable(feature = "std_misc",
+           reason = "state querying was recently added")]
+#[derive(Eq, PartialEq, Copy)]
+pub enum LocalKeyState {
+    /// All keys are in this state whenever a thread starts. Keys will
+    /// transition to the `Valid` state once the first call to `with` happens
+    /// and the initialization expression succeeds.
+    ///
+    /// Keys in the `Uninitialized` state will yield a reference to the closure
+    /// passed to `with` so long as the initialization routine does not panic.
+    Uninitialized,
+
+    /// Once a key has been accessed successfully, it will enter the `Valid`
+    /// state. Keys in the `Valid` state will remain so until the thread exits,
+    /// at which point the destructor will be run and the key will enter the
+    /// `Destroyed` state.
+    ///
+    /// Keys in the `Valid` state will be guaranteed to yield a reference to the
+    /// closure passed to `with`.
+    Valid,
+
+    /// When a thread exits, the destructors for keys will be run (if
+    /// necessary). While a destructor is running, and possibly after a
+    /// destructor has run, a key is in the `Destroyed` state.
+    ///
+    /// Keys in the `Destroyed` states will trigger a panic when accessed via
+    /// `with`.
+    Destroyed,
+}
+
+impl<T: 'static> LocalKey<T> {
+    /// Acquire a reference to the value in this TLS key.
+    ///
+    /// This will lazily initialize the value if this thread has not referenced
+    /// this key yet.
+    ///
+    /// # Panics
+    ///
+    /// This function will `panic!()` if the key currently has its
+    /// destructor running, and it **may** panic if the destructor has
+    /// previously been run for this thread.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with<F, R>(&'static self, f: F) -> R
+                      where F: FnOnce(&T) -> R {
+        let slot = (self.inner)();
+        unsafe {
+            let slot = slot.get().expect("cannot access a TLS value during or \
+                                          after it is destroyed");
+            f(match *slot.get() {
+                Some(ref inner) => inner,
+                None => self.init(slot),
+            })
+        }
+    }
+
+    unsafe fn init(&self, slot: &UnsafeCell<Option<T>>) -> &T {
+        // Execute the initialization up front, *then* move it into our slot,
+        // just in case initialization fails.
+        let value = (self.init)();
+        let ptr = slot.get();
+        *ptr = Some(value);
+        (*ptr).as_ref().unwrap()
+    }
+
+    /// Query the current state of this key.
+    ///
+    /// A key is initially in the `Uninitialized` state whenever a thread
+    /// starts. It will remain in this state up until the first call to `with`
+    /// within a thread has run the initialization expression successfully.
+    ///
+    /// Once the initialization expression succeeds, the key transitions to the
+    /// `Valid` state which will guarantee that future calls to `with` will
+    /// succeed within the thread.
+    ///
+    /// When a thread exits, each key will be destroyed in turn, and as keys are
+    /// destroyed they will enter the `Destroyed` state just before the
+    /// destructor starts to run. Keys may remain in the `Destroyed` state after
+    /// destruction has completed. Keys without destructors (e.g. with types
+    /// that are `Copy`), may never enter the `Destroyed` state.
+    ///
+    /// Keys in the `Uninitialized` can be accessed so long as the
+    /// initialization does not panic. Keys in the `Valid` state are guaranteed
+    /// to be able to be accessed. Keys in the `Destroyed` state will panic on
+    /// any call to `with`.
+    #[unstable(feature = "std_misc",
+               reason = "state querying was recently added")]
+    pub fn state(&'static self) -> LocalKeyState {
+        unsafe {
+            match (self.inner)().get() {
+                Some(cell) => {
+                    match *cell.get() {
+                        Some(..) => LocalKeyState::Valid,
+                        None => LocalKeyState::Uninitialized,
+                    }
+                }
+                None => LocalKeyState::Destroyed,
+            }
+        }
+    }
+
+    /// Deprecated
+    #[unstable(feature = "std_misc")]
+    #[deprecated(since = "1.0.0",
+                 reason = "function renamed to state() and returns more info")]
+    pub fn destroyed(&'static self) -> bool { self.state() == LocalKeyState::Destroyed }
+}
+
+#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
+mod imp {
+    use prelude::v1::*;
+
+    use cell::UnsafeCell;
+    use intrinsics;
+    use ptr;
+
+    #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
+    pub struct Key<T> {
+        // Place the inner bits in an `UnsafeCell` to currently get around the
+        // "only Sync statics" restriction. This allows any type to be placed in
+        // the cell.
+        //
+        // Note that all access requires `T: 'static` so it can't be a type with
+        // any borrowed pointers still.
+        #[unstable(feature = "thread_local_internals")]
+        pub inner: UnsafeCell<T>,
+
+        // Metadata to keep track of the state of the destructor. Remember that
+        // these variables are thread-local, not global.
+        #[unstable(feature = "thread_local_internals")]
+        pub dtor_registered: UnsafeCell<bool>, // should be Cell
+        #[unstable(feature = "thread_local_internals")]
+        pub dtor_running: UnsafeCell<bool>, // should be Cell
+    }
+
+    unsafe impl<T> ::marker::Sync for Key<T> { }
+
+    #[doc(hidden)]
+    impl<T> Key<T> {
+        pub unsafe fn get(&'static self) -> Option<&'static T> {
+            if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
+                return None
+            }
+            self.register_dtor();
+            Some(&*self.inner.get())
+        }
+
+        unsafe fn register_dtor(&self) {
+            if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
+                return
+            }
+
+            register_dtor(self as *const _ as *mut u8,
+                          destroy_value::<T>);
+            *self.dtor_registered.get() = true;
+        }
+    }
+
+    // Since what appears to be glibc 2.18 this symbol has been shipped which
+    // GCC and clang both use to invoke destructors in thread_local globals, so
+    // let's do the same!
+    //
+    // Note, however, that we run on lots older linuxes, as well as cross
+    // compiling from a newer linux to an older linux, so we also have a
+    // fallback implementation to use as well.
+    //
+    // Due to rust-lang/rust#18804, make sure this is not generic!
+    #[cfg(target_os = "linux")]
+    unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+        use boxed;
+        use mem;
+        use libc;
+        use sys_common::thread_local as os;
+
+        extern {
+            static __dso_handle: *mut u8;
+            #[linkage = "extern_weak"]
+            static __cxa_thread_atexit_impl: *const ();
+        }
+        if !__cxa_thread_atexit_impl.is_null() {
+            type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
+                                      arg: *mut u8,
+                                      dso_handle: *mut u8) -> libc::c_int;
+            mem::transmute::<*const (), F>(__cxa_thread_atexit_impl)
+            (dtor, t, __dso_handle);
+            return
+        }
+
+        // The fallback implementation uses a vanilla OS-based TLS key to track
+        // the list of destructors that need to be run for this thread. The key
+        // then has its own destructor which runs all the other destructors.
+        //
+        // The destructor for DTORS is a little special in that it has a `while`
+        // loop to continuously drain the list of registered destructors. It
+        // *should* be the case that this loop always terminates because we
+        // provide the guarantee that a TLS key cannot be set after it is
+        // flagged for destruction.
+        static DTORS: os::StaticKey = os::StaticKey {
+            inner: os::INIT_INNER,
+            dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)),
+        };
+        type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+        if DTORS.get().is_null() {
+            let v: Box<List> = box Vec::new();
+            DTORS.set(boxed::into_raw(v) as *mut u8);
+        }
+        let list: &mut List = &mut *(DTORS.get() as *mut List);
+        list.push((t, dtor));
+
+        unsafe extern fn run_dtors(mut ptr: *mut u8) {
+            while !ptr.is_null() {
+                let list: Box<List> = Box::from_raw(ptr as *mut List);
+                for &(ptr, dtor) in &*list {
+                    dtor(ptr);
+                }
+                ptr = DTORS.get();
+                DTORS.set(ptr::null_mut());
+            }
+        }
+    }
+
+    // OSX's analog of the above linux function is this _tlv_atexit function.
+    // The disassembly of thread_local globals in C++ (at least produced by
+    // clang) will have this show up in the output.
+    #[cfg(target_os = "macos")]
+    unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+        extern {
+            fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
+                           arg: *mut u8);
+        }
+        _tlv_atexit(dtor, t);
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
+    pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
+        let ptr = ptr as *mut Key<T>;
+        // Right before we run the user destructor be sure to flag the
+        // destructor as running for this thread so calls to `get` will return
+        // `None`.
+        *(*ptr).dtor_running.get() = true;
+        ptr::read((*ptr).inner.get());
+    }
+}
+
+#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
+mod imp {
+    use prelude::v1::*;
+
+    use alloc::boxed;
+    use cell::UnsafeCell;
+    use mem;
+    use ptr;
+    use sys_common::thread_local::StaticKey as OsStaticKey;
+
+    #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
+    pub struct Key<T> {
+        // Statically allocated initialization expression, using an `UnsafeCell`
+        // for the same reasons as above.
+        #[unstable(feature = "thread_local_internals")]
+        pub inner: UnsafeCell<T>,
+
+        // OS-TLS key that we'll use to key off.
+        #[unstable(feature = "thread_local_internals")]
+        pub os: OsStaticKey,
+    }
+
+    unsafe impl<T> ::marker::Sync for Key<T> { }
+
+    struct Value<T: 'static> {
+        key: &'static Key<T>,
+        value: T,
+    }
+
+    #[doc(hidden)]
+    impl<T> Key<T> {
+        pub unsafe fn get(&'static self) -> Option<&'static T> {
+            self.ptr().map(|p| &*p)
+        }
+
+        unsafe fn ptr(&'static self) -> Option<*mut T> {
+            let ptr = self.os.get() as *mut Value<T>;
+            if !ptr.is_null() {
+                if ptr as usize == 1 {
+                    return None
+                }
+                return Some(&mut (*ptr).value as *mut T);
+            }
+
+            // If the lookup returned null, we haven't initialized our own local
+            // copy, so do that now.
+            //
+            // Also note that this transmute_copy should be ok because the value
+            // `inner` is already validated to be a valid `static` value, so we
+            // should be able to freely copy the bits.
+            let ptr: Box<Value<T>> = box Value {
+                key: self,
+                value: mem::transmute_copy(&self.inner),
+            };
+            let ptr: *mut Value<T> = boxed::into_raw(ptr);
+            self.os.set(ptr as *mut u8);
+            Some(&mut (*ptr).value as *mut T)
+        }
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
+    pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
+        // The OS TLS ensures that this key contains a NULL value when this
+        // destructor starts to run. We set it back to a sentinel value of 1 to
+        // ensure that any future calls to `get` for this thread will return
+        // `None`.
+        //
+        // Note that to prevent an infinite loop we reset it back to null right
+        // before we return from the destructor ourselves.
+        let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
+        let key = ptr.key;
+        key.os.set(1 as *mut u8);
+        drop(ptr);
+        key.os.set(ptr::null_mut());
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+
+    use sync::mpsc::{channel, Sender};
+    use cell::UnsafeCell;
+    use super::LocalKeyState;
+    use thread;
+
+    struct Foo(Sender<()>);
+
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            let Foo(ref s) = *self;
+            s.send(()).unwrap();
+        }
+    }
+
+    #[test]
+    fn smoke_no_dtor() {
+        thread_local!(static FOO: UnsafeCell<i32> = UnsafeCell { value: 1 });
+
+        FOO.with(|f| unsafe {
+            assert_eq!(*f.get(), 1);
+            *f.get() = 2;
+        });
+        let (tx, rx) = channel();
+        let _t = thread::spawn(move|| {
+            FOO.with(|f| unsafe {
+                assert_eq!(*f.get(), 1);
+            });
+            tx.send(()).unwrap();
+        });
+        rx.recv().unwrap();
+
+        FOO.with(|f| unsafe {
+            assert_eq!(*f.get(), 2);
+        });
+    }
+
+    #[test]
+    fn states() {
+        struct Foo;
+        impl Drop for Foo {
+            fn drop(&mut self) {
+                assert!(FOO.state() == LocalKeyState::Destroyed);
+            }
+        }
+        fn foo() -> Foo {
+            assert!(FOO.state() == LocalKeyState::Uninitialized);
+            Foo
+        }
+        thread_local!(static FOO: Foo = foo());
+
+        thread::spawn(|| {
+            assert!(FOO.state() == LocalKeyState::Uninitialized);
+            FOO.with(|_| {
+                assert!(FOO.state() == LocalKeyState::Valid);
+            });
+            assert!(FOO.state() == LocalKeyState::Valid);
+        }).join().ok().unwrap();
+    }
+
+    #[test]
+    fn smoke_dtor() {
+        thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell {
+            value: None
+        });
+
+        let (tx, rx) = channel();
+        let _t = thread::spawn(move|| unsafe {
+            let mut tx = Some(tx);
+            FOO.with(|f| {
+                *f.get() = Some(Foo(tx.take().unwrap()));
+            });
+        });
+        rx.recv().unwrap();
+    }
+
+    #[test]
+    fn circular() {
+        struct S1;
+        struct S2;
+        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
+            value: None
+        });
+        thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell {
+            value: None
+        });
+        static mut HITS: u32 = 0;
+
+        impl Drop for S1 {
+            fn drop(&mut self) {
+                unsafe {
+                    HITS += 1;
+                    if K2.state() == LocalKeyState::Destroyed {
+                        assert_eq!(HITS, 3);
+                    } else {
+                        if HITS == 1 {
+                            K2.with(|s| *s.get() = Some(S2));
+                        } else {
+                            assert_eq!(HITS, 3);
+                        }
+                    }
+                }
+            }
+        }
+        impl Drop for S2 {
+            fn drop(&mut self) {
+                unsafe {
+                    HITS += 1;
+                    assert!(K1.state() != LocalKeyState::Destroyed);
+                    assert_eq!(HITS, 2);
+                    K1.with(|s| *s.get() = Some(S1));
+                }
+            }
+        }
+
+        thread::spawn(move|| {
+            drop(S1);
+        }).join().ok().unwrap();
+    }
+
+    #[test]
+    fn self_referential() {
+        struct S1;
+        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
+            value: None
+        });
+
+        impl Drop for S1 {
+            fn drop(&mut self) {
+                assert!(K1.state() == LocalKeyState::Destroyed);
+            }
+        }
+
+        thread::spawn(move|| unsafe {
+            K1.with(|s| *s.get() = Some(S1));
+        }).join().ok().unwrap();
+    }
+
+    #[test]
+    fn dtors_in_dtors_in_dtors() {
+        struct S1(Sender<()>);
+        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
+            value: None
+        });
+        thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell {
+            value: None
+        });
+
+        impl Drop for S1 {
+            fn drop(&mut self) {
+                let S1(ref tx) = *self;
+                unsafe {
+                    if K2.state() != LocalKeyState::Destroyed {
+                        K2.with(|s| *s.get() = Some(Foo(tx.clone())));
+                    }
+                }
+            }
+        }
+
+        let (tx, rx) = channel();
+        let _t = thread::spawn(move|| unsafe {
+            let mut tx = Some(tx);
+            K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
+        });
+        rx.recv().unwrap();
+    }
+}
+
+#[cfg(test)]
+mod dynamic_tests {
+    use prelude::v1::*;
+
+    use cell::RefCell;
+    use collections::HashMap;
+
+    #[test]
+    fn smoke() {
+        fn square(i: i32) -> i32 { i * i }
+        thread_local!(static FOO: i32 = square(3));
+
+        FOO.with(|f| {
+            assert_eq!(*f, 9);
+        });
+    }
+
+    #[test]
+    fn hashmap() {
+        fn map() -> RefCell<HashMap<i32, i32>> {
+            let mut m = HashMap::new();
+            m.insert(1, 2);
+            RefCell::new(m)
+        }
+        thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
+
+        FOO.with(|map| {
+            assert_eq!(map.borrow()[&1], 2);
+        });
+    }
+
+    #[test]
+    fn refcell_vec() {
+        thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
+
+        FOO.with(|vec| {
+            assert_eq!(vec.borrow().len(), 3);
+            vec.borrow_mut().push(4);
+            assert_eq!(vec.borrow()[3], 4);
+        });
+    }
+}
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
new file mode 100644 (file)
index 0000000..57baeb1
--- /dev/null
@@ -0,0 +1,1026 @@
+// Copyright 2014 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.
+
+//! Native threads
+//!
+//! ## The threading model
+//!
+//! An executing Rust program consists of a collection of native OS threads,
+//! each with their own stack and local state.
+//!
+//! Communication between threads can be done through
+//! [channels](../../std/sync/mpsc/index.html), Rust's message-passing
+//! types, along with [other forms of thread
+//! synchronization](../../std/sync/index.html) and shared-memory data
+//! structures. In particular, types that are guaranteed to be
+//! threadsafe are easily shared between threads using the
+//! atomically-reference-counted container,
+//! [`Arc`](../../std/sync/struct.Arc.html).
+//!
+//! Fatal logic errors in Rust cause *thread panic*, during which
+//! a thread will unwind the stack, running destructors and freeing
+//! owned resources. Thread panic is unrecoverable from within
+//! the panicking thread (i.e. there is no 'try/catch' in Rust), but
+//! the panic may optionally be detected from a different thread. If
+//! the main thread panics, the application will exit with a non-zero
+//! exit code.
+//!
+//! When the main thread of a Rust program terminates, the entire program shuts
+//! down, even if other threads are still running. However, this module provides
+//! convenient facilities for automatically waiting for the termination of a
+//! child thread (i.e., join).
+//!
+//! ## The `Thread` type
+//!
+//! Threads are represented via the `Thread` type, which you can
+//! get in one of two ways:
+//!
+//! * By spawning a new thread, e.g. using the `thread::spawn` function.
+//! * By requesting the current thread, using the `thread::current` function.
+//!
+//! Threads can be named, and provide some built-in support for low-level
+//! synchronization (described below).
+//!
+//! The `thread::current()` function is available even for threads not spawned
+//! by the APIs of this module.
+//!
+//! ## Spawning a thread
+//!
+//! A new thread can be spawned using the `thread::spawn` function:
+//!
+//! ```rust
+//! use std::thread;
+//!
+//! thread::spawn(move || {
+//!     // some work here
+//! });
+//! ```
+//!
+//! In this example, the spawned thread is "detached" from the current
+//! thread. This means that it can outlive its parent (the thread that spawned
+//! it), unless this parent is the main thread.
+//!
+//! ## Scoped threads
+//!
+//! Often a parent thread uses a child thread to perform some particular task,
+//! and at some point must wait for the child to complete before continuing.
+//! For this scenario, use the `thread::scoped` function:
+//!
+//! ```rust
+//! use std::thread;
+//!
+//! let guard = thread::scoped(move || {
+//!     // some work here
+//! });
+//!
+//! // do some other work in the meantime
+//! let output = guard.join();
+//! ```
+//!
+//! The `scoped` function doesn't return a `Thread` directly; instead,
+//! it returns a *join guard*. The join guard is an RAII-style guard
+//! that will automatically join the child thread (block until it
+//! terminates) when it is dropped. You can join the child thread in
+//! advance by calling the `join` method on the guard, which will also
+//! return the result produced by the thread.  A handle to the thread
+//! itself is available via the `thread` method of the join guard.
+//!
+//! ## Configuring threads
+//!
+//! A new thread can be configured before it is spawned via the `Builder` type,
+//! which currently allows you to set the name, stack size, and writers for
+//! `println!` and `panic!` for the child thread:
+//!
+//! ```rust
+//! use std::thread;
+//!
+//! thread::Builder::new().name("child1".to_string()).spawn(move || {
+//!     println!("Hello, world!");
+//! });
+//! ```
+//!
+//! ## Blocking support: park and unpark
+//!
+//! Every thread is equipped with some basic low-level blocking support, via the
+//! `park` and `unpark` functions.
+//!
+//! Conceptually, each `Thread` handle has an associated token, which is
+//! initially not present:
+//!
+//! * The `thread::park()` function blocks the current thread unless or until
+//!   the token is available for its thread handle, at which point it atomically
+//!   consumes the token. It may also return *spuriously*, without consuming the
+//!   token. `thread::park_timeout()` does the same, but allows specifying a
+//!   maximum time to block the thread for.
+//!
+//! * The `unpark()` method on a `Thread` atomically makes the token available
+//!   if it wasn't already.
+//!
+//! In other words, each `Thread` acts a bit like a semaphore with initial count
+//! 0, except that the semaphore is *saturating* (the count cannot go above 1),
+//! and can return spuriously.
+//!
+//! The API is typically used by acquiring a handle to the current thread,
+//! placing that handle in a shared data structure so that other threads can
+//! find it, and then `park`ing. When some desired condition is met, another
+//! thread calls `unpark` on the handle.
+//!
+//! The motivation for this design is twofold:
+//!
+//! * It avoids the need to allocate mutexes and condvars when building new
+//!   synchronization primitives; the threads already provide basic blocking/signaling.
+//!
+//! * It can be implemented very efficiently on many platforms.
+//!
+//! ## Thread-local storage
+//!
+//! This module also provides an implementation of thread local storage for Rust
+//! programs. Thread local storage is a method of storing data into a global
+//! variable which each thread in the program will have its own copy of.
+//! Threads do not share this data, so accesses do not need to be synchronized.
+//!
+//! At a high level, this module provides two variants of storage:
+//!
+//! * Owned thread-local storage. This is a type of thread local key which
+//!   owns the value that it contains, and will destroy the value when the
+//!   thread exits. This variant is created with the `thread_local!` macro and
+//!   can contain any value which is `'static` (no borrowed pointers).
+//!
+//! * Scoped thread-local storage. This type of key is used to store a reference
+//!   to a value into local storage temporarily for the scope of a function
+//!   call. There are no restrictions on what types of values can be placed
+//!   into this key.
+//!
+//! Both forms of thread local storage provide an accessor function, `with`,
+//! which will yield a shared reference to the value to the specified
+//! closure. Thread-local keys only allow shared access to values as there is no
+//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
+//! will want to make use of some form of **interior mutability** through the
+//! `Cell` or `RefCell` types.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::__local::{LocalKey, LocalKeyState};
+
+#[unstable(feature = "scoped_tls",
+            reason = "scoped TLS has yet to have wide enough use to fully consider \
+                      stabilizing its interface")]
+pub use self::__scoped::ScopedKey;
+
+use prelude::v1::*;
+
+use any::Any;
+use cell::UnsafeCell;
+use fmt;
+use io;
+use marker::PhantomData;
+use rt::{self, unwind};
+use sync::{Mutex, Condvar, Arc};
+use sys::thread as imp;
+use sys_common::{stack, thread_info};
+use thunk::Thunk;
+use time::Duration;
+
+#[allow(deprecated)] use old_io::Writer;
+
+////////////////////////////////////////////////////////////////////////////////
+// Thread-local storage
+////////////////////////////////////////////////////////////////////////////////
+
+#[macro_use]
+#[doc(hidden)]
+#[path = "local.rs"] pub mod __local;
+
+#[macro_use]
+#[doc(hidden)]
+#[path = "scoped.rs"] pub mod __scoped;
+
+////////////////////////////////////////////////////////////////////////////////
+// Builder
+////////////////////////////////////////////////////////////////////////////////
+
+/// Thread configuration. Provides detailed control over the properties
+/// and behavior of new threads.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Builder {
+    // A name for the thread-to-be, for identification in panic messages
+    name: Option<String>,
+    // The size of the stack for the spawned thread
+    stack_size: Option<usize>,
+}
+
+impl Builder {
+    /// Generate the base configuration for spawning a thread, from which
+    /// configuration methods can be chained.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new() -> Builder {
+        Builder {
+            name: None,
+            stack_size: None,
+        }
+    }
+
+    /// Name the thread-to-be. Currently the name is used for identification
+    /// only in panic messages.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn name(mut self, name: String) -> Builder {
+        self.name = Some(name);
+        self
+    }
+
+    /// Set the size of the stack for the new thread.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn stack_size(mut self, size: usize) -> Builder {
+        self.stack_size = Some(size);
+        self
+    }
+
+    /// Redirect thread-local stdout.
+    #[unstable(feature = "std_misc",
+               reason = "Will likely go away after proc removal")]
+    #[deprecated(since = "1.0.0",
+                 reason = "the old I/O module is deprecated and this function \
+                           will be removed with no replacement")]
+    #[allow(deprecated)]
+    pub fn stdout(self, _stdout: Box<Writer + Send + 'static>) -> Builder {
+        self
+    }
+
+    /// Redirect thread-local stderr.
+    #[unstable(feature = "std_misc",
+               reason = "Will likely go away after proc removal")]
+    #[deprecated(since = "1.0.0",
+                 reason = "the old I/O module is deprecated and this function \
+                           will be removed with no replacement")]
+    #[allow(deprecated)]
+    pub fn stderr(self, _stderr: Box<Writer + Send + 'static>) -> Builder {
+        self
+    }
+
+    /// Spawn a new thread, and return a join handle for it.
+    ///
+    /// The child thread may outlive the parent (unless the parent thread
+    /// is the main thread; the whole process is terminated when the main
+    /// thread finishes.) The join handle can be used to block on
+    /// termination of the child thread, including recovering its panics.
+    ///
+    /// # Errors
+    ///
+    /// Unlike the `spawn` free function, this method yields an
+    /// `io::Result` to capture any failure to create the thread at
+    /// the OS level.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn spawn<F>(self, f: F) -> io::Result<JoinHandle> where
+        F: FnOnce(), F: Send + 'static
+    {
+        self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i))
+    }
+
+    /// Spawn a new child thread that must be joined within a given
+    /// scope, and return a `JoinGuard`.
+    ///
+    /// The join guard can be used to explicitly join the child thread (via
+    /// `join`), returning `Result<T>`, or it will implicitly join the child
+    /// upon being dropped. Because the child thread may refer to data on the
+    /// current thread's stack (hence the "scoped" name), it cannot be detached;
+    /// it *must* be joined before the relevant stack frame is popped. See the
+    /// module documentation for additional details.
+    ///
+    /// # Errors
+    ///
+    /// Unlike the `scoped` free function, this method yields an
+    /// `io::Result` to capture any failure to create the thread at
+    /// the OS level.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
+        T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
+    {
+        self.spawn_inner(Thunk::new(f)).map(|inner| {
+            JoinGuard { inner: inner, _marker: PhantomData }
+        })
+    }
+
+    fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
+        let Builder { name, stack_size } = self;
+
+        let stack_size = stack_size.unwrap_or(rt::min_stack());
+
+        let my_thread = Thread::new(name);
+        let their_thread = my_thread.clone();
+
+        let my_packet = Packet(Arc::new(UnsafeCell::new(None)));
+        let their_packet = Packet(my_packet.0.clone());
+
+        // Spawning a new OS thread guarantees that __morestack will never get
+        // triggered, but we must manually set up the actual stack bounds once
+        // this function starts executing. This raises the lower limit by a bit
+        // because by the time that this function is executing we've already
+        // consumed at least a little bit of stack (we don't know the exact byte
+        // address at which our stack started).
+        let main = move || {
+            let something_around_the_top_of_the_stack = 1;
+            let addr = &something_around_the_top_of_the_stack as *const i32;
+            let my_stack_top = addr as usize;
+            let my_stack_bottom = my_stack_top - stack_size + 1024;
+            unsafe {
+                if let Some(name) = their_thread.name() {
+                    imp::set_name(name);
+                }
+                stack::record_os_managed_stack_bounds(my_stack_bottom,
+                                                      my_stack_top);
+                thread_info::set(imp::guard::current(), their_thread);
+            }
+
+            let mut output = None;
+            let try_result = {
+                let ptr = &mut output;
+
+                // There are two primary reasons that general try/catch is
+                // unsafe. The first is that we do not support nested
+                // try/catch. The fact that this is happening in a newly-spawned
+                // thread suffices. The second is that unwinding while unwinding
+                // is not defined.  We take care of that by having an
+                // 'unwinding' flag in the thread itself. For these reasons,
+                // this unsafety should be ok.
+                unsafe {
+                    unwind::try(move || *ptr = Some(f.invoke(())))
+                }
+            };
+            unsafe {
+                *their_packet.0.get() = Some(match (output, try_result) {
+                    (Some(data), Ok(_)) => Ok(data),
+                    (None, Err(cause)) => Err(cause),
+                    _ => unreachable!()
+                });
+            }
+        };
+
+        Ok(JoinInner {
+            native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }),
+            thread: my_thread,
+            packet: my_packet,
+            joined: false,
+        })
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Free functions
+////////////////////////////////////////////////////////////////////////////////
+
+/// Spawn a new thread, returning a `JoinHandle` for it.
+///
+/// The join handle will implicitly *detach* the child thread upon being
+/// dropped. In this case, the child thread may outlive the parent (unless
+/// the parent thread is the main thread; the whole process is terminated when
+/// the main thread finishes.) Additionally, the join handle provides a `join`
+/// method that can be used to join the child thread. If the child thread
+/// panics, `join` will return an `Err` containing the argument given to
+/// `panic`.
+///
+/// # Panics
+///
+/// Panicks if the OS fails to create a thread; use `Builder::spawn`
+/// to recover from such errors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
+    Builder::new().spawn(f).unwrap()
+}
+
+/// Spawn a new *scoped* thread, returning a `JoinGuard` for it.
+///
+/// The join guard can be used to explicitly join the child thread (via
+/// `join`), returning `Result<T>`, or it will implicitly join the child
+/// upon being dropped. Because the child thread may refer to data on the
+/// current thread's stack (hence the "scoped" name), it cannot be detached;
+/// it *must* be joined before the relevant stack frame is popped. See the
+/// module documentation for additional details.
+///
+/// # Panics
+///
+/// Panicks if the OS fails to create a thread; use `Builder::scoped`
+/// to recover from such errors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
+    T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
+{
+    Builder::new().scoped(f).unwrap()
+}
+
+/// Gets a handle to the thread that invokes it.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn current() -> Thread {
+    thread_info::current_thread()
+}
+
+/// Cooperatively give up a timeslice to the OS scheduler.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn yield_now() {
+    unsafe { imp::yield_now() }
+}
+
+/// Determines whether the current thread is unwinding because of panic.
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn panicking() -> bool {
+    unwind::panicking()
+}
+
+/// Put the current thread to sleep for the specified amount of time.
+///
+/// The thread may sleep longer than the duration specified due to scheduling
+/// specifics or platform-dependent functionality. Note that on unix platforms
+/// this function will not return early due to a signal being received or a
+/// spurious wakeup.
+#[unstable(feature = "thread_sleep",
+           reason = "recently added, needs an RFC, and `Duration` itself is \
+                     unstable")]
+pub fn sleep(dur: Duration) {
+    imp::sleep(dur)
+}
+
+/// Block unless or until the current thread's token is made available (may wake spuriously).
+///
+/// See the module doc for more detail.
+//
+// The implementation currently uses the trivial strategy of a Mutex+Condvar
+// with wakeup flag, which does not actually allow spurious wakeups. In the
+// future, this will be implemented in a more efficient way, perhaps along the lines of
+//   http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
+// or futuxes, and in either case may allow spurious wakeups.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn park() {
+    let thread = current();
+    let mut guard = thread.inner.lock.lock().unwrap();
+    while !*guard {
+        guard = thread.inner.cvar.wait(guard).unwrap();
+    }
+    *guard = false;
+}
+
+/// Block unless or until the current thread's token is made available or
+/// the specified duration has been reached (may wake spuriously).
+///
+/// The semantics of this function are equivalent to `park()` except that the
+/// thread will be blocked for roughly no longer than *duration*. This method
+/// should not be used for precise timing due to anomalies such as
+/// preemption or platform differences that may not cause the maximum
+/// amount of time waited to be precisely *duration* long.
+///
+/// See the module doc for more detail.
+#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")]
+pub fn park_timeout(duration: Duration) {
+    let thread = current();
+    let mut guard = thread.inner.lock.lock().unwrap();
+    if !*guard {
+        let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap();
+        guard = g;
+    }
+    *guard = false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Thread
+////////////////////////////////////////////////////////////////////////////////
+
+/// The internal representation of a `Thread` handle
+struct Inner {
+    name: Option<String>,
+    lock: Mutex<bool>,          // true when there is a buffered unpark
+    cvar: Condvar,
+}
+
+unsafe impl Sync for Inner {}
+
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+/// A handle to a thread.
+pub struct Thread {
+    inner: Arc<Inner>,
+}
+
+impl Thread {
+    // Used only internally to construct a thread object without spawning
+    fn new(name: Option<String>) -> Thread {
+        Thread {
+            inner: Arc::new(Inner {
+                name: name,
+                lock: Mutex::new(false),
+                cvar: Condvar::new(),
+            })
+        }
+    }
+
+    /// Deprecated: use module-level free function.
+    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
+    #[unstable(feature = "std_misc",
+               reason = "may change with specifics of new Send semantics")]
+    pub fn spawn<F>(f: F) -> Thread where F: FnOnce(), F: Send + 'static {
+        Builder::new().spawn(f).unwrap().thread().clone()
+    }
+
+    /// Deprecated: use module-level free function.
+    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
+    #[unstable(feature = "std_misc",
+               reason = "may change with specifics of new Send semantics")]
+    pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
+        T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
+    {
+        Builder::new().scoped(f).unwrap()
+    }
+
+    /// Deprecated: use module-level free function.
+    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn current() -> Thread {
+        thread_info::current_thread()
+    }
+
+    /// Deprecated: use module-level free function.
+    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
+    #[unstable(feature = "std_misc", reason = "name may change")]
+    pub fn yield_now() {
+        unsafe { imp::yield_now() }
+    }
+
+    /// Deprecated: use module-level free function.
+    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn panicking() -> bool {
+        unwind::panicking()
+    }
+
+    /// Deprecated: use module-level free function.
+    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
+    #[unstable(feature = "std_misc", reason = "recently introduced")]
+    pub fn park() {
+        let thread = current();
+        let mut guard = thread.inner.lock.lock().unwrap();
+        while !*guard {
+            guard = thread.inner.cvar.wait(guard).unwrap();
+        }
+        *guard = false;
+    }
+
+    /// Deprecated: use module-level free function.
+    #[deprecated(since = "1.0.0", reason = "use module-level free function")]
+    #[unstable(feature = "std_misc", reason = "recently introduced")]
+    pub fn park_timeout(duration: Duration) {
+        let thread = current();
+        let mut guard = thread.inner.lock.lock().unwrap();
+        if !*guard {
+            let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap();
+            guard = g;
+        }
+        *guard = false;
+    }
+
+    /// Atomically makes the handle's token available if it is not already.
+    ///
+    /// See the module doc for more detail.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn unpark(&self) {
+        let mut guard = self.inner.lock.lock().unwrap();
+        if !*guard {
+            *guard = true;
+            self.inner.cvar.notify_one();
+        }
+    }
+
+    /// Get the thread's name.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn name(&self) -> Option<&str> {
+        self.inner.name.as_ref().map(|s| &**s)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Thread {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.name(), f)
+    }
+}
+
+// a hack to get around privacy restrictions
+impl thread_info::NewThread for Thread {
+    fn new(name: Option<String>) -> Thread { Thread::new(name) }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// JoinHandle and JoinGuard
+////////////////////////////////////////////////////////////////////////////////
+
+/// Indicates the manner in which a thread exited.
+///
+/// A thread that completes without panicking is considered to exit successfully.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>;
+
+struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
+
+unsafe impl<T:Send> Send for Packet<T> {}
+unsafe impl<T> Sync for Packet<T> {}
+
+/// Inner representation for JoinHandle and JoinGuard
+struct JoinInner<T> {
+    native: imp::rust_thread,
+    thread: Thread,
+    packet: Packet<T>,
+    joined: bool,
+}
+
+impl<T> JoinInner<T> {
+    fn join(&mut self) -> Result<T> {
+        assert!(!self.joined);
+        unsafe { imp::join(self.native) };
+        self.joined = true;
+        unsafe {
+            (*self.packet.0.get()).take().unwrap()
+        }
+    }
+}
+
+/// An owned permission to join on a thread (block on its termination).
+///
+/// Unlike a `JoinGuard`, a `JoinHandle` *detaches* the child thread
+/// when it is dropped, rather than automatically joining on drop.
+///
+/// Due to platform restrictions, it is not possible to `Clone` this
+/// handle: the ability to join a child thread is a uniquely-owned
+/// permission.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct JoinHandle(JoinInner<()>);
+
+impl JoinHandle {
+    /// Extract a handle to the underlying thread
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn thread(&self) -> &Thread {
+        &self.0.thread
+    }
+
+    /// Wait for the associated thread to finish.
+    ///
+    /// If the child thread panics, `Err` is returned with the parameter given
+    /// to `panic`.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn join(mut self) -> Result<()> {
+        self.0.join()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Drop for JoinHandle {
+    fn drop(&mut self) {
+        if !self.0.joined {
+            unsafe { imp::detach(self.0.native) }
+        }
+    }
+}
+
+/// An RAII-style guard that will block until thread termination when dropped.
+///
+/// The type `T` is the return type for the thread's main function.
+///
+/// Joining on drop is necessary to ensure memory safety when stack
+/// data is shared between a parent and child thread.
+///
+/// Due to platform restrictions, it is not possible to `Clone` this
+/// handle: the ability to join a child thread is a uniquely-owned
+/// permission.
+#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct JoinGuard<'a, T: 'a> {
+    inner: JoinInner<T>,
+    _marker: PhantomData<&'a T>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {}
+
+impl<'a, T: Send + 'a> JoinGuard<'a, T> {
+    /// Extract a handle to the thread this guard will join on.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn thread(&self) -> &Thread {
+        &self.inner.thread
+    }
+
+    /// Wait for the associated thread to finish, returning the result of the thread's
+    /// calculation.
+    ///
+    /// # Panics
+    ///
+    /// Panics on the child thread are propagated by panicking the parent.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn join(mut self) -> T {
+        match self.inner.join() {
+            Ok(res) => res,
+            Err(_) => panic!("child thread {:?} panicked", self.thread()),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Send> JoinGuard<'static, T> {
+    /// Detaches the child thread, allowing it to outlive its parent.
+    #[deprecated(since = "1.0.0", reason = "use spawn instead")]
+    #[unstable(feature = "std_misc")]
+    pub fn detach(mut self) {
+        unsafe { imp::detach(self.inner.native) };
+        self.inner.joined = true; // avoid joining in the destructor
+    }
+}
+
+#[unsafe_destructor]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
+    fn drop(&mut self) {
+        if !self.inner.joined {
+            if self.inner.join().is_err() {
+                panic!("child thread {:?} panicked", self.thread());
+            }
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests
+////////////////////////////////////////////////////////////////////////////////
+
+#[cfg(test)]
+mod test {
+    use prelude::v1::*;
+
+    use any::Any;
+    use sync::mpsc::{channel, Sender};
+    use boxed::BoxAny;
+    use result;
+    use std::old_io::{ChanReader, ChanWriter};
+    use super::{Builder};
+    use thread;
+    use thunk::Thunk;
+    use time::Duration;
+
+    // !!! These tests are dangerous. If something is buggy, they will hang, !!!
+    // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
+
+    #[test]
+    fn test_unnamed_thread() {
+        thread::spawn(move|| {
+            assert!(thread::current().name().is_none());
+        }).join().ok().unwrap();
+    }
+
+    #[test]
+    fn test_named_thread() {
+        Builder::new().name("ada lovelace".to_string()).scoped(move|| {
+            assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
+        }).unwrap().join();
+    }
+
+    #[test]
+    fn test_run_basic() {
+        let (tx, rx) = channel();
+        thread::spawn(move|| {
+            tx.send(()).unwrap();
+        });
+        rx.recv().unwrap();
+    }
+
+    #[test]
+    fn test_join_success() {
+        assert!(thread::scoped(move|| -> String {
+            "Success!".to_string()
+        }).join() == "Success!");
+    }
+
+    #[test]
+    fn test_join_panic() {
+        match thread::spawn(move|| {
+            panic!()
+        }).join() {
+            result::Result::Err(_) => (),
+            result::Result::Ok(()) => panic!()
+        }
+    }
+
+    #[test]
+    fn test_scoped_success() {
+        let res = thread::scoped(move|| -> String {
+            "Success!".to_string()
+        }).join();
+        assert!(res == "Success!");
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_scoped_panic() {
+        thread::scoped(|| panic!()).join();
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_scoped_implicit_panic() {
+        let _ = thread::scoped(|| panic!());
+    }
+
+    #[test]
+    fn test_spawn_sched() {
+        use clone::Clone;
+
+        let (tx, rx) = channel();
+
+        fn f(i: i32, tx: Sender<()>) {
+            let tx = tx.clone();
+            thread::spawn(move|| {
+                if i == 0 {
+                    tx.send(()).unwrap();
+                } else {
+                    f(i - 1, tx);
+                }
+            });
+
+        }
+        f(10, tx);
+        rx.recv().unwrap();
+    }
+
+    #[test]
+    fn test_spawn_sched_childs_on_default_sched() {
+        let (tx, rx) = channel();
+
+        thread::spawn(move|| {
+            thread::spawn(move|| {
+                tx.send(()).unwrap();
+            });
+        });
+
+        rx.recv().unwrap();
+    }
+
+    fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Thunk<'static>) {
+        let (tx, rx) = channel();
+
+        let x: Box<_> = box 1;
+        let x_in_parent = (&*x) as *const i32 as usize;
+
+        spawnfn(Thunk::new(move|| {
+            let x_in_child = (&*x) as *const i32 as usize;
+            tx.send(x_in_child).unwrap();
+        }));
+
+        let x_in_child = rx.recv().unwrap();
+        assert_eq!(x_in_parent, x_in_child);
+    }
+
+    #[test]
+    fn test_avoid_copying_the_body_spawn() {
+        avoid_copying_the_body(|v| {
+            thread::spawn(move || v.invoke(()));
+        });
+    }
+
+    #[test]
+    fn test_avoid_copying_the_body_thread_spawn() {
+        avoid_copying_the_body(|f| {
+            thread::spawn(move|| {
+                f.invoke(());
+            });
+        })
+    }
+
+    #[test]
+    fn test_avoid_copying_the_body_join() {
+        avoid_copying_the_body(|f| {
+            let _ = thread::spawn(move|| {
+                f.invoke(())
+            }).join();
+        })
+    }
+
+    #[test]
+    fn test_child_doesnt_ref_parent() {
+        // If the child refcounts the parent task, this will stack overflow when
+        // climbing the task tree to dereference each ancestor. (See #1789)
+        // (well, it would if the constant were 8000+ - I lowered it to be more
+        // valgrind-friendly. try this at home, instead..!)
+        const GENERATIONS: u32 = 16;
+        fn child_no(x: u32) -> Thunk<'static> {
+            return Thunk::new(move|| {
+                if x < GENERATIONS {
+                    thread::spawn(move|| child_no(x+1).invoke(()));
+                }
+            });
+        }
+        thread::spawn(|| child_no(0).invoke(()));
+    }
+
+    #[test]
+    fn test_simple_newsched_spawn() {
+        thread::spawn(move || {});
+    }
+
+    #[test]
+    fn test_try_panic_message_static_str() {
+        match thread::spawn(move|| {
+            panic!("static string");
+        }).join() {
+            Err(e) => {
+                type T = &'static str;
+                assert!(e.is::<T>());
+                assert_eq!(*e.downcast::<T>().unwrap(), "static string");
+            }
+            Ok(()) => panic!()
+        }
+    }
+
+    #[test]
+    fn test_try_panic_message_owned_str() {
+        match thread::spawn(move|| {
+            panic!("owned string".to_string());
+        }).join() {
+            Err(e) => {
+                type T = String;
+                assert!(e.is::<T>());
+                assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
+            }
+            Ok(()) => panic!()
+        }
+    }
+
+    #[test]
+    fn test_try_panic_message_any() {
+        match thread::spawn(move|| {
+            panic!(box 413u16 as Box<Any + Send>);
+        }).join() {
+            Err(e) => {
+                type T = Box<Any + Send>;
+                assert!(e.is::<T>());
+                let any = e.downcast::<T>().unwrap();
+                assert!(any.is::<u16>());
+                assert_eq!(*any.downcast::<u16>().unwrap(), 413);
+            }
+            Ok(()) => panic!()
+        }
+    }
+
+    #[test]
+    fn test_try_panic_message_unit_struct() {
+        struct Juju;
+
+        match thread::spawn(move|| {
+            panic!(Juju)
+        }).join() {
+            Err(ref e) if e.is::<Juju>() => {}
+            Err(_) | Ok(()) => panic!()
+        }
+    }
+
+    #[test]
+    fn test_park_timeout_unpark_before() {
+        for _ in 0..10 {
+            thread::current().unpark();
+            thread::park_timeout(Duration::seconds(10_000_000));
+        }
+    }
+
+    #[test]
+    fn test_park_timeout_unpark_not_called() {
+        for _ in 0..10 {
+            thread::park_timeout(Duration::milliseconds(10));
+        }
+    }
+
+    #[test]
+    fn test_park_timeout_unpark_called_other_thread() {
+        use std::old_io;
+
+        for _ in 0..10 {
+            let th = thread::current();
+
+            let _guard = thread::spawn(move || {
+                old_io::timer::sleep(Duration::milliseconds(50));
+                th.unpark();
+            });
+
+            thread::park_timeout(Duration::seconds(10_000_000));
+        }
+    }
+
+    #[test]
+    fn sleep_smoke() {
+        thread::sleep(Duration::milliseconds(2));
+        thread::sleep(Duration::milliseconds(-2));
+    }
+
+    // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
+    // to the test harness apparently interfering with stderr configuration.
+}
diff --git a/src/libstd/thread/scoped.rs b/src/libstd/thread/scoped.rs
new file mode 100644 (file)
index 0000000..2a8be2a
--- /dev/null
@@ -0,0 +1,317 @@
+// Copyright 2014-2015 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.
+
+//! Scoped thread-local storage
+//!
+//! This module provides the ability to generate *scoped* thread-local
+//! variables. In this sense, scoped indicates that thread local storage
+//! actually stores a reference to a value, and this reference is only placed
+//! in storage for a scoped amount of time.
+//!
+//! There are no restrictions on what types can be placed into a scoped
+//! variable, but all scoped variables are initialized to the equivalent of
+//! null. Scoped thread local storage is useful when a value is present for a known
+//! period of time and it is not required to relinquish ownership of the
+//! contents.
+//!
+//! # Examples
+//!
+//! ```
+//! scoped_thread_local!(static FOO: u32);
+//!
+//! // Initially each scoped slot is empty.
+//! assert!(!FOO.is_set());
+//!
+//! // When inserting a value, the value is only in place for the duration
+//! // of the closure specified.
+//! FOO.set(&1, || {
+//!     FOO.with(|slot| {
+//!         assert_eq!(*slot, 1);
+//!     });
+//! });
+//! ```
+
+#![unstable(feature = "thread_local_internals")]
+
+use prelude::v1::*;
+
+// macro hygiene sure would be nice, wouldn't it?
+#[doc(hidden)]
+pub mod __impl {
+    pub use super::imp::KeyInner;
+    pub use sys_common::thread_local::INIT as OS_INIT;
+}
+
+/// Type representing a thread local storage key corresponding to a reference
+/// to the type parameter `T`.
+///
+/// Keys are statically allocated and can contain a reference to an instance of
+/// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
+/// and `with`, both of which currently use closures to control the scope of
+/// their contents.
+#[unstable(feature = "scoped_tls",
+           reason = "scoped TLS has yet to have wide enough use to fully consider \
+                     stabilizing its interface")]
+pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
+
+/// Declare a new scoped thread local storage key.
+///
+/// This macro declares a `static` item on which methods are used to get and
+/// set the value stored within.
+#[macro_export]
+#[allow_internal_unstable]
+macro_rules! scoped_thread_local {
+    (static $name:ident: $t:ty) => (
+        __scoped_thread_local_inner!(static $name: $t);
+    );
+    (pub static $name:ident: $t:ty) => (
+        __scoped_thread_local_inner!(pub static $name: $t);
+    );
+}
+
+#[macro_export]
+#[doc(hidden)]
+#[allow_internal_unstable]
+macro_rules! __scoped_thread_local_inner {
+    (static $name:ident: $t:ty) => (
+        #[cfg_attr(not(any(windows,
+                           target_os = "android",
+                           target_os = "ios",
+                           target_os = "openbsd",
+                           target_arch = "aarch64")),
+                   thread_local)]
+        static $name: ::std::thread::ScopedKey<$t> =
+            __scoped_thread_local_inner!($t);
+    );
+    (pub static $name:ident: $t:ty) => (
+        #[cfg_attr(not(any(windows,
+                           target_os = "android",
+                           target_os = "ios",
+                           target_os = "openbsd",
+                           target_arch = "aarch64")),
+                   thread_local)]
+        pub static $name: ::std::thread::ScopedKey<$t> =
+            __scoped_thread_local_inner!($t);
+    );
+    ($t:ty) => ({
+        use std::thread::ScopedKey as __Key;
+
+        #[cfg(not(any(windows,
+                      target_os = "android",
+                      target_os = "ios",
+                      target_os = "openbsd",
+                      target_arch = "aarch64")))]
+        const _INIT: __Key<$t> = __Key {
+            inner: ::std::thread::__scoped::__impl::KeyInner {
+                inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
+            }
+        };
+
+        #[cfg(any(windows,
+                  target_os = "android",
+                  target_os = "ios",
+                  target_os = "openbsd",
+                  target_arch = "aarch64"))]
+        const _INIT: __Key<$t> = __Key {
+            inner: ::std::thread::__scoped::__impl::KeyInner {
+                inner: ::std::thread::__scoped::__impl::OS_INIT,
+                marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
+            }
+        };
+
+        _INIT
+    })
+}
+
+#[unstable(feature = "scoped_tls",
+           reason = "scoped TLS has yet to have wide enough use to fully consider \
+                     stabilizing its interface")]
+impl<T> ScopedKey<T> {
+    /// Insert a value into this scoped thread local storage slot for a
+    /// duration of a closure.
+    ///
+    /// While `cb` is running, the value `t` will be returned by `get` unless
+    /// this function is called recursively inside of `cb`.
+    ///
+    /// Upon return, this function will restore the previous value, if any
+    /// was available.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// scoped_thread_local!(static FOO: u32);
+    ///
+    /// FOO.set(&100, || {
+    ///     let val = FOO.with(|v| *v);
+    ///     assert_eq!(val, 100);
+    ///
+    ///     // set can be called recursively
+    ///     FOO.set(&101, || {
+    ///         // ...
+    ///     });
+    ///
+    ///     // Recursive calls restore the previous value.
+    ///     let val = FOO.with(|v| *v);
+    ///     assert_eq!(val, 100);
+    /// });
+    /// ```
+    pub fn set<R, F>(&'static self, t: &T, cb: F) -> R where
+        F: FnOnce() -> R,
+    {
+        struct Reset<'a, T: 'a> {
+            key: &'a __impl::KeyInner<T>,
+            val: *mut T,
+        }
+        #[unsafe_destructor]
+        impl<'a, T> Drop for Reset<'a, T> {
+            fn drop(&mut self) {
+                unsafe { self.key.set(self.val) }
+            }
+        }
+
+        let prev = unsafe {
+            let prev = self.inner.get();
+            self.inner.set(t as *const T as *mut T);
+            prev
+        };
+
+        let _reset = Reset { key: &self.inner, val: prev };
+        cb()
+    }
+
+    /// Get a value out of this scoped variable.
+    ///
+    /// This function takes a closure which receives the value of this
+    /// variable.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if `set` has not previously been called.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// scoped_thread_local!(static FOO: u32);
+    ///
+    /// FOO.with(|slot| {
+    ///     // work with `slot`
+    /// });
+    /// ```
+    pub fn with<R, F>(&'static self, cb: F) -> R where
+        F: FnOnce(&T) -> R
+    {
+        unsafe {
+            let ptr = self.inner.get();
+            assert!(!ptr.is_null(), "cannot access a scoped thread local \
+                                     variable without calling `set` first");
+            cb(&*ptr)
+        }
+    }
+
+    /// Test whether this TLS key has been `set` for the current thread.
+    pub fn is_set(&'static self) -> bool {
+        unsafe { !self.inner.get().is_null() }
+    }
+}
+
+#[cfg(not(any(windows,
+              target_os = "android",
+              target_os = "ios",
+              target_os = "openbsd",
+              target_arch = "aarch64")))]
+mod imp {
+    use std::cell::UnsafeCell;
+
+    #[doc(hidden)]
+    pub struct KeyInner<T> { pub inner: UnsafeCell<*mut T> }
+
+    unsafe impl<T> ::marker::Sync for KeyInner<T> { }
+
+    #[doc(hidden)]
+    impl<T> KeyInner<T> {
+        #[doc(hidden)]
+        pub unsafe fn set(&self, ptr: *mut T) { *self.inner.get() = ptr; }
+        #[doc(hidden)]
+        pub unsafe fn get(&self) -> *mut T { *self.inner.get() }
+    }
+}
+
+#[cfg(any(windows,
+          target_os = "android",
+          target_os = "ios",
+          target_os = "openbsd",
+          target_arch = "aarch64"))]
+mod imp {
+    use marker;
+    use std::cell::Cell;
+    use sys_common::thread_local::StaticKey as OsStaticKey;
+
+    #[doc(hidden)]
+    pub struct KeyInner<T> {
+        pub inner: OsStaticKey,
+        pub marker: marker::PhantomData<Cell<T>>,
+    }
+
+    unsafe impl<T> ::marker::Sync for KeyInner<T> { }
+
+    #[doc(hidden)]
+    impl<T> KeyInner<T> {
+        #[doc(hidden)]
+        pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr as *mut _) }
+        #[doc(hidden)]
+        pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ }
+    }
+}
+
+
+#[cfg(test)]
+mod tests {
+    use cell::Cell;
+    use prelude::v1::*;
+
+    scoped_thread_local!(static FOO: u32);
+
+    #[test]
+    fn smoke() {
+        scoped_thread_local!(static BAR: u32);
+
+        assert!(!BAR.is_set());
+        BAR.set(&1, || {
+            assert!(BAR.is_set());
+            BAR.with(|slot| {
+                assert_eq!(*slot, 1);
+            });
+        });
+        assert!(!BAR.is_set());
+    }
+
+    #[test]
+    fn cell_allowed() {
+        scoped_thread_local!(static BAR: Cell<u32>);
+
+        BAR.set(&Cell::new(1), || {
+            BAR.with(|slot| {
+                assert_eq!(slot.get(), 1);
+            });
+        });
+    }
+
+    #[test]
+    fn scope_item_allowed() {
+        assert!(!FOO.is_set());
+        FOO.set(&1, || {
+            assert!(FOO.is_set());
+            FOO.with(|slot| {
+                assert_eq!(*slot, 1);
+            });
+        });
+        assert!(!FOO.is_set());
+    }
+}
diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs
deleted file mode 100644 (file)
index 0878029..0000000
+++ /dev/null
@@ -1,762 +0,0 @@
-// Copyright 2014-2015 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.
-
-//! Thread local storage
-//!
-//! This module provides an implementation of thread local storage for Rust
-//! programs. Thread local storage is a method of storing data into a global
-//! variable which each thread in the program will have its own copy of.
-//! Threads do not share this data, so accesses do not need to be synchronized.
-//!
-//! At a high level, this module provides two variants of storage:
-//!
-//! * Owning thread local storage. This is a type of thread local key which
-//!   owns the value that it contains, and will destroy the value when the
-//!   thread exits. This variant is created with the `thread_local!` macro and
-//!   can contain any value which is `'static` (no borrowed pointers.
-//!
-//! * Scoped thread local storage. This type of key is used to store a reference
-//!   to a value into local storage temporarily for the scope of a function
-//!   call. There are no restrictions on what types of values can be placed
-//!   into this key.
-//!
-//! Both forms of thread local storage provide an accessor function, `with`,
-//! which will yield a shared reference to the value to the specified
-//! closure. Thread local keys only allow shared access to values as there is no
-//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
-//! will want to make use of some form of **interior mutability** through the
-//! `Cell` or `RefCell` types.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use prelude::v1::*;
-
-use cell::UnsafeCell;
-
-#[macro_use]
-pub mod scoped;
-
-// Sure wish we had macro hygiene, no?
-#[doc(hidden)]
-#[unstable(feature = "thread_local_internals")]
-pub mod __impl {
-    pub use super::imp::Key as KeyInner;
-    pub use super::imp::destroy_value;
-    pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER;
-    pub use sys_common::thread_local::StaticKey as OsStaticKey;
-}
-
-/// A thread local storage key which owns its contents.
-///
-/// This key uses the fastest possible implementation available to it for the
-/// target platform. It is instantiated with the `thread_local!` macro and the
-/// primary method is the `with` method.
-///
-/// The `with` method yields a reference to the contained value which cannot be
-/// sent across tasks or escape the given closure.
-///
-/// # Initialization and Destruction
-///
-/// Initialization is dynamically performed on the first call to `with()`
-/// within a thread, and values support destructors which will be run when a
-/// thread exits.
-///
-/// # Examples
-///
-/// ```
-/// use std::cell::RefCell;
-/// use std::thread;
-///
-/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
-///
-/// FOO.with(|f| {
-///     assert_eq!(*f.borrow(), 1);
-///     *f.borrow_mut() = 2;
-/// });
-///
-/// // each thread starts out with the initial value of 1
-/// thread::spawn(move|| {
-///     FOO.with(|f| {
-///         assert_eq!(*f.borrow(), 1);
-///         *f.borrow_mut() = 3;
-///     });
-/// });
-///
-/// // we retain our original value of 2 despite the child thread
-/// FOO.with(|f| {
-///     assert_eq!(*f.borrow(), 2);
-/// });
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Key<T> {
-    // The key itself may be tagged with #[thread_local], and this `Key` is
-    // stored as a `static`, and it's not valid for a static to reference the
-    // address of another thread_local static. For this reason we kinda wonkily
-    // work around this by generating a shim function which will give us the
-    // address of the inner TLS key at runtime.
-    //
-    // This is trivially devirtualizable by LLVM because we never store anything
-    // to this field and rustc can declare the `static` as constant as well.
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
-    pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
-
-    // initialization routine to invoke to create a value
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
-    pub init: fn() -> T,
-}
-
-/// Declare a new thread local storage key of type `std::thread_local::Key`.
-#[macro_export]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable]
-macro_rules! thread_local {
-    (static $name:ident: $t:ty = $init:expr) => (
-        static $name: ::std::thread_local::Key<$t> = {
-            use std::cell::UnsafeCell as __UnsafeCell;
-            use std::thread_local::__impl::KeyInner as __KeyInner;
-            use std::option::Option as __Option;
-            use std::option::Option::None as __None;
-
-            __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
-                __UnsafeCell { value: __None }
-            });
-            fn __init() -> $t { $init }
-            fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
-                &__KEY
-            }
-            ::std::thread_local::Key { inner: __getit, init: __init }
-        };
-    );
-    (pub static $name:ident: $t:ty = $init:expr) => (
-        pub static $name: ::std::thread_local::Key<$t> = {
-            use std::cell::UnsafeCell as __UnsafeCell;
-            use std::thread_local::__impl::KeyInner as __KeyInner;
-            use std::option::Option as __Option;
-            use std::option::Option::None as __None;
-
-            __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
-                __UnsafeCell { value: __None }
-            });
-            fn __init() -> $t { $init }
-            fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
-                &__KEY
-            }
-            ::std::thread_local::Key { inner: __getit, init: __init }
-        };
-    );
-}
-
-// Macro pain #4586:
-//
-// When cross compiling, rustc will load plugins and macros from the *host*
-// platform before search for macros from the target platform. This is primarily
-// done to detect, for example, plugins. Ideally the macro below would be
-// defined once per module below, but unfortunately this means we have the
-// following situation:
-//
-// 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro
-//    will inject #[thread_local] statics.
-// 2. We then try to compile a program for arm-linux-androideabi
-// 3. The compiler has a host of linux and a target of android, so it loads
-//    macros from the *linux* libstd.
-// 4. The macro generates a #[thread_local] field, but the android libstd does
-//    not use #[thread_local]
-// 5. Compile error about structs with wrong fields.
-//
-// To get around this, we're forced to inject the #[cfg] logic into the macro
-// itself. Woohoo.
-
-#[macro_export]
-#[doc(hidden)]
-#[allow_internal_unstable]
-macro_rules! __thread_local_inner {
-    (static $name:ident: $t:ty = $init:expr) => (
-        #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
-                       not(target_arch = "aarch64")),
-                   thread_local)]
-        static $name: ::std::thread_local::__impl::KeyInner<$t> =
-            __thread_local_inner!($init, $t);
-    );
-    (pub static $name:ident: $t:ty = $init:expr) => (
-        #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
-                       not(target_arch = "aarch64")),
-                   thread_local)]
-        pub static $name: ::std::thread_local::__impl::KeyInner<$t> =
-            __thread_local_inner!($init, $t);
-    );
-    ($init:expr, $t:ty) => ({
-        #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
-        const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
-            ::std::thread_local::__impl::KeyInner {
-                inner: ::std::cell::UnsafeCell { value: $init },
-                dtor_registered: ::std::cell::UnsafeCell { value: false },
-                dtor_running: ::std::cell::UnsafeCell { value: false },
-            }
-        };
-
-        #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
-        const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
-            unsafe extern fn __destroy(ptr: *mut u8) {
-                ::std::thread_local::__impl::destroy_value::<$t>(ptr);
-            }
-
-            ::std::thread_local::__impl::KeyInner {
-                inner: ::std::cell::UnsafeCell { value: $init },
-                os: ::std::thread_local::__impl::OsStaticKey {
-                    inner: ::std::thread_local::__impl::OS_INIT_INNER,
-                    dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
-                },
-            }
-        };
-
-        _INIT
-    });
-}
-
-/// Indicator of the state of a thread local storage key.
-#[unstable(feature = "std_misc",
-           reason = "state querying was recently added")]
-#[derive(Eq, PartialEq, Copy)]
-pub enum State {
-    /// All keys are in this state whenever a thread starts. Keys will
-    /// transition to the `Valid` state once the first call to `with` happens
-    /// and the initialization expression succeeds.
-    ///
-    /// Keys in the `Uninitialized` state will yield a reference to the closure
-    /// passed to `with` so long as the initialization routine does not panic.
-    Uninitialized,
-
-    /// Once a key has been accessed successfully, it will enter the `Valid`
-    /// state. Keys in the `Valid` state will remain so until the thread exits,
-    /// at which point the destructor will be run and the key will enter the
-    /// `Destroyed` state.
-    ///
-    /// Keys in the `Valid` state will be guaranteed to yield a reference to the
-    /// closure passed to `with`.
-    Valid,
-
-    /// When a thread exits, the destructors for keys will be run (if
-    /// necessary). While a destructor is running, and possibly after a
-    /// destructor has run, a key is in the `Destroyed` state.
-    ///
-    /// Keys in the `Destroyed` states will trigger a panic when accessed via
-    /// `with`.
-    Destroyed,
-}
-
-impl<T: 'static> Key<T> {
-    /// Acquire a reference to the value in this TLS key.
-    ///
-    /// This will lazily initialize the value if this thread has not referenced
-    /// this key yet.
-    ///
-    /// # Panics
-    ///
-    /// This function will `panic!()` if the key currently has its
-    /// destructor running, and it **may** panic if the destructor has
-    /// previously been run for this thread.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with<F, R>(&'static self, f: F) -> R
-                      where F: FnOnce(&T) -> R {
-        let slot = (self.inner)();
-        unsafe {
-            let slot = slot.get().expect("cannot access a TLS value during or \
-                                          after it is destroyed");
-            f(match *slot.get() {
-                Some(ref inner) => inner,
-                None => self.init(slot),
-            })
-        }
-    }
-
-    unsafe fn init(&self, slot: &UnsafeCell<Option<T>>) -> &T {
-        // Execute the initialization up front, *then* move it into our slot,
-        // just in case initialization fails.
-        let value = (self.init)();
-        let ptr = slot.get();
-        *ptr = Some(value);
-        (*ptr).as_ref().unwrap()
-    }
-
-    /// Query the current state of this key.
-    ///
-    /// A key is initially in the `Uninitialized` state whenever a thread
-    /// starts. It will remain in this state up until the first call to `with`
-    /// within a thread has run the initialization expression successfully.
-    ///
-    /// Once the initialization expression succeeds, the key transitions to the
-    /// `Valid` state which will guarantee that future calls to `with` will
-    /// succeed within the thread.
-    ///
-    /// When a thread exits, each key will be destroyed in turn, and as keys are
-    /// destroyed they will enter the `Destroyed` state just before the
-    /// destructor starts to run. Keys may remain in the `Destroyed` state after
-    /// destruction has completed. Keys without destructors (e.g. with types
-    /// that are `Copy`), may never enter the `Destroyed` state.
-    ///
-    /// Keys in the `Uninitialized` can be accessed so long as the
-    /// initialization does not panic. Keys in the `Valid` state are guaranteed
-    /// to be able to be accessed. Keys in the `Destroyed` state will panic on
-    /// any call to `with`.
-    #[unstable(feature = "std_misc",
-               reason = "state querying was recently added")]
-    pub fn state(&'static self) -> State {
-        unsafe {
-            match (self.inner)().get() {
-                Some(cell) => {
-                    match *cell.get() {
-                        Some(..) => State::Valid,
-                        None => State::Uninitialized,
-                    }
-                }
-                None => State::Destroyed,
-            }
-        }
-    }
-
-    /// Deprecated
-    #[unstable(feature = "std_misc")]
-    #[deprecated(since = "1.0.0",
-                 reason = "function renamed to state() and returns more info")]
-    pub fn destroyed(&'static self) -> bool { self.state() == State::Destroyed }
-}
-
-#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
-mod imp {
-    use prelude::v1::*;
-
-    use cell::UnsafeCell;
-    use intrinsics;
-    use ptr;
-
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
-    pub struct Key<T> {
-        // Place the inner bits in an `UnsafeCell` to currently get around the
-        // "only Sync statics" restriction. This allows any type to be placed in
-        // the cell.
-        //
-        // Note that all access requires `T: 'static` so it can't be a type with
-        // any borrowed pointers still.
-        #[unstable(feature = "thread_local_internals")]
-        pub inner: UnsafeCell<T>,
-
-        // Metadata to keep track of the state of the destructor. Remember that
-        // these variables are thread-local, not global.
-        #[unstable(feature = "thread_local_internals")]
-        pub dtor_registered: UnsafeCell<bool>, // should be Cell
-        #[unstable(feature = "thread_local_internals")]
-        pub dtor_running: UnsafeCell<bool>, // should be Cell
-    }
-
-    unsafe impl<T> ::marker::Sync for Key<T> { }
-
-    #[doc(hidden)]
-    impl<T> Key<T> {
-        pub unsafe fn get(&'static self) -> Option<&'static T> {
-            if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
-                return None
-            }
-            self.register_dtor();
-            Some(&*self.inner.get())
-        }
-
-        unsafe fn register_dtor(&self) {
-            if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
-                return
-            }
-
-            register_dtor(self as *const _ as *mut u8,
-                          destroy_value::<T>);
-            *self.dtor_registered.get() = true;
-        }
-    }
-
-    // Since what appears to be glibc 2.18 this symbol has been shipped which
-    // GCC and clang both use to invoke destructors in thread_local globals, so
-    // let's do the same!
-    //
-    // Note, however, that we run on lots older linuxes, as well as cross
-    // compiling from a newer linux to an older linux, so we also have a
-    // fallback implementation to use as well.
-    //
-    // Due to rust-lang/rust#18804, make sure this is not generic!
-    #[cfg(target_os = "linux")]
-    unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        use boxed;
-        use mem;
-        use libc;
-        use sys_common::thread_local as os;
-
-        extern {
-            static __dso_handle: *mut u8;
-            #[linkage = "extern_weak"]
-            static __cxa_thread_atexit_impl: *const ();
-        }
-        if !__cxa_thread_atexit_impl.is_null() {
-            type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
-                                      arg: *mut u8,
-                                      dso_handle: *mut u8) -> libc::c_int;
-            mem::transmute::<*const (), F>(__cxa_thread_atexit_impl)
-            (dtor, t, __dso_handle);
-            return
-        }
-
-        // The fallback implementation uses a vanilla OS-based TLS key to track
-        // the list of destructors that need to be run for this thread. The key
-        // then has its own destructor which runs all the other destructors.
-        //
-        // The destructor for DTORS is a little special in that it has a `while`
-        // loop to continuously drain the list of registered destructors. It
-        // *should* be the case that this loop always terminates because we
-        // provide the guarantee that a TLS key cannot be set after it is
-        // flagged for destruction.
-        static DTORS: os::StaticKey = os::StaticKey {
-            inner: os::INIT_INNER,
-            dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)),
-        };
-        type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
-        if DTORS.get().is_null() {
-            let v: Box<List> = box Vec::new();
-            DTORS.set(boxed::into_raw(v) as *mut u8);
-        }
-        let list: &mut List = &mut *(DTORS.get() as *mut List);
-        list.push((t, dtor));
-
-        unsafe extern fn run_dtors(mut ptr: *mut u8) {
-            while !ptr.is_null() {
-                let list: Box<List> = Box::from_raw(ptr as *mut List);
-                for &(ptr, dtor) in &*list {
-                    dtor(ptr);
-                }
-                ptr = DTORS.get();
-                DTORS.set(ptr::null_mut());
-            }
-        }
-    }
-
-    // OSX's analog of the above linux function is this _tlv_atexit function.
-    // The disassembly of thread_local globals in C++ (at least produced by
-    // clang) will have this show up in the output.
-    #[cfg(target_os = "macos")]
-    unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        extern {
-            fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
-                           arg: *mut u8);
-        }
-        _tlv_atexit(dtor, t);
-    }
-
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
-    pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
-        let ptr = ptr as *mut Key<T>;
-        // Right before we run the user destructor be sure to flag the
-        // destructor as running for this thread so calls to `get` will return
-        // `None`.
-        *(*ptr).dtor_running.get() = true;
-        ptr::read((*ptr).inner.get());
-    }
-}
-
-#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
-mod imp {
-    use prelude::v1::*;
-
-    use alloc::boxed;
-    use cell::UnsafeCell;
-    use mem;
-    use ptr;
-    use sys_common::thread_local::StaticKey as OsStaticKey;
-
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
-    pub struct Key<T> {
-        // Statically allocated initialization expression, using an `UnsafeCell`
-        // for the same reasons as above.
-        #[unstable(feature = "thread_local_internals")]
-        pub inner: UnsafeCell<T>,
-
-        // OS-TLS key that we'll use to key off.
-        #[unstable(feature = "thread_local_internals")]
-        pub os: OsStaticKey,
-    }
-
-    unsafe impl<T> ::marker::Sync for Key<T> { }
-
-    struct Value<T: 'static> {
-        key: &'static Key<T>,
-        value: T,
-    }
-
-    #[doc(hidden)]
-    impl<T> Key<T> {
-        pub unsafe fn get(&'static self) -> Option<&'static T> {
-            self.ptr().map(|p| &*p)
-        }
-
-        unsafe fn ptr(&'static self) -> Option<*mut T> {
-            let ptr = self.os.get() as *mut Value<T>;
-            if !ptr.is_null() {
-                if ptr as usize == 1 {
-                    return None
-                }
-                return Some(&mut (*ptr).value as *mut T);
-            }
-
-            // If the lookup returned null, we haven't initialized our own local
-            // copy, so do that now.
-            //
-            // Also note that this transmute_copy should be ok because the value
-            // `inner` is already validated to be a valid `static` value, so we
-            // should be able to freely copy the bits.
-            let ptr: Box<Value<T>> = box Value {
-                key: self,
-                value: mem::transmute_copy(&self.inner),
-            };
-            let ptr: *mut Value<T> = boxed::into_raw(ptr);
-            self.os.set(ptr as *mut u8);
-            Some(&mut (*ptr).value as *mut T)
-        }
-    }
-
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
-    pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
-        // The OS TLS ensures that this key contains a NULL value when this
-        // destructor starts to run. We set it back to a sentinel value of 1 to
-        // ensure that any future calls to `get` for this thread will return
-        // `None`.
-        //
-        // Note that to prevent an infinite loop we reset it back to null right
-        // before we return from the destructor ourselves.
-        let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
-        let key = ptr.key;
-        key.os.set(1 as *mut u8);
-        drop(ptr);
-        key.os.set(ptr::null_mut());
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use prelude::v1::*;
-
-    use sync::mpsc::{channel, Sender};
-    use cell::UnsafeCell;
-    use super::State;
-    use thread;
-
-    struct Foo(Sender<()>);
-
-    impl Drop for Foo {
-        fn drop(&mut self) {
-            let Foo(ref s) = *self;
-            s.send(()).unwrap();
-        }
-    }
-
-    #[test]
-    fn smoke_no_dtor() {
-        thread_local!(static FOO: UnsafeCell<i32> = UnsafeCell { value: 1 });
-
-        FOO.with(|f| unsafe {
-            assert_eq!(*f.get(), 1);
-            *f.get() = 2;
-        });
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move|| {
-            FOO.with(|f| unsafe {
-                assert_eq!(*f.get(), 1);
-            });
-            tx.send(()).unwrap();
-        });
-        rx.recv().unwrap();
-
-        FOO.with(|f| unsafe {
-            assert_eq!(*f.get(), 2);
-        });
-    }
-
-    #[test]
-    fn states() {
-        struct Foo;
-        impl Drop for Foo {
-            fn drop(&mut self) {
-                assert!(FOO.state() == State::Destroyed);
-            }
-        }
-        fn foo() -> Foo {
-            assert!(FOO.state() == State::Uninitialized);
-            Foo
-        }
-        thread_local!(static FOO: Foo = foo());
-
-        thread::spawn(|| {
-            assert!(FOO.state() == State::Uninitialized);
-            FOO.with(|_| {
-                assert!(FOO.state() == State::Valid);
-            });
-            assert!(FOO.state() == State::Valid);
-        }).join().ok().unwrap();
-    }
-
-    #[test]
-    fn smoke_dtor() {
-        thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell {
-            value: None
-        });
-
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move|| unsafe {
-            let mut tx = Some(tx);
-            FOO.with(|f| {
-                *f.get() = Some(Foo(tx.take().unwrap()));
-            });
-        });
-        rx.recv().unwrap();
-    }
-
-    #[test]
-    fn circular() {
-        struct S1;
-        struct S2;
-        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
-            value: None
-        });
-        thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell {
-            value: None
-        });
-        static mut HITS: u32 = 0;
-
-        impl Drop for S1 {
-            fn drop(&mut self) {
-                unsafe {
-                    HITS += 1;
-                    if K2.state() == State::Destroyed {
-                        assert_eq!(HITS, 3);
-                    } else {
-                        if HITS == 1 {
-                            K2.with(|s| *s.get() = Some(S2));
-                        } else {
-                            assert_eq!(HITS, 3);
-                        }
-                    }
-                }
-            }
-        }
-        impl Drop for S2 {
-            fn drop(&mut self) {
-                unsafe {
-                    HITS += 1;
-                    assert!(K1.state() != State::Destroyed);
-                    assert_eq!(HITS, 2);
-                    K1.with(|s| *s.get() = Some(S1));
-                }
-            }
-        }
-
-        thread::spawn(move|| {
-            drop(S1);
-        }).join().ok().unwrap();
-    }
-
-    #[test]
-    fn self_referential() {
-        struct S1;
-        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
-            value: None
-        });
-
-        impl Drop for S1 {
-            fn drop(&mut self) {
-                assert!(K1.state() == State::Destroyed);
-            }
-        }
-
-        thread::spawn(move|| unsafe {
-            K1.with(|s| *s.get() = Some(S1));
-        }).join().ok().unwrap();
-    }
-
-    #[test]
-    fn dtors_in_dtors_in_dtors() {
-        struct S1(Sender<()>);
-        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
-            value: None
-        });
-        thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell {
-            value: None
-        });
-
-        impl Drop for S1 {
-            fn drop(&mut self) {
-                let S1(ref tx) = *self;
-                unsafe {
-                    if K2.state() != State::Destroyed {
-                        K2.with(|s| *s.get() = Some(Foo(tx.clone())));
-                    }
-                }
-            }
-        }
-
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move|| unsafe {
-            let mut tx = Some(tx);
-            K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
-        });
-        rx.recv().unwrap();
-    }
-}
-
-#[cfg(test)]
-mod dynamic_tests {
-    use prelude::v1::*;
-
-    use cell::RefCell;
-    use collections::HashMap;
-
-    #[test]
-    fn smoke() {
-        fn square(i: i32) -> i32 { i * i }
-        thread_local!(static FOO: i32 = square(3));
-
-        FOO.with(|f| {
-            assert_eq!(*f, 9);
-        });
-    }
-
-    #[test]
-    fn hashmap() {
-        fn map() -> RefCell<HashMap<i32, i32>> {
-            let mut m = HashMap::new();
-            m.insert(1, 2);
-            RefCell::new(m)
-        }
-        thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
-
-        FOO.with(|map| {
-            assert_eq!(map.borrow()[1], 2);
-        });
-    }
-
-    #[test]
-    fn refcell_vec() {
-        thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
-
-        FOO.with(|vec| {
-            assert_eq!(vec.borrow().len(), 3);
-            vec.borrow_mut().push(4);
-            assert_eq!(vec.borrow()[3], 4);
-        });
-    }
-}
diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs
deleted file mode 100644 (file)
index 86e6c05..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright 2014-2015 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.
-
-//! Scoped thread-local storage
-//!
-//! This module provides the ability to generate *scoped* thread-local
-//! variables. In this sense, scoped indicates that thread local storage
-//! actually stores a reference to a value, and this reference is only placed
-//! in storage for a scoped amount of time.
-//!
-//! There are no restrictions on what types can be placed into a scoped
-//! variable, but all scoped variables are initialized to the equivalent of
-//! null. Scoped thread local storage is useful when a value is present for a known
-//! period of time and it is not required to relinquish ownership of the
-//! contents.
-//!
-//! # Examples
-//!
-//! ```
-//! scoped_thread_local!(static FOO: u32);
-//!
-//! // Initially each scoped slot is empty.
-//! assert!(!FOO.is_set());
-//!
-//! // When inserting a value, the value is only in place for the duration
-//! // of the closure specified.
-//! FOO.set(&1, || {
-//!     FOO.with(|slot| {
-//!         assert_eq!(*slot, 1);
-//!     });
-//! });
-//! ```
-
-#![unstable(feature = "std_misc",
-            reason = "scoped TLS has yet to have wide enough use to fully consider \
-                      stabilizing its interface")]
-
-use prelude::v1::*;
-
-// macro hygiene sure would be nice, wouldn't it?
-#[doc(hidden)]
-pub mod __impl {
-    pub use super::imp::KeyInner;
-    pub use sys_common::thread_local::INIT as OS_INIT;
-}
-
-/// Type representing a thread local storage key corresponding to a reference
-/// to the type parameter `T`.
-///
-/// Keys are statically allocated and can contain a reference to an instance of
-/// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
-/// and `with`, both of which currently use closures to control the scope of
-/// their contents.
-pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
-
-/// Declare a new scoped thread local storage key.
-///
-/// This macro declares a `static` item on which methods are used to get and
-/// set the value stored within.
-#[macro_export]
-#[allow_internal_unstable]
-macro_rules! scoped_thread_local {
-    (static $name:ident: $t:ty) => (
-        __scoped_thread_local_inner!(static $name: $t);
-    );
-    (pub static $name:ident: $t:ty) => (
-        __scoped_thread_local_inner!(pub static $name: $t);
-    );
-}
-
-#[macro_export]
-#[doc(hidden)]
-#[allow_internal_unstable]
-macro_rules! __scoped_thread_local_inner {
-    (static $name:ident: $t:ty) => (
-        #[cfg_attr(not(any(windows,
-                           target_os = "android",
-                           target_os = "ios",
-                           target_os = "openbsd",
-                           target_arch = "aarch64")),
-                   thread_local)]
-        static $name: ::std::thread_local::scoped::Key<$t> =
-            __scoped_thread_local_inner!($t);
-    );
-    (pub static $name:ident: $t:ty) => (
-        #[cfg_attr(not(any(windows,
-                           target_os = "android",
-                           target_os = "ios",
-                           target_os = "openbsd",
-                           target_arch = "aarch64")),
-                   thread_local)]
-        pub static $name: ::std::thread_local::scoped::Key<$t> =
-            __scoped_thread_local_inner!($t);
-    );
-    ($t:ty) => ({
-        use std::thread_local::scoped::Key as __Key;
-
-        #[cfg(not(any(windows,
-                      target_os = "android",
-                      target_os = "ios",
-                      target_os = "openbsd",
-                      target_arch = "aarch64")))]
-        const _INIT: __Key<$t> = __Key {
-            inner: ::std::thread_local::scoped::__impl::KeyInner {
-                inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
-            }
-        };
-
-        #[cfg(any(windows,
-                  target_os = "android",
-                  target_os = "ios",
-                  target_os = "openbsd",
-                  target_arch = "aarch64"))]
-        const _INIT: __Key<$t> = __Key {
-            inner: ::std::thread_local::scoped::__impl::KeyInner {
-                inner: ::std::thread_local::scoped::__impl::OS_INIT,
-                marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
-            }
-        };
-
-        _INIT
-    })
-}
-
-impl<T> Key<T> {
-    /// Insert a value into this scoped thread local storage slot for a
-    /// duration of a closure.
-    ///
-    /// While `cb` is running, the value `t` will be returned by `get` unless
-    /// this function is called recursively inside of `cb`.
-    ///
-    /// Upon return, this function will restore the previous value, if any
-    /// was available.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// scoped_thread_local!(static FOO: u32);
-    ///
-    /// FOO.set(&100, || {
-    ///     let val = FOO.with(|v| *v);
-    ///     assert_eq!(val, 100);
-    ///
-    ///     // set can be called recursively
-    ///     FOO.set(&101, || {
-    ///         // ...
-    ///     });
-    ///
-    ///     // Recursive calls restore the previous value.
-    ///     let val = FOO.with(|v| *v);
-    ///     assert_eq!(val, 100);
-    /// });
-    /// ```
-    pub fn set<R, F>(&'static self, t: &T, cb: F) -> R where
-        F: FnOnce() -> R,
-    {
-        struct Reset<'a, T: 'a> {
-            key: &'a __impl::KeyInner<T>,
-            val: *mut T,
-        }
-        #[unsafe_destructor]
-        impl<'a, T> Drop for Reset<'a, T> {
-            fn drop(&mut self) {
-                unsafe { self.key.set(self.val) }
-            }
-        }
-
-        let prev = unsafe {
-            let prev = self.inner.get();
-            self.inner.set(t as *const T as *mut T);
-            prev
-        };
-
-        let _reset = Reset { key: &self.inner, val: prev };
-        cb()
-    }
-
-    /// Get a value out of this scoped variable.
-    ///
-    /// This function takes a closure which receives the value of this
-    /// variable.
-    ///
-    /// # Panics
-    ///
-    /// This function will panic if `set` has not previously been called.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// scoped_thread_local!(static FOO: u32);
-    ///
-    /// FOO.with(|slot| {
-    ///     // work with `slot`
-    /// });
-    /// ```
-    pub fn with<R, F>(&'static self, cb: F) -> R where
-        F: FnOnce(&T) -> R
-    {
-        unsafe {
-            let ptr = self.inner.get();
-            assert!(!ptr.is_null(), "cannot access a scoped thread local \
-                                     variable without calling `set` first");
-            cb(&*ptr)
-        }
-    }
-
-    /// Test whether this TLS key has been `set` for the current thread.
-    pub fn is_set(&'static self) -> bool {
-        unsafe { !self.inner.get().is_null() }
-    }
-}
-
-#[cfg(not(any(windows,
-              target_os = "android",
-              target_os = "ios",
-              target_os = "openbsd",
-              target_arch = "aarch64")))]
-mod imp {
-    use std::cell::UnsafeCell;
-
-    #[doc(hidden)]
-    pub struct KeyInner<T> { pub inner: UnsafeCell<*mut T> }
-
-    unsafe impl<T> ::marker::Sync for KeyInner<T> { }
-
-    #[doc(hidden)]
-    impl<T> KeyInner<T> {
-        #[doc(hidden)]
-        pub unsafe fn set(&self, ptr: *mut T) { *self.inner.get() = ptr; }
-        #[doc(hidden)]
-        pub unsafe fn get(&self) -> *mut T { *self.inner.get() }
-    }
-}
-
-#[cfg(any(windows,
-          target_os = "android",
-          target_os = "ios",
-          target_os = "openbsd",
-          target_arch = "aarch64"))]
-mod imp {
-    use marker;
-    use std::cell::Cell;
-    use sys_common::thread_local::StaticKey as OsStaticKey;
-
-    #[doc(hidden)]
-    pub struct KeyInner<T> {
-        pub inner: OsStaticKey,
-        pub marker: marker::PhantomData<Cell<T>>,
-    }
-
-    unsafe impl<T> ::marker::Sync for KeyInner<T> { }
-
-    #[doc(hidden)]
-    impl<T> KeyInner<T> {
-        #[doc(hidden)]
-        pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr as *mut _) }
-        #[doc(hidden)]
-        pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ }
-    }
-}
-
-
-#[cfg(test)]
-mod tests {
-    use cell::Cell;
-    use prelude::v1::*;
-
-    scoped_thread_local!(static FOO: u32);
-
-    #[test]
-    fn smoke() {
-        scoped_thread_local!(static BAR: u32);
-
-        assert!(!BAR.is_set());
-        BAR.set(&1, || {
-            assert!(BAR.is_set());
-            BAR.with(|slot| {
-                assert_eq!(*slot, 1);
-            });
-        });
-        assert!(!BAR.is_set());
-    }
-
-    #[test]
-    fn cell_allowed() {
-        scoped_thread_local!(static BAR: Cell<u32>);
-
-        BAR.set(&Cell::new(1), || {
-            BAR.with(|slot| {
-                assert_eq!(slot.get(), 1);
-            });
-        });
-    }
-
-    #[test]
-    fn scope_item_allowed() {
-        assert!(!FOO.is_set());
-        FOO.set(&1, || {
-            assert!(FOO.is_set());
-            FOO.with(|slot| {
-                assert_eq!(*slot, 1);
-            });
-        });
-        assert!(!FOO.is_set());
-    }
-}
index 70aab26092c440548a082bebf4d1ae230602ac6a..1abe8d0a3c1b1352e77100adb0f246b130981a04 100644 (file)
@@ -351,8 +351,7 @@ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
                         let max_line_length = if lines.len() == 1 {
                             0
                         } else {
-                            lines.as_slice()
-                                 .windows(2)
+                            lines.windows(2)
                                  .map(|w| w[1] - w[0])
                                  .map(|bp| bp.to_usize())
                                  .max()
index 0eaca9af4f08d41258287ac5c0dc24704b848caa..2fe77bf7a5411cbff2ed0c49a6acfeb769e32491 100644 (file)
@@ -513,7 +513,7 @@ fn into_expr(mut self) -> P<ast::Expr> {
             let lname = self.ecx.ident_of(&format!("__arg{}",
                                                   *name));
             pats.push(self.ecx.pat_ident(e.span, lname));
-            names[self.name_positions[*name]] =
+            names[*self.name_positions.get(name).unwrap()] =
                 Some(Context::format_arg(self.ecx, e.span, arg_ty,
                                          self.ecx.expr_ident(e.span, lname)));
             heads.push(self.ecx.expr_addr_of(e.span, e));
index c61aec0069db255032b059d3bedd105b86305878..31d8b207bb9f080134fcbc582391391b1924c726 100644 (file)
@@ -194,7 +194,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 fn res_rel_file(cx: &mut ExtCtxt, sp: codemap::Span, arg: &Path) -> PathBuf {
     // NB: relative paths are resolved relative to the compilation unit
     if !arg.is_absolute() {
-        let mut cu = PathBuf::new(&cx.codemap().span_to_filename(sp));
+        let mut cu = PathBuf::from(&cx.codemap().span_to_filename(sp));
         cu.pop();
         cu.push(arg);
         cu
index 7a2ae55e91494cfad3186ac0122fcbc45c955bd5..5940b791843797cacf97c7225dd9a413e27d74c8 100644 (file)
@@ -236,7 +236,7 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
                                      argument_gram);
 
     // Extract the arguments:
-    let lhses = match *argument_map[lhs_nm] {
+    let lhses = match **argument_map.get(&lhs_nm).unwrap() {
         MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
         _ => cx.span_bug(def.span, "wrong-structured lhs")
     };
@@ -245,7 +245,7 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
         check_lhs_nt_follows(cx, &**lhs, def.span);
     }
 
-    let rhses = match *argument_map[rhs_nm] {
+    let rhses = match **argument_map.get(&rhs_nm).unwrap() {
         MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
         _ => cx.span_bug(def.span, "wrong-structured rhs")
     };
index 0a9980c892527a9b88bec0fecbb6f1bcf2282f56..f5e891a9dd6439c87a732933ab25b306e0cd693c 100644 (file)
@@ -563,6 +563,13 @@ fn visit_item(&mut self, i: &ast::Item) {
                 }
             }
 
+            ast::ItemDefaultImpl(..) => {
+                self.gate_feature("optin_builtin_traits",
+                                  i.span,
+                                  "default trait implementations are experimental \
+                                   and possibly buggy");
+            }
+
             ast::ItemImpl(_, polarity, _, _, _, _) => {
                 match polarity {
                     ast::ImplPolarity::Negative => {
index 9f217bba00ab6e2b30b280c953a72032aed578a4..9af7b9ab633116619c2e9ff3cc12b4ad28e5ad74 100644 (file)
@@ -39,6 +39,8 @@
 #![feature(unicode)]
 #![feature(path_ext)]
 #![feature(str_char)]
+#![feature(convert)]
+#![feature(into_cow)]
 
 extern crate arena;
 extern crate fmt_macros;
index 667af642744b9db478dad5ce0fcd12f528599e3b..e77786c134707567abb3bb38f34611ff6de0d0bb 100644 (file)
@@ -5064,8 +5064,8 @@ fn eval_src_mod(&mut self,
                     outer_attrs: &[ast::Attribute],
                     id_sp: Span)
                     -> (ast::Item_, Vec<ast::Attribute> ) {
-        let mut prefix = PathBuf::new(&self.sess.span_diagnostic.cm
-                                           .span_to_filename(self.span));
+        let mut prefix = PathBuf::from(&self.sess.span_diagnostic.cm
+                                            .span_to_filename(self.span));
         prefix.pop();
         let mut dir_path = prefix;
         for part in &self.mod_path_stack {
index f517dca53cdd20366324ceae83dd523a55597220..8e3c00bb805fe30aaefd92ac2ba9f1e3f0d14cd9 100644 (file)
@@ -62,6 +62,7 @@
 #![feature(std_misc)]
 #![feature(str_char)]
 #![feature(path_ext)]
+#![feature(convert)]
 #![cfg_attr(windows, feature(libc))]
 
 #[macro_use] extern crate log;
index f47921cbf5e6acc3e921dd04ea36b1b373a33b2e..66ee2b1ba87cbee6337302ff195d21093564ae41 100644 (file)
@@ -31,7 +31,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<PathBuf>> {
 
     // Find search directory
     match env::var_os("TERMINFO") {
-        Some(dir) => dirs_to_search.push(PathBuf::new(&dir)),
+        Some(dir) => dirs_to_search.push(PathBuf::from(dir)),
         None => {
             if homedir.is_some() {
                 // ncurses compatibility;
@@ -40,9 +40,9 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<PathBuf>> {
             match env::var("TERMINFO_DIRS") {
                 Ok(dirs) => for i in dirs.split(':') {
                     if i == "" {
-                        dirs_to_search.push(PathBuf::new("/usr/share/terminfo"));
+                        dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
                     } else {
-                        dirs_to_search.push(PathBuf::new(i));
+                        dirs_to_search.push(PathBuf::from(i));
                     }
                 },
                 // Found nothing in TERMINFO_DIRS, use the default paths:
@@ -50,9 +50,9 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<PathBuf>> {
                 // ~/.terminfo, ncurses will search /etc/terminfo, then
                 // /lib/terminfo, and eventually /usr/share/terminfo.
                 Err(..) => {
-                    dirs_to_search.push(PathBuf::new("/etc/terminfo"));
-                    dirs_to_search.push(PathBuf::new("/lib/terminfo"));
-                    dirs_to_search.push(PathBuf::new("/usr/share/terminfo"));
+                    dirs_to_search.push(PathBuf::from("/etc/terminfo"));
+                    dirs_to_search.push(PathBuf::from("/lib/terminfo"));
+                    dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
                 }
             }
         }
index 51decbab8587d1e516279ff98e05dccd3dd6ce91..94944453eda07d50368ccc410060e6189f3d1245 100644 (file)
@@ -45,6 +45,7 @@
 #![feature(libc)]
 #![feature(set_stdio)]
 #![feature(os)]
+#![feature(convert)]
 
 extern crate getopts;
 extern crate serialize;
@@ -382,7 +383,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     let run_ignored = matches.opt_present("ignored");
 
     let logfile = matches.opt_str("logfile");
-    let logfile = logfile.map(|s| PathBuf::new(&s));
+    let logfile = logfile.map(|s| PathBuf::from(&s));
 
     let run_benchmarks = matches.opt_present("bench");
     let run_tests = ! run_benchmarks ||
@@ -696,7 +697,7 @@ fn len_if_padded(t: &TestDescAndFn) -> uint {
     match tests.iter().max_by(|t|len_if_padded(*t)) {
         Some(t) => {
             let n = t.desc.name.as_slice();
-            st.max_name_len = n.as_slice().len();
+            st.max_name_len = n.len();
         },
         None => {}
     }
index ac7f2f824cbbf9ab9c5d3dcab3fb911ad7ea8df0..a08481f8be94e0473c8cfc6b77167bf83d7aa4c1 100644 (file)
@@ -102,8 +102,8 @@ fn collapse(stack: &mut Vec<BookItem>,
     // always include the introduction
     top_items.push(BookItem {
         title: "Introduction".to_string(),
-        path: PathBuf::new("README.md"),
-        path_to_root: PathBuf::new("."),
+        path: PathBuf::from("README.md"),
+        path_to_root: PathBuf::from("."),
         children: vec!(),
     });
 
@@ -133,10 +133,10 @@ fn collapse(stack: &mut Vec<BookItem>,
                 errors.push(format!("paths in SUMMARY.md must be relative, \
                                      but path '{}' for section '{}' is not.",
                                      given_path, title));
-                PathBuf::new("")
+                PathBuf::new()
             }
         };
-        let path_to_root = PathBuf::new(&iter::repeat("../")
+        let path_to_root = PathBuf::from(&iter::repeat("../")
                                          .take(path_from_root.components().count() - 1)
                                          .collect::<String>());
         let item = BookItem {
index 731773917e09118452152504f0df79da09bd10e4..f06290b27cb2809583269f159f4b3313de5745ee 100644 (file)
@@ -87,7 +87,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
         if env::args().len() < 3 {
             src = env::current_dir().unwrap().clone();
         } else {
-            src = PathBuf::new(&env::args().nth(2).unwrap());
+            src = PathBuf::from(&env::args().nth(2).unwrap());
         }
         // preprocess the markdown, rerouting markdown references to html references
         let mut markdown_data = String::new();
@@ -164,13 +164,13 @@ fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
         if env::args().len() < 3 {
             src = cwd.clone();
         } else {
-            src = PathBuf::new(&env::args().nth(2).unwrap());
+            src = PathBuf::from(&env::args().nth(2).unwrap());
         }
 
         if env::args().len() < 4 {
             tgt = cwd.join("_book");
         } else {
-            tgt = PathBuf::new(&env::args().nth(3).unwrap());
+            tgt = PathBuf::from(&env::args().nth(3).unwrap());
         }
 
         try!(fs::create_dir(&tgt));
index 294b4e556694ad2be1c935ab5749226a392877bf..e896dee27919e1c4121e2be47b7c5c334e8ffa1f 100644 (file)
@@ -20,6 +20,7 @@
 pub type CommandResult<T> = Result<T, CommandError>;
 
 pub fn err(s: &str) -> CliError {
+    #[derive(Debug)]
     struct E(String);
 
     impl Error for E {
index 09fcd518c1e7e3998f32851738559f36840d845d..4a652f846ed58bd0112c54e609a64737c8dad74f 100644 (file)
@@ -15,6 +15,7 @@
 #![feature(rustdoc)]
 #![feature(rustc_private)]
 #![feature(path_relative_from)]
+#![feature(convert)]
 
 extern crate rustdoc;
 extern crate rustc_back;
index dd1ad413a3d279a873f299ec853c7e03dbf68c1a..604a3e69a21767909233a369c61149385b64a07a 100644 (file)
@@ -19,6 +19,6 @@
 
 // the unused ty param is necessary so this gets monomorphized
 pub fn request<T>(req: &header_map) {
-  let data = req["METHOD".to_string()].clone();
+  let data = req[&"METHOD".to_string()].clone();
   let _x = data.borrow().clone()[0].clone();
 }
index d9a2b06e0393f6f9899af007653ddf0cadc22e4e..18db50a831ca8d5b840168b96550869729573054 100644 (file)
@@ -33,7 +33,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
 
     let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) {
         Success(map) => {
-            match (&*map[str_to_ident("matched")], &*map[str_to_ident("pat")]) {
+            match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) {
                 (&MatchedNonterminal(NtExpr(ref matched_expr)),
                  &MatchedSeq(ref pats, seq_sp)) => {
                     let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt|
diff --git a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs
new file mode 100644 (file)
index 0000000..a88445b
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that macro reexports item are gated by `macro_reexport` feature gate.
+
+// aux-build:macro_reexport_1.rs
+// ignore-stage1
+
+#![crate_type = "dylib"]
+
+#[macro_reexport(reexported)]
+#[macro_use] #[no_link]
+extern crate macro_reexport_1;
+//~^ ERROR macros reexports are experimental and possibly buggy
+//~| HELP add #![feature(macro_reexport)] to the crate attributes to enable
diff --git a/src/test/compile-fail/borrowck-overloaded-index-2.rs b/src/test/compile-fail/borrowck-overloaded-index-2.rs
deleted file mode 100644 (file)
index 58668b7..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 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.
-
-#![feature(box_syntax)]
-
-use std::ops::Index;
-
-struct MyVec<T> {
-    data: Vec<T>,
-}
-
-impl<T> Index<usize> for MyVec<T> {
-    type Output = T;
-
-    fn index(&self, &i: &usize) -> &T {
-        &self.data[i]
-    }
-}
-
-fn main() {
-    let v = MyVec::<Box<_>> { data: vec!(box 1, box 2, box 3) };
-    let good = &v[0]; // Shouldn't fail here
-    let bad = v[0];
-    //~^ ERROR cannot move out of indexed content
-}
index 430f2fcc13a73c0a075cd0ae286739c9bbcb54ea..bee56c9bf390bb17092d20dc86324435decad8e7 100644 (file)
@@ -19,7 +19,7 @@ struct MyVec<T> { x: T }
 
 impl<T> Index<usize> for MyVec<T> {
     type Output = T;
-    fn index(&self, _: &usize) -> &T {
+    fn index(&self, _: usize) -> &T {
         &self.x
     }
 }
index 99f396ef8143213af415dbca2a649d0b4e1cd167..55a6e2ac7b8d6755f8bd2bcac6da1e07105a5d8e 100644 (file)
@@ -18,6 +18,7 @@ struct Foo {
     y: isize,
 }
 
+#[cfg(stage0)]
 impl Index<String> for Foo {
     type Output = isize;
 
@@ -30,8 +31,20 @@ fn index<'a>(&'a self, z: &String) -> &'a isize {
     }
 }
 
-impl IndexMut<String> for Foo {
-    fn index_mut<'a>(&'a mut self, z: &String) -> &'a mut isize {
+impl<'a> Index<&'a String> for Foo {
+    type Output = isize;
+
+    fn index(&self, z: &String) -> &isize {
+        if *z == "x" {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl<'a> IndexMut<&'a String> for Foo {
+    fn index_mut(&mut self, z: &String) -> &mut isize {
         if *z == "x" {
             &mut self.x
         } else {
@@ -41,13 +54,13 @@ fn index_mut<'a>(&'a mut self, z: &String) -> &'a mut isize {
 }
 
 fn test1(mut f: Box<Foo>, s: String) {
-    let _p = &mut f[s];
-    let _q = &f[s]; //~ ERROR cannot borrow
+    let _p = &mut f[&s];
+    let _q = &f[&s]; //~ ERROR cannot borrow
 }
 
 fn test2(mut f: Box<Foo>, s: String) {
-    let _p = &mut f[s];
-    let _q = &mut f[s]; //~ ERROR cannot borrow
+    let _p = &mut f[&s];
+    let _q = &mut f[&s]; //~ ERROR cannot borrow
 }
 
 struct Bar {
@@ -55,37 +68,37 @@ struct Bar {
 }
 
 fn test3(mut f: Box<Bar>, s: String) {
-    let _p = &mut f.foo[s];
-    let _q = &mut f.foo[s]; //~ ERROR cannot borrow
+    let _p = &mut f.foo[&s];
+    let _q = &mut f.foo[&s]; //~ ERROR cannot borrow
 }
 
 fn test4(mut f: Box<Bar>, s: String) {
-    let _p = &f.foo[s];
-    let _q = &f.foo[s];
+    let _p = &f.foo[&s];
+    let _q = &f.foo[&s];
 }
 
 fn test5(mut f: Box<Bar>, s: String) {
-    let _p = &f.foo[s];
-    let _q = &mut f.foo[s]; //~ ERROR cannot borrow
+    let _p = &f.foo[&s];
+    let _q = &mut f.foo[&s]; //~ ERROR cannot borrow
 }
 
 fn test6(mut f: Box<Bar>, g: Foo, s: String) {
-    let _p = &f.foo[s];
+    let _p = &f.foo[&s];
     f.foo = g; //~ ERROR cannot assign
 }
 
 fn test7(mut f: Box<Bar>, g: Bar, s: String) {
-    let _p = &f.foo[s];
+    let _p = &f.foo[&s];
     *f = g; //~ ERROR cannot assign
 }
 
 fn test8(mut f: Box<Bar>, g: Foo, s: String) {
-    let _p = &mut f.foo[s];
+    let _p = &mut f.foo[&s];
     f.foo = g; //~ ERROR cannot assign
 }
 
 fn test9(mut f: Box<Bar>, g: Bar, s: String) {
-    let _p = &mut f.foo[s];
+    let _p = &mut f.foo[&s];
     *f = g; //~ ERROR cannot assign
 }
 
diff --git a/src/test/compile-fail/borrowck-overloaded-index-move-from-vec.rs b/src/test/compile-fail/borrowck-overloaded-index-move-from-vec.rs
new file mode 100644 (file)
index 0000000..1b62d9c
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2014 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.
+
+#![feature(box_syntax)]
+
+use std::ops::Index;
+
+struct MyVec<T> {
+    data: Vec<T>,
+}
+
+impl<T> Index<usize> for MyVec<T> {
+    type Output = T;
+
+    fn index(&self, i: usize) -> &T {
+        &self.data[i]
+    }
+}
+
+fn main() {
+    let v = MyVec::<Box<_>> { data: vec!(box 1, box 2, box 3) };
+    let good = &v[0]; // Shouldn't fail here
+    let bad = v[0];
+    //~^ ERROR cannot move out of indexed content
+}
diff --git a/src/test/compile-fail/borrowck-overloaded-index-move-index.rs b/src/test/compile-fail/borrowck-overloaded-index-move-index.rs
new file mode 100644 (file)
index 0000000..d8615d1
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2014 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::ops::{Index, IndexMut};
+
+struct Foo {
+    x: isize,
+    y: isize,
+}
+
+impl Index<String> for Foo {
+    type Output = isize;
+
+    fn index(&self, z: String) -> &isize {
+        if z == "x" {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl IndexMut<String> for Foo {
+    fn index_mut(&mut self, z: String) -> &mut isize {
+        if z == "x" {
+            &mut self.x
+        } else {
+            &mut self.y
+        }
+    }
+}
+
+struct Bar {
+    x: isize,
+}
+
+impl Index<isize> for Bar {
+    type Output = isize;
+
+    fn index<'a>(&'a self, z: isize) -> &'a isize {
+        &self.x
+    }
+}
+
+fn main() {
+    let mut f = Foo {
+        x: 1,
+        y: 2,
+    };
+    let mut s = "hello".to_string();
+    let rs = &mut s;
+
+    println!("{}", f[s]);
+    //~^ ERROR cannot move out of `s` because it is borrowed
+
+    f[s] = 10;
+    //~^ ERROR cannot move out of `s` because it is borrowed
+    //~| ERROR use of moved value: `s`
+
+    let s = Bar {
+        x: 1,
+    };
+    let i = 2;
+    let _j = &i;
+    println!("{}", s[i]); // no error, i is copy
+    println!("{}", s[i]);
+}
diff --git a/src/test/compile-fail/borrowck-overloaded-index-ref-index.rs b/src/test/compile-fail/borrowck-overloaded-index-ref-index.rs
new file mode 100644 (file)
index 0000000..4c50caf
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2014 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::ops::{Index, IndexMut};
+
+struct Foo {
+    x: isize,
+    y: isize,
+}
+
+impl<'a> Index<&'a String> for Foo {
+    type Output = isize;
+
+    fn index(&self, z: &String) -> &isize {
+        if *z == "x" {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl<'a> IndexMut<&'a String> for Foo {
+    fn index_mut(&mut self, z: &String) -> &mut isize {
+        if *z == "x" {
+            &mut self.x
+        } else {
+            &mut self.y
+        }
+    }
+}
+
+struct Bar {
+    x: isize,
+}
+
+impl Index<isize> for Bar {
+    type Output = isize;
+
+    fn index<'a>(&'a self, z: isize) -> &'a isize {
+        &self.x
+    }
+}
+
+fn main() {
+    let mut f = Foo {
+        x: 1,
+        y: 2,
+    };
+    let mut s = "hello".to_string();
+    let rs = &mut s;
+    println!("{}", f[&s]);
+    //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+    f[&s] = 10;
+    //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+    let s = Bar {
+        x: 1,
+    };
+    s[2] = 20;
+    //~^ ERROR cannot assign to immutable indexed content
+}
diff --git a/src/test/compile-fail/borrowck-overloaded-index.rs b/src/test/compile-fail/borrowck-overloaded-index.rs
deleted file mode 100644 (file)
index 2d752ab..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2014 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::ops::{Index, IndexMut};
-
-struct Foo {
-    x: isize,
-    y: isize,
-}
-
-impl Index<String> for Foo {
-    type Output = isize;
-
-    fn index<'a>(&'a self, z: &String) -> &'a isize {
-        if *z == "x" {
-            &self.x
-        } else {
-            &self.y
-        }
-    }
-}
-
-impl IndexMut<String> for Foo {
-    fn index_mut<'a>(&'a mut self, z: &String) -> &'a mut isize {
-        if *z == "x" {
-            &mut self.x
-        } else {
-            &mut self.y
-        }
-    }
-}
-
-struct Bar {
-    x: isize,
-}
-
-impl Index<isize> for Bar {
-    type Output = isize;
-
-    fn index<'a>(&'a self, z: &isize) -> &'a isize {
-        &self.x
-    }
-}
-
-fn main() {
-    let mut f = Foo {
-        x: 1,
-        y: 2,
-    };
-    let mut s = "hello".to_string();
-    let rs = &mut s;
-    println!("{}", f[s]);
-    //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
-    f[s] = 10;
-    //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
-    let s = Bar {
-        x: 1,
-    };
-    s[2] = 20;
-    //~^ ERROR cannot assign to immutable indexed content
-}
index 6bcbefb904d9e6a510ec6120a94a40e80aeefa57..a5b317307379e82cfa80d034d4a95e8bca787c6c 100644 (file)
@@ -21,4 +21,14 @@ impl MyTrait for .. {}
 impl MyTrait for .. {}
 //~^ ERROR conflicting implementations for trait `MyTrait`
 
+trait MySafeTrait: MarkerTrait {}
+
+unsafe impl MySafeTrait for .. {}
+//~^ ERROR implementing the trait `MySafeTrait` is not unsafe
+
+unsafe trait MyUnsafeTrait: MarkerTrait {}
+
+impl MyUnsafeTrait for .. {}
+//~^ ERROR the trait `MyUnsafeTrait` requires an `unsafe impl` declaration
+
 fn main() {}
index 91f34320482561aca98a3a707e8405a976579c41..021ef7343cbb4432f028f51e030967d23a98db43 100644 (file)
@@ -20,7 +20,7 @@
 impl Index<usize> for S {
     type Output = str;
 
-    fn index<'a>(&'a self, _: &usize) -> &'a str {
+    fn index(&self, _: usize) -> &str {
         "hello"
     }
 }
@@ -31,7 +31,7 @@ fn index<'a>(&'a self, _: &usize) -> &'a str {
 impl Index<usize> for T {
     type Output = Debug + 'static;
 
-    fn index<'a>(&'a self, idx: &usize) -> &'a (Debug + 'static) {
+    fn index<'a>(&'a self, idx: usize) -> &'a (Debug + 'static) {
         static x: usize = 42;
         &x
     }
diff --git a/src/test/compile-fail/gated-box-patterns.rs b/src/test/compile-fail/gated-box-patterns.rs
new file mode 100644 (file)
index 0000000..abaa256
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that patterns including the box syntax are gated by `box_patterns` feature gate.
+
+fn main() {
+    let x = Box::new(1);
+
+    match x {
+        box 1 => (),
+        //~^ box pattern syntax is experimental
+        //~| add #![feature(box_patterns)] to the crate attributes to enable
+        _     => ()
+    };
+}
diff --git a/src/test/compile-fail/gated-box-syntax.rs b/src/test/compile-fail/gated-box-syntax.rs
new file mode 100644 (file)
index 0000000..3e08c1f
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the use of the box syntax is gated by `box_syntax` feature gate.
+
+fn main() {
+    let x = box 3;
+    //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead.
+    //~| HELP add #![feature(box_syntax)] to the crate attributes to enable
+}
diff --git a/src/test/compile-fail/gated-simd-ffi.rs b/src/test/compile-fail/gated-simd-ffi.rs
new file mode 100644 (file)
index 0000000..c0a251e
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the use of smid types in the ffi is gated by `smid_ffi` feature gate.
+
+#![feature(simd)]
+
+#[repr(C)]
+#[derive(Copy)]
+#[simd]
+pub struct f32x4(f32, f32, f32, f32);
+
+#[allow(dead_code)]
+extern {
+    fn foo(x: f32x4);
+    //~^ ERROR use of SIMD type `f32x4` in FFI is highly experimental and may result in invalid code
+    //~| HELP add #![feature(simd_ffi)] to the crate attributes to enable
+}
+
+fn main() {}
index 015f1fa603a2004ae08c5fcae9cff0af5295b7bb..f8d85f939374dabce61c3f7eeaa4f705b2fc0b5a 100644 (file)
@@ -33,7 +33,4 @@ fn main() {
 
     0.contains(bits);
     //~^ ERROR overflow
-    //~| ERROR overflow
-    //~| ERROR overflow
-    //~| ERROR mismatched types
 }
diff --git a/src/test/compile-fail/match-ref-mut-invariance.rs b/src/test/compile-fail/match-ref-mut-invariance.rs
new file mode 100644 (file)
index 0000000..c2b54a9
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2014 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.
+
+// Check that when making a ref mut binding with type `&mut T`, the
+// type `T` must match precisely the type `U` of the value being
+// matched, and in particular cannot be some supertype of `U`. Issue
+// #23116. This test focuses on a `match`.
+
+#![allow(dead_code)]
+struct S<'b>(&'b i32);
+impl<'b> S<'b> {
+    fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+        match self.0 { ref mut x => x } //~ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/match-ref-mut-let-invariance.rs b/src/test/compile-fail/match-ref-mut-let-invariance.rs
new file mode 100644 (file)
index 0000000..ea16c61
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 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.
+
+// Check that when making a ref mut binding with type `&mut T`, the
+// type `T` must match precisely the type `U` of the value being
+// matched, and in particular cannot be some supertype of `U`. Issue
+// #23116. This test focuses on a `let`.
+
+#![allow(dead_code)]
+struct S<'b>(&'b i32);
+impl<'b> S<'b> {
+    fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+        let ref mut x = self.0;
+        x //~ ERROR mismatched types
+    }
+}
+
+fn main() {}
index e8bc11317f2aadbd597b1a58228d0a61be3505a1..368269999a296c0008f457a5f7c37f12b63d9e63 100644 (file)
@@ -42,12 +42,5 @@ fn is_send<T:Send>() { }
 fn main() {
     is_send::<A>();
     //~^ ERROR overflow evaluating
-    //~^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
-    //~^^^ NOTE required by `is_send`
-    //~^^^^ ERROR overflow evaluating
-    //~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
-    //~^^^^^^ NOTE required by `is_send`
-    //~^^^^^^^ ERROR overflow evaluating
-    //~^^^^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
-    //~^^^^^^^^^ NOTE required by `is_send`
+    //~| NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
 }
diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs
new file mode 100644 (file)
index 0000000..8d05cb6
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Dummy { fn dummy(&self); }
+
+fn foo1<'a:'b,'b>(x: &'a mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
+    // Here, we are able to coerce
+    x
+}
+
+fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
+    // Here, we are able to coerce
+    x
+}
+
+fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
+    // Without knowing 'a:'b, we can't coerce
+    x //~ ERROR mismatched types
+     //~^ ERROR cannot infer
+}
+
+struct Wrapper<T>(T);
+fn foo4<'a:'b,'b>(x: Wrapper<&'a mut Dummy>) -> Wrapper<&'b mut Dummy> {
+    // We can't coerce because it is packed in `Wrapper`
+    x //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs
new file mode 100644 (file)
index 0000000..5415915
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let _x = 1_i32 << id(32);
+}
diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs
new file mode 100644 (file)
index 0000000..fd3e801
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let _x = 1 << id(-1);
+}
diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs
new file mode 100644 (file)
index 0000000..58914ba
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let _x = 1_u64 << id(64);
+}
diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs
new file mode 100644 (file)
index 0000000..ed25876
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// This function is checking that our automatic truncation does not
+// sidestep the overflow checking.
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    // this signals overflow when checking is on
+    let x = 1_i8 << id(17);
+
+    // ... but when checking is off, the fallback will truncate the
+    // input to its lower three bits (= 1). Note that this is *not*
+    // the behavior of the x86 processor for 8- and 16-bit types,
+    // but it is necessary to avoid undefined behavior from LLVM.
+    //
+    // We check that here, by ensuring the result has only been
+    // shifted by one place; if overflow checking is turned off, then
+    // this assertion will pass (and the compiletest driver will
+    // report that the test did not produce the error expected above).
+    assert_eq!(x, 2_i8);
+}
diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs
new file mode 100644 (file)
index 0000000..c36a16f
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let _x = -1_i32 >> id(32);
+}
diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs
new file mode 100644 (file)
index 0000000..f619ebe
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let _x = -1_i32 >> id(-1);
+}
diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs
new file mode 100644 (file)
index 0000000..c261e19
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    let _x = -1_i64 >> id(64);
+}
diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs
new file mode 100644 (file)
index 0000000..6e79a13
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2015 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:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// This function is checking that our (type-based) automatic
+// truncation does not sidestep the overflow checking.
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    // this signals overflow when checking is on
+    let x = 2_i8 >> id(17);
+
+    // ... but when checking is off, the fallback will truncate the
+    // input to its lower three bits (= 1). Note that this is *not*
+    // the behavior of the x86 processor for 8- and 16-bit types,
+    // but it is necessary to avoid undefined behavior from LLVM.
+    //
+    // We check that here, by ensuring the result is not zero; if
+    // overflow checking is turned off, then this assertion will pass
+    // (and the compiletest driver will report that the test did not
+    // produce the error expected above).
+    assert_eq!(x, 1_i8);
+}
index 08f3bd10e74a716c05b1699be930e7d698b3db0c..4c30c7b22a60dcb62d28bd4511d6a513ef5e1971 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(optin_builtin_traits)]
+
 pub mod bar {
     use std::marker;
 
index 0c7ecfcefff34bcdc9bcf3cac4e53fd5eefe9dad..9539486118b812efd53a8c98368ab85b7528ef9d 100644 (file)
@@ -19,7 +19,7 @@
 impl Index<uint> for S {
     type Output = str;
 
-    fn index<'a>(&'a self, _: &uint) -> &'a str {
+    fn index<'a>(&'a self, _: uint) -> &'a str {
         "hello"
     }
 }
@@ -29,7 +29,7 @@ fn index<'a>(&'a self, _: &uint) -> &'a str {
 impl Index<uint> for T {
     type Output = Debug + 'static;
 
-    fn index<'a>(&'a self, idx: &uint) -> &'a (Debug + 'static) {
+    fn index<'a>(&'a self, idx: uint) -> &'a (Debug + 'static) {
         static X: uint = 42;
         &X as &(Debug + 'static)
     }
index 5d68a25a14ada73433012e8a3a13ccdf1c9c04f0..cd6147504512873f74d225b04d3474c0e6b299eb 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(convert)]
+
 use std::env::*;
 use std::path::PathBuf;
 
@@ -16,7 +18,7 @@ fn main() {
     let oldhome = var("HOME");
 
     set_var("HOME", "/home/MountainView");
-    assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
+    assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
 
     remove_var("HOME");
     if cfg!(target_os = "android") {
@@ -37,14 +39,14 @@ fn main() {
     assert!(home_dir().is_some());
 
     set_var("HOME", "/home/MountainView");
-    assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
+    assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
 
     remove_var("HOME");
 
     set_var("USERPROFILE", "/home/MountainView");
-    assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
+    assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
 
     set_var("HOME", "/home/MountainView");
     set_var("USERPROFILE", "/home/PaloAlto");
-    assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
+    assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
 }
index 18e4190ee459f6b24acccb8d36a18733a6ca28d8..76a5b6488b5a300a69265155008c56d9905b5365 100644 (file)
@@ -29,7 +29,7 @@ fn row<'a>(&'a self, row: uint) -> Row<&'a Mat<T>> {
 impl<T> Index<(uint, uint)> for Mat<T> {
     type Output = T;
 
-    fn index<'a>(&'a self, &(row, col): &(uint, uint)) -> &'a T {
+    fn index<'a>(&'a self, (row, col): (uint, uint)) -> &'a T {
         &self.data[row * self.cols + col]
     }
 }
@@ -37,7 +37,7 @@ fn index<'a>(&'a self, &(row, col): &(uint, uint)) -> &'a T {
 impl<'a, T> Index<(uint, uint)> for &'a Mat<T> {
     type Output = T;
 
-    fn index<'b>(&'b self, index: &(uint, uint)) -> &'b T {
+    fn index<'b>(&'b self, index: (uint, uint)) -> &'b T {
         (*self).index(index)
     }
 }
@@ -47,8 +47,8 @@ struct Row<M> { mat: M, row: uint, }
 impl<T, M: Index<(uint, uint), Output=T>> Index<uint> for Row<M> {
     type Output = T;
 
-    fn index<'a>(&'a self, col: &uint) -> &'a T {
-        &self.mat[(self.row, *col)]
+    fn index<'a>(&'a self, col: uint) -> &'a T {
+        &self.mat[(self.row, col)]
     }
 }
 
@@ -56,7 +56,7 @@ fn main() {
     let m = Mat::new(vec!(1, 2, 3, 4, 5, 6), 3);
     let r = m.row(1);
 
-    assert!(r.index(&2) == &6);
+    assert!(r.index(2) == &6);
     assert!(r[2] == 6);
     assert!(r[2] == 6);
     assert!(6 == r[2]);
diff --git a/src/test/run-pass/issue-23550.rs b/src/test/run-pass/issue-23550.rs
new file mode 100644 (file)
index 0000000..97357c1
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2015 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.
+
+#![feature(core)]
+#![allow(warnings)]
+
+use std::intrinsics;
+
+#[derive(Copy)]
+struct Wrap(i64);
+
+// These volatile and atomic intrinsics used to cause an ICE
+
+unsafe fn test_bool(p: &mut bool, v: bool) {
+    intrinsics::volatile_load(p);
+    intrinsics::volatile_store(p, v);
+    intrinsics::atomic_load(p);
+    intrinsics::atomic_cxchg(p, v, v);
+    intrinsics::atomic_store(p, v);
+    intrinsics::atomic_xchg(p, v);
+}
+
+unsafe fn test_immediate_fca(p: &mut Wrap, v: Wrap) {
+    intrinsics::volatile_load(p);
+    intrinsics::volatile_store(p, v);
+    intrinsics::atomic_load(p);
+    intrinsics::atomic_cxchg(p, v, v);
+    intrinsics::atomic_store(p, v);
+    intrinsics::atomic_xchg(p, v);
+}
+
+fn main() {}
index 4f89d28332a2349a5a1ff0d3e9636cba60effd41..b04ae0edbed87b20f791ca3bb893652e94c9e250 100644 (file)
@@ -16,7 +16,7 @@
 use std::collections::HashMap;
 
 fn add_interfaces(managed_ip: String, device: HashMap<String, int>)  {
-     println!("{}, {}", managed_ip, device["interfaces".to_string()]);
+     println!("{}, {}", managed_ip, device["interfaces"]);
 }
 
 pub fn main() {}
index b9b5aec62fcdaf1f9725be141732384b08f97680..619bd08141fb62259766fb2d856cfbe96ef340d3 100644 (file)
@@ -56,8 +56,7 @@ fn add_interface(_store: int, managed_ip: String, data: json::Json) -> (String,
 
 fn add_interfaces(store: int, managed_ip: String, device: HashMap<String, json::Json>)
 -> Vec<(String, object)> {
-    match device["interfaces".to_string()]
-    {
+    match device["interfaces"] {
         Json::Array(ref interfaces) =>
         {
           interfaces.iter().map(|interface| {
@@ -67,7 +66,7 @@ fn add_interfaces(store: int, managed_ip: String, device: HashMap<String, json::
         _ =>
         {
             println!("Expected list for {} interfaces, found {}", managed_ip,
-                   device["interfaces".to_string()]);
+                     device["interfaces"]);
             Vec::new()
         }
     }
index fb0e8e599eb2af9477cdbffce70a292b28b7ffd4..7016e28f2ee022800ad3831037e59df33bb6b4df 100644 (file)
@@ -17,7 +17,7 @@ fn bar(a: foo::map) {
     if false {
         panic!();
     } else {
-        let _b = &(*a)[2];
+        let _b = &(*a)[&2];
     }
 }
 
index 9e36b1f5082d03dad3f1a48bc3ed9a38326eb600..78318e083ba404a09b5de94293eb0b0591bd95d3 100644 (file)
@@ -21,6 +21,6 @@ pub fn main() {
     let mut m: HashMap<int, A> = HashMap::new();
     m.insert(1, A(0, 0));
 
-    let A(ref _a, ref _b) = m[1];
-    let (a, b) = match m[1] { A(ref _a, ref _b) => (_a, _b) };
+    let A(ref _a, ref _b) = m[&1];
+    let (a, b) = match m[&1] { A(ref _a, ref _b) => (_a, _b) };
 }
diff --git a/src/test/run-pass/match-ref-unsized.rs b/src/test/run-pass/match-ref-unsized.rs
new file mode 100644 (file)
index 0000000..4de0282
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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.
+
+// Binding unsized expressions to ref patterns
+
+pub fn main() {
+    let ref a = *"abcdef";
+    assert_eq!(a, "abcdef");
+
+    match *"12345" {
+        ref b => { assert_eq!(b, "12345") }
+    }
+}
index 3ddc666cd384c0ce2c551b5df122201a48992a4a..801e71b3038622f504f7c3c738d9eb5798f84c4b 100644 (file)
@@ -52,8 +52,8 @@ fn not(self) -> Point {
 impl ops::Index<bool> for Point {
     type Output = int;
 
-    fn index(&self, x: &bool) -> &int {
-        if *x {
+    fn index(&self, x: bool) -> &int {
+        if x {
             &self.x
         } else {
             &self.y
index 1118638fe071345d3987346dcd925200c1e261f0..c2b42ac1c8163a5b4667a07ec8898b23bbcd479c 100644 (file)
@@ -11,7 +11,7 @@
 // Regression test for issue #152.
 pub fn main() {
     let mut b: uint = 1_usize;
-    while b <= 32_usize {
+    while b < std::mem::size_of::<usize>() {
         0_usize << b;
         b <<= 1_usize;
         println!("{}", b);
index 0064748e883699dc3968e813eae7c5c389ed89b9..b5c9962fe9c3f4d37ef9ff1c9c9483f41904a89d 100644 (file)
@@ -28,7 +28,7 @@ fn push(&mut self, key: K, value: V) {
     }
 }
 
-impl<K: PartialEq + std::fmt::Debug, V:Clone> Index<K> for AssociationList<K,V> {
+impl<'a, K: PartialEq + std::fmt::Debug, V:Clone> Index<&'a K> for AssociationList<K,V> {
     type Output = V;
 
     fn index<'a>(&'a self, index: &K) -> &'a V {
@@ -49,9 +49,9 @@ pub fn main() {
     list.push(foo.clone(), 22);
     list.push(bar.clone(), 44);
 
-    assert!(list[foo] == 22);
-    assert!(list[bar] == 44);
+    assert!(list[&foo] == 22);
+    assert!(list[&bar] == 44);
 
-    assert!(list[foo] == 22);
-    assert!(list[bar] == 44);
+    assert!(list[&foo] == 22);
+    assert!(list[&bar] == 44);
 }
index 8f655f0517ddf47fe56224d420ba0e0a34992a59..107f0fbc20904b8e4b0fe18d744b5b2040441350 100644 (file)
@@ -23,8 +23,8 @@ struct Foo {
 impl Index<int> for Foo {
     type Output = int;
 
-    fn index(&self, z: &int) -> &int {
-        if *z == 0 {
+    fn index(&self, z: int) -> &int {
+        if z == 0 {
             &self.x
         } else {
             &self.y
@@ -33,8 +33,8 @@ fn index(&self, z: &int) -> &int {
 }
 
 impl IndexMut<int> for Foo {
-    fn index_mut(&mut self, z: &int) -> &mut int {
-        if *z == 0 {
+    fn index_mut(&mut self, z: int) -> &mut int {
+        if z == 0 {
             &mut self.x
         } else {
             &mut self.y
index 487fb93c9fee8f3a09135d7503989ade445b6158..f01e5541c423b11d2034a77f9bbe557533ffe6e5 100644 (file)
@@ -25,8 +25,8 @@ struct Bar {
 impl Index<int> for Foo {
     type Output = int;
 
-    fn index(&self, z: &int) -> &int {
-        if *z == 0 {
+    fn index(&self, z: int) -> &int {
+        if z == 0 {
             &self.x
         } else {
             &self.y
index 10ca3804eaedbc187ab128e619f45d20cd7c41dd..60e0ed9bfdd0f6298b56c26864542da9cd4ecf26 100644 (file)
@@ -18,8 +18,8 @@ struct Foo {
 impl Index<int> for Foo {
     type Output = int;
 
-    fn index(&self, z: &int) -> &int {
-        if *z == 0 {
+    fn index(&self, z: int) -> &int {
+        if z == 0 {
             &self.x
         } else {
             &self.y
@@ -28,8 +28,8 @@ fn index(&self, z: &int) -> &int {
 }
 
 impl IndexMut<int> for Foo {
-    fn index_mut(&mut self, z: &int) -> &mut int {
-        if *z == 0 {
+    fn index_mut(&mut self, z: int) -> &mut int {
+        if z == 0 {
             &mut self.x
         } else {
             &mut self.y
diff --git a/src/test/run-pass/shift-near-oflo.rs b/src/test/run-pass/shift-near-oflo.rs
new file mode 100644 (file)
index 0000000..4ff058f
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2015 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: -C debug-assertions
+
+// Check that we do *not* overflow on a number of edge cases.
+// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+    test_left_shift();
+    test_right_shift();
+}
+
+fn test_left_shift() {
+    // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+    macro_rules! tests {
+        ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
+            let x = (1 as $iN) << id(0);
+            assert_eq!(x, 1);
+            let x = (1 as $uN) << id(0);
+            assert_eq!(x, 1);
+            let x = (1 as $iN) << id($max_rhs);
+            assert_eq!(x, $expect_i);
+            let x = (1 as $uN) << id($max_rhs);
+            assert_eq!(x, $expect_u);
+            // high-order bits on LHS are silently discarded without panic.
+            let x = (3 as $iN) << id($max_rhs);
+            assert_eq!(x, $expect_i);
+            let x = (3 as $uN) << id($max_rhs);
+            assert_eq!(x, $expect_u);
+        } }
+    }
+
+    let x = 1_i8 << id(0);
+    assert_eq!(x, 1);
+    let x = 1_u8 << id(0);
+    assert_eq!(x, 1);
+    let x = 1_i8 << id(7);
+    assert_eq!(x, std::i8::MIN);
+    let x = 1_u8 << id(7);
+    assert_eq!(x, 0x80);
+    // high-order bits on LHS are silently discarded without panic.
+    let x = 3_i8 << id(7);
+    assert_eq!(x, std::i8::MIN);
+    let x = 3_u8 << id(7);
+    assert_eq!(x, 0x80);
+
+    // above is (approximately) expanded from:
+    tests!(i8, u8, 7, std::i8::MIN, 0x80_u8);
+
+    tests!(i16, u16, 15, std::i16::MIN, 0x8000_u16);
+    tests!(i32, u32, 31, std::i32::MIN, 0x8000_0000_u32);
+    tests!(i64, u64, 63, std::i64::MIN, 0x8000_0000_0000_0000_u64);
+}
+
+fn test_right_shift() {
+    // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+    macro_rules! tests {
+        ($iN:ty, $uN:ty, $max_rhs:expr,
+         $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
+        { {
+            let x = (1 as $iN) >> id(0);
+            assert_eq!(x, 1);
+            let x = (1 as $uN) >> id(0);
+            assert_eq!(x, 1);
+            let x = ($highbit_i) >> id($max_rhs-1);
+            assert_eq!(x, 1);
+            let x = ($highbit_u) >> id($max_rhs);
+            assert_eq!(x, 1);
+            // sign-bit is carried by arithmetic right shift
+            let x = ($signbit_i) >> id($max_rhs);
+            assert_eq!(x, -1);
+            // low-order bits on LHS are silently discarded without panic.
+            let x = ($highbit_i + 1) >> id($max_rhs-1);
+            assert_eq!(x, 1);
+            let x = ($highbit_u + 1) >> id($max_rhs);
+            assert_eq!(x, 1);
+            let x = ($signbit_i + 1) >> id($max_rhs);
+            assert_eq!(x, -1);
+        } }
+    }
+
+    tests!(i8, u8, 7, std::i8::MIN, 0x40_i8, 0x80_u8);
+    tests!(i16, u16, 15, std::i16::MIN, 0x4000_u16, 0x8000_u16);
+    tests!(i32, u32, 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
+    tests!(i64, u64, 63, std::i64::MIN,
+           0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
+}
index 30b53dbb0ad5bea0bdf96b7ddb419345e2749ad6..ee9bb80356164504e1dcee563bbc0478316f863c 100644 (file)
 
 impl Index<Range<Foo>> for Foo {
     type Output = Foo;
-    fn index(&self, index: &Range<Foo>) -> &Foo {
+    fn index(&self, index: Range<Foo>) -> &Foo {
         unsafe { COUNT += 1; }
         self
     }
 }
 impl Index<RangeTo<Foo>> for Foo {
     type Output = Foo;
-    fn index(&self, index: &RangeTo<Foo>) -> &Foo {
+    fn index(&self, index: RangeTo<Foo>) -> &Foo {
         unsafe { COUNT += 1; }
         self
     }
 }
 impl Index<RangeFrom<Foo>> for Foo {
     type Output = Foo;
-    fn index(&self, index: &RangeFrom<Foo>) -> &Foo {
+    fn index(&self, index: RangeFrom<Foo>) -> &Foo {
         unsafe { COUNT += 1; }
         self
     }
 }
 impl Index<RangeFull> for Foo {
     type Output = Foo;
-    fn index(&self, _index: &RangeFull) -> &Foo {
+    fn index(&self, _index: RangeFull) -> &Foo {
         unsafe { COUNT += 1; }
         self
     }
 }
 
 impl IndexMut<Range<Foo>> for Foo {
-    fn index_mut(&mut self, index: &Range<Foo>) -> &mut Foo {
+    fn index_mut(&mut self, index: Range<Foo>) -> &mut Foo {
         unsafe { COUNT += 1; }
         self
     }
 }
 impl IndexMut<RangeTo<Foo>> for Foo {
-    fn index_mut(&mut self, index: &RangeTo<Foo>) -> &mut Foo {
+    fn index_mut(&mut self, index: RangeTo<Foo>) -> &mut Foo {
         unsafe { COUNT += 1; }
         self
     }
 }
 impl IndexMut<RangeFrom<Foo>> for Foo {
-    fn index_mut(&mut self, index: &RangeFrom<Foo>) -> &mut Foo {
+    fn index_mut(&mut self, index: RangeFrom<Foo>) -> &mut Foo {
         unsafe { COUNT += 1; }
         self
     }
 }
 impl IndexMut<RangeFull> for Foo {
-    fn index_mut(&mut self, _index: &RangeFull) -> &mut Foo {
+    fn index_mut(&mut self, _index: RangeFull) -> &mut Foo {
         unsafe { COUNT += 1; }
         self
     }