]> git.lizzy.rs Git - rust.git/commitdiff
rollup merge of #23776: nrc/allow_trivial_cast
authorAlex Crichton <alex@alexcrichton.com>
Fri, 27 Mar 2015 17:07:54 +0000 (10:07 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 27 Mar 2015 17:07:54 +0000 (10:07 -0700)
r? @alexcrichton

129 files changed:
src/compiletest/util.rs
src/doc/trpl/README.md
src/doc/trpl/SUMMARY.md
src/doc/trpl/advanced-macros.md
src/doc/trpl/arrays-vectors-and-slices.md
src/doc/trpl/basic.md
src/doc/trpl/compound-data-types.md
src/doc/trpl/documentation.md
src/doc/trpl/ffi.md
src/doc/trpl/inline-assembly.md [new file with mode: 0644]
src/doc/trpl/intrinsics.md [new file with mode: 0644]
src/doc/trpl/lang-items.md [new file with mode: 0644]
src/doc/trpl/link-args.md [new file with mode: 0644]
src/doc/trpl/looping.md
src/doc/trpl/method-syntax.md
src/doc/trpl/no-stdlib.md [new file with mode: 0644]
src/doc/trpl/plugins.md
src/doc/trpl/pointers.md
src/doc/trpl/standard-input.md
src/doc/trpl/tracing-macros.md [new file with mode: 0644]
src/doc/trpl/unsafe.md
src/liballoc/arc.rs
src/liballoc/boxed.rs
src/liballoc/lib.rs
src/liballoc/rc.rs
src/libcollections/btree/map.rs
src/libcollections/btree/node.rs
src/libcollections/lib.rs
src/libcollections/slice.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcollections/vec_map.rs
src/libcore/any.rs
src/libcore/array.rs
src/libcore/convert.rs
src/libcore/intrinsics.rs
src/libcore/lib.rs
src/libcore/marker.rs
src/libcore/mem.rs
src/libcore/option.rs
src/libcore/ptr.rs
src/libcore/result.rs
src/libcore/slice.rs
src/librand/distributions/mod.rs
src/librustc/metadata/loader.rs
src/librustc/metadata/macro_import.rs
src/librustc/middle/dataflow.rs
src/librustc/middle/traits/fulfill.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/object_safety.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/traits/util.rs
src/librustc/middle/ty.rs
src/librustc/plugin/mod.rs
src/librustc/session/config.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/adt.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/context.rs
src/librustc_trans/trans/datum.rs
src/librustc_trans/trans/glue.rs
src/librustc_trans/trans/intrinsic.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/vtable.rs
src/librustc_typeck/variance.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/table.rs
src/libstd/collections/mod.rs
src/libstd/ffi/os_str.rs
src/libstd/io/buffered.rs
src/libstd/io/mod.rs
src/libstd/lib.rs
src/libstd/macros.rs
src/libstd/net/addr.rs
src/libstd/net/mod.rs
src/libstd/net/parser.rs
src/libstd/old_io/buffered.rs
src/libstd/old_io/fs.rs
src/libstd/old_io/process.rs
src/libstd/path.rs
src/libstd/process.rs
src/libstd/sys/common/net2.rs
src/libstd/sys/unix/os_str.rs
src/libstd/sys/windows/os_str.rs
src/libstd/thread/mod.rs
src/libsyntax/ext/mtwt.rs
src/libsyntax/ext/quote.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/lib.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/obsolete.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/ptr.rs
src/libsyntax/test.rs
src/test/auxiliary/typeid-intrinsic.rs
src/test/auxiliary/typeid-intrinsic2.rs
src/test/bench/noise.rs
src/test/compile-fail/deprecated-phase.rs [deleted file]
src/test/compile-fail/manual-link-bad-form.rs
src/test/compile-fail/manual-link-bad-kind.rs
src/test/compile-fail/manual-link-framework.rs
src/test/compile-fail/plugin-extern-crate-attr-deprecated.rs [deleted file]
src/test/compile-fail/reflect-assoc.rs [new file with mode: 0644]
src/test/compile-fail/reflect-object-param.rs [new file with mode: 0644]
src/test/compile-fail/reflect.rs [new file with mode: 0644]
src/test/compile-fail/slice-1.rs [deleted file]
src/test/compile-fail/variance-region-bounds.rs [new file with mode: 0644]
src/test/parse-fail/issue-23620-invalid-escapes.rs [new file with mode: 0644]
src/test/parse-fail/new-unicode-escapes-4.rs
src/test/run-pass/box-of-array-of-drop-1.rs [new file with mode: 0644]
src/test/run-pass/box-of-array-of-drop-2.rs [new file with mode: 0644]
src/test/run-pass/drop-flag-sanity-check.rs [new file with mode: 0644]
src/test/run-pass/drop-flag-skip-sanity-check.rs [new file with mode: 0644]
src/test/run-pass/intrinsic-move-val.rs
src/test/run-pass/issue-15149.rs
src/test/run-pass/nested-vec-1.rs [new file with mode: 0644]
src/test/run-pass/nested-vec-2.rs [new file with mode: 0644]
src/test/run-pass/nested-vec-3.rs [new file with mode: 0644]
src/test/run-pass/object-one-type-two-traits.rs
src/test/run-pass/spawn-fn.rs
src/test/run-pass/type-id-higher-rank.rs

index 2e11cf47d1e56fa2bf7c09e04457ca848cbe3ff1..a8b26cb3ef76835a5fb498ca76a347eabcfee5e8 100644 (file)
 
 /// Conversion table from triple OS name to Rust SYSNAME
 const OS_TABLE: &'static [(&'static str, &'static str)] = &[
-    ("mingw32", "windows"),
-    ("win32", "windows"),
-    ("windows", "windows"),
-    ("darwin", "macos"),
     ("android", "android"),
-    ("linux", "linux"),
-    ("freebsd", "freebsd"),
-    ("dragonfly", "dragonfly"),
     ("bitrig", "bitrig"),
+    ("darwin", "macos"),
+    ("dragonfly", "dragonfly"),
+    ("freebsd", "freebsd"),
+    ("ios", "ios"),
+    ("linux", "linux"),
+    ("mingw32", "windows"),
     ("openbsd", "openbsd"),
+    ("win32", "windows"),
+    ("windows", "windows"),
 ];
 
 const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
-    ("i386", "x86"),
-    ("i686", "x86"),
+    ("aarch64", "aarch64"),
     ("amd64", "x86_64"),
-    ("x86_64", "x86_64"),
-    ("sparc", "sparc"),
-    ("powerpc", "powerpc"),
-    ("arm64", "aarch64"),
     ("arm", "arm"),
-    ("aarch64", "aarch64"),
+    ("arm64", "aarch64"),
+    ("hexagon", "hexagon"),
+    ("i386", "x86"),
+    ("i686", "x86"),
     ("mips", "mips"),
-    ("xcore", "xcore"),
     ("msp430", "msp430"),
-    ("hexagon", "hexagon"),
+    ("powerpc", "powerpc"),
     ("s390x", "systemz"),
+    ("sparc", "sparc"),
+    ("x86_64", "x86_64"),
+    ("xcore", "xcore"),
 ];
 
 pub fn get_os(triple: &str) -> &'static str {
index eb9e2b24ac900e0d7f1090cc7697c057111bec19..4a866d6224d5d134b01120deaac0b4ef4abb74d6 100644 (file)
@@ -11,8 +11,7 @@ navigate through the menu on the left.
 <h2 class="section-header"><a href="basic.html">Basics</a></h2>
 
 This section is a linear introduction to the basic syntax and semantics of
-Rust. It has individual sections on each part of Rust's syntax, and culminates
-in a small project: a guessing game.
+Rust. It has individual sections on each part of Rust's syntax.
 
 After reading "Basics," you will have a good foundation to learn more about
 Rust, and can write very simple programs.
@@ -29,7 +28,12 @@ and will be able to understand most Rust code and write more complex programs.
 
 In a similar fashion to "Intermediate," this section is full of individual,
 deep-dive chapters, which stand alone and can be read in any order. These
-chapters focus on the most complex features, as well as some things that
-are only available in upcoming versions of Rust.
+chapters focus on the most complex features,
 
-After reading "Advanced," you'll be a Rust expert!
+<h2 class="section-header"><a href="unstable.html">Unstable</a></h2>
+
+In a similar fashion to "Intermediate," this section is full of individual,
+deep-dive chapters, which stand alone and can be read in any order.
+
+This chapter contains things that are only available on the nightly channel of
+Rust.
index 70c74825a072cd7fac01e1b772f70ad659d7dba1..140086e32d080e6f819d43326782a7244c56fe83 100644 (file)
     * [FFI](ffi.md)
     * [Unsafe Code](unsafe.md)
     * [Advanced Macros](advanced-macros.md)
+* [Unstable Rust](unstable.md)
     * [Compiler Plugins](plugins.md)
+    * [Inline Assembly](inline-assembly.md)
+    * [No stdlib](no-stdlib.md)
+    * [Intrinsics](intrinsics.md)
+    * [Lang items](lang-items.md)
+    * [Link args](link-args.md)
 * [Conclusion](conclusion.md)
 * [Glossary](glossary.md)
index 86279f7f1a1680899e6f72435826edd64c056cf1..fef458caaaf3343a1aa2e198888d005bc2ba8221 100644 (file)
@@ -206,8 +206,6 @@ the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
 within Rust's macro system.
 
 ```rust
-#![feature(trace_macros)]
-
 macro_rules! bct {
     // cmd 0:  d ... => ...
     (0, $($ps:tt),* ; $_d:tt)
@@ -229,13 +227,6 @@ macro_rules! bct {
     ( $($ps:tt),* ; )
         => (());
 }
-
-fn main() {
-    trace_macros!(true);
-# /* just check the definition
-    bct!(0, 0, 1, 1, 1 ; 1, 0, 1);
-# */
-}
 ```
 
 Exercise: use macros to reduce duplication in the above definition of the
index 5d0f314e8c62ec5556b804303a7ef7884647c793..fb56e4a676784908f085797f168f37920dac32d9 100644 (file)
@@ -99,7 +99,5 @@ You can also take a slice of a vector, `String`, or `&str`, because they are
 backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover
 generics.
 
-We have now learned all of the most basic Rust concepts. We're ready to start
-building ourselves a guessing game, we just need to know one last thing: how to
-get input from the keyboard. You can't have a guessing game without the ability
-to guess!
+We have now learned all of the most basic Rust concepts. Next, we learn how to
+get input from the keyboard.
index 087121d0e7dc3d30e35240165ff9090bd7fcd452..c267830e6e0d0c5e0fc700713abb67ad205ef7d4 100644 (file)
@@ -1,8 +1,7 @@
 % Basics
 
 This section is a linear introduction to the basic syntax and semantics of
-Rust. It has individual sections on each part of Rust's syntax, and cumulates
-in a small project: a guessing game.
+Rust. It has individual sections on each part of Rust's syntax.
 
 After reading "Basics," you will have a good foundation to learn more about
 Rust, and can write very simple programs.
index d531a22d0e0dd55d2b2a0d5d913b88f9d3912c73..e44d2edd667a1ea822cde1798278bbc8b1fe3b55 100644 (file)
@@ -361,5 +361,4 @@ and brittle `if`/`else`s.
 
 [arity]: ./glossary.html#arity
 [match]: ./match.html
-[game]: ./guessing-game.html#comparing-guesses
 [generics]: ./generics.html
index 54821e3ce304d5dfc05045c397e56260116bc416..43b49c09ae4ac7ace50eaee3c728c9d0059a7a77 100644 (file)
@@ -352,7 +352,7 @@ Here’s an example of documenting a macro:
 /// # }
 /// ```
 ///
-/// ```should_fail
+/// ```should_panic
 /// # #[macro_use] extern crate foo;
 /// # fn main() {
 /// panic_unless!(true == false, “I’m broken.”);
index 695279e2d5bb6983cd34a3c6903633969fa2992a..3dff72b3794defdc930f1cc32f9bfb0a234bc45f 100644 (file)
@@ -366,31 +366,6 @@ A few examples of how this model can be used are:
 
 On OSX, frameworks behave with the same semantics as a dynamic library.
 
-## The `link_args` attribute
-
-There is one other way to tell rustc how to customize linking, and that is via
-the `link_args` attribute. This attribute is applied to `extern` blocks and
-specifies raw flags which need to get passed to the linker when producing an
-artifact. An example usage would be:
-
-``` no_run
-#![feature(link_args)]
-
-#[link_args = "-foo -bar -baz"]
-extern {}
-# fn main() {}
-```
-
-Note that this feature is currently hidden behind the `feature(link_args)` gate
-because this is not a sanctioned way of performing linking. Right now rustc
-shells out to the system linker, so it makes sense to provide extra command line
-arguments, but this will not always be the case. In the future rustc may use
-LLVM directly to link native libraries in which case `link_args` will have no
-meaning.
-
-It is highly recommended to *not* use this attribute, and rather use the more
-formal `#[link(...)]` attribute on `extern` blocks instead.
-
 # Unsafe blocks
 
 Some operations, like dereferencing unsafe pointers or calling functions that have been marked
diff --git a/src/doc/trpl/inline-assembly.md b/src/doc/trpl/inline-assembly.md
new file mode 100644 (file)
index 0000000..1a4592f
--- /dev/null
@@ -0,0 +1,141 @@
+% Inline Assembly
+
+For extremely low-level manipulations and performance reasons, one
+might wish to control the CPU directly. Rust supports using inline
+assembly to do this via the `asm!` macro. The syntax roughly matches
+that of GCC & Clang:
+
+```ignore
+asm!(assembly template
+   : output operands
+   : input operands
+   : clobbers
+   : options
+   );
+```
+
+Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
+crate to allow) and of course requires an `unsafe` block.
+
+> **Note**: the examples here are given in x86/x86-64 assembly, but
+> all platforms are supported.
+
+## Assembly template
+
+The `assembly template` is the only required parameter and must be a
+literal string (i.e. `""`)
+
+```
+#![feature(asm)]
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn foo() {
+    unsafe {
+        asm!("NOP");
+    }
+}
+
+// other platforms
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+fn foo() { /* ... */ }
+
+fn main() {
+    // ...
+    foo();
+    // ...
+}
+```
+
+(The `feature(asm)` and `#[cfg]`s are omitted from now on.)
+
+Output operands, input operands, clobbers and options are all optional
+but you must add the right number of `:` if you skip them:
+
+```
+# #![feature(asm)]
+# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+# fn main() { unsafe {
+asm!("xor %eax, %eax"
+    :
+    :
+    : "eax"
+   );
+# } }
+```
+
+Whitespace also doesn't matter:
+
+```
+# #![feature(asm)]
+# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+# fn main() { unsafe {
+asm!("xor %eax, %eax" ::: "eax");
+# } }
+```
+
+## Operands
+
+Input and output operands follow the same format: `:
+"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
+expressions must be mutable lvalues:
+
+```
+# #![feature(asm)]
+# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn add(a: i32, b: i32) -> i32 {
+    let mut c = 0;
+    unsafe {
+        asm!("add $2, $0"
+             : "=r"(c)
+             : "0"(a), "r"(b)
+             );
+    }
+    c
+}
+# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+# fn add(a: i32, b: i32) -> i32 { a + b }
+
+fn main() {
+    assert_eq!(add(3, 14159), 14162)
+}
+```
+
+## Clobbers
+
+Some instructions modify registers which might otherwise have held
+different values so we use the clobbers list to indicate to the
+compiler not to assume any values loaded into those registers will
+stay valid.
+
+```
+# #![feature(asm)]
+# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+# fn main() { unsafe {
+// Put the value 0x200 in eax
+asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
+# } }
+```
+
+Input and output registers need not be listed since that information
+is already communicated by the given constraints. Otherwise, any other
+registers used either implicitly or explicitly should be listed.
+
+If the assembly changes the condition code register `cc` should be
+specified as one of the clobbers. Similarly, if the assembly modifies
+memory, `memory` should also be specified.
+
+## Options
+
+The last section, `options` is specific to Rust. The format is comma
+separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
+specify some extra info about the inline assembly:
+
+Current valid options are:
+
+1. *volatile* - specifying this is analogous to
+   `__asm__ __volatile__ (...)` in gcc/clang.
+2. *alignstack* - certain instructions expect the stack to be
+   aligned a certain way (i.e. SSE) and specifying this indicates to
+   the compiler to insert its usual stack alignment code
+3. *intel* - use intel syntax instead of the default AT&T.
+
diff --git a/src/doc/trpl/intrinsics.md b/src/doc/trpl/intrinsics.md
new file mode 100644 (file)
index 0000000..25f7c54
--- /dev/null
@@ -0,0 +1,25 @@
+% Intrinsics
+
+> **Note**: intrinsics will forever have an unstable interface, it is
+> recommended to use the stable interfaces of libcore rather than intrinsics
+> directly.
+
+These are imported as if they were FFI functions, with the special
+`rust-intrinsic` ABI. For example, if one was in a freestanding
+context, but wished to be able to `transmute` between types, and
+perform efficient pointer arithmetic, one would import those functions
+via a declaration like
+
+```
+# #![feature(intrinsics)]
+# fn main() {}
+
+extern "rust-intrinsic" {
+    fn transmute<T, U>(x: T) -> U;
+
+    fn offset<T>(dst: *const T, offset: isize) -> *const T;
+}
+```
+
+As with any other FFI functions, these are always `unsafe` to call.
+
diff --git a/src/doc/trpl/lang-items.md b/src/doc/trpl/lang-items.md
new file mode 100644 (file)
index 0000000..30ab59c
--- /dev/null
@@ -0,0 +1,79 @@
+% Lang items
+
+> **Note**: lang items are often provided by crates in the Rust distribution,
+> and lang items themselves have an unstable interface. It is recommended to use
+> officially distributed crates instead of defining your own lang items.
+
+The `rustc` compiler has certain pluggable operations, that is,
+functionality that isn't hard-coded into the language, but is
+implemented in libraries, with a special marker to tell the compiler
+it exists. The marker is the attribute `#[lang="..."]` and there are
+various different values of `...`, i.e. various different 'lang
+items'.
+
+For example, `Box` pointers require two lang items, one for allocation
+and one for deallocation. A freestanding program that uses the `Box`
+sugar for dynamic allocations via `malloc` and `free`:
+
+```
+#![feature(lang_items, box_syntax, start, no_std)]
+#![no_std]
+
+extern crate libc;
+
+extern {
+    fn abort() -> !;
+}
+
+#[lang = "owned_box"]
+pub struct Box<T>(*mut T);
+
+#[lang="exchange_malloc"]
+unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
+    let p = libc::malloc(size as libc::size_t) as *mut u8;
+
+    // malloc failed
+    if p as usize == 0 {
+        abort();
+    }
+
+    p
+}
+#[lang="exchange_free"]
+unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
+    libc::free(ptr as *mut libc::c_void)
+}
+
+#[start]
+fn main(argc: isize, argv: *const *const u8) -> isize {
+    let x = box 1;
+
+    0
+}
+
+#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
+#[lang = "eh_personality"] extern fn eh_personality() {}
+#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
+```
+
+Note the use of `abort`: the `exchange_malloc` lang item is assumed to
+return a valid pointer, and so needs to do the check internally.
+
+Other features provided by lang items include:
+
+- overloadable operators via traits: the traits corresponding to the
+  `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
+  marked with lang items; those specific four are `eq`, `ord`,
+  `deref`, and `add` respectively.
+- stack unwinding and general failure; the `eh_personality`, `fail`
+  and `fail_bounds_checks` lang items.
+- the traits in `std::marker` used to indicate types of
+  various kinds; lang items `send`, `sync` and `copy`.
+- the marker types and variance indicators found in
+  `std::marker`; lang items `covariant_type`,
+  `contravariant_lifetime`, etc.
+
+Lang items are loaded lazily by the compiler; e.g. if one never uses
+`Box` then there is no need to define functions for `exchange_malloc`
+and `exchange_free`. `rustc` will emit an error when an item is needed
+but not found in the current crate or any that it depends on.
diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md
new file mode 100644 (file)
index 0000000..ee5159a
--- /dev/null
@@ -0,0 +1,25 @@
+% Link args
+
+There is one other way to tell rustc how to customize linking, and that is via
+the `link_args` attribute. This attribute is applied to `extern` blocks and
+specifies raw flags which need to get passed to the linker when producing an
+artifact. An example usage would be:
+
+``` no_run
+#![feature(link_args)]
+
+#[link_args = "-foo -bar -baz"]
+extern {}
+# fn main() {}
+```
+
+Note that this feature is currently hidden behind the `feature(link_args)` gate
+because this is not a sanctioned way of performing linking. Right now rustc
+shells out to the system linker, so it makes sense to provide extra command line
+arguments, but this will not always be the case. In the future rustc may use
+LLVM directly to link native libraries in which case `link_args` will have no
+meaning.
+
+It is highly recommended to *not* use this attribute, and rather use the more
+formal `#[link(...)]` attribute on `extern` blocks instead.
+
index 4301149d1f8b3d62a26c07ba395f43976c5c3a5c..28f02b1ffe1528239ba2ba798a12dad126dde496 100644 (file)
@@ -123,7 +123,7 @@ We now loop forever with `loop` and use `break` to break out early.
 iteration. This will only print the odd numbers:
 
 ```{rust}
-for x in 0u32..10 {
+for x in 0..10 {
     if x % 2 == 0 { continue; }
 
     println!("{}", x);
index 8cb16f7ab33406422659b3d3a57eb82a7de220ec..85472ff5db76727dde9dad6ec3a7f226305cb0b8 100644 (file)
@@ -46,7 +46,7 @@ This will print `12.566371`.
 
 We've made a struct that represents a circle. We then write an `impl` block,
 and inside it, define a method, `area`. Methods take a  special first
-parameter, `&self`. There are three variants: `self`, `&self`, and `&mut self`.
+parameter, of which there are three variants: `self`, `&self`, and `&mut self`.
 You can think of this first parameter as being the `x` in `x.foo()`. The three
 variants correspond to the three kinds of thing `x` could be: `self` if it's
 just a value on the stack, `&self` if it's a reference, and `&mut self` if it's
diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md
new file mode 100644 (file)
index 0000000..539a072
--- /dev/null
@@ -0,0 +1,168 @@
+% No stdlib
+
+By default, `std` is linked to every Rust crate. In some contexts,
+this is undesirable, and can be avoided with the `#![no_std]`
+attribute attached to the crate.
+
+```ignore
+// a minimal library
+#![crate_type="lib"]
+#![feature(no_std)]
+#![no_std]
+# // fn main() {} tricked you, rustdoc!
+```
+
+Obviously there's more to life than just libraries: one can use
+`#[no_std]` with an executable, controlling the entry point is
+possible in two ways: the `#[start]` attribute, or overriding the
+default shim for the C `main` function with your own.
+
+The function marked `#[start]` is passed the command line parameters
+in the same format as C:
+
+```
+#![feature(lang_items, start, no_std)]
+#![no_std]
+
+// Pull in the system libc library for what crt0.o likely requires
+extern crate libc;
+
+// Entry point for this program
+#[start]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+
+// These functions and traits are used by the compiler, but not
+// for a bare-bones hello world. These are normally
+// provided by libstd.
+#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
+#[lang = "eh_personality"] extern fn eh_personality() {}
+#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
+# // fn main() {} tricked you, rustdoc!
+```
+
+To override the compiler-inserted `main` shim, one has to disable it
+with `#![no_main]` and then create the appropriate symbol with the
+correct ABI and the correct name, which requires overriding the
+compiler's name mangling too:
+
+```ignore
+#![feature(no_std)]
+#![no_std]
+#![no_main]
+#![feature(lang_items, start)]
+
+extern crate libc;
+
+#[no_mangle] // ensure that this symbol is called `main` in the output
+pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
+    0
+}
+
+#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
+#[lang = "eh_personality"] extern fn eh_personality() {}
+#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
+# // fn main() {} tricked you, rustdoc!
+```
+
+
+The compiler currently makes a few assumptions about symbols which are available
+in the executable to call. Normally these functions are provided by the standard
+library, but without it you must define your own.
+
+The first of these three functions, `stack_exhausted`, is invoked whenever stack
+overflow is detected.  This function has a number of restrictions about how it
+can be called and what it must do, but if the stack limit register is not being
+maintained then a thread always has an "infinite stack" and this function
+shouldn't get triggered.
+
+The second of these three functions, `eh_personality`, is used by the
+failure mechanisms of the compiler. This is often mapped to GCC's
+personality function (see the
+[libstd implementation](../std/rt/unwind/index.html) for more
+information), but crates which do not trigger a panic can be assured
+that this function is never called. The final function, `panic_fmt`, is
+also used by the failure mechanisms of the compiler.
+
+## Using libcore
+
+> **Note**: the core library's structure is unstable, and it is recommended to
+> use the standard library instead wherever possible.
+
+With the above techniques, we've got a bare-metal executable running some Rust
+code. There is a good deal of functionality provided by the standard library,
+however, that is necessary to be productive in Rust. If the standard library is
+not sufficient, then [libcore](../core/index.html) is designed to be used
+instead.
+
+The core library has very few dependencies and is much more portable than the
+standard library itself. Additionally, the core library has most of the
+necessary functionality for writing idiomatic and effective Rust code.
+
+As an example, here is a program that will calculate the dot product of two
+vectors provided from C, using idiomatic Rust practices.
+
+```
+#![feature(lang_items, start, no_std)]
+#![no_std]
+
+# extern crate libc;
+extern crate core;
+
+use core::prelude::*;
+
+use core::mem;
+
+#[no_mangle]
+pub extern fn dot_product(a: *const u32, a_len: u32,
+                          b: *const u32, b_len: u32) -> u32 {
+    use core::raw::Slice;
+
+    // Convert the provided arrays into Rust slices.
+    // The core::raw module guarantees that the Slice
+    // structure has the same memory layout as a &[T]
+    // slice.
+    //
+    // This is an unsafe operation because the compiler
+    // cannot tell the pointers are valid.
+    let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
+        mem::transmute((
+            Slice { data: a, len: a_len as usize },
+            Slice { data: b, len: b_len as usize },
+        ))
+    };
+
+    // Iterate over the slices, collecting the result
+    let mut ret = 0;
+    for (i, j) in a_slice.iter().zip(b_slice.iter()) {
+        ret += (*i) * (*j);
+    }
+    return ret;
+}
+
+#[lang = "panic_fmt"]
+extern fn panic_fmt(args: &core::fmt::Arguments,
+                    file: &str,
+                    line: u32) -> ! {
+    loop {}
+}
+
+#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
+#[lang = "eh_personality"] extern fn eh_personality() {}
+# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
+# fn main() {}
+```
+
+Note that there is one extra lang item here which differs from the examples
+above, `panic_fmt`. This must be defined by consumers of libcore because the
+core library declares panics, but it does not define it. The `panic_fmt`
+lang item is this crate's definition of panic, and it must be guaranteed to
+never return.
+
+As can be seen in this example, the core library is intended to provide the
+power of Rust in all circumstances, regardless of platform requirements. Further
+libraries, such as liballoc, add functionality to libcore which make other
+platform-specific assumptions, but continue to be more portable than the
+standard library itself.
+
index 33f0893466da604ad7472600230c3a5d4a390778..9eb22a7f6985a51bb6e026aaf73896f1a630135a 100644 (file)
@@ -1,29 +1,5 @@
 % Compiler Plugins
 
-<div class="unstable-feature">
-
-<p>
-<b>Warning:</b> Plugins are an advanced, unstable feature! For many details,
-the only available documentation is the <a
-href="../syntax/index.html"><code>libsyntax</code></a> and <a
-href="../rustc/index.html"><code>librustc</code></a> API docs, or even the source
-code itself. These internal compiler APIs are also subject to change at any
-time.
-</p>
-
-<p>
-For defining new syntax it is often much easier to use Rust's <a
-href="macros.html">built-in macro system</a>.
-</p>
-
-<p style="margin-bottom: 0">
-The code in this document uses language features not covered in the Rust
-Guide.  See the <a href="../reference.html">Reference Manual</a> for more
-information.
-</p>
-
-</div>
-
 # Introduction
 
 `rustc` can load compiler plugins, which are user-provided libraries that
index bd9b449fc087e7db4c0aab4b0cba53656063f2a2..107d7d979a09cc8c2db3457aabb28e458f04fc5c 100644 (file)
@@ -568,8 +568,8 @@ fn add(x: &i32, y: &i32) -> i32 {
 fn main() {
     let x = Box::new(5);
 
-    println!("{}", add(&x, &x));
-    println!("{}", add(&x, &x));
+    println!("{}", add(&*x, &*x));
+    println!("{}", add(&*x, &*x));
 }
 ```
 
index a296e1311e6d16472e1df9427dfee03c8971fec1..38af0c94954ca9ba4ee7302ff73235058aaaf31d 100644 (file)
@@ -5,7 +5,8 @@ we haven't seen before. Here's a simple program that reads some input,
 and then prints it back out:
 
 ```{rust,ignore}
-corefn main() {
+# #![feature(old_io)]
+fn main() {
     println!("Type something!");
 
     let input = std::old_io::stdin().read_line().ok().expect("Failed to read line");
diff --git a/src/doc/trpl/tracing-macros.md b/src/doc/trpl/tracing-macros.md
new file mode 100644 (file)
index 0000000..bc337f3
--- /dev/null
@@ -0,0 +1,90 @@
+% Tracing Macros
+
+The `trace_macros` feature allows you to use a special feature: tracing macro
+invocations.
+
+In the advanced macros chapter, we defined a `bct` macro:
+
+```rust
+macro_rules! bct {
+    // cmd 0:  d ... => ...
+    (0, $($ps:tt),* ; $_d:tt)
+        => (bct!($($ps),*, 0 ; ));
+    (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
+        => (bct!($($ps),*, 0 ; $($ds),*));
+
+    // cmd 1p:  1 ... => 1 ... p
+    (1, $p:tt, $($ps:tt),* ; 1)
+        => (bct!($($ps),*, 1, $p ; 1, $p));
+    (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
+        => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
+
+    // cmd 1p:  0 ... => 0 ...
+    (1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
+        => (bct!($($ps),*, 1, $p ; $($ds),*));
+
+    // halt on empty data string
+    ( $($ps:tt),* ; )
+        => (());
+}
+```
+
+This is pretty complex! we can see the output
+
+ ```rust
+#![feature(trace_macros)]
+
+macro_rules! bct {
+    // cmd 0:  d ... => ...
+    (0, $($ps:tt),* ; $_d:tt)
+        => (bct!($($ps),*, 0 ; ));
+    (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
+        => (bct!($($ps),*, 0 ; $($ds),*));
+
+    // cmd 1p:  1 ... => 1 ... p
+    (1, $p:tt, $($ps:tt),* ; 1)
+        => (bct!($($ps),*, 1, $p ; 1, $p));
+    (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
+        => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
+
+    // cmd 1p:  0 ... => 0 ...
+    (1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
+        => (bct!($($ps),*, 1, $p ; $($ds),*));
+
+    // halt on empty data string
+    ( $($ps:tt),* ; )
+        => (());
+}
+
+fn main() {
+    trace_macros!(true);
+
+    bct!(0, 0, 1, 1, 1 ; 1, 0, 1);
+}
+
+This will print out a wall of text:
+
+```text
+bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 }
+bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 }
+bct! { 1 , 1 , 1 , 0 , 0 ; 1 }
+bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 }
+bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 }
+bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 }
+bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 }
+bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 }
+bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 }
+bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 }
+bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 }
+```
+
+And eventually, error:
+
+```text
+18:45 error: recursion limit reached while expanding the macro `bct`
+    => (bct!($($ps),*, 1, $p ; $($ds),*));
+        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+```
+
+The `trace_macros!` call is what produces this output, showing how we match
+each time.
index dbf0cae6f4ba84b852e771e978b94ae84bbb99c5..3ca3cfd05886ee8add73eaa419c16f7c3c4c34b5 100644 (file)
@@ -181,539 +181,3 @@ code:
   that clean-up is always run, even when the thread panics.
 - ensure that any data stored behind a raw pointer is destroyed at the
   appropriate time.
-
-As an example, we give a reimplementation of owned boxes by wrapping
-`malloc` and `free`. Rust's move semantics and lifetimes mean this
-reimplementation is as safe as the `Box` type.
-
-```
-# #![feature(libc)]
-#![feature(unsafe_destructor)]
-
-extern crate libc;
-use libc::{c_void, size_t, malloc, free};
-use std::mem;
-use std::ptr;
-
-// Define a wrapper around the handle returned by the foreign code.
-// Unique<T> has the same semantics as Box<T>
-//
-// NB: For simplicity and correctness, we require that T has kind Send
-// (owned boxes relax this restriction).
-pub struct Unique<T: Send> {
-    // It contains a single raw, mutable pointer to the object in question.
-    ptr: *mut T
-}
-
-// Implement methods for creating and using the values in the box.
-
-impl<T: Send> Unique<T> {
-    pub fn new(value: T) -> Unique<T> {
-        unsafe {
-            let ptr = malloc(mem::size_of::<T>() as size_t) as *mut T;
-            // we *need* valid pointer.
-            assert!(!ptr.is_null());
-            // `*ptr` is uninitialized, and `*ptr = value` would
-            // attempt to destroy it `overwrite` moves a value into
-            // this memory without attempting to drop the original
-            // value.
-            ptr::write(&mut *ptr, value);
-            Unique{ptr: ptr}
-        }
-    }
-
-    // the 'r lifetime results in the same semantics as `&*x` with
-    // Box<T>
-    pub fn borrow<'r>(&'r self) -> &'r T {
-        // By construction, self.ptr is valid
-        unsafe { &*self.ptr }
-    }
-
-    // the 'r lifetime results in the same semantics as `&mut *x` with
-    // Box<T>
-    pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
-        unsafe { &mut *self.ptr }
-    }
-}
-
-// A key ingredient for safety, we associate a destructor with
-// Unique<T>, making the struct manage the raw pointer: when the
-// struct goes out of scope, it will automatically free the raw pointer.
-//
-// NB: This is an unsafe destructor; rustc will not normally allow
-// destructors to be associated with parameterized types (due to
-// historically failing to check them soundly).  Note that the
-// `#[unsafe_destructor]` feature gate is currently required to use
-// unsafe destructors.
-#[unsafe_destructor]
-impl<T: Send> Drop for Unique<T> {
-    fn drop(&mut self) {
-        unsafe {
-            // Copy the object out from the pointer onto the stack,
-            // where it is covered by normal Rust destructor semantics
-            // and cleans itself up, if necessary
-            ptr::read(self.ptr);
-
-            // clean-up our allocation
-            free(self.ptr as *mut c_void)
-        }
-    }
-}
-
-// A comparison between the built-in `Box` and this reimplementation
-fn main() {
-    {
-        let mut x = Box::new(5);
-        *x = 10;
-    } // `x` is freed here
-
-    {
-        let mut y = Unique::new(5);
-        *y.borrow_mut() = 10;
-    } // `y` is freed here
-}
-```
-
-Notably, the only way to construct a `Unique` is via the `new`
-function, and this function ensures that the internal pointer is valid
-and hidden in the private field. The two `borrow` methods are safe
-because the compiler statically guarantees that objects are never used
-before creation or after destruction (unless you use some `unsafe`
-code...).
-
-# Inline assembly
-
-For extremely low-level manipulations and performance reasons, one
-might wish to control the CPU directly. Rust supports using inline
-assembly to do this via the `asm!` macro. The syntax roughly matches
-that of GCC & Clang:
-
-```ignore
-asm!(assembly template
-   : output operands
-   : input operands
-   : clobbers
-   : options
-   );
-```
-
-Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
-crate to allow) and of course requires an `unsafe` block.
-
-> **Note**: the examples here are given in x86/x86-64 assembly, but
-> all platforms are supported.
-
-## Assembly template
-
-The `assembly template` is the only required parameter and must be a
-literal string (i.e. `""`)
-
-```
-#![feature(asm)]
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn foo() {
-    unsafe {
-        asm!("NOP");
-    }
-}
-
-// other platforms
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-fn foo() { /* ... */ }
-
-fn main() {
-    // ...
-    foo();
-    // ...
-}
-```
-
-(The `feature(asm)` and `#[cfg]`s are omitted from now on.)
-
-Output operands, input operands, clobbers and options are all optional
-but you must add the right number of `:` if you skip them:
-
-```
-# #![feature(asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# fn main() { unsafe {
-asm!("xor %eax, %eax"
-    :
-    :
-    : "eax"
-   );
-# } }
-```
-
-Whitespace also doesn't matter:
-
-```
-# #![feature(asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# fn main() { unsafe {
-asm!("xor %eax, %eax" ::: "eax");
-# } }
-```
-
-## Operands
-
-Input and output operands follow the same format: `:
-"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
-expressions must be mutable lvalues:
-
-```
-# #![feature(asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn add(a: i32, b: i32) -> i32 {
-    let mut c = 0;
-    unsafe {
-        asm!("add $2, $0"
-             : "=r"(c)
-             : "0"(a), "r"(b)
-             );
-    }
-    c
-}
-# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-# fn add(a: i32, b: i32) -> i32 { a + b }
-
-fn main() {
-    assert_eq!(add(3, 14159), 14162)
-}
-```
-
-## Clobbers
-
-Some instructions modify registers which might otherwise have held
-different values so we use the clobbers list to indicate to the
-compiler not to assume any values loaded into those registers will
-stay valid.
-
-```
-# #![feature(asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# fn main() { unsafe {
-// Put the value 0x200 in eax
-asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
-# } }
-```
-
-Input and output registers need not be listed since that information
-is already communicated by the given constraints. Otherwise, any other
-registers used either implicitly or explicitly should be listed.
-
-If the assembly changes the condition code register `cc` should be
-specified as one of the clobbers. Similarly, if the assembly modifies
-memory, `memory` should also be specified.
-
-## Options
-
-The last section, `options` is specific to Rust. The format is comma
-separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
-specify some extra info about the inline assembly:
-
-Current valid options are:
-
-1. *volatile* - specifying this is analogous to
-   `__asm__ __volatile__ (...)` in gcc/clang.
-2. *alignstack* - certain instructions expect the stack to be
-   aligned a certain way (i.e. SSE) and specifying this indicates to
-   the compiler to insert its usual stack alignment code
-3. *intel* - use intel syntax instead of the default AT&T.
-
-# Avoiding the standard library
-
-By default, `std` is linked to every Rust crate. In some contexts,
-this is undesirable, and can be avoided with the `#![no_std]`
-attribute attached to the crate.
-
-```ignore
-// a minimal library
-#![crate_type="lib"]
-#![feature(no_std)]
-#![no_std]
-# // fn main() {} tricked you, rustdoc!
-```
-
-Obviously there's more to life than just libraries: one can use
-`#[no_std]` with an executable, controlling the entry point is
-possible in two ways: the `#[start]` attribute, or overriding the
-default shim for the C `main` function with your own.
-
-The function marked `#[start]` is passed the command line parameters
-in the same format as C:
-
-```
-# #![feature(libc)]
-#![feature(lang_items, start, no_std)]
-#![no_std]
-
-// Pull in the system libc library for what crt0.o likely requires
-extern crate libc;
-
-// Entry point for this program
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    0
-}
-
-// These functions and traits are used by the compiler, but not
-// for a bare-bones hello world. These are normally
-// provided by libstd.
-#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
-#[lang = "eh_personality"] extern fn eh_personality() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-# // fn main() {} tricked you, rustdoc!
-```
-
-To override the compiler-inserted `main` shim, one has to disable it
-with `#![no_main]` and then create the appropriate symbol with the
-correct ABI and the correct name, which requires overriding the
-compiler's name mangling too:
-
-```ignore
-# #![feature(libc)]
-#![feature(no_std)]
-#![no_std]
-#![no_main]
-#![feature(lang_items, start)]
-
-extern crate libc;
-
-#[no_mangle] // ensure that this symbol is called `main` in the output
-pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
-    0
-}
-
-#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
-#[lang = "eh_personality"] extern fn eh_personality() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-# // fn main() {} tricked you, rustdoc!
-```
-
-
-The compiler currently makes a few assumptions about symbols which are available
-in the executable to call. Normally these functions are provided by the standard
-library, but without it you must define your own.
-
-The first of these three functions, `stack_exhausted`, is invoked whenever stack
-overflow is detected.  This function has a number of restrictions about how it
-can be called and what it must do, but if the stack limit register is not being
-maintained then a thread always has an "infinite stack" and this function
-shouldn't get triggered.
-
-The second of these three functions, `eh_personality`, is used by the
-failure mechanisms of the compiler. This is often mapped to GCC's
-personality function (see the
-[libstd implementation](../std/rt/unwind/index.html) for more
-information), but crates which do not trigger a panic can be assured
-that this function is never called. The final function, `panic_fmt`, is
-also used by the failure mechanisms of the compiler.
-
-## Using libcore
-
-> **Note**: the core library's structure is unstable, and it is recommended to
-> use the standard library instead wherever possible.
-
-With the above techniques, we've got a bare-metal executable running some Rust
-code. There is a good deal of functionality provided by the standard library,
-however, that is necessary to be productive in Rust. If the standard library is
-not sufficient, then [libcore](../core/index.html) is designed to be used
-instead.
-
-The core library has very few dependencies and is much more portable than the
-standard library itself. Additionally, the core library has most of the
-necessary functionality for writing idiomatic and effective Rust code.
-
-As an example, here is a program that will calculate the dot product of two
-vectors provided from C, using idiomatic Rust practices.
-
-```
-# #![feature(libc, core)]
-#![feature(lang_items, start, no_std)]
-#![no_std]
-
-# extern crate libc;
-extern crate core;
-
-use core::prelude::*;
-
-use core::mem;
-
-#[no_mangle]
-pub extern fn dot_product(a: *const u32, a_len: u32,
-                          b: *const u32, b_len: u32) -> u32 {
-    use core::raw::Slice;
-
-    // Convert the provided arrays into Rust slices.
-    // The core::raw module guarantees that the Slice
-    // structure has the same memory layout as a &[T]
-    // slice.
-    //
-    // This is an unsafe operation because the compiler
-    // cannot tell the pointers are valid.
-    let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
-        mem::transmute((
-            Slice { data: a, len: a_len as usize },
-            Slice { data: b, len: b_len as usize },
-        ))
-    };
-
-    // Iterate over the slices, collecting the result
-    let mut ret = 0;
-    for (i, j) in a_slice.iter().zip(b_slice.iter()) {
-        ret += (*i) * (*j);
-    }
-    return ret;
-}
-
-#[lang = "panic_fmt"]
-extern fn panic_fmt(args: &core::fmt::Arguments,
-                    file: &str,
-                    line: u32) -> ! {
-    loop {}
-}
-
-#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
-#[lang = "eh_personality"] extern fn eh_personality() {}
-# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
-# fn main() {}
-```
-
-Note that there is one extra lang item here which differs from the examples
-above, `panic_fmt`. This must be defined by consumers of libcore because the
-core library declares panics, but it does not define it. The `panic_fmt`
-lang item is this crate's definition of panic, and it must be guaranteed to
-never return.
-
-As can be seen in this example, the core library is intended to provide the
-power of Rust in all circumstances, regardless of platform requirements. Further
-libraries, such as liballoc, add functionality to libcore which make other
-platform-specific assumptions, but continue to be more portable than the
-standard library itself.
-
-# Interacting with the compiler internals
-
-> **Note**: this section is specific to the `rustc` compiler; these
-> parts of the language may never be fully specified and so details may
-> differ wildly between implementations (and even versions of `rustc`
-> itself).
->
-> Furthermore, this is just an overview; the best form of
-> documentation for specific instances of these features are their
-> definitions and uses in `std`.
-
-The Rust language currently has two orthogonal mechanisms for allowing
-libraries to interact directly with the compiler and vice versa:
-
-- intrinsics, functions built directly into the compiler providing
-  very basic low-level functionality,
-- lang-items, special functions, types and traits in libraries marked
-  with specific `#[lang]` attributes
-
-## Intrinsics
-
-> **Note**: intrinsics will forever have an unstable interface, it is
-> recommended to use the stable interfaces of libcore rather than intrinsics
-> directly.
-
-These are imported as if they were FFI functions, with the special
-`rust-intrinsic` ABI. For example, if one was in a freestanding
-context, but wished to be able to `transmute` between types, and
-perform efficient pointer arithmetic, one would import those functions
-via a declaration like
-
-```
-# #![feature(intrinsics)]
-# fn main() {}
-
-extern "rust-intrinsic" {
-    fn transmute<T, U>(x: T) -> U;
-
-    fn offset<T>(dst: *const T, offset: isize) -> *const T;
-}
-```
-
-As with any other FFI functions, these are always `unsafe` to call.
-
-## Lang items
-
-> **Note**: lang items are often provided by crates in the Rust distribution,
-> and lang items themselves have an unstable interface. It is recommended to use
-> officially distributed crates instead of defining your own lang items.
-
-The `rustc` compiler has certain pluggable operations, that is,
-functionality that isn't hard-coded into the language, but is
-implemented in libraries, with a special marker to tell the compiler
-it exists. The marker is the attribute `#[lang="..."]` and there are
-various different values of `...`, i.e. various different 'lang
-items'.
-
-For example, `Box` pointers require two lang items, one for allocation
-and one for deallocation. A freestanding program that uses the `Box`
-sugar for dynamic allocations via `malloc` and `free`:
-
-```
-# #![feature(libc)]
-#![feature(lang_items, box_syntax, start, no_std)]
-#![no_std]
-
-extern crate libc;
-
-extern {
-    fn abort() -> !;
-}
-
-#[lang = "owned_box"]
-pub struct Box<T>(*mut T);
-
-#[lang="exchange_malloc"]
-unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
-    let p = libc::malloc(size as libc::size_t) as *mut u8;
-
-    // malloc failed
-    if p as usize == 0 {
-        abort();
-    }
-
-    p
-}
-#[lang="exchange_free"]
-unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
-    libc::free(ptr as *mut libc::c_void)
-}
-
-#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
-    let x = box 1;
-
-    0
-}
-
-#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
-#[lang = "eh_personality"] extern fn eh_personality() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-```
-
-Note the use of `abort`: the `exchange_malloc` lang item is assumed to
-return a valid pointer, and so needs to do the check internally.
-
-Other features provided by lang items include:
-
-- overloadable operators via traits: the traits corresponding to the
-  `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
-  marked with lang items; those specific four are `eq`, `ord`,
-  `deref`, and `add` respectively.
-- stack unwinding and general failure; the `eh_personality`, `fail`
-  and `fail_bounds_checks` lang items.
-- the traits in `std::marker` used to indicate types of
-  various kinds; lang items `send`, `sync` and `copy`.
-- the marker types and variance indicators found in
-  `std::marker`; lang items `covariant_type`,
-  `contravariant_lifetime`, etc.
-
-Lang items are loaded lazily by the compiler; e.g. if one never uses
-`Box` then there is no need to define functions for `exchange_malloc`
-and `exchange_free`. `rustc` will emit an error when an item is needed
-but not found in the current crate or any that it depends on.
index b5d16d29272850843e9204749c68e6be9165d56d..338d7e336316474e1d59f2cafea68bf989e46f38 100644 (file)
@@ -33,7 +33,7 @@
 //!
 //! Sharing some immutable data between tasks:
 //!
-//! ```
+//! ```no_run
 //! use std::sync::Arc;
 //! use std::thread;
 //!
@@ -50,7 +50,7 @@
 //!
 //! Sharing mutable data safely between tasks with a `Mutex`:
 //!
-//! ```
+//! ```no_run
 //! use std::sync::{Arc, Mutex};
 //! use std::thread;
 //!
@@ -94,6 +94,9 @@
 /// With simple pipes, without `Arc`, a copy would have to be made for each
 /// task.
 ///
+/// When you clone an `Arc<T>`, it will create another pointer to the data and
+/// increase the reference counter.
+///
 /// ```
 /// # #![feature(alloc, core)]
 /// use std::sync::Arc;
@@ -354,7 +357,8 @@ fn drop(&mut self) {
         // more than once (but it is guaranteed to be zeroed after the first if
         // it's run more than once)
         let ptr = *self._ptr;
-        if ptr.is_null() { return }
+        // if ptr.is_null() { return }
+        if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
 
         // Because `fetch_sub` is already atomic, we do not need to synchronize
         // with other threads unless we are going to delete the object. This
@@ -485,7 +489,7 @@ fn drop(&mut self) {
         let ptr = *self._ptr;
 
         // see comments above for why this check is here
-        if ptr.is_null() { return }
+        if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
 
         // If we find out that we were the last weak pointer, then its time to
         // deallocate the data entirely. See the discussion in Arc::drop() about
index 8b18fbf554a4cad6218fb0bf99b79135c637aa1b..f9bd0ab2f1e0fdbe1e3cb88fcb61413d1e21b8b6 100644 (file)
@@ -244,13 +244,13 @@ pub trait BoxAny {
     /// Returns the boxed value if it is of type `T`, or
     /// `Err(Self)` if it isn't.
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>>;
+    fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>>;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl BoxAny for Box<Any> {
     #[inline]
-    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
+    fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
         if self.is::<T>() {
             unsafe {
                 // Get the raw representation of the trait object
@@ -270,7 +270,7 @@ fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl BoxAny for Box<Any+Send> {
     #[inline]
-    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
+    fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
         <Box<Any>>::downcast(self)
     }
 }
index 541de2d37fbe0cf68f47a6c51d6c9df8e96a2203..b92dfa9117e6beb5745f97c106a758ebfedef1fe 100644 (file)
@@ -75,7 +75,7 @@
 #![feature(box_syntax)]
 #![feature(optin_builtin_traits)]
 #![feature(unboxed_closures)]
-#![feature(unsafe_no_drop_flag)]
+#![feature(unsafe_no_drop_flag, filling_drop)]
 #![feature(core)]
 #![feature(unique)]
 #![cfg_attr(test, feature(test, alloc, rustc_private))]
index eb3c5c167268bfe143f68dbef5fb449e6443b8b9..7cdd48884262182d4c30ee873acc3c082011e863 100644 (file)
 use core::fmt;
 use core::hash::{Hasher, Hash};
 use core::marker;
-use core::mem::{min_align_of, size_of, forget};
+use core::mem::{self, min_align_of, size_of, forget};
 use core::nonzero::NonZero;
 use core::ops::{Deref, Drop};
 use core::option::Option;
@@ -407,7 +407,7 @@ impl<T> Drop for Rc<T> {
     fn drop(&mut self) {
         unsafe {
             let ptr = *self._ptr;
-            if !ptr.is_null() {
+            if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
                 self.dec_strong();
                 if self.strong() == 0 {
                     ptr::read(&**self); // destroy the contained object
@@ -431,7 +431,8 @@ impl<T> Clone for Rc<T> {
 
     /// Makes a clone of the `Rc<T>`.
     ///
-    /// This increases the strong reference count.
+    /// When you clone an `Rc<T>`, it will create another pointer to the data and
+    /// increase the strong reference counter.
     ///
     /// # Examples
     ///
@@ -718,7 +719,7 @@ impl<T> Drop for Weak<T> {
     fn drop(&mut self) {
         unsafe {
             let ptr = *self._ptr;
-            if !ptr.is_null() {
+            if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
                 self.dec_weak();
                 // the weak count starts at 1, and will only go to zero if all
                 // the strong pointers have disappeared.
index c2f6fbc0b2602cb62c537c23d9c2eb3c9e3905c9..04a692cc3aea2b59d63675bb648ddcd900418d4b 100644 (file)
@@ -1143,15 +1143,39 @@ fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { self.inner.next_back() }
 }
 
 impl<'a, K: Ord, V> Entry<'a, K, V> {
-    /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
     #[unstable(feature = "std_misc",
                reason = "will soon be replaced by or_insert")]
+    #[deprecated(since = "1.0",
+                reason = "replaced with more ergonomic `or_insert` and `or_insert_with`")]
+    /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
     pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, K, V>> {
         match self {
             Occupied(entry) => Ok(entry.into_mut()),
             Vacant(entry) => Err(entry),
         }
     }
+
+    #[unstable(feature = "collections",
+               reason = "matches entry v3 specification, waiting for dust to settle")]
+    /// Ensures a value is in the entry by inserting the default if empty, and returns
+    /// a mutable reference to the value in the entry.
+    pub fn or_insert(self, default: V) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default),
+        }
+    }
+
+    #[unstable(feature = "collections",
+               reason = "matches entry v3 specification, waiting for dust to settle")]
+    /// Ensures a value is in the entry by inserting the result of the default function if empty,
+    /// and returns a mutable reference to the value in the entry.
+    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default()),
+        }
+    }
 }
 
 impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
@@ -1563,21 +1587,12 @@ pub fn range_mut<'a>(&'a mut self, min: Bound<&K>, max: Bound<&K>) -> RangeMut<'
     /// ```
     /// # #![feature(collections)]
     /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
     ///
     /// let mut count: BTreeMap<&str, usize> = BTreeMap::new();
     ///
     /// // count the number of occurrences of letters in the vec
-    /// for x in vec!["a","b","a","c","a","b"].iter() {
-    ///     match count.entry(*x) {
-    ///         Entry::Vacant(view) => {
-    ///             view.insert(1);
-    ///         },
-    ///         Entry::Occupied(mut view) => {
-    ///             let v = view.get_mut();
-    ///             *v += 1;
-    ///         },
-    ///     }
+    /// for x in vec!["a","b","a","c","a","b"] {
+    ///     *count.entry(x).or_insert(0) += 1;
     /// }
     ///
     /// assert_eq!(count["a"], 3);
index 23eafa41d8a01d4075737d74cae3b39171b6a5cd..bf57d745a0dcea07b244f2393d1c9bb8b5f77987 100644 (file)
@@ -280,9 +280,11 @@ fn drop(&mut self) {
 #[unsafe_destructor]
 impl<K, V> Drop for Node<K, V> {
     fn drop(&mut self) {
-        if self.keys.is_null() {
+        if self.keys.is_null() ||
+            (unsafe { self.keys.get() as *const K as usize == mem::POST_DROP_USIZE })
+        {
             // Since we have #[unsafe_no_drop_flag], we have to watch
-            // out for a null value being stored in self.keys. (Using
+            // out for the sentinel value being stored in self.keys. (Using
             // null is technically a violation of the `Unique`
             // requirements, though.)
             return;
index 2e6a35277062414022b8447aff66435ccb22a151..3a05409680710255d4738cd6a72ff00e19f7711f 100644 (file)
@@ -35,7 +35,7 @@
 #![feature(unicode)]
 #![feature(unsafe_destructor)]
 #![feature(unique)]
-#![feature(unsafe_no_drop_flag)]
+#![feature(unsafe_no_drop_flag, filling_drop)]
 #![feature(step_by)]
 #![feature(str_char)]
 #![feature(convert)]
index 688d730e2528744c03f49903d7928a0610384a29..83e632e6c9676fef00036319fc5cd7c652c16e0a 100644 (file)
@@ -611,9 +611,11 @@ pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
         core_slice::SliceExt::get_mut(self, index)
     }
 
-    /// Work with `self` as a mut slice.
-    /// Primarily intended for getting a &mut [T] from a [T; N].
-    #[stable(feature = "rust1", since = "1.0.0")]
+    /// Deprecated: use `&mut s[..]` instead.
+    #[unstable(feature = "collections",
+               reason = "will be replaced by slice syntax")]
+    #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
+    #[allow(deprecated)]
     pub fn as_mut_slice(&mut self) -> &mut [T] {
         core_slice::SliceExt::as_mut_slice(self)
     }
index e71077c96c774a4acbfb7bdf5174138ae39dd08e..95cb949ae6c9c36462b9e632d2857b4ff59fea27 100644 (file)
@@ -423,24 +423,13 @@ pub fn truncate(&mut self, len: usize) {
         }
     }
 
-    /// Returns a mutable slice of the elements of `self`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// fn foo(slice: &mut [i32]) {}
-    ///
-    /// let mut vec = vec![1, 2];
-    /// foo(vec.as_mut_slice());
-    /// ```
+    /// Deprecated: use `&mut s[..]` instead.
     #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
+    #[unstable(feature = "collections",
+               reason = "will be replaced by slice syntax")]
+    #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
     pub fn as_mut_slice(&mut self) -> &mut [T] {
-        unsafe {
-            let ptr = *self.ptr;
-            assume(!ptr.is_null());
-            slice::from_raw_parts_mut(ptr, self.len)
-        }
+        &mut self[..]
     }
 
     /// Creates a consuming iterator, that is, one that moves each value out of
@@ -1494,13 +1483,13 @@ 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()
+        self
     }
 
     #[cfg(not(stage0))]
     #[inline]
     fn index_mut(&mut self, _index: ops::RangeFull) -> &mut [T] {
-        self.as_mut_slice()
+        self
     }
 }
 
@@ -1519,7 +1508,13 @@ fn deref(&self) -> &[T] {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ops::DerefMut for Vec<T> {
-    fn deref_mut(&mut self) -> &mut [T] { self.as_mut_slice() }
+    fn deref_mut(&mut self) -> &mut [T] {
+        unsafe {
+            let ptr = *self.ptr;
+            assume(!ptr.is_null());
+            slice::from_raw_parts_mut(ptr, self.len)
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1656,21 +1651,13 @@ fn cmp(&self, other: &Vec<T>) -> Ordering {
     }
 }
 
+#[unstable(feature = "collections",
+           reason = "will be replaced by slice syntax")]
+#[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
 #[allow(deprecated)]
 impl<T> AsSlice<T> for Vec<T> {
-    /// Returns a slice into `self`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(core)]
-    /// fn foo(slice: &[i32]) {}
-    ///
-    /// let vec = vec![1, 2];
-    /// foo(vec.as_slice());
-    /// ```
+    /// Deprecated: use `&mut s[..]` instead.
     #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
     fn as_slice(&self) -> &[T] {
         self
     }
@@ -1694,7 +1681,7 @@ impl<T> Drop for Vec<T> {
     fn drop(&mut self) {
         // This is (and should always remain) a no-op if the fields are
         // zeroed (when moving out, because of #[unsafe_no_drop_flag]).
-        if self.cap != 0 {
+        if self.cap != 0 && self.cap != mem::POST_DROP_USIZE {
             unsafe {
                 for x in &*self {
                     ptr::read(x);
@@ -1977,7 +1964,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Drop for Drain<'a, T> {
     fn drop(&mut self) {
-        // self.ptr == self.end == null if drop has already been called,
+        // self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
         // so we can use #[unsafe_no_drop_flag].
 
         // destroy the remaining elements
index af9db46f810b96b4a3fac3fcb3e97ef50f4cfb1f..a9884b80e42045d6890b8d9885e89b2d8365392a 100644 (file)
@@ -553,7 +553,7 @@ pub fn iter(&self) -> Iter<T> {
     ///     *num = *num - 2;
     /// }
     /// let b: &[_] = &[&mut 3, &mut 1, &mut 2];
-    /// assert_eq!(&buf.iter_mut().collect::<Vec<&mut i32>>()[], b);
+    /// assert_eq!(&buf.iter_mut().collect::<Vec<&mut i32>>()[..], b);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<T> {
index c994064d34724e8917c809c7a20f23725b5b6f66..58f9101d1d366046597aa756dcc5ab7eafc19f39 100644 (file)
@@ -632,21 +632,12 @@ pub fn remove(&mut self, key: &usize) -> Option<V> {
     /// ```
     /// # #![feature(collections)]
     /// use std::collections::VecMap;
-    /// use std::collections::vec_map::Entry;
     ///
     /// let mut count: VecMap<u32> = VecMap::new();
     ///
     /// // count the number of occurrences of numbers in the vec
-    /// for x in vec![1, 2, 1, 2, 3, 4, 1, 2, 4].iter() {
-    ///     match count.entry(*x) {
-    ///         Entry::Vacant(view) => {
-    ///             view.insert(1);
-    ///         },
-    ///         Entry::Occupied(mut view) => {
-    ///             let v = view.get_mut();
-    ///             *v += 1;
-    ///         },
-    ///     }
+    /// for x in vec![1, 2, 1, 2, 3, 4, 1, 2, 4] {
+    ///     *count.entry(x).or_insert(0) += 1;
     /// }
     ///
     /// assert_eq!(count[1], 3);
@@ -675,6 +666,8 @@ pub fn entry(&mut self, key: usize) -> Entry<V> {
 impl<'a, V> Entry<'a, V> {
     #[unstable(feature = "collections",
                reason = "will soon be replaced by or_insert")]
+    #[deprecated(since = "1.0",
+                reason = "replaced with more ergonomic `or_insert` and `or_insert_with`")]
     /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
     pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, V>> {
         match self {
@@ -682,6 +675,28 @@ pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, V>> {
             Vacant(entry) => Err(entry),
         }
     }
+
+    #[unstable(feature = "collections",
+               reason = "matches entry v3 specification, waiting for dust to settle")]
+    /// Ensures a value is in the entry by inserting the default if empty, and returns
+    /// a mutable reference to the value in the entry.
+    pub fn or_insert(self, default: V) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default),
+        }
+    }
+
+    #[unstable(feature = "collections",
+               reason = "matches entry v3 specification, waiting for dust to settle")]
+    /// Ensures a value is in the entry by inserting the result of the default function if empty,
+    /// and returns a mutable reference to the value in the entry.
+    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default()),
+        }
+    }
 }
 
 impl<'a, V> VacantEntry<'a, V> {
index c94d8e2ed0c8d8d5ee79f0743ff6a826c30968cd..d3bc07b173ac8e963f5541204ab68e3fded38731 100644 (file)
@@ -55,7 +55,7 @@
 //! }
 //!
 //! // This function wants to log its parameter out prior to doing work with it.
-//! fn do_work<T: Debug + 'static>(value: &T) {
+//! fn do_work<T: Any + Debug>(value: &T) {
 //!     log(value);
 //!     // ...do some other work
 //! }
@@ -76,7 +76,7 @@
 use option::Option::{self, Some, None};
 use raw::TraitObject;
 use intrinsics;
-use marker::Sized;
+use marker::{Reflect, Sized};
 
 ///////////////////////////////////////////////////////////////////////////////
 // Any trait
 ///
 /// [mod]: ../index.html
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait Any: 'static {
+pub trait Any: Reflect + 'static {
     /// Get the `TypeId` of `self`
     #[unstable(feature = "core",
                reason = "this method will likely be replaced by an associated static")]
     fn get_type_id(&self) -> TypeId;
 }
 
-impl<T: 'static> Any for T {
+impl<T> Any for T
+    where T: Reflect + 'static
+{
     fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
 }
 
@@ -107,7 +109,7 @@ impl Any {
     /// Returns true if the boxed type is the same as `T`
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn is<T: 'static>(&self) -> bool {
+    pub fn is<T: Any>(&self) -> bool {
         // Get TypeId of the type this function is instantiated with
         let t = TypeId::of::<T>();
 
@@ -122,7 +124,7 @@ pub fn is<T: 'static>(&self) -> bool {
     /// `None` if it isn't.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
+    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
         if self.is::<T>() {
             unsafe {
                 // Get the raw representation of the trait object
@@ -140,7 +142,7 @@ pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
     /// `None` if it isn't.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
+    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
         if self.is::<T>() {
             unsafe {
                 // Get the raw representation of the trait object
@@ -159,21 +161,21 @@ impl Any+Send {
     /// Forwards to the method defined on the type `Any`.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn is<T: 'static>(&self) -> bool {
+    pub fn is<T: Any>(&self) -> bool {
         Any::is::<T>(self)
     }
 
     /// Forwards to the method defined on the type `Any`.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
+    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
         Any::downcast_ref::<T>(self)
     }
 
     /// Forwards to the method defined on the type `Any`.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
+    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
         Any::downcast_mut::<T>(self)
     }
 }
@@ -202,7 +204,7 @@ impl TypeId {
     /// instantiated with
     #[unstable(feature = "core",
                reason = "may grow a `Reflect` bound soon via marker traits")]
-    pub fn of<T: ?Sized + 'static>() -> TypeId {
+    pub fn of<T: ?Sized + Any>() -> TypeId {
         TypeId {
             t: unsafe { intrinsics::type_id::<T>() },
         }
index b2c23f051d5f1d1b96dd9eecd3b71915717c4078..91301ee558ca566315559f663a6948d11519f2ba 100644 (file)
@@ -18,6 +18,7 @@
 
 use clone::Clone;
 use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use convert::{AsRef, AsMut};
 use fmt;
 use hash::{Hash, self};
 use iter::IntoIterator;
@@ -53,6 +54,24 @@ fn as_mut_slice(&mut self) -> &mut [T] {
                 }
             }
 
+            #[unstable(feature = "array_as_ref",
+                       reason = "should ideally be implemented for all fixed-sized arrays")]
+            impl<T> AsRef<[T]> for [T; $N] {
+                #[inline]
+                fn as_ref(&self) -> &[T] {
+                    &self[..]
+                }
+            }
+
+            #[unstable(feature = "array_as_ref",
+                       reason = "should ideally be implemented for all fixed-sized arrays")]
+            impl<T> AsMut<[T]> for [T; $N] {
+                #[inline]
+                fn as_mut(&mut self) -> &mut [T] {
+                    &mut self[..]
+                }
+            }
+
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<T:Copy> Clone for [T; $N] {
                 fn clone(&self) -> [T; $N] {
index 65a226d37cbc038c80f38c3ef532bc66a2c27ac6..21f9b1f5513aaaf7f7c8d5184616c3f3552371b8 100644 (file)
@@ -69,6 +69,14 @@ fn as_ref(&self) -> &U {
     }
 }
 
+// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
+// // As lifts over Deref
+// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
+//     fn as_ref(&self) -> &U {
+//         self.deref().as_ref()
+//     }
+// }
+
 // 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 {
@@ -83,6 +91,14 @@ fn as_mut(&mut self) -> &mut U {
     }
 }
 
+// FIXME (#23442): replace the above impl for &mut with the following more general one:
+// // AsMut lifts over DerefMut
+// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
+//     fn as_mut(&mut self) -> &mut U {
+//         self.deref_mut().as_mut()
+//     }
+// }
+
 // From implies Into
 impl<T, U> Into<U> for T where U: From<T> {
     fn into(self) -> U {
index 1f1044b0b21520d0148877edbe132faf6e9c5a6e..eb74a41db55e354f43641559f796d514ad0db26d 100644 (file)
     /// crate it is invoked in.
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
+    /// Create a value initialized to so that its drop flag,
+    /// if any, says that it has been dropped.
+    ///
+    /// `init_dropped` is unsafe because it returns a datum with all
+    /// of its bytes set to the drop flag, which generally does not
+    /// correspond to a valid value.
+    ///
+    /// This intrinsic is likely to be deprecated in the future when
+    /// Rust moves to non-zeroing dynamic drop (and thus removes the
+    /// embedded drop flags that are being established by this
+    /// intrinsic).
+    #[cfg(not(stage0))]
+    pub fn init_dropped<T>() -> T;
+
     /// Create a value initialized to zero.
     ///
     /// `init` is unsafe because it returns a zeroed-out datum,
-    /// which is unsafe unless T is Copy.
+    /// which is unsafe unless T is `Copy`.  Also, even if T is
+    /// `Copy`, an all-zero value may not correspond to any legitimate
+    /// state for the type in question.
     pub fn init<T>() -> T;
 
     /// Create an uninitialized value.
+    ///
+    /// `uninit` is unsafe because there is no guarantee of what its
+    /// contents are. In particular its drop-flag may be set to any
+    /// state, which means it may claim either dropped or
+    /// undropped. In the general case one must use `ptr::write` to
+    /// initialize memory previous set to the result of `uninit`.
     pub fn uninit<T>() -> T;
 
     /// Move a value out of scope without running drop glue.
index a2b13584270940317f8935b3a7674d5e4d841b22..7225b016e6ba645c6a8315b1159dbd14517e3145 100644 (file)
@@ -72,6 +72,7 @@
 #![feature(rustc_attrs)]
 #![feature(optin_builtin_traits)]
 #![feature(concat_idents)]
+#![feature(reflect)]
 
 #[macro_use]
 mod macros;
index 88c10e3661e7a7714bea28e9c8f7d6788cbcf743..35fde2cb64a310e029b14f626ac7aeb92f3c668b 100644 (file)
@@ -450,3 +450,46 @@ unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
 #[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<T>>`")]
 #[lang="invariant_type"]
 pub struct InvariantType<T>;
+
+/// A marker trait indicates a type that can be reflected over. This
+/// trait is implemented for all types. Its purpose is to ensure that
+/// when you write a generic function that will employ reflection,
+/// that must be reflected (no pun intended) in the generic bounds of
+/// that function. Here is an example:
+///
+/// ```
+/// #![feature(core)]
+/// use std::marker::Reflect;
+/// use std::any::Any;
+/// fn foo<T:Reflect+'static>(x: &T) {
+///     let any: &Any = x;
+///     if any.is::<u32>() { println!("u32"); }
+/// }
+/// ```
+///
+/// Without the declaration `T:Reflect`, `foo` would not type check
+/// (note: as a matter of style, it would be preferable to to write
+/// `T:Any`, because `T:Any` implies `T:Reflect` and `T:'static`, but
+/// we use `Reflect` here to show how it works). The `Reflect` bound
+/// thus serves to alert `foo`'s caller to the fact that `foo` may
+/// behave differently depending on whether `T=u32` or not. In
+/// particular, thanks to the `Reflect` bound, callers know that a
+/// function declared like `fn bar<T>(...)` will always act in
+/// precisely the same way no matter what type `T` is supplied,
+/// beacuse there are no bounds declared on `T`. (The ability for a
+/// caller to reason about what a function may do based solely on what
+/// generic bounds are declared is often called the ["parametricity
+/// property"][1].)
+///
+/// [1]: http://en.wikipedia.org/wiki/Parametricity
+#[rustc_reflect_like]
+#[unstable(feature = "core", reason = "requires RFC and more experience")]
+pub trait Reflect : MarkerTrait {
+}
+
+#[cfg(stage0)]
+impl<T> Reflect for T { }
+
+#[cfg(not(stage0))]
+impl Reflect for .. { }
+
index 1e6fb51a8a528e9d75bac0d6fa36da598104f057..434a5d17a9254cd6cf1627cd7d2129f81808621c 100644 (file)
@@ -158,6 +158,32 @@ pub unsafe fn zeroed<T>() -> T {
     intrinsics::init()
 }
 
+/// Create a value initialized to an unspecified series of bytes.
+///
+/// The byte sequence usually indicates that the value at the memory
+/// in question has been dropped. Thus, *if* T carries a drop flag,
+/// any associated destructor will not be run when the value falls out
+/// of scope.
+///
+/// Some code at one time used the `zeroed` function above to
+/// accomplish this goal.
+///
+/// This function is expected to be deprecated with the transition
+/// to non-zeroing drop.
+#[inline]
+#[unstable(feature = "filling_drop")]
+pub unsafe fn dropped<T>() -> T {
+    #[cfg(stage0)]
+    #[inline(always)]
+    unsafe fn dropped_impl<T>() -> T { zeroed() }
+
+    #[cfg(not(stage0))]
+    #[inline(always)]
+    unsafe fn dropped_impl<T>() -> T { intrinsics::init_dropped() }
+
+    dropped_impl()
+}
+
 /// Create an uninitialized value.
 ///
 /// Care must be taken when using this function, if the type `T` has a destructor and the value
@@ -291,6 +317,49 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn drop<T>(_x: T) { }
 
+macro_rules! repeat_u8_as_u32 {
+    ($name:expr) => { (($name as u32) << 24 |
+                       ($name as u32) << 16 |
+                       ($name as u32) <<  8 |
+                       ($name as u32)) }
+}
+macro_rules! repeat_u8_as_u64 {
+    ($name:expr) => { ((repeat_u8_as_u32!($name) as u64) << 32 |
+                       (repeat_u8_as_u32!($name) as u64)) }
+}
+
+// NOTE: Keep synchronized with values used in librustc_trans::trans::adt.
+//
+// In particular, the POST_DROP_U8 marker must never equal the
+// DTOR_NEEDED_U8 marker.
+//
+// For a while pnkfelix was using 0xc1 here.
+// But having the sign bit set is a pain, so 0x1d is probably better.
+//
+// And of course, 0x00 brings back the old world of zero'ing on drop.
+#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+pub const POST_DROP_U8: u8 = 0x1d;
+#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8);
+#[cfg(not(stage0))]  #[unstable(feature = "filling_drop")]
+pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8);
+
+#[cfg(target_pointer_width = "32")]
+#[cfg(not(stage0))]  #[unstable(feature = "filling_drop")]
+pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize;
+#[cfg(target_pointer_width = "64")]
+#[cfg(not(stage0))]  #[unstable(feature = "filling_drop")]
+pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize;
+
+#[cfg(stage0)]  #[unstable(feature = "filling_drop")]
+pub const POST_DROP_U8: u8 = 0;
+#[cfg(stage0)]  #[unstable(feature = "filling_drop")]
+pub const POST_DROP_U32: u32 = 0;
+#[cfg(stage0)]  #[unstable(feature = "filling_drop")]
+pub const POST_DROP_U64: u64 = 0;
+#[cfg(stage0)]  #[unstable(feature = "filling_drop")]
+pub const POST_DROP_USIZE: usize = 0;
+
 /// Interprets `src` as `&U`, and then reads `src` without moving the contained value.
 ///
 /// This function will unsafely assume the pointer `src` is valid for `sizeof(U)` bytes by
index a565b137cc852a5f84cd33885f87f0a954cd3e13..368d56f515e55b2fa47112cc76b67bdaef8ab1e2 100644 (file)
@@ -320,7 +320,7 @@ pub fn as_mut_slice<'r>(&'r mut self) -> &'r mut [T] {
     /// assert_eq!(x.expect("the world is ending"), "value");
     /// ```
     ///
-    /// ```{.should_fail}
+    /// ```{.should_panic}
     /// let x: Option<&str> = None;
     /// x.expect("the world is ending"); // panics with `world is ending`
     /// ```
@@ -352,7 +352,7 @@ pub fn expect(self, msg: &str) -> T {
     /// assert_eq!(x.unwrap(), "air");
     /// ```
     ///
-    /// ```{.should_fail}
+    /// ```{.should_panic}
     /// let x: Option<&str> = None;
     /// assert_eq!(x.unwrap(), "air"); // fails
     /// ```
@@ -480,7 +480,7 @@ pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, def: D, f: F) -
     /// assert_eq!(x.ok_or(0), Err(0));
     /// ```
     #[inline]
-    #[unstable(feature = "core")]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn ok_or<E>(self, err: E) -> Result<T, E> {
         match self {
             Some(v) => Ok(v),
@@ -502,7 +502,7 @@ pub fn ok_or<E>(self, err: E) -> Result<T, E> {
     /// assert_eq!(x.ok_or_else(|| 0), Err(0));
     /// ```
     #[inline]
-    #[unstable(feature = "core")]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
         match self {
             Some(v) => Ok(v),
@@ -548,8 +548,7 @@ pub fn iter(&self) -> Iter<T> {
     /// assert_eq!(x.iter_mut().next(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "core",
-               reason = "waiting for iterator conventions")]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<T> {
         IterMut { inner: Item { opt: self.as_mut() } }
     }
@@ -721,13 +720,11 @@ pub fn as_slice<'a>(&'a self) -> &'a [T] {
     }
 }
 
-impl<'a, T: Clone, D: Deref<Target=T>> Option<D> {
-    /// Maps an Option<D> to an Option<T> by dereffing and cloning the contents of the Option.
-    /// Useful for converting an Option<&T> to an Option<T>.
-    #[unstable(feature = "core",
-               reason = "recently added as part of collections reform")]
+impl<'a, T: Clone> Option<&'a T> {
+    /// Maps an Option<&T> to an Option<T> by cloning the contents of the Option.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn cloned(self) -> Option<T> {
-        self.map(|t| t.deref().clone())
+        self.map(|t| t.clone())
     }
 }
 
index 9b3ee3ef5e0c28fb1a402d0b6100bf1af5ad2288..07d018dea929651d983768c8b1f3e940ca99515f 100644 (file)
@@ -230,6 +230,21 @@ pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
     tmp
 }
 
+/// Variant of read_and_zero that writes the specific drop-flag byte
+/// (which may be more appropriate than zero).
+#[inline(always)]
+#[unstable(feature = "core",
+           reason = "may play a larger role in std::ptr future extensions")]
+pub unsafe fn read_and_drop<T>(dest: *mut T) -> T {
+    // Copy the data out from `dest`:
+    let tmp = read(&*dest);
+
+    // Now mark `dest` as dropped:
+    write_bytes(dest, mem::POST_DROP_U8, 1);
+
+    tmp
+}
+
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
index 62e1bcd827ae7ccbac2b0a2c20965d84aa0f94d8..d36ae10931913030553583043551442c77986c63 100644 (file)
@@ -92,7 +92,7 @@
 //! useful value.
 //!
 //! Consider the `write_line` method defined for I/O types
-//! by the [`Writer`](../io/trait.Writer.html) trait:
+//! by the [`Writer`](../old_io/trait.Writer.html) trait:
 //!
 //! ```
 //! # #![feature(old_io)]
@@ -762,7 +762,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
     /// assert_eq!(x.unwrap(), 2);
     /// ```
     ///
-    /// ```{.should_fail}
+    /// ```{.should_panic}
     /// let x: Result<u32, &str> = Err("emergency failure");
     /// x.unwrap(); // panics with `emergency failure`
     /// ```
@@ -788,7 +788,7 @@ impl<T: fmt::Debug, E> Result<T, E> {
     ///
     /// # Examples
     ///
-    /// ```{.should_fail}
+    /// ```{.should_panic}
     /// let x: Result<u32, &str> = Ok(2);
     /// x.unwrap_err(); // panics with `2`
     /// ```
index fce29abed7300c161c416be5f78b8f379cb92594..892660b98bc95ac4279fa7c3c147cf54339f4023 100644 (file)
@@ -88,6 +88,9 @@ fn binary_search_by<F>(&self, f: F) -> Result<usize, usize> where
     fn len(&self) -> usize;
     fn is_empty(&self) -> bool { self.len() == 0 }
     fn get_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut Self::Item>;
+    #[unstable(feature = "core",
+               reason = "will be replaced by slice syntax")]
+    #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
     fn as_mut_slice<'a>(&'a mut self) -> &'a mut [Self::Item];
     fn iter_mut<'a>(&'a mut self) -> IterMut<'a, Self::Item>;
     fn first_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>;
@@ -261,6 +264,9 @@ fn get_mut(&mut self, index: usize) -> Option<&mut T> {
     }
 
     #[inline]
+    #[unstable(feature = "core",
+               reason = "will be replaced by slice syntax")]
+    #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
     fn as_mut_slice(&mut self) -> &mut [T] { self }
 
     #[cfg(stage0)]
index 5cafb8d2e5eae2ab6f61339c9f4f2c42536d75d8..83cb5c567c794adff525ce74b835b385f5e551d0 100644 (file)
@@ -101,7 +101,7 @@ pub struct Weighted<T> {
 /// let mut items = vec!(Weighted { weight: 2, item: 'a' },
 ///                      Weighted { weight: 4, item: 'b' },
 ///                      Weighted { weight: 1, item: 'c' });
-/// let wc = WeightedChoice::new(items.as_mut_slice());
+/// let wc = WeightedChoice::new(&mut items[..]);
 /// let mut rng = rand::thread_rng();
 /// for _ in 0..16 {
 ///      // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
index 7854db811466517bbd3f675ab3ac0e80b9edc643..80fc3769453427f4815464ccbca410dd2c4129d4 100644 (file)
@@ -426,8 +426,8 @@ fn find_library_crate(&mut self) -> Option<Library> {
             info!("lib candidate: {}", path.display());
 
             let hash_str = hash.to_string();
-            let slot = candidates.entry(hash_str).get().unwrap_or_else(
-                |vacant_entry| vacant_entry.insert((HashMap::new(), HashMap::new())));
+            let slot = candidates.entry(hash_str)
+                                 .or_insert_with(|| (HashMap::new(), HashMap::new()));
             let (ref mut rlibs, ref mut dylibs) = *slot;
             if rlib {
                 rlibs.insert(fs::realpath(path).unwrap(), kind);
index 3714e3b8c73da6a7cc4ca9eecb641743c7751388..c2d7911d151fbfb7f3a79e2e4d61776a4e851a59 100644 (file)
@@ -79,15 +79,6 @@ fn visit_item(&mut self, item: &ast::Item) {
         for attr in &item.attrs {
             let mut used = true;
             match &attr.name()[..] {
-                "phase" => {
-                    self.sess.span_err(attr.span, "#[phase] is deprecated");
-                }
-                "plugin" => {
-                    self.sess.span_err(attr.span, "#[plugin] on `extern crate` is deprecated");
-                    self.sess.fileline_help(attr.span, &format!("use a crate attribute instead, \
-                                                            i.e. #![plugin({})]",
-                                                            item.ident.as_str()));
-                }
                 "macro_use" => {
                     let names = attr.meta_item_list();
                     if names.is_none() {
index a1ce8d18184e3e47af087755ad6192fff48bc8c9..0d58fd2702f680e692933464c594e232ec1d1188 100644 (file)
@@ -160,12 +160,7 @@ fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
 
     cfg.graph.each_node(|node_idx, node| {
         if let cfg::CFGNodeData::AST(id) = node.data {
-            match index.entry(id).get() {
-                Ok(v) => v.push(node_idx),
-                Err(e) => {
-                    e.insert(vec![node_idx]);
-                }
-            }
+            index.entry(id).or_insert(vec![]).push(node_idx);
         }
         true
     });
@@ -185,12 +180,7 @@ struct Formals<'a> {
         visit::walk_fn_decl(&mut formals, decl);
         impl<'a, 'v> visit::Visitor<'v> for Formals<'a> {
             fn visit_pat(&mut self, p: &ast::Pat) {
-                match self.index.entry(p.id).get() {
-                    Ok(v) => v.push(self.entry),
-                    Err(e) => {
-                        e.insert(vec![self.entry]);
-                    }
-                }
+                self.index.entry(p.id).or_insert(vec![]).push(self.entry);
                 visit::walk_pat(self, p)
             }
         }
index c1066aa899eaea4fe4f7e34ea89b319a443c4e8f..2eaa536dabebc29b6059ba99d0891881b529cf21 100644 (file)
@@ -11,7 +11,6 @@
 use middle::infer::{InferCtxt};
 use middle::ty::{self, RegionEscape, Ty};
 use std::collections::HashSet;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::default::Default;
 use syntax::ast;
 use util::common::ErrorReported;
@@ -164,6 +163,8 @@ pub fn register_predicate_obligation<'a>(&mut self,
         // debug output much nicer to read and so on.
         let obligation = infcx.resolve_type_vars_if_possible(&obligation);
 
+        assert!(!obligation.has_escaping_regions());
+
         if !self.duplicate_set.insert(obligation.predicate.clone()) {
             debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
             return;
@@ -437,9 +438,7 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>,
     debug!("register_region_obligation({})",
            region_obligation.repr(tcx));
 
-    match region_obligations.entry(region_obligation.cause.body_id) {
-        Vacant(entry) => { entry.insert(vec![region_obligation]); },
-        Occupied(mut entry) => { entry.get_mut().push(region_obligation); },
-    }
+    region_obligations.entry(region_obligation.cause.body_id).or_insert(vec![])
+        .push(region_obligation);
 
 }
index 24b201c960f16ffe001b9914c2010b81170e4946..ffc11efe7c711e7c6c435225ca7d6af69a5d54d4 100644 (file)
@@ -48,6 +48,8 @@
 pub use self::util::trait_ref_for_builtin_bound;
 pub use self::util::supertraits;
 pub use self::util::Supertraits;
+pub use self::util::supertrait_def_ids;
+pub use self::util::SupertraitDefIds;
 pub use self::util::transitive_bounds;
 pub use self::util::upcast;
 
@@ -640,7 +642,7 @@ fn new(obligation: PredicateObligation<'tcx>,
 }
 
 impl<'tcx> TraitObligation<'tcx> {
-    fn self_ty(&self) -> Ty<'tcx> {
-        self.predicate.0.self_ty()
+    fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
+        ty::Binder(self.predicate.skip_binder().self_ty())
     }
 }
index 881487a2dad1150b6e9423075c14fbfb042258db..9dccadc932bb49e2fcbf3ab33aa298fbb413cdea 100644 (file)
@@ -53,36 +53,36 @@ pub enum MethodViolationCode {
 }
 
 pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
-                            trait_ref: ty::PolyTraitRef<'tcx>)
+                            trait_def_id: ast::DefId)
                             -> bool
 {
     // Because we query yes/no results frequently, we keep a cache:
     let cached_result =
-        tcx.object_safety_cache.borrow().get(&trait_ref.def_id()).cloned();
+        tcx.object_safety_cache.borrow().get(&trait_def_id).cloned();
 
     let result =
         cached_result.unwrap_or_else(|| {
-            let result = object_safety_violations(tcx, trait_ref.clone()).is_empty();
+            let result = object_safety_violations(tcx, trait_def_id).is_empty();
 
             // Record just a yes/no result in the cache; this is what is
             // queried most frequently. Note that this may overwrite a
             // previous result, but always with the same thing.
-            tcx.object_safety_cache.borrow_mut().insert(trait_ref.def_id(), result);
+            tcx.object_safety_cache.borrow_mut().insert(trait_def_id, result);
 
             result
         });
 
-    debug!("is_object_safe({}) = {}", trait_ref.repr(tcx), result);
+    debug!("is_object_safe({}) = {}", trait_def_id.repr(tcx), result);
 
     result
 }
 
 pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                      sub_trait_ref: ty::PolyTraitRef<'tcx>)
+                                      trait_def_id: ast::DefId)
                                       -> Vec<ObjectSafetyViolation<'tcx>>
 {
-    supertraits(tcx, sub_trait_ref)
-        .flat_map(|tr| object_safety_violations_for_trait(tcx, tr.def_id()).into_iter())
+    traits::supertrait_def_ids(tcx, trait_def_id)
+        .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id).into_iter())
         .collect()
 }
 
index 0d6a1f7df5e564cd8d26bf8d7beebec1ba9f4201..7e89534026ff37a5e1bf1b312f1dba997700db66 100644 (file)
@@ -138,6 +138,7 @@ enum SelectionCandidate<'tcx> {
     ParamCandidate(ty::PolyTraitRef<'tcx>),
     ImplCandidate(ast::DefId),
     DefaultImplCandidate(ast::DefId),
+    DefaultImplObjectCandidate(ast::DefId),
 
     /// This is a trait matching with a projected type as `Self`, and
     /// we found an applicable bound in the trait definition.
@@ -171,7 +172,7 @@ struct SelectionCandidateSet<'tcx> {
 }
 
 enum BuiltinBoundConditions<'tcx> {
-    If(Vec<Ty<'tcx>>),
+    If(ty::Binder<Vec<Ty<'tcx>>>),
     ParameterBuiltin,
     AmbiguousBuiltin
 }
@@ -292,7 +293,7 @@ fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligatio
         // because if it is a closure type, it must be a closure type from
         // within this current fn, and hence none of the higher-ranked
         // lifetimes can appear inside the self-type.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let (closure_def_id, substs) = match self_ty.sty {
             ty::ty_closure(id, ref substs) => (id, substs.clone()),
             _ => { return; }
@@ -1050,7 +1051,10 @@ fn assemble_closure_candidates(&mut self,
             None => { return Ok(()); }
         };
 
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        // ok to skip binder because the substs on closure types never
+        // touch bound regions, they just capture the in-scope
+        // type/region parameters
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let (closure_def_id, substs) = match self_ty.sty {
             ty::ty_closure(id, ref substs) => (id, substs.clone()),
             ty::ty_infer(ty::TyVar(_)) => {
@@ -1093,7 +1097,8 @@ fn assemble_fn_pointer_candidates(&mut self,
             return Ok(());
         }
 
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        // ok to skip binder because what we are inspecting doesn't involve bound regions
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         match self_ty.sty {
             ty::ty_infer(ty::TyVar(_)) => {
                 debug!("assemble_fn_pointer_candidates: ambiguous self-type");
@@ -1125,8 +1130,7 @@ fn assemble_candidates_from_impls(&mut self,
                                       candidates: &mut SelectionCandidateSet<'tcx>)
                                       -> Result<(), SelectionError<'tcx>>
     {
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
-        debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx()));
+        debug!("assemble_candidates_from_impls(obligation={})", obligation.repr(self.tcx()));
 
         let def_id = obligation.predicate.def_id();
         let all_impls = self.all_impls(def_id);
@@ -1152,15 +1156,28 @@ fn assemble_candidates_from_default_impls(&mut self,
                                               candidates: &mut SelectionCandidateSet<'tcx>)
                                               -> Result<(), SelectionError<'tcx>>
     {
-
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        // OK to skip binder here because the tests we do below do not involve bound regions
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         debug!("assemble_candidates_from_default_impls(self_ty={})", self_ty.repr(self.tcx()));
 
         let def_id = obligation.predicate.def_id();
 
         if ty::trait_has_default_impl(self.tcx(), def_id) {
             match self_ty.sty {
-                ty::ty_trait(..) |
+                ty::ty_trait(..) => {
+                    // For object types, we don't know what the closed
+                    // over types are. For most traits, this means we
+                    // conservatively say nothing; a candidate may be
+                    // added by `assemble_candidates_from_object_ty`.
+                    // However, for the kind of magic reflect trait,
+                    // we consider it to be implemented even for
+                    // object types, because it just lets you reflect
+                    // onto the object type, not into the object's
+                    // interior.
+                    if ty::has_attr(self.tcx(), def_id, "rustc_reflect_like") {
+                        candidates.vec.push(DefaultImplObjectCandidate(def_id));
+                    }
+                }
                 ty::ty_param(..) |
                 ty::ty_projection(..) => {
                     // In these cases, we don't know what the actual
@@ -1210,10 +1227,8 @@ fn assemble_candidates_from_object_ty(&mut self,
                                           obligation: &TraitObligation<'tcx>,
                                           candidates: &mut SelectionCandidateSet<'tcx>)
     {
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
-
         debug!("assemble_candidates_from_object_ty(self_ty={})",
-               self_ty.repr(self.tcx()));
+               self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()).repr(self.tcx()));
 
         // Object-safety candidates are only applicable to object-safe
         // traits. Including this check is useful because it helps
@@ -1222,47 +1237,56 @@ fn assemble_candidates_from_object_ty(&mut self,
         // self-type from one of the other inputs. Without this check,
         // these cases wind up being considered ambiguous due to a
         // (spurious) ambiguity introduced here.
-        if !object_safety::is_object_safe(self.tcx(), obligation.predicate.to_poly_trait_ref()) {
+        let predicate_trait_ref = obligation.predicate.to_poly_trait_ref();
+        if !object_safety::is_object_safe(self.tcx(), predicate_trait_ref.def_id()) {
             return;
         }
 
-        let poly_trait_ref = match self_ty.sty {
-            ty::ty_trait(ref data) => {
-                match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
-                    Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => {
-                        if data.bounds.builtin_bounds.contains(&bound) {
-                            debug!("assemble_candidates_from_object_ty: matched builtin bound, \
-                            pushing candidate");
-                            candidates.vec.push(BuiltinObjectCandidate);
-                            return;
+        self.infcx.try(|snapshot| {
+            let bound_self_ty =
+                self.infcx.resolve_type_vars_if_possible(&obligation.self_ty());
+            let (self_ty, _) =
+                self.infcx().skolemize_late_bound_regions(&bound_self_ty, snapshot);
+            let poly_trait_ref = match self_ty.sty {
+                ty::ty_trait(ref data) => {
+                    match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
+                        Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => {
+                            if data.bounds.builtin_bounds.contains(&bound) {
+                                debug!("assemble_candidates_from_object_ty: matched builtin bound, \
+                                        pushing candidate");
+                                candidates.vec.push(BuiltinObjectCandidate);
+                                return Ok(());
+                            }
                         }
+                        _ => {}
                     }
-                    _ => {}
+
+                    data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
+                }
+                ty::ty_infer(ty::TyVar(_)) => {
+                    debug!("assemble_candidates_from_object_ty: ambiguous");
+                    candidates.ambiguous = true; // could wind up being an object type
+                    return Ok(());
+                }
+                _ => {
+                    return Ok(());
                 }
+            };
 
-                data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
-            }
-            ty::ty_infer(ty::TyVar(_)) => {
-                debug!("assemble_candidates_from_object_ty: ambiguous");
-                candidates.ambiguous = true; // could wind up being an object type
-                return;
-            }
-            _ => {
-                return;
-            }
-        };
+            debug!("assemble_candidates_from_object_ty: poly_trait_ref={}",
+                   poly_trait_ref.repr(self.tcx()));
 
-        debug!("assemble_candidates_from_object_ty: poly_trait_ref={}",
-               poly_trait_ref.repr(self.tcx()));
+            // see whether the object trait can be upcast to the trait we are looking for
+            let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
+            if upcast_trait_refs.len() > 1 {
+                // can be upcast in many ways; need more type information
+                candidates.ambiguous = true;
+            } else if upcast_trait_refs.len() == 1 {
+                candidates.vec.push(ObjectCandidate);
+            }
 
-        // see whether the object trait can be upcast to the trait we are looking for
-        let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
-        if upcast_trait_refs.len() > 1 {
-            // can be upcast in many ways; need more type information
-            candidates.ambiguous = true;
-        } else if upcast_trait_refs.len() == 1 {
-            candidates.vec.push(ObjectCandidate);
-        }
+            Ok::<(),()>(())
+        }).unwrap();
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -1397,23 +1421,23 @@ fn builtin_bound(&mut self,
 
         let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
         return match self_ty.sty {
-            ty::ty_infer(ty::IntVar(_))
-            | ty::ty_infer(ty::FloatVar(_))
-            | ty::ty_uint(_)
-            | ty::ty_int(_)
-            | ty::ty_bool
-            | ty::ty_float(_)
-            | ty::ty_bare_fn(..)
-            ty::ty_char => {
+            ty::ty_infer(ty::IntVar(_)) |
+            ty::ty_infer(ty::FloatVar(_)) |
+            ty::ty_uint(_) |
+            ty::ty_int(_) |
+            ty::ty_bool |
+            ty::ty_float(_) |
+            ty::ty_bare_fn(..) |
+            ty::ty_char => {
                 // safe for everything
-                Ok(If(Vec::new()))
+                ok_if(Vec::new())
             }
 
             ty::ty_uniq(_) => {  // Box<T>
                 match bound {
                     ty::BoundCopy => Err(Unimplemented),
 
-                    ty::BoundSized => Ok(If(Vec::new())),
+                    ty::BoundSized => ok_if(Vec::new()),
 
                     ty::BoundSync | ty::BoundSend => {
                         self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
@@ -1423,7 +1447,7 @@ fn builtin_bound(&mut self,
 
             ty::ty_ptr(..) => {     // *const T, *mut T
                 match bound {
-                    ty::BoundCopy | ty::BoundSized => Ok(If(Vec::new())),
+                    ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()),
 
                     ty::BoundSync | ty::BoundSend => {
                         self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
@@ -1436,7 +1460,7 @@ fn builtin_bound(&mut self,
                     ty::BoundSized => Err(Unimplemented),
                     ty::BoundCopy => {
                         if data.bounds.builtin_bounds.contains(&bound) {
-                            Ok(If(Vec::new()))
+                            ok_if(Vec::new())
                         } else {
                             // Recursively check all supertraits to find out if any further
                             // bounds are required and thus we must fulfill.
@@ -1446,7 +1470,7 @@ fn builtin_bound(&mut self,
                             let desired_def_id = obligation.predicate.def_id();
                             for tr in util::supertraits(self.tcx(), principal) {
                                 if tr.def_id() == desired_def_id {
-                                    return Ok(If(Vec::new()))
+                                    return ok_if(Vec::new())
                                 }
                             }
 
@@ -1468,11 +1492,11 @@ fn builtin_bound(&mut self,
                             ast::MutMutable => Err(Unimplemented),
 
                             // &T is always copyable
-                            ast::MutImmutable => Ok(If(Vec::new())),
+                            ast::MutImmutable => ok_if(Vec::new()),
                         }
                     }
 
-                    ty::BoundSized => Ok(If(Vec::new())),
+                    ty::BoundSized => ok_if(Vec::new()),
 
                     ty::BoundSync | ty::BoundSend => {
                         self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
@@ -1486,7 +1510,7 @@ fn builtin_bound(&mut self,
                     ty::BoundCopy => {
                         match *len {
                             // [T, ..n] is copy iff T is copy
-                            Some(_) => Ok(If(vec![element_ty])),
+                            Some(_) => ok_if(vec![element_ty]),
 
                             // [T] is unsized and hence affine
                             None => Err(Unimplemented),
@@ -1495,7 +1519,7 @@ fn builtin_bound(&mut self,
 
                     ty::BoundSized => {
                         if len.is_some() {
-                            Ok(If(Vec::new()))
+                            ok_if(Vec::new())
                         } else {
                             Err(Unimplemented)
                         }
@@ -1519,7 +1543,7 @@ fn builtin_bound(&mut self,
             }
 
             // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-            ty::ty_tup(ref tys) => Ok(If(tys.clone())),
+            ty::ty_tup(ref tys) => ok_if(tys.clone()),
 
             ty::ty_closure(def_id, substs) => {
                 // FIXME -- This case is tricky. In the case of by-ref
@@ -1544,11 +1568,11 @@ fn builtin_bound(&mut self,
                 // unsized, so the closure struct as a whole must be
                 // Sized.
                 if bound == ty::BoundSized {
-                    return Ok(If(Vec::new()));
+                    return ok_if(Vec::new());
                 }
 
                 match self.closure_typer.closure_upvars(def_id, substs) {
-                    Some(upvars) => Ok(If(upvars.iter().map(|c| c.ty).collect())),
+                    Some(upvars) => ok_if(upvars.iter().map(|c| c.ty).collect()),
                     None => {
                         debug!("assemble_builtin_bound_candidates: no upvar types available yet");
                         Ok(AmbiguousBuiltin)
@@ -1590,7 +1614,7 @@ fn builtin_bound(&mut self,
                 Ok(AmbiguousBuiltin)
             }
 
-            ty::ty_err => Ok(If(Vec::new())),
+            ty::ty_err => ok_if(Vec::new()),
 
             ty::ty_infer(ty::FreshTy(_))
             | ty::ty_infer(ty::FreshIntTy(_)) => {
@@ -1601,6 +1625,11 @@ fn builtin_bound(&mut self,
             }
         };
 
+        fn ok_if<'tcx>(v: Vec<Ty<'tcx>>)
+                       -> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>> {
+            Ok(If(ty::Binder(v)))
+        }
+
         fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound,
                               types: Vec<Ty<'tcx>>)
                               -> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>>
@@ -1611,7 +1640,7 @@ fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound,
                 ty::BoundCopy => Ok(ParameterBuiltin),
 
                 // Sized if all the component types are sized.
-                ty::BoundSized => Ok(If(types)),
+                ty::BoundSized => ok_if(types),
 
                 // Shouldn't be coming through here.
                 ty::BoundSend | ty::BoundSync => unreachable!(),
@@ -1714,8 +1743,9 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Option<Vec<Ty<'tcx>>> {
     fn collect_predicates_for_types(&mut self,
                                     obligation: &TraitObligation<'tcx>,
                                     trait_def_id: ast::DefId,
-                                    types: Vec<Ty<'tcx>>) -> Vec<PredicateObligation<'tcx>> {
-
+                                    types: ty::Binder<Vec<Ty<'tcx>>>)
+                                    -> Vec<PredicateObligation<'tcx>>
+    {
         let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) {
             Some(_) => {
                 self.derived_cause(obligation, BuiltinDerivedObligation)
@@ -1725,43 +1755,52 @@ fn collect_predicates_for_types(&mut self,
             }
         };
 
-        let normalized = project::normalize_with_depth(self, obligation.cause.clone(),
-                                                       obligation.recursion_depth + 1,
-                                                       &types);
-
-        let obligations = normalized.value.iter().map(|&nested_ty| {
-            // the obligation might be higher-ranked, e.g. for<'a> &'a
-            // int : Copy. In that case, we will wind up with
-            // late-bound regions in the `nested` vector. So for each
-            // one we instantiate to a skolemized region, do our work
-            // to produce something like `&'0 int : Copy`, and then
-            // re-bind it. This is a bit of busy-work but preserves
-            // the invariant that we only manipulate free regions, not
-            // bound ones.
+        // Because the types were potentially derived from
+        // higher-ranked obligations they may reference late-bound
+        // regions. For example, `for<'a> Foo<&'a int> : Copy` would
+        // yield a type like `for<'a> &'a int`. In general, we
+        // maintain the invariant that we never manipulate bound
+        // regions, so we have to process these bound regions somehow.
+        //
+        // The strategy is to:
+        //
+        // 1. Instantiate those regions to skolemized regions (e.g.,
+        //    `for<'a> &'a int` becomes `&0 int`.
+        // 2. Produce something like `&'0 int : Copy`
+        // 3. Re-bind the regions back to `for<'a> &'a int : Copy`
+
+        // Move the binder into the individual types
+        let bound_types: Vec<ty::Binder<Ty<'tcx>>> =
+            types.skip_binder()
+                 .iter()
+                 .map(|&nested_ty| ty::Binder(nested_ty))
+                 .collect();
+
+        // For each type, produce a vector of resulting obligations
+        let obligations: Result<Vec<Vec<_>>, _> = bound_types.iter().map(|nested_ty| {
             self.infcx.try(|snapshot| {
                 let (skol_ty, skol_map) =
-                    self.infcx().skolemize_late_bound_regions(&ty::Binder(nested_ty), snapshot);
-                let skol_predicate =
-                    util::predicate_for_trait_def(
-                        self.tcx(),
-                        derived_cause.clone(),
-                        trait_def_id,
-                        obligation.recursion_depth + 1,
-                        skol_ty);
-                match skol_predicate {
-                    Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot,
-                                                                     &skol_predicate)),
-                    Err(ErrorReported) => Err(ErrorReported)
-                }
+                    self.infcx().skolemize_late_bound_regions(nested_ty, snapshot);
+                let Normalized { value: normalized_ty, mut obligations } =
+                    project::normalize_with_depth(self,
+                                                  obligation.cause.clone(),
+                                                  obligation.recursion_depth + 1,
+                                                  &skol_ty);
+                let skol_obligation =
+                    try!(util::predicate_for_trait_def(self.tcx(),
+                                                       derived_cause.clone(),
+                                                       trait_def_id,
+                                                       obligation.recursion_depth + 1,
+                                                       normalized_ty));
+                obligations.push(skol_obligation);
+                Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations))
             })
-        }).collect::<Result<Vec<PredicateObligation<'tcx>>, _>>();
+        }).collect();
 
+        // Flatten those vectors (couldn't do it above due `collect`)
         match obligations {
-            Ok(mut obls) => {
-                obls.push_all(&normalized.obligations);
-                obls
-            },
-            Err(ErrorReported) => Vec::new()
+            Ok(obligations) => obligations.into_iter().flat_map(|o| o.into_iter()).collect(),
+            Err(ErrorReported) => Vec::new(),
         }
     }
 
@@ -1798,7 +1837,12 @@ fn confirm_candidate(&mut self,
             }
 
             DefaultImplCandidate(trait_def_id) => {
-                let data = try!(self.confirm_default_impl_candidate(obligation, trait_def_id));
+                let data = self.confirm_default_impl_candidate(obligation, trait_def_id);
+                Ok(VtableDefaultImpl(data))
+            }
+
+            DefaultImplObjectCandidate(trait_def_id) => {
+                let data = self.confirm_default_impl_object_candidate(obligation, trait_def_id);
                 Ok(VtableDefaultImpl(data))
             }
 
@@ -1900,7 +1944,7 @@ fn confirm_builtin_candidate(&mut self,
     fn vtable_builtin_data(&mut self,
                            obligation: &TraitObligation<'tcx>,
                            bound: ty::BuiltinBound,
-                           nested: Vec<Ty<'tcx>>)
+                           nested: ty::Binder<Vec<Ty<'tcx>>>)
                            -> VtableBuiltinData<PredicateObligation<'tcx>>
     {
         let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) {
@@ -1927,17 +1971,17 @@ fn vtable_builtin_data(&mut self,
     /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
     fn confirm_default_impl_candidate(&mut self,
                                       obligation: &TraitObligation<'tcx>,
-                                      impl_def_id: ast::DefId)
-                              -> Result<VtableDefaultImplData<PredicateObligation<'tcx>>,
-                                        SelectionError<'tcx>>
+                                      trait_def_id: ast::DefId)
+                                      -> VtableDefaultImplData<PredicateObligation<'tcx>>
     {
         debug!("confirm_default_impl_candidate({}, {})",
                obligation.repr(self.tcx()),
-               impl_def_id.repr(self.tcx()));
+               trait_def_id.repr(self.tcx()));
 
-        let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
+        // binder is moved below
+        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
         match self.constituent_types_for_ty(self_ty) {
-            Some(types) => Ok(self.vtable_default_impl(obligation, impl_def_id, types)),
+            Some(types) => self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types)),
             None => {
                 self.tcx().sess.bug(
                     &format!(
@@ -1947,33 +1991,72 @@ fn confirm_default_impl_candidate(&mut self,
         }
     }
 
+    fn confirm_default_impl_object_candidate(&mut self,
+                                             obligation: &TraitObligation<'tcx>,
+                                             trait_def_id: ast::DefId)
+                                             -> VtableDefaultImplData<PredicateObligation<'tcx>>
+    {
+        debug!("confirm_default_impl_object_candidate({}, {})",
+               obligation.repr(self.tcx()),
+               trait_def_id.repr(self.tcx()));
+
+        assert!(ty::has_attr(self.tcx(), trait_def_id, "rustc_reflect_like"));
+
+        // OK to skip binder, it is reintroduced below
+        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
+        match self_ty.sty {
+            ty::ty_trait(ref data) => {
+                // OK to skip the binder, it is reintroduced below
+                let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace);
+                let assoc_types = data.bounds.projection_bounds
+                                             .iter()
+                                             .map(|pb| pb.skip_binder().ty);
+                let all_types: Vec<_> = input_types.iter().cloned()
+                                                          .chain(assoc_types)
+                                                          .collect();
+
+                // reintroduce the two binding levels we skipped, then flatten into one
+                let all_types = ty::Binder(ty::Binder(all_types));
+                let all_types = ty::flatten_late_bound_regions(self.tcx(), &all_types);
+
+                self.vtable_default_impl(obligation, trait_def_id, all_types)
+            }
+            _ => {
+                self.tcx().sess.bug(
+                    &format!(
+                        "asked to confirm default object implementation for non-object type: {}",
+                        self_ty.repr(self.tcx())));
+            }
+        }
+    }
+
     /// See `confirm_default_impl_candidate`
     fn vtable_default_impl(&mut self,
                            obligation: &TraitObligation<'tcx>,
                            trait_def_id: ast::DefId,
-                           nested: Vec<Ty<'tcx>>)
+                           nested: ty::Binder<Vec<Ty<'tcx>>>)
                            -> VtableDefaultImplData<PredicateObligation<'tcx>>
     {
+        debug!("vtable_default_impl_data: nested={}", nested.repr(self.tcx()));
 
         let mut obligations = self.collect_predicates_for_types(obligation,
                                                                 trait_def_id,
                                                                 nested);
 
-        let _: Result<(),()> = self.infcx.try(|snapshot| {
-            let (_, skol_map) =
-                self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
-
-            let substs = obligation.predicate.to_poly_trait_ref().substs();
-            let trait_obligations = self.impl_or_trait_obligations(obligation.cause.clone(),
-                                                                   obligation.recursion_depth + 1,
-                                                                   trait_def_id,
-                                                                   substs,
-                                                                   skol_map,
-                                                                   snapshot);
-            obligations.push_all(trait_obligations.as_slice());
-            Ok(())
+        let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.try(|snapshot| {
+            let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
+            let (trait_ref, skol_map) =
+                self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot);
+            Ok(self.impl_or_trait_obligations(obligation.cause.clone(),
+                                              obligation.recursion_depth + 1,
+                                              trait_def_id,
+                                              &trait_ref.substs,
+                                              skol_map,
+                                              snapshot))
         });
 
+        obligations.extend(trait_obligations.unwrap().into_iter()); // no Errors in that code above
+
         debug!("vtable_default_impl_data: obligations={}", obligations.repr(self.tcx()));
 
         VtableDefaultImplData {
@@ -2047,7 +2130,11 @@ fn confirm_object_candidate(&mut self,
         debug!("confirm_object_candidate({})",
                obligation.repr(self.tcx()));
 
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        // FIXME skipping binder here seems wrong -- we should
+        // probably flatten the binder from the obligation and the
+        // binder from the object. Have to try to make a broken test
+        // case that results. -nmatsakis
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let poly_trait_ref = match self_ty.sty {
             ty::ty_trait(ref data) => {
                 data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
@@ -2085,15 +2172,16 @@ fn confirm_fn_pointer_candidate(&mut self,
         debug!("confirm_fn_pointer_candidate({})",
                obligation.repr(self.tcx()));
 
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        // ok to skip binder; it is reintroduced below
+        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let sig = ty::ty_fn_sig(self_ty);
-        let ty::Binder((trait_ref, _)) =
+        let trait_ref =
             util::closure_trait_ref_and_return_type(self.tcx(),
                                                     obligation.predicate.def_id(),
                                                     self_ty,
                                                     sig,
-                                                    util::TupleArgumentsFlag::Yes);
-        let trait_ref = ty::Binder(trait_ref);
+                                                    util::TupleArgumentsFlag::Yes)
+            .map_bound(|(trait_ref, _)| trait_ref);
 
         try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
                                           obligation.predicate.to_poly_trait_ref(),
@@ -2448,6 +2536,8 @@ fn impl_or_trait_obligations(&mut self,
                                  snapshot: &infer::CombinedSnapshot)
                                  -> VecPerParamSpace<PredicateObligation<'tcx>>
     {
+        debug!("impl_or_trait_obligations(def_id={})", def_id.repr(self.tcx()));
+
         let predicates = ty::lookup_predicates(self.tcx(), def_id);
         let predicates = predicates.instantiate(self.tcx(), substs);
         let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates);
@@ -2530,6 +2620,7 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
             ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
             ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
             DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
+            DefaultImplObjectCandidate(t) => format!("DefaultImplObjectCandidate({:?})", t),
             ProjectionCandidate => format!("ProjectionCandidate"),
             FnPointerCandidate => format!("FnPointerCandidate"),
             ObjectCandidate => format!("ObjectCandidate"),
index 965aaf12044ec20692b20ca403d9234580c25a04..06b687bd92b9e2a6eea49ffdc78e033b1a0109af 100644 (file)
@@ -209,6 +209,47 @@ pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
     elaborate_trait_refs(tcx, bounds).filter_to_traits()
 }
 
+///////////////////////////////////////////////////////////////////////////
+// Iterator over def-ids of supertraits
+
+pub struct SupertraitDefIds<'cx, 'tcx:'cx> {
+    tcx: &'cx ty::ctxt<'tcx>,
+    stack: Vec<ast::DefId>,
+    visited: FnvHashSet<ast::DefId>,
+}
+
+pub fn supertrait_def_ids<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
+                                     trait_def_id: ast::DefId)
+                                     -> SupertraitDefIds<'cx, 'tcx>
+{
+    SupertraitDefIds {
+        tcx: tcx,
+        stack: vec![trait_def_id],
+        visited: Some(trait_def_id).into_iter().collect(),
+    }
+}
+
+impl<'cx, 'tcx> Iterator for SupertraitDefIds<'cx, 'tcx> {
+    type Item = ast::DefId;
+
+    fn next(&mut self) -> Option<ast::DefId> {
+        let def_id = match self.stack.pop() {
+            Some(def_id) => def_id,
+            None => { return None; }
+        };
+
+        let predicates = ty::lookup_super_predicates(self.tcx, def_id);
+        let visited = &mut self.visited;
+        self.stack.extend(
+            predicates.predicates
+                      .iter()
+                      .filter_map(|p| p.to_opt_poly_trait_ref())
+                      .map(|t| t.def_id())
+                      .filter(|&super_def_id| visited.insert(super_def_id)));
+        Some(def_id)
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Other
 ///////////////////////////////////////////////////////////////////////////
index 92b444e85d8c3f5fa713bfc632c1272b50acf01f..01e13887462b1235c102d1a21a5b484cc4193f6c 100644 (file)
@@ -1108,16 +1108,16 @@ pub struct FnSig<'tcx> {
 
 impl<'tcx> PolyFnSig<'tcx> {
     pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
-        ty::Binder(self.0.inputs.clone())
+        self.map_bound_ref(|fn_sig| fn_sig.inputs.clone())
     }
     pub fn input(&self, index: uint) -> ty::Binder<Ty<'tcx>> {
-        ty::Binder(self.0.inputs[index])
+        self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
     }
     pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
-        ty::Binder(self.0.output.clone())
+        self.map_bound_ref(|fn_sig| fn_sig.output.clone())
     }
     pub fn variadic(&self) -> bool {
-        self.0.variadic
+        self.skip_binder().variadic
     }
 }
 
@@ -1519,6 +1519,22 @@ impl<T> Binder<T> {
     pub fn skip_binder(&self) -> &T {
         &self.0
     }
+
+    pub fn as_ref(&self) -> Binder<&T> {
+        ty::Binder(&self.0)
+    }
+
+    pub fn map_bound_ref<F,U>(&self, f: F) -> Binder<U>
+        where F: FnOnce(&T) -> U
+    {
+        self.as_ref().map_bound(f)
+    }
+
+    pub fn map_bound<F,U>(self, f: F) -> Binder<U>
+        where F: FnOnce(T) -> U
+    {
+        ty::Binder(f(self.0))
+    }
 }
 
 #[derive(Clone, Copy, PartialEq)]
@@ -2062,8 +2078,7 @@ fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
 
 impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
-        // We are just preserving the binder levels here
-        ty::Binder(self.0.trait_ref.clone())
+        self.map_bound_ref(|trait_pred| trait_pred.trait_ref.clone())
     }
 }
 
@@ -5669,9 +5684,7 @@ pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>,
         node_id_to_type(tcx, id.node)
     } else {
         let mut tcache = tcx.tcache.borrow_mut();
-        let pty = tcache.entry(id).get().unwrap_or_else(
-            |vacant_entry| vacant_entry.insert(csearch::get_field_type(tcx, struct_id, id)));
-        pty.ty
+        tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty
     };
     ty.subst(tcx, substs)
 }
@@ -6755,6 +6768,30 @@ pub fn binds_late_bound_regions<'tcx, T>(
     count_late_bound_regions(tcx, value) > 0
 }
 
+/// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
+/// becomes `for<'a,'b> Foo`.
+pub fn flatten_late_bound_regions<'tcx, T>(
+    tcx: &ty::ctxt<'tcx>,
+    bound2_value: &Binder<Binder<T>>)
+    -> Binder<T>
+    where T: TypeFoldable<'tcx> + Repr<'tcx>
+{
+    let bound0_value = bound2_value.skip_binder().skip_binder();
+    let value = ty_fold::fold_regions(tcx, bound0_value, |region, current_depth| {
+        match region {
+            ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
+                // should be true if no escaping regions from bound2_value
+                assert!(debruijn.depth - current_depth <= 1);
+                ty::ReLateBound(DebruijnIndex::new(current_depth), br)
+            }
+            _ => {
+                region
+            }
+        }
+    });
+    Binder(value)
+}
+
 pub fn no_late_bound_regions<'tcx, T>(
     tcx: &ty::ctxt<'tcx>,
     value: &Binder<T>)
@@ -6819,9 +6856,7 @@ pub fn replace_late_bound_regions<'tcx, T, F>(
         debug!("region={}", region.repr(tcx));
         match region {
             ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
-                let region =
-                    * map.entry(br).get().unwrap_or_else(
-                        |vacant_entry| vacant_entry.insert(mapf(br)));
+                let region = *map.entry(br).or_insert_with(|| mapf(br));
 
                 if let ty::ReLateBound(debruijn1, br) = region {
                     // If the callback returns a late-bound region,
@@ -7093,6 +7128,12 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
     }
 }
 
+impl<'tcx,P:RegionEscape> RegionEscape for traits::Obligation<'tcx,P> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.predicate.has_regions_escaping_depth(depth)
+    }
+}
+
 impl<'tcx> RegionEscape for TraitRef<'tcx> {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
index 711ed43fe06062eec3590fa6b52ceeebeaaf398c..3162c4fc570236d75246364cea365867f97e9ed6 100644 (file)
@@ -47,7 +47,7 @@
 //! #![plugin(myplugin)]
 //! ```
 //!
-//! See [the compiler plugin guide](../../guide-plugin.html)
+//! See the [Plugins Chapter](../../book/plugins.html) of the book
 //! for more examples.
 
 pub use self::registry::Registry;
index a7c67a0863182e6af468f5e4ba104a01b3c5a50c..c725d93e2b103eb5218ed007ed20100a0dd13e90 100644 (file)
@@ -35,7 +35,6 @@
 
 use getopts;
 use std::collections::HashMap;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::env;
 use std::fmt;
 use std::path::PathBuf;
@@ -605,6 +604,8 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
           "Print the size of enums and their variants"),
     force_overflow_checks: Option<bool> = (None, parse_opt_bool,
           "Force overflow checks on or off"),
+    force_dropflag_checks: Option<bool> = (None, parse_opt_bool,
+          "Force drop flag checks on or off"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -959,24 +960,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let libs = matches.opt_strs("l").into_iter().map(|s| {
         let mut parts = s.splitn(1, '=');
         let kind = parts.next().unwrap();
-        if let Some(name) = parts.next() {
-            let kind = match kind {
-                "dylib" => cstore::NativeUnknown,
-                "framework" => cstore::NativeFramework,
-                "static" => cstore::NativeStatic,
-                s => {
-                    early_error(&format!("unknown library kind `{}`, expected \
-                                          one of dylib, framework, or static",
-                                         s));
-                }
-            };
-            return (name.to_string(), kind)
-        }
-
-        // FIXME(acrichto) remove this once crates have stopped using it, this
-        //                 is deprecated behavior now.
-        let mut parts = s.rsplitn(1, ':');
-        let kind = parts.next().unwrap();
         let (name, kind) = match (parts.next(), kind) {
             (None, name) |
             (Some(name), "dylib") => (name, cstore::NativeUnknown),
@@ -1037,10 +1020,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             None => early_error("--extern value must be of the format `foo=bar`"),
         };
 
-        match externs.entry(name.to_string()) {
-            Vacant(entry) => { entry.insert(vec![location.to_string()]); },
-            Occupied(mut entry) => { entry.get_mut().push(location.to_string()); },
-        }
+        externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
     }
 
     let crate_name = matches.opt_str("crate-name");
index 566af2590e6c07cd0ec1a256856951ee36478222..5bf561c218d044365f88de58687a99b0a078a6ac 100644 (file)
@@ -26,7 +26,6 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(std_misc)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
index 46451019760dd478aa179449473532a32d15fe63..662b5a366431ca785460742cc0775e2fb0ca6f42 100644 (file)
@@ -836,11 +836,8 @@ fn merge_import_resolution(&mut self,
         let is_public = import_directive.is_public;
 
         let mut import_resolutions = module_.import_resolutions.borrow_mut();
-        let dest_import_resolution = import_resolutions.entry(name).get().unwrap_or_else(
-            |vacant_entry| {
-                // Create a new import resolution from this child.
-                vacant_entry.insert(ImportResolution::new(id, is_public))
-            });
+        let dest_import_resolution = import_resolutions.entry(name)
+            .or_insert_with(|| ImportResolution::new(id, is_public));
 
         debug!("(resolving glob import) writing resolution `{}` in `{}` \
                to `{}`",
index c48b63cdcb6c4bccc640fff215ce3a650a90c720..d583eef0e0f7b0ba9f529e910601b33a181d15bd 100644 (file)
@@ -1528,7 +1528,7 @@ fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             let scope = cleanup::var_scope(tcx, p_id);
             bcx = mk_binding_alloca(
                 bcx, p_id, &path1.node, scope, (),
-                |(), bcx, llval, ty| { zero_mem(bcx, llval, ty); bcx });
+                |(), bcx, llval, ty| { drop_done_fill_mem(bcx, llval, ty); bcx });
         });
         bcx
     }
index 61214f65c87ea2d60951f044df44de9944aa97d3..dddc2d2be48b041339d281d2f0d9cbdf2ccc1ebc 100644 (file)
@@ -81,14 +81,18 @@ pub enum Repr<'tcx> {
     /// Structs with destructors need a dynamic destroyedness flag to
     /// avoid running the destructor too many times; this is included
     /// in the `Struct` if present.
-    Univariant(Struct<'tcx>, bool),
+    /// (The flag if nonzero, represents the initialization value to use;
+    ///  if zero, then use no flag at all.)
+    Univariant(Struct<'tcx>, u8),
     /// General-case enums: for each case there is a struct, and they
     /// all start with a field for the discriminant.
     ///
     /// Types with destructors need a dynamic destroyedness flag to
     /// avoid running the destructor too many times; the last argument
     /// indicates whether such a flag is present.
-    General(IntType, Vec<Struct<'tcx>>, bool),
+    /// (The flag, if nonzero, represents the initialization value to use;
+    ///  if zero, then use no flag at all.)
+    General(IntType, Vec<Struct<'tcx>>, u8),
     /// Two cases distinguished by a nullable pointer: the case with discriminant
     /// `nndiscr` must have single field which is known to be nonnull due to its type.
     /// The other case is known to be zero sized. Hence we represent the enum
@@ -151,11 +155,59 @@ pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     repr
 }
 
+macro_rules! repeat_u8_as_u32 {
+    ($name:expr) => { (($name as u32) << 24 |
+                       ($name as u32) << 16 |
+                       ($name as u32) <<  8 |
+                       ($name as u32)) }
+}
+macro_rules! repeat_u8_as_u64 {
+    ($name:expr) => { ((repeat_u8_as_u32!($name) as u64) << 32 |
+                       (repeat_u8_as_u32!($name) as u64)) }
+}
+
+pub const DTOR_NEEDED: u8 = 0xd4;
+pub const DTOR_NEEDED_U32: u32 = repeat_u8_as_u32!(DTOR_NEEDED);
+pub const DTOR_NEEDED_U64: u64 = repeat_u8_as_u64!(DTOR_NEEDED);
+#[allow(dead_code)]
+pub fn dtor_needed_usize(ccx: &CrateContext) -> usize {
+    match &ccx.tcx().sess.target.target.target_pointer_width[..] {
+        "32" => DTOR_NEEDED_U32 as usize,
+        "64" => DTOR_NEEDED_U64 as usize,
+        tws => panic!("Unsupported target word size for int: {}", tws),
+    }
+}
+
+pub const DTOR_DONE: u8 = 0x1d;
+pub const DTOR_DONE_U32: u32 = repeat_u8_as_u32!(DTOR_DONE);
+pub const DTOR_DONE_U64: u64 = repeat_u8_as_u64!(DTOR_DONE);
+#[allow(dead_code)]
+pub fn dtor_done_usize(ccx: &CrateContext) -> usize {
+    match &ccx.tcx().sess.target.target.target_pointer_width[..] {
+        "32" => DTOR_DONE_U32 as usize,
+        "64" => DTOR_DONE_U64 as usize,
+        tws => panic!("Unsupported target word size for int: {}", tws),
+    }
+}
+
+fn dtor_to_init_u8(dtor: bool) -> u8 {
+    if dtor { DTOR_NEEDED } else { 0 }
+}
+
+pub trait GetDtorType<'tcx> { fn dtor_type(&self) -> Ty<'tcx>; }
+impl<'tcx> GetDtorType<'tcx> for ty::ctxt<'tcx> {
+    fn dtor_type(&self) -> Ty<'tcx> { self.types.u8 }
+}
+
+fn dtor_active(flag: u8) -> bool {
+    flag != 0
+}
+
 fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                      t: Ty<'tcx>) -> Repr<'tcx> {
     match t.sty {
         ty::ty_tup(ref elems) => {
-            Univariant(mk_struct(cx, &elems[..], false, t), false)
+            Univariant(mk_struct(cx, &elems[..], false, t), 0)
         }
         ty::ty_struct(def_id, substs) => {
             let fields = ty::lookup_struct_fields(cx.tcx(), def_id);
@@ -165,15 +217,15 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }).collect::<Vec<_>>();
             let packed = ty::lookup_packed(cx.tcx(), def_id);
             let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
-            if dtor { ftys.push(cx.tcx().types.bool); }
+            if dtor { ftys.push(cx.tcx().dtor_type()); }
 
-            Univariant(mk_struct(cx, &ftys[..], packed, t), dtor)
+            Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
         }
         ty::ty_closure(def_id, substs) => {
             let typer = NormalizingClosureTyper::new(cx.tcx());
             let upvars = typer.closure_upvars(def_id, substs).unwrap();
             let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
-            Univariant(mk_struct(cx, &upvar_types[..], false, t), false)
+            Univariant(mk_struct(cx, &upvar_types[..], false, t), 0)
         }
         ty::ty_enum(def_id, substs) => {
             let cases = get_cases(cx.tcx(), def_id, substs);
@@ -186,9 +238,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 // Uninhabitable; represent as unit
                 // (Typechecking will reject discriminant-sizing attrs.)
                 assert_eq!(hint, attr::ReprAny);
-                let ftys = if dtor { vec!(cx.tcx().types.bool) } else { vec!() };
+                let ftys = if dtor { vec!(cx.tcx().dtor_type()) } else { vec!() };
                 return Univariant(mk_struct(cx, &ftys[..], false, t),
-                                  dtor);
+                                  dtor_to_init_u8(dtor));
             }
 
             if !dtor && cases.iter().all(|c| c.tys.len() == 0) {
@@ -218,9 +270,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 // (Typechecking will reject discriminant-sizing attrs.)
                 assert_eq!(hint, attr::ReprAny);
                 let mut ftys = cases[0].tys.clone();
-                if dtor { ftys.push(cx.tcx().types.bool); }
+                if dtor { ftys.push(cx.tcx().dtor_type()); }
                 return Univariant(mk_struct(cx, &ftys[..], false, t),
-                                  dtor);
+                                  dtor_to_init_u8(dtor));
             }
 
             if !dtor && cases.len() == 2 && hint == attr::ReprAny {
@@ -266,7 +318,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields : Vec<_> = cases.iter().map(|c| {
                 let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity));
                 ftys.push_all(&c.tys);
-                if dtor { ftys.push(cx.tcx().types.bool); }
+                if dtor { ftys.push(cx.tcx().dtor_type()); }
                 mk_struct(cx, &ftys, false, t)
             }).collect();
 
@@ -319,13 +371,13 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields : Vec<_> = cases.iter().map(|c| {
                 let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity));
                 ftys.push_all(&c.tys);
-                if dtor { ftys.push(cx.tcx().types.bool); }
+                if dtor { ftys.push(cx.tcx().dtor_type()); }
                 mk_struct(cx, &ftys[..], false, t)
             }).collect();
 
             ensure_enum_fits_in_address_space(cx, &fields[..], t);
 
-            General(ity, fields, dtor)
+            General(ity, fields, dtor_to_init_u8(dtor))
         }
         _ => cx.sess().bug(&format!("adt::represent_type called on non-ADT type: {}",
                            ty_to_string(cx.tcx(), t)))
@@ -830,18 +882,18 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
                   val)
         }
         General(ity, ref cases, dtor) => {
-            if dtor {
+            if dtor_active(dtor) {
                 let ptr = trans_field_ptr(bcx, r, val, discr,
                                           cases[discr as uint].fields.len() - 2);
-                Store(bcx, C_u8(bcx.ccx(), 1), ptr);
+                Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED as usize), ptr);
             }
             Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
                   GEPi(bcx, val, &[0, 0]))
         }
         Univariant(ref st, dtor) => {
             assert_eq!(discr, 0);
-            if dtor {
-                Store(bcx, C_u8(bcx.ccx(), 1),
+            if dtor_active(dtor) {
+                Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED as usize),
                     GEPi(bcx, val, &[0, st.fields.len() - 1]));
             }
         }
@@ -875,10 +927,10 @@ pub fn num_args(r: &Repr, discr: Disr) -> uint {
         CEnum(..) => 0,
         Univariant(ref st, dtor) => {
             assert_eq!(discr, 0);
-            st.fields.len() - (if dtor { 1 } else { 0 })
+            st.fields.len() - (if dtor_active(dtor) { 1 } else { 0 })
         }
         General(_, ref cases, dtor) => {
-            cases[discr as uint].fields.len() - 1 - (if dtor { 1 } else { 0 })
+            cases[discr as uint].fields.len() - 1 - (if dtor_active(dtor) { 1 } else { 0 })
         }
         RawNullablePointer { nndiscr, ref nullfields, .. } => {
             if discr == nndiscr { 1 } else { nullfields.len() }
@@ -992,17 +1044,17 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx
                                        -> datum::DatumBlock<'blk, 'tcx, datum::Expr>
 {
     let tcx = bcx.tcx();
-    let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), tcx.types.bool);
+    let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), tcx.dtor_type());
     match *r {
-        Univariant(ref st, true) => {
+        Univariant(ref st, dtor) if dtor_active(dtor) => {
             let flag_ptr = GEPi(bcx, val, &[0, st.fields.len() - 1]);
             datum::immediate_rvalue_bcx(bcx, flag_ptr, ptr_ty).to_expr_datumblock()
         }
-        General(_, _, true) => {
+        General(_, _, dtor) if dtor_active(dtor) => {
             let fcx = bcx.fcx;
             let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
             let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
-                bcx, tcx.types.bool, "drop_flag",
+                bcx, tcx.dtor_type(), "drop_flag",
                 cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx
             ));
             bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
index 2f944e49b15161dc6d6243d9aebed4eb49fdb95f..f482e4fa72b84531c67ac9d1a3897d46cdede060 100644 (file)
@@ -1146,20 +1146,27 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
-pub fn zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) {
+pub fn drop_done_fill_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) {
     if cx.unreachable.get() { return; }
-    let _icx = push_ctxt("zero_mem");
+    let _icx = push_ctxt("drop_done_fill_mem");
     let bcx = cx;
-    memzero(&B(bcx), llptr, t);
+    memfill(&B(bcx), llptr, t, adt::DTOR_DONE);
 }
 
-// Always use this function instead of storing a zero constant to the memory
-// in question. If you store a zero constant, LLVM will drown in vreg
+pub fn init_zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) {
+    if cx.unreachable.get() { return; }
+    let _icx = push_ctxt("init_zero_mem");
+    let bcx = cx;
+    memfill(&B(bcx), llptr, t, 0);
+}
+
+// Always use this function instead of storing a constant byte to the memory
+// in question. e.g. if you store a zero constant, LLVM will drown in vreg
 // allocation for large data structures, and the generated code will be
 // awful. (A telltale sign of this is large quantities of
 // `mov [byte ptr foo],0` in the generated code.)
-fn memzero<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>) {
-    let _icx = push_ctxt("memzero");
+fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte: u8) {
+    let _icx = push_ctxt("memfill");
     let ccx = b.ccx;
 
     let llty = type_of::type_of(ccx, ty);
@@ -1172,7 +1179,7 @@ fn memzero<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>) {
 
     let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key);
     let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to());
-    let llzeroval = C_u8(ccx, 0);
+    let llzeroval = C_u8(ccx, byte as usize);
     let size = machine::llsize_of(ccx, llty);
     let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32);
     let volatile = C_bool(ccx, false);
@@ -3022,6 +3029,12 @@ pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
         tcx.sess.opts.debug_assertions
     };
 
+    let check_dropflag = if let Some(v) = tcx.sess.opts.debugging_opts.force_dropflag_checks {
+        v
+    } else {
+        tcx.sess.opts.debug_assertions
+    };
+
     // Before we touch LLVM, make sure that multithreading is enabled.
     unsafe {
         use std::sync::{Once, ONCE_INIT};
@@ -3050,7 +3063,8 @@ pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
                                              Sha256::new(),
                                              link_meta.clone(),
                                              reachable,
-                                             check_overflow);
+                                             check_overflow,
+                                             check_dropflag);
 
     {
         let ccx = shared_ccx.get_ccx(0);
index ad07f3953ccc5176b8d54a3376617e6016d7a95f..c7897f9b62ea5b16a62b48669fe570d036825e84 100644 (file)
@@ -1015,7 +1015,7 @@ fn trans<'blk>(&self,
             glue::drop_ty(bcx, self.val, self.ty, debug_loc)
         };
         if self.zero {
-            base::zero_mem(bcx, self.val, self.ty);
+            base::drop_done_fill_mem(bcx, self.val, self.ty);
         }
         bcx
     }
index 6614d538971ddc1c7cc8a74bc9abff22841d24b1..b834050a6d929b2f71be37047c8ee0ca6188fe4d 100644 (file)
@@ -69,6 +69,7 @@ pub struct SharedCrateContext<'tcx> {
     tcx: ty::ctxt<'tcx>,
     stats: Stats,
     check_overflow: bool,
+    check_drop_flag_for_sanity: bool,
 
     available_monomorphizations: RefCell<FnvHashSet<String>>,
     available_drop_glues: RefCell<FnvHashMap<Ty<'tcx>, String>>,
@@ -242,7 +243,8 @@ pub fn new(crate_name: &str,
                symbol_hasher: Sha256,
                link_meta: LinkMeta,
                reachable: NodeSet,
-               check_overflow: bool)
+               check_overflow: bool,
+               check_drop_flag_for_sanity: bool)
                -> SharedCrateContext<'tcx> {
         let (metadata_llcx, metadata_llmod) = unsafe {
             create_context_and_module(&tcx.sess, "metadata")
@@ -271,6 +273,7 @@ pub fn new(crate_name: &str,
                 fn_stats: RefCell::new(Vec::new()),
             },
             check_overflow: check_overflow,
+            check_drop_flag_for_sanity: check_drop_flag_for_sanity,
             available_monomorphizations: RefCell::new(FnvHashSet()),
             available_drop_glues: RefCell::new(FnvHashMap()),
         };
@@ -727,6 +730,13 @@ pub fn report_overbig_object(&self, obj: Ty<'tcx>) -> ! {
     pub fn check_overflow(&self) -> bool {
         self.shared.check_overflow
     }
+
+    pub fn check_drop_flag_for_sanity(&self) -> bool {
+        // This controls whether we emit a conditional llvm.debugtrap
+        // guarded on whether the dropflag is one of its (two) valid
+        // values.
+        self.shared.check_drop_flag_for_sanity
+    }
 }
 
 fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef> {
index 15738d1e61ac14122f0161df205f0d536ebca146..399b7eb102e83cc478a67588e90e43375b51ce7d 100644 (file)
@@ -307,8 +307,8 @@ fn post_store<'blk, 'tcx>(&self,
                               -> Block<'blk, 'tcx> {
         let _icx = push_ctxt("<Lvalue as KindOps>::post_store");
         if bcx.fcx.type_needs_drop(ty) {
-            // cancel cleanup of affine values by zeroing out
-            let () = zero_mem(bcx, val, ty);
+            // cancel cleanup of affine values by drop-filling the memory
+            let () = drop_done_fill_mem(bcx, val, ty);
             bcx
         } else {
             bcx
index b2de8435f641bd5c4e8d6340ba27379805ee4a43..32b4d14177c2a050fbd512c4df1b0efe32b09448 100644 (file)
@@ -21,6 +21,7 @@
 use middle::subst;
 use middle::subst::{Subst, Substs};
 use trans::adt;
+use trans::adt::GetDtorType; // for tcx.dtor_type()
 use trans::base::*;
 use trans::build::*;
 use trans::callee;
@@ -231,9 +232,31 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         Load(bcx, llval)
     };
     let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
-    with_cond(bcx, load_ty(bcx, drop_flag.val, bcx.tcx().types.bool), |cx| {
+    let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type());
+    let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
+    let init_val = C_integral(drop_flag_llty, adt::DTOR_NEEDED as u64, false);
+
+    let bcx = if !bcx.ccx().check_drop_flag_for_sanity() {
+        bcx
+    } else {
+        let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
+        let done_val = C_integral(drop_flag_llty, adt::DTOR_DONE as u64, false);
+        let not_init = ICmp(bcx, llvm::IntNE, loaded, init_val, DebugLoc::None);
+        let not_done = ICmp(bcx, llvm::IntNE, loaded, done_val, DebugLoc::None);
+        let drop_flag_neither_initialized_nor_cleared =
+            And(bcx, not_init, not_done, DebugLoc::None);
+        with_cond(bcx, drop_flag_neither_initialized_nor_cleared, |cx| {
+            let llfn = cx.ccx().get_intrinsic(&("llvm.debugtrap"));
+            Call(cx, llfn, &[], None, DebugLoc::None);
+            cx
+        })
+    };
+
+    let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
+    with_cond(bcx, drop_flag_dtor_needed, |cx| {
         trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
     })
+
 }
 
 fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
@@ -395,13 +418,24 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
                               -> Block<'blk, 'tcx> {
     // NB: v0 is an *alias* of type t here, not a direct value.
     let _icx = push_ctxt("make_drop_glue");
+
+    // Only drop the value when it ... well, we used to check for
+    // non-null, (and maybe we need to continue doing so), but we now
+    // must definitely check for special bit-patterns corresponding to
+    // the special dtor markings.
+
+    let inttype = Type::int(bcx.ccx());
+    let dropped_pattern = C_integral(inttype, adt::dtor_done_usize(bcx.fcx.ccx) as u64, false);
+
     match t.sty {
         ty::ty_uniq(content_ty) => {
             if !type_is_sized(bcx.tcx(), content_ty) {
                 let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
                 let llbox = Load(bcx, llval);
-                let not_null = IsNotNull(bcx, llbox);
-                with_cond(bcx, not_null, |bcx| {
+                let llbox_as_usize = PtrToInt(bcx, llbox, Type::int(bcx.ccx()));
+                let drop_flag_not_dropped_already =
+                    ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None);
+                with_cond(bcx, drop_flag_not_dropped_already, |bcx| {
                     let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
                     let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
                     let info = Load(bcx, info);
@@ -420,8 +454,10 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
             } else {
                 let llval = v0;
                 let llbox = Load(bcx, llval);
-                let not_null = IsNotNull(bcx, llbox);
-                with_cond(bcx, not_null, |bcx| {
+                let llbox_as_usize = PtrToInt(bcx, llbox, inttype);
+                let drop_flag_not_dropped_already =
+                    ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None);
+                with_cond(bcx, drop_flag_not_dropped_already, |bcx| {
                     let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
                     trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
                 })
index f714c5800c57b3717f5fb2532413b7e5159f17a3..ee0274b182794b19c550ad7973d8f32ab832c2f7 100644 (file)
@@ -359,11 +359,18 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 &ccx.link_meta().crate_hash);
             C_u64(ccx, hash)
         }
+        (_, "init_dropped") => {
+            let tp_ty = *substs.types.get(FnSpace, 0);
+            if !return_type_is_void(ccx, tp_ty) {
+                drop_done_fill_mem(bcx, llresult, tp_ty);
+            }
+            C_nil(ccx)
+        }
         (_, "init") => {
             let tp_ty = *substs.types.get(FnSpace, 0);
             if !return_type_is_void(ccx, tp_ty) {
                 // Just zero out the stack slot. (See comment on base::memzero for explanation)
-                zero_mem(bcx, llresult, tp_ty);
+                init_zero_mem(bcx, llresult, tp_ty);
             }
             C_nil(ccx)
         }
index 3efe3a13562a1259d53d2a073a12a8720bbba9a5..34a0632c3d3cb3ecb92816588480de0d902cad47 100644 (file)
 use util::lev_distance::lev_distance;
 
 use std::cell::{Cell, Ref, RefCell};
-use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::mem::replace;
 use std::rc::Rc;
 use std::iter::repeat;
@@ -1366,11 +1365,7 @@ fn record_deferred_call_resolution(&self,
                                        closure_def_id: ast::DefId,
                                        r: DeferredCallResolutionHandler<'tcx>) {
         let mut deferred_call_resolutions = self.inh.deferred_call_resolutions.borrow_mut();
-        let mut vec = match deferred_call_resolutions.entry(closure_def_id) {
-            Occupied(entry) => entry.into_mut(),
-            Vacant(entry) => entry.insert(Vec::new()),
-        };
-        vec.push(r);
+        deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r);
     }
 
     fn remove_deferred_call_resolutions(&self,
@@ -5385,7 +5380,7 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
             "breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)),
             "size_of" |
             "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.uint),
-            "init" => (1, Vec::new(), param(ccx, 0)),
+            "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)),
             "uninit" => (1, Vec::new(), param(ccx, 0)),
             "forget" => (1, vec!( param(ccx, 0) ), ty::mk_nil(tcx)),
             "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
index 2858dc9b569fe1adaa22ffb7cde199e4e375404a..67461ff561bb8beb529a74f4ba1a6a876c091113 100644 (file)
@@ -28,18 +28,17 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
                                  object_trait: &ty::TyTrait<'tcx>,
                                  span: Span)
 {
-    let object_trait_ref =
-        object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
+    let trait_def_id = object_trait.principal_def_id();
 
-    if traits::is_object_safe(tcx, object_trait_ref.clone()) {
+    if traits::is_object_safe(tcx, trait_def_id) {
         return;
     }
 
     span_err!(tcx.sess, span, E0038,
               "cannot convert to a trait object because trait `{}` is not object-safe",
-              ty::item_path_str(tcx, object_trait_ref.def_id()));
+              ty::item_path_str(tcx, trait_def_id));
 
-    let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
+    let violations = traits::object_safety_violations(tcx, trait_def_id);
     for violation in violations {
         match violation {
             ObjectSafetyViolation::SizedSelf => {
index ac1ff29e7f5455407c9eecd35e1dc4c46c2cc493..3a716b28e73a711696a28cea07517b09dd385668 100644 (file)
@@ -1059,14 +1059,29 @@ fn add_constraints_from_predicates(&mut self,
                 }
 
                 ty::Predicate::Equate(ty::Binder(ref data)) => {
-                    self.add_constraints_from_ty(generics, data.0, variance);
-                    self.add_constraints_from_ty(generics, data.1, variance);
+                    // A == B is only true if A and B are the same
+                    // types, not subtypes of one another, so this is
+                    // an invariant position:
+                    self.add_constraints_from_ty(generics, data.0, self.invariant);
+                    self.add_constraints_from_ty(generics, data.1, self.invariant);
                 }
 
                 ty::Predicate::TypeOutlives(ty::Binder(ref data)) => {
-                    self.add_constraints_from_ty(generics, data.0, variance);
+                    // Why contravariant on both? Let's consider:
+                    //
+                    // Under what conditions is `(T:'t) <: (U:'u)`,
+                    // meaning that `(T:'t) => (U:'u)`. The answer is
+                    // if `U <: T` or `'u <= 't`. Let's see some examples:
+                    //
+                    //   (T: 'big) => (T: 'small)
+                    //   where 'small <= 'big
+                    //
+                    //   (&'small Foo: 't) => (&'big Foo: 't)
+                    //   where 'small <= 'big
+                    //   note that &'big Foo <: &'small Foo
 
                     let variance_r = self.xform(variance, self.contravariant);
+                    self.add_constraints_from_ty(generics, data.0, variance_r);
                     self.add_constraints_from_region(generics, data.1, variance_r);
                 }
 
@@ -1084,6 +1099,9 @@ fn add_constraints_from_predicates(&mut self,
                                                         &*data.projection_ty.trait_ref,
                                                         variance);
 
+                    // as the equality predicate above, a binder is a
+                    // type equality relation, not a subtyping
+                    // relation
                     self.add_constraints_from_ty(generics, data.ty, self.invariant);
                 }
             }
index cfa84de5ca7c9f37577877f1bc6f38ea347300ca..8022f2d466f78efa7cae4934d240d9496920e5e9 100644 (file)
@@ -356,7 +356,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
             });
             let text = lines.collect::<Vec<&str>>().connect("\n");
             tests.add_test(text.to_string(),
-                           block_info.should_fail, block_info.no_run,
+                           block_info.should_panic, block_info.no_run,
                            block_info.ignore, block_info.test_harness);
         }
     }
@@ -397,7 +397,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
 
 #[derive(Eq, PartialEq, Clone, Debug)]
 struct LangString {
-    should_fail: bool,
+    should_panic: bool,
     no_run: bool,
     ignore: bool,
     rust: bool,
@@ -407,7 +407,7 @@ struct LangString {
 impl LangString {
     fn all_false() -> LangString {
         LangString {
-            should_fail: false,
+            should_panic: false,
             no_run: false,
             ignore: false,
             rust: true,  // NB This used to be `notrust = false`
@@ -427,7 +427,7 @@ fn parse(string: &str) -> LangString {
         for token in tokens {
             match token {
                 "" => {},
-                "should_fail" => { data.should_fail = true; seen_rust_tags = true; },
+                "should_panic" => { data.should_panic = true; seen_rust_tags = true; },
                 "no_run" => { data.no_run = true; seen_rust_tags = true; },
                 "ignore" => { data.ignore = true; seen_rust_tags = true; },
                 "rust" => { data.rust = true; seen_rust_tags = true; },
@@ -528,9 +528,9 @@ mod tests {
     #[test]
     fn test_lang_string_parse() {
         fn t(s: &str,
-            should_fail: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool) {
+            should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool) {
             assert_eq!(LangString::parse(s), LangString {
-                should_fail: should_fail,
+                should_panic: should_panic,
                 no_run: no_run,
                 ignore: ignore,
                 rust: rust,
@@ -538,16 +538,16 @@ fn t(s: &str,
             })
         }
 
-        // marker                | should_fail | no_run | ignore | rust | test_harness
+        // marker                | should_panic| no_run | ignore | rust | test_harness
         t("",                      false,        false,   false,   true,  false);
         t("rust",                  false,        false,   false,   true,  false);
         t("sh",                    false,        false,   false,   false, false);
         t("ignore",                false,        false,   true,    true,  false);
-        t("should_fail",           true,         false,   false,   true,  false);
+        t("should_panic",          true,         false,   false,   true,  false);
         t("no_run",                false,        true,    false,   true,  false);
         t("test_harness",          false,        false,   false,   true,  true);
         t("{.no_run .example}",    false,        true,    false,   true,  false);
-        t("{.sh .should_fail}",    true,         false,   false,   true,  false);
+        t("{.sh .should_panic}",   true,         false,   false,   true,  false);
         t("{.example .rust}",      false,        false,   false,   true,  false);
         t("{.test_harness .rust}", false,        false,   false,   true,  true);
     }
index d57739c4002494165c4f48cf4fbc7abbce720425..d36124247945bf936f473641e49f704e82a0c7e7 100644 (file)
@@ -876,9 +876,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if let clean::ImplItem(ref i) = item.inner {
             match i.trait_ {
                 Some(clean::ResolvedPath{ did, .. }) => {
-                    let v = self.implementors.entry(did).get().unwrap_or_else(
-                        |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
-                    v.push(Implementor {
+                    self.implementors.entry(did).or_insert(vec![]).push(Implementor {
                         def_id: item.def_id,
                         generics: i.generics.clone(),
                         trait_: i.trait_.as_ref().unwrap().clone(),
@@ -1080,9 +1078,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                         };
 
                         if let Some(did) = did {
-                            let v = self.impls.entry(did).get().unwrap_or_else(
-                                |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
-                            v.push(Impl {
+                            self.impls.entry(did).or_insert(vec![]).push(Impl {
                                 impl_: i,
                                 dox: dox,
                                 stability: item.stability.clone(),
@@ -1334,9 +1330,8 @@ fn build_sidebar_items(&self, m: &clean::Module) -> HashMap<String, Vec<NameDoc>
                 Some(ref s) => s.to_string(),
             };
             let short = short.to_string();
-            let v = map.entry(short).get().unwrap_or_else(
-                |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
-            v.push((myname, Some(plain_summary_line(item.doc_value()))));
+            map.entry(short).or_insert(vec![])
+                .push((myname, Some(plain_summary_line(item.doc_value()))));
         }
 
         for (_, items) in &mut map {
index 9f1d876432c389c55cdf55e6c8d18f1fb25dfda5..a85f770f63ca49fceaea83886ab68397ee181985 100644 (file)
@@ -352,9 +352,7 @@ fn parse_externs(matches: &getopts::Matches) -> Result<core::Externs, String> {
             }
         };
         let name = name.to_string();
-        let locs = externs.entry(name).get().unwrap_or_else(
-            |vacant_entry| vacant_entry.insert(Vec::with_capacity(1)));
-        locs.push(location.to_string());
+        externs.entry(name).or_insert(vec![]).push(location.to_string());
     }
     Ok(externs)
 }
index f9558b85825d2ee03ebacde2850aa347441a4d3e..91225891338a58a42dc19542377103de57ff457f 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};
+use ops::{Deref, FnMut, FnOnce, Index};
 use option::Option::{self, Some, None};
 use rand::{self, Rng};
 use result::Result::{self, Ok, Err};
@@ -1488,12 +1488,37 @@ impl<'a, K, V> Entry<'a, K, V> {
     /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant.
     #[unstable(feature = "std_misc",
                reason = "will soon be replaced by or_insert")]
+    #[deprecated(since = "1.0",
+                reason = "replaced with more ergonomic `or_insert` and `or_insert_with`")]
+    /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
     pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, K, V>> {
         match self {
             Occupied(entry) => Ok(entry.into_mut()),
             Vacant(entry) => Err(entry),
         }
     }
+
+    #[unstable(feature = "collections",
+               reason = "matches entry v3 specification, waiting for dust to settle")]
+    /// Ensures a value is in the entry by inserting the default if empty, and returns
+    /// a mutable reference to the value in the entry.
+    pub fn or_insert(self, default: V) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default),
+        }
+    }
+
+    #[unstable(feature = "collections",
+               reason = "matches entry v3 specification, waiting for dust to settle")]
+    /// Ensures a value is in the entry by inserting the result of the default function if empty,
+    /// and returns a mutable reference to the value in the entry.
+    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default()),
+        }
+    }
 }
 
 impl<'a, K, V> OccupiedEntry<'a, K, V> {
index 052bcfd7e164951ac15fd7d576e8643b386225d1..710f0fe19db8e6d36782a44700db27857982277a 100644 (file)
@@ -985,7 +985,7 @@ fn clone(&self) -> RawTable<K, V> {
 #[unsafe_destructor]
 impl<K, V> Drop for RawTable<K, V> {
     fn drop(&mut self) {
-        if self.capacity == 0 {
+        if self.capacity == 0 || self.capacity == mem::POST_DROP_USIZE {
             return;
         }
 
index 8d24f6b191659f622aa6379aa4dc968ed8a2e499..0ac97b71298b85df6c737c6bec041bb512522544 100644 (file)
 //! let message = "she sells sea shells by the sea shore";
 //!
 //! for c in message.chars() {
-//!     match count.entry(c) {
-//!         Entry::Vacant(entry) => { entry.insert(1); },
-//!         Entry::Occupied(mut entry) => *entry.get_mut() += 1,
-//!     }
+//!     *count.entry(c).or_insert(0) += 1;
 //! }
 //!
 //! assert_eq!(count.get(&'s'), Some(&8));
 //! for id in orders.into_iter() {
 //!     // If this is the first time we've seen this customer, initialize them
 //!     // with no blood alcohol. Otherwise, just retrieve them.
-//!     let person = match blood_alcohol.entry(id) {
-//!         Entry::Vacant(entry) => entry.insert(Person{id: id, blood_alcohol: 0.0}),
-//!         Entry::Occupied(entry) => entry.into_mut(),
-//!     };
+//!     let person = blood_alcohol.entry(id).or_insert(Person{id: id, blood_alcohol: 0.0});
 //!
 //!     // Reduce their blood alcohol level. It takes time to order and drink a beer!
 //!     person.blood_alcohol *= 0.9;
index 5851c6e2998095923c744da0d01fceeb6556355b..24844ad096121eae28c384e048a27436fe1dccc7 100644 (file)
@@ -113,23 +113,9 @@ fn from(s: String) -> OsString {
 }
 
 #[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() }
+impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for OsString {
+    fn from(s: &'a T) -> OsString {
+        s.as_ref().to_os_string()
     }
 }
 
index 2a1294f23b20e9a33384abf6d83f14b5ab548a12..23cbe79145a0fb692f40a8210d902b8d942e2598 100644 (file)
@@ -681,7 +681,7 @@ fn test_chars() {
     }
 
     #[test]
-    #[should_fail]
+    #[should_panic]
     fn dont_panic_in_drop_on_panicked_flush() {
         struct FailFlushWriter;
 
index 0ed6d07bf79185331c6fb8a383cd99a44b96541b..5d62f1341e300f046100ffd2abcd7a112c4ebfa4 100644 (file)
@@ -609,8 +609,7 @@ fn read_line(&mut self, buf: &mut String) -> Result<usize> {
     ///
     /// This function will yield errors whenever `read_until` would have also
     /// yielded an error.
-    #[unstable(feature = "io", reason = "may be renamed to not conflict with \
-                                         SliceExt::split")]
+    #[stable(feature = "rust1", since = "1.0.0")]
     fn split(self, byte: u8) -> Split<Self> where Self: Sized {
         Split { buf: self, delim: byte }
     }
@@ -854,13 +853,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 /// particular byte.
 ///
 /// See `BufReadExt::split` for more information.
-#[unstable(feature = "io", reason = "awaiting stability of BufReadExt::split")]
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct Split<B> {
     buf: B,
     delim: u8,
 }
 
-#[unstable(feature = "io", reason = "awaiting stability of BufReadExt::split")]
+#[stable(feature = "rust1", since = "1.0.0")]
 impl<B: BufRead> Iterator for Split<B> {
     type Item = Result<Vec<u8>>;
 
index f3fb98e8c6683b8953d51e4d38da12aabdc0d714..dab270e3582659e957880369ac837db9c742a79c 100644 (file)
@@ -67,9 +67,8 @@
 //! module encapsulates the platform-specific rules for dealing
 //! with file paths.
 //!
-//! `std` also includes modules for interoperating with the
-//! C language: [`c_str`](c_str/index.html) and
-//! [`c_vec`](c_vec/index.html).
+//! `std` also includes the [`ffi`](ffi/index.html) module for interoperating
+//! with the C language.
 //!
 //! ## Concurrency, I/O, and the runtime
 //!
 #![feature(unboxed_closures)]
 #![feature(unicode)]
 #![feature(unsafe_destructor)]
-#![feature(unsafe_no_drop_flag)]
+#![feature(unsafe_no_drop_flag, filling_drop)]
 #![feature(macro_reexport)]
 #![feature(int_uint)]
 #![feature(unique)]
index 1681ed4282f48c9e2fa767e1868ab82674084aea..52492a019a2988170e2e94f52457b438264c5958 100644 (file)
@@ -28,7 +28,7 @@
 ///
 /// # Examples
 ///
-/// ```should_fail
+/// ```should_panic
 /// # #![allow(unreachable_code)]
 /// panic!();
 /// panic!("this is a terrible mistake!");
index dafca974bec0eacf96d39c766cb466fa68024996..a08b33b342bece06aebe3183e2646b9301a2d70b 100644 (file)
@@ -47,6 +47,15 @@ pub struct SocketAddrV4 { inner: libc::sockaddr_in }
 pub struct SocketAddrV6 { inner: libc::sockaddr_in6 }
 
 impl SocketAddr {
+    /// Creates a new socket address from the (ip, port) pair.
+    #[unstable(feature = "ip_addr", reason = "recent addition")]
+    pub fn new(ip: IpAddr, port: u16) -> SocketAddr {
+        match ip {
+            IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
+            IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
+        }
+    }
+
     /// Gets the IP address associated with this socket address.
     #[unstable(feature = "ip_addr", reason = "recent addition")]
     pub fn ip(&self) -> IpAddr {
index 7f51b1cba3fe796a8ef66bd4aab1ac06f792525f..68f3098d993c0510af6d2687bcb9d26a95c5841e 100644 (file)
@@ -111,3 +111,13 @@ fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
     net_imp::lookup_host(host).map(LookupHost)
 }
+
+/// Resolve the given address to a hostname.
+///
+/// This function may perform a DNS query to resolve `addr` and may also inspect
+/// system configuration to resolve the specified address. If the address
+/// cannot be resolved, it is returned in string format.
+#[unstable(feature = "lookup_addr", reason = "recent addition")]
+pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
+    net_imp::lookup_addr(addr)
+}
index e7509834c7b7866a83b2f52f564c40816c76781a..7c1667a603f65f7e8bcaf2cf3891f79320a32b0c 100644 (file)
@@ -16,7 +16,7 @@
 use prelude::v1::*;
 
 use str::FromStr;
-use net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
 
 struct Parser<'a> {
     // parsing as ASCII, so can use byte array
@@ -24,11 +24,6 @@ struct Parser<'a> {
     pos: usize,
 }
 
-enum IpAddr {
-    V4(Ipv4Addr),
-    V6(Ipv6Addr),
-}
-
 impl<'a> Parser<'a> {
     fn new(s: &'a str) -> Parser<'a> {
         Parser {
@@ -296,6 +291,17 @@ fn read_socket_addr(&mut self) -> Option<SocketAddr> {
     }
 }
 
+#[unstable(feature = "ip_addr", reason = "recent addition")]
+impl FromStr for IpAddr {
+    type Err = AddrParseError;
+    fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
+        match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
+            Some(s) => Ok(s),
+            None => Err(AddrParseError(()))
+        }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl FromStr for Ipv4Addr {
     type Err = AddrParseError;
index 9a9d421dfe1f02700d12a855837c7d1370e19699..9c42fbf5c16e11acf8851b0e0d1f62c3e53c2d52 100644 (file)
@@ -510,37 +510,37 @@ fn test_buffered_writer() {
 
         writer.write_all(&[0, 1]).unwrap();
         let b: &[_] = &[];
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
 
         writer.write_all(&[2]).unwrap();
         let b: &[_] = &[0, 1];
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
 
         writer.write_all(&[3]).unwrap();
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
 
         writer.flush().unwrap();
         let a: &[_] = &[0, 1, 2, 3];
-        assert_eq!(a, &writer.get_ref()[]);
+        assert_eq!(a, &writer.get_ref()[..]);
 
         writer.write_all(&[4]).unwrap();
         writer.write_all(&[5]).unwrap();
-        assert_eq!(a, &writer.get_ref()[]);
+        assert_eq!(a, &writer.get_ref()[..]);
 
         writer.write_all(&[6]).unwrap();
         let a: &[_] = &[0, 1, 2, 3, 4, 5];
-        assert_eq!(a, &writer.get_ref()[]);
+        assert_eq!(a, &writer.get_ref()[..]);
 
         writer.write_all(&[7, 8]).unwrap();
         let a: &[_] = &[0, 1, 2, 3, 4, 5, 6];
-        assert_eq!(a, &writer.get_ref()[]);
+        assert_eq!(a, &writer.get_ref()[..]);
 
         writer.write_all(&[9, 10, 11]).unwrap();
         let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
-        assert_eq!(a, &writer.get_ref()[]);
+        assert_eq!(a, &writer.get_ref()[..]);
 
         writer.flush().unwrap();
-        assert_eq!(a, &writer.get_ref()[]);
+        assert_eq!(a, &writer.get_ref()[..]);
     }
 
     #[test]
@@ -548,7 +548,7 @@ fn test_buffered_writer_inner_flushes() {
         let mut w = BufferedWriter::with_capacity(3, Vec::new());
         w.write_all(&[0, 1]).unwrap();
         let a: &[_] = &[];
-        assert_eq!(a, &w.get_ref()[]);
+        assert_eq!(a, &w.get_ref()[..]);
         let w = w.into_inner();
         let a: &[_] = &[0, 1];
         assert_eq!(a, &w[..]);
@@ -593,21 +593,21 @@ fn test_line_buffer() {
         let mut writer = LineBufferedWriter::new(Vec::new());
         writer.write_all(&[0]).unwrap();
         let b: &[_] = &[];
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
         writer.write_all(&[1]).unwrap();
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
         writer.flush().unwrap();
         let b: &[_] = &[0, 1];
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
         writer.write_all(&[0, b'\n', 1, b'\n', 2]).unwrap();
         let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n'];
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
         writer.flush().unwrap();
         let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2];
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
         writer.write_all(&[3, b'\n']).unwrap();
         let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n'];
-        assert_eq!(&writer.get_ref()[], b);
+        assert_eq!(&writer.get_ref()[..], b);
     }
 
     #[test]
index 40a7cce81dd01ebb8b85c7e481f30d0848612084..c2a0477b4d1704abac98528b2ca55b0e094ed3c7 100644 (file)
@@ -105,7 +105,7 @@ impl File {
     ///
     /// # Examples
     ///
-    /// ```rust,should_fail
+    /// ```rust,should_panic
     /// # #![feature(old_io, old_path)]
     /// use std::old_io::*;
     /// use std::old_path::Path;
index d7ede451fb8b79460b3916374ac59b4de9aad267..40be2a8b9d9c97ccbfac9a6fd7b31041255d3cb3 100644 (file)
@@ -60,7 +60,7 @@
 ///
 /// # Examples
 ///
-/// ```should_fail
+/// ```should_panic
 /// # #![feature(old_io)]
 /// use std::old_io::*;
 ///
index 50f79967f555ef86a707fcd4f96d798f9eb2daa9..58d3ae9f7cfabcff1c975fa162ac2cb6303e88da 100644 (file)
@@ -1038,23 +1038,16 @@ pub fn into_os_string(self) -> OsString {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<&'a Path> for PathBuf {
-    fn from(s: &'a Path) -> PathBuf {
-        s.to_path_buf()
+impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for PathBuf {
+    fn from(s: &'a T) -> PathBuf {
+        PathBuf::from(s.as_ref().to_os_string())
     }
 }
 
 #[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))
+impl From<OsString> for PathBuf {
+    fn from(s: OsString) -> PathBuf {
+        PathBuf { inner: s }
     }
 }
 
@@ -1065,27 +1058,6 @@ fn from(s: String) -> PathBuf {
     }
 }
 
-#[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 {
index 6a36ecefcf4466ef1bf033f7d651f2e46e8b6e59..b4bd513e8f027ce7c7514ce3ce0c3e613970fbb2 100644 (file)
@@ -37,7 +37,7 @@
 ///
 /// # Examples
 ///
-/// ```should_fail
+/// ```should_panic
 /// # #![feature(process)]
 ///
 /// use std::process::Command;
index e213a86644fe1ee5fd7f14e976b53874def7342f..a8ee40639e32ee3fcda50ff9acdd78c0ef6290ba 100644 (file)
 
 use prelude::v1::*;
 
-use ffi::CString;
+use ffi::{CStr, CString};
 use io::{self, Error, ErrorKind};
 use libc::{self, c_int, c_char, c_void, socklen_t};
 use mem;
 use net::{SocketAddr, Shutdown, IpAddr};
+use str::from_utf8;
 use sys::c;
 use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
 use sys_common::{AsInner, FromInner, IntoInner};
@@ -126,6 +127,42 @@ pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// lookup_addr
+////////////////////////////////////////////////////////////////////////////////
+
+extern "system" {
+    fn getnameinfo(sa: *const libc::sockaddr, salen: socklen_t,
+                   host: *mut c_char, hostlen: libc::size_t,
+                   serv: *mut c_char, servlen: libc::size_t,
+                   flags: c_int) -> c_int;
+}
+
+const NI_MAXHOST: usize = 1025;
+
+pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
+    init();
+
+    let saddr = SocketAddr::new(*addr, 0);
+    let (inner, len) = saddr.into_inner();
+    let mut hostbuf = [0 as c_char; NI_MAXHOST];
+
+    let data = unsafe {
+        try!(cvt_gai(getnameinfo(inner, len,
+                                 hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t,
+                                 0 as *mut _, 0, 0)));
+
+        CStr::from_ptr(hostbuf.as_ptr())
+    };
+
+    match from_utf8(data.to_bytes()) {
+        Ok(name) => Ok(name.to_string()),
+        Err(_) => Err(io::Error::new(io::ErrorKind::Other,
+                                     "failed to lookup address information",
+                                     Some("invalid host name".to_string())))
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // TCP streams
 ////////////////////////////////////////////////////////////////////////////////
index 3b8d18d87a0cafbe3f8d7c44237a4bf5fa17d27b..69d876a48a4b22b3421aa8e293c074dc1497c7af 100644 (file)
@@ -46,10 +46,6 @@ pub fn from_string(s: String) -> Buf {
         Buf { inner: s.into_bytes() }
     }
 
-    pub fn from_str(s: &str) -> Buf {
-        Buf { inner: s.as_bytes().to_vec() }
-    }
-
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
index ad1e6c4b0e727eeb0f0776f3ae4bf8c6f2e802a4..91905ae7489d528b100b874e19183cedaeca9e4c 100644 (file)
@@ -45,10 +45,6 @@ pub fn from_string(s: String) -> Buf {
         Buf { inner: Wtf8Buf::from_string(s) }
     }
 
-    pub fn from_str(s: &str) -> Buf {
-        Buf { inner: Wtf8Buf::from_str(s) }
-    }
-
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(self.inner.as_slice()) }
     }
index 27b50fc9aaa60ca0312245161eb46c48b8a8f61e..074030bd07bdb7853f1f9e4d70a61836d3044043 100644 (file)
@@ -434,6 +434,55 @@ pub fn panicking() -> bool {
     unwind::panicking()
 }
 
+/// Invoke a closure, capturing the cause of panic if one occurs.
+///
+/// This function will return `Ok(())` if the closure does not panic, and will
+/// return `Err(cause)` if the closure panics. The `cause` returned is the
+/// object with which panic was originally invoked.
+///
+/// It is currently undefined behavior to unwind from Rust code into foreign
+/// code, so this function is particularly useful when Rust is called from
+/// another language (normally C). This can run arbitrary Rust code, capturing a
+/// panic and allowing a graceful handling of the error.
+///
+/// It is **not** recommended to use this function for a general try/catch
+/// mechanism. The `Result` type is more appropriate to use for functions that
+/// can fail on a regular basis.
+///
+/// The closure provided is required to adhere to the `'static` bound to ensure
+/// that it cannot reference data in the parent stack frame, mitigating problems
+/// with exception safety. Furthermore, a `Send` bound is also required,
+/// providing the same safety guarantees as `thread::spawn` (ensuring the
+/// closure is properly isolated from the parent).
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(catch_panic)]
+/// use std::thread;
+///
+/// let result = thread::catch_panic(|| {
+///     println!("hello!");
+/// });
+/// assert!(result.is_ok());
+///
+/// let result = thread::catch_panic(|| {
+///     panic!("oh no!");
+/// });
+/// assert!(result.is_err());
+/// ```
+#[unstable(feature = "catch_panic", reason = "recent API addition")]
+pub fn catch_panic<F, R>(f: F) -> Result<R>
+    where F: FnOnce() -> R + Send + 'static
+{
+    let mut result = None;
+    unsafe {
+        let result = &mut result;
+        try!(::rt::unwind::try(move || *result = Some(f())))
+    }
+    Ok(result.unwrap())
+}
+
 /// Put the current thread to sleep for the specified amount of time.
 ///
 /// The thread may sleep longer than the duration specified due to scheduling
@@ -821,13 +870,13 @@ fn test_scoped_success() {
     }
 
     #[test]
-    #[should_fail]
+    #[should_panic]
     fn test_scoped_panic() {
         thread::scoped(|| panic!()).join();
     }
 
     #[test]
-    #[should_fail]
+    #[should_panic]
     fn test_scoped_implicit_panic() {
         let _ = thread::scoped(|| panic!());
     }
index 72431d8e6aa2c317ccd23aa9449193f01445c344..a2023d6832efbce2fe48cf33ed7e85962fc9c431 100644 (file)
@@ -66,9 +66,8 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext {
 /// Extend a syntax context with a given mark and sctable (explicit memoization)
 fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext {
     let key = (ctxt, m);
-    * table.mark_memo.borrow_mut().entry(key).get().unwrap_or_else(
-          |vacant_entry|
-              vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))))
+    * table.mark_memo.borrow_mut().entry(key)
+        .or_insert_with(|| idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt)))
 }
 
 /// Extend a syntax context with a given rename
@@ -84,9 +83,8 @@ fn apply_rename_internal(id: Ident,
                        table: &SCTable) -> SyntaxContext {
     let key = (ctxt, id, to);
 
-    * table.rename_memo.borrow_mut().entry(key).get().unwrap_or_else(
-          |vacant_entry|
-              vacant_entry.insert(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))))
+    * table.rename_memo.borrow_mut().entry(key)
+        .or_insert_with(|| idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt)))
 }
 
 /// Apply a list of renamings to a context
index c11ffe66e6c392305450dd13706994e6ba3ed812..2f609d86f39ffdb1d82bee877d44ef7ec2a7a690 100644 (file)
@@ -171,10 +171,12 @@ fn to_source_with_hygiene(&self) -> String {
         }
     }
 
+    impl_to_source! { ast::Path, path_to_string }
     impl_to_source! { ast::Ty, ty_to_string }
     impl_to_source! { ast::Block, block_to_string }
     impl_to_source! { ast::Arg, arg_to_string }
     impl_to_source! { Generics, generics_to_string }
+    impl_to_source! { ast::WhereClause, where_clause_to_string }
     impl_to_source! { P<ast::Item>, item_to_string }
     impl_to_source! { P<ast::ImplItem>, impl_item_to_string }
     impl_to_source! { P<ast::TraitItem>, trait_item_to_string }
@@ -309,6 +311,7 @@ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
     }
 
     impl_to_tokens! { ast::Ident }
+    impl_to_tokens! { ast::Path }
     impl_to_tokens! { P<ast::Item> }
     impl_to_tokens! { P<ast::ImplItem> }
     impl_to_tokens! { P<ast::TraitItem> }
@@ -318,6 +321,7 @@ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
     impl_to_tokens! { ast::Ty }
     impl_to_tokens_lifetime! { &'a [ast::Ty] }
     impl_to_tokens! { Generics }
+    impl_to_tokens! { ast::WhereClause }
     impl_to_tokens! { P<ast::Stmt> }
     impl_to_tokens! { P<ast::Expr> }
     impl_to_tokens! { ast::Block }
index 60f81dac1e9abaf09fc2e1c7cba5c113b9030fdc..9c3be5018f2b538af1d90f180ee3e6a1af19b435 100644 (file)
@@ -54,7 +54,6 @@
     ("non_ascii_idents", "1.0.0", Active),
     ("thread_local", "1.0.0", Active),
     ("link_args", "1.0.0", Active),
-    ("phase", "1.0.0", Removed),
     ("plugin_registrar", "1.0.0", Active),
     ("log_syntax", "1.0.0", Active),
     ("trace_macros", "1.0.0", Active),
@@ -74,6 +73,7 @@
 
     ("rustc_diagnostic_macros", "1.0.0", Active),
     ("unboxed_closures", "1.0.0", Active),
+    ("reflect", "1.0.0", Active),
     ("import_shadowing", "1.0.0", Removed),
     ("advanced_slice_patterns", "1.0.0", Active),
     ("tuple_indexing", "1.0.0", Accepted),
@@ -201,7 +201,6 @@ enum Status {
     ("no_mangle", Normal),
     ("no_link", Normal),
     ("derive", Normal),
-    ("should_fail", Normal),
     ("should_panic", Normal),
     ("ignore", Normal),
     ("no_implicit_prelude", Normal),
@@ -281,7 +280,11 @@ enum Status {
     // FIXME: #19470 this shouldn't be needed forever
     ("old_orphan_check", Whitelisted),
     ("old_impl_check", Whitelisted),
-    ("rustc_paren_sugar", Whitelisted), // FIXME: #18101 temporary unboxed closure hack
+
+    ("rustc_paren_sugar", Gated("unboxed_closures",
+                                "unboxed_closures are still evolving")),
+    ("rustc_reflect_like", Gated("reflect",
+                                 "defining reflective traits is still evolving")),
 
     // Crate level attributes
     ("crate_name", CrateLevel),
index 105a61d085725e8c004f1f8200d3c5d50b877167..d4451cc7b71243ea87a0b847d2e6941412a7d1f1 100644 (file)
@@ -40,7 +40,7 @@ fn move_map<F>(mut self, mut f: F) -> Vec<T> where F: FnMut(T) -> T {
         for p in &mut self {
             unsafe {
                 // FIXME(#5016) this shouldn't need to zero to be safe.
-                ptr::write(p, f(ptr::read_and_zero(p)));
+                ptr::write(p, f(ptr::read_and_drop(p)));
             }
         }
         self
index 9af7b9ab633116619c2e9ff3cc12b4ad28e5ad74..72498afa3201e7c9383c46edd05ca78ded6d5bb3 100644 (file)
@@ -35,7 +35,6 @@
 #![feature(quote, unsafe_destructor)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(std_misc)]
 #![feature(unicode)]
 #![feature(path_ext)]
 #![feature(str_char)]
index 0843713681bbdaad8b27502a7b8c34956ba151de..e11e9f62a5b379c44c3363e7713776ecd7234fa1 100644 (file)
@@ -742,6 +742,7 @@ fn scan_hex_digits(&mut self,
         let start_bpos = self.last_pos;
         let mut accum_int = 0;
 
+        let mut valid = true;
         for _ in 0..n_digits {
             if self.is_eof() {
                 let last_bpos = self.last_pos;
@@ -750,6 +751,7 @@ fn scan_hex_digits(&mut self,
             if self.curr_is(delim) {
                 let last_bpos = self.last_pos;
                 self.err_span_(start_bpos, last_bpos, "numeric character escape is too short");
+                valid = false;
                 break;
             }
             let c = self.curr.unwrap_or('\x00');
@@ -757,6 +759,8 @@ fn scan_hex_digits(&mut self,
             accum_int += c.to_digit(16).unwrap_or_else(|| {
                 self.err_span_char(self.last_pos, self.pos,
                               "illegal character in numeric character escape", c);
+
+                valid = false;
                 0
             });
             self.bump();
@@ -767,10 +771,11 @@ fn scan_hex_digits(&mut self,
                            self.last_pos,
                            "this form of character escape may only be used \
                             with characters in the range [\\x00-\\x7f]");
+            valid = false;
         }
 
         match char::from_u32(accum_int) {
-            Some(_) => true,
+            Some(_) => valid,
             None => {
                 let last_bpos = self.last_pos;
                 self.err_span_(start_bpos, last_bpos, "illegal numeric character escape");
@@ -799,7 +804,18 @@ fn scan_char_or_byte(&mut self, start: BytePos, first_source_char: char,
                             'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true,
                             'x' => self.scan_byte_escape(delim, !ascii_only),
                             'u' if self.curr_is('{') => {
-                                self.scan_unicode_escape(delim)
+                            let valid = self.scan_unicode_escape(delim);
+                            if valid && ascii_only {
+                                self.err_span_(
+                                    escaped_pos,
+                                    self.last_pos,
+                                    "unicode escape sequences cannot be used as a byte or in \
+                                    a byte string"
+                                );
+                                false
+                            } else {
+                               valid
+                            }
                             }
                             '\n' if delim == '"' => {
                                 self.consume_whitespace();
@@ -869,6 +885,7 @@ fn scan_unicode_escape(&mut self, delim: char) -> bool {
         let start_bpos = self.last_pos;
         let mut count = 0;
         let mut accum_int = 0;
+        let mut valid = true;
 
         while !self.curr_is('}') && count <= 6 {
             let c = match self.curr {
@@ -884,29 +901,30 @@ fn scan_unicode_escape(&mut self, delim: char) -> bool {
                     self.fatal_span_(self.last_pos, self.pos,
                                      "unterminated unicode escape (needed a `}`)");
                 } else {
-                    self.fatal_span_char(self.last_pos, self.pos,
+                    self.err_span_char(self.last_pos, self.pos,
                                    "illegal character in unicode escape", c);
                 }
+                valid = false;
+                0
             });
             self.bump();
             count += 1;
         }
 
         if count > 6 {
-            self.fatal_span_(start_bpos, self.last_pos,
+            self.err_span_(start_bpos, self.last_pos,
                           "overlong unicode escape (can have at most 6 hex digits)");
+            valid = false;
         }
 
         self.bump(); // past the ending }
 
-        let mut valid = count >= 1 && count <= 6;
-        if char::from_u32(accum_int).is_none() {
-            valid = false;
+        if valid && (char::from_u32(accum_int).is_none() || count == 0) {
+            self.err_span_(start_bpos, self.last_pos, "illegal unicode character escape");
+            valid= false;
         }
 
-        if !valid {
-            self.fatal_span_(start_bpos, self.last_pos, "illegal unicode character escape");
-        }
+
         valid
     }
 
@@ -1330,7 +1348,7 @@ fn scan_byte(&mut self) -> token::Lit {
                 "unterminated byte constant".to_string());
         }
 
-        let id = if valid { self.name_from(start) } else { token::intern("??") };
+        let id = if valid { self.name_from(start) } else { token::intern("?") };
         self.bump(); // advance curr past token
         return token::Byte(id);
     }
index 276be73823a421dec63d6a22791bfd239f634d43..bb9b586bb3f3d1914320b1d452ba0678905cfc77 100644 (file)
@@ -23,7 +23,6 @@
 #[derive(Copy, PartialEq, Eq, Hash)]
 pub enum ObsoleteSyntax {
     ClosureKind,
-    EmptyIndex,
     ExternCrateString,
 }
 
@@ -52,11 +51,6 @@ fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
                 "rely on inference instead",
                 true,
             ),
-            ObsoleteSyntax::EmptyIndex => (
-                "[]",
-                "write `[..]` instead",
-                false, // warning for now
-            ),
             ObsoleteSyntax::ExternCrateString => (
                 "\"crate-name\"",
                 "use an identifier not in quotes instead",
index 220ea30256e03cba2014e41a1bdb663671b95e49..9d8d4eec18a085907fbf151232dc0f01d1173713 100644 (file)
@@ -1126,7 +1126,7 @@ pub fn parse_trait_items(&mut self) -> Vec<P<TraitItem>> {
                     p.parse_arg_general(false)
                 });
 
-                p.parse_where_clause(&mut generics);
+                generics.where_clause = p.parse_where_clause();
                 let sig = ast::MethodSig {
                     unsafety: style,
                     decl: d,
@@ -2312,46 +2312,13 @@ pub fn parse_dot_or_call_expr_with(&mut self, e0: P<Expr>) -> P<Expr> {
               // expr[...]
               // Could be either an index expression or a slicing expression.
               token::OpenDelim(token::Bracket) => {
-                let bracket_pos = self.span.lo;
                 self.bump();
 
-                if self.eat(&token::CloseDelim(token::Bracket)) {
-                    // No expression, expand to a RangeFull
-                    // FIXME(#20516) It would be better to use a lang item or
-                    // something for RangeFull.
-                    hi = self.last_span.hi;
-
-                    let idents = vec![token::str_to_ident("std"),
-                                      token::str_to_ident("ops"),
-                                      token::str_to_ident("RangeFull")];
-                    let segments = idents.into_iter().map(|ident| {
-                        ast::PathSegment {
-                            identifier: ident,
-                            parameters: ast::PathParameters::none(),
-                        }
-                    }).collect();
-                    let span = mk_sp(lo, hi);
-                    let path = ast::Path {
-                        span: span,
-                        global: true,
-                        segments: segments,
-                    };
-
-                    let range = ExprStruct(path, vec![], None);
-                    let ix = self.mk_expr(bracket_pos, hi, range);
-                    let index = self.mk_index(e, ix);
-                    e = self.mk_expr(lo, hi, index);
-
-                    let obsolete_span = mk_sp(bracket_pos, hi);
-                    self.obsolete(obsolete_span, ObsoleteSyntax::EmptyIndex);
-                } else {
-                    let ix = self.parse_expr();
-                    hi = self.span.hi;
-                    self.commit_expr_expecting(&*ix, token::CloseDelim(token::Bracket));
-                    let index = self.mk_index(e, ix);
-                    e = self.mk_expr(lo, hi, index)
-                }
-
+                let ix = self.parse_expr();
+                hi = self.span.hi;
+                self.commit_expr_expecting(&*ix, token::CloseDelim(token::Bracket));
+                let index = self.mk_index(e, ix);
+                e = self.mk_expr(lo, hi, index)
               }
               _ => return e
             }
@@ -3932,9 +3899,14 @@ fn forbid_lifetime(&mut self) {
     /// ```
     /// where T : Trait<U, V> + 'b, 'a : 'b
     /// ```
-    fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
+    fn parse_where_clause(&mut self) -> ast::WhereClause {
+        let mut where_clause = WhereClause {
+            id: ast::DUMMY_NODE_ID,
+            predicates: Vec::new(),
+        };
+
         if !self.eat_keyword(keywords::Where) {
-            return
+            return where_clause;
         }
 
         let mut parsed_something = false;
@@ -3957,7 +3929,7 @@ fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
                     let hi = self.span.hi;
                     let span = mk_sp(lo, hi);
 
-                    generics.where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
+                    where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
                         ast::WhereRegionPredicate {
                             span: span,
                             lifetime: bounded_lifetime,
@@ -3992,7 +3964,7 @@ fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
                                            at least one bound in it");
                         }
 
-                        generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
+                        where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
                                 ast::WhereBoundPredicate {
                                     span: span,
                                     bound_lifetimes: bound_lifetimes,
@@ -4005,7 +3977,7 @@ fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
                         // let ty = self.parse_ty();
                         let hi = self.span.hi;
                         let span = mk_sp(lo, hi);
-                        // generics.where_clause.predicates.push(
+                        // where_clause.predicates.push(
                         //     ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
                         //         id: ast::DUMMY_NODE_ID,
                         //         span: span,
@@ -4036,6 +4008,8 @@ fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
                           "a `where` clause must have at least one predicate \
                            in it");
         }
+
+        where_clause
     }
 
     fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool)
@@ -4354,7 +4328,7 @@ fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident,
     fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> ItemInfo {
         let (ident, mut generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl(false);
-        self.parse_where_clause(&mut generics);
+        generics.where_clause = self.parse_where_clause();
         let (inner_attrs, body) = self.parse_inner_attrs_and_block();
         (ident, ItemFn(decl, unsafety, abi, generics, body), Some(inner_attrs))
     }
@@ -4439,7 +4413,7 @@ fn parse_impl_method(&mut self, vis: Visibility)
             let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
                     p.parse_arg()
                 });
-            self.parse_where_clause(&mut generics);
+            generics.where_clause = self.parse_where_clause();
             let (inner_attrs, body) = self.parse_inner_attrs_and_block();
             (ident, inner_attrs, MethodImplItem(ast::MethodSig {
                 generics: generics,
@@ -4460,7 +4434,7 @@ fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
         // Parse supertrait bounds.
         let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare);
 
-        self.parse_where_clause(&mut tps);
+        tps.where_clause = self.parse_where_clause();
 
         let meths = self.parse_trait_items();
         (ident, ItemTrait(unsafety, tps, bounds, meths), None)
@@ -4531,7 +4505,7 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo {
             if opt_trait.is_some() {
                 ty = self.parse_ty_sum();
             }
-            self.parse_where_clause(&mut generics);
+            generics.where_clause = self.parse_where_clause();
 
             self.expect(&token::OpenDelim(token::Brace));
             let attrs = self.parse_inner_attributes();
@@ -4603,7 +4577,7 @@ fn parse_item_struct(&mut self) -> ItemInfo {
         // struct.
 
         let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) {
-            self.parse_where_clause(&mut generics);
+            generics.where_clause = self.parse_where_clause();
             if self.eat(&token::Semi) {
                 // If we see a: `struct Foo<T> where T: Copy;` style decl.
                 (Vec::new(), Some(ast::DUMMY_NODE_ID))
@@ -4684,12 +4658,12 @@ pub fn parse_tuple_struct_body(&mut self,
                     token::get_ident(class_name.clone())));
             }
 
-            self.parse_where_clause(generics);
+            generics.where_clause = self.parse_where_clause();
             self.expect(&token::Semi);
             fields
         // This is the case where we just see struct Foo<T> where T: Copy;
         } else if self.token.is_keyword(keywords::Where) {
-            self.parse_where_clause(generics);
+            generics.where_clause = self.parse_where_clause();
             self.expect(&token::Semi);
             Vec::new()
         // This case is where we see: `struct Foo<T>;`
@@ -4937,7 +4911,7 @@ fn parse_item_foreign_fn(&mut self, vis: ast::Visibility,
 
         let (ident, mut generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl(true);
-        self.parse_where_clause(&mut generics);
+        generics.where_clause = self.parse_where_clause();
         let hi = self.span.hi;
         self.expect(&token::Semi);
         P(ast::ForeignItem {
@@ -5074,7 +5048,7 @@ fn parse_item_foreign_mod(&mut self,
     fn parse_item_type(&mut self) -> ItemInfo {
         let ident = self.parse_ident();
         let mut tps = self.parse_generics();
-        self.parse_where_clause(&mut tps);
+        tps.where_clause = self.parse_where_clause();
         self.expect(&token::Eq);
         let ty = self.parse_ty_sum();
         self.expect(&token::Semi);
@@ -5174,7 +5148,7 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> EnumDef {
     fn parse_item_enum(&mut self) -> ItemInfo {
         let id = self.parse_ident();
         let mut generics = self.parse_generics();
-        self.parse_where_clause(&mut generics);
+        generics.where_clause = self.parse_where_clause();
         self.expect(&token::OpenDelim(token::Brace));
 
         let enum_definition = self.parse_enum_def(&generics);
index 2bc3fc1017ae6808e7940d2e7b75822fe8f8408d..da1b7a7bdde50e93ec50a11aac7702b4db45b759 100644 (file)
@@ -367,6 +367,10 @@ pub fn generics_to_string(generics: &ast::Generics) -> String {
     $to_string(|s| s.print_generics(generics))
 }
 
+pub fn where_clause_to_string(i: &ast::WhereClause) -> String {
+    $to_string(|s| s.print_where_clause(i))
+}
+
 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
     $to_string(|s| s.print_fn_block_args(p))
 }
@@ -917,7 +921,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                 try!(space(&mut self.s));
                 try!(self.word_space("="));
                 try!(self.print_type(&**ty));
-                try!(self.print_where_clause(params));
+                try!(self.print_where_clause(&params.where_clause));
                 try!(word(&mut self.s, ";"));
                 try!(self.end()); // end the outer ibox
             }
@@ -980,7 +984,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                 }
 
                 try!(self.print_type(&**ty));
-                try!(self.print_where_clause(generics));
+                try!(self.print_where_clause(&generics.where_clause));
 
                 try!(space(&mut self.s));
                 try!(self.bopen());
@@ -1008,7 +1012,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                     }
                 }
                 try!(self.print_bounds(":", &real_bounds[..]));
-                try!(self.print_where_clause(generics));
+                try!(self.print_where_clause(&generics.where_clause));
                 try!(word(&mut self.s, " "));
                 try!(self.bopen());
                 for trait_item in trait_items {
@@ -1066,7 +1070,7 @@ pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
         try!(self.head(&visibility_qualified(visibility, "enum")));
         try!(self.print_ident(ident));
         try!(self.print_generics(generics));
-        try!(self.print_where_clause(generics));
+        try!(self.print_where_clause(&generics.where_clause));
         try!(space(&mut self.s));
         self.print_variants(&enum_definition.variants, span)
     }
@@ -1120,12 +1124,12 @@ pub fn print_struct(&mut self,
                 ));
                 try!(self.pclose());
             }
-            try!(self.print_where_clause(generics));
+            try!(self.print_where_clause(&generics.where_clause));
             try!(word(&mut self.s, ";"));
             try!(self.end());
             self.end() // close the outer-box
         } else {
-            try!(self.print_where_clause(generics));
+            try!(self.print_where_clause(&generics.where_clause));
             try!(self.nbsp());
             try!(self.bopen());
             try!(self.hardbreak_if_not_bol());
@@ -2348,7 +2352,7 @@ pub fn print_fn(&mut self,
         }
         try!(self.print_generics(generics));
         try!(self.print_fn_args_and_ret(decl, opt_explicit_self));
-        self.print_where_clause(generics)
+        self.print_where_clause(&generics.where_clause)
     }
 
     pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
@@ -2531,19 +2535,16 @@ pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
         }
     }
 
-    pub fn print_where_clause(&mut self, generics: &ast::Generics)
+    pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
                               -> io::Result<()> {
-        if generics.where_clause.predicates.len() == 0 {
+        if where_clause.predicates.len() == 0 {
             return Ok(())
         }
 
         try!(space(&mut self.s));
         try!(self.word_space("where"));
 
-        for (i, predicate) in generics.where_clause
-                                      .predicates
-                                      .iter()
-                                      .enumerate() {
+        for (i, predicate) in where_clause.predicates.iter().enumerate() {
             if i != 0 {
                 try!(self.word_space(","));
             }
index ca3a1848c3a6161313590be914a2b5d1a2756302..7e0bcd3e1dc3f8a2229823209c8d47a9cb722bdc 100644 (file)
@@ -71,8 +71,8 @@ pub fn map<F>(mut self, f: F) -> P<T> where
     {
         unsafe {
             let p = &mut *self.ptr;
-            // FIXME(#5016) this shouldn't need to zero to be safe.
-            ptr::write(p, f(ptr::read_and_zero(p)));
+            // FIXME(#5016) this shouldn't need to drop-fill to be safe.
+            ptr::write(p, f(ptr::read_and_drop(p)));
         }
         self
     }
index 2a47a696b1cf2ad8745b1c92d9667973a5ed96f7..fbee11ee657c3411740dc29305edf7296c42acd7 100644 (file)
@@ -134,7 +134,7 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                         path: self.cx.path.clone(),
                         bench: is_bench_fn(&self.cx, &*i),
                         ignore: is_ignored(&*i),
-                        should_panic: should_panic(&*i, self.cx.span_diagnostic)
+                        should_panic: should_panic(&*i)
                     };
                     self.cx.testfns.push(test);
                     self.tests.push(i.ident);
@@ -386,16 +386,8 @@ fn is_ignored(i: &ast::Item) -> bool {
     i.attrs.iter().any(|attr| attr.check_name("ignore"))
 }
 
-fn should_panic(i: &ast::Item, diag: &diagnostic::SpanHandler) -> ShouldPanic {
-    match i.attrs.iter().find(|attr| {
-        if attr.check_name("should_panic") { return true; }
-        if attr.check_name("should_fail") {
-            diag.span_warn(attr.span, "`#[should_fail]` is deprecated. Use `#[should_panic]` \
-                                       instead");
-            return true;
-        }
-        false
-    }) {
+fn should_panic(i: &ast::Item) -> ShouldPanic {
+    match i.attrs.iter().find(|attr| attr.check_name("should_panic")) {
         Some(attr) => {
             let msg = attr.meta_item_list()
                 .and_then(|list| list.iter().find(|mi| mi.check_name("expected")))
index 82d07a9df4e12662e428d1feb51cffb1ea716e81..bd47054f093ce71ebe0d1ba5c7a3cd41d0a99f9c 100644 (file)
@@ -10,7 +10,7 @@
 
 #![feature(core)]
 
-use std::any::TypeId;
+use std::any::{Any, TypeId};
 
 pub struct A;
 pub struct B(Option<A>);
@@ -31,4 +31,4 @@ pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
 pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
 pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
 
-pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
+pub unsafe fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
index 82d07a9df4e12662e428d1feb51cffb1ea716e81..5e81bf50ae449f0f9f3d48de057741c132b25746 100644 (file)
@@ -10,7 +10,7 @@
 
 #![feature(core)]
 
-use std::any::TypeId;
+use std::any::{Any, TypeId};
 
 pub struct A;
 pub struct B(Option<A>);
@@ -31,4 +31,4 @@ pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
 pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
 pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
 
-pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
+pub unsafe fn foo<T:Any>() -> TypeId { TypeId::of::<T>() }
index 6cd758361870ee4e8ec84713f82b1884f4c2ab16..42051e33e2e0d673ab74160f51c3094be65f81dc 100644 (file)
@@ -47,7 +47,7 @@ fn new() -> Noise2DContext {
         let mut rng = StdRng::new().unwrap();
 
         let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }; 256];
-        for x in &mut rgradients[] {
+        for x in &mut rgradients[..] {
             *x = random_gradient(&mut rng);
         }
 
diff --git a/src/test/compile-fail/deprecated-phase.rs b/src/test/compile-fail/deprecated-phase.rs
deleted file mode 100644 (file)
index 22fc4a9..0000000
+++ /dev/null
@@ -1,17 +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(custom_attribute)]
-
-#[phase(blah)]
-//~^ ERROR #[phase] is deprecated
-extern crate foo;
-
-fn main() {}
index c251ce6a3c834960942f371f538b704cb7e6294b..fc4fa838a5693078afab08222be45fd89b727501 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags:-l :static
+// compile-flags:-l static=
 // error-pattern: empty library name given via `-l`
 
 fn main() {
index 5ab073c33bcb310e15588af7249852e143f069c8..e9cbdb099480c4aca9d80700cd6962819805bdc6 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags:-l foo:bar
+// compile-flags:-l bar=foo
 // error-pattern: unknown library kind `bar`, expected one of dylib, framework, or static
 
 fn main() {
index 96cc35049ee40e309fb4ea4e7a083b0dc1680142..97176a533d2bd0d5e48d2aaa945d082ce106af1a 100644 (file)
@@ -10,7 +10,7 @@
 
 // ignore-macos
 // ignore-ios
-// compile-flags:-l foo:framework
+// compile-flags:-l framework=foo
 // error-pattern: native frameworks are only available on OSX targets
 
 fn main() {
diff --git a/src/test/compile-fail/plugin-extern-crate-attr-deprecated.rs b/src/test/compile-fail/plugin-extern-crate-attr-deprecated.rs
deleted file mode 100644 (file)
index efa352e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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(plugin)]
-
-#[plugin]  //~ ERROR #[plugin] on `extern crate` is deprecated
-//~^ HELP use a crate attribute instead, i.e. #![plugin(std)]
-extern crate std;
-
-fn main() {}
diff --git a/src/test/compile-fail/reflect-assoc.rs b/src/test/compile-fail/reflect-assoc.rs
new file mode 100644 (file)
index 0000000..9cf0d25
--- /dev/null
@@ -0,0 +1,35 @@
+// 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 types that appear in assoc bindings in an object
+// type are subject to the reflect check.
+
+use std::marker::Reflect;
+use std::io::Write;
+
+trait Get {
+    type Output;
+    fn get(self) -> Self::Output;
+}
+
+struct Struct<T>(T);
+
+fn is_reflect<T:Reflect>() { }
+
+fn a<T>() {
+    is_reflect::<Box<Get<Output=T>>>(); //~ ERROR not implemented
+}
+
+fn ok_a<T: Reflect>() {
+    is_reflect::<Box<Get<Output=T>>>(); // OK
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/reflect-object-param.rs b/src/test/compile-fail/reflect-object-param.rs
new file mode 100644 (file)
index 0000000..9f07466
--- /dev/null
@@ -0,0 +1,47 @@
+// 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 types that appear in input types in an object type are
+// subject to the reflect check.
+
+use std::marker::Reflect;
+use std::io::Write;
+
+trait Get<T> {
+    fn get(self) -> T;
+}
+
+struct Struct<T>(T);
+
+fn is_reflect<T:Reflect>() { }
+
+fn a<T>() {
+    is_reflect::<T>(); //~ ERROR not implemented
+}
+
+fn ok_a<T: Reflect>() {
+    is_reflect::<T>(); // OK
+}
+
+fn b<T>() {
+    is_reflect::<Box<Get<T>>>(); //~ ERROR not implemented
+}
+
+fn ok_b<T: Reflect>() {
+    is_reflect::<Box<Get<T>>>(); // OK
+}
+
+fn c<T>() {
+    is_reflect::<Box<Get<Struct<T>>>>(); //~ ERROR not implemented
+}
+
+fn main() {
+    is_reflect::<Box<Get<Struct<()>>>>(); // OK
+}
diff --git a/src/test/compile-fail/reflect.rs b/src/test/compile-fail/reflect.rs
new file mode 100644 (file)
index 0000000..701aa5b
--- /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.
+
+// Test that there is no way to get a generic type `T` to be
+// considered as `Reflect` (or accessible via something that is
+// considered `Reflect`) without a reflect bound, but that any
+// concrete type works fine. Note that object types are tested
+// separately.
+
+use std::marker::Reflect;
+use std::io::Write;
+
+struct Struct<T>(T);
+
+fn is_reflect<T:Reflect>() { }
+
+fn c<T>() {
+    is_reflect::<Struct<T>>(); //~ ERROR not implemented
+}
+
+fn ok_c<T: Reflect>() {
+    is_reflect::<Struct<T>>(); // OK
+}
+
+fn d<T>() {
+    is_reflect::<(i32, T)>(); //~ ERROR not implemented
+}
+
+fn main() {
+    is_reflect::<&i32>(); // OK
+    is_reflect::<Box<Write>>(); // OK
+}
diff --git a/src/test/compile-fail/slice-1.rs b/src/test/compile-fail/slice-1.rs
deleted file mode 100644 (file)
index 3b992e3..0000000
+++ /dev/null
@@ -1,20 +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.
-
-// Test slicing &expr[] is deprecated and gives a helpful error message.
-
-struct Foo;
-
-fn main() {
-    let x = Foo;
-    &x[];
-    //~^ WARN obsolete syntax
-    //~| ERROR cannot index
-}
diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs
new file mode 100644 (file)
index 0000000..96ae201
--- /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 `T:'a` is contravariant in T.
+
+#![feature(rustc_attrs)]
+
+#[rustc_variance]
+trait Foo: 'static { //~ ERROR types=[[];[-];[]]
+}
+
+#[rustc_variance]
+trait Bar<T> { //~ ERROR types=[[+];[-];[]]
+    fn do_it(&self)
+        where T: 'static;
+}
+
+fn main() { }
diff --git a/src/test/parse-fail/issue-23620-invalid-escapes.rs b/src/test/parse-fail/issue-23620-invalid-escapes.rs
new file mode 100644 (file)
index 0000000..7930ea7
--- /dev/null
@@ -0,0 +1,45 @@
+// 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.
+
+fn main() {
+    let _ = b"\u{a66e}";
+    //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string
+
+    let _ = b'\u{a66e}';
+    //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string
+
+    let _ = b'\u';
+    //~^ ERROR unknown byte escape: u
+
+    let _ = b'\x5';
+    //~^ ERROR numeric character escape is too short
+
+    let _ = b'\xxy';
+    //~^ ERROR illegal character in numeric character escape: x
+    //~^^ ERROR illegal character in numeric character escape: y
+
+    let _ = '\x5';
+    //~^ ERROR numeric character escape is too short
+
+    let _ = '\xxy';
+    //~^ ERROR illegal character in numeric character escape: x
+    //~^^ ERROR illegal character in numeric character escape: y
+
+    let _ = b"\u{a4a4} \xf \u";
+    //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string
+    //~^^ ERROR illegal character in numeric character escape:
+    //~^^^ ERROR unknown byte escape: u
+
+    let _ = "\u{ffffff} \xf \u";
+    //~^ ERROR illegal unicode character escape
+    //~^^ ERROR illegal character in numeric character escape:
+    //~^^^ ERROR form of character escape may only be used with characters in the range [\x00-\x7f]
+    //~^^^^ ERROR unknown character escape: u
+}
index ffc2b11e0c13caba1ff7f9e639349528f706ff23..96b86f1f5635f96cc2243076085258cf455ffea3 100644 (file)
@@ -9,5 +9,8 @@
 // except according to those terms.
 
 pub fn main() {
-    let s = "\u{lol}"; //~ ERROR illegal character in unicode escape
+    let s = "\u{lol}";
+     //~^ ERROR illegal character in unicode escape: l
+     //~^^ ERROR illegal character in unicode escape: o
+     //~^^^ ERROR illegal character in unicode escape: l
 }
diff --git a/src/test/run-pass/box-of-array-of-drop-1.rs b/src/test/run-pass/box-of-array-of-drop-1.rs
new file mode 100644 (file)
index 0000000..a93a488
--- /dev/null
@@ -0,0 +1,52 @@
+// 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 we cleanup a fixed size Box<[D; k]> properly when D has a
+// destructor.
+
+use std::thread;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+
+static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+
+struct D(u8);
+
+impl Drop for D {
+    fn drop(&mut self) {
+        println!("Dropping {}", self.0);
+        let old = LOG.load(Ordering::SeqCst);
+        LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+    }
+}
+
+fn main() {
+    fn die() -> D { panic!("Oh no"); }
+    let g = thread::spawn(|| {
+        let _b1: Box<[D; 4]> = Box::new([D( 1), D( 2), D( 3), D( 4)]);
+        let _b2: Box<[D; 4]> = Box::new([D( 5), D( 6), D( 7), D( 8)]);
+        let _b3: Box<[D; 4]> = Box::new([D( 9), D(10), die(), D(12)]);
+        let _b4: Box<[D; 4]> = Box::new([D(13), D(14), D(15), D(16)]);
+    });
+    assert!(g.join().is_err());
+
+    // When the panic occurs, we will be in the midst of constructing
+    // the input to `_b3`.  Therefore, we drop the elements of the
+    // partially filled array first, before we get around to dropping
+    // the elements of `_b1` and _b2`.
+
+    // Issue 23222: The order in which the elements actually get
+    // dropped is a little funky. See similar notes in nested-vec-3;
+    // in essence, I would not be surprised if we change the ordering
+    // given in `expect` in the future.
+
+    let expect = 0x__A_9__5_6_7_8__1_2_3_4;
+    let actual = LOG.load(Ordering::SeqCst);
+    assert!(actual == expect, "expect: 0x{:x} actual: 0x{:x}", expect, actual);
+}
diff --git a/src/test/run-pass/box-of-array-of-drop-2.rs b/src/test/run-pass/box-of-array-of-drop-2.rs
new file mode 100644 (file)
index 0000000..7155713
--- /dev/null
@@ -0,0 +1,52 @@
+// 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 we cleanup dynamic sized Box<[D]> properly when D has a
+// destructor.
+
+use std::thread;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+
+static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+
+struct D(u8);
+
+impl Drop for D {
+    fn drop(&mut self) {
+        println!("Dropping {}", self.0);
+        let old = LOG.load(Ordering::SeqCst);
+        LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+    }
+}
+
+fn main() {
+    fn die() -> D { panic!("Oh no"); }
+    let g = thread::spawn(|| {
+        let _b1: Box<[D; 4]> = Box::new([D( 1), D( 2), D( 3), D( 4)]);
+        let _b2: Box<[D; 4]> = Box::new([D( 5), D( 6), D( 7), D( 8)]);
+        let _b3: Box<[D; 4]> = Box::new([D( 9), D(10), die(), D(12)]);
+        let _b4: Box<[D; 4]> = Box::new([D(13), D(14), D(15), D(16)]);
+    });
+    assert!(g.join().is_err());
+
+    // When the panic occurs, we will be in the midst of constructing
+    // the input to `_b3`.  Therefore, we drop the elements of the
+    // partially filled array first, before we get around to dropping
+    // the elements of `_b1` and _b2`.
+
+    // Issue 23222: The order in which the elements actually get
+    // dropped is a little funky. See similar notes in nested-vec-3;
+    // in essence, I would not be surprised if we change the ordering
+    // given in `expect` in the future.
+
+    let expect = 0x__A_9__5_6_7_8__1_2_3_4;
+    let actual = LOG.load(Ordering::SeqCst);
+    assert!(actual == expect, "expect: 0x{:x} actual: 0x{:x}", expect, actual);
+}
diff --git a/src/test/run-pass/drop-flag-sanity-check.rs b/src/test/run-pass/drop-flag-sanity-check.rs
new file mode 100644 (file)
index 0000000..02f6cc7
--- /dev/null
@@ -0,0 +1,69 @@
+// 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: -Z force-dropflag-checks=on
+
+// Quick-and-dirty test to ensure -Z force-dropflag-checks=on works as
+// expected. Note that the inlined drop-flag is slated for removal
+// (RFC 320); when that happens, the -Z flag and this test should
+// simply be removed.
+//
+// See also drop-flag-skip-sanity-check.rs.
+
+#![feature(old_io)]
+
+use std::env;
+use std::old_io::process::{Command, ExitSignal, ExitStatus};
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() > 1 && args[1] == "test" {
+        return test();
+    }
+
+    let mut p = Command::new(&args[0]).arg("test").spawn().unwrap();
+    // The invocation should fail due to the drop-flag sanity check.
+    assert!(!p.wait().unwrap().success());
+}
+
+#[derive(Debug)]
+struct Corrupted {
+    x: u8
+}
+
+impl Drop for Corrupted {
+    fn drop(&mut self) { println!("dropping"); }
+}
+
+fn test() {
+    {
+        let mut c1 = Corrupted { x: 1 };
+        let mut c2 = Corrupted { x: 2 };
+        unsafe {
+            let p1 = &mut c1 as *mut Corrupted as *mut u8;
+            let p2 = &mut c2 as *mut Corrupted as *mut u8;
+            for i in 0..std::mem::size_of::<Corrupted>() {
+                // corrupt everything, *including the drop flag.
+                //
+                // (We corrupt via two different means to safeguard
+                // against the hypothetical assignment of the
+                // dtor_needed/dtor_done values to v and v+k.  that
+                // happen to match with one of the corruption values
+                // below.)
+                *p1.offset(i as isize) += 2;
+                *p2.offset(i as isize) += 3;
+            }
+        }
+        // Here, at the end of the scope of `c1` and `c2`, the
+        // drop-glue should detect the corruption of (at least one of)
+        // the drop-flags.
+    }
+    println!("We should never get here.");
+}
diff --git a/src/test/run-pass/drop-flag-skip-sanity-check.rs b/src/test/run-pass/drop-flag-skip-sanity-check.rs
new file mode 100644 (file)
index 0000000..7066b40
--- /dev/null
@@ -0,0 +1,69 @@
+// 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: -Z force-dropflag-checks=off
+
+// Quick-and-dirty test to ensure -Z force-dropflag-checks=off works as
+// expected. Note that the inlined drop-flag is slated for removal
+// (RFC 320); when that happens, the -Z flag and this test should
+// simply be removed.
+//
+// See also drop-flag-sanity-check.rs.
+
+#![feature(old_io)]
+
+use std::env;
+use std::old_io::process::{Command, ExitSignal, ExitStatus};
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    if args.len() > 1 && args[1] == "test" {
+        return test();
+    }
+
+    let mut p = Command::new(&args[0]).arg("test").spawn().unwrap();
+    // Invocatinn should succeed as drop-flag sanity check is skipped.
+    assert!(p.wait().unwrap().success());
+}
+
+#[derive(Debug)]
+struct Corrupted {
+    x: u8
+}
+
+impl Drop for Corrupted {
+    fn drop(&mut self) { println!("dropping"); }
+}
+
+fn test() {
+    {
+        let mut c1 = Corrupted { x: 1 };
+        let mut c2 = Corrupted { x: 2 };
+        unsafe {
+            let p1 = &mut c1 as *mut Corrupted as *mut u8;
+            let p2 = &mut c2 as *mut Corrupted as *mut u8;
+            for i in 0..std::mem::size_of::<Corrupted>() {
+                // corrupt everything, *including the drop flag.
+                //
+                // (We corrupt via two different means to safeguard
+                // against the hypothetical assignment of the
+                // dtor_needed/dtor_done values to v and v+k.  that
+                // happen to match with one of the corruption values
+                // below.)
+                *p1.offset(i as isize) += 2;
+                *p2.offset(i as isize) += 3;
+            }
+        }
+        // Here, at the end of the scope of `c1` and `c2`, the
+        // drop-glue should detect the corruption of (at least one of)
+        // the drop-flags.
+    }
+    println!("We should never get here.");
+}
index 89aea93e7b35a5a3f535b2a53ea13c590ebe9402..c0585afc22ff8c32a72c176e1b854a92be6c71e3 100644 (file)
 #![allow(unknown_features)]
 #![feature(box_syntax)]
 #![feature(intrinsics)]
+// needed to check for drop fill word.
+#![feature(filling_drop)]
 
-use std::mem::transmute;
+use std::mem::{self, transmute};
 
 mod rusti {
     extern "rust-intrinsic" {
@@ -30,6 +32,7 @@ pub fn main() {
         let mut z: *const uint = transmute(&x);
         rusti::move_val_init(&mut y, x);
         assert_eq!(*y, 1);
-        assert_eq!(*z, 0); // `x` is nulled out, not directly visible
+        // `x` is nulled out, not directly visible
+        assert_eq!(*z, mem::POST_DROP_USIZE);
     }
 }
index 0e194860251a8067900e846b664bf44ba1e62914..ee348d9cb0ccfe7ebb6aa8534e6fee9960fb7abc 100644 (file)
@@ -28,7 +28,7 @@ fn main() {
         // checking that it ends_with the executable name. This
         // is needed because of Windows, which has a different behavior.
         // See #15149 for more info.
-        return assert!(args[0].ends_with(&format!("mytest{}", env::consts::EXE_SUFFIX)[]));
+        return assert!(args[0].ends_with(&format!("mytest{}", env::consts::EXE_SUFFIX)));
     }
 
     test();
diff --git a/src/test/run-pass/nested-vec-1.rs b/src/test/run-pass/nested-vec-1.rs
new file mode 100644 (file)
index 0000000..2b92ed3
--- /dev/null
@@ -0,0 +1,16 @@
+// 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 using the `vec!` macro nested within itself works
+
+fn main() {
+    let nested = vec![vec![1u32, 2u32, 3u32]];
+    assert_eq!(nested[0][1], 2);
+}
diff --git a/src/test/run-pass/nested-vec-2.rs b/src/test/run-pass/nested-vec-2.rs
new file mode 100644 (file)
index 0000000..669f9e4
--- /dev/null
@@ -0,0 +1,23 @@
+// 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 using the `vec!` macro nested within itself works
+// when the contents implement Drop
+
+struct D(u32);
+
+impl Drop for D {
+    fn drop(&mut self) { println!("Dropping {}", self.0); }
+}
+
+fn main() {
+    let nested = vec![vec![D(1u32), D(2u32), D(3u32)]];
+    assert_eq!(nested[0][1].0, 2);
+}
diff --git a/src/test/run-pass/nested-vec-3.rs b/src/test/run-pass/nested-vec-3.rs
new file mode 100644 (file)
index 0000000..60cf795
--- /dev/null
@@ -0,0 +1,60 @@
+// 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 using the `vec!` macro nested within itself works when
+// the contents implement Drop and we hit a panic in the middle of
+// construction.
+
+
+use std::thread;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+
+static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+
+struct D(u8);
+
+impl Drop for D {
+    fn drop(&mut self) {
+        println!("Dropping {}", self.0);
+        let old = LOG.load(Ordering::SeqCst);
+        LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+    }
+}
+
+fn main() {
+    fn die() -> D { panic!("Oh no"); }
+    let g = thread::spawn(|| {
+        let _nested = vec![vec![D( 1), D( 2), D( 3), D( 4)],
+                           vec![D( 5), D( 6), D( 7), D( 8)],
+                           vec![D( 9), D(10), die(), D(12)],
+                           vec![D(13), D(14), D(15), D(16)]];
+    });
+    assert!(g.join().is_err());
+
+    // When the panic occurs, we will be in the midst of constructing the
+    // second inner vector.  Therefore, we drop the elements of the
+    // partially filled vector first, before we get around to dropping
+    // the elements of the filled vector.
+
+    // Issue 23222: The order in which the elements actually get
+    // dropped is a little funky: as noted above, we'll drop the 9+10
+    // first, but due to #23222, they get dropped in reverse
+    // order. Likewise, again due to #23222, we will drop the second
+    // filled vec before the first filled vec.
+    //
+    // If Issue 23222 is "fixed", then presumably the corrected
+    // expected order of events will be 0x__9_A__1_2_3_4__5_6_7_8;
+    // that is, we would still drop 9+10 first, since they belong to
+    // the more deeply nested expression when the panic occurs.
+
+    let expect = 0x__A_9__5_6_7_8__1_2_3_4;
+    let actual = LOG.load(Ordering::SeqCst);
+    assert!(actual == expect, "expect: 0x{:x} actual: 0x{:x}", expect, actual);
+}
index baf8c6e4c97913e459911e0940be8e47220833d3..f4e056b3f21b1d68f9c15faa04ee73f07756541e 100644 (file)
@@ -30,7 +30,7 @@ fn wrap(self: Box<int>) -> Box<Any+'static> {
     }
 }
 
-fn is<T:'static>(x: &Any) -> bool {
+fn is<T:Any>(x: &Any) -> bool {
     x.is::<T>()
 }
 
index 4f8ba7f655ee6d48d6f8405db6d17163a0bc2506..efddf0455cd5fbe472bb57e6158e1dff84739a08 100644 (file)
@@ -8,23 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(std_misc)]
+use std::thread;
 
-use std::thread::Thread;
-
-fn x(s: String, n: int) {
+fn x(s: String, n: isize) {
     println!("{}", s);
     println!("{}", n);
 }
 
 pub fn main() {
-    let _t = Thread::spawn(|| x("hello from first spawned fn".to_string(), 65) );
-    let _t = Thread::spawn(|| x("hello from second spawned fn".to_string(), 66) );
-    let _t = Thread::spawn(|| x("hello from third spawned fn".to_string(), 67) );
-    let mut i: int = 30;
+    let _t = thread::scoped(|| x("hello from first spawned fn".to_string(), 65) );
+    let _t = thread::scoped(|| x("hello from second spawned fn".to_string(), 66) );
+    let _t = thread::scoped(|| x("hello from third spawned fn".to_string(), 67) );
+    let mut i = 30;
     while i > 0 {
         i = i - 1;
         println!("parent sleeping");
-        Thread::yield_now();
+        thread::yield_now();
     }
 }
index 5670c45b68ad00a2865149ed54f42cef3c20fd98..a40989d4e37fedc31a939414c17cec2b1816d1cc 100644 (file)
@@ -15,7 +15,7 @@
 
 #![feature(unboxed_closures, core)]
 
-use std::any::TypeId;
+use std::any::{Any, TypeId};
 
 fn main() {
     // Bare fns
@@ -63,7 +63,7 @@ fn main() {
         assert!(a != b);
     }
 
-    fn id<T:'static>(_: T) -> TypeId {
+    fn id<T:Any>(_: T) -> TypeId {
         TypeId::of::<T>()
     }
 }