diff options
Diffstat (limited to 'src')
66 files changed, 982 insertions, 1100 deletions
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 7fbe772b7f5..01c4e99b77c 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -224,7 +224,7 @@ pub fn run_tests(config: &Config) { // android debug-info test uses remote debugger // so, we test 1 task at once. // also trying to isolate problems with adb_run_wrapper.sh ilooping - env::set_var("RUST_TEST_TASKS","1"); + env::set_var("RUST_TEST_THREADS","1"); } match config.mode { @@ -232,7 +232,7 @@ pub fn run_tests(config: &Config) { // Some older versions of LLDB seem to have problems with multiple // instances running in parallel, so only run one test task at a // time. - env::set_var("RUST_TEST_TASKS", "1"); + env::set_var("RUST_TEST_THREADS", "1"); } _ => { /* proceed */ } } diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 21cebc61b3a..29123173f5b 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -131,7 +131,7 @@ pub fn load_props(testfile: &Path) -> TestProps { true }); - for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_TASKS"] { + for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { match env::var(key) { Ok(val) => if exec_env.iter().find(|&&(ref x, _)| *x == key.to_string()).is_none() { @@ -163,6 +163,9 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool { fn ignore_target(config: &Config) -> String { format!("ignore-{}", util::get_os(&config.target)) } + fn ignore_architecture(config: &Config) -> String { + format!("ignore-{}", util::get_arch(&config.target)) + } fn ignore_stage(config: &Config) -> String { format!("ignore-{}", config.stage_id.split('-').next().unwrap()) @@ -226,6 +229,7 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool { let val = iter_header(testfile, &mut |ln| { !parse_name_directive(ln, "ignore-test") && !parse_name_directive(ln, &ignore_target(config)) && + !parse_name_directive(ln, &ignore_architecture(config)) && !parse_name_directive(ln, &ignore_stage(config)) && !(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) && !(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) && diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 16e2806f72c..2e11cf47d1e 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -25,6 +25,23 @@ const OS_TABLE: &'static [(&'static str, &'static str)] = &[ ("openbsd", "openbsd"), ]; +const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ + ("i386", "x86"), + ("i686", "x86"), + ("amd64", "x86_64"), + ("x86_64", "x86_64"), + ("sparc", "sparc"), + ("powerpc", "powerpc"), + ("arm64", "aarch64"), + ("arm", "arm"), + ("aarch64", "aarch64"), + ("mips", "mips"), + ("xcore", "xcore"), + ("msp430", "msp430"), + ("hexagon", "hexagon"), + ("s390x", "systemz"), +]; + pub fn get_os(triple: &str) -> &'static str { for &(triple_os, os) in OS_TABLE { if triple.contains(triple_os) { @@ -33,6 +50,14 @@ pub fn get_os(triple: &str) -> &'static str { } panic!("Cannot determine OS from triple"); } +pub fn get_arch(triple: &str) -> &'static str { + for &(triple_arch, arch) in ARCH_TABLE { + if triple.contains(triple_arch) { + return arch + } + } + panic!("Cannot determine Architecture from triple"); +} pub fn make_new_path(path: &str) -> String { assert!(cfg!(windows)); diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index c65389287fb..6ff51e8d1b9 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -14,7 +14,6 @@ * [Strings](strings.md) * [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md) * [Standard Input](standard-input.md) - * [Guessing Game](guessing-game.md) * [II: Intermediate Rust](intermediate.md) * [Crates and Modules](crates-and-modules.md) * [Testing](testing.md) diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md index a226e4d0bf9..86279f7f1a1 100644 --- a/src/doc/trpl/advanced-macros.md +++ b/src/doc/trpl/advanced-macros.md @@ -6,9 +6,11 @@ off. # Syntactic requirements Even when Rust code contains un-expanded macros, it can be parsed as a full -syntax tree. This property can be very useful for editors and other tools that -process code. It also has a few consequences for the design of Rust's macro -system. +[syntax tree][ast]. This property can be very useful for editors and other +tools that process code. It also has a few consequences for the design of +Rust's macro system. + +[ast]: glossary.html#abstract-syntax-tree One consequence is that Rust must determine, when it parses a macro invocation, whether the macro stands in for diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 20b0ffc1b28..018f35337f3 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -170,6 +170,8 @@ Foreign libraries often hand off ownership of resources to the calling code. When this occurs, we must use Rust's destructors to provide safety and guarantee the release of these resources (especially in the case of panic). +For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html). + # Callbacks from C code to Rust functions Some external libraries require the usage of callbacks to report back their diff --git a/src/doc/trpl/glossary.md b/src/doc/trpl/glossary.md index 156f3374867..97898324847 100644 --- a/src/doc/trpl/glossary.md +++ b/src/doc/trpl/glossary.md @@ -14,3 +14,26 @@ let z = (8, 2, 6); ``` In the example above `x` and `y` have arity 2. `z` has arity 3. + +### Abstract Syntax Tree + +When a compiler is compiling your program, it does a number of different +things. One of the things that it does is turn the text of your program into an +'abstract syntax tree,' or 'AST.' This tree is a representation of the +structure of your program. For example, `2 + 3` can be turned into a tree: + +```text + + + / \ +2 3 +``` + +And `2 + (3 * 4)` would look like this: + +```text + + + / \ +2 * + / \ + 3 4 +``` diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md deleted file mode 100644 index 4e7222269a8..00000000000 --- a/src/doc/trpl/guessing-game.md +++ /dev/null @@ -1,893 +0,0 @@ -% Guessing Game - -Okay! We've got the basics of Rust down. Let's write a bigger program. - -For our first project, we'll implement a classic beginner programming problem: -the guessing game. Here's how it works: Our program will generate a random -integer between one and a hundred. It will then prompt us to enter a guess. -Upon entering our guess, it will tell us if we're too low or too high. Once we -guess correctly, it will congratulate us. Sound good? - -## Set up - -Let's set up a new project. Go to your projects directory. Remember how we -had to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo -has a command that does that for us. Let's give it a shot: - -```{bash} -$ cd ~/projects -$ cargo new guessing_game --bin -$ cd guessing_game -``` - -We pass the name of our project to `cargo new`, and then the `--bin` flag, -since we're making a binary, rather than a library. - -Check out the generated `Cargo.toml`: - -```toml -[package] - -name = "guessing_game" -version = "0.0.1" -authors = ["Your Name <you@example.com>"] -``` - -Cargo gets this information from your environment. If it's not correct, go ahead -and fix that. - -Finally, Cargo generated a "Hello, world!" for us. Check out `src/main.rs`: - -```{rust} -fn main() { - println!("Hello, world!") -} -``` - -Let's try compiling what Cargo gave us: - -```{bash} -$ cargo build - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) -``` - -Excellent! Open up your `src/main.rs` again. We'll be writing all of -our code in this file. We'll talk about multiple-file projects later on in the -guide. - -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: - -```bash -$ cargo run - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) - Running `target/guessing_game` -Hello, world! -``` - -Great! The `run` command comes in handy when you need to rapidly iterate on a project. -Our game is just such a project, we need to quickly test each iteration before moving on to the next one. - -## Processing a Guess - -Let's get to it! The first thing we need to do for our guessing game is -allow our player to input a guess. Put this in your `src/main.rs`: - -```{rust,no_run} -use std::old_io; - -fn main() { - println!("Guess the number!"); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - - println!("You guessed: {}", input); -} -``` - -You've seen this code before, when we talked about standard input. We -import the `std::old_io` module with `use`, and then our `main` function contains -our program's logic. We print a little message announcing the game, ask the -user to input a guess, get their input, and then print it out. - -Because we talked about this in the section on standard I/O, I won't go into -more details here. If you need a refresher, go re-read that section. - -## Generating a secret number - -Next, we need to generate a secret number. To do that, we need to use Rust's -random number generation, which we haven't talked about yet. Rust includes a -bunch of interesting functions in its standard library. If you need a bit of -code, it's possible that it's already been written for you! In this case, -we do know that Rust has random number generation, but we don't know how to -use it. - -Enter the docs. Rust has a page specifically to document the standard library. -You can find that page [here](../std/index.html). There's a lot of information on -that page, but the best part is the search bar. Right up at the top, there's -a box that you can enter in a search term. The search is pretty primitive -right now, but is getting better all the time. If you type "random" in that -box, the page will update to [this one](../std/index.html?search=random). The very -first result is a link to [`std::rand::random`](../std/rand/fn.random.html). If we -click on that result, we'll be taken to its documentation page. - -This page shows us a few things: the type signature of the function, some -explanatory text, and then an example. Let's try to modify our code to add in the -`random` function and see what happens: - -```{rust,ignore} -use std::old_io; -use std::rand; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random() % 100) + 1; // secret_number: i32 - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - - - println!("You guessed: {}", input); -} -``` - -The first thing we changed was to `use std::rand`, as the docs -explained. We then added in a `let` expression to create a variable binding -named `secret_number`, and we printed out its result. - -Also, you may wonder why we are using `%` on the result of `rand::random()`. -This operator is called *modulo*, and it returns the remainder of a division. -By taking the modulo of the result of `rand::random()`, we're limiting the -values to be between 0 and 99. Then, we add one to the result, making it from 1 -to 100. Using modulo can give you a very, very small bias in the result, but -for this example, it is not important. - -Let's try to compile this using `cargo build`: - -```bash -$ 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 -src/main.rs:7 let secret_number = (rand::random() % 100) + 1; - ^~~~~~~~ -error: aborting due to previous error -``` - -It didn't work! Rust says "the type of this value must be known in this -context." What's up with that? Well, as it turns out, `rand::random()` can -generate many kinds of random values, not just integers. And in this case, Rust -isn't sure what kind of value `random()` should generate. So we have to help -it. With number literals, we can just add an `i32` onto the end to tell Rust they're -integers, but that does not work with functions. There's a different syntax, -and it looks like this: - -```{rust,ignore} -rand::random::<i32>(); -``` - -This says "please give me a random `i32` value." We can change our code to use -this hint: - -```{rust,no_run} -use std::old_io; -use std::rand; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<i32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - - - println!("You guessed: {}", input); -} -``` - -Try running our new program a few times: - -```bash -$ cargo run - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) - Running `target/guessing_game` -Guess the number! -The secret number is: 7 -Please input your guess. -4 -You guessed: 4 -$ ./target/guessing_game -Guess the number! -The secret number is: 83 -Please input your guess. -5 -You guessed: 5 -$ ./target/guessing_game -Guess the number! -The secret number is: -29 -Please input your guess. -42 -You guessed: 42 -``` - -Wait. Negative 29? We wanted a number between one and a hundred! We have two -options here: we can either ask `random()` to generate an unsigned integer, which -can only be positive, or we can use the `abs()` function. Let's go with the -unsigned integer approach. If we want a random positive number, we should ask for -a random positive number. Our code looks like this now: - -```{rust,no_run} -use std::old_io; -use std::rand; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - - - println!("You guessed: {}", input); -} -``` - -And trying it out: - -```bash -$ cargo run - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) - Running `target/guessing_game` -Guess the number! -The secret number is: 57 -Please input your guess. -3 -You guessed: 3 -``` - -Great! Next up: let's compare our guess to the secret guess. - -## Comparing guesses - -If you remember, earlier in the guide, we made a `cmp` function that compared -two numbers. Let's add that in, along with a `match` statement to compare our -guess to the secret number: - -```{rust,ignore} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - - - println!("You guessed: {}", input); - - match cmp(input, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } -} - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -If we try to compile, we'll get some errors: - -```bash -$ 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 `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String) -src/main.rs:20 match cmp(input, secret_number) { - ^~~~~ -src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `u32` (expected i32 but found u32) -src/main.rs:20 match cmp(input, secret_number) { - ^~~~~~~~~~~~~ -error: aborting due to 2 previous errors -``` - -This often happens when writing Rust programs, and is one of Rust's greatest -strengths. You try out some code, see if it compiles, and Rust tells you that -you've done something wrong. In this case, our `cmp` function works on integers, -but we've given it unsigned integers. In this case, the fix is easy, because -we wrote the `cmp` function! Let's change it to take `u32`s: - -```{rust,ignore} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - - - println!("You guessed: {}", input); - - match cmp(input, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -And try compiling again: - -```bash -$ 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 `u32` but found `collections::string::String` (expected u32 but found struct collections::string::String) -src/main.rs:20 match cmp(input, secret_number) { - ^~~~~ -error: aborting due to previous error -``` - -This error is similar to the last one: we expected to get a `u32`, 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: - -```bash -$ ./target/guessing_game -Guess the number! -The secret number is: 73 -Please input your guess. -hello -You guessed: hello -``` - -Oops! Also, you'll note that we just ran our program even though it didn't compile. -This works because the older version we did successfully compile was still lying -around. Gotta be careful! - -Anyway, we have a `String`, but we need a `u32`. What to do? Well, there's -a function for that: - -```{rust,ignore} -let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); -let input_num: Result<u32, _> = input.parse(); -``` - -The `parse` function takes in a `&str` value and converts it into something. -We tell it what kind of something with a type hint. Remember our type hint with -`random()`? It looked like this: - -```{rust,ignore} -rand::random::<u32>(); -``` - -There's an alternate way of providing a hint too, and that's declaring the type -in a `let`: - -```{rust,ignore} -let x: u32 = rand::random(); -``` - -In this case, we say `x` is a `u32` explicitly, so Rust is able to properly -tell `random()` what to generate. In a similar fashion, both of these work: - -```{rust,ignore} -let input_num_option = "5".parse::<u32>().ok(); // input_num: Option<u32> -let input_num_result: Result<u32, _> = "5".parse(); // input_num: Result<u32, <u32 as FromStr>::Err> -``` - -Above, we're converting the `Result` returned by `parse` to an `Option` by using -the `ok` method as well. Anyway, with us now converting our input to a number, -our code looks like this: - -```{rust,ignore} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - let input_num: Result<u32, _> = input.parse(); - - println!("You guessed: {:?}", input_num); - - match cmp(input_num, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -Let's try it out! - -```bash -$ cargo build - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) -src/main.rs:21:15: 21:24 error: mismatched types: expected `u32`, found `core::result::Result<u32, core::num::ParseIntError>` (expected u32, found enum `core::result::Result`) [E0308] -src/main.rs:21 match cmp(input_num, secret_number) { - ^~~~~~~~~ -error: aborting due to previous error -``` - -Oh yeah! Our `input_num` has the type `Result<u32, <some error>>`, rather than `u32`. We -need to unwrap the Result. If you remember from before, `match` is a great way -to do that. Try this code: - -```{rust,no_run} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - let input_num: Result<u32, _> = input.parse(); - - let num = match input_num { - Ok(n) => n, - Err(_) => { - println!("Please input a number!"); - return; - } - }; - - - println!("You guessed: {}", num); - - match cmp(num, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -We use a `match` to either give us the `u32` inside of the `Result`, or else -print an error message and return. Let's give this a shot: - -```bash -$ cargo run - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) - Running `target/guessing_game` -Guess the number! -The secret number is: 17 -Please input your guess. -5 -Please input a number! -``` - -Uh, what? But we did! - -... actually, we didn't. See, when you get a line of input from `stdin()`, -you get all the input. Including the `\n` character from you pressing Enter. -Therefore, `parse()` sees the string `"5\n"` and says "nope, that's not a -number; there's non-number stuff in there!" Luckily for us, `&str`s have an easy -method we can use defined on them: `trim()`. One small modification, and our -code looks like this: - -```{rust,no_run} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - let input_num: Result<u32, _> = input.trim().parse(); - - let num = match input_num { - Ok(num) => num, - Err(_) => { - println!("Please input a number!"); - return; - } - }; - - - println!("You guessed: {}", num); - - match cmp(num, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -Let's try it! - -```bash -$ cargo run - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) - Running `target/guessing_game` -Guess the number! -The secret number is: 58 -Please input your guess. - 76 -You guessed: 76 -Too big! -``` - -Nice! You can see I even added spaces before my guess, and it still figured -out that I guessed 76. Run the program a few times, and verify that guessing -the number works, as well as guessing a number too small. - -The Rust compiler helped us out quite a bit there! This technique is called -"leaning on the compiler", and it's often useful when working on some code. -Let the error messages help guide you towards the correct types. - -Now we've got most of the game working, but we can only make one guess. Let's -change that by adding loops! - -## Looping - -As we already discussed, the `loop` keyword gives us an infinite loop. -Let's add that in: - -```{rust,no_run} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - loop { - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - let input_num: Result<u32, _> = input.trim().parse(); - - let num = match input_num { - Ok(num) => num, - Err(_) => { - println!("Please input a number!"); - return; - } - }; - - - println!("You guessed: {}", num); - - match cmp(num, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -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: - -```bash -$ cargo run - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) - Running `target/guessing_game` -Guess the number! -The secret number is: 59 -Please input your guess. -45 -You guessed: 45 -Too small! -Please input your guess. -60 -You guessed: 60 -Too big! -Please input your guess. -59 -You guessed: 59 -You win! -Please input your guess. -quit -Please input a number! -``` - -Ha! `quit` actually quits. As does any other non-number input. Well, this is -suboptimal to say the least. First, let's actually quit when you win the game: - -```{rust,no_run} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - loop { - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - let input_num: Result<u32, _> = input.trim().parse(); - - let num = match input_num { - Ok(num) => num, - Err(_) => { - println!("Please input a number!"); - return; - } - }; - - - println!("You guessed: {}", num); - - match cmp(num, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => { - println!("You win!"); - return; - }, - } - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -By adding the `return` line after the `You win!`, we'll exit the program when -we win. We have just one more tweak to make: when someone inputs a non-number, -we don't want to quit, we just want to ignore it. Change that `return` to -`continue`: - - -```{rust,no_run} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - println!("The secret number is: {}", secret_number); - - loop { - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - let input_num: Result<u32, _> = input.trim().parse(); - - let num = match input_num { - Ok(num) => num, - Err(_) => { - println!("Please input a number!"); - continue; - } - }; - - - println!("You guessed: {}", num); - - match cmp(num, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => { - println!("You win!"); - return; - }, - } - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -Now we should be good! Let's try: - -```bash -$ cargo run - Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) - Running `target/guessing_game` -Guess the number! -The secret number is: 61 -Please input your guess. -10 -You guessed: 10 -Too small! -Please input your guess. -99 -You guessed: 99 -Too big! -Please input your guess. -foo -Please input a number! -Please input your guess. -61 -You guessed: 61 -You win! -``` - -Awesome! With one tiny last tweak, we have finished the guessing game. Can you -think of what it is? That's right, we don't want to print out the secret number. -It was good for testing, but it kind of ruins the game. Here's our final source: - -```{rust,no_run} -use std::old_io; -use std::rand; -use std::cmp::Ordering; - -fn main() { - println!("Guess the number!"); - - let secret_number = (rand::random::<u32>() % 100) + 1; - - loop { - - println!("Please input your guess."); - - let input = old_io::stdin().read_line() - .ok() - .expect("Failed to read line"); - let input_num: Result<u32, _> = input.trim().parse(); - - let num = match input_num { - Ok(num) => num, - Err(_) => { - println!("Please input a number!"); - continue; - } - }; - - - println!("You guessed: {}", num); - - match cmp(num, secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => { - println!("You win!"); - return; - }, - } - } -} - -fn cmp(a: u32, b: u32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} -``` - -## Complete! - -At this point, you have successfully built the Guessing Game! Congratulations! - -You've now learned the basic syntax of Rust. All of this is relatively close to -various other programming languages you have used in the past. These -fundamental syntactical and semantic elements will form the foundation for the -rest of your Rust education. - -Now that you're an expert at the basics, it's time to learn about some of -Rust's more unique features. diff --git a/src/doc/trpl/pointers.md b/src/doc/trpl/pointers.md index 930a40c5050..39106aaf857 100644 --- a/src/doc/trpl/pointers.md +++ b/src/doc/trpl/pointers.md @@ -561,38 +561,40 @@ fn main() { In this case, Rust knows that `x` is being *borrowed* by the `add_one()` function, and since it's only reading the value, allows it. -We can borrow `x` multiple times, as long as it's not simultaneous: +We can borrow `x` as read-only multiple times, even simultaneously: ```{rust} -fn add_one(x: &i32) -> i32 { - *x + 1 +fn add(x: &i32, y: &i32) -> i32 { + *x + *y } fn main() { let x = Box::new(5); - println!("{}", add_one(&*x)); - println!("{}", add_one(&*x)); - println!("{}", add_one(&*x)); + println!("{}", add(&x, &x)); + println!("{}", add(&x, &x)); } ``` -Or as long as it's not a mutable borrow. This will error: +We can mutably borrow `x` multiple times, but only if x itself is mutable, and +it may not be *simultaneously* borrowed: ```{rust,ignore} -fn add_one(x: &mut i32) -> i32 { - *x + 1 +fn increment(x: &mut i32) { + *x += 1; } fn main() { - let x = Box::new(5); + // If variable x is not "mut", this will not compile + let mut x = Box::new(5); - println!("{}", add_one(&*x)); // error: cannot borrow immutable dereference - // of `&`-pointer as mutable + increment(&mut x); + increment(&mut x); + println!("{}", x); } ``` -Notice we changed the signature of `add_one()` to request a mutable reference. +Notice the signature of `increment()` requests a mutable reference. ## Best practices diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 4e14085599b..11f0b8e1ddb 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -93,10 +93,6 @@ offered by the Rust language and libraries. For example, they - are plain-old-data, that is, they don't move ownership, again unlike `Box`, hence the Rust compiler cannot protect against bugs like use-after-free; -- are considered sendable (if their contents is considered sendable), - so the compiler offers no assistance with ensuring their use is - thread-safe; for example, one can concurrently access a `*mut i32` - from two threads without synchronization. - lack any form of lifetimes, unlike `&`, and so the compiler cannot reason about dangling pointers; and - have no guarantees about aliasing or mutability other than mutation diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 8befb0579c3..8528be2860c 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -210,6 +210,21 @@ impl<T> Arc<T> { // contents. unsafe { &**self._ptr } } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + let ptr = *self._ptr; + + // Destroy the data at this time, even though we may not free the box allocation itself + // (there may still be weak pointers lying around). + drop(ptr::read(&self.inner().data)); + + if self.inner().weak.fetch_sub(1, Release) == 1 { + atomic::fence(Acquire); + deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(), min_align_of::<ArcInner<T>>()) + } + } } /// Get the number of weak references to this value. @@ -325,6 +340,7 @@ impl<T: Sync + Send> Drop for Arc<T> { /// /// } // implicit drop /// ``` + #[inline] fn drop(&mut self) { // This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but // it is guaranteed to be zeroed after the first if it's run more than once) @@ -353,14 +369,8 @@ impl<T: Sync + Send> Drop for Arc<T> { // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) atomic::fence(Acquire); - // Destroy the data at this time, even though we may not free the box allocation itself - // (there may still be weak pointers lying around). - unsafe { drop(ptr::read(&self.inner().data)); } - - if self.inner().weak.fetch_sub(1, Release) == 1 { - atomic::fence(Acquire); - unsafe { deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(), - min_align_of::<ArcInner<T>>()) } + unsafe { + self.drop_slow() } } } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 156bc2708fb..17ef0ecb1c0 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -345,6 +345,16 @@ pub trait Int /// Saturating integer addition. Computes `self + other`, saturating at /// the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// ``` + /// use std::num::Int; + /// + /// assert_eq!(5u16.saturating_add(65534), 65535); + /// assert_eq!((-5i16).saturating_add(-32767), -32768); + /// assert_eq!(100u32.saturating_add(4294967294), 4294967295); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] fn saturating_add(self, other: Self) -> Self { @@ -357,6 +367,16 @@ pub trait Int /// Saturating integer subtraction. Computes `self - other`, saturating at /// the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// ``` + /// use std::num::Int; + /// + /// assert_eq!(5u16.saturating_sub(65534), 0); + /// assert_eq!(5i16.saturating_sub(-32767), 32767); + /// assert_eq!(100u32.saturating_sub(4294967294), 0); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] fn saturating_sub(self, other: Self) -> Self { diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 9eeb9b869ce..7bf248917a5 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -25,7 +25,7 @@ use super::CharEq; /// /// The trait itself acts as a builder for an associated /// `Searcher` type, which does the actual work of finding -/// occurences of the pattern in a string. +/// occurrences of the pattern in a string. pub trait Pattern<'a>: Sized { /// Associated searcher for this pattern type Searcher: Searcher<'a>; @@ -72,7 +72,7 @@ pub enum SearchStep { /// Expresses that `haystack[a..b]` has been rejected as a possible match /// of the pattern. /// - /// Note that there might be more than one `Reject` betwen two `Match`es, + /// Note that there might be more than one `Reject` between two `Match`es, /// there is no requirement for them to be combined into one. Reject(usize, usize), /// Expresses that every byte of the haystack has been visted, ending diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index c634a46888e..4537fc763c9 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -183,10 +183,9 @@ use std::io::{self, Stderr}; use std::io::prelude::*; use std::mem; use std::env; -use std::ptr; use std::rt; use std::slice; -use std::sync::{Once, ONCE_INIT}; +use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT}; use directive::LOG_LEVEL_NAMES; @@ -202,6 +201,8 @@ pub const MAX_LOG_LEVEL: u32 = 255; /// The default logging level of a crate if no other is specified. const DEFAULT_LOG_LEVEL: u32 = 1; +static LOCK: StaticMutex = MUTEX_INIT; + /// An unsafe constant that is the maximum logging level of any module /// specified. This is the first line of defense to determining whether a /// logging statement should be run. @@ -286,9 +287,18 @@ impl Drop for DefaultLogger { pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // Test the literal string from args against the current filter, if there // is one. - match unsafe { FILTER.as_ref() } { - Some(filter) if !args.to_string().contains(&filter[..]) => return, - _ => {} + unsafe { + let _g = LOCK.lock(); + match FILTER as uint { + 0 => {} + 1 => panic!("cannot log after main thread has exited"), + n => { + let filter = mem::transmute::<_, &String>(n); + if !args.to_string().contains(&filter[..]) { + return + } + } + } } // Completely remove the local logger from TLS in case anyone attempts to @@ -370,9 +380,15 @@ pub fn mod_enabled(level: u32, module: &str) -> bool { // This assertion should never get tripped unless we're in an at_exit // handler after logging has been torn down and a logging attempt was made. - assert!(unsafe { !DIRECTIVES.is_null() }); - enabled(level, module, unsafe { (*DIRECTIVES).iter() }) + let _g = LOCK.lock(); + unsafe { + assert!(DIRECTIVES as uint != 0); + assert!(DIRECTIVES as uint != 1, + "cannot log after the main thread has exited"); + + enabled(level, module, (*DIRECTIVES).iter()) + } } fn enabled(level: u32, @@ -428,14 +444,14 @@ fn init() { // Schedule the cleanup for the globals for when the runtime exits. rt::at_exit(move || { + let _g = LOCK.lock(); assert!(!DIRECTIVES.is_null()); - let _directives: Box<Vec<directive::LogDirective>> = - Box::from_raw(DIRECTIVES); - DIRECTIVES = ptr::null_mut(); + let _directives = Box::from_raw(DIRECTIVES); + DIRECTIVES = 1 as *mut _; if !FILTER.is_null() { - let _filter: Box<String> = Box::from_raw(FILTER); - FILTER = 0 as *mut _; + let _filter = Box::from_raw(FILTER); + FILTER = 1 as *mut _; } }); } diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 5d1fbc32f14..1a794f56f80 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -1061,7 +1061,7 @@ pub mod writer { } /// Returns the current position while marking it stable, i.e. - /// generated bytes so far woundn't be affected by relaxation. + /// generated bytes so far wouldn't be affected by relaxation. pub fn mark_stable_position(&mut self) -> u64 { let pos = self.writer.seek(SeekFrom::Current(0)).unwrap(); if self.relax_limit < pos { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index faadf669a43..bffcb93bc6d 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -236,12 +236,27 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { pub fn tr_span(&self, span: Span) -> Span { let imported_filemaps = &self.cdata.codemap_import_info[..]; + let span = if span.lo > span.hi { + // Currently macro expansion sometimes produces invalid Span values + // where lo > hi. In order not to crash the compiler when trying to + // translate these values, let's transform them into something we + // can handle (and which will produce useful debug locations at + // least some of the time). + // This workaround is only necessary as long as macro expansion is + // not fixed. FIXME(#23480) + codemap::mk_sp(span.lo, span.lo) + } else { + span + }; + let filemap_index = { // Optimize for the case that most spans within a translated item // originate from the same filemap. let last_filemap_index = self.last_filemap_index.get(); if span.lo >= imported_filemaps[last_filemap_index].original_start_pos && + span.lo <= imported_filemaps[last_filemap_index].original_end_pos && + span.hi >= imported_filemaps[last_filemap_index].original_start_pos && span.hi <= imported_filemaps[last_filemap_index].original_end_pos { last_filemap_index } else { diff --git a/src/librustc_back/tempdir.rs b/src/librustc_back/tempdir.rs index 4d8619a8121..0e87ba278db 100644 --- a/src/librustc_back/tempdir.rs +++ b/src/librustc_back/tempdir.rs @@ -61,12 +61,12 @@ impl TempDir { let path = tmpdir.join(&leaf); match fs::create_dir(&path) { Ok(_) => return Ok(TempDir { path: Some(path) }), - Err(ref e) if e.kind() == ErrorKind::PathAlreadyExists => {} + Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {} Err(e) => return Err(e) } } - Err(Error::new(ErrorKind::PathAlreadyExists, + Err(Error::new(ErrorKind::AlreadyExists, "too many temporary directories already exist", None)) } diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 97278eb0512..8d228c22c3c 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -264,7 +264,7 @@ pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { } /// Get the LLVM type corresponding to a Rust type, i.e. `middle::ty::Ty`. -/// This is the right LLVM type for an alloca containg a value of that type, +/// This is the right LLVM type for an alloca containing a value of that type, /// and the pointee of an Lvalue Datum (which is always a LLVM pointer). /// For unsized types, the returned type is a fat pointer, thus the resulting /// LLVM type for a `Trait` Lvalue is `{ i8*, void(i8*)** }*`, which is a double diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 2b937768e2e..5a4ccc0b7b4 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -225,7 +225,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// } /// ``` /// - /// Here, the region of `b` will be `<R0>`. `<R0>` is constrainted to be some subregion of the + /// Here, the region of `b` will be `<R0>`. `<R0>` is constrained to be some subregion of the /// block B and some superregion of the call. If we forced it now, we'd choose the smaller /// region (the call). But that would make the *b illegal. Since we don't resolve, the type /// of b will be `&<R0>.int` and then `*b` will require that `<R0>` be bigger than the let and diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 17fc2aad286..09592db8a11 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -294,7 +294,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { /// Indicates that `cmt` is being directly mutated (e.g., assigned /// to). If cmt contains any by-ref upvars, this implies that - /// those upvars must be borrowed using an `&mut` borow. + /// those upvars must be borrowed using an `&mut` borrow. fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { debug!("adjust_upvar_borrow_kind_for_mut(cmt={})", cmt.repr(self.tcx())); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f97470dbaed..81daac7b90f 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -692,16 +692,23 @@ fn shortty(item: &clean::Item) -> ItemType { /// Takes a path to a source file and cleans the path to it. This canonicalizes /// things like ".." to components which preserve the "top down" hierarchy of a -/// static HTML tree. +/// static HTML tree. Each component in the cleaned path will be passed as an +/// argument to `f`. The very last component of the path (ie the file name) will +/// be passed to `f` if `keep_filename` is true, and ignored otherwise. // FIXME (#9639): The closure should deal with &[u8] instead of &str // FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths -fn clean_srcpath<F>(src_root: &Path, p: &Path, mut f: F) where +fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) where F: FnMut(&str), { // make it relative, if possible let p = p.relative_from(src_root).unwrap_or(p); - for c in p.iter().map(|x| x.to_str().unwrap()) { + let mut iter = p.iter().map(|x| x.to_str().unwrap()).peekable(); + while let Some(c) = iter.next() { + if !keep_filename && iter.peek().is_none() { + break; + } + if ".." == c { f("up"); } else { @@ -803,7 +810,7 @@ impl<'a> SourceCollector<'a> { // Create the intermediate directories let mut cur = self.dst.clone(); let mut root_path = String::from_str("../../"); - clean_srcpath(&self.cx.src_root, &p, |component| { + clean_srcpath(&self.cx.src_root, &p, false, |component| { cur.push(component); mkdir(&cur).unwrap(); root_path.push_str("../"); @@ -1368,7 +1375,7 @@ impl<'a> Item<'a> { if ast_util::is_local(self.item.def_id) { let mut path = Vec::new(); clean_srcpath(&cx.src_root, Path::new(&self.item.source.filename), - |component| { + true, |component| { path.push(component.to_string()); }); let href = if self.item.source.loline == self.item.source.hiline { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index bd4177861dd..0650b4d5158 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -35,7 +35,6 @@ #![feature(test)] #![feature(unicode)] #![feature(str_words)] -#![feature(io)] #![feature(file_path)] #![feature(path_ext)] #![feature(path_relative_from)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 31c270dca6b..90cb88046e5 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -31,7 +31,6 @@ Core encoding and decoding interfaces. #![feature(collections)] #![feature(core)] #![feature(int_uint)] -#![feature(io)] #![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs index b02f68c1630..4b319cdd437 100644 --- a/src/libstd/fs/mod.rs +++ b/src/libstd/fs/mod.rs @@ -73,6 +73,11 @@ pub struct Metadata(fs_imp::FileAttr); /// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry` /// information like the entry's path and possibly other metadata can be /// learned. +/// +/// # Failure +/// +/// This `io::Result` will be an `Err` if there's some sort of intermittent +/// IO error during iteration. #[stable(feature = "rust1", since = "1.0.0")] pub struct ReadDir(fs_imp::ReadDir); @@ -493,7 +498,7 @@ pub fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> { let from = from.as_path(); let to = to.as_path(); if !from.is_file() { - return Err(Error::new(ErrorKind::MismatchedFileTypeForOperation, + return Err(Error::new(ErrorKind::InvalidInput, "the source path is not an existing file", None)) } @@ -1134,7 +1139,7 @@ mod tests { let dir = &tmpdir.join("mkdir_error_twice"); check!(fs::create_dir(dir)); let e = fs::create_dir(dir).err().unwrap(); - assert_eq!(e.kind(), ErrorKind::PathAlreadyExists); + assert_eq!(e.kind(), ErrorKind::AlreadyExists); } #[test] diff --git a/src/libstd/fs/tempdir.rs b/src/libstd/fs/tempdir.rs index c1da77a6668..8f32d7a5864 100644 --- a/src/libstd/fs/tempdir.rs +++ b/src/libstd/fs/tempdir.rs @@ -68,12 +68,12 @@ impl TempDir { let path = tmpdir.join(&leaf); match fs::create_dir(&path) { Ok(_) => return Ok(TempDir { path: Some(path) }), - Err(ref e) if e.kind() == ErrorKind::PathAlreadyExists => {} + Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {} Err(e) => return Err(e) } } - Err(Error::new(ErrorKind::PathAlreadyExists, + Err(Error::new(ErrorKind::AlreadyExists, "too many temporary directories already exist", None)) } diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 530c6728107..f445ace081e 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -51,41 +51,53 @@ struct Custom { } /// A list specifying general categories of I/O error. +/// +/// This list is intended to grow over time and it is not recommended to +/// exhaustively match against it. #[derive(Copy, PartialEq, Eq, Clone, Debug)] -#[unstable(feature = "io", - reason = "the interaction between OS error codes and how they map to \ - these names (as well as the names themselves) has not \ - been thoroughly thought out")] +#[stable(feature = "rust1", since = "1.0.0")] pub enum ErrorKind { - /// The file was not found. - FileNotFound, - /// The file permissions disallowed access to this file. + /// An entity was not found, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + NotFound, + /// The operation lacked the necessary privileges to complete. + #[stable(feature = "rust1", since = "1.0.0")] PermissionDenied, /// The connection was refused by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] ConnectionRefused, /// The connection was reset by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] ConnectionReset, /// The connection was aborted (terminated) by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] ConnectionAborted, /// The network operation failed because it was not connected yet. + #[stable(feature = "rust1", since = "1.0.0")] NotConnected, + /// A socket address could not be bound because the address is already in + /// use elsewhere. + #[stable(feature = "rust1", since = "1.0.0")] + AddrInUse, + /// A nonexistent interface was requested or the requested address was not + /// local. + #[stable(feature = "rust1", since = "1.0.0")] + AddrNotAvailable, /// The operation failed because a pipe was closed. + #[stable(feature = "rust1", since = "1.0.0")] BrokenPipe, - /// A file already existed with that name. - PathAlreadyExists, - /// No file exists at that location. - PathDoesntExist, - /// The path did not specify the type of file that this operation required. - /// For example, attempting to copy a directory with the `fs::copy()` - /// operation will fail with this error. - MismatchedFileTypeForOperation, - /// The operation temporarily failed (for example, because a signal was - /// received), and retrying may succeed. - ResourceUnavailable, - /// A parameter was incorrect in a way that caused an I/O error not part of - /// this list. + /// An entity already exists, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + AlreadyExists, + /// The operation needs to block to complete, but the blocking operation was + /// requested to not occur. + #[stable(feature = "rust1", since = "1.0.0")] + WouldBlock, + /// A parameter was incorrect. + #[stable(feature = "rust1", since = "1.0.0")] InvalidInput, /// The I/O operation's timeout expired, causing it to be canceled. + #[stable(feature = "rust1", since = "1.0.0")] TimedOut, /// An error returned when an operation could not be completed because a /// call to `write` returned `Ok(0)`. @@ -93,11 +105,23 @@ pub enum ErrorKind { /// This typically means that an operation could only succeed if it wrote a /// particular number of bytes but only a smaller number of bytes could be /// written. + #[stable(feature = "rust1", since = "1.0.0")] WriteZero, - /// This operation was interrupted + /// This operation was interrupted. + /// + /// Interrupted operations can typically be retried. + #[stable(feature = "rust1", since = "1.0.0")] Interrupted, /// Any I/O error not part of this list. + #[stable(feature = "rust1", since = "1.0.0")] Other, + + /// Any I/O error not part of this list. + #[unstable(feature = "std_misc", + reason = "better expressed through extensible enums that this \ + enum cannot be exhaustively matched against")] + #[doc(hidden)] + __Nonexhaustive, } impl Error { @@ -134,6 +158,19 @@ impl Error { Error { repr: Repr::Os(code) } } + /// Returns the OS error that this error represents (if any). + /// + /// If this `Error` was constructed via `last_os_error` then this function + /// will return `Some`, otherwise it will return `None`. + #[unstable(feature = "io", reason = "function was just added and the return \ + type may become an abstract OS error")] + pub fn raw_os_error(&self) -> Option<i32> { + match self.repr { + Repr::Os(i) => Some(i), + Repr::Custom(..) => None, + } + } + /// Return the corresponding `ErrorKind` for this error. #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> ErrorKind { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 8691c84a462..237435d6dfb 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -584,7 +584,8 @@ pub trait BufRead: Read { read_until(self, byte, buf) } - /// Read all bytes until a newline byte (the 0xA byte) is reached. + /// Read all bytes until a newline byte (the 0xA byte) is reached, and + /// append them to the provided buffer. /// /// This function will continue to read (and buffer) bytes from the /// underlying stream until the newline delimiter (the 0xA byte) or EOF is diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 9b36408aa51..53f67766ea6 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -19,7 +19,7 @@ use io::{self, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; -/// Stdout used by print! and println! macroses +/// Stdout used by print! and println! macros thread_local! { static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = { RefCell::new(None) diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 36f36af73e1..543fdd16f41 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -25,6 +25,7 @@ pub use self::ip::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; pub use self::tcp::{TcpStream, TcpListener}; pub use self::udp::UdpSocket; +pub use self::parser::AddrParseError; mod ip; mod addr; diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 9843a152718..e7509834c7b 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -296,35 +296,40 @@ impl<'a> Parser<'a> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl FromStr for Ipv4Addr { - type Err = ParseError; - fn from_str(s: &str) -> Result<Ipv4Addr, ParseError> { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> { match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) { Some(s) => Ok(s), - None => Err(ParseError) + None => Err(AddrParseError(())) } } } +#[stable(feature = "rust1", since = "1.0.0")] impl FromStr for Ipv6Addr { - type Err = ParseError; - fn from_str(s: &str) -> Result<Ipv6Addr, ParseError> { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> { match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) { Some(s) => Ok(s), - None => Err(ParseError) + None => Err(AddrParseError(())) } } } +#[stable(feature = "rust1", since = "1.0.0")] impl FromStr for SocketAddr { - type Err = ParseError; - fn from_str(s: &str) -> Result<SocketAddr, ParseError> { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> { match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) { Some(s) => Ok(s), - None => Err(ParseError), + None => Err(AddrParseError(())), } } } -#[derive(Debug, Clone, PartialEq, Copy)] -pub struct ParseError; +/// An error returned when parsing an IP address or a socket address. +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone, PartialEq)] +pub struct AddrParseError(()); diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 501ba2dc2c1..f263d7d72d3 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -273,8 +273,7 @@ mod tests { match TcpListener::bind("1.1.1.1:9999") { Ok(..) => panic!(), Err(e) => - // EADDRNOTAVAIL is mapped to ConnectionRefused - assert_eq!(e.kind(), ErrorKind::ConnectionRefused), + assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), } } @@ -282,8 +281,11 @@ mod tests { fn connect_error() { match TcpStream::connect("0.0.0.0:1") { Ok(..) => panic!(), - Err(e) => assert!((e.kind() == ErrorKind::ConnectionRefused) - || (e.kind() == ErrorKind::InvalidInput)), + Err(e) => assert!(e.kind() == ErrorKind::ConnectionRefused || + e.kind() == ErrorKind::InvalidInput || + e.kind() == ErrorKind::AddrInUse || + e.kind() == ErrorKind::AddrNotAvailable, + "bad error: {} {:?}", e, e.kind()), } } @@ -535,7 +537,8 @@ mod tests { Ok(..) => panic!(), Err(e) => { assert!(e.kind() == ErrorKind::ConnectionRefused || - e.kind() == ErrorKind::Other, + e.kind() == ErrorKind::Other || + e.kind() == ErrorKind::AddrInUse, "unknown error: {} {:?}", e, e.kind()); } } diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 11e2b8dca1b..b5513dfd035 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -191,8 +191,8 @@ impl Float for f32 { /// Constructs a floating point number by multiplying `x` by 2 raised to the /// power of `exp` #[inline] - fn ldexp(x: f32, exp: int) -> f32 { - unsafe { cmath::ldexpf(x, exp as c_int) } + fn ldexp(self, exp: isize) -> f32 { + unsafe { cmath::ldexpf(self, exp as c_int) } } /// Breaks the number into a normalized fraction and a base-2 exponent, @@ -2207,8 +2207,8 @@ mod tests { let f1: f32 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); let f2: f32 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); let f3: f32 = FromStrRadix::from_str_radix("1.Cp-12", 16).unwrap(); - assert_eq!(Float::ldexp(1f32, -123), f1); - assert_eq!(Float::ldexp(1f32, -111), f2); + assert_eq!(1f32.ldexp(-123), f1); + assert_eq!(1f32.ldexp(-111), f2); assert_eq!(Float::ldexp(1.75f32, -12), f3); assert_eq!(Float::ldexp(0f32, -123), 0f32); diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 650f642220f..61bddc3d18f 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -200,8 +200,8 @@ impl Float for f64 { fn to_radians(self) -> f64 { num::Float::to_radians(self) } #[inline] - fn ldexp(x: f64, exp: int) -> f64 { - unsafe { cmath::ldexp(x, exp as c_int) } + fn ldexp(self, exp: isize) -> f64 { + unsafe { cmath::ldexp(self, exp as c_int) } } /// Breaks the number into a normalized fraction and a base-2 exponent, @@ -2214,8 +2214,8 @@ mod tests { let f1: f64 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); let f2: f64 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); let f3: f64 = FromStrRadix::from_str_radix("1.Cp-12", 16).unwrap(); - assert_eq!(Float::ldexp(1f64, -123), f1); - assert_eq!(Float::ldexp(1f64, -111), f2); + assert_eq!(1f64.ldexp(-123), f1); + assert_eq!(1f64.ldexp(-111), f2); assert_eq!(Float::ldexp(1.75f64, -12), f3); assert_eq!(Float::ldexp(0f64, -123), 0f64); diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 37f1f691776..082dad613b5 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -699,7 +699,7 @@ pub trait Float /// ``` #[unstable(feature = "std_misc", reason = "pending integer conventions")] - fn ldexp(x: Self, exp: isize) -> Self; + fn ldexp(self, exp: isize) -> Self; /// Breaks the number into a normalized fraction and a base-2 exponent, /// satisfying: /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index df8a5d27c7f..cda37b19c48 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -668,7 +668,7 @@ mod tests { #[test] fn test_process_output_fail_to_start() { match Command::new("/no-binary-by-this-name-should-exist").output() { - Err(e) => assert_eq!(e.kind(), ErrorKind::FileNotFound), + Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), Ok(..) => panic!() } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 90cc189b9a0..e52e68dad23 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -30,7 +30,7 @@ use thunk::Thunk; use usize; // Reexport some of our utilities which are expected by other crates. -pub use self::util::{default_sched_threads, min_stack, running_on_valgrind}; +pub use self::util::{min_stack, running_on_valgrind}; pub use self::unwind::{begin_unwind, begin_unwind_fmt}; // Reexport some functionality from liballoc. @@ -147,20 +147,14 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { } } -/// Enqueues a procedure to run when the runtime is cleaned up -/// -/// The procedure passed to this function will be executed as part of the -/// runtime cleanup phase. For normal rust programs, this means that it will run -/// after all other threads have exited. -/// -/// The procedure is *not* executed with a local `Thread` available to it, so -/// primitives like logging, I/O, channels, spawning, etc, are *not* available. -/// This is meant for "bare bones" usage to clean up runtime details, this is -/// not meant as a general-purpose "let's clean everything up" function. +/// Enqueues a procedure to run when the main thread exits. /// /// It is forbidden for procedures to register more `at_exit` handlers when they /// are running, and doing so will lead to a process abort. -pub fn at_exit<F:FnOnce()+Send+'static>(f: F) { +/// +/// Note that other threads may still be running when `at_exit` routines start +/// running. +pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) { at_exit_imp::push(Thunk::new(f)); } @@ -176,8 +170,5 @@ pub fn at_exit<F:FnOnce()+Send+'static>(f: F) { pub unsafe fn cleanup() { args::cleanup(); sys::stack_overflow::cleanup(); - // FIXME: (#20012): the resources being cleaned up by at_exit - // currently are not prepared for cleanup to happen asynchronously - // with detached threads using the resources; for now, we leak. - // at_exit_imp::cleanup(); + at_exit_imp::cleanup(); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index ebb2a2e4827..3ee3954ed64 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -69,7 +69,7 @@ use intrinsics; use libc::c_void; use mem; use sync::atomic::{self, Ordering}; -use sync::{Once, ONCE_INIT}; +use sys_common::mutex::{Mutex, MUTEX_INIT}; use rt::libunwind as uw; @@ -534,11 +534,22 @@ pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, uint)) -> /// Doing this split took the LLVM IR line counts of `fn main() { panic!() /// }` from ~1900/3700 (-O/no opts) to 180/590. #[inline(never)] #[cold] // this is the slow path, please never inline this -fn begin_unwind_inner(msg: Box<Any + Send>, file_line: &(&'static str, uint)) -> ! { - // Make sure the default panic handler is registered before we look at the - // callbacks. - static INIT: Once = ONCE_INIT; - INIT.call_once(|| unsafe { register(panicking::on_panic); }); +fn begin_unwind_inner(msg: Box<Any + Send>, + file_line: &(&'static str, uint)) -> ! { + // Make sure the default failure handler is registered before we look at the + // callbacks. We also use a raw sys-based mutex here instead of a + // `std::sync` one as accessing TLS can cause weird recursive problems (and + // we don't need poison checking). + unsafe { + static LOCK: Mutex = MUTEX_INIT; + static mut INIT: bool = false; + LOCK.lock(); + if !INIT { + register(panicking::on_panic); + INIT = true; + } + LOCK.unlock(); + } // First, invoke call the user-defined callbacks triggered on thread panic. // diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index e72fd7b3320..f1c43a07e6e 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -58,29 +58,6 @@ pub fn min_stack() -> uint { return amt; } -/// Get's the number of scheduler threads requested by the environment -/// either `RUST_THREADS` or `num_cpus`. -#[allow(deprecated)] -pub fn default_sched_threads() -> uint { - use os; - match env::var("RUST_THREADS") { - Ok(nstr) => { - let opt_n: Option<uint> = nstr.parse().ok(); - match opt_n { - Some(n) if n > 0 => n, - _ => panic!("`RUST_THREADS` is `{}`, should be a positive integer", nstr) - } - } - Err(..) => { - if limit_thread_creation_due_to_osx_and_valgrind() { - 1 - } else { - os::num_cpus() - } - } - } -} - // Indicates whether we should perform expensive sanity checks, including rtassert! // // FIXME: Once the runtime matures remove the `true` below to turn off rtassert, diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index 3b5fd5a5714..2a852fbcd57 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -24,7 +24,6 @@ use prelude::v1::*; use boxed; use cell::UnsafeCell; -use ptr; use rt; use sync::{StaticMutex, StaticCondvar}; use sync::mpsc::{channel, Sender, Receiver}; @@ -97,7 +96,7 @@ impl<M: Send> Helper<M> { { unsafe { let _guard = self.lock.lock().unwrap(); - if !*self.initialized.get() { + if *self.chan.get() as uint == 0 { let (tx, rx) = channel(); *self.chan.get() = boxed::into_raw(box tx); let (receive, send) = helper_signal::new(); @@ -113,8 +112,10 @@ impl<M: Send> Helper<M> { self.cond.notify_one() }); - rt::at_exit(move|| { self.shutdown() }); + rt::at_exit(move || { self.shutdown() }); *self.initialized.get() = true; + } else if *self.chan.get() as uint == 1 { + panic!("cannot continue usage after shutdown"); } } } @@ -129,7 +130,9 @@ impl<M: Send> Helper<M> { // Must send and *then* signal to ensure that the child receives the // message. Otherwise it could wake up and go to sleep before we // send the message. - assert!(!self.chan.get().is_null()); + assert!(*self.chan.get() as uint != 0); + assert!(*self.chan.get() as uint != 1, + "cannot continue usage after shutdown"); (**self.chan.get()).send(msg).unwrap(); helper_signal::signal(*self.signal.get() as helper_signal::signal); } @@ -142,9 +145,13 @@ impl<M: Send> Helper<M> { // returns. let mut guard = self.lock.lock().unwrap(); + let ptr = *self.chan.get(); + if ptr as uint == 1 { + panic!("cannot continue usage after shutdown"); + } // Close the channel by destroying it - let chan: Box<Sender<M>> = Box::from_raw(*self.chan.get()); - *self.chan.get() = ptr::null_mut(); + let chan = Box::from_raw(*self.chan.get()); + *self.chan.get() = 1 as *mut Sender<M>; drop(chan); helper_signal::signal(*self.signal.get() as helper_signal::signal); diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys/common/rwlock.rs index fe374e1fd78..f7d7a5715bc 100644 --- a/src/libstd/sys/common/rwlock.rs +++ b/src/libstd/sys/common/rwlock.rs @@ -25,7 +25,7 @@ impl RWLock { /// thread to do so. /// /// Behavior is undefined if the rwlock has been moved between this and any - /// previous methodo call. + /// previous method call. #[inline] pub unsafe fn read(&self) { self.0.read() } @@ -35,7 +35,7 @@ impl RWLock { /// This function does not block the current thread. /// /// Behavior is undefined if the rwlock has been moved between this and any - /// previous methodo call. + /// previous method call. #[inline] pub unsafe fn try_read(&self) -> bool { self.0.try_read() } @@ -43,7 +43,7 @@ impl RWLock { /// to do so. /// /// Behavior is undefined if the rwlock has been moved between this and any - /// previous methodo call. + /// previous method call. #[inline] pub unsafe fn write(&self) { self.0.write() } @@ -53,7 +53,7 @@ impl RWLock { /// This function does not block the current thread. /// /// Behavior is undefined if the rwlock has been moved between this and any - /// previous methodo call. + /// previous method call. #[inline] pub unsafe fn try_write(&self) -> bool { self.0.try_write() } diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index ecd047710bb..5e2a138fa63 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -61,7 +61,6 @@ use prelude::v1::*; use sync::atomic::{self, AtomicUsize, Ordering}; -use sync::{Mutex, Once, ONCE_INIT}; use sys::thread_local as imp; @@ -142,9 +141,6 @@ pub const INIT_INNER: StaticKeyInner = StaticKeyInner { key: atomic::ATOMIC_USIZE_INIT, }; -static INIT_KEYS: Once = ONCE_INIT; -static mut KEYS: *mut Mutex<Vec<imp::Key>> = 0 as *mut _; - impl StaticKey { /// Gets the value associated with this TLS key /// diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index a8cee74828d..5555eec4f39 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -139,22 +139,19 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::EPIPE => ErrorKind::BrokenPipe, libc::ENOTCONN => ErrorKind::NotConnected, libc::ECONNABORTED => ErrorKind::ConnectionAborted, - libc::EADDRNOTAVAIL => ErrorKind::ConnectionRefused, - libc::EADDRINUSE => ErrorKind::ConnectionRefused, - libc::ENOENT => ErrorKind::FileNotFound, - libc::EISDIR => ErrorKind::InvalidInput, + libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, + libc::EADDRINUSE => ErrorKind::AddrInUse, + libc::ENOENT => ErrorKind::NotFound, libc::EINTR => ErrorKind::Interrupted, libc::EINVAL => ErrorKind::InvalidInput, - libc::ENOTTY => ErrorKind::MismatchedFileTypeForOperation, libc::ETIMEDOUT => ErrorKind::TimedOut, - libc::ECANCELED => ErrorKind::TimedOut, - libc::consts::os::posix88::EEXIST => ErrorKind::PathAlreadyExists, + libc::consts::os::posix88::EEXIST => ErrorKind::AlreadyExists, // These two constants can have the same value on some systems, // but different values on others, so we can't use a match // clause x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => - ErrorKind::ResourceUnavailable, + ErrorKind::WouldBlock, _ => ErrorKind::Other, } diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index c830eb91068..b6d2aca9a52 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -170,8 +170,15 @@ fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) { 1 => { loop { match messages.try_recv() { + // Once we've been disconnected it means the main thread + // is exiting (at_exit has run). We could still have + // active timers for other threads, so we're just going + // to drop them all on the floor. This is all we can + // really do, however, to prevent resource leakage. The + // remaining timers will likely start panicking quickly + // as they attempt to re-use this thread but are + // disallowed to do so. Err(TryRecvError::Disconnected) => { - assert!(active.len() == 0); break 'outer; } diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index d02fe79fcdb..eeaf4ced072 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -149,25 +149,21 @@ pub fn decode_error_detailed(errno: i32) -> IoError { pub fn decode_error_kind(errno: i32) -> ErrorKind { match errno as libc::c_int { libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied, - libc::ERROR_ALREADY_EXISTS => ErrorKind::PathAlreadyExists, + libc::ERROR_ALREADY_EXISTS => ErrorKind::AlreadyExists, libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe, - libc::ERROR_FILE_NOT_FOUND => ErrorKind::FileNotFound, - libc::ERROR_INVALID_FUNCTION => ErrorKind::InvalidInput, - libc::ERROR_INVALID_HANDLE => ErrorKind::MismatchedFileTypeForOperation, - libc::ERROR_INVALID_NAME => ErrorKind::InvalidInput, - libc::ERROR_NOTHING_TO_TERMINATE => ErrorKind::InvalidInput, + libc::ERROR_FILE_NOT_FOUND => ErrorKind::NotFound, libc::ERROR_NO_DATA => ErrorKind::BrokenPipe, libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut, libc::WSAEACCES => ErrorKind::PermissionDenied, - libc::WSAEADDRINUSE => ErrorKind::ConnectionRefused, - libc::WSAEADDRNOTAVAIL => ErrorKind::ConnectionRefused, + libc::WSAEADDRINUSE => ErrorKind::AddrInUse, + libc::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable, libc::WSAECONNABORTED => ErrorKind::ConnectionAborted, libc::WSAECONNREFUSED => ErrorKind::ConnectionRefused, libc::WSAECONNRESET => ErrorKind::ConnectionReset, libc::WSAEINVAL => ErrorKind::InvalidInput, libc::WSAENOTCONN => ErrorKind::NotConnected, - libc::WSAEWOULDBLOCK => ErrorKind::ResourceUnavailable, + libc::WSAEWOULDBLOCK => ErrorKind::WouldBlock, _ => ErrorKind::Other, } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 30c483ac52f..1359803070a 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -138,9 +138,9 @@ unsafe fn init_dtors() { rt::at_exit(move|| { DTOR_LOCK.lock(); let dtors = DTORS; - DTORS = ptr::null_mut(); + DTORS = 1 as *mut _; Box::from_raw(dtors); - assert!(DTORS.is_null()); // can't re-init after destructing + assert!(DTORS as uint == 1); // can't re-init after destructing DTOR_LOCK.unlock(); }); } @@ -148,6 +148,9 @@ unsafe fn init_dtors() { unsafe fn register_dtor(key: Key, dtor: Dtor) { DTOR_LOCK.lock(); init_dtors(); + assert!(DTORS as uint != 0); + assert!(DTORS as uint != 1, + "cannot create new TLS keys after the main thread has exited"); (*DTORS).push((key, dtor)); DTOR_LOCK.unlock(); } @@ -155,6 +158,9 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) { unsafe fn unregister_dtor(key: Key) -> bool { DTOR_LOCK.lock(); init_dtors(); + assert!(DTORS as uint != 0); + assert!(DTORS as uint != 1, + "cannot unregister destructors after the main thread has exited"); let ret = { let dtors = &mut *DTORS; let before = dtors.len(); @@ -241,7 +247,7 @@ unsafe fn run_dtors() { any_run = false; let dtors = { DTOR_LOCK.lock(); - let ret = if DTORS.is_null() { + let ret = if DTORS as usize <= 1 { Vec::new() } else { (*DTORS).iter().map(|s| *s).collect() diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs index 91a7f694181..9bcae926eea 100644 --- a/src/libstd/sys/windows/timer.rs +++ b/src/libstd/sys/windows/timer.rs @@ -80,9 +80,10 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) { None => {} } } + // See the comment in unix::timer for why we don't have any + // asserts here and why we're likely just leaving timers on + // the floor as we exit. Err(TryRecvError::Disconnected) => { - assert_eq!(objs.len(), 1); - assert_eq!(chans.len(), 0); break 'outer; } Err(..) => break diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6006366ad9a..704abc43f10 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -913,7 +913,7 @@ pub enum Expr_ { /// The explicit Self type in a "qualified path". The actual /// path, including the trait and the associated item, is stored -/// sepparately. `position` represents the index of the associated +/// separately. `position` represents the index of the associated /// item qualified with this Self type. /// /// <Vec<T> as a::b::Trait>::AssociatedItem diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c38556b0782..c11ffe66e6c 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -176,6 +176,8 @@ pub mod rt { impl_to_source! { ast::Arg, arg_to_string } impl_to_source! { Generics, generics_to_string } impl_to_source! { P<ast::Item>, item_to_string } + impl_to_source! { P<ast::ImplItem>, impl_item_to_string } + impl_to_source! { P<ast::TraitItem>, trait_item_to_string } impl_to_source! { P<ast::Stmt>, stmt_to_string } impl_to_source! { P<ast::Expr>, expr_to_string } impl_to_source! { P<ast::Pat>, pat_to_string } @@ -308,6 +310,8 @@ pub mod rt { impl_to_tokens! { ast::Ident } impl_to_tokens! { P<ast::Item> } + impl_to_tokens! { P<ast::ImplItem> } + impl_to_tokens! { P<ast::TraitItem> } impl_to_tokens! { P<ast::Pat> } impl_to_tokens! { ast::Arm } impl_to_tokens_lifetime! { &'a [P<ast::Item>] } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b58c121c5fd..239fea57d94 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -355,6 +355,14 @@ pub fn item_to_string(i: &ast::Item) -> String { $to_string(|s| s.print_item(i)) } +pub fn impl_item_to_string(i: &ast::ImplItem) -> String { + $to_string(|s| s.print_impl_item(i)) +} + +pub fn trait_item_to_string(i: &ast::TraitItem) -> String { + $to_string(|s| s.print_trait_item(i)) +} + pub fn generics_to_string(generics: &ast::Generics) -> String { $to_string(|s| s.print_generics(generics)) } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 02ddeea46bf..51decbab858 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -44,6 +44,7 @@ #![feature(std_misc)] #![feature(libc)] #![feature(set_stdio)] +#![feature(os)] extern crate getopts; extern crate serialize; @@ -338,7 +339,7 @@ The FILTER regex is tested against the name of all tests to run, and only those tests that match are run. By default, all tests are run in parallel. This can be altered with the -RUST_TEST_TASKS environment variable when running tests (set it to 1). +RUST_TEST_THRADS environment variable when running tests (set it to 1). All tests have their standard output and standard error captured by default. This can be overridden with the --nocapture flag or the RUST_TEST_NOCAPTURE=1 @@ -841,18 +842,22 @@ fn run_tests<F>(opts: &TestOpts, Ok(()) } +#[allow(deprecated)] fn get_concurrency() -> uint { - use std::rt; - match env::var("RUST_TEST_TASKS") { + match env::var("RUST_TEST_THREADS") { Ok(s) => { let opt_n: Option<uint> = s.parse().ok(); match opt_n { Some(n) if n > 0 => n, - _ => panic!("RUST_TEST_TASKS is `{}`, should be a positive integer.", s) + _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s) } } Err(..) => { - rt::default_sched_threads() + if std::rt::util::limit_thread_creation_due_to_osx_and_valgrind() { + 1 + } else { + std::os::num_cpus() + } } } } diff --git a/src/libunicode/char.rs b/src/libunicode/char.rs index 5850fed980a..5e1070c6dc5 100644 --- a/src/libunicode/char.rs +++ b/src/libunicode/char.rs @@ -41,8 +41,429 @@ pub use normalize::{decompose_canonical, decompose_compatible, compose}; pub use tables::normalization::canonical_combining_class; pub use tables::UNICODE_VERSION; +#[cfg(stage0)] +/// Functionality for manipulating `char`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait CharExt { + /// Checks if a `char` parses as a numeric digit in the given radix. + /// + /// Compared to `is_numeric()`, this function only recognizes the characters + /// `0-9`, `a-z` and `A-Z`. + /// + /// # Return value + /// + /// Returns `true` if `c` is a valid digit under `radix`, and `false` + /// otherwise. + /// + /// # Panics + /// + /// Panics if given a radix > 36. + /// + /// # Examples + /// + /// ``` + /// let c = '1'; + /// + /// assert!(c.is_digit(10)); + /// + /// assert!('f'.is_digit(16)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn is_digit(self, radix: u32) -> bool; + + /// Converts a character to the corresponding digit. + /// + /// # Return value + /// + /// If `c` is between '0' and '9', the corresponding value between 0 and + /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns + /// none if the character does not refer to a digit in the given radix. + /// + /// # Panics + /// + /// Panics if given a radix outside the range [0..36]. + /// + /// # Examples + /// + /// ``` + /// let c = '1'; + /// + /// assert_eq!(c.to_digit(10), Some(1)); + /// + /// assert_eq!('f'.to_digit(16), Some(15)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn to_digit(self, radix: u32) -> Option<u32>; + + /// Returns an iterator that yields the hexadecimal Unicode escape of a + /// character, as `char`s. + /// + /// All characters are escaped with Rust syntax of the form `\\u{NNNN}` + /// where `NNNN` is the shortest hexadecimal representation of the code + /// point. + /// + /// # Examples + /// + /// ``` + /// for i in '❤'.escape_unicode() { + /// println!("{}", i); + /// } + /// ``` + /// + /// This prints: + /// + /// ```text + /// \ + /// u + /// { + /// 2 + /// 7 + /// 6 + /// 4 + /// } + /// ``` + /// + /// Collecting into a `String`: + /// + /// ``` + /// let heart: String = '❤'.escape_unicode().collect(); + /// + /// assert_eq!(heart, r"\u{2764}"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn escape_unicode(self) -> EscapeUnicode; + + /// Returns an iterator that yields the 'default' ASCII and + /// C++11-like literal escape of a character, as `char`s. + /// + /// The default is chosen with a bias toward producing literals that are + /// legal in a variety of languages, including C++11 and similar C-family + /// languages. The exact rules are: + /// + /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. + /// * Single-quote, double-quote and backslash chars are backslash- + /// escaped. + /// * Any other chars in the range [0x20,0x7e] are not escaped. + /// * Any other chars are given hex Unicode escapes; see `escape_unicode`. + /// + /// # Examples + /// + /// ``` + /// for i in '"'.escape_default() { + /// println!("{}", i); + /// } + /// ``` + /// + /// This prints: + /// + /// ```text + /// \ + /// " + /// ``` + /// + /// Collecting into a `String`: + /// + /// ``` + /// let quote: String = '"'.escape_default().collect(); + /// + /// assert_eq!(quote, "\\\""); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn escape_default(self) -> EscapeDefault; + + /// Returns the number of bytes this character would need if encoded in + /// UTF-8. + /// + /// # Examples + /// + /// ``` + /// let n = 'ß'.len_utf8(); + /// + /// assert_eq!(n, 2); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn len_utf8(self) -> usize; + + /// Returns the number of 16-bit code units this character would need if + /// encoded in UTF-16. + /// + /// # Examples + /// + /// ``` + /// let n = 'ß'.len_utf16(); + /// + /// assert_eq!(n, 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn len_utf16(self) -> usize; + + /// Encodes this character as UTF-8 into the provided byte buffer, and then + /// returns the number of bytes written. + /// + /// If the buffer is not large enough, nothing will be written into it and a + /// `None` will be returned. A buffer of length four is large enough to + /// encode any `char`. + /// + /// # Examples + /// + /// In both of these examples, 'ß' takes two bytes to encode. + /// + /// ``` + /// let mut b = [0; 2]; + /// + /// let result = 'ß'.encode_utf8(&mut b); + /// + /// assert_eq!(result, Some(2)); + /// ``` + /// + /// A buffer that's too small: + /// + /// ``` + /// let mut b = [0; 1]; + /// + /// let result = 'ß'.encode_utf8(&mut b); + /// + /// assert_eq!(result, None); + /// ``` + #[unstable(feature = "unicode", + reason = "pending decision about Iterator/Writer/Reader")] + fn encode_utf8(self, dst: &mut [u8]) -> Option<usize>; + + /// Encodes this character as UTF-16 into the provided `u16` buffer, and + /// then returns the number of `u16`s written. + /// + /// If the buffer is not large enough, nothing will be written into it and a + /// `None` will be returned. A buffer of length 2 is large enough to encode + /// any `char`. + /// + /// # Examples + /// + /// In both of these examples, 'ß' takes one `u16` to encode. + /// + /// ``` + /// let mut b = [0; 1]; + /// + /// let result = 'ß'.encode_utf16(&mut b); + /// + /// assert_eq!(result, Some(1)); + /// ``` + /// + /// A buffer that's too small: + /// + /// ``` + /// let mut b = [0; 0]; + /// + /// let result = 'ß'.encode_utf8(&mut b); + /// + /// assert_eq!(result, None); + /// ``` + #[unstable(feature = "unicode", + reason = "pending decision about Iterator/Writer/Reader")] + fn encode_utf16(self, dst: &mut [u16]) -> Option<usize>; + + /// Returns whether the specified character is considered a Unicode + /// alphabetic code point. + #[stable(feature = "rust1", since = "1.0.0")] + fn is_alphabetic(self) -> bool; + + /// Returns whether the specified character satisfies the 'XID_Start' + /// Unicode property. + /// + /// 'XID_Start' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to ID_Start but modified for closure under NFKx. + #[unstable(feature = "unicode", + reason = "mainly needed for compiler internals")] + fn is_xid_start(self) -> bool; + + /// Returns whether the specified `char` satisfies the 'XID_Continue' + /// Unicode property. + /// + /// 'XID_Continue' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to 'ID_Continue' but modified for closure under NFKx. + #[unstable(feature = "unicode", + reason = "mainly needed for compiler internals")] + fn is_xid_continue(self) -> bool; + + /// Indicates whether a character is in lowercase. + /// + /// This is defined according to the terms of the Unicode Derived Core + /// Property `Lowercase`. + #[stable(feature = "rust1", since = "1.0.0")] + fn is_lowercase(self) -> bool; + + /// Indicates whether a character is in uppercase. + /// + /// This is defined according to the terms of the Unicode Derived Core + /// Property `Uppercase`. + #[stable(feature = "rust1", since = "1.0.0")] + fn is_uppercase(self) -> bool; + + /// Indicates whether a character is whitespace. + /// + /// Whitespace is defined in terms of the Unicode Property `White_Space`. + #[stable(feature = "rust1", since = "1.0.0")] + fn is_whitespace(self) -> bool; + + /// Indicates whether a character is alphanumeric. + /// + /// Alphanumericness is defined in terms of the Unicode General Categories + /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. + #[stable(feature = "rust1", since = "1.0.0")] + fn is_alphanumeric(self) -> bool; + + /// Indicates whether a character is a control code point. + /// + /// Control code points are defined in terms of the Unicode General + /// Category `Cc`. + #[stable(feature = "rust1", since = "1.0.0")] + fn is_control(self) -> bool; + + /// Indicates whether the character is numeric (Nd, Nl, or No). + #[stable(feature = "rust1", since = "1.0.0")] + fn is_numeric(self) -> bool; + + /// Converts a character to its lowercase equivalent. + /// + /// The case-folding performed is the common or simple mapping. See + /// `to_uppercase()` for references and more information. + /// + /// # Return value + /// + /// Returns an iterator which yields the characters corresponding to the + /// lowercase equivalent of the character. If no conversion is possible then + /// the input character is returned. + #[stable(feature = "rust1", since = "1.0.0")] + fn to_lowercase(self) -> ToLowercase; + + /// Converts a character to its uppercase equivalent. + /// + /// The case-folding performed is the common or simple mapping: it maps + /// one Unicode codepoint to its uppercase equivalent according to the + /// Unicode database [1]. The additional [`SpecialCasing.txt`] is not yet + /// considered here, but the iterator returned will soon support this form + /// of case folding. + /// + /// A full reference can be found here [2]. + /// + /// # Return value + /// + /// Returns an iterator which yields the characters corresponding to the + /// uppercase equivalent of the character. If no conversion is possible then + /// the input character is returned. + /// + /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + /// + /// [`SpecialCasing`.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt + /// + /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992 + #[stable(feature = "rust1", since = "1.0.0")] + fn to_uppercase(self) -> ToUppercase; + + /// Returns this character's displayed width in columns, or `None` if it is a + /// control character other than `'\x00'`. + /// + /// `is_cjk` determines behavior for characters in the Ambiguous category: + /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1. + /// In CJK contexts, `is_cjk` should be `true`, else it should be `false`. + /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// recommends that these characters be treated as 1 column (i.e., + /// `is_cjk` = `false`) if the context cannot be reliably determined. + #[unstable(feature = "unicode", + reason = "needs expert opinion. is_cjk flag stands out as ugly")] + fn width(self, is_cjk: bool) -> Option<usize>; +} + +#[cfg(stage0)] +#[stable(feature = "rust1", since = "1.0.0")] +impl CharExt for char { + #[inline] + fn is_digit(self, radix: u32) -> bool { C::is_digit(self, radix) } + fn to_digit(self, radix: u32) -> Option<u32> { C::to_digit(self, radix) } + fn escape_unicode(self) -> EscapeUnicode { C::escape_unicode(self) } + fn escape_default(self) -> EscapeDefault { C::escape_default(self) } + fn len_utf8(self) -> usize { C::len_utf8(self) } + fn len_utf16(self) -> usize { C::len_utf16(self) } + fn encode_utf8(self, dst: &mut [u8]) -> Option<usize> { C::encode_utf8(self, dst) } + fn encode_utf16(self, dst: &mut [u16]) -> Option<usize> { C::encode_utf16(self, dst) } + + #[inline] + fn is_alphabetic(self) -> bool { + match self { + 'a' ... 'z' | 'A' ... 'Z' => true, + c if c > '\x7f' => derived_property::Alphabetic(c), + _ => false + } + } + + #[inline] + fn is_xid_start(self) -> bool { derived_property::XID_Start(self) } + + #[inline] + fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) } + + #[inline] + fn is_lowercase(self) -> bool { + match self { + 'a' ... 'z' => true, + c if c > '\x7f' => derived_property::Lowercase(c), + _ => false + } + } + + #[inline] + fn is_uppercase(self) -> bool { + match self { + 'A' ... 'Z' => true, + c if c > '\x7f' => derived_property::Uppercase(c), + _ => false + } + } + + #[inline] + fn is_whitespace(self) -> bool { + match self { + ' ' | '\x09' ... '\x0d' => true, + c if c > '\x7f' => property::White_Space(c), + _ => false + } + } + + #[inline] + fn is_alphanumeric(self) -> bool { + self.is_alphabetic() || self.is_numeric() + } + + #[inline] + fn is_control(self) -> bool { general_category::Cc(self) } + + #[inline] + fn is_numeric(self) -> bool { + match self { + '0' ... '9' => true, + c if c > '\x7f' => general_category::N(c), + _ => false + } + } + + #[inline] + fn to_lowercase(self) -> ToLowercase { + ToLowercase(Some(conversions::to_lower(self))) + } + + #[inline] + fn to_uppercase(self) -> ToUppercase { + ToUppercase(Some(conversions::to_upper(self))) + } + + #[inline] + fn width(self, is_cjk: bool) -> Option<usize> { charwidth::width(self, is_cjk) } +} + /// An iterator over the lowercase mapping of a given character, returned from -/// the `lowercase` method on characters. +/// the [`to_lowercase` method](../primitive.char.html#method.to_lowercase) on +/// characters. #[stable(feature = "rust1", since = "1.0.0")] pub struct ToLowercase(Option<char>); @@ -53,7 +474,8 @@ impl Iterator for ToLowercase { } /// An iterator over the uppercase mapping of a given character, returned from -/// the `uppercase` method on characters. +/// the [`to_uppercase` method](../primitive.char.html#method.to_uppercase) on +/// characters. #[stable(feature = "rust1", since = "1.0.0")] pub struct ToUppercase(Option<char>); @@ -90,6 +512,7 @@ impl char { /// assert!('f'.is_digit(16)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_digit(self, radix: u32) -> bool { C::is_digit(self, radix) } /// Converts a character to the corresponding digit. @@ -285,6 +708,7 @@ impl char { /// Returns whether the specified character is considered a Unicode /// alphabetic code point. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_alphabetic(self) -> bool { match self { 'a' ... 'z' | 'A' ... 'Z' => true, @@ -301,6 +725,7 @@ impl char { /// mostly similar to ID_Start but modified for closure under NFKx. #[unstable(feature = "unicode", reason = "mainly needed for compiler internals")] + #[inline] pub fn is_xid_start(self) -> bool { derived_property::XID_Start(self) } /// Returns whether the specified `char` satisfies the 'XID_Continue' @@ -311,6 +736,7 @@ impl char { /// mostly similar to 'ID_Continue' but modified for closure under NFKx. #[unstable(feature = "unicode", reason = "mainly needed for compiler internals")] + #[inline] pub fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) } /// Indicates whether a character is in lowercase. @@ -318,6 +744,7 @@ impl char { /// This is defined according to the terms of the Unicode Derived Core /// Property `Lowercase`. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_lowercase(self) -> bool { match self { 'a' ... 'z' => true, @@ -331,6 +758,7 @@ impl char { /// This is defined according to the terms of the Unicode Derived Core /// Property `Uppercase`. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_uppercase(self) -> bool { match self { 'A' ... 'Z' => true, @@ -343,6 +771,7 @@ impl char { /// /// Whitespace is defined in terms of the Unicode Property `White_Space`. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_whitespace(self) -> bool { match self { ' ' | '\x09' ... '\x0d' => true, @@ -356,6 +785,7 @@ impl char { /// Alphanumericness is defined in terms of the Unicode General Categories /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_alphanumeric(self) -> bool { self.is_alphabetic() || self.is_numeric() } @@ -365,10 +795,12 @@ impl char { /// Control code points are defined in terms of the Unicode General /// Category `Cc`. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_control(self) -> bool { general_category::Cc(self) } /// Indicates whether the character is numeric (Nd, Nl, or No). #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn is_numeric(self) -> bool { match self { '0' ... '9' => true, @@ -388,6 +820,7 @@ impl char { /// lowercase equivalent of the character. If no conversion is possible then /// the input character is returned. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn to_lowercase(self) -> ToLowercase { ToLowercase(Some(conversions::to_lower(self))) } @@ -414,6 +847,7 @@ impl char { /// /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992 #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn to_uppercase(self) -> ToUppercase { ToUppercase(Some(conversions::to_upper(self))) } diff --git a/src/test/auxiliary/crate_with_invalid_spans.rs b/src/test/auxiliary/crate_with_invalid_spans.rs new file mode 100644 index 00000000000..b37533d2da7 --- /dev/null +++ b/src/test/auxiliary/crate_with_invalid_spans.rs @@ -0,0 +1,30 @@ +// 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. + +#![crate_type = "rlib"] +// no-prefer-dynamic + +// compile-flags: -g + +#[macro_use] +mod crate_with_invalid_spans_macros; + +pub fn exported_generic<T>(x: T, y: u32) -> (T, u32) { + // Using the add1 macro will produce an invalid span, because the `y` passed + // to the macro will have a span from this file, but the rest of the code + // generated from the macro will have spans from the macro-defining file. + // The AST node for the (1 + y) expression generated by the macro will then + // take it's `lo` span bound from the `1` literal in the macro-defining file + // and it's `hi` bound from `y` in this file, which should be lower than the + // `lo` and even lower than the lower bound of the FileMap it is supposedly + // contained in because the FileMap for this file was allocated earlier than + // the FileMap of the macro-defining file. + return (x, add1!(y)); +} diff --git a/src/test/auxiliary/crate_with_invalid_spans_macros.rs b/src/test/auxiliary/crate_with_invalid_spans_macros.rs new file mode 100644 index 00000000000..112315af844 --- /dev/null +++ b/src/test/auxiliary/crate_with_invalid_spans_macros.rs @@ -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. + +macro_rules! add1 { + ($e:expr) => ({ + let a = 1 + $e; + let b = $e + 1; + a + b - 1 + }) +} diff --git a/src/test/run-fail/rt-set-exit-status-panic2.rs b/src/test/run-fail/rt-set-exit-status-panic2.rs index 775d38c8b30..fb1e03c234d 100644 --- a/src/test/run-fail/rt-set-exit-status-panic2.rs +++ b/src/test/run-fail/rt-set-exit-status-panic2.rs @@ -35,7 +35,7 @@ fn r(x:int) -> r { fn main() { error!("whatever"); - let _t = thread::spawn(move|| { + let _t = thread::scoped(move|| { let _i = r(5); }); panic!(); diff --git a/src/test/run-fail/test-tasks-invalid-value.rs b/src/test/run-fail/test-tasks-invalid-value.rs index 8c9cd2d63cb..94ed641c79c 100644 --- a/src/test/run-fail/test-tasks-invalid-value.rs +++ b/src/test/run-fail/test-tasks-invalid-value.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This checks that RUST_TEST_TASKS not being 1, 2, ... is detected +// This checks that RUST_TEST_THREADS not being 1, 2, ... is detected // properly. // error-pattern:should be a positive integer // compile-flags: --test -// exec-env:RUST_TEST_TASKS=foo +// exec-env:RUST_TEST_THREADS=foo // ignore-pretty: does not work well with `--test` #[test] diff --git a/src/test/run-make/rustdoc-src-links/Makefile b/src/test/run-make/rustdoc-src-links/Makefile new file mode 100644 index 00000000000..419603e82f7 --- /dev/null +++ b/src/test/run-make/rustdoc-src-links/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk +all: + $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs + $(HTMLDOCCK) $(TMPDIR)/doc foo.rs + $(HTMLDOCCK) $(TMPDIR)/doc qux/mod.rs diff --git a/src/test/run-make/rustdoc-src-links/foo.rs b/src/test/run-make/rustdoc-src-links/foo.rs new file mode 100644 index 00000000000..9a964f11252 --- /dev/null +++ b/src/test/run-make/rustdoc-src-links/foo.rs @@ -0,0 +1,43 @@ +// 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. + +#![crate_name = "foo"] + +//! Dox +// @has src/foo/foo.rs.html +// @has foo/index.html '//a/@href' '../src/foo/foo.rs.html' + +pub mod qux; + +// @has foo/bar/index.html '//a/@href' '../../src/foo/foo.rs.html' +pub mod bar { + + /// Dox + // @has foo/bar/baz/index.html '//a/@href' '../../../src/foo/foo.rs.html' + pub mod baz { + /// Dox + // @has foo/bar/baz/fn.baz.html '//a/@href' '../../../src/foo/foo.rs.html' + pub fn baz() { } + } + + /// Dox + // @has foo/bar/trait.Foobar.html '//a/@href' '../../src/foo/foo.rs.html' + pub trait Foobar { fn dummy(&self) { } } + + // @has foo/bar/struct.Foo.html '//a/@href' '../../src/foo/foo.rs.html' + pub struct Foo { x: i32, y: u32 } + + // @has foo/bar/fn.prawns.html '//a/@href' '../../src/foo/foo.rs.html' + pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } +} + +/// Dox +// @has foo/fn.modfn.html '//a/@href' '../src/foo/foo.rs.html' +pub fn modfn() { } diff --git a/src/test/run-make/rustdoc-src-links/qux/mod.rs b/src/test/run-make/rustdoc-src-links/qux/mod.rs new file mode 100644 index 00000000000..9b1563d32ac --- /dev/null +++ b/src/test/run-make/rustdoc-src-links/qux/mod.rs @@ -0,0 +1,39 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Dox +// @has src/foo/qux/mod.rs.html +// @has foo/qux/index.html '//a/@href' '../../src/foo/qux/mod.rs.html' + +// @has foo/qux/bar/index.html '//a/@href' '../../../src/foo/qux/mod.rs.html' +pub mod bar { + + /// Dox + // @has foo/qux/bar/baz/index.html '//a/@href' '../../../../src/foo/qux/mod.rs.html' + pub mod baz { + /// Dox + // @has foo/qux/bar/baz/fn.baz.html '//a/@href' '../../../../src/foo/qux/mod.rs.html' + pub fn baz() { } + } + + /// Dox + // @has foo/qux/bar/trait.Foobar.html '//a/@href' '../../../src/foo/qux/mod.rs.html' + pub trait Foobar { fn dummy(&self) { } } + + // @has foo/qux/bar/struct.Foo.html '//a/@href' '../../../src/foo/qux/mod.rs.html' + pub struct Foo { x: i32, y: u32 } + + // @has foo/qux/bar/fn.prawns.html '//a/@href' '../../../src/foo/qux/mod.rs.html' + pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } +} + +/// Dox +// @has foo/qux/fn.modfn.html '//a/@href' '../../src/foo/qux/mod.rs.html' +pub fn modfn() { } diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index 3f226a1985e..9e05f38af7a 100644 --- a/src/test/run-pass/foreign-call-no-runtime.rs +++ b/src/test/run-pass/foreign-call-no-runtime.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-aarch64 + extern crate libc; use std::mem; diff --git a/src/test/run-pass/import-crate-with-invalid-spans.rs b/src/test/run-pass/import-crate-with-invalid-spans.rs new file mode 100644 index 00000000000..a949f25f41e --- /dev/null +++ b/src/test/run-pass/import-crate-with-invalid-spans.rs @@ -0,0 +1,20 @@ +// 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. + +// aux-build:crate_with_invalid_spans.rs + +extern crate crate_with_invalid_spans; + +fn main() { + // The AST of `exported_generic` stored in crate_with_invalid_spans's + // metadata should contain an invalid span where span.lo > span.hi. + // Let's make sure the compiler doesn't crash when encountering this. + let _ = crate_with_invalid_spans::exported_generic(32u32, 7u32); +} diff --git a/src/test/run-pass/issue-13304.rs b/src/test/run-pass/issue-13304.rs index f1c747eca68..bd2ddc6b9b2 100644 --- a/src/test/run-pass/issue-13304.rs +++ b/src/test/run-pass/issue-13304.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-aarch64 + use std::env; use std::io::prelude::*; use std::io; diff --git a/src/test/run-pass/issue-16272.rs b/src/test/run-pass/issue-16272.rs index 92d8dfa2cf9..9562d113ada 100644 --- a/src/test/run-pass/issue-16272.rs +++ b/src/test/run-pass/issue-16272.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-aarch64 + use std::process::Command; use std::env; diff --git a/src/test/run-pass/issue-20091.rs b/src/test/run-pass/issue-20091.rs index ba107dd2cf9..fe9ae022d88 100644 --- a/src/test/run-pass/issue-20091.rs +++ b/src/test/run-pass/issue-20091.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-aarch64 + #[cfg(unix)] fn main() { use std::process::Command; diff --git a/src/test/run-pass/process-spawn-with-unicode-params.rs b/src/test/run-pass/process-spawn-with-unicode-params.rs index 3e5f84fa26f..466b38e8742 100644 --- a/src/test/run-pass/process-spawn-with-unicode-params.rs +++ b/src/test/run-pass/process-spawn-with-unicode-params.rs @@ -16,6 +16,8 @@ // non-ASCII characters. The child process ensures all the strings are // intact. +// ignore-aarch64 + use std::io::prelude::*; use std::io; use std::fs; diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs index d1a3edcfbc5..5462a996f73 100644 --- a/src/test/run-pass/tcp-connect-timeouts.rs +++ b/src/test/run-pass/tcp-connect-timeouts.rs @@ -10,7 +10,7 @@ // ignore-pretty // compile-flags:--test -// exec-env:RUST_TEST_TASKS=1 +// exec-env:RUST_TEST_THREADS=1 // Tests for the connect_timeout() function on a TcpStream. This runs with only // one test task to ensure that errors are timeouts, not file descriptor diff --git a/src/test/run-pass/unique-send-2.rs b/src/test/run-pass/unique-send-2.rs index 654ac9a095c..e0785779ab3 100644 --- a/src/test/run-pass/unique-send-2.rs +++ b/src/test/run-pass/unique-send-2.rs @@ -25,7 +25,7 @@ pub fn main() { let _t = (0..n).map(|i| { expected += i; let tx = tx.clone(); - thread::spawn(move|| { + thread::scoped(move|| { child(&tx, i) }) }).collect::<Vec<_>>(); |
