auto merge of #19665 : alexcrichton/rust/rollup, r=alexcrichton

This commit is contained in:
bors 2014-12-09 19:12:02 +00:00
commit b25e100173
53 changed files with 791 additions and 307 deletions

View File

@ -123,7 +123,8 @@ PKG_EXE = dist/$(PKG_NAME)-$(CFG_BUILD).exe
$(PKG_EXE): rust.iss modpath.iss upgrade.iss LICENSE.txt rust-logo.ico \
$(CSREQ3_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \
dist-prepare-win
$(CFG_PYTHON) $(S)src/etc/make-win-dist.py tmp/dist/win $(CFG_BUILD)
$(Q)rm -rf tmp/dist/win/gcc
$(CFG_PYTHON) $(S)src/etc/make-win-dist.py tmp/dist/win/rust tmp/dist/win/gcc $(CFG_BUILD)
@$(call E, ISCC: $@)
$(Q)$(CFG_ISCC) $<
@ -131,7 +132,7 @@ $(eval $(call DEF_PREPARE,win))
dist-prepare-win: PREPARE_HOST=$(CFG_BUILD)
dist-prepare-win: PREPARE_TARGETS=$(CFG_BUILD)
dist-prepare-win: PREPARE_DEST_DIR=tmp/dist/win
dist-prepare-win: PREPARE_DEST_DIR=tmp/dist/win/rust
dist-prepare-win: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
dist-prepare-win: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
dist-prepare-win: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)

View File

@ -32,7 +32,7 @@ two languages for those phrases to be in. We'll use this module layout:
+---------+ | +-----------+
| +---| farewells |
+---------+ | +-----------+
| phrases |---+
| phrases |---+
+---------+ | +-----------+
| +---| greetings |
+----------+ | +-----------+
@ -219,7 +219,7 @@ Put this in `src/english/greetings.rs`:
fn hello() -> String {
"Hello!".to_string()
}
}
```
Put this in `src/english/farewells.rs`:
@ -229,7 +229,7 @@ Put this in `src/english/farewells.rs`:
fn goodbye() -> String {
"Goodbye.".to_string()
}
}
```
Put this in `src/japanese/greetings.rs`:
@ -239,7 +239,7 @@ Put this in `src/japanese/greetings.rs`:
fn hello() -> String {
"こんにちは".to_string()
}
}
```
Of course, you can copy and paste this from this web page, or just type
@ -253,7 +253,7 @@ Put this in `src/japanese/farewells.rs`:
fn goodbye() -> String {
"さようなら".to_string()
}
}
```
(This is "Sayoonara", if you're curious.)
@ -381,11 +381,11 @@ $ cargo run
/home/you/projects/phrases/src/japanese/greetings.rs:1:1: 3:2 warning: code is never used: `hello`, #[warn(dead_code)] on by default
/home/you/projects/phrases/src/japanese/greetings.rs:1 fn hello() -> String {
/home/you/projects/phrases/src/japanese/greetings.rs:2 "こんにちは".to_string()
/home/you/projects/phrases/src/japanese/greetings.rs:3 }
/home/you/projects/phrases/src/japanese/greetings.rs:3 }
/home/you/projects/phrases/src/japanese/farewells.rs:1:1: 3:2 warning: code is never used: `goodbye`, #[warn(dead_code)] on by default
/home/you/projects/phrases/src/japanese/farewells.rs:1 fn goodbye() -> String {
/home/you/projects/phrases/src/japanese/farewells.rs:2 "さようなら".to_string()
/home/you/projects/phrases/src/japanese/farewells.rs:3 }
/home/you/projects/phrases/src/japanese/farewells.rs:3 }
Running `target/phrases`
Hello in English: Hello!
Goodbye in English: Goodbye.
@ -452,7 +452,7 @@ fn main() {
Rust will give us a compile-time error:
```{notrust,ignore}
```{notrust}
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
/home/you/projects/phrases/src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module
/home/you/projects/phrases/src/main.rs:4 use phrases::japanese::greetings::hello;

View File

@ -2,7 +2,7 @@
> The best-laid plans of mice and men
> Often go awry
>
>
> "Tae a Moose", Robert Burns
Sometimes, things just go wrong. It's important to have a plan for when the
@ -76,7 +76,7 @@ fn main() {
This will give us an error:
```{notrust,ignore}
```{notrust}
error: non-exhaustive patterns: `_` not covered [E0004]
```
@ -189,7 +189,7 @@ panic!("boom");
gives
```{notrust,ignore}
```{notrust}
task '<main>' panicked at 'boom', hello.rs:2
```

View File

@ -93,7 +93,7 @@ must have a deallocation for each allocation. Rust handles this for you. It
knows that our handle, `x`, is the owning reference to our box. Rust knows that
`x` will go out of scope at the end of the block, and so it inserts a call to
deallocate the memory at the end of the scope. Because the compiler does this
for us, it's impossible to forget. We always exaclty one deallocations paired
for us, it's impossible to forget. We always have exactly one deallocation paired
with each of our allocations.
This is pretty straightforward, but what happens when we want to pass our box
@ -130,7 +130,7 @@ fn add_one(mut num: Box<int>) {
This does not compile, and gives us an error:
```{notrust,ignore}
```{notrust}
error: use of moved value: `x`
println!("{}", x);
^
@ -186,11 +186,11 @@ This function takes ownership, because it takes a `Box`, which owns its
contents. But then we give ownership right back.
In the physical world, you can give one of your possessions to someone for a
short period of time. You still own your posession, you're just letting someone
short period of time. You still own your possession, you're just letting someone
else use it for a while. We call that 'lending' something to someone, and that
person is said to be 'borrowing' that something from you.
Rust's ownershp system also allows an owner to lend out a handle for a limited
Rust's ownership system also allows an owner to lend out a handle for a limited
period. This is also called 'borrowing.' Here's a version of `add_one` which
borrows its argument rather than taking ownership:
@ -231,7 +231,7 @@ fn add_one(num: &int) -> int {
Rust has a feature called 'lifetime elision,' which allows you to not write
lifetime annotations in certain circumstances. This is one of them. Without
eliding the liftimes, `add_one` looks like this:
eliding the lifetimes, `add_one` looks like this:
```rust
fn add_one<'a>(num: &'a int) -> int {
@ -254,7 +254,7 @@ This part _declares_ our lifetimes. This says that `add_one` has one lifetime,
fn add_two<'a, 'b>(...)
```
Then in our parameter list, we use the liftimes we've named:
Then in our parameter list, we use the lifetimes we've named:
```{rust,ignore}
...(num: &'a int) -> ...
@ -279,7 +279,7 @@ fn main() {
}
```
As you can see, `struct`s can also have liftimes. In a similar way to functions,
As you can see, `struct`s can also have lifetimes. In a similar way to functions,
```{rust}
struct Foo<'a> {
@ -295,7 +295,7 @@ x: &'a int,
# }
```
uses it. So why do we need a liftime here? We need to ensure that any reference
uses it. So why do we need a lifetime here? We need to ensure that any reference
to a `Foo` cannot outlive the reference to an `int` it contains.
## Thinking in scopes
@ -406,7 +406,7 @@ fn main() {
We try to make four `Wheel`s, each with a `Car` that it's attached to. But the
compiler knows that on the second iteration of the loop, there's a problem:
```{notrust,ignore}
```{notrust}
error: use of moved value: `car`
Wheel { size: 360, owner: car };
^~~

View File

@ -84,7 +84,7 @@ println!("{}", x + z);
This gives us an error:
```{notrust,ignore}
```{notrust}
hello.rs:6:24: 6:25 error: mismatched types: expected `int` but found `&int` (expected int but found &-ptr)
hello.rs:6 println!("{}", x + z);
^
@ -132,7 +132,7 @@ Pointers are useful in languages that are pass-by-value, rather than
pass-by-reference. Basically, languages can make two choices (this is made
up syntax, it's not Rust):
```{notrust,ignore}
```{ignore}
func foo(x) {
x = 5
}
@ -152,7 +152,7 @@ and therefore, can change its value. At the comment, `i` will be `5`.
So what do pointers have to do with this? Well, since pointers point to a
location in memory...
```{notrust,ignore}
```{ignore}
func foo(&int x) {
*x = 5
}
@ -179,7 +179,7 @@ but here are problems with pointers in other languages:
Uninitialized pointers can cause a problem. For example, what does this program
do?
```{notrust,ignore}
```{ignore}
&int x;
*x = 5; // whoops!
```
@ -191,7 +191,7 @@ knows. This might be harmless, and it might be catastrophic.
When you combine pointers and functions, it's easy to accidentally invalidate
the memory the pointer is pointing to. For example:
```{notrust,ignore}
```{ignore}
func make_pointer(): &int {
x = 5;
@ -213,7 +213,7 @@ As one last example of a big problem with pointers, **aliasing** can be an
issue. Two pointers are said to alias when they point at the same location
in memory. Like this:
```{notrust,ignore}
```{ignore}
func mutate(&int i, int j) {
*i = j;
}
@ -398,7 +398,7 @@ fn main() {
It gives this error:
```{notrust,ignore}
```{notrust}
test.rs:5:8: 5:10 error: cannot assign to `*x` because it is borrowed
test.rs:5 *x -= 1;
^~
@ -522,7 +522,7 @@ boxes, though. As a rough approximation, you can treat this Rust code:
As being similar to this C code:
```{notrust,ignore}
```{ignore}
{
int *x;
x = (int *)malloc(sizeof(int));
@ -626,7 +626,7 @@ fn main() {
This prints:
```{notrust,ignore}
```{ignore}
Cons(1, box Cons(2, box Cons(3, box Nil)))
```

View File

@ -181,7 +181,7 @@ for l in s.graphemes(true) {
This prints:
```{notrust,ignore}
```{text}
n͈̰̎
i̙̮͚̦
@ -207,7 +207,7 @@ for l in s.chars() {
This prints:
```{notrust,ignore}
```{text}
u
͔
n
@ -252,7 +252,7 @@ for l in s.bytes() {
This will print:
```{notrust,ignore}
```{text}
117
205
148

View File

@ -355,7 +355,7 @@ just `cargo build` and it'll work the right way.
You'll also notice that Cargo has created a new file: `Cargo.lock`.
```{ignore,notrust}
```{ignore}
[root]
name = "hello_world"
version = "0.0.1"
@ -426,7 +426,7 @@ x = 10i;
It will give you this error:
```{ignore,notrust}
```{notrust}
error: re-assignment of immutable variable `x`
x = 10i;
^~~~~~~
@ -486,7 +486,7 @@ fn main() {
You can use `cargo build` on the command line to build it. You'll get a warning,
but it will still print "Hello, world!":
```{ignore,notrust}
```{notrust}
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default
src/main.rs:2 let x: int;
@ -664,7 +664,7 @@ let y: int = if x == 5i { 10i; } else { 15i; };
Note the semicolons after the 10 and 15. Rust will give us the following error:
```{ignore,notrust}
```{notrust}
error: mismatched types: expected `int` but found `()` (expected int but found ())
```
@ -747,7 +747,7 @@ fn print_number(x, y) {
You get this error:
```{ignore,notrust}
```{notrust}
hello.rs:5:18: 5:19 error: expected `:` but found `,`
hello.rs:5 fn print_number(x, y) {
```
@ -779,7 +779,7 @@ fn add_one(x: int) -> int {
We would get an error:
```{ignore,notrust}
```{ignore}
error: not all control paths return a value
fn add_one(x: int) -> int {
x + 1;
@ -1160,6 +1160,55 @@ Where a `StringResult` is either an `StringOK`, with the result of a computation
`ErrorReason` with a `String` explaining what caused the computation to fail. These kinds of
`enum`s are actually very useful and are even part of the standard library.
Enum variants are namespaced under the enum names. For example, here is an example of using
our `StringResult`:
```rust
# enum StringResult {
# StringOK(String),
# ErrorReason(String),
# }
fn respond(greeting: &str) -> StringResult {
if greeting == "Hello" {
StringResult::StringOK("Good morning!".to_string())
} else {
StringResult::ErrorReason("I didn't understand you!".to_string())
}
}
```
Notice that we need both the enum name and the variant name: `StringResult::StringOK`, but
we didn't need to with `Ordering`, we just said `Greater` rather than `Ordering::Greater`.
There's a reason: the Rust prelude imports the variants of `Ordering` as well as the enum
itself. We can use the `use` keyword to do something similar with `StringResult`:
```rust
use StringResult::StringOK;
use StringResult::ErrorReason;
enum StringResult {
StringOK(String),
ErrorReason(String),
}
# fn main() {}
fn respond(greeting: &str) -> StringResult {
if greeting == "Hello" {
StringOK("Good morning!".to_string())
} else {
ErrorReason("I didn't understand you!".to_string())
}
}
```
We'll learn more about `use` later, but it's used to bring names into scope. `use` declarations
must come before anything else, which looks a little strange in this example, since we `use`
the variants before we define them. Anyway, in the body of `respond`, we can just say `StringOK`
now, rather than the full `StringResult::StringOK`. Importing variants can be convenient, but can
also cause name conflicts, so do this with caution. It's considered good style to rarely import
variants for this reason.
As you can see `enum`s with values are quite a powerful tool for data representation,
and can be even more useful when they're generic across types. But before we get to
generics, let's talk about how to use them with pattern matching, a tool that will
@ -1197,7 +1246,7 @@ So what's the big advantage here? Well, there are a few. First of all, `match`
enforces 'exhaustiveness checking.' Do you see that last arm, the one with the
underscore (`_`)? If we remove that arm, Rust will give us an error:
```{ignore,notrust}
```{notrust}
error: non-exhaustive patterns: `_` not covered
```
@ -1344,7 +1393,7 @@ for x in range(0i, 10i) {
In slightly more abstract terms,
```{ignore,notrust}
```{ignore}
for var in expression {
code
}
@ -1849,7 +1898,7 @@ Before we move on, let me show you one more Cargo command: `run`. `cargo run`
is kind of like `cargo build`, but it also then runs the produced executable.
Try it out:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
@ -1947,7 +1996,7 @@ for this example, it is not important.
Let's try to compile this using `cargo build`:
```{notrust,no_run}
```{notrust}
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:7:26: 7:34 error: the type of this value must be known in this context
@ -1995,7 +2044,7 @@ fn main() {
Try running our new program a few times:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
@ -2048,7 +2097,7 @@ fn main() {
And trying it out:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
@ -2103,7 +2152,7 @@ fn cmp(a: int, b: int) -> Ordering {
If we try to compile, we'll get some errors:
```{notrust,ignore}
```{notrust}
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:20:15: 20:20 error: mismatched types: expected `int` but found `collections::string::String` (expected int but found struct collections::string::String)
@ -2157,7 +2206,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
And try compiling again:
```{notrust,ignore}
```{notrust}
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
@ -2170,7 +2219,7 @@ This error is similar to the last one: we expected to get a `uint`, but we got
a `String` instead! That's because our `input` variable is coming from the
standard input, and you can guess anything. Try it:
```{notrust,ignore}
```{notrust}
$ ./target/guessing_game
Guess the number!
The secret number is: 73
@ -2254,7 +2303,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
Let's try it out!
```{notrust,ignore}
```{notrust}
$ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
@ -2313,7 +2362,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
We use a `match` to either give us the `uint` inside of the `Option`, or we
print an error message and return. Let's give this a shot:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
@ -2378,7 +2427,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
Let's try it!
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
@ -2455,7 +2504,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
And try it out. But wait, didn't we just add an infinite loop? Yup. Remember
that `return`? If we give a non-number answer, we'll `return` and quit. Observe:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
@ -2587,7 +2636,7 @@ fn cmp(a: uint, b: uint) -> Ordering {
Now we should be good! Let's try:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
@ -2703,7 +2752,7 @@ $ cd modules
Let's double check our work by compiling:
```{bash,notrust}
```{bash}
$ cargo run
Compiling modules v0.0.1 (file:///home/you/projects/modules)
Running `target/modules`
@ -2765,7 +2814,7 @@ mod hello {
It gives an error:
```{notrust,ignore}
```{notrust}
Compiling modules v0.0.1 (file:///home/you/projects/modules)
src/main.rs:2:5: 2:23 error: function `print_hello` is private
src/main.rs:2 hello::print_hello();
@ -2789,7 +2838,7 @@ mod hello {
Usage of the `pub` keyword is sometimes called 'exporting', because
we're making the function available for other modules. This will work:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling modules v0.0.1 (file:///home/you/projects/modules)
Running `target/modules`
@ -2923,7 +2972,7 @@ $ cd testing
And try it out:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling testing v0.0.1 (file:///home/you/projects/testing)
Running `target/testing`
@ -2955,7 +3004,7 @@ you give them descriptive names. You'll see why in a moment. We then use a
macro, `assert!`, to assert that something is true. In this case, we're giving
it `false`, so this test should fail. Let's try it!
```{notrust,ignore}
```{notrust}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
@ -2984,7 +3033,7 @@ task '<main>' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.
Lots of output! Let's break this down:
```{notrust,ignore}
```{ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
```
@ -2992,7 +3041,7 @@ $ cargo test
You can run all of your tests with `cargo test`. This runs both your tests in
`tests`, as well as the tests you put inside of your crate.
```{notrust,ignore}
```{notrust}
/home/you/projects/testing/src/main.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/you/projects/testing/src/main.rs:1 fn main() {
/home/you/projects/testing/src/main.rs:2 println!("Hello, world!")
@ -3006,7 +3055,7 @@ case, Rust is warning us that we've written some code that's never used: our
We'll turn this lint off for just this function soon. For now, just ignore this
output.
```{notrust,ignore}
```{ignore}
Running target/lib-654ce120f310a3a5
running 1 test
@ -3018,7 +3067,7 @@ with good names? This is why. Here, it says 'test foo' because we called our
test 'foo.' If we had given it a good name, it'd be more clear which test
failed, especially as we accumulate more tests.
```{notrust,ignore}
```{notrust}
failures:
---- foo stdout ----
@ -3049,7 +3098,7 @@ fn foo() {
And then try to run our tests again:
```{notrust,ignore}
```{ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
Running target/lib-654ce120f310a3a5
@ -3089,7 +3138,7 @@ include `main` when it's _not_ true. So we use `not` to negate things:
With this attribute we won't get the warning (even
though `src/main.rs` gets recompiled this time):
```{notrust,ignore}
```{ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
Running target/lib-654ce120f310a3a5
@ -3120,7 +3169,7 @@ fn math_checks_out() {
And try to run the test:
```{notrust,ignore}
```{notrust}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
/home/you/projects/testing/tests/lib.rs:3:18: 3:38 error: unresolved name `add_three_times_four`.
@ -3180,7 +3229,7 @@ fn math_checks_out() {
Let's give it a run:
```{ignore,notrust}
```{ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
Running target/lib-654ce120f310a3a5
@ -3229,7 +3278,7 @@ fn times_four(x: int) -> int { x * 4 }
If you run `cargo test`, you should get the same output:
```{ignore,notrust}
```{ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
Running target/lib-654ce120f310a3a5
@ -3283,7 +3332,7 @@ fn test_add_three() {
We'd get this error:
```{notrust,ignore}
```{notrust}
Compiling testing v0.0.1 (file:///home/you/projects/testing)
/home/you/projects/testing/tests/lib.rs:3:5: 3:24 error: function `add_three` is private
/home/you/projects/testing/tests/lib.rs:3 use testing::add_three;
@ -3325,7 +3374,7 @@ mod test {
Let's give it a shot:
```{ignore,notrust}
```{ignore}
$ cargo test
Compiling testing v0.0.1 (file:///home/you/projects/testing)
Running target/lib-654ce120f310a3a5
@ -3455,7 +3504,7 @@ let y = &mut x;
Rust will complain:
```{ignore,notrust}
```{notrust}
error: cannot borrow immutable local variable `x` as mutable
let y = &mut x;
^
@ -3482,7 +3531,7 @@ let z = &mut x;
It gives us this error:
```{notrust,ignore}
```{notrust}
error: cannot borrow `x` as mutable more than once at a time
let z = &mut x;
^
@ -3628,7 +3677,7 @@ let z = &mut x;
The error:
```{notrust,ignore}
```{notrust}
error: cannot borrow `x` as mutable more than once at a time
let z = &mut x;
^
@ -3646,7 +3695,7 @@ note: previous borrow ends here
This error comes in three parts. Let's go over each in turn.
```{notrust,ignore}
```{notrust}
error: cannot borrow `x` as mutable more than once at a time
let z = &mut x;
^
@ -3655,7 +3704,7 @@ error: cannot borrow `x` as mutable more than once at a time
This error states the restriction: you cannot lend out something mutable more
than once at the same time. The borrow checker knows the rules!
```{notrust,ignore}
```{notrust}
note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends
let y = &mut x;
^
@ -3667,7 +3716,7 @@ the first mutable borrow occurred. The error showed us the second. So now we
see both parts of the problem. It also alludes to rule #3, by reminding us that
we can't change `x` until the borrow is over.
```{notrust,ignore}
```{ignore}
note: previous borrow ends here
fn main() {
let mut x = 5i;
@ -3681,8 +3730,8 @@ Here's the second note, which lets us know where the first borrow would be over.
This is useful, because if we wait to try to borrow `x` after this borrow is
over, then everything will work.
For more advanced patterns, please consult the [Lifetime
Guide](guide-lifetimes.html). You'll also learn what this type signature with
For more advanced patterns, please consult the [Ownership
Guide](guide-ownership.html). You'll also learn what this type signature with
the `'a` syntax is:
```{rust,ignore}
@ -3770,7 +3819,7 @@ let y = &mut x;
This gives us this error:
```{notrust,ignore}
```{notrust}
error: cannot use `*x` because it was mutably borrowed
*x;
^~
@ -4595,7 +4644,7 @@ element reference has the closure it's been given as an argument called on it.
So this would give us the numbers from `2-100`. Well, almost! If you
compile the example, you'll get a warning:
```{notrust,ignore}
```{ignore}
warning: unused result which must be used: iterator adaptors are lazy and
do nothing unless consumed, #[warn(unused_must_use)] on by default
range(1i, 100i).map(|x| x + 1i);
@ -4625,7 +4674,7 @@ for i in std::iter::count(1i, 5i).take(5) {
This will print
```{notrust,ignore}
```{ignore}
1
6
11
@ -4838,7 +4887,7 @@ We can then use `T` inside the rest of the signature: `x` has type `T`, and half
of the `Result` has type `T`. However, if we try to compile that example, we'll get
an error:
```{notrust,ignore}
```{notrust}
error: binary operation `==` cannot be applied to type `T`
```
@ -4894,7 +4943,7 @@ we use `impl Trait for Item`, rather than just `impl Item`.
So what's the big deal? Remember the error we were getting with our generic
`inverse` function?
```{notrust,ignore}
```{notrust}
error: binary operation `==` cannot be applied to type `T`
```
@ -4909,7 +4958,7 @@ fn print_area<T>(shape: T) {
Rust complains:
```{notrust,ignore}
```{notrust}
error: type `T` does not implement any method in scope named `area`
```
@ -4985,7 +5034,7 @@ fn main() {
This program outputs:
```{notrust,ignore}
```{ignore}
This shape has an area of 3.141593
This shape has an area of 1
```
@ -4999,7 +5048,7 @@ print_area(5i);
We get a compile-time error:
```{notrust,ignore}
```{ignore}
error: failed to find an implementation of trait main::HasArea for int
```
@ -5066,7 +5115,7 @@ fn main() {
Now that we've moved the structs and traits into their own module, we get an
error:
```{notrust,ignore}
```{notrust}
error: type `shapes::Circle` does not implement any method in scope named `area`
```

View File

@ -58,13 +58,13 @@ authors = ["Your Name <you@example.com>"]
```
This is called a **manifest**, and it contains all of the metadata that Cargo
needs to compile your project.
needs to compile your project.
Here's what's in `src/main.rs`:
```{rust}
fn main() {
println!("Hello, world!")
println!("Hello, world!");
}
```
@ -207,7 +207,7 @@ and two...
```{bash}
$ g++ hello.cpp -Wall -Werror
$ ./a.out
$ ./a.out
Segmentation fault (core dumped)
```
@ -313,7 +313,7 @@ print `"Hello"`, or does Rust crash?
Neither. It refuses to compile:
```{notrust,ignore}
```{notrust}
$ cargo run
Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
main.rs:8:5: 8:6 error: cannot borrow `v` as mutable because it is also borrowed as immutable
@ -428,7 +428,7 @@ fn main() {
It gives us this error:
```{notrust,ignore}
```{notrust}
6:71 error: capture of moved value: `numbers`
for j in range(0, 3) { numbers[j] += 1 }
^~~~~~~

View File

@ -496,9 +496,8 @@ Examples of integer literals of various forms:
A _floating-point literal_ has one of two forms:
* Two _decimal literals_ separated by a period
character `U+002E` (`.`), with an optional _exponent_ trailing after the
second decimal literal.
* A _decimal literal_ followed by a period character `U+002E` (`.`). This is
optionally followed by another decimal literal, with an optional _exponent_.
* A single _decimal literal_ followed by an _exponent_.
By default, a floating-point literal has a generic type, and, like integer
@ -509,12 +508,17 @@ types), which explicitly determine the type of the literal.
Examples of floating-point literals of various forms:
```
123.0f64; // type f64
0.1f64; // type f64
0.1f32; // type f32
12E+99_f64; // type f64
123.0f64; // type f64
0.1f64; // type f64
0.1f32; // type f32
12E+99_f64; // type f64
let x: f64 = 2.; // type f64
```
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`.
##### Boolean literals
The two values of the boolean type are written `true` and `false`.

View File

@ -8,6 +8,12 @@
# option. This file may not be copied, modified, or distributed
# except according to those terms.
# Script parameters:
# argv[1] = rust component root,
# argv[2] = gcc component root,
# argv[3] = target triple
# The first two correspond to the two installable components defined in the setup script.
import sys, os, shutil, subprocess
def find_files(files, path):
@ -22,7 +28,7 @@ def find_files(files, path):
raise Exception("Could not find '%s' in %s" % (fname, path))
return found
def make_win_dist(dist_root, target_triple):
def make_win_dist(rust_root, gcc_root, target_triple):
# Ask gcc where it keeps its stuff
gcc_out = subprocess.check_output(["gcc.exe", "-print-search-dirs"])
bin_path = os.environ["PATH"].split(os.pathsep)
@ -90,29 +96,29 @@ def make_win_dist(dist_root, target_triple):
target_libs = find_files(target_libs, lib_path)
# Copy runtime dlls next to rustc.exe
dist_bin_dir = os.path.join(dist_root, "bin")
dist_bin_dir = os.path.join(rust_root, "bin")
for src in rustc_dlls:
shutil.copy(src, dist_bin_dir)
# Copy platform tools to platform-specific bin directory
target_bin_dir = os.path.join(dist_root, "bin", "rustlib", target_triple, "bin")
target_bin_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "bin")
if not os.path.exists(target_bin_dir):
os.makedirs(target_bin_dir)
for src in target_tools:
shutil.copy(src, target_bin_dir)
# Copy platform libs to platform-spcific lib directory
target_lib_dir = os.path.join(dist_root, "bin", "rustlib", target_triple, "lib")
target_lib_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "lib")
if not os.path.exists(target_lib_dir):
os.makedirs(target_lib_dir)
for src in target_libs:
shutil.copy(src, target_lib_dir)
# Copy license files
lic_dir = os.path.join(dist_root, "bin", "third-party")
lic_dir = os.path.join(rust_root, "bin", "third-party")
if os.path.exists(lic_dir):
shutil.rmtree(lic_dir) # copytree() won't overwrite existing files
shutil.copytree(os.path.join(os.path.dirname(__file__), "third-party"), lic_dir)
if __name__=="__main__":
make_win_dist(sys.argv[1], sys.argv[2])
make_win_dist(sys.argv[1], sys.argv[2], sys.argv[3])

View File

@ -14,6 +14,7 @@ AppPublisherURL=http://www.rust-lang.org
VersionInfoVersion={#CFG_VERSION_WIN}
LicenseFile=LICENSE.txt
PrivilegesRequired=lowest
DisableWelcomePage=true
DisableProgramGroupPage=true
DisableReadyPage=true
@ -37,8 +38,13 @@ Uninstallable=yes
[Tasks]
Name: modifypath; Description: &Add {app}\bin to your PATH (recommended)
[Components]
Name: rust; Description: "Rust compiler and standard crates"; Types: full compact custom; Flags: fixed
Name: gcc; Description: "Linker and platform libraries"; Types: full
[Files]
Source: "tmp/dist/win/*.*" ; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
Source: "tmp/dist/win/rust/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust
Source: "tmp/dist/win/gcc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: gcc
[Code]
const

View File

@ -141,6 +141,7 @@
#![stable]
use core::borrow::BorrowFrom;
use core::cell::Cell;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
@ -349,6 +350,12 @@ impl<T: Clone> Rc<T> {
}
}
impl<T> BorrowFrom<Rc<T>> for T {
fn borrow_from(owned: &Rc<T>) -> &T {
&**owned
}
}
#[experimental = "Deref is experimental."]
impl<T> Deref<T> for Rc<T> {
#[inline(always)]

View File

@ -1026,6 +1026,24 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
impl<K, V> BTreeMap<K, V> {
/// Gets an iterator over the entries of the map.
///
/// # Example
///
/// ```
/// use std::collections::BTreeMap;
///
/// let mut map = BTreeMap::new();
/// map.insert(1u, "a");
/// map.insert(2u, "b");
/// map.insert(3u, "c");
///
/// for (key, value) in map.iter() {
/// println!("{}: {}", key, value);
/// }
///
/// let (first_key, first_value) = map.iter().next().unwrap();
/// assert_eq!((*first_key, *first_value), (1u, "a"));
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn iter<'a>(&'a self) -> Entries<'a, K, V> {
let len = self.len();

View File

@ -11,9 +11,6 @@
//! A doubly-linked list with owned nodes.
//!
//! The `DList` allows pushing and popping elements at either end.
//!
//! `DList` implements the trait `Deque`. It should be imported with
//! `use collections::Deque`.
// DList is constructed like a singly-linked list over the field `next`.
// including the last link being None; each Node owns its `next` field.

View File

@ -11,7 +11,6 @@
//! This crate implements a double-ended queue with `O(1)` amortized inserts and removals from both
//! ends of the container. It also has `O(1)` indexing like a vector. The contained elements are
//! not required to be copyable, and the queue will be sendable if the contained type is sendable.
//! Its interface `Deque` is defined in `collections`.
use core::prelude::*;
@ -35,7 +34,7 @@ static MINIMUM_CAPACITY: uint = 2u;
// FIXME(conventions): implement shrink_to_fit. Awkward with the current design, but it should
// be scrapped anyway. Defer to rewrite?
/// `RingBuf` is a circular buffer that implements `Deque`.
/// `RingBuf` is a circular buffer.
pub struct RingBuf<T> {
// tail and head are pointers into the buffer. Tail always points
// to the first element that could be read, Head always points

View File

@ -729,15 +729,38 @@ impl FromIterator<char> for String {
}
}
#[experimental = "waiting on FromIterator stabilization"]
impl<'a> FromIterator<&'a str> for String {
fn from_iter<I:Iterator<&'a str>>(iterator: I) -> String {
let mut buf = String::new();
buf.extend(iterator);
buf
}
}
#[experimental = "waiting on Extend stabilization"]
impl Extend<char> for String {
fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
let (lower_bound, _) = iterator.size_hint();
self.reserve(lower_bound);
for ch in iterator {
self.push(ch)
}
}
}
#[experimental = "waiting on Extend stabilization"]
impl<'a> Extend<&'a str> for String {
fn extend<I: Iterator<&'a str>>(&mut self, mut iterator: I) {
// A guess that at least one byte per iterator element will be needed.
let (lower_bound, _) = iterator.size_hint();
self.reserve(lower_bound);
for s in iterator {
self.push_str(s)
}
}
}
impl PartialEq for String {
#[inline]
fn eq(&self, other: &String) -> bool { PartialEq::eq(&**self, &**other) }
@ -1307,6 +1330,27 @@ mod tests {
"[[], [1], [1, 1]]");
}
#[test]
fn test_from_iterator() {
let s = "ศไทย中华Việt Nam".to_string();
let t = "ศไทย中华";
let u = "Việt Nam";
let a: String = s.chars().collect();
assert_eq!(s, a);
let mut b = t.to_string();
b.extend(u.chars());
assert_eq!(s, b);
let c: String = vec![t, u].into_iter().collect();
assert_eq!(s, c);
let mut d = t.to_string();
d.extend(vec![u].into_iter());
assert_eq!(s, d);
}
#[bench]
fn bench_with_capacity(b: &mut Bencher) {
b.iter(|| {

View File

@ -44,7 +44,7 @@
pub use self::Ordering::*;
use kinds::{Copy, Sized};
use option::{Option, Some, None};
use option::Option::{mod, Some, None};
/// Trait for values that can be compared for equality and inequality.
///

View File

@ -59,7 +59,7 @@
#![allow(unknown_features, raw_pointer_deriving)]
#![feature(globs, intrinsics, lang_items, macro_rules, phase)]
#![feature(simd, unsafe_destructor, slicing_syntax)]
#![feature(default_type_params)]
#![feature(default_type_params, unboxed_closures)]
#![deny(missing_docs)]
mod macros;

View File

@ -143,7 +143,10 @@
#![stable]
#[cfg(stage0)]
pub use self::Option::*;
#[cfg(not(stage0))]
use self::Option::*;
use cmp::{Eq, Ord};
use default::Default;

View File

@ -230,7 +230,7 @@
#![stable]
pub use self::Result::*;
use self::Result::*;
use kinds::Copy;
use std::fmt::Show;

View File

@ -76,7 +76,7 @@ impl FromStr for bool {
Section: Creating a string
*/
/// Converts a vector to a string slice without performing any allocations.
/// Converts a slice of bytes to a string slice without performing any allocations.
///
/// Once the slice has been validated as utf-8, it is transmuted in-place and
/// returned as a '&str' instead of a '&[u8]'

View File

@ -117,7 +117,7 @@ impl ChaChaRng {
/// security proof for a more involved example of this.
///
/// The modified word layout is:
/// ```notrust
/// ```ignore
/// constant constant constant constant
/// key key key key
/// key key key key

View File

@ -120,7 +120,7 @@
//!
//! The compiler accepts a flag of this form a number of times:
//!
//! ```notrust
//! ```ignore
//! --extern crate-name=path/to/the/crate.rlib
//! ```
//!
@ -152,7 +152,7 @@
//!
//! and the compiler would be invoked as:
//!
//! ```notrust
//! ```ignore
//! rustc a.rs --extern b1=path/to/libb1.rlib --extern b2=path/to/libb2.rlib
//! ```
//!
@ -178,7 +178,7 @@
//! dependencies, not the upstream transitive dependencies. Consider this
//! dependency graph:
//!
//! ```notrust
//! ```ignore
//! A.1 A.2
//! | |
//! | |

View File

@ -288,7 +288,6 @@ fn load_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debuginfo::create_captured_var_metadata(
bcx,
def_id.node,
cdata_ty,
env_pointer_alloca,
i,
captured_by_ref,
@ -328,7 +327,7 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
// Store the pointer to closure data in an alloca for debug info because that's what the
// llvm.dbg.declare intrinsic expects
let env_pointer_alloca = if bcx.sess().opts.debuginfo == FullDebugInfo {
let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), self_type), "__debuginfo_env_ptr");
let alloc = alloca(bcx, val_ty(llenv), "__debuginfo_env_ptr");
Store(bcx, llenv, alloc);
Some(alloc)
} else {
@ -357,7 +356,6 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
debuginfo::create_captured_var_metadata(
bcx,
def_id.node,
self_type,
env_pointer_alloca,
i,
captured_by_ref,

View File

@ -884,7 +884,6 @@ pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
node_id: ast::NodeId,
env_data_type: Ty<'tcx>,
env_pointer: ValueRef,
env_index: uint,
captured_by_ref: bool,
@ -930,7 +929,10 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let variable_type = node_id_type(bcx, node_id);
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, span).fn_metadata;
let llvm_env_data_type = type_of::type_of(cx, env_data_type);
// env_pointer is the alloca containing the pointer to the environment,
// so it's type is **EnvironmentType. In order to find out the type of
// the environment we have to "dereference" two times.
let llvm_env_data_type = val_ty(env_pointer).element_type().element_type();
let byte_offset_of_var_in_env = machine::llelement_offset(cx,
llvm_env_data_type,
env_index);

View File

@ -386,20 +386,81 @@ fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
(regions, types)
}
/// Returns the appropriate lifetime to use for any output lifetimes
/// (if one exists) and a vector of the (pattern, number of lifetimes)
/// corresponding to each input type/pattern.
fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec<String>)
-> (Option<ty::Region>, Vec<(String, uint)>)
{
let mut lifetimes_for_params: Vec<(String, uint)> = Vec::new();
let mut possible_implied_output_region = None;
for (input_type, input_pat) in input_tys.iter().zip(input_pats.into_iter()) {
let mut accumulator = Vec::new();
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type);
if accumulator.len() == 1 {
// there's a chance that the unique lifetime of this
// iteration will be the appropriate lifetime for output
// parameters, so lets store it.
possible_implied_output_region = Some(accumulator[0])
}
lifetimes_for_params.push((input_pat, accumulator.len()));
}
let implied_output_region = if lifetimes_for_params.iter().map(|&(_, n)| n).sum() == 1 {
assert!(possible_implied_output_region.is_some());
possible_implied_output_region
} else {
None
};
(implied_output_region, lifetimes_for_params)
}
fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC,
implied_output_region: Option<ty::Region>,
param_lifetimes: Vec<(String, uint)>,
ty: &ast::Ty)
-> Ty<'tcx>
where AC: AstConv<'tcx>
{
match implied_output_region {
Some(implied_output_region) => {
let rb = SpecificRscope::new(implied_output_region);
ast_ty_to_ty(this, &rb, ty)
}
None => {
// All regions must be explicitly specified in the output
// if the lifetime elision rules do not apply. This saves
// the user from potentially-confusing errors.
let rb = UnelidableRscope::new(param_lifetimes);
ast_ty_to_ty(this, &rb, ty)
}
}
}
fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
data: &ast::ParenthesizedParameterData)
-> Vec<Ty<'tcx>>
where AC: AstConv<'tcx>
{
let binding_rscope = BindingRscope::new();
let inputs = data.inputs.iter()
.map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
.collect();
.collect::<Vec<Ty<'tcx>>>();
let input_params = Vec::from_elem(inputs.len(), String::new());
let (implied_output_region,
params_lifetimes) = find_implied_output_region(&*inputs, input_params);
let input_ty = ty::mk_tup(this.tcx(), inputs);
let output = match data.output {
Some(ref output_ty) => ast_ty_to_ty(this, &binding_rscope, &**output_ty),
Some(ref output_ty) => convert_ty_with_lifetime_elision(this,
implied_output_region,
params_lifetimes,
&**output_ty),
None => ty::mk_nil(this.tcx()),
};
@ -1059,55 +1120,33 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
let self_and_input_tys: Vec<Ty> =
self_ty.into_iter().chain(input_tys).collect();
let mut lifetimes_for_params: Vec<(String, Vec<ty::Region>)> = Vec::new();
// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
if implied_output_region.is_none() {
let mut self_and_input_tys_iter = self_and_input_tys.iter();
if self_ty.is_some() {
let lifetimes_for_params = if implied_output_region.is_none() {
let input_tys = if self_ty.is_some() {
// Skip the first argument if `self` is present.
drop(self_and_input_tys_iter.next())
}
self_and_input_tys.slice_from(1)
} else {
self_and_input_tys.slice_from(0)
};
for (input_type, input_pat) in self_and_input_tys_iter.zip(input_pats.into_iter()) {
let mut accumulator = Vec::new();
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type);
lifetimes_for_params.push((input_pat, accumulator));
}
if lifetimes_for_params.iter().map(|&(_, ref x)| x.len()).sum() == 1 {
implied_output_region =
Some(lifetimes_for_params.iter()
.filter_map(|&(_, ref x)|
if x.len() == 1 { Some(x[0]) } else { None })
.next().unwrap());
}
}
let param_lifetimes: Vec<(String, uint)> = lifetimes_for_params.into_iter()
.map(|(n, v)| (n, v.len()))
.filter(|&(_, l)| l != 0)
.collect();
let (ior, lfp) = find_implied_output_region(input_tys, input_pats);
implied_output_region = ior;
lfp
} else {
vec![]
};
let output_ty = match decl.output {
ast::Return(ref output) if output.node == ast::TyInfer =>
ty::FnConverging(this.ty_infer(output.span)),
ast::Return(ref output) =>
ty::FnConverging(match implied_output_region {
Some(implied_output_region) => {
let rb = SpecificRscope::new(implied_output_region);
ast_ty_to_ty(this, &rb, &**output)
}
None => {
// All regions must be explicitly specified in the output
// if the lifetime elision rules do not apply. This saves
// the user from potentially-confusing errors.
let rb = UnelidableRscope::new(param_lifetimes);
ast_ty_to_ty(this, &rb, &**output)
}
}),
ty::FnConverging(convert_ty_with_lifetime_elision(this,
implied_output_region,
lifetimes_for_params,
&**output)),
ast::NoReturn(_) => ty::FnDiverging
};

View File

@ -0,0 +1,46 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syntax::ast;
use syntax::codemap::Span;
use CrateCtxt;
/// Check that it is legal to call methods of the trait corresponding
/// to `trait_id` (this only cares about the trait, not the specific
/// method that is called)
pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: ast::DefId) {
let tcx = ccx.tcx;
let did = Some(trait_id);
let li = &tcx.lang_items;
if did == li.drop_trait() {
span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
} else if !tcx.sess.features.borrow().unboxed_closures {
// the #[feature(unboxed_closures)] feature isn't
// activated so we need to enforce the closure
// restrictions.
let method = if did == li.fn_trait() {
"call"
} else if did == li.fn_mut_trait() {
"call_mut"
} else if did == li.fn_once_trait() {
"call_once"
} else {
return // not a closure method, everything is OK.
};
span_err!(tcx.sess, span, E0174,
"explicit use of unboxed closure method `{}` is experimental",
method);
span_help!(tcx.sess, span,
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
}
}

View File

@ -10,7 +10,7 @@
use super::probe;
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue};
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee};
use middle::subst::{mod, Subst};
use middle::traits;
use middle::ty::{mod, Ty};
@ -90,7 +90,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
// Make sure nobody calls `drop()` explicitly.
self.enforce_drop_trait_limitations(&pick);
self.enforce_illegal_method_limitations(&pick);
// Create substitutions for the method's type parameters.
let (rcvr_substs, method_origin) =
@ -624,14 +624,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
self.fcx.infcx()
}
fn enforce_drop_trait_limitations(&self, pick: &probe::Pick) {
fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
// Disallow calls to the method `drop` defined in the `Drop` trait.
match pick.method_ty.container {
ty::TraitContainer(trait_def_id) => {
if Some(trait_def_id) == self.tcx().lang_items.drop_trait() {
span_err!(self.tcx().sess, self.span, E0040,
"explicit call to destructor");
}
callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
}
ty::ImplContainer(..) => {
// Since `drop` is a trait method, we expect that any

View File

@ -130,6 +130,7 @@ pub mod demand;
pub mod method;
pub mod wf;
mod closure;
mod callee;
/// Fields that are part of a `FnCtxt` which are inherited by
/// closures defined within the function. For example:
@ -5095,8 +5096,17 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
// Case 3. Reference to a method.
def::DefStaticMethod(..) => {
def::DefStaticMethod(_, providence) |
def::DefMethod(_, _, providence) => {
assert!(path.segments.len() >= 2);
match providence {
def::FromTrait(trait_did) => {
callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
}
def::FromImpl(_) => {}
}
segment_spaces = Vec::from_elem(path.segments.len() - 2, None);
segment_spaces.push(Some(subst::TypeSpace));
segment_spaces.push(Some(subst::FnSpace));
@ -5108,7 +5118,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
def::DefMod(..) |
def::DefForeignMod(..) |
def::DefLocal(..) |
def::DefMethod(..) |
def::DefUse(..) |
def::DefRegion(..) |
def::DefLabel(..) |

View File

@ -212,6 +212,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
trait_ref.repr(self.crate_context.tcx),
token::get_ident(item.ident));
enforce_trait_manually_implementable(self.crate_context.tcx,
item.span,
trait_ref.def_id);
self.add_trait_impl(trait_ref.def_id, impl_did);
}
@ -542,6 +545,28 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
}
}
fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: ast::DefId) {
if tcx.sess.features.borrow().unboxed_closures {
// the feature gate allows all of them
return
}
let did = Some(trait_def_id);
let li = &tcx.lang_items;
let trait_name = if did == li.fn_trait() {
"Fn"
} else if did == li.fn_mut_trait() {
"FnMut"
} else if did == li.fn_once_trait() {
"FnOnce"
} else {
return // everything OK
};
span_err!(tcx.sess, sp, E0173, "manual implementations of `{}` are experimental", trait_name);
span_help!(tcx.sess, sp,
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
}
fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
impl_id: ast::DefId,
impl_poly_type: &ty::Polytype<'tcx>,

View File

@ -53,7 +53,7 @@ register_diagnostics!(
E0035,
E0036,
E0038,
E0040,
E0040, // explicit use of destructor method
E0044,
E0045,
E0046,
@ -147,5 +147,7 @@ register_diagnostics!(
E0168,
E0169,
E0171,
E0172
E0172,
E0173, // manual implementations of unboxed closure traits are experimental
E0174 // explicit use of unboxed closure methods are experimental
)

View File

@ -1,4 +1,4 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -28,10 +28,22 @@ pub enum CharacterSet {
impl Copy for CharacterSet {}
/// Available newline types
pub enum Newline {
/// A linefeed (i.e. Unix-style newline)
LF,
/// A carriage return and a linefeed (i.e. Windows-style newline)
CRLF
}
impl Copy for Newline {}
/// Contains configuration parameters for `to_base64`.
pub struct Config {
/// Character set to use
pub char_set: CharacterSet,
/// Newline to use
pub newline: Newline,
/// True to pad output with `=` characters
pub pad: bool,
/// `Some(len)` to wrap lines at `len`, `None` to disable line wrapping
@ -42,15 +54,15 @@ impl Copy for Config {}
/// Configuration for RFC 4648 standard base64 encoding
pub static STANDARD: Config =
Config {char_set: Standard, pad: true, line_length: None};
Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: None};
/// Configuration for RFC 4648 base64url encoding
pub static URL_SAFE: Config =
Config {char_set: UrlSafe, pad: false, line_length: None};
Config {char_set: UrlSafe, newline: Newline::CRLF, pad: false, line_length: None};
/// Configuration for RFC 2045 MIME base64 encoding
pub static MIME: Config =
Config {char_set: Standard, pad: true, line_length: Some(76)};
Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: Some(76)};
static STANDARD_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
@ -87,24 +99,30 @@ impl ToBase64 for [u8] {
UrlSafe => URLSAFE_CHARS
};
let mut v = Vec::new();
// In general, this Vec only needs (4/3) * self.len() memory, but
// addition is faster than multiplication and division.
let mut v = Vec::with_capacity(self.len() + self.len());
let mut i = 0;
let mut cur_length = 0;
let len = self.len();
while i < len - (len % 3) {
match config.line_length {
Some(line_length) =>
if cur_length >= line_length {
v.push(b'\r');
v.push(b'\n');
cur_length = 0;
},
None => ()
let mod_len = len % 3;
let cond_len = len - mod_len;
let newline = match config.newline {
Newline::LF => b"\n",
Newline::CRLF => b"\r\n"
};
while i < cond_len {
let (first, second, third) = (self[i], self[i + 1], self[i + 2]);
if let Some(line_length) = config.line_length {
if cur_length >= line_length {
v.push_all(newline);
cur_length = 0;
}
}
let n = (self[i] as u32) << 16 |
(self[i + 1] as u32) << 8 |
(self[i + 2] as u32);
let n = (first as u32) << 16 |
(second as u32) << 8 |
(third as u32);
// This 24-bit number gets separated into four 6-bit numbers.
v.push(bytes[((n >> 18) & 63) as uint]);
@ -116,20 +134,17 @@ impl ToBase64 for [u8] {
i += 3;
}
if len % 3 != 0 {
match config.line_length {
Some(line_length) =>
if cur_length >= line_length {
v.push(b'\r');
v.push(b'\n');
},
None => ()
if mod_len != 0 {
if let Some(line_length) = config.line_length {
if cur_length >= line_length {
v.push_all(newline);
}
}
}
// Heh, would be cool if we knew this was exhaustive
// (the dream of bounded integer types)
match len % 3 {
match mod_len {
0 => (),
1 => {
let n = (self[i] as u32) << 16;
@ -232,7 +247,7 @@ impl FromBase64 for str {
impl FromBase64 for [u8] {
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error> {
let mut r = Vec::new();
let mut r = Vec::with_capacity(self.len());
let mut buf: u32 = 0;
let mut modulus = 0i;
@ -288,7 +303,7 @@ impl FromBase64 for [u8] {
mod tests {
extern crate test;
use self::test::Bencher;
use base64::{Config, FromBase64, ToBase64, STANDARD, URL_SAFE};
use base64::{Config, Newline, FromBase64, ToBase64, STANDARD, URL_SAFE};
#[test]
fn test_to_base64_basic() {
@ -302,14 +317,27 @@ mod tests {
}
#[test]
fn test_to_base64_line_break() {
fn test_to_base64_crlf_line_break() {
assert!(![0u8, ..1000].to_base64(Config {line_length: None, ..STANDARD})
.contains("\r\n"));
assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4),
..STANDARD}),
assert_eq!(b"foobar".to_base64(Config {line_length: Some(4),
..STANDARD}),
"Zm9v\r\nYmFy");
}
#[test]
fn test_to_base64_lf_line_break() {
assert!(![0u8, ..1000].to_base64(Config {line_length: None,
newline: Newline::LF,
..STANDARD})
.as_slice()
.contains("\n"));
assert_eq!(b"foobar".to_base64(Config {line_length: Some(4),
newline: Newline::LF,
..STANDARD}),
"Zm9v\nYmFy");
}
#[test]
fn test_to_base64_padding() {
assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zg");
@ -344,6 +372,10 @@ mod tests {
b"foobar");
assert_eq!("Zm9vYg==\r\n".from_base64().unwrap(),
b"foob");
assert_eq!("Zm9v\nYmFy".from_base64().unwrap(),
b"foobar");
assert_eq!("Zm9vYg==\n".from_base64().unwrap(),
b"foob");
}
#[test]

View File

@ -23,7 +23,7 @@ Core encoding and decoding interfaces.
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![allow(unknown_features)]
#![feature(macro_rules, default_type_params, phase, slicing_syntax, globs)]
#![feature(macro_rules, default_type_params, phase, slicing_syntax, globs, if_let)]
// test harness access
#[cfg(test)]

View File

@ -21,9 +21,11 @@ use iter::IteratorExt;
use mem;
use ops::*;
use option::*;
use option::Option::{None, Some};
use os;
use path::{Path,GenericPath};
use result::*;
use result::Result::{Err, Ok};
use slice::{AsSlice,SlicePrelude};
use str;
use string::String;
@ -216,6 +218,7 @@ pub mod dl {
use kinds::Copy;
use ptr;
use result::*;
use result::Result::{Err, Ok};
use string::String;
pub unsafe fn open_external<T: ToCStr>(filename: T) -> *mut u8 {

View File

@ -160,7 +160,7 @@ pub fn getcwd() -> IoResult<Path> {
}
#[cfg(windows)]
pub mod windows {
pub mod windoze {
use libc::types::os::arch::extra::DWORD;
use libc;
use option::Option;
@ -386,7 +386,7 @@ pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
pub fn getenv(n: &str) -> Option<String> {
unsafe {
with_env_lock(|| {
use os::windows::{fill_utf16_buf_and_decode};
use os::windoze::{fill_utf16_buf_and_decode};
let mut n: Vec<u16> = n.utf16_units().collect();
n.push(0);
fill_utf16_buf_and_decode(|buf, sz| {
@ -715,7 +715,7 @@ pub fn self_exe_name() -> Option<Path> {
#[cfg(windows)]
fn load_self() -> Option<Vec<u8>> {
unsafe {
use os::windows::fill_utf16_buf_and_decode;
use os::windoze::fill_utf16_buf_and_decode;
fill_utf16_buf_and_decode(|buf, sz| {
libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
}).map(|s| s.into_string().into_bytes())
@ -1215,7 +1215,11 @@ pub enum MapOption {
/// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
/// POSIX.
MapAddr(*const u8),
/// Create a memory mapping for a file with a given HANDLE.
#[cfg(windows)]
MapFd(libc::HANDLE),
/// Create a memory mapping for a file with a given fd.
#[cfg(not(windows))]
MapFd(c_int),
/// When using `MapFd`, the start of the map is `uint` bytes from the start
/// of the file.
@ -1413,7 +1417,7 @@ impl MemoryMap {
let mut readable = false;
let mut writable = false;
let mut executable = false;
let mut fd: c_int = -1;
let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE;
let mut offset: uint = 0;
let len = round_up(min_len, page_size());
@ -1423,23 +1427,23 @@ impl MemoryMap {
MapWritable => { writable = true; },
MapExecutable => { executable = true; }
MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
MapFd(fd_) => { fd = fd_; },
MapFd(handle_) => { handle = handle_; },
MapOffset(offset_) => { offset = offset_; },
MapNonStandardFlags(..) => {}
}
}
let flProtect = match (executable, readable, writable) {
(false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
(false, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_NOACCESS,
(false, true, false) => libc::PAGE_READONLY,
(false, true, true) => libc::PAGE_READWRITE,
(true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
(true, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_EXECUTE,
(true, true, false) => libc::PAGE_EXECUTE_READ,
(true, true, true) => libc::PAGE_EXECUTE_READWRITE,
_ => return Err(ErrUnsupProt)
};
if fd == -1 {
if handle == libc::INVALID_HANDLE_VALUE {
if offset != 0 {
return Err(ErrUnsupOffset);
}
@ -1467,7 +1471,7 @@ impl MemoryMap {
// we should never get here.
};
unsafe {
let hFile = libc::get_osfhandle(fd) as HANDLE;
let hFile = handle;
let mapping = libc::CreateFileMappingW(hFile,
ptr::null_mut(),
flProtect,
@ -1991,55 +1995,47 @@ mod tests {
#[test]
fn memory_map_file() {
use result::Result::{Ok, Err};
use libc;
use os::*;
use libc::*;
use io::fs;
use io::fs::{File, unlink};
use io::SeekStyle::SeekSet;
use io::FileMode::Open;
use io::FileAccess::ReadWrite;
#[cfg(unix)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
}
#[cfg(not(windows))]
fn get_fd(file: &File) -> libc::c_int {
use os::unix::AsRawFd;
file.as_raw_fd()
}
#[cfg(windows)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
}
fn get_fd(file: &File) -> libc::HANDLE {
use os::windows::AsRawHandle;
file.as_raw_handle()
}
let mut path = tmpdir();
path.push("mmap_file.tmp");
let size = MemoryMap::granularity() * 2;
let mut file = File::open_mode(&path, Open, ReadWrite).unwrap();
file.seek(size as i64, SeekSet);
file.write_u8(0);
let fd = unsafe {
let fd = path.with_c_str(|path| {
open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
});
lseek_(fd, size);
"x".with_c_str(|x| assert!(write(fd, x as *const c_void, 1) == 1));
fd
};
let chunk = match MemoryMap::new(size / 2, &[
let chunk = MemoryMap::new(size / 2, &[
MapReadable,
MapWritable,
MapFd(fd),
MapFd(get_fd(&file)),
MapOffset(size / 2)
]) {
Ok(chunk) => chunk,
Err(msg) => panic!("{}", msg)
};
]).unwrap();
assert!(chunk.len > 0);
unsafe {
*chunk.data = 0xbe;
assert!(*chunk.data == 0xbe);
close(fd);
}
drop(chunk);
fs::unlink(&path).unwrap();
unlink(&path).unwrap();
}
#[test]

View File

@ -80,7 +80,7 @@
//! circle, both centered at the origin. Since the area of a unit circle is π,
//! we have:
//!
//! ```notrust
//! ```text
//! (area of unit circle) / (area of square) = π / 4
//! ```
//!

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use option::None;
use option::Option::None;
use rustrt::task::Task;
use rustrt::local::Local;

View File

@ -185,7 +185,23 @@ impl StaticKey {
}
unsafe fn lazy_init(&self) -> uint {
let key = imp::create(self.dtor);
// POSIX allows the key created here to be 0, but the compare_and_swap
// below relies on using 0 as a sentinel value to check who won the
// race to set the shared TLS key. As far as I know, there is no
// guaranteed value that cannot be returned as a posix_key_create key,
// so there is no value we can initialize the inner key with to
// prove that it has not yet been set. As such, we'll continue using a
// value of 0, but with some gyrations to make sure we have a non-0
// value returned from the creation routine.
// FIXME: this is clearly a hack, and should be cleaned up.
let key1 = imp::create(self.dtor);
let key = if key1 != 0 {
key1
} else {
let key2 = imp::create(self.dtor);
imp::destroy(key1);
key2
};
assert!(key != 0);
match self.inner.key.compare_and_swap(0, key as uint, atomic::SeqCst) {
// The CAS succeeded, so we've created the actual key

View File

@ -15,7 +15,7 @@ use libc::{mod, c_int};
use c_str::CString;
use mem;
use os::windows::fill_utf16_buf_and_decode;
use os::windoze::fill_utf16_buf_and_decode;
use path;
use ptr;
use str;

View File

@ -66,12 +66,19 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
cx.ident_of("cmp"),
cx.ident_of("Equal")));
let cmp_path = vec![
cx.ident_of("std"),
cx.ident_of("cmp"),
cx.ident_of("Ord"),
cx.ident_of("cmp"),
];
/*
Builds:
let __test = self_field1.cmp(&other_field2);
let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1);
if other == ::std::cmp::Ordering::Equal {
let __test = self_field2.cmp(&other_field2);
let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2);
if __test == ::std::cmp::Ordering::Equal {
...
} else {
@ -83,11 +90,11 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
FIXME #6449: These `if`s could/should be `match`es.
*/
cs_same_method_fold(
cs_fold(
// foldr nests the if-elses correctly, leaving the first field
// as the outermost one, and the last as the innermost.
false,
|cx, span, old, new| {
|cx, span, old, self_f, other_fs| {
// let __test = new;
// if __test == ::std::cmp::Ordering::Equal {
// old
@ -95,6 +102,20 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
// __test
// }
let new = {
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `deriving(PartialOrd)`"),
};
let args = vec![
cx.expr_addr_of(span, self_f),
cx.expr_addr_of(span, other_f.clone()),
];
cx.expr_call_global(span, cmp_path.clone(), args)
};
let assign = cx.stmt_let(span, false, test_id, new);
let cond = cx.expr_binary(span, ast::BiEq,

View File

@ -20,5 +20,5 @@ impl Drop for Foo {
fn main() {
let x = Foo { x: 3 };
x.drop(); //~ ERROR explicit call to destructor
x.drop(); //~ ERROR explicit use of destructor method
}

View File

@ -24,7 +24,7 @@ impl Drop for Foo {
impl Bar for Foo {
fn blah(&self) {
self.drop(); //~ ERROR explicit call to destructor
self.drop(); //~ ERROR explicit use of destructor method
}
}

View File

@ -0,0 +1,26 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]
struct Foo;
impl Fn<(), ()> for Foo { //~ ERROR manual implementations of `Fn` are experimental
extern "rust-call" fn call(&self, args: ()) -> () {}
}
struct Bar;
impl FnMut<(), ()> for Bar { //~ ERROR manual implementations of `FnMut` are experimental
extern "rust-call" fn call_mut(&self, args: ()) -> () {}
}
struct Baz;
impl FnOnce<(), ()> for Baz { //~ ERROR manual implementations of `FnOnce` are experimental
extern "rust-call" fn call_once(&self, args: ()) -> () {}
}
fn main() {}

View File

@ -0,0 +1,19 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]
fn foo<F: Fn<(), ()>>(mut f: F) {
f.call(()); //~ ERROR explicit use of unboxed closure method `call`
f.call_mut(()); //~ ERROR explicit use of unboxed closure method `call_mut`
f.call_once(()); //~ ERROR explicit use of unboxed closure method `call_once`
}
fn main() {}

View File

@ -0,0 +1,19 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]
fn foo<F: Fn<(), ()>>(mut f: F, mut g: F) {
Fn::call(&g, ()); //~ ERROR explicit use of unboxed closure method `call`
FnMut::call_mut(&mut g, ()); //~ ERROR explicit use of unboxed closure method `call_mut`
FnOnce::call_once(g, ()); //~ ERROR explicit use of unboxed closure method `call_once`
}
fn main() {}

View File

@ -0,0 +1,20 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {}
}
fn main() {
Drop::drop(&mut Foo) //~ ERROR explicit use of destructor method
}

View File

@ -33,7 +33,6 @@ fn h(_x: &Foo) -> &int { //~ ERROR missing lifetime specifier
fn i(_x: int) -> &int { //~ ERROR missing lifetime specifier
//~^ HELP this function's return type contains a borrowed value
//~^^ HELP consider giving it a 'static lifetime
panic!()
}

View File

@ -44,9 +44,9 @@ fn test<'a,'b>() {
eq::< for<'a,'b> Foo<(&'a int,&'b uint),uint>,
Foo(&int,&uint) -> uint >();
// FIXME(#18992) Test lifetime elision in `()` form:
// eq::< for<'a,'b> Foo<(&'a int,), &'a int>,
// Foo(&int) -> &int >();
// lifetime elision
eq::< for<'a,'b> Foo<(&'a int,), &'a int>,
Foo(&int) -> &int >();
// Errors expected:
eq::< Foo<(),()>, Foo(char) >();

View File

@ -0,0 +1,34 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that the unboxed closure sugar can be used with an arbitrary
// struct type and that it is equivalent to the same syntax using
// angle brackets. This test covers only simple types and in
// particular doesn't test bound regions.
#![feature(unboxed_closures)]
#![allow(dead_code)]
trait Foo<T,U> {
fn dummy(&self, t: T, u: U);
}
trait Eq<Sized? X> for Sized? { }
impl<Sized? X> Eq<X> for X { }
fn eq<Sized? A,Sized? B:Eq<A>>() { }
fn main() {
eq::< for<'a> Foo<(&'a int,), &'a int>,
Foo(&int) -> &int >();
eq::< for<'a> Foo<(&'a int,), (&'a int, &'a int)>,
Foo(&int) -> (&int, &int) >();
let _: Foo(&int, &uint) -> &uint; //~ ERROR missing lifetime specifier
}

View File

@ -28,6 +28,19 @@
// gdb-command:print *owned
// gdb-check:$5 = 6
// gdb-command:continue
// gdb-command:print variable
// gdb-check:$6 = 2
// gdb-command:print constant
// gdb-check:$7 = 2
// gdb-command:print a_struct
// gdb-check:$8 = {a = -3, b = 4.5, c = 5}
// gdb-command:print *struct_ref
// gdb-check:$9 = {a = -3, b = 4.5, c = 5}
// gdb-command:print *owned
// gdb-check:$10 = 6
// === LLDB TESTS ==================================================================================
@ -44,6 +57,20 @@
// lldb-command:print *owned
// lldb-check:[...]$4 = 6
// lldb-command:continue
// lldb-command:print variable
// lldb-check:[...]$5 = 2
// lldb-command:print constant
// lldb-check:[...]$6 = 2
// lldb-command:print a_struct
// lldb-check:[...]$7 = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
// lldb-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
// lldb-check:[...]$9 = 6
#![feature(unboxed_closures)]
#![allow(unused_variables)]
struct Struct {
@ -65,12 +92,22 @@ fn main() {
let struct_ref = &a_struct;
let owned = box 6;
let closure = || {
zzz(); // #break
variable = constant + a_struct.a + struct_ref.a + *owned;
};
{
let closure = || {
zzz(); // #break
variable = constant + a_struct.a + struct_ref.a + *owned;
};
closure();
closure();
}
{
let mut unboxed_closure = |&mut:| {
zzz(); // #break
variable = constant + a_struct.a + struct_ref.a + *owned;
};
unboxed_closure();
}
}
fn zzz() {()}

View File

@ -8,18 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[deriving(PartialEq, PartialOrd)]
#[deriving(Eq, PartialEq, PartialOrd, Ord)]
enum Test<'a> {
Int(&'a int),
Slice(&'a [u8]),
}
#[deriving(PartialEq, PartialOrd)]
#[deriving(Eq, PartialEq, PartialOrd, Ord)]
struct Version {
vendor_info: &'static str
}
#[deriving(PartialEq, PartialOrd)]
#[deriving(Eq, PartialEq, PartialOrd, Ord)]
struct Foo(&'static str);
fn main() {}

View File

@ -0,0 +1,22 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Foo<T> {
fn get(&self) -> T;
}
impl Foo<i32> for i32 {
fn get(&self) -> i32 { *self }
}
fn main() {
let x: i32 = 1;
Foo::<i32>::get(&x);
}

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-test
extern crate libc;
use std::io::process::Command;
@ -18,51 +16,38 @@ use std::iter::IteratorExt;
use libc::funcs::posix88::unistd;
// "ps -A -o pid,sid,command" with GNU ps should output something like this:
// PID SID COMMAND
// 1 1 /sbin/init
// The output from "ps -A -o pid,ppid,args" should look like this:
// PID PPID COMMAND
// 1 0 /sbin/init
// 2 0 [kthreadd]
// 3 0 [ksoftirqd/0]
// ...
// 12562 9237 ./spawn-failure
// 12563 9237 [spawn-failure] <defunct>
// 12564 9237 [spawn-failure] <defunct>
// 6076 9064 /bin/zsh
// ...
// 12592 9237 [spawn-failure] <defunct>
// 12593 9237 ps -A -o pid,sid,command
// 12884 12884 /bin/zsh
// 12922 12922 /bin/zsh
// 7164 6076 ./spawn-failure
// 7165 7164 [spawn-failure] <defunct>
// 7166 7164 [spawn-failure] <defunct>
// ...
// 7197 7164 [spawn-failure] <defunct>
// 7198 7164 ps -A -o pid,ppid,command
// ...
#[cfg(unix)]
fn find_zombies() {
// http://man.freebsd.org/ps(1)
// http://man7.org/linux/man-pages/man1/ps.1.html
#[cfg(not(target_os = "macos"))]
const FIELDS: &'static str = "pid,sid,command";
let my_pid = unsafe { unistd::getpid() };
// https://developer.apple.com/library/mac/documentation/Darwin/
// Reference/ManPages/man1/ps.1.html
#[cfg(target_os = "macos")]
const FIELDS: &'static str = "pid,sess,command";
let my_sid = unsafe { unistd::getsid(0) };
let ps_cmd_output = Command::new("ps").args(&["-A", "-o", FIELDS]).output().unwrap();
// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
let ps_cmd_output = Command::new("ps").args(&["-A", "-o", "pid,ppid,args"]).output().unwrap();
let ps_output = String::from_utf8_lossy(ps_cmd_output.output.as_slice());
let found = ps_output.split('\n').enumerate().any(|(line_no, line)|
0 < line_no && 0 < line.len() &&
my_sid == from_str(line.split(' ').filter(|w| 0 < w.len()).nth(1)
.expect("1st column should be Session ID")
).expect("Session ID string into integer") &&
line.contains("defunct") && {
println!("Zombie child {}", line);
true
for (line_no, line) in ps_output.split('\n').enumerate() {
if 0 < line_no && 0 < line.len() &&
my_pid == from_str(line.split(' ').filter(|w| 0 < w.len()).nth(1)
.expect("1st column should be PPID")
).expect("PPID string into integer") &&
line.contains("defunct") {
panic!("Zombie child {}", line);
}
);
assert!( ! found, "Found at least one zombie child");
}
}
#[cfg(windows)]
@ -71,10 +56,13 @@ fn find_zombies() { }
fn main() {
let too_long = format!("/NoSuchCommand{:0300}", 0u8);
for _ in range(0u32, 100) {
let invalid = Command::new(too_long.as_slice()).spawn();
assert!(invalid.is_err());
}
let _failures = Vec::from_fn(100, |_i| {
let cmd = Command::new(too_long.as_slice());
let failed = cmd.spawn();
assert!(failed.is_err(), "Make sure the command fails to spawn(): {}", cmd);
failed
});
find_zombies();
// then _failures goes out of scope
}