Auto merge of #22724 - Manishearth:rollup, r=alexcrichton
Seems to pass `check-stage1`, but I had to tweak some things so it's going through the test gauntlet again.
This commit is contained in:
commit
91a5a1ab4a
81 changed files with 1378 additions and 855 deletions
75
README.md
75
README.md
|
@ -15,28 +15,34 @@ Read ["Installing Rust"] from [The Book].
|
|||
## Building from Source
|
||||
|
||||
1. Make sure you have installed the dependencies:
|
||||
* `g++` 4.7 or `clang++` 3.x
|
||||
* `python` 2.6 or later (but not 3.x)
|
||||
* GNU `make` 3.81 or later
|
||||
* `curl`
|
||||
* `git`
|
||||
|
||||
* `g++` 4.7 or `clang++` 3.x
|
||||
* `python` 2.6 or later (but not 3.x)
|
||||
* GNU `make` 3.81 or later
|
||||
* `curl`
|
||||
* `git`
|
||||
|
||||
2. Clone the [source] with `git`:
|
||||
|
||||
$ git clone https://github.com/rust-lang/rust.git
|
||||
$ cd rust
|
||||
```sh
|
||||
$ git clone https://github.com/rust-lang/rust.git
|
||||
$ cd rust
|
||||
```
|
||||
|
||||
[source]: https://github.com/rust-lang/rust
|
||||
|
||||
3. Build and install:
|
||||
|
||||
$ ./configure
|
||||
$ make && make install
|
||||
```sh
|
||||
$ ./configure
|
||||
$ make && make install
|
||||
```
|
||||
|
||||
> ***Note:*** You may need to use `sudo make install` if you do not normally have
|
||||
> permission to modify the destination directory. The install locations can
|
||||
> be adjusted by passing a `--prefix` argument to `configure`. Various other
|
||||
> options are also supported, pass `--help` for more information on them.
|
||||
> ***Note:*** You may need to use `sudo make install` if you do not
|
||||
> normally have permission to modify the destination directory. The
|
||||
> install locations can be adjusted by passing a `--prefix` argument
|
||||
> to `configure`. Various other options are also supported – pass
|
||||
> `--help` for more information on them.
|
||||
|
||||
When complete, `make install` will place several programs into
|
||||
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||
|
@ -47,27 +53,30 @@ Read ["Installing Rust"] from [The Book].
|
|||
|
||||
### Building on Windows
|
||||
|
||||
To easily build on windows we can use [MSYS2](http://msys2.github.io/):
|
||||
[MSYS2](http://msys2.github.io/) can be used to easily build Rust on Windows:
|
||||
|
||||
1. Grab the latest MSYS2 installer and go through the installer.
|
||||
2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other
|
||||
tools we need.
|
||||
|
||||
```bash
|
||||
# choose one based on platform
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ pacman -S mingw-w64-x86_64-toolchain
|
||||
2. From the MSYS2 terminal, install the `mingw64` toolchain and other required
|
||||
tools.
|
||||
|
||||
$ pacman -S base-devel
|
||||
```
|
||||
```sh
|
||||
# Choose one based on platform:
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ pacman -S mingw-w64-x86_64-toolchain
|
||||
|
||||
$ pacman -S base-devel
|
||||
```
|
||||
|
||||
3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat`
|
||||
from where you installed MSYS2 (i.e. `C:\msys`). Which one you
|
||||
choose depends on if you want 32 or 64 bit Rust.
|
||||
4. From there just navigate to where you have Rust's source code, configure and build it:
|
||||
3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed
|
||||
MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust.
|
||||
|
||||
$ ./configure
|
||||
$ make && make install
|
||||
4. Navigate to Rust's source code, configure and build it:
|
||||
|
||||
```sh
|
||||
$ ./configure
|
||||
$ make && make install
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
|
@ -92,15 +101,15 @@ There is more advice about hacking on Rust in [CONTRIBUTING.md].
|
|||
|
||||
[CONTRIBUTING.md]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md
|
||||
|
||||
## Getting help
|
||||
## Getting Help
|
||||
|
||||
The Rust community congregates in a few places:
|
||||
|
||||
* [StackOverflow] - Direct questions about using the language here.
|
||||
* [users.rust-lang.org] - General discussion, broader questions.
|
||||
* [Stack Overflow] - Direct questions about using the language.
|
||||
* [users.rust-lang.org] - General discussion and broader questions.
|
||||
* [/r/rust] - News and general discussion.
|
||||
|
||||
[StackOverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
[/r/rust]: http://reddit.com/r/rust
|
||||
[users.rust-lang.org]: http://users.rust-lang.org/
|
||||
|
||||
|
@ -111,7 +120,7 @@ To contribute to Rust, please see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|||
Rust has an [IRC] culture and most real-time collaboration happens in a
|
||||
variety of channels on Mozilla's IRC network, irc.mozilla.org. The
|
||||
most popular channel is [#rust], a venue for general discussion about
|
||||
Rust, and a good place to ask for help,
|
||||
Rust, and a good place to ask for help.
|
||||
|
||||
[IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat
|
||||
[#rust]: irc://irc.mozilla.org/rust
|
||||
|
|
|
@ -268,7 +268,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
|
|||
logfile: config.logfile.clone(),
|
||||
run_tests: true,
|
||||
run_benchmarks: true,
|
||||
nocapture: false,
|
||||
nocapture: env::var("RUST_TEST_NOCAPTURE").is_ok(),
|
||||
color: test::AutoColor,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::env;
|
||||
|
||||
use common::Config;
|
||||
use common;
|
||||
use util;
|
||||
|
@ -125,6 +127,16 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
|||
true
|
||||
});
|
||||
|
||||
for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_TASKS"] {
|
||||
match env::var(key) {
|
||||
Ok(val) =>
|
||||
if exec_env.iter().find(|&&(ref x, _)| *x == key.to_string()).is_none() {
|
||||
exec_env.push((key.to_string(), val))
|
||||
},
|
||||
Err(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
TestProps {
|
||||
error_patterns: error_patterns,
|
||||
compile_flags: compile_flags,
|
||||
|
|
|
@ -89,7 +89,7 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
|
|||
let proc_res = compile_test(config, props, testfile);
|
||||
|
||||
if proc_res.status.success() {
|
||||
fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[],
|
||||
fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..],
|
||||
&proc_res);
|
||||
}
|
||||
|
||||
|
@ -398,7 +398,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
|||
for line in breakpoint_lines.iter() {
|
||||
script_str.push_str(&format!("break {:?}:{}\n",
|
||||
testfile.filename_display(),
|
||||
*line)[]);
|
||||
*line)[..]);
|
||||
}
|
||||
script_str.push_str(&cmds);
|
||||
script_str.push_str("quit\n");
|
||||
|
@ -553,17 +553,17 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
|||
script_str.push_str("set print pretty off\n");
|
||||
|
||||
// Add the pretty printer directory to GDB's source-file search path
|
||||
script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)[]);
|
||||
script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)[..]);
|
||||
|
||||
// Load the target executable
|
||||
script_str.push_str(&format!("file {}\n",
|
||||
exe_file.as_str().unwrap().replace("\\", "\\\\"))[]);
|
||||
exe_file.as_str().unwrap().replace("\\", "\\\\"))[..]);
|
||||
|
||||
// Add line breakpoints
|
||||
for line in &breakpoint_lines {
|
||||
script_str.push_str(&format!("break '{}':{}\n",
|
||||
testfile.filename_display(),
|
||||
*line)[]);
|
||||
*line)[..]);
|
||||
}
|
||||
|
||||
script_str.push_str(&cmds);
|
||||
|
@ -689,7 +689,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
|
|||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
script_str.push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[]);
|
||||
script_str.push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[..]);
|
||||
script_str.push_str("type summary add --no-value ");
|
||||
script_str.push_str("--python-function lldb_rust_formatters.print_val ");
|
||||
script_str.push_str("-x \".*\" --category Rust\n");
|
||||
|
|
|
@ -426,39 +426,33 @@ use std::thread::Thread;
|
|||
fn main() {
|
||||
let mut numbers = vec![1, 2, 3];
|
||||
|
||||
for i in 0..3 {
|
||||
Thread::spawn(move || {
|
||||
let guards: Vec<_> = (0..3).map(|i| {
|
||||
Thread::scoped(move || {
|
||||
for j in 0..3 { numbers[j] += 1 }
|
||||
});
|
||||
}
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
It gives us this error:
|
||||
|
||||
```text
|
||||
6:71 error: capture of moved value: `numbers`
|
||||
for j in 0..3 { numbers[j] += 1 }
|
||||
^~~~~~~
|
||||
7:50 note: `numbers` moved into closure environment here
|
||||
spawn(move || {
|
||||
for j in 0..3 { numbers[j] += 1 }
|
||||
});
|
||||
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
|
||||
for j in 0..3 { numbers[j] += 1 }
|
||||
^~~~~~~~~~~~~~~
|
||||
7:29: 9:10 error: cannot move out of captured outer variable in an `FnMut` closure
|
||||
7 Thread::scoped(move || {
|
||||
8 for j in 0..3 { numbers[j] += 1 }
|
||||
9 });
|
||||
```
|
||||
|
||||
It mentions that "numbers moved into closure environment". Because we
|
||||
declared the closure as a moving closure, and it referred to
|
||||
`numbers`, the closure will try to take ownership of the vector. But
|
||||
the closure itself is created in a loop, and hence we will actually
|
||||
create three closures, one for every iteration of the loop. This means
|
||||
that all three of those closures would try to own `numbers`, which is
|
||||
impossible -- `numbers` must have just one owner. Rust detects this
|
||||
and gives us the error: we claim that `numbers` has ownership, but our
|
||||
code tries to make three owners. This may cause a safety problem, so
|
||||
Rust disallows it.
|
||||
It mentions that "captured outer variable in an `FnMut` closure".
|
||||
Because we declared the closure as a moving closure, and it referred
|
||||
to `numbers`, the closure will try to take ownership of the
|
||||
vector. But the closure itself is created in a loop, and hence we will
|
||||
actually create three closures, one for every iteration of the
|
||||
loop. This means that all three of those closures would try to own
|
||||
`numbers`, which is impossible -- `numbers` must have just one
|
||||
owner. Rust detects this and gives us the error: we claim that
|
||||
`numbers` has ownership, but our code tries to make three owners. This
|
||||
may cause a safety problem, so Rust disallows it.
|
||||
|
||||
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
|
||||
*Arc* stands for "atomically reference counted". In other words, an Arc will
|
||||
|
@ -480,14 +474,14 @@ use std::sync::{Arc,Mutex};
|
|||
fn main() {
|
||||
let numbers = Arc::new(Mutex::new(vec![1, 2, 3]));
|
||||
|
||||
for i in 0..3 {
|
||||
let guards: Vec<_> = (0..3).map(|i| {
|
||||
let number = numbers.clone();
|
||||
Thread::spawn(move || {
|
||||
Thread::scoped(move || {
|
||||
let mut array = number.lock().unwrap();
|
||||
array[i] += 1;
|
||||
println!("numbers[{}] is {}", i, array[i]);
|
||||
});
|
||||
}
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -516,8 +510,10 @@ numbers[1] is 3
|
|||
numbers[0] is 2
|
||||
```
|
||||
|
||||
Each time, we get a slightly different output, because each thread works in a
|
||||
different order. You may not get the same output as this sample, even.
|
||||
Each time, we can get a slithtly different output because the threads
|
||||
are not quaranteed to run in any set order. If you get the same order
|
||||
every time it is because each of these threads are very small and
|
||||
complete too fast for their indeterminate behavior to surface.
|
||||
|
||||
The important part here is that the Rust compiler was able to use ownership to
|
||||
give us assurance _at compile time_ that we weren't doing something incorrect
|
||||
|
@ -539,13 +535,13 @@ safety check that makes this an error about moved values:
|
|||
use std::thread::Thread;
|
||||
|
||||
fn main() {
|
||||
let vec = vec![1, 2, 3];
|
||||
|
||||
for i in 0..3 {
|
||||
Thread::spawn(move || {
|
||||
println!("{}", vec[i]);
|
||||
let numbers = vec![1, 2, 3];
|
||||
|
||||
let guards: Vec<_> = (0..3).map(|i| {
|
||||
Thread::scoped(move || {
|
||||
println!("{}", numbers[i]);
|
||||
});
|
||||
}
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -515,6 +515,9 @@ This last example is different because it is not possible to use the suffix
|
|||
syntax with a floating point literal ending in a period. `2.f64` would attempt
|
||||
to call a method named `f64` on `2`.
|
||||
|
||||
The representation semantics of floating-point numbers are described in
|
||||
["Machine Types"](#machine-types).
|
||||
|
||||
#### Boolean literals
|
||||
|
||||
The two values of the boolean type are written `true` and `false`.
|
||||
|
@ -3554,7 +3557,8 @@ Tuple types and values are denoted by listing the types or values of their
|
|||
elements, respectively, in a parenthesized, comma-separated list.
|
||||
|
||||
Because tuple elements don't have a name, they can only be accessed by
|
||||
pattern-matching.
|
||||
pattern-matching or by using `N` directly as a field to access the
|
||||
`N`th element.
|
||||
|
||||
An example of a tuple type and its use:
|
||||
|
||||
|
@ -3563,6 +3567,7 @@ type Pair<'a> = (i32, &'a str);
|
|||
let p: Pair<'static> = (10, "hello");
|
||||
let (a, b) = p;
|
||||
assert!(b != "world");
|
||||
assert!(p.0 == 10);
|
||||
```
|
||||
|
||||
### Array, and Slice types
|
||||
|
|
|
@ -12,7 +12,7 @@ Rust has two distinct terms that relate to the module system: *crate* and
|
|||
*module*. A crate is synonymous with a *library* or *package* in other
|
||||
languages. Hence "Cargo" as the name of Rust's package management tool: you
|
||||
ship your crates to others with Cargo. Crates can produce an executable or a
|
||||
shared library, depending on the project.
|
||||
library, depending on the project.
|
||||
|
||||
Each crate has an implicit *root module* that contains the code for that crate.
|
||||
You can then define a tree of sub-modules under that root module. Modules allow
|
||||
|
|
|
@ -57,14 +57,13 @@ for i in 0..nums.len() {
|
|||
}
|
||||
```
|
||||
|
||||
This is strictly worse than using an actual iterator. The `.iter()` method on
|
||||
vectors returns an iterator which iterates through a reference to each element
|
||||
of the vector in turn. So write this:
|
||||
This is strictly worse than using an actual iterator. You can iterate over vectors
|
||||
directly, so write this:
|
||||
|
||||
```rust
|
||||
let nums = vec![1, 2, 3];
|
||||
|
||||
for num in nums.iter() {
|
||||
for num in &nums {
|
||||
println!("{}", num);
|
||||
}
|
||||
```
|
||||
|
@ -86,16 +85,17 @@ see it. This code works fine too:
|
|||
```rust
|
||||
let nums = vec![1, 2, 3];
|
||||
|
||||
for num in nums.iter() {
|
||||
for num in &nums {
|
||||
println!("{}", *num);
|
||||
}
|
||||
```
|
||||
|
||||
Now we're explicitly dereferencing `num`. Why does `iter()` give us references?
|
||||
Well, if it gave us the data itself, we would have to be its owner, which would
|
||||
involve making a copy of the data and giving us the copy. With references,
|
||||
we're just borrowing a reference to the data, and so it's just passing
|
||||
a reference, without needing to do the copy.
|
||||
Now we're explicitly dereferencing `num`. Why does `&nums` give us
|
||||
references? Firstly, because we explicitly asked it to with
|
||||
`&`. Secondly, if it gave us the data itself, we would have to be its
|
||||
owner, which would involve making a copy of the data and giving us the
|
||||
copy. With references, we're just borrowing a reference to the data,
|
||||
and so it's just passing a reference, without needing to do the move.
|
||||
|
||||
So, now that we've established that ranges are often not what you want, let's
|
||||
talk about what you do want instead.
|
||||
|
@ -230,9 +230,9 @@ let nums = (1..100).collect::<Vec<i32>>();
|
|||
Now, `collect()` will require that the range gives it some numbers, and so
|
||||
it will do the work of generating the sequence.
|
||||
|
||||
Ranges are one of two basic iterators that you'll see. The other is `iter()`,
|
||||
which you've used before. `iter()` can turn a vector into a simple iterator
|
||||
that gives you each element in turn:
|
||||
Ranges are one of two basic iterators that you'll see. The other is `iter()`.
|
||||
`iter()` can turn a vector into a simple iterator that gives you each element
|
||||
in turn:
|
||||
|
||||
```rust
|
||||
let nums = [1, 2, 3];
|
||||
|
|
|
@ -38,8 +38,9 @@ string literal or a `String`.
|
|||
|
||||
# String
|
||||
|
||||
A `String` is a heap-allocated string. This string is growable, and is also
|
||||
guaranteed to be UTF-8.
|
||||
A `String` is a heap-allocated string. This string is growable, and is
|
||||
also guaranteed to be UTF-8. `String`s are commonly created by
|
||||
converting from a string slice using the `to_string` method.
|
||||
|
||||
```
|
||||
let mut s = "Hello".to_string();
|
||||
|
@ -49,7 +50,7 @@ s.push_str(", world.");
|
|||
println!("{}", s);
|
||||
```
|
||||
|
||||
You can coerce a `String` into a `&str` by dereferencing it:
|
||||
A reference to a `String` will automatically coerce to a string slice:
|
||||
|
||||
```
|
||||
fn takes_slice(slice: &str) {
|
||||
|
@ -58,7 +59,7 @@ fn takes_slice(slice: &str) {
|
|||
|
||||
fn main() {
|
||||
let s = "Hello".to_string();
|
||||
takes_slice(&*s);
|
||||
takes_slice(&s);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -79,10 +79,11 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
This has some upsides: static dispatching of any method calls, allowing for
|
||||
inlining and hence usually higher performance. It also has some downsides:
|
||||
causing code bloat due to many copies of the same function existing in the
|
||||
binary, one for each type.
|
||||
This has a great upside: static dispatch allows function calls to be
|
||||
inlined because the callee is known at compile time, and inlining is
|
||||
the key to good optimization. Static dispatch is fast, but it comes at
|
||||
a tradeoff: 'code bloat', due to many copies of the same function
|
||||
existing in the binary, one for each type.
|
||||
|
||||
Furthermore, compilers aren’t perfect and may “optimize” code to become slower.
|
||||
For example, functions inlined too eagerly will bloat the instruction cache
|
||||
|
|
|
@ -25,8 +25,10 @@ compiled program, and exists for the entire duration it runs. The `string`
|
|||
binding is a reference to this statically allocated string. String slices
|
||||
have a fixed size, and cannot be mutated.
|
||||
|
||||
A `String`, on the other hand, is an in-memory string. This string is
|
||||
growable, and is also guaranteed to be UTF-8.
|
||||
A `String`, on the other hand, is a heap-allocated string. This string
|
||||
is growable, and is also guaranteed to be UTF-8. `String`s are
|
||||
commonly created by converting from a string slice using the
|
||||
`to_string` method.
|
||||
|
||||
```{rust}
|
||||
let mut s = "Hello".to_string(); // mut s: String
|
||||
|
|
|
@ -105,15 +105,16 @@ impl<T : ?Sized> Box<T> {
|
|||
/// After this function call, pointer is owned by resulting box.
|
||||
/// In particular, it means that `Box` destructor calls destructor
|
||||
/// of `T` and releases memory. Since the way `Box` allocates and
|
||||
/// releases memory is unspecified, so the only valid pointer to
|
||||
/// pass to this function is the one taken from another `Box` with
|
||||
/// `box::into_raw` function.
|
||||
/// releases memory is unspecified, the only valid pointer to pass
|
||||
/// to this function is the one taken from another `Box` with
|
||||
/// `boxed::into_raw` function.
|
||||
///
|
||||
/// Function is unsafe, because improper use of this function may
|
||||
/// lead to memory problems like double-free, for example if the
|
||||
/// function is called twice on the same raw pointer.
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "may be renamed or moved out of Box scope")]
|
||||
#[inline]
|
||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||
mem::transmute(raw)
|
||||
}
|
||||
|
@ -141,6 +142,7 @@ impl<T : ?Sized> Box<T> {
|
|||
/// ```
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "may be renamed")]
|
||||
#[inline]
|
||||
pub unsafe fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
|
||||
mem::transmute(b)
|
||||
}
|
||||
|
@ -248,11 +250,12 @@ impl BoxAny for Box<Any> {
|
|||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
let raw = into_raw(self);
|
||||
let to: TraitObject =
|
||||
mem::transmute::<Box<Any>, TraitObject>(self);
|
||||
mem::transmute::<*mut Any, TraitObject>(raw);
|
||||
|
||||
// Extract the data pointer
|
||||
Ok(mem::transmute(to.data))
|
||||
Ok(Box::from_raw(to.data as *mut T))
|
||||
}
|
||||
} else {
|
||||
Err(self)
|
||||
|
|
|
@ -143,7 +143,10 @@
|
|||
//! ```
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
#[cfg(not(test))]
|
||||
use boxed;
|
||||
#[cfg(test)]
|
||||
use std::boxed;
|
||||
use core::cell::Cell;
|
||||
use core::clone::Clone;
|
||||
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||
|
@ -151,7 +154,7 @@ use core::default::Default;
|
|||
use core::fmt;
|
||||
use core::hash::{Hasher, Hash};
|
||||
use core::marker;
|
||||
use core::mem::{transmute, min_align_of, size_of, forget};
|
||||
use core::mem::{min_align_of, size_of, forget};
|
||||
use core::nonzero::NonZero;
|
||||
use core::ops::{Deref, Drop};
|
||||
use core::option::Option;
|
||||
|
@ -201,7 +204,7 @@ impl<T> Rc<T> {
|
|||
// there is an implicit weak pointer owned by all the strong pointers, which
|
||||
// ensures that the weak destructor never frees the allocation while the strong
|
||||
// destructor is running, even if the weak pointer is stored inside the strong one.
|
||||
_ptr: NonZero::new(transmute(box RcBox {
|
||||
_ptr: NonZero::new(boxed::into_raw(box RcBox {
|
||||
value: value,
|
||||
strong: Cell::new(1),
|
||||
weak: Cell::new(1)
|
||||
|
|
|
@ -110,7 +110,7 @@ fn reverse_bits(byte: u8) -> u8 {
|
|||
result
|
||||
}
|
||||
|
||||
// Take two BitV's, and return iterators of their words, where the shorter one
|
||||
// Take two BitVec's, and return iterators of their words, where the shorter one
|
||||
// has been padded with 0's
|
||||
fn match_words <'a,'b>(a: &'a BitVec, b: &'b BitVec) -> (MatchWords<'a>, MatchWords<'b>) {
|
||||
let a_len = a.storage.len();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -388,7 +388,7 @@ impl<T> Vec<T> {
|
|||
pub fn into_boxed_slice(mut self) -> Box<[T]> {
|
||||
self.shrink_to_fit();
|
||||
unsafe {
|
||||
let xs: Box<[T]> = mem::transmute(&mut *self);
|
||||
let xs: Box<[T]> = Box::from_raw(&mut *self);
|
||||
mem::forget(self);
|
||||
xs
|
||||
}
|
||||
|
@ -1493,69 +1493,34 @@ impl<T> Extend<T> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<A, B> PartialEq<Vec<B>> for Vec<A> where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Vec<B>) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &Vec<B>) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
}
|
||||
__impl_slice_eq1! { Vec<A>, Vec<B> }
|
||||
__impl_slice_eq2! { Vec<A>, &'b [B] }
|
||||
__impl_slice_eq2! { Vec<A>, &'b mut [B] }
|
||||
__impl_slice_eq2! { CowVec<'a, A>, &'b [B], Clone }
|
||||
__impl_slice_eq2! { CowVec<'a, A>, &'b mut [B], Clone }
|
||||
__impl_slice_eq2! { CowVec<'a, A>, Vec<B>, Clone }
|
||||
|
||||
macro_rules! impl_eq {
|
||||
($lhs:ty, $rhs:ty) => {
|
||||
impl<'b, A, B> PartialEq<$rhs> for $lhs where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
}
|
||||
|
||||
impl<'b, A, B> PartialEq<$lhs> for $rhs where B: PartialEq<A> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &$lhs) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
}
|
||||
macro_rules! array_impls {
|
||||
($($N: expr)+) => {
|
||||
$(
|
||||
// NOTE: some less important impls are omitted to reduce code bloat
|
||||
__impl_slice_eq2! { Vec<A>, [B; $N] }
|
||||
__impl_slice_eq2! { Vec<A>, &'b [B; $N] }
|
||||
// __impl_slice_eq2! { Vec<A>, &'b mut [B; $N] }
|
||||
// __impl_slice_eq2! { CowVec<'a, A>, [B; $N], Clone }
|
||||
// __impl_slice_eq2! { CowVec<'a, A>, &'b [B; $N], Clone }
|
||||
// __impl_slice_eq2! { CowVec<'a, A>, &'b mut [B; $N], Clone }
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
impl_eq! { Vec<A>, &'b [B] }
|
||||
impl_eq! { Vec<A>, &'b mut [B] }
|
||||
|
||||
impl<'a, A, B> PartialEq<Vec<B>> for Cow<'a, [A]> where A: PartialEq<B> + Clone {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Vec<B>) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &Vec<B>) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
array_impls! {
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
10 11 12 13 14 15 16 17 18 19
|
||||
20 21 22 23 24 25 26 27 28 29
|
||||
30 31 32
|
||||
}
|
||||
|
||||
impl<'a, A, B> PartialEq<Cow<'a, [A]>> for Vec<B> where A: Clone, B: PartialEq<A> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
}
|
||||
|
||||
macro_rules! impl_eq_for_cowvec {
|
||||
($rhs:ty) => {
|
||||
impl<'a, 'b, A, B> PartialEq<$rhs> for Cow<'a, [A]> where A: PartialEq<B> + Clone {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
}
|
||||
|
||||
impl<'a, 'b, A, B> PartialEq<Cow<'a, [A]>> for $rhs where A: Clone, B: PartialEq<A> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_eq_for_cowvec! { &'b [B] }
|
||||
impl_eq_for_cowvec! { &'b mut [B] }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: PartialOrd> PartialOrd for Vec<T> {
|
||||
#[inline]
|
||||
|
@ -2470,7 +2435,7 @@ mod tests {
|
|||
fn test_into_boxed_slice() {
|
||||
let xs = vec![1, 2, 3];
|
||||
let ys = xs.into_boxed_slice();
|
||||
assert_eq!(ys, [1, 2, 3]);
|
||||
assert_eq!(&*ys, [1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -17,13 +17,13 @@ use self::Entry::*;
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use core::cmp::Ordering;
|
||||
use core::cmp::{max, Ordering};
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::iter::{Enumerate, FilterMap, Map, FromIterator, IntoIterator};
|
||||
use core::iter;
|
||||
use core::mem::replace;
|
||||
use core::mem::{replace, swap};
|
||||
use core::ops::{Index, IndexMut};
|
||||
|
||||
use {vec, slice};
|
||||
|
@ -320,6 +320,95 @@ impl<V> VecMap<V> {
|
|||
IntoIter { iter: self.v.into_iter().enumerate().filter_map(filter) }
|
||||
}
|
||||
|
||||
/// Moves all elements from `other` into the map while overwriting existing keys.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
///
|
||||
/// let mut a = VecMap::new();
|
||||
/// a.insert(1, "a");
|
||||
/// a.insert(2, "b");
|
||||
///
|
||||
/// let mut b = VecMap::new();
|
||||
/// b.insert(3, "c");
|
||||
/// b.insert(4, "d");
|
||||
///
|
||||
/// a.append(&mut b);
|
||||
///
|
||||
/// assert_eq!(a.len(), 4);
|
||||
/// assert_eq!(b.len(), 0);
|
||||
/// assert_eq!(a[1], "a");
|
||||
/// assert_eq!(a[2], "b");
|
||||
/// assert_eq!(a[3], "c");
|
||||
/// assert_eq!(a[4], "d");
|
||||
/// ```
|
||||
#[unstable(feature = "collections",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
self.extend(other.drain());
|
||||
}
|
||||
|
||||
/// Splits the collection into two at the given key.
|
||||
///
|
||||
/// Returns a newly allocated `Self`. `self` contains elements `[0, at)`,
|
||||
/// and the returned `Self` contains elements `[at, max_key)`.
|
||||
///
|
||||
/// Note that the capacity of `self` does not change.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
///
|
||||
/// let mut a = VecMap::new();
|
||||
/// a.insert(1, "a");
|
||||
/// a.insert(2, "b");
|
||||
/// a.insert(3, "c");
|
||||
/// a.insert(4, "d");
|
||||
///
|
||||
/// let b = a.split_off(3);
|
||||
///
|
||||
/// assert_eq!(a[1], "a");
|
||||
/// assert_eq!(a[2], "b");
|
||||
///
|
||||
/// assert_eq!(b[3], "c");
|
||||
/// assert_eq!(b[4], "d");
|
||||
/// ```
|
||||
#[unstable(feature = "collections",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn split_off(&mut self, at: usize) -> Self {
|
||||
let mut other = VecMap::new();
|
||||
|
||||
if at == 0 {
|
||||
// Move all elements to other
|
||||
swap(self, &mut other);
|
||||
return other
|
||||
} else if at > self.v.len() {
|
||||
// No elements to copy
|
||||
return other;
|
||||
}
|
||||
|
||||
// Look up the index of the first non-None item
|
||||
let first_index = self.v.iter().position(|el| el.is_some());
|
||||
let start_index = match first_index {
|
||||
Some(index) => max(at, index),
|
||||
None => {
|
||||
// self has no elements
|
||||
return other;
|
||||
}
|
||||
};
|
||||
|
||||
// Fill the new VecMap with `None`s until `start_index`
|
||||
other.v.extend((0..start_index).map(|_| None));
|
||||
|
||||
// Move elements beginning with `start_index` from `self` into `other`
|
||||
other.v.extend(self.v[start_index..].iter_mut().map(|el| el.take()));
|
||||
|
||||
other
|
||||
}
|
||||
|
||||
/// Returns an iterator visiting all key-value pairs in ascending order of
|
||||
/// the keys, emptying (but not consuming) the original `VecMap`.
|
||||
/// The iterator's element type is `(usize, &'r V)`. Keeps the allocated memory for reuse.
|
||||
|
@ -1141,6 +1230,85 @@ mod test_map {
|
|||
assert_eq!(map.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_append() {
|
||||
let mut a = VecMap::new();
|
||||
a.insert(1, "a");
|
||||
a.insert(2, "b");
|
||||
a.insert(3, "c");
|
||||
|
||||
let mut b = VecMap::new();
|
||||
b.insert(3, "d"); // Overwrite element from a
|
||||
b.insert(4, "e");
|
||||
b.insert(5, "f");
|
||||
|
||||
a.append(&mut b);
|
||||
|
||||
assert_eq!(a.len(), 5);
|
||||
assert_eq!(b.len(), 0);
|
||||
// Capacity shouldn't change for possible reuse
|
||||
assert!(b.capacity() >= 4);
|
||||
|
||||
assert_eq!(a[1], "a");
|
||||
assert_eq!(a[2], "b");
|
||||
assert_eq!(a[3], "d");
|
||||
assert_eq!(a[4], "e");
|
||||
assert_eq!(a[5], "f");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_off() {
|
||||
// Split within the key range
|
||||
let mut a = VecMap::new();
|
||||
a.insert(1, "a");
|
||||
a.insert(2, "b");
|
||||
a.insert(3, "c");
|
||||
a.insert(4, "d");
|
||||
|
||||
let b = a.split_off(3);
|
||||
|
||||
assert_eq!(a.len(), 2);
|
||||
assert_eq!(b.len(), 2);
|
||||
|
||||
assert_eq!(a[1], "a");
|
||||
assert_eq!(a[2], "b");
|
||||
|
||||
assert_eq!(b[3], "c");
|
||||
assert_eq!(b[4], "d");
|
||||
|
||||
// Split at 0
|
||||
a.clear();
|
||||
a.insert(1, "a");
|
||||
a.insert(2, "b");
|
||||
a.insert(3, "c");
|
||||
a.insert(4, "d");
|
||||
|
||||
let b = a.split_off(0);
|
||||
|
||||
assert_eq!(a.len(), 0);
|
||||
assert_eq!(b.len(), 4);
|
||||
assert_eq!(b[1], "a");
|
||||
assert_eq!(b[2], "b");
|
||||
assert_eq!(b[3], "c");
|
||||
assert_eq!(b[4], "d");
|
||||
|
||||
// Split behind max_key
|
||||
a.clear();
|
||||
a.insert(1, "a");
|
||||
a.insert(2, "b");
|
||||
a.insert(3, "c");
|
||||
a.insert(4, "d");
|
||||
|
||||
let b = a.split_off(5);
|
||||
|
||||
assert_eq!(a.len(), 4);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert_eq!(a[1], "a");
|
||||
assert_eq!(a[2], "b");
|
||||
assert_eq!(a[3], "c");
|
||||
assert_eq!(a[4], "d");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let mut map = VecMap::new();
|
||||
|
|
|
@ -19,8 +19,7 @@ use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
|
|||
use fmt;
|
||||
use hash::{Hash, self};
|
||||
use iter::IntoIterator;
|
||||
use marker::Copy;
|
||||
use ops::Deref;
|
||||
use marker::{Copy, Sized};
|
||||
use option::Option;
|
||||
use slice::{Iter, IterMut, SliceExt};
|
||||
|
||||
|
@ -69,47 +68,13 @@ macro_rules! array_impls {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A, B> PartialEq<[B; $N]> for [A; $N] where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &[B; $N]) -> bool {
|
||||
&self[..] == &other[..]
|
||||
}
|
||||
#[inline]
|
||||
fn ne(&self, other: &[B; $N]) -> bool {
|
||||
&self[..] != &other[..]
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, A, B, Rhs> PartialEq<Rhs> for [A; $N] where
|
||||
A: PartialEq<B>,
|
||||
Rhs: Deref<Target=[B]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Rhs) -> bool {
|
||||
PartialEq::eq(&self[..], &**other)
|
||||
}
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Rhs) -> bool {
|
||||
PartialEq::ne(&self[..], &**other)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, A, B, Lhs> PartialEq<[B; $N]> for Lhs where
|
||||
A: PartialEq<B>,
|
||||
Lhs: Deref<Target=[A]>
|
||||
{
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &[B; $N]) -> bool {
|
||||
PartialEq::eq(&**self, &other[..])
|
||||
}
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &[B; $N]) -> bool {
|
||||
PartialEq::ne(&**self, &other[..])
|
||||
}
|
||||
}
|
||||
// NOTE: some less important impls are omitted to reduce code bloat
|
||||
__impl_slice_eq1! { [A; $N], [B; $N] }
|
||||
__impl_slice_eq2! { [A; $N], [B] }
|
||||
__impl_slice_eq2! { [A; $N], &'b [B] }
|
||||
__impl_slice_eq2! { [A; $N], &'b mut [B] }
|
||||
// __impl_slice_eq2! { [A; $N], &'b [B; $N] }
|
||||
// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T:Eq> Eq for [T; $N] { }
|
||||
|
|
50
src/libcore/cmp_macros.rs
Normal file
50
src/libcore/cmp_macros.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
// 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.
|
||||
|
||||
// Utility macros for implementing PartialEq on slice-like types
|
||||
|
||||
#![doc(hidden)]
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! __impl_slice_eq1 {
|
||||
($Lhs: ty, $Rhs: ty) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, 'b, A, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
|
||||
#[inline]
|
||||
fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! __impl_slice_eq2 {
|
||||
($Lhs: ty, $Rhs: ty) => {
|
||||
__impl_slice_eq2! { $Lhs, $Rhs, Sized }
|
||||
};
|
||||
($Lhs: ty, $Rhs: ty, $Bound: ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
|
||||
#[inline]
|
||||
fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$Lhs) -> bool { &self[..] == &other[..] }
|
||||
#[inline]
|
||||
fn ne(&self, other: &$Lhs) -> bool { &self[..] != &other[..] }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -72,6 +72,9 @@
|
|||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
#[macro_use]
|
||||
mod cmp_macros;
|
||||
|
||||
#[path = "num/float_macros.rs"]
|
||||
#[macro_use]
|
||||
mod float_macros;
|
||||
|
|
|
@ -167,6 +167,7 @@
|
|||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(int_uint)]
|
||||
|
@ -175,6 +176,7 @@
|
|||
#![feature(std_misc)]
|
||||
#![feature(env)]
|
||||
|
||||
use std::boxed;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::old_io::LineBufferedWriter;
|
||||
|
@ -205,11 +207,11 @@ const DEFAULT_LOG_LEVEL: u32 = 1;
|
|||
/// logging statement should be run.
|
||||
static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL;
|
||||
|
||||
static mut DIRECTIVES: *const Vec<directive::LogDirective> =
|
||||
0 as *const Vec<directive::LogDirective>;
|
||||
static mut DIRECTIVES: *mut Vec<directive::LogDirective> =
|
||||
0 as *mut Vec<directive::LogDirective>;
|
||||
|
||||
/// Optional filter.
|
||||
static mut FILTER: *const String = 0 as *const _;
|
||||
static mut FILTER: *mut String = 0 as *mut _;
|
||||
|
||||
/// Debug log level
|
||||
pub const DEBUG: u32 = 4;
|
||||
|
@ -419,23 +421,23 @@ fn init() {
|
|||
|
||||
assert!(FILTER.is_null());
|
||||
match filter {
|
||||
Some(f) => FILTER = mem::transmute(box f),
|
||||
Some(f) => FILTER = boxed::into_raw(box f),
|
||||
None => {}
|
||||
}
|
||||
|
||||
assert!(DIRECTIVES.is_null());
|
||||
DIRECTIVES = mem::transmute(box directives);
|
||||
DIRECTIVES = boxed::into_raw(box directives);
|
||||
|
||||
// Schedule the cleanup for the globals for when the runtime exits.
|
||||
rt::at_exit(move || {
|
||||
assert!(!DIRECTIVES.is_null());
|
||||
let _directives: Box<Vec<directive::LogDirective>> =
|
||||
mem::transmute(DIRECTIVES);
|
||||
DIRECTIVES = ptr::null();
|
||||
Box::from_raw(DIRECTIVES);
|
||||
DIRECTIVES = ptr::null_mut();
|
||||
|
||||
if !FILTER.is_null() {
|
||||
let _filter: Box<String> = mem::transmute(FILTER);
|
||||
FILTER = 0 as *const _;
|
||||
let _filter: Box<String> = Box::from_raw(FILTER);
|
||||
FILTER = 0 as *mut _;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -81,6 +81,8 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
|
|||
};
|
||||
if s.len() == 0 {
|
||||
err("crate name must not be empty");
|
||||
} else if s.char_at(0) == '-' {
|
||||
err(&format!("crate name cannot start with a hyphen: {}", s));
|
||||
}
|
||||
for c in s.chars() {
|
||||
if c.is_alphanumeric() { continue }
|
||||
|
|
|
@ -861,7 +861,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
|||
encode_attributes(rbml_w, &ast_method.attrs);
|
||||
let scheme = ty::lookup_item_type(ecx.tcx, m.def_id);
|
||||
let any_types = !scheme.generics.types.is_empty();
|
||||
if any_types || is_default_impl || should_inline(&ast_method.attrs) {
|
||||
if any_types || is_default_impl || attr::requests_inline(&ast_method.attrs) {
|
||||
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id),
|
||||
ast_item_opt.unwrap()));
|
||||
}
|
||||
|
@ -954,14 +954,6 @@ const FN_FAMILY: char = 'f';
|
|||
const STATIC_METHOD_FAMILY: char = 'F';
|
||||
const METHOD_FAMILY: char = 'h';
|
||||
|
||||
fn should_inline(attrs: &[ast::Attribute]) -> bool {
|
||||
use syntax::attr::*;
|
||||
match find_inline_attr(attrs) {
|
||||
InlineNone | InlineNever => false,
|
||||
InlineHint | InlineAlways => true
|
||||
}
|
||||
}
|
||||
|
||||
// Encodes the inherent implementations of a structure, enumeration, or trait.
|
||||
fn encode_inherent_implementations(ecx: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
|
@ -1067,7 +1059,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_name(rbml_w, item.ident.name);
|
||||
encode_path(rbml_w, path);
|
||||
encode_attributes(rbml_w, &item.attrs);
|
||||
if tps_len > 0 || should_inline(&item.attrs) {
|
||||
if tps_len > 0 || attr::requests_inline(&item.attrs) {
|
||||
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
|
||||
}
|
||||
if tps_len == 0 {
|
||||
|
|
|
@ -465,7 +465,8 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
|||
* Replace all regions bound by `binder` with skolemized regions and
|
||||
* return a map indicating which bound-region was replaced with what
|
||||
* skolemized region. This is the first step of checking subtyping
|
||||
* when higher-ranked things are involved. See `doc.rs` for more details.
|
||||
* when higher-ranked things are involved. See `README.md` for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br| {
|
||||
|
@ -490,7 +491,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|||
* and checks to determine whether any of the skolemized regions created
|
||||
* in `skol_map` would "escape" -- meaning that they are related to
|
||||
* other regions in some way. If so, the higher-ranked subtyping doesn't
|
||||
* hold. See `doc.rs` for more details.
|
||||
* hold. See `README.md` for more details.
|
||||
*/
|
||||
|
||||
debug!("leak_check: skol_map={}",
|
||||
|
@ -533,7 +534,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|||
/// passed; currently, it's used in the trait matching code to create
|
||||
/// a set of nested obligations frmo an impl that matches against
|
||||
/// something higher-ranked. More details can be found in
|
||||
/// `middle::traits::doc.rs`.
|
||||
/// `librustc/middle/traits/README.md`.
|
||||
///
|
||||
/// As a brief example, consider the obligation `for<'a> Fn(&'a int)
|
||||
/// -> &'a int`, and the impl:
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! See doc.rs
|
||||
//! See README.md
|
||||
|
||||
pub use self::Constraint::*;
|
||||
pub use self::Verify::*;
|
||||
|
|
|
@ -26,20 +26,10 @@ use syntax::abi;
|
|||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{is_local, PostExpansionMethod};
|
||||
use syntax::attr::{InlineAlways, InlineHint, InlineNever, InlineNone};
|
||||
use syntax::attr;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::visit;
|
||||
|
||||
// Returns true if the given set of attributes contains the `#[inline]`
|
||||
// attribute.
|
||||
fn attributes_specify_inlining(attrs: &[ast::Attribute]) -> bool {
|
||||
match attr::find_inline_attr(attrs) {
|
||||
InlineNone | InlineNever => false,
|
||||
InlineAlways | InlineHint => true,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the given set of generics implies that the item it's
|
||||
// associated with must be inlined.
|
||||
fn generics_require_inlining(generics: &ast::Generics) -> bool {
|
||||
|
@ -50,7 +40,7 @@ fn generics_require_inlining(generics: &ast::Generics) -> bool {
|
|||
// monomorphized or it was marked with `#[inline]`. This will only return
|
||||
// true for functions.
|
||||
fn item_might_be_inlined(item: &ast::Item) -> bool {
|
||||
if attributes_specify_inlining(&item.attrs) {
|
||||
if attr::requests_inline(&item.attrs) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -65,7 +55,7 @@ fn item_might_be_inlined(item: &ast::Item) -> bool {
|
|||
|
||||
fn method_might_be_inlined(tcx: &ty::ctxt, method: &ast::Method,
|
||||
impl_src: ast::DefId) -> bool {
|
||||
if attributes_specify_inlining(&method.attrs) ||
|
||||
if attr::requests_inline(&method.attrs) ||
|
||||
generics_require_inlining(method.pe_generics()) {
|
||||
return true
|
||||
}
|
||||
|
@ -201,8 +191,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
match *impl_item {
|
||||
ast::MethodImplItem(ref method) => {
|
||||
if generics_require_inlining(method.pe_generics()) ||
|
||||
attributes_specify_inlining(
|
||||
&method.attrs) {
|
||||
attr::requests_inline(&method.attrs) {
|
||||
true
|
||||
} else {
|
||||
let impl_did = self.tcx
|
||||
|
|
|
@ -852,7 +852,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
|
|||
// The idea is that call.callee_id represents *the time when
|
||||
// the invoked function is actually running* and call.id
|
||||
// represents *the time to prepare the arguments and make the
|
||||
// call*. See the section "Borrows in Calls" borrowck/doc.rs
|
||||
// call*. See the section "Borrows in Calls" borrowck/README.md
|
||||
// for an extended explanation of why this distinction is
|
||||
// important.
|
||||
//
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! See `doc.rs` for high-level documentation
|
||||
//! See `README.md` for high-level documentation
|
||||
|
||||
use super::Normalized;
|
||||
use super::SelectionContext;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! See `doc.rs` for high-level documentation
|
||||
//! See `README.md` for high-level documentation
|
||||
#![allow(dead_code)] // FIXME -- just temporarily
|
||||
|
||||
pub use self::MethodMatchResult::*;
|
||||
|
@ -547,7 +547,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
//
|
||||
// The selection process begins by examining all in-scope impls,
|
||||
// caller obligations, and so forth and assembling a list of
|
||||
// candidates. See `doc.rs` and the `Candidate` type for more details.
|
||||
// candidates. See `README.md` and the `Candidate` type for more
|
||||
// details.
|
||||
|
||||
fn candidate_from_obligation<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
|
@ -1619,7 +1620,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
//
|
||||
// Confirmation unifies the output type parameters of the trait
|
||||
// with the values found in the obligation, possibly yielding a
|
||||
// type error. See `doc.rs` for more details.
|
||||
// type error. See `README.md` for more details.
|
||||
|
||||
fn confirm_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
|
|
|
@ -212,7 +212,7 @@ pub fn memoized<T, U, S, F>(cache: &RefCell<HashMap<T, U, S>>, arg: T, f: F) ->
|
|||
F: FnOnce(T) -> U,
|
||||
{
|
||||
let key = arg.clone();
|
||||
let result = cache.borrow().get(&key).map(|result| result.clone());
|
||||
let result = cache.borrow().get(&key).cloned();
|
||||
match result {
|
||||
Some(result) => result,
|
||||
None => {
|
||||
|
|
|
@ -53,8 +53,8 @@ Here `x` represents some variable, `LV.f` is a field reference,
|
|||
and `*LV` is a pointer dereference. There is no auto-deref or other
|
||||
niceties. This means that if you have a type like:
|
||||
|
||||
```text
|
||||
struct S { f: uint }
|
||||
```rust
|
||||
struct S { f: i32 }
|
||||
```
|
||||
|
||||
and a variable `a: Box<S>`, then the rust expression `a.f` would correspond
|
||||
|
@ -63,8 +63,8 @@ to an `LV` of `(*a).f`.
|
|||
Here is the formal grammar for the types we'll consider:
|
||||
|
||||
```text
|
||||
TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY
|
||||
MQ = mut | imm | const
|
||||
TY = i32 | bool | S<'LT...> | Box<TY> | & 'LT MQ TY
|
||||
MQ = mut | imm
|
||||
```
|
||||
|
||||
Most of these types should be pretty self explanatory. Here `S` is a
|
||||
|
@ -82,13 +82,13 @@ SD = struct S<'LT...> { (f: TY)... }
|
|||
|
||||
Now, imagine we had a program like this:
|
||||
|
||||
```text
|
||||
struct Foo { f: uint, g: uint }
|
||||
```rust
|
||||
struct Foo { f: i32, g: i32 }
|
||||
...
|
||||
'a: {
|
||||
let mut x: Box<Foo> = ...;
|
||||
let y = &mut (*x).f;
|
||||
x = ...;
|
||||
let mut x: Box<Foo> = ...;
|
||||
let y = &mut (*x).f;
|
||||
x = ...;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -198,7 +198,7 @@ The kinds of expressions which in-scope loans can render illegal are:
|
|||
|
||||
Now that we hopefully have some kind of intuitive feeling for how the
|
||||
borrow checker works, let's look a bit more closely now at the precise
|
||||
conditions that it uses. For simplicity I will ignore const loans.
|
||||
conditions that it uses.
|
||||
|
||||
I will present the rules in a modified form of standard inference
|
||||
rules, which looks as follows:
|
||||
|
@ -261,12 +261,11 @@ that will go into the final loan. We'll discuss in more detail below.
|
|||
## Checking mutability
|
||||
|
||||
Checking mutability is fairly straightforward. We just want to prevent
|
||||
immutable data from being borrowed as mutable. Note that it is ok to
|
||||
borrow mutable data as immutable, since that is simply a
|
||||
freeze. Formally we define a predicate `MUTABLE(LV, MQ)` which, if
|
||||
defined, means that "borrowing `LV` with mutability `MQ` is ok. The
|
||||
Rust code corresponding to this predicate is the function
|
||||
`check_mutability` in `middle::borrowck::gather_loans`.
|
||||
immutable data from being borrowed as mutable. Note that it is ok to borrow
|
||||
mutable data as immutable, since that is simply a freeze. The judgement
|
||||
`MUTABILITY(LV, MQ)` means the mutability of `LV` is compatible with a borrow
|
||||
of mutability `MQ`. The Rust code corresponding to this predicate is the
|
||||
function `check_mutability` in `middle::borrowck::gather_loans`.
|
||||
|
||||
### Checking mutability of variables
|
||||
|
||||
|
@ -275,15 +274,14 @@ but also the code in `mem_categorization`.
|
|||
|
||||
Let's begin with the rules for variables, which state that if a
|
||||
variable is declared as mutable, it may be borrowed any which way, but
|
||||
otherwise the variable must be borrowed as immutable or const:
|
||||
otherwise the variable must be borrowed as immutable:
|
||||
|
||||
```text
|
||||
MUTABILITY(X, MQ) // M-Var-Mut
|
||||
DECL(X) = mut
|
||||
|
||||
MUTABILITY(X, MQ) // M-Var-Imm
|
||||
MUTABILITY(X, imm) // M-Var-Imm
|
||||
DECL(X) = imm
|
||||
MQ = imm | const
|
||||
```
|
||||
|
||||
### Checking mutability of owned content
|
||||
|
@ -304,12 +302,11 @@ MUTABILITY(*LV, MQ) // M-Deref-Unique
|
|||
### Checking mutability of immutable pointer types
|
||||
|
||||
Immutable pointer types like `&T` can only
|
||||
be borrowed if MQ is immutable or const:
|
||||
be borrowed if MQ is immutable:
|
||||
|
||||
```text
|
||||
MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm
|
||||
MUTABILITY(*LV, imm) // M-Deref-Borrowed-Imm
|
||||
TYPE(LV) = &Ty
|
||||
MQ == imm | const
|
||||
```
|
||||
|
||||
### Checking mutability of mutable pointer types
|
||||
|
@ -323,12 +320,11 @@ MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Mut
|
|||
|
||||
## Checking aliasability
|
||||
|
||||
The goal of the aliasability check is to ensure that we never permit
|
||||
`&mut` borrows of aliasable data. Formally we define a predicate
|
||||
`ALIASABLE(LV, MQ)` which if defined means that
|
||||
"borrowing `LV` with mutability `MQ` is ok". The
|
||||
Rust code corresponding to this predicate is the function
|
||||
`check_aliasability()` in `middle::borrowck::gather_loans`.
|
||||
The goal of the aliasability check is to ensure that we never permit `&mut`
|
||||
borrows of aliasable data. The judgement `ALIASABLE(LV, MQ)` means the
|
||||
aliasability of `LV` is compatible with a borrow of mutability `MQ`. The Rust
|
||||
code corresponding to this predicate is the function `check_aliasability()` in
|
||||
`middle::borrowck::gather_loans`.
|
||||
|
||||
### Checking aliasability of variables
|
||||
|
||||
|
@ -379,40 +375,6 @@ Formally, we define a predicate `LIFETIME(LV, LT, MQ)`, which states that
|
|||
`MQ`". The Rust code corresponding to this predicate is the module
|
||||
`middle::borrowck::gather_loans::lifetime`.
|
||||
|
||||
### The Scope function
|
||||
|
||||
Several of the rules refer to a helper function `SCOPE(LV)=LT`. The
|
||||
`SCOPE(LV)` yields the lifetime `LT` for which the lvalue `LV` is
|
||||
guaranteed to exist, presuming that no mutations occur.
|
||||
|
||||
The scope of a local variable is the block where it is declared:
|
||||
|
||||
```text
|
||||
SCOPE(X) = block where X is declared
|
||||
```
|
||||
|
||||
The scope of a field is the scope of the struct:
|
||||
|
||||
```text
|
||||
SCOPE(LV.f) = SCOPE(LV)
|
||||
```
|
||||
|
||||
The scope of a unique referent is the scope of the pointer, since
|
||||
(barring mutation or moves) the pointer will not be freed until
|
||||
the pointer itself `LV` goes out of scope:
|
||||
|
||||
```text
|
||||
SCOPE(*LV) = SCOPE(LV) if LV has type Box<T>
|
||||
```
|
||||
|
||||
The scope of a borrowed referent is the scope associated with the
|
||||
pointer. This is a conservative approximation, since the data that
|
||||
the pointer points at may actually live longer:
|
||||
|
||||
```text
|
||||
SCOPE(*LV) = LT if LV has type &'LT T or &'LT mut T
|
||||
```
|
||||
|
||||
### Checking lifetime of variables
|
||||
|
||||
The rule for variables states that a variable can only be borrowed a
|
||||
|
@ -420,7 +382,7 @@ lifetime `LT` that is a subregion of the variable's scope:
|
|||
|
||||
```text
|
||||
LIFETIME(X, LT, MQ) // L-Local
|
||||
LT <= SCOPE(X)
|
||||
LT <= block where X is declared
|
||||
```
|
||||
|
||||
### Checking lifetime for owned content
|
||||
|
@ -466,15 +428,12 @@ are computed based on the kind of borrow:
|
|||
```text
|
||||
&mut LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM|FREEZE)
|
||||
&LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM)
|
||||
&const LV => RESTRICTIONS(LV, LT, [])
|
||||
```
|
||||
|
||||
The reasoning here is that a mutable borrow must be the only writer,
|
||||
therefore it prevents other writes (`MUTATE`), mutable borrows
|
||||
(`CLAIM`), and immutable borrows (`FREEZE`). An immutable borrow
|
||||
permits other immutable borrows but forbids writes and mutable borrows.
|
||||
Finally, a const borrow just wants to be sure that the value is not
|
||||
moved out from under it, so no actions are forbidden.
|
||||
|
||||
### Restrictions for loans of a local variable
|
||||
|
||||
|
@ -548,8 +507,8 @@ specify that the lifetime of the loan must be less than the lifetime
|
|||
of the `&Ty` pointer. In simple cases, this clause is redundant, since
|
||||
the `LIFETIME()` function will already enforce the required rule:
|
||||
|
||||
```
|
||||
fn foo(point: &'a Point) -> &'static f32 {
|
||||
```rust
|
||||
fn foo(point: &'a Point) -> &'static i32 {
|
||||
&point.x // Error
|
||||
}
|
||||
```
|
||||
|
@ -558,8 +517,8 @@ The above example fails to compile both because of clause (1) above
|
|||
but also by the basic `LIFETIME()` check. However, in more advanced
|
||||
examples involving multiple nested pointers, clause (1) is needed:
|
||||
|
||||
```
|
||||
fn foo(point: &'a &'b mut Point) -> &'b f32 {
|
||||
```rust
|
||||
fn foo(point: &'a &'b mut Point) -> &'b i32 {
|
||||
&point.x // Error
|
||||
}
|
||||
```
|
||||
|
@ -577,8 +536,8 @@ which is only `'a`, not `'b`. Hence this example yields an error.
|
|||
As a final twist, consider the case of two nested *immutable*
|
||||
pointers, rather than a mutable pointer within an immutable one:
|
||||
|
||||
```
|
||||
fn foo(point: &'a &'b Point) -> &'b f32 {
|
||||
```rust
|
||||
fn foo(point: &'a &'b Point) -> &'b i32 {
|
||||
&point.x // OK
|
||||
}
|
||||
```
|
||||
|
@ -599,8 +558,8 @@ The rules pertaining to `LIFETIME` exist to ensure that we don't
|
|||
create a borrowed pointer that outlives the memory it points at. So
|
||||
`LIFETIME` prevents a function like this:
|
||||
|
||||
```
|
||||
fn get_1<'a>() -> &'a int {
|
||||
```rust
|
||||
fn get_1<'a>() -> &'a i32 {
|
||||
let x = 1;
|
||||
&x
|
||||
}
|
||||
|
@ -619,8 +578,8 @@ after we return and hence the remaining code in `'a` cannot possibly
|
|||
mutate it. This distinction is important for type checking functions
|
||||
like this one:
|
||||
|
||||
```
|
||||
fn inc_and_get<'a>(p: &'a mut Point) -> &'a int {
|
||||
```rust
|
||||
fn inc_and_get<'a>(p: &'a mut Point) -> &'a i32 {
|
||||
p.x += 1;
|
||||
&p.x
|
||||
}
|
||||
|
@ -641,19 +600,6 @@ in terms of capability, the caller passed in the ability to mutate
|
|||
`*p` is borrowed since that would be a move of `p`, as `&mut` pointers
|
||||
are affine.)
|
||||
|
||||
### Restrictions for loans of const aliasable referents
|
||||
|
||||
Freeze pointers are read-only. There may be `&mut` or `&` aliases, and
|
||||
we can not prevent *anything* but moves in that case. So the
|
||||
`RESTRICTIONS` function is only defined if `ACTIONS` is the empty set.
|
||||
Because moves from a `&const` lvalue are never legal, it is not
|
||||
necessary to add any restrictions at all to the final result.
|
||||
|
||||
```text
|
||||
RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed
|
||||
TYPE(LV) = &const Ty
|
||||
```
|
||||
|
||||
### Restrictions for loans of mutable borrowed referents
|
||||
|
||||
Mutable borrowed pointers are guaranteed to be the only way to mutate
|
||||
|
@ -685,7 +631,7 @@ maximum of `LT'`.
|
|||
|
||||
Here is a concrete example of a bug this rule prevents:
|
||||
|
||||
```
|
||||
```rust
|
||||
// Test region-reborrow-from-shorter-mut-ref.rs:
|
||||
fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T {
|
||||
&mut **p // ERROR due to clause (1)
|
||||
|
@ -713,10 +659,10 @@ ways to violate the rules is to move the base pointer to a new name
|
|||
and access it via that new name, thus bypassing the restrictions on
|
||||
the old name. Here is an example:
|
||||
|
||||
```
|
||||
```rust
|
||||
// src/test/compile-fail/borrowck-move-mut-base-ptr.rs
|
||||
fn foo(t0: &mut int) {
|
||||
let p: &int = &*t0; // Freezes `*t0`
|
||||
fn foo(t0: &mut i32) {
|
||||
let p: &i32 = &*t0; // Freezes `*t0`
|
||||
let t1 = t0; //~ ERROR cannot move out of `t0`
|
||||
*t1 = 22; // OK, not a write through `*t0`
|
||||
}
|
||||
|
@ -733,11 +679,11 @@ danger is to mutably borrow the base path. This can lead to two bad
|
|||
scenarios. The most obvious is that the mutable borrow itself becomes
|
||||
another path to access the same data, as shown here:
|
||||
|
||||
```
|
||||
```rust
|
||||
// src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs
|
||||
fn foo<'a>(mut t0: &'a mut int,
|
||||
mut t1: &'a mut int) {
|
||||
let p: &int = &*t0; // Freezes `*t0`
|
||||
fn foo<'a>(mut t0: &'a mut i32,
|
||||
mut t1: &'a mut i32) {
|
||||
let p: &i32 = &*t0; // Freezes `*t0`
|
||||
let mut t2 = &mut t0; //~ ERROR cannot borrow `t0`
|
||||
**t2 += 1; // Mutates `*t0`
|
||||
}
|
||||
|
@ -754,11 +700,11 @@ of `t0`. Hence the claim `&mut t0` is illegal.
|
|||
Another danger with an `&mut` pointer is that we could swap the `t0`
|
||||
value away to create a new path:
|
||||
|
||||
```
|
||||
```rust
|
||||
// src/test/compile-fail/borrowck-swap-mut-base-ptr.rs
|
||||
fn foo<'a>(mut t0: &'a mut int,
|
||||
mut t1: &'a mut int) {
|
||||
let p: &int = &*t0; // Freezes `*t0`
|
||||
fn foo<'a>(mut t0: &'a mut i32,
|
||||
mut t1: &'a mut i32) {
|
||||
let p: &i32 = &*t0; // Freezes `*t0`
|
||||
swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0`
|
||||
*t1 = 22;
|
||||
}
|
||||
|
@ -772,37 +718,37 @@ careful to ensure this example is still illegal.
|
|||
referent is claimed, even freezing the base pointer can be dangerous,
|
||||
as shown in the following example:
|
||||
|
||||
```
|
||||
```rust
|
||||
// src/test/compile-fail/borrowck-borrow-of-mut-base-ptr.rs
|
||||
fn foo<'a>(mut t0: &'a mut int,
|
||||
mut t1: &'a mut int) {
|
||||
let p: &mut int = &mut *t0; // Claims `*t0`
|
||||
fn foo<'a>(mut t0: &'a mut i32,
|
||||
mut t1: &'a mut i32) {
|
||||
let p: &mut i32 = &mut *t0; // Claims `*t0`
|
||||
let mut t2 = &t0; //~ ERROR cannot borrow `t0`
|
||||
let q: &int = &*t2; // Freezes `*t0` but not through `*p`
|
||||
let q: &i32 = &*t2; // Freezes `*t0` but not through `*p`
|
||||
*p += 1; // violates type of `*q`
|
||||
}
|
||||
```
|
||||
|
||||
Here the problem is that `*t0` is claimed by `p`, and hence `p` wants
|
||||
to be the controlling pointer through which mutation or freezes occur.
|
||||
But `t2` would -- if it were legal -- have the type `& &mut int`, and
|
||||
But `t2` would -- if it were legal -- have the type `& &mut i32`, and
|
||||
hence would be a mutable pointer in an aliasable location, which is
|
||||
considered frozen (since no one can write to `**t2` as it is not a
|
||||
unique path). Therefore, we could reasonably create a frozen `&int`
|
||||
unique path). Therefore, we could reasonably create a frozen `&i32`
|
||||
pointer pointing at `*t0` that coexists with the mutable pointer `p`,
|
||||
which is clearly unsound.
|
||||
|
||||
However, it is not always unsafe to freeze the base pointer. In
|
||||
particular, if the referent is frozen, there is no harm in it:
|
||||
|
||||
```
|
||||
```rust
|
||||
// src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs
|
||||
fn foo<'a>(mut t0: &'a mut int,
|
||||
mut t1: &'a mut int) {
|
||||
let p: &int = &*t0; // Freezes `*t0`
|
||||
fn foo<'a>(mut t0: &'a mut i32,
|
||||
mut t1: &'a mut i32) {
|
||||
let p: &i32 = &*t0; // Freezes `*t0`
|
||||
let mut t2 = &t0;
|
||||
let q: &int = &*t2; // Freezes `*t0`, but that's ok...
|
||||
let r: &int = &*t0; // ...after all, could do same thing directly.
|
||||
let q: &i32 = &*t2; // Freezes `*t0`, but that's ok...
|
||||
let r: &i32 = &*t0; // ...after all, could do same thing directly.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -811,11 +757,11 @@ thing `t2` can be used for is to further freeze `*t0`, which is
|
|||
already frozen. In particular, we cannot assign to `*t0` through the
|
||||
new alias `t2`, as demonstrated in this test case:
|
||||
|
||||
```
|
||||
```rust
|
||||
// src/test/run-pass/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
|
||||
fn foo(t0: & &mut int) {
|
||||
fn foo(t0: & &mut i32) {
|
||||
let t1 = t0;
|
||||
let p: &int = &**t0;
|
||||
let p: &i32 = &**t0;
|
||||
**t1 = 22; //~ ERROR cannot assign
|
||||
}
|
||||
```
|
||||
|
@ -855,6 +801,9 @@ prohibited from both freezes and claims. This would avoid the need to
|
|||
prevent `const` borrows of the base pointer when the referent is
|
||||
borrowed.
|
||||
|
||||
[ Previous revisions of this document discussed `&const` in more detail.
|
||||
See the revision history. ]
|
||||
|
||||
# Moves and initialization
|
||||
|
||||
The borrow checker is also in charge of ensuring that:
|
||||
|
@ -881,9 +830,9 @@ moves/uninitializations of the variable that is being used.
|
|||
|
||||
Let's look at a simple example:
|
||||
|
||||
```
|
||||
fn foo(a: Box<int>) {
|
||||
let b: Box<int>; // Gen bit 0.
|
||||
```rust
|
||||
fn foo(a: Box<i32>) {
|
||||
let b: Box<i32>; // Gen bit 0.
|
||||
|
||||
if cond { // Bits: 0
|
||||
use(&*a);
|
||||
|
@ -897,7 +846,7 @@ fn foo(a: Box<int>) {
|
|||
use(&*b); // Error.
|
||||
}
|
||||
|
||||
fn use(a: &int) { }
|
||||
fn use(a: &i32) { }
|
||||
```
|
||||
|
||||
In this example, the variable `b` is created uninitialized. In one
|
||||
|
@ -1028,8 +977,8 @@ not) the destructor invocation for that path.
|
|||
A simple example of this is the following:
|
||||
|
||||
```rust
|
||||
struct D { p: int }
|
||||
impl D { fn new(x: int) -> D { ... }
|
||||
struct D { p: i32 }
|
||||
impl D { fn new(x: i32) -> D { ... }
|
||||
impl Drop for D { ... }
|
||||
|
||||
fn foo(a: D, b: D, t: || -> bool) {
|
||||
|
@ -1142,7 +1091,7 @@ the elements of an array that has been passed by value, such as
|
|||
the following:
|
||||
|
||||
```rust
|
||||
fn foo(a: [D; 10], i: uint) -> D {
|
||||
fn foo(a: [D; 10], i: i32) -> D {
|
||||
a[i]
|
||||
}
|
||||
```
|
||||
|
@ -1158,7 +1107,7 @@ all-but-one element of the array. A place where that distinction
|
|||
would arise is the following:
|
||||
|
||||
```rust
|
||||
fn foo(a: [D; 10], b: [D; 10], i: uint, t: bool) -> D {
|
||||
fn foo(a: [D; 10], b: [D; 10], i: i32, t: bool) -> D {
|
||||
if t {
|
||||
a[i]
|
||||
} else {
|
||||
|
@ -1173,7 +1122,7 @@ fn foo(a: [D; 10], b: [D; 10], i: uint, t: bool) -> D {
|
|||
|
||||
There are a number of ways that the trans backend could choose to
|
||||
compile this (e.g. a `[bool; 10]` array for each such moved array;
|
||||
or an `Option<uint>` for each moved array). From the viewpoint of the
|
||||
or an `Option<usize>` for each moved array). From the viewpoint of the
|
||||
borrow-checker, the important thing is to record what kind of fragment
|
||||
is implied by the relevant moves.
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
//! Helper routines used for fragmenting structural paths due to moves for
|
||||
//! tracking drop obligations. Please see the extensive comments in the
|
||||
//! section "Structural fragments" in `doc.rs`.
|
||||
//! section "Structural fragments" in `README.md`.
|
||||
|
||||
use self::Fragment::*;
|
||||
|
||||
|
|
|
@ -106,8 +106,6 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
|||
//! lvalue `cmt` is guaranteed to be valid without any
|
||||
//! rooting etc, and presuming `cmt` is not mutated.
|
||||
|
||||
// See the SCOPE(LV) function in doc.rs
|
||||
|
||||
match cmt.cat {
|
||||
mc::cat_rvalue(temp_scope) => {
|
||||
temp_scope
|
||||
|
|
|
@ -173,7 +173,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Implements the A-* rules in doc.rs.
|
||||
/// Implements the A-* rules in README.md.
|
||||
fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
borrow_span: Span,
|
||||
loan_cause: euv::LoanCause,
|
||||
|
@ -375,7 +375,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
|||
cmt: mc::cmt<'tcx>,
|
||||
req_kind: ty::BorrowKind)
|
||||
-> Result<(),()> {
|
||||
//! Implements the M-* rules in doc.rs.
|
||||
//! Implements the M-* rules in README.md.
|
||||
|
||||
match req_kind {
|
||||
ty::UniqueImmBorrow | ty::ImmBorrow => {
|
||||
|
|
|
@ -295,7 +295,7 @@ impl<'tcx> PartialEq for LoanPath<'tcx> {
|
|||
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub enum LoanPathKind<'tcx> {
|
||||
LpVar(ast::NodeId), // `x` in doc.rs
|
||||
LpVar(ast::NodeId), // `x` in README.md
|
||||
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
|
||||
LpDowncast(Rc<LoanPath<'tcx>>, ast::DefId), // `x` downcast to particular enum variant
|
||||
LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem)
|
||||
|
@ -336,8 +336,8 @@ impl ToInteriorKind for mc::InteriorKind {
|
|||
|
||||
#[derive(Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum LoanPathElem {
|
||||
LpDeref(mc::PointerKind), // `*LV` in doc.rs
|
||||
LpInterior(InteriorKind), // `LV.f` in doc.rs
|
||||
LpDeref(mc::PointerKind), // `*LV` in README.md
|
||||
LpInterior(InteriorKind), // `LV.f` in README.md
|
||||
}
|
||||
|
||||
pub fn closure_to_block(closure_id: ast::NodeId,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
//! Data structures used for tracking moves. Please see the extensive
|
||||
//! comments in the section "Moves and initialization" in `doc.rs`.
|
||||
//! comments in the section "Moves and initialization" in `README.md`.
|
||||
|
||||
pub use self::MoveKind::*;
|
||||
|
||||
|
@ -33,7 +33,7 @@ use syntax::codemap::Span;
|
|||
pub mod fragments;
|
||||
|
||||
pub struct MoveData<'tcx> {
|
||||
/// Move paths. See section "Move paths" in `doc.rs`.
|
||||
/// Move paths. See section "Move paths" in `README.md`.
|
||||
pub paths: RefCell<Vec<MovePath<'tcx>>>,
|
||||
|
||||
/// Cache of loan path to move path index, for easy lookup.
|
||||
|
@ -464,7 +464,7 @@ impl<'tcx> MoveData<'tcx> {
|
|||
/// assignments into the provided data flow contexts.
|
||||
/// Moves are generated by moves and killed by assignments and
|
||||
/// scoping. Assignments are generated by assignment to variables and
|
||||
/// killed by scoping. See `doc.rs` for more details.
|
||||
/// killed by scoping. See `README.md` for more details.
|
||||
fn add_gen_kills(&self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
dfcx_moves: &mut MoveDataFlow,
|
||||
|
|
|
@ -663,23 +663,21 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
match typ.node {
|
||||
// Common case impl for a struct or something basic.
|
||||
ast::TyPath(ref path, id) => {
|
||||
match self.lookup_type_ref(id) {
|
||||
Some(id) => {
|
||||
let sub_span = self.span.sub_span_for_type_name(path.span);
|
||||
self.fmt.ref_str(recorder::TypeRef,
|
||||
path.span,
|
||||
sub_span,
|
||||
id,
|
||||
self.cur_scope);
|
||||
self.fmt.impl_str(path.span,
|
||||
sub_span,
|
||||
item.id,
|
||||
Some(id),
|
||||
trait_id,
|
||||
self.cur_scope);
|
||||
},
|
||||
None => ()
|
||||
}
|
||||
let sub_span = self.span.sub_span_for_type_name(path.span);
|
||||
let self_id = self.lookup_type_ref(id).map(|id| {
|
||||
self.fmt.ref_str(recorder::TypeRef,
|
||||
path.span,
|
||||
sub_span,
|
||||
id,
|
||||
self.cur_scope);
|
||||
id
|
||||
});
|
||||
self.fmt.impl_str(path.span,
|
||||
sub_span,
|
||||
item.id,
|
||||
self_id,
|
||||
trait_id,
|
||||
self.cur_scope);
|
||||
},
|
||||
_ => {
|
||||
// Less useful case, impl for a compound type.
|
||||
|
@ -1002,28 +1000,39 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
ast::PatStruct(ref path, ref fields, _) => {
|
||||
self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef));
|
||||
visit::walk_path(self, path);
|
||||
let struct_def = match self.lookup_type_ref(p.id) {
|
||||
Some(sd) => sd,
|
||||
None => {
|
||||
self.sess.span_bug(p.span,
|
||||
&format!("Could not find struct_def for `{}`",
|
||||
self.span.snippet(p.span)));
|
||||
}
|
||||
};
|
||||
for &Spanned { node: ref field, span } in fields {
|
||||
let sub_span = self.span.span_for_first_ident(span);
|
||||
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
|
||||
for f in fields {
|
||||
if f.name == field.ident.name {
|
||||
self.fmt.ref_str(recorder::VarRef,
|
||||
span,
|
||||
sub_span,
|
||||
f.id,
|
||||
self.cur_scope);
|
||||
break;
|
||||
|
||||
let def = self.analysis.ty_cx.def_map.borrow()[p.id];
|
||||
let struct_def = match def {
|
||||
def::DefConst(..) => None,
|
||||
def::DefVariant(_, variant_id, _) => Some(variant_id),
|
||||
_ => {
|
||||
match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
|
||||
None => {
|
||||
self.sess.span_bug(p.span,
|
||||
&format!("Could not find struct_def for `{}`",
|
||||
self.span.snippet(p.span)));
|
||||
}
|
||||
Some(def_id) => Some(def_id),
|
||||
}
|
||||
}
|
||||
self.visit_pat(&*field.pat);
|
||||
};
|
||||
|
||||
if let Some(struct_def) = struct_def {
|
||||
let struct_fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
|
||||
for &Spanned { node: ref field, span } in fields {
|
||||
let sub_span = self.span.span_for_first_ident(span);
|
||||
for f in &struct_fields {
|
||||
if f.name == field.ident.name {
|
||||
self.fmt.ref_str(recorder::VarRef,
|
||||
span,
|
||||
sub_span,
|
||||
f.id,
|
||||
self.cur_scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.visit_pat(&*field.pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::PatEnum(ref path, _) => {
|
||||
|
|
|
@ -301,7 +301,7 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
self_type.repr(ccx.tcx()));
|
||||
(&function_type.sig, RustCall, Some(llenvironment_type))
|
||||
}
|
||||
_ => panic!("expected closure or fn")
|
||||
_ => ccx.sess().bug("expected closure or fn")
|
||||
};
|
||||
|
||||
let sig = ty::erase_late_bound_regions(ccx.tcx(), sig);
|
||||
|
@ -435,7 +435,7 @@ pub fn set_inline_hint(f: ValueRef) {
|
|||
pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
|
||||
use syntax::attr::*;
|
||||
// Set the inline hint if there is one
|
||||
match find_inline_attr(attrs) {
|
||||
match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) {
|
||||
InlineHint => set_inline_hint(llfn),
|
||||
InlineAlways => set_always_inline(llfn),
|
||||
InlineNever => set_no_inline(llfn),
|
||||
|
@ -2410,12 +2410,15 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
node_id: ast::NodeId,
|
||||
node_type: Ty<'tcx>)
|
||||
-> ValueRef {
|
||||
match node_type.sty {
|
||||
ty::ty_bare_fn(_, ref f) => {
|
||||
assert!(f.abi == Rust || f.abi == RustCall);
|
||||
if let ty::ty_bare_fn(_, ref f) = node_type.sty {
|
||||
if f.abi != Rust && f.abi != RustCall {
|
||||
ccx.sess().span_bug(sp, &format!("only the `{}` or `{}` calling conventions are valid \
|
||||
for this function; `{}` was specified",
|
||||
Rust.name(), RustCall.name(), f.abi.name()));
|
||||
}
|
||||
_ => panic!("expected bare rust fn")
|
||||
};
|
||||
} else {
|
||||
ccx.sess().span_bug(sp, "expected bare rust function")
|
||||
}
|
||||
|
||||
let llfn = decl_rust_fn(ccx, node_type, &sym[..]);
|
||||
finish_register_fn(ccx, sp, sym, node_id, llfn);
|
||||
|
@ -2802,7 +2805,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
|||
llfn
|
||||
}
|
||||
|
||||
_ => panic!("get_item_val: weird result in table")
|
||||
_ => ccx.sess().bug("get_item_val: weird result in table")
|
||||
};
|
||||
|
||||
match attr::first_attr_value_str_by_name(&i.attrs,
|
||||
|
@ -2866,7 +2869,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
|||
let args = match v.node.kind {
|
||||
ast::TupleVariantKind(ref args) => args,
|
||||
ast::StructVariantKind(_) => {
|
||||
panic!("struct variant kind unexpected in get_item_val")
|
||||
ccx.sess().bug("struct variant kind unexpected in get_item_val")
|
||||
}
|
||||
};
|
||||
assert!(args.len() != 0);
|
||||
|
@ -2882,7 +2885,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
|||
ast::ItemEnum(_, _) => {
|
||||
register_fn(ccx, (*v).span, sym, id, ty)
|
||||
}
|
||||
_ => panic!("NodeVariant, shouldn't happen")
|
||||
_ => ccx.sess().bug("NodeVariant, shouldn't happen")
|
||||
};
|
||||
set_inline_hint(llfn);
|
||||
llfn
|
||||
|
@ -2935,9 +2938,17 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId,
|
|||
|
||||
let sym = exported_name(ccx, id, mty, &m.attrs);
|
||||
|
||||
let llfn = register_fn(ccx, m.span, sym, id, mty);
|
||||
set_llvm_fn_attrs(ccx, &m.attrs, llfn);
|
||||
llfn
|
||||
if let ty::ty_bare_fn(_, ref f) = mty.sty {
|
||||
let llfn = if f.abi == Rust || f.abi == RustCall {
|
||||
register_fn(ccx, m.span, sym, id, mty)
|
||||
} else {
|
||||
foreign::register_rust_fn_with_foreign_abi(ccx, m.span, sym, id)
|
||||
};
|
||||
set_llvm_fn_attrs(ccx, &m.attrs, llfn);
|
||||
return llfn;
|
||||
} else {
|
||||
ccx.sess().span_bug(m.span, "expected bare rust function");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>,
|
||||
|
|
|
@ -765,8 +765,16 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
if is_rust_fn {
|
||||
let mut llargs = Vec::new();
|
||||
|
||||
if let (ty::FnConverging(ret_ty), Some(llretslot)) = (ret_ty, opt_llretslot) {
|
||||
if let (ty::FnConverging(ret_ty), Some(mut llretslot)) = (ret_ty, opt_llretslot) {
|
||||
if type_of::return_uses_outptr(ccx, ret_ty) {
|
||||
let llformal_ret_ty = type_of::type_of(ccx, ret_ty).ptr_to();
|
||||
let llret_ty = common::val_ty(llretslot);
|
||||
if llformal_ret_ty != llret_ty {
|
||||
// this could happen due to e.g. subtyping
|
||||
debug!("casting actual return type ({}) to match formal ({})",
|
||||
bcx.llty_str(llret_ty), bcx.llty_str(llformal_ret_ty));
|
||||
llretslot = PointerCast(bcx, llretslot, llformal_ret_ty);
|
||||
}
|
||||
llargs.push(llretslot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ use syntax::codemap::DUMMY_SP;
|
|||
/// A `Datum` encapsulates the result of evaluating an expression. It
|
||||
/// describes where the value is stored, what Rust type the value has,
|
||||
/// whether it is addressed by reference, and so forth. Please refer
|
||||
/// the section on datums in `doc.rs` for more details.
|
||||
/// the section on datums in `README.md` for more details.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Datum<'tcx, K> {
|
||||
/// The llvm value. This is either a pointer to the Rust value or
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Method lookup: the secret sauce of Rust. See `doc.rs`.
|
||||
//! Method lookup: the secret sauce of Rust. See `README.md`.
|
||||
|
||||
use astconv::AstConv;
|
||||
use check::{FnCtxt};
|
||||
|
|
|
@ -203,7 +203,7 @@ fn test_resize_policy() {
|
|||
// produces identical results to a linear naive reinsertion from the same
|
||||
// element.
|
||||
//
|
||||
// FIXME(Gankro, pczarn): review the proof and put it all in a separate doc.rs
|
||||
// FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md
|
||||
|
||||
/// A hash map implementation which uses linear probing with Robin
|
||||
/// Hood bucket stealing.
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
//!
|
||||
//! Rust's collections can be grouped into four major categories:
|
||||
//!
|
||||
//! * Sequences: `Vec`, `VecDeque`, `LinkedList`, `BitV`
|
||||
//! * Sequences: `Vec`, `VecDeque`, `LinkedList`, `BitVec`
|
||||
//! * Maps: `HashMap`, `BTreeMap`, `VecMap`
|
||||
//! * Sets: `HashSet`, `BTreeSet`, `BitVSet`
|
||||
//! * Sets: `HashSet`, `BTreeSet`, `BitSet`
|
||||
//! * Misc: `BinaryHeap`
|
||||
//!
|
||||
//! # When Should You Use Which Collection?
|
||||
|
@ -73,11 +73,11 @@
|
|||
//! * There is no meaningful value to associate with your keys.
|
||||
//! * You just want a set.
|
||||
//!
|
||||
//! ### Use a `BitV` when:
|
||||
//! ### Use a `BitVec` when:
|
||||
//! * You want to store an unbounded number of booleans in a small space.
|
||||
//! * You want a bit vector.
|
||||
//!
|
||||
//! ### Use a `BitVSet` when:
|
||||
//! ### Use a `BitSet` when:
|
||||
//! * You want a `VecSet`.
|
||||
//!
|
||||
//! ### Use a `BinaryHeap` when:
|
||||
|
|
|
@ -224,7 +224,7 @@ impl CString {
|
|||
/// Returns the contents of this `CString` as a slice of bytes.
|
||||
///
|
||||
/// The returned slice does **not** contain the trailing nul separator and
|
||||
/// it is guaranteet to not have any interior nul bytes.
|
||||
/// it is guaranteed to not have any interior nul bytes.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.inner[..self.inner.len() - 1]
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ impl CStr {
|
|||
/// Return the inner pointer to this C string.
|
||||
///
|
||||
/// The returned pointer will be valid for as long as `self` is and points
|
||||
/// to a continguous region of memory terminated with a 0 byte to represent
|
||||
/// to a contiguous region of memory terminated with a 0 byte to represent
|
||||
/// the end of the string.
|
||||
pub fn as_ptr(&self) -> *const libc::c_char {
|
||||
self.inner.as_ptr()
|
||||
|
@ -371,7 +371,7 @@ impl CStr {
|
|||
|
||||
impl PartialEq for CStr {
|
||||
fn eq(&self, other: &CStr) -> bool {
|
||||
self.to_bytes().eq(&other.to_bytes())
|
||||
self.to_bytes().eq(other.to_bytes())
|
||||
}
|
||||
}
|
||||
impl Eq for CStr {}
|
||||
|
|
|
@ -669,6 +669,11 @@ impl<T> Take<T> {
|
|||
|
||||
impl<T: Read> Read for Take<T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
// Don't call into inner reader at all at EOF because it may still block
|
||||
if self.limit == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let max = cmp::min(buf.len() as u64, self.limit) as usize;
|
||||
let n = try!(self.inner.read(&mut buf[..max]));
|
||||
self.limit -= n as u64;
|
||||
|
@ -676,6 +681,21 @@ impl<T: Read> Read for Take<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: BufRead> BufRead for Take<T> {
|
||||
fn fill_buf(&mut self) -> Result<&[u8]> {
|
||||
let buf = try!(self.inner.fill_buf());
|
||||
let cap = cmp::min(buf.len() as u64, self.limit) as usize;
|
||||
Ok(&buf[..cap])
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
// Don't let callers reset the limit by passing an overlarge value
|
||||
let amt = cmp::min(amt as u64, self.limit) as usize;
|
||||
self.limit -= amt as u64;
|
||||
self.inner.consume(amt);
|
||||
}
|
||||
}
|
||||
|
||||
/// An adaptor which will emit all read data to a specified writer as well.
|
||||
///
|
||||
/// For more information see `ReadExt::tee`
|
||||
|
@ -846,6 +866,7 @@ impl<B: BufRead> Iterator for Lines<B> {
|
|||
mod tests {
|
||||
use prelude::v1::*;
|
||||
use io::prelude::*;
|
||||
use io;
|
||||
use super::Cursor;
|
||||
|
||||
#[test]
|
||||
|
@ -943,4 +964,18 @@ mod tests {
|
|||
let mut v = String::new();
|
||||
assert!(c.read_to_string(&mut v).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn take_eof() {
|
||||
struct R;
|
||||
|
||||
impl Read for R {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "", None))
|
||||
}
|
||||
}
|
||||
|
||||
let mut buf = [0; 1];
|
||||
assert_eq!(Ok(0), R.take(0).read(&mut buf));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,7 @@
|
|||
#![feature(unsafe_destructor)]
|
||||
#![feature(unsafe_no_drop_flag)]
|
||||
#![feature(macro_reexport)]
|
||||
#![feature(hash)]
|
||||
#![cfg_attr(test, feature(test, rustc_private, env))]
|
||||
|
||||
// Don't link to std. We are std.
|
||||
|
|
|
@ -1751,6 +1751,72 @@ mod tests {
|
|||
assert_pow!((8, 3 ) => 512);
|
||||
assert_pow!((2u64, 50) => 1125899906842624);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uint_to_str_overflow() {
|
||||
let mut u8_val: u8 = 255_u8;
|
||||
assert_eq!(u8_val.to_string(), "255");
|
||||
|
||||
u8_val += 1 as u8;
|
||||
assert_eq!(u8_val.to_string(), "0");
|
||||
|
||||
let mut u16_val: u16 = 65_535_u16;
|
||||
assert_eq!(u16_val.to_string(), "65535");
|
||||
|
||||
u16_val += 1 as u16;
|
||||
assert_eq!(u16_val.to_string(), "0");
|
||||
|
||||
let mut u32_val: u32 = 4_294_967_295_u32;
|
||||
assert_eq!(u32_val.to_string(), "4294967295");
|
||||
|
||||
u32_val += 1 as u32;
|
||||
assert_eq!(u32_val.to_string(), "0");
|
||||
|
||||
let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
|
||||
assert_eq!(u64_val.to_string(), "18446744073709551615");
|
||||
|
||||
u64_val += 1 as u64;
|
||||
assert_eq!(u64_val.to_string(), "0");
|
||||
}
|
||||
|
||||
fn from_str<T: ::str::FromStr>(t: &str) -> Option<T> {
|
||||
::str::FromStr::from_str(t).ok()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uint_from_str_overflow() {
|
||||
let mut u8_val: u8 = 255_u8;
|
||||
assert_eq!(from_str::<u8>("255"), Some(u8_val));
|
||||
assert_eq!(from_str::<u8>("256"), None);
|
||||
|
||||
u8_val += 1 as u8;
|
||||
assert_eq!(from_str::<u8>("0"), Some(u8_val));
|
||||
assert_eq!(from_str::<u8>("-1"), None);
|
||||
|
||||
let mut u16_val: u16 = 65_535_u16;
|
||||
assert_eq!(from_str::<u16>("65535"), Some(u16_val));
|
||||
assert_eq!(from_str::<u16>("65536"), None);
|
||||
|
||||
u16_val += 1 as u16;
|
||||
assert_eq!(from_str::<u16>("0"), Some(u16_val));
|
||||
assert_eq!(from_str::<u16>("-1"), None);
|
||||
|
||||
let mut u32_val: u32 = 4_294_967_295_u32;
|
||||
assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
|
||||
assert_eq!(from_str::<u32>("4294967296"), None);
|
||||
|
||||
u32_val += 1 as u32;
|
||||
assert_eq!(from_str::<u32>("0"), Some(u32_val));
|
||||
assert_eq!(from_str::<u32>("-1"), None);
|
||||
|
||||
let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
|
||||
assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
|
||||
assert_eq!(from_str::<u64>("18446744073709551616"), None);
|
||||
|
||||
u64_val += 1 as u64;
|
||||
assert_eq!(from_str::<u64>("0"), Some(u64_val));
|
||||
assert_eq!(from_str::<u64>("-1"), None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,68 +48,6 @@ mod tests {
|
|||
assert_eq!(FromStrRadix::from_str_radix("Z", 10).ok(), None::<$T>);
|
||||
assert_eq!(FromStrRadix::from_str_radix("_", 2).ok(), None::<$T>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uint_to_str_overflow() {
|
||||
let mut u8_val: u8 = 255_u8;
|
||||
assert_eq!(u8_val.to_string(), "255");
|
||||
|
||||
u8_val += 1 as u8;
|
||||
assert_eq!(u8_val.to_string(), "0");
|
||||
|
||||
let mut u16_val: u16 = 65_535_u16;
|
||||
assert_eq!(u16_val.to_string(), "65535");
|
||||
|
||||
u16_val += 1 as u16;
|
||||
assert_eq!(u16_val.to_string(), "0");
|
||||
|
||||
let mut u32_val: u32 = 4_294_967_295_u32;
|
||||
assert_eq!(u32_val.to_string(), "4294967295");
|
||||
|
||||
u32_val += 1 as u32;
|
||||
assert_eq!(u32_val.to_string(), "0");
|
||||
|
||||
let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
|
||||
assert_eq!(u64_val.to_string(), "18446744073709551615");
|
||||
|
||||
u64_val += 1 as u64;
|
||||
assert_eq!(u64_val.to_string(), "0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uint_from_str_overflow() {
|
||||
let mut u8_val: u8 = 255_u8;
|
||||
assert_eq!(from_str::<u8>("255"), Some(u8_val));
|
||||
assert_eq!(from_str::<u8>("256"), None);
|
||||
|
||||
u8_val += 1 as u8;
|
||||
assert_eq!(from_str::<u8>("0"), Some(u8_val));
|
||||
assert_eq!(from_str::<u8>("-1"), None);
|
||||
|
||||
let mut u16_val: u16 = 65_535_u16;
|
||||
assert_eq!(from_str::<u16>("65535"), Some(u16_val));
|
||||
assert_eq!(from_str::<u16>("65536"), None);
|
||||
|
||||
u16_val += 1 as u16;
|
||||
assert_eq!(from_str::<u16>("0"), Some(u16_val));
|
||||
assert_eq!(from_str::<u16>("-1"), None);
|
||||
|
||||
let mut u32_val: u32 = 4_294_967_295_u32;
|
||||
assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
|
||||
assert_eq!(from_str::<u32>("4294967296"), None);
|
||||
|
||||
u32_val += 1 as u32;
|
||||
assert_eq!(from_str::<u32>("0"), Some(u32_val));
|
||||
assert_eq!(from_str::<u32>("-1"), None);
|
||||
|
||||
let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
|
||||
assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
|
||||
assert_eq!(from_str::<u64>("18446744073709551616"), None);
|
||||
|
||||
u64_val += 1 as u64;
|
||||
assert_eq!(from_str::<u64>("0"), Some(u64_val));
|
||||
assert_eq!(from_str::<u64>("-1"), None);
|
||||
}
|
||||
}
|
||||
|
||||
) }
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
use self::StdSource::*;
|
||||
|
||||
use boxed;
|
||||
use boxed::Box;
|
||||
use cell::RefCell;
|
||||
use clone::Clone;
|
||||
|
@ -218,7 +219,7 @@ impl Reader for StdinReader {
|
|||
/// See `stdout()` for more notes about this function.
|
||||
pub fn stdin() -> StdinReader {
|
||||
// We're following the same strategy as kimundi's lazy_static library
|
||||
static mut STDIN: *const StdinReader = 0 as *const StdinReader;
|
||||
static mut STDIN: *mut StdinReader = 0 as *mut StdinReader;
|
||||
static ONCE: Once = ONCE_INIT;
|
||||
|
||||
unsafe {
|
||||
|
@ -235,12 +236,12 @@ pub fn stdin() -> StdinReader {
|
|||
let stdin = StdinReader {
|
||||
inner: Arc::new(Mutex::new(RaceBox(stdin)))
|
||||
};
|
||||
STDIN = mem::transmute(box stdin);
|
||||
STDIN = boxed::into_raw(box stdin);
|
||||
|
||||
// Make sure to free it at exit
|
||||
rt::at_exit(|| {
|
||||
mem::transmute::<_, Box<StdinReader>>(STDIN);
|
||||
STDIN = ptr::null();
|
||||
Box::from_raw(STDIN);
|
||||
STDIN = ptr::null_mut();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use boxed;
|
||||
use boxed::Box;
|
||||
use vec::Vec;
|
||||
use mem;
|
||||
use thunk::Thunk;
|
||||
use sys_common::mutex::{Mutex, MUTEX_INIT};
|
||||
|
||||
|
@ -32,7 +32,7 @@ static mut QUEUE: *mut Queue = 0 as *mut Queue;
|
|||
unsafe fn init() {
|
||||
if QUEUE.is_null() {
|
||||
let state: Box<Queue> = box Vec::new();
|
||||
QUEUE = mem::transmute(state);
|
||||
QUEUE = boxed::into_raw(state);
|
||||
} else {
|
||||
// can't re-init after a cleanup
|
||||
rtassert!(QUEUE as uint != 1);
|
||||
|
@ -57,7 +57,7 @@ pub fn cleanup() {
|
|||
|
||||
// If we never called init, not need to cleanup!
|
||||
if queue as uint != 0 {
|
||||
let queue: Box<Queue> = mem::transmute(queue);
|
||||
let queue: Box<Queue> = Box::from_raw(queue);
|
||||
for to_run in *queue {
|
||||
to_run.invoke(());
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
use prelude::v1::*;
|
||||
|
||||
use any::Any;
|
||||
use boxed;
|
||||
use cell::Cell;
|
||||
use cmp;
|
||||
use panicking;
|
||||
|
@ -173,7 +174,8 @@ fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
|
|||
},
|
||||
cause: Some(cause),
|
||||
};
|
||||
let error = uw::_Unwind_RaiseException(mem::transmute(exception));
|
||||
let exception_param = boxed::into_raw(exception) as *mut uw::_Unwind_Exception;
|
||||
let error = uw::_Unwind_RaiseException(exception_param);
|
||||
rtabort!("Could not unwind stack, error = {}", error as int)
|
||||
}
|
||||
|
||||
|
@ -181,7 +183,7 @@ fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
|
|||
exception: *mut uw::_Unwind_Exception) {
|
||||
rtdebug!("exception_cleanup()");
|
||||
unsafe {
|
||||
let _: Box<Exception> = mem::transmute(exception);
|
||||
let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ pub use self::PopResult::*;
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use alloc::boxed;
|
||||
use alloc::boxed::Box;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
|
@ -82,7 +82,7 @@ unsafe impl<T: Send> Sync for Queue<T> { }
|
|||
|
||||
impl<T> Node<T> {
|
||||
unsafe fn new(v: Option<T>) -> *mut Node<T> {
|
||||
mem::transmute(box Node {
|
||||
boxed::into_raw(box Node {
|
||||
next: AtomicPtr::new(ptr::null_mut()),
|
||||
value: v,
|
||||
})
|
||||
|
@ -129,7 +129,7 @@ impl<T: Send> Queue<T> {
|
|||
assert!((*tail).value.is_none());
|
||||
assert!((*next).value.is_some());
|
||||
let ret = (*next).value.take().unwrap();
|
||||
let _: Box<Node<T>> = mem::transmute(tail);
|
||||
let _: Box<Node<T>> = Box::from_raw(tail);
|
||||
return Data(ret);
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ impl<T: Send> Drop for Queue<T> {
|
|||
let mut cur = *self.tail.get();
|
||||
while !cur.is_null() {
|
||||
let next = (*cur).next.load(Ordering::Relaxed);
|
||||
let _: Box<Node<T>> = mem::transmute(cur);
|
||||
let _: Box<Node<T>> = Box::from_raw(cur);
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
|
||||
use core::prelude::*;
|
||||
|
||||
use alloc::boxed;
|
||||
use alloc::boxed::Box;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
|
@ -81,7 +81,7 @@ unsafe impl<T: Send> Sync for Queue<T> { }
|
|||
impl<T: Send> Node<T> {
|
||||
fn new() -> *mut Node<T> {
|
||||
unsafe {
|
||||
mem::transmute(box Node {
|
||||
boxed::into_raw(box Node {
|
||||
value: None,
|
||||
next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
|
||||
})
|
||||
|
@ -200,7 +200,7 @@ impl<T: Send> Queue<T> {
|
|||
.next.store(next, Ordering::Relaxed);
|
||||
// We have successfully erased all references to 'tail', so
|
||||
// now we can safely drop it.
|
||||
let _: Box<Node<T>> = mem::transmute(tail);
|
||||
let _: Box<Node<T>> = Box::from_raw(tail);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
@ -233,7 +233,7 @@ impl<T: Send> Drop for Queue<T> {
|
|||
let mut cur = *self.first.get();
|
||||
while !cur.is_null() {
|
||||
let next = (*cur).next.load(Ordering::Relaxed);
|
||||
let _n: Box<Node<T>> = mem::transmute(cur);
|
||||
let _n: Box<Node<T>> = Box::from_raw(cur);
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
use prelude::v1::*;
|
||||
|
||||
use boxed;
|
||||
use cell::UnsafeCell;
|
||||
use mem;
|
||||
use ptr;
|
||||
use rt;
|
||||
use sync::{StaticMutex, StaticCondvar};
|
||||
|
@ -88,7 +88,7 @@ impl<M: Send> Helper<M> {
|
|||
let _guard = self.lock.lock().unwrap();
|
||||
if !*self.initialized.get() {
|
||||
let (tx, rx) = channel();
|
||||
*self.chan.get() = mem::transmute(box tx);
|
||||
*self.chan.get() = boxed::into_raw(box tx);
|
||||
let (receive, send) = helper_signal::new();
|
||||
*self.signal.get() = send as uint;
|
||||
|
||||
|
@ -132,7 +132,7 @@ impl<M: Send> Helper<M> {
|
|||
let mut guard = self.lock.lock().unwrap();
|
||||
|
||||
// Close the channel by destroying it
|
||||
let chan: Box<Sender<M>> = mem::transmute(*self.chan.get());
|
||||
let chan: Box<Sender<M>> = Box::from_raw(*self.chan.get());
|
||||
*self.chan.get() = ptr::null_mut();
|
||||
drop(chan);
|
||||
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn start_thread(main: *mut libc::c_void) -> thread::rust_thread_return {
|
|||
unsafe {
|
||||
stack::record_os_managed_stack_bounds(0, usize::MAX);
|
||||
let handler = stack_overflow::Handler::new();
|
||||
let f: Box<Thunk> = mem::transmute(main);
|
||||
let f: Box<Thunk> = Box::from_raw(main as *mut Thunk);
|
||||
f.invoke(());
|
||||
drop(handler);
|
||||
mem::transmute(0 as thread::rust_thread_return)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
use core::prelude::*;
|
||||
|
||||
use io;
|
||||
use boxed;
|
||||
use boxed::Box;
|
||||
use cmp;
|
||||
use mem;
|
||||
|
@ -241,13 +242,15 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
|
|||
},
|
||||
};
|
||||
|
||||
let arg: *mut libc::c_void = mem::transmute(box p); // must box since sizeof(p)=2*uint
|
||||
// must box since sizeof(p)=2*uint
|
||||
let raw_p = boxed::into_raw(box p);
|
||||
let arg = raw_p as *mut libc::c_void;
|
||||
let ret = pthread_create(&mut native, &attr, thread_start, arg);
|
||||
assert_eq!(pthread_attr_destroy(&mut attr), 0);
|
||||
|
||||
if ret != 0 {
|
||||
// be sure to not leak the closure
|
||||
let _p: Box<Box<FnOnce()+Send>> = mem::transmute(arg);
|
||||
let _p: Box<Thunk> = Box::from_raw(raw_p);
|
||||
Err(io::Error::from_os_error(ret))
|
||||
} else {
|
||||
Ok(native)
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
use prelude::v1::*;
|
||||
|
||||
use boxed;
|
||||
use cmp;
|
||||
use io;
|
||||
use mem;
|
||||
use ptr;
|
||||
use libc;
|
||||
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
|
||||
|
@ -45,7 +45,8 @@ pub mod guard {
|
|||
}
|
||||
|
||||
pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
|
||||
let arg: *mut libc::c_void = mem::transmute(box p);
|
||||
let raw_p = boxed::into_raw(box p);
|
||||
let arg = raw_p as *mut libc::c_void;
|
||||
// FIXME On UNIX, we guard against stack sizes that are too small but
|
||||
// that's because pthreads enforces that stacks are at least
|
||||
// PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
|
||||
|
@ -61,7 +62,7 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
|
|||
|
||||
if ret as uint == 0 {
|
||||
// be sure to not leak the closure
|
||||
let _p: Box<Thunk> = mem::transmute(arg);
|
||||
let _p: Box<Thunk> = Box::from_raw(raw_p);
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
|
|
|
@ -12,7 +12,7 @@ use prelude::v1::*;
|
|||
|
||||
use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
|
||||
|
||||
use mem;
|
||||
use boxed;
|
||||
use ptr;
|
||||
use rt;
|
||||
use sys_common::mutex::{MUTEX_INIT, Mutex};
|
||||
|
@ -133,13 +133,13 @@ unsafe fn init_dtors() {
|
|||
if !DTORS.is_null() { return }
|
||||
|
||||
let dtors = box Vec::<(Key, Dtor)>::new();
|
||||
DTORS = mem::transmute(dtors);
|
||||
DTORS = boxed::into_raw(dtors);
|
||||
|
||||
rt::at_exit(move|| {
|
||||
DTOR_LOCK.lock();
|
||||
let dtors = DTORS;
|
||||
DTORS = ptr::null_mut();
|
||||
mem::transmute::<_, Box<Vec<(Key, Dtor)>>>(dtors);
|
||||
Box::from_raw(dtors);
|
||||
assert!(DTORS.is_null()); // can't re-init after destructing
|
||||
DTOR_LOCK.unlock();
|
||||
});
|
||||
|
|
|
@ -388,6 +388,7 @@ mod imp {
|
|||
// Due to rust-lang/rust#18804, make sure this is not generic!
|
||||
#[cfg(target_os = "linux")]
|
||||
unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
|
||||
use boxed;
|
||||
use mem;
|
||||
use libc;
|
||||
use sys_common::thread_local as os;
|
||||
|
@ -422,14 +423,14 @@ mod imp {
|
|||
type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
|
||||
if DTORS.get().is_null() {
|
||||
let v: Box<List> = box Vec::new();
|
||||
DTORS.set(mem::transmute(v));
|
||||
DTORS.set(boxed::into_raw(v) as *mut u8);
|
||||
}
|
||||
let list: &mut List = &mut *(DTORS.get() as *mut List);
|
||||
list.push((t, dtor));
|
||||
|
||||
unsafe extern fn run_dtors(mut ptr: *mut u8) {
|
||||
while !ptr.is_null() {
|
||||
let list: Box<List> = mem::transmute(ptr);
|
||||
let list: Box<List> = Box::from_raw(ptr as *mut List);
|
||||
for &(ptr, dtor) in &*list {
|
||||
dtor(ptr);
|
||||
}
|
||||
|
@ -467,6 +468,7 @@ mod imp {
|
|||
mod imp {
|
||||
use prelude::v1::*;
|
||||
|
||||
use alloc::boxed;
|
||||
use cell::UnsafeCell;
|
||||
use mem;
|
||||
use ptr;
|
||||
|
@ -517,7 +519,7 @@ mod imp {
|
|||
key: self,
|
||||
value: mem::transmute_copy(&self.inner),
|
||||
};
|
||||
let ptr: *mut Value<T> = mem::transmute(ptr);
|
||||
let ptr: *mut Value<T> = boxed::into_raw(ptr);
|
||||
self.os.set(ptr as *mut u8);
|
||||
Some(&mut (*ptr).value as *mut T)
|
||||
}
|
||||
|
@ -533,7 +535,7 @@ mod imp {
|
|||
//
|
||||
// Note that to prevent an infinite loop we reset it back to null right
|
||||
// before we return from the destructor ourselves.
|
||||
let ptr: Box<Value<T>> = mem::transmute(ptr);
|
||||
let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
|
||||
let key = ptr.key;
|
||||
key.os.set(1 as *mut u8);
|
||||
drop(ptr);
|
||||
|
|
|
@ -292,7 +292,7 @@ pub enum InlineAttr {
|
|||
}
|
||||
|
||||
/// Determine what `#[inline]` attribute is present in `attrs`, if any.
|
||||
pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr {
|
||||
pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
|
||||
// FIXME (#2809)---validate the usage of #[inline] and #[inline]
|
||||
attrs.iter().fold(InlineNone, |ia,attr| {
|
||||
match attr.node.value.node {
|
||||
|
@ -302,12 +302,16 @@ pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr {
|
|||
}
|
||||
MetaList(ref n, ref items) if *n == "inline" => {
|
||||
mark_used(attr);
|
||||
if contains_name(&items[..], "always") {
|
||||
if items.len() != 1 {
|
||||
diagnostic.map(|d|{ d.span_err(attr.span, "expected one argument"); });
|
||||
InlineNone
|
||||
} else if contains_name(&items[..], "always") {
|
||||
InlineAlways
|
||||
} else if contains_name(&items[..], "never") {
|
||||
InlineNever
|
||||
} else {
|
||||
InlineHint
|
||||
diagnostic.map(|d|{ d.span_err((*items[0]).span, "invalid argument"); });
|
||||
InlineNone
|
||||
}
|
||||
}
|
||||
_ => ia
|
||||
|
@ -317,7 +321,7 @@ pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr {
|
|||
|
||||
/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
|
||||
pub fn requests_inline(attrs: &[Attribute]) -> bool {
|
||||
match find_inline_attr(attrs) {
|
||||
match find_inline_attr(None, attrs) {
|
||||
InlineHint | InlineAlways => true,
|
||||
InlineNone | InlineNever => false,
|
||||
}
|
||||
|
|
|
@ -3494,6 +3494,9 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
pat = PatIdent(BindByValue(MutImmutable), pth1, sub);
|
||||
}
|
||||
} else if self.look_ahead(1, |t| *t == token::Lt) {
|
||||
self.bump();
|
||||
self.unexpected()
|
||||
} else {
|
||||
// parse an enum pat
|
||||
let enum_path = self.parse_path(LifetimeAndTypesWithColons);
|
||||
|
|
|
@ -50,14 +50,14 @@ impl<'a> Iterator for BookItems<'a> {
|
|||
|
||||
let mut section = "".to_string();
|
||||
for &(_, idx) in &self.stack {
|
||||
section.push_str(&(idx + 1).to_string()[]);
|
||||
section.push_str(&(idx + 1).to_string()[..]);
|
||||
section.push('.');
|
||||
}
|
||||
section.push_str(&(self.cur_idx + 1).to_string()[]);
|
||||
section.push_str(&(self.cur_idx + 1).to_string()[..]);
|
||||
section.push('.');
|
||||
|
||||
self.stack.push((self.cur_items, self.cur_idx));
|
||||
self.cur_items = &cur.children[];
|
||||
self.cur_items = &cur.children[..];
|
||||
self.cur_idx = 0;
|
||||
return Some((section, cur))
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ impl<'a> Iterator for BookItems<'a> {
|
|||
impl Book {
|
||||
pub fn iter(&self) -> BookItems {
|
||||
BookItems {
|
||||
cur_items: &self.chapters[],
|
||||
cur_items: &self.chapters[..],
|
||||
cur_idx: 0,
|
||||
stack: Vec::new(),
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
//! Implementation of the `build` subcommand, used to compile a book.
|
||||
|
||||
use std::os;
|
||||
use std::env;
|
||||
use std::old_io;
|
||||
use std::old_io::{fs, File, BufferedWriter, TempDir, IoResult};
|
||||
|
@ -41,7 +40,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()>
|
|||
path_to_root: &Path,
|
||||
out: &mut Writer) -> IoResult<()> {
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
try!(walk_item(item, &format!("{}{}.", section, i + 1)[], path_to_root, out));
|
||||
try!(walk_item(item, &format!("{}{}.", section, i + 1)[..], path_to_root, out));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -55,7 +54,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()>
|
|||
item.title));
|
||||
if !item.children.is_empty() {
|
||||
try!(writeln!(out, "<ul class='section'>"));
|
||||
let _ = walk_items(&item.children[], section, path_to_root, out);
|
||||
let _ = walk_items(&item.children[..], section, path_to_root, out);
|
||||
try!(writeln!(out, "</ul>"));
|
||||
}
|
||||
try!(writeln!(out, "</li>"));
|
||||
|
@ -65,7 +64,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()>
|
|||
|
||||
try!(writeln!(out, "<div id='toc' class='mobile-hidden'>"));
|
||||
try!(writeln!(out, "<ul class='chapter'>"));
|
||||
try!(walk_items(&book.chapters[], "", path_to_root, out));
|
||||
try!(walk_items(&book.chapters[..], "", path_to_root, out));
|
||||
try!(writeln!(out, "</ul>"));
|
||||
try!(writeln!(out, "</div>"));
|
||||
|
||||
|
@ -82,7 +81,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
|||
|
||||
let src;
|
||||
if env::args().len() < 3 {
|
||||
src = os::getcwd().unwrap().clone();
|
||||
src = env::current_dir().unwrap().clone();
|
||||
} else {
|
||||
src = Path::new(env::args().nth(2).unwrap().clone());
|
||||
}
|
||||
|
@ -150,7 +149,7 @@ impl Subcommand for Build {
|
|||
}
|
||||
fn usage(&self) {}
|
||||
fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
|
||||
let cwd = os::getcwd().unwrap();
|
||||
let cwd = env::current_dir().unwrap();
|
||||
let src;
|
||||
let tgt;
|
||||
|
||||
|
@ -179,7 +178,7 @@ impl Subcommand for Build {
|
|||
Err(errors) => {
|
||||
let n = errors.len();
|
||||
for err in errors {
|
||||
term.err(&format!("error: {}", err)[]);
|
||||
term.err(&format!("error: {}", err)[..]);
|
||||
}
|
||||
|
||||
Err(box format!("{} errors occurred", n) as Box<Error>)
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#![feature(collections)]
|
||||
#![feature(core)]
|
||||
#![feature(old_io)]
|
||||
#![feature(os)]
|
||||
#![feature(env)]
|
||||
#![feature(old_path)]
|
||||
#![feature(rustdoc)]
|
||||
|
@ -54,16 +53,16 @@ fn main() {
|
|||
if cmd.len() <= 1 {
|
||||
help::usage()
|
||||
} else {
|
||||
match subcommand::parse_name(&cmd[1][]) {
|
||||
match subcommand::parse_name(&cmd[1][..]) {
|
||||
Some(mut subcmd) => {
|
||||
match subcmd.parse_args(cmd.tail()) {
|
||||
Ok(_) => {
|
||||
match subcmd.execute(&mut term) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
term.err(&format!("error: {}", err.description())[]);
|
||||
term.err(&format!("error: {}", err.description())[..]);
|
||||
err.detail().map(|detail| {
|
||||
term.err(&format!("detail: {}", detail)[]);
|
||||
term.err(&format!("detail: {}", detail)[..]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use error::Error;
|
|||
use term::Term;
|
||||
use book;
|
||||
use std::old_io::{Command, File};
|
||||
use std::os;
|
||||
use std::env;
|
||||
|
||||
struct Test;
|
||||
|
||||
|
@ -35,7 +35,7 @@ impl Subcommand for Test {
|
|||
}
|
||||
fn usage(&self) {}
|
||||
fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
|
||||
let cwd = os::getcwd().unwrap();
|
||||
let cwd = env::current_dir().unwrap();
|
||||
let src = cwd.clone();
|
||||
|
||||
let summary = File::open(&src.join("SUMMARY.md"));
|
||||
|
@ -50,8 +50,8 @@ impl Subcommand for Test {
|
|||
Ok(output) => {
|
||||
if !output.status.success() {
|
||||
term.err(&format!("{}\n{}",
|
||||
String::from_utf8_lossy(&output.output[]),
|
||||
String::from_utf8_lossy(&output.error[]))[]);
|
||||
String::from_utf8_lossy(&output.output[..]),
|
||||
String::from_utf8_lossy(&output.error[..]))[..]);
|
||||
return Err(box "Some tests failed." as Box<Error>);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// Test that attempt to reborrow an `&mut` pointer in an aliasable
|
||||
// location yields an error.
|
||||
//
|
||||
// Example from src/middle/borrowck/doc.rs
|
||||
// Example from src/librustc_borrowck/borrowck/README.md
|
||||
|
||||
fn foo(t0: & &mut isize) {
|
||||
let t1 = t0;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// Test that attempt to move `&mut` pointer while pointee is borrowed
|
||||
// yields an error.
|
||||
//
|
||||
// Example from src/middle/borrowck/doc.rs
|
||||
// Example from src/librustc_borrowck/borrowck/README.md
|
||||
|
||||
fn foo(t0: &mut isize) {
|
||||
let p: &isize = &*t0; // Freezes `*t0`
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// Test that attempt to mutably borrow `&mut` pointer while pointee is
|
||||
// borrowed yields an error.
|
||||
//
|
||||
// Example from src/middle/borrowck/doc.rs
|
||||
// Example from src/librustc_borrowck/borrowck/README.md
|
||||
|
||||
fn foo<'a>(mut t0: &'a mut isize,
|
||||
mut t1: &'a mut isize) {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// Test that attempt to swap `&mut` pointer while pointee is borrowed
|
||||
// yields an error.
|
||||
//
|
||||
// Example from src/middle/borrowck/doc.rs
|
||||
// Example from src/librustc_borrowck/borrowck/README.md
|
||||
|
||||
use std::mem::swap;
|
||||
|
||||
|
|
24
src/test/compile-fail/invalid-inline.rs
Normal file
24
src/test/compile-fail/invalid-inline.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[inline(please_no)] //~ ERROR invalid argument
|
||||
fn a() {
|
||||
}
|
||||
|
||||
#[inline(please,no)] //~ ERROR expected one argument
|
||||
fn b() {
|
||||
}
|
||||
|
||||
#[inline()] //~ ERROR expected one argument
|
||||
fn c() {
|
||||
}
|
||||
|
||||
fn main() {}
|
17
src/test/compile-fail/issue-22426-1.rs
Normal file
17
src/test/compile-fail/issue-22426-1.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
match 42 {
|
||||
x < 7 => (),
|
||||
//~^ error: unexpected token: `<`
|
||||
_ => ()
|
||||
}
|
||||
}
|
12
src/test/compile-fail/issue-22426-2.rs
Normal file
12
src/test/compile-fail/issue-22426-2.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// 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 a(B<) {}
|
||||
//~^ error: unexpected token: `<`
|
22
src/test/compile-fail/issue-22426-3.rs
Normal file
22
src/test/compile-fail/issue-22426-3.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct Foo<T>(T, T);
|
||||
|
||||
impl<T> Foo<T> {
|
||||
fn foo(&self) {
|
||||
match *self {
|
||||
Foo<T>(x, y) => {
|
||||
//~^ error: unexpected token: `<`
|
||||
println!("Goodbye, World!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
src/test/compile-fail/retslot-cast.rs
Normal file
25
src/test/compile-fail/retslot-cast.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
// 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(rustc_attrs)]
|
||||
#![allow(warnings)]
|
||||
|
||||
pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
|
||||
// This call used to trigger an LLVM assertion because the return slot had type
|
||||
// "Option<&Iterator>"* instead of "Option<&(Iterator+Send)>"*
|
||||
inner(x)
|
||||
}
|
||||
|
||||
pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
|
||||
x
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
|
@ -10,3 +10,6 @@ all:
|
|||
cp foo.rs $(TMPDIR)/+foo+bar
|
||||
$(RUSTC) $(TMPDIR)/+foo+bar 2>&1 \
|
||||
| grep "invalid character.*in crate name:"
|
||||
cp foo.rs $(TMPDIR)/-foo.rs
|
||||
$(RUSTC) $(TMPDIR)/-foo.rs 2>&1 \
|
||||
| grep "crate name cannot start with a hyphen:"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// Test that freezing an `&mut` pointer while referent is
|
||||
// frozen is legal.
|
||||
//
|
||||
// Example from src/middle/borrowck/doc.rs
|
||||
// Example from src/librustc_borrowck/borrowck/README.md
|
||||
|
||||
fn foo<'a>(mut t0: &'a mut int,
|
||||
mut t1: &'a mut int) {
|
||||
|
|
38
src/test/run-pass/extern-methods.rs
Normal file
38
src/test/run-pass/extern-methods.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// 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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
trait A : MarkerTrait {
|
||||
extern "fastcall" fn test1(i: i32);
|
||||
extern fn test2(i: i32);
|
||||
}
|
||||
|
||||
struct S;
|
||||
impl S {
|
||||
extern "stdcall" fn test3(i: i32) {
|
||||
assert_eq!(i, 3);
|
||||
}
|
||||
}
|
||||
|
||||
impl A for S {
|
||||
extern "fastcall" fn test1(i: i32) {
|
||||
assert_eq!(i, 1);
|
||||
}
|
||||
extern fn test2(i: i32) {
|
||||
assert_eq!(i, 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
<S as A>::test1(1);
|
||||
<S as A>::test2(2);
|
||||
S::test3(3);
|
||||
}
|
16
src/test/run-pass/issue-22426.rs
Normal file
16
src/test/run-pass/issue-22426.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
match 42 {
|
||||
x if x < 7 => (),
|
||||
_ => ()
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
// aux-build:lang-item-public.rs
|
||||
// ignore-android
|
||||
// ignore-windows #13361
|
||||
|
||||
#![feature(lang_items, start, no_std)]
|
||||
#![no_std]
|
||||
|
|
|
@ -37,7 +37,8 @@ fn f(tx: Sender<bool>) {
|
|||
|
||||
pub fn main() {
|
||||
let (tx, rx) = channel();
|
||||
let _t = thread::spawn(move|| f(tx.clone()));
|
||||
let t = thread::spawn(move|| f(tx.clone()));
|
||||
println!("hiiiiiiiii");
|
||||
assert!(rx.recv().unwrap());
|
||||
drop(t.join());
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@ fn f() {
|
|||
}
|
||||
|
||||
pub fn main() {
|
||||
let _t = thread::spawn(f);
|
||||
let t = thread::spawn(f);
|
||||
drop(t.join());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue