1
Fork 0

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:
bors 2015-02-23 20:47:30 +00:00
commit 91a5a1ab4a
81 changed files with 1378 additions and 855 deletions

View file

@ -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

View file

@ -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,
}
}

View file

@ -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,

View file

@ -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");

View file

@ -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();
}
```

View file

@ -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

View file

@ -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

View file

@ -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];

View file

@ -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);
}
```

View file

@ -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 arent perfect and may “optimize” code to become slower.
For example, functions inlined too eagerly will bloat the instruction cache

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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]

View file

@ -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();

View file

@ -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
View 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[..] }
}
}
}

View file

@ -72,6 +72,9 @@
#[macro_use]
mod macros;
#[macro_use]
mod cmp_macros;
#[path = "num/float_macros.rs"]
#[macro_use]
mod float_macros;

View file

@ -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 _;
}
});
}

View file

@ -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 }

View file

@ -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 {

View file

@ -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:

View file

@ -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::*;

View file

@ -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

View file

@ -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.
//

View file

@ -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;

View file

@ -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>,

View file

@ -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 => {

View file

@ -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.

View file

@ -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::*;

View file

@ -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

View file

@ -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 => {

View file

@ -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,

View file

@ -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,

View file

@ -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, _) => {

View file

@ -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>,

View file

@ -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);
}
}

View file

@ -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

View file

@ -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};

View file

@ -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.

View file

@ -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:

View file

@ -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 {}

View file

@ -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));
}
}

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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);
}
}
) }

View file

@ -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();
});
});

View file

@ -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(());
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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();
});

View file

@ -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);

View file

@ -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,
}

View file

@ -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);

View file

@ -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(),
}

View file

@ -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>)

View file

@ -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)[..]);
});
}
}

View file

@ -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>);
}

View file

@ -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;

View file

@ -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`

View file

@ -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) {

View file

@ -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;

View 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() {}

View 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: `<`
_ => ()
}
}

View 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: `<`

View 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!")
}
}
}
}

View 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

View file

@ -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:"

View file

@ -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) {

View 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);
}

View 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 => (),
_ => ()
}
}

View file

@ -10,7 +10,6 @@
// aux-build:lang-item-public.rs
// ignore-android
// ignore-windows #13361
#![feature(lang_items, start, no_std)]
#![no_std]

View file

@ -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());
}

View file

@ -19,5 +19,6 @@ fn f() {
}
pub fn main() {
let _t = thread::spawn(f);
let t = thread::spawn(f);
drop(t.join());
}