/// 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 {
<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.
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.
* [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)
within Rust's macro system.
```rust
-#![feature(trace_macros)]
-
macro_rules! bct {
// cmd 0: d ... => ...
(0, $($ps:tt),* ; $_d:tt)
( $($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
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.
% 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.
[arity]: ./glossary.html#arity
[match]: ./match.html
-[game]: ./guessing-game.html#comparing-guesses
[generics]: ./generics.html
/// # }
/// ```
///
-/// ```should_fail
+/// ```should_panic
/// # #[macro_use] extern crate foo;
/// # fn main() {
/// panic_unless!(true == false, “I’m broken.”);
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
--- /dev/null
+% 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.
+
--- /dev/null
+% 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.
+
--- /dev/null
+% 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.
--- /dev/null
+% 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.
+
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);
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
--- /dev/null
+% 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.
+
% 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
fn main() {
let x = Box::new(5);
- println!("{}", add(&x, &x));
- println!("{}", add(&x, &x));
+ println!("{}", add(&*x, &*x));
+ println!("{}", add(&*x, &*x));
}
```
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");
--- /dev/null
+% 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.
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.
//!
//! Sharing some immutable data between tasks:
//!
-//! ```
+//! ```no_run
//! use std::sync::Arc;
//! use std::thread;
//!
//!
//! Sharing mutable data safely between tasks with a `Mutex`:
//!
-//! ```
+//! ```no_run
//! use std::sync::{Arc, Mutex};
//! use std::thread;
//!
/// 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;
// 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
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
/// 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
#[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)
}
}
#![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))]
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;
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
/// 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
///
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.
}
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> {
/// ```
/// # #![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);
#[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;
#![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)]
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)
}
}
}
- /// 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
#[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
}
}
#[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")]
}
}
+#[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
}
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);
#[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
/// *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> {
/// ```
/// # #![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);
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 {
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> {
//! }
//!
//! // 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
//! }
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>() }
}
/// 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>();
/// `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
/// `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
/// 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)
}
}
/// 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>() },
}
use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use convert::{AsRef, AsMut};
use fmt;
use hash::{Hash, self};
use iter::IntoIterator;
}
}
+ #[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] {
}
}
+// 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 {
}
}
+// 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 {
/// 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.
#![feature(rustc_attrs)]
#![feature(optin_builtin_traits)]
#![feature(concat_idents)]
+#![feature(reflect)]
#[macro_use]
mod macros;
#[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 .. { }
+
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
#[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
/// 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`
/// ```
/// assert_eq!(x.unwrap(), "air");
/// ```
///
- /// ```{.should_fail}
+ /// ```{.should_panic}
/// let x: Option<&str> = None;
/// assert_eq!(x.unwrap(), "air"); // fails
/// ```
/// 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),
/// 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),
/// 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() } }
}
}
}
-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())
}
}
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.
///
//! 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)]
/// assert_eq!(x.unwrap(), 2);
/// ```
///
- /// ```{.should_fail}
+ /// ```{.should_panic}
/// let x: Result<u32, &str> = Err("emergency failure");
/// x.unwrap(); // panics with `emergency failure`
/// ```
///
/// # Examples
///
- /// ```{.should_fail}
+ /// ```{.should_panic}
/// let x: Result<u32, &str> = Ok(2);
/// x.unwrap_err(); // panics with `2`
/// ```
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>;
}
#[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)]
/// 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.
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);
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() {
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
});
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)
}
}
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;
// 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;
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);
}
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;
}
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())
}
}
}
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()
}
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.
}
enum BuiltinBoundConditions<'tcx> {
- If(Vec<Ty<'tcx>>),
+ If(ty::Binder<Vec<Ty<'tcx>>>),
ParameterBuiltin,
AmbiguousBuiltin
}
// 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; }
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(_)) => {
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");
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);
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
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
// 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();
}
///////////////////////////////////////////////////////////////////////////
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()");
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()");
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.
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())
}
}
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()");
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),
ty::BoundSized => {
if len.is_some() {
- Ok(If(Vec::new()))
+ ok_if(Vec::new())
} else {
Err(Unimplemented)
}
}
// (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
// 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)
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(_)) => {
}
};
+ 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>>
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!(),
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)
}
};
- 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(),
}
}
}
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))
}
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) {
/// 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!(
}
}
+ 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 {
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)
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(),
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);
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"),
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
///////////////////////////////////////////////////////////////////////////
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
}
}
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)]
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())
}
}
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)
}
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>)
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,
}
}
+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)) ||
//! #![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;
use getopts;
use std::collections::HashMap;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::env;
use std::fmt;
use std::path::PathBuf;
"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 {
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),
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");
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(std_misc)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
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 `{}`",
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
}
/// 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
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);
}).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);
// 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) {
// (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 {
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();
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)))
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]));
}
}
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() }
-> 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| {
}
}
-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);
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);
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};
Sha256::new(),
link_meta.clone(),
reachable,
- check_overflow);
+ check_overflow,
+ check_dropflag);
{
let ccx = shared_ccx.get_ccx(0);
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
}
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>>,
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")
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()),
};
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> {
-> 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
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;
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>,
-> 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);
} 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)
})
&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)
}
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;
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,
"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)),
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 => {
}
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);
}
&*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);
}
}
});
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);
}
}
#[derive(Eq, PartialEq, Clone, Debug)]
struct LangString {
- should_fail: bool,
+ should_panic: bool,
no_run: bool,
ignore: bool,
rust: bool,
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`
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; },
#[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,
})
}
- // 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);
}
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(),
};
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(),
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 {
}
};
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)
}
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};
/// 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> {
#[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;
}
//! 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;
}
#[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()
}
}
}
#[test]
- #[should_fail]
+ #[should_panic]
fn dont_panic_in_drop_on_panicked_flush() {
struct FailFlushWriter;
///
/// 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 }
}
/// 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>>;
//! 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)]
///
/// # Examples
///
-/// ```should_fail
+/// ```should_panic
/// # #![allow(unreachable_code)]
/// panic!();
/// panic!("this is a terrible mistake!");
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 {
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)
+}
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
pos: usize,
}
-enum IpAddr {
- V4(Ipv4Addr),
- V6(Ipv6Addr),
-}
-
impl<'a> Parser<'a> {
fn new(s: &'a str) -> Parser<'a> {
Parser {
}
}
+#[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;
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]
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[..]);
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]
///
/// # Examples
///
- /// ```rust,should_fail
+ /// ```rust,should_panic
/// # #![feature(old_io, old_path)]
/// use std::old_io::*;
/// use std::old_path::Path;
///
/// # Examples
///
-/// ```should_fail
+/// ```should_panic
/// # #![feature(old_io)]
/// use std::old_io::*;
///
}
#[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 }
}
}
}
}
-#[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 {
///
/// # Examples
///
-/// ```should_fail
+/// ```should_panic
/// # #![feature(process)]
///
/// use std::process::Command;
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};
}
}
+////////////////////////////////////////////////////////////////////////////////
+// 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
////////////////////////////////////////////////////////////////////////////////
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) }
}
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()) }
}
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
}
#[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!());
}
/// 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
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
}
}
+ 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 }
}
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> }
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 }
("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),
("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),
("no_mangle", Normal),
("no_link", Normal),
("derive", Normal),
- ("should_fail", Normal),
("should_panic", Normal),
("ignore", Normal),
("no_implicit_prelude", Normal),
// 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),
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
#![feature(quote, unsafe_destructor)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(std_misc)]
#![feature(unicode)]
#![feature(path_ext)]
#![feature(str_char)]
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;
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');
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();
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");
'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();
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 {
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
}
"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);
}
#[derive(Copy, PartialEq, Eq, Hash)]
pub enum ObsoleteSyntax {
ClosureKind,
- EmptyIndex,
ExternCrateString,
}
"rely on inference instead",
true,
),
- ObsoleteSyntax::EmptyIndex => (
- "[]",
- "write `[..]` instead",
- false, // warning for now
- ),
ObsoleteSyntax::ExternCrateString => (
"\"crate-name\"",
"use an identifier not in quotes instead",
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,
// 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
}
/// ```
/// 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;
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,
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,
// 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,
"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)
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))
}
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,
// 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)
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();
// 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))
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>;`
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 {
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);
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);
$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))
}
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(¶ms.where_clause));
try!(word(&mut self.s, ";"));
try!(self.end()); // end the outer ibox
}
}
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());
}
}
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 {
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)
}
));
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());
}
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,
}
}
- 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(","));
}
{
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
}
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);
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")))
#![feature(core)]
-use std::any::TypeId;
+use std::any::{Any, TypeId};
pub struct A;
pub struct B(Option<A>);
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>() }
#![feature(core)]
-use std::any::TypeId;
+use std::any::{Any, TypeId};
pub struct A;
pub struct B(Option<A>);
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>() }
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);
}
+++ /dev/null
-// 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() {}
// 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() {
// 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() {
// 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() {
+++ /dev/null
-// 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() {}
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+}
+++ /dev/null
-// 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
-}
--- /dev/null
+// 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() { }
--- /dev/null
+// 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
+}
// 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
}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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.");
+}
--- /dev/null
+// 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.");
+}
#![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" {
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);
}
}
// 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();
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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);
+}
}
}
-fn is<T:'static>(x: &Any) -> bool {
+fn is<T:Any>(x: &Any) -> bool {
x.is::<T>()
}
// 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();
}
}
#![feature(unboxed_closures, core)]
-use std::any::TypeId;
+use std::any::{Any, TypeId};
fn main() {
// Bare fns
assert!(a != b);
}
- fn id<T:'static>(_: T) -> TypeId {
+ fn id<T:Any>(_: T) -> TypeId {
TypeId::of::<T>()
}
}