Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 10 pull requests #33523

Merged
merged 25 commits into from
May 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7f09b1f
std: Allow creating ExitStatus from raw values
alexcrichton Apr 26, 2016
dca29d7
save-analysis: use a decoupled representation for dumped data
aochagavia May 3, 2016
ca6062d
Merge branch 'dump' of https://github.com/aochagavia/rust into aochag…
nrc May 6, 2016
01be25b
Use crate/index pair for def ids
nrc May 6, 2016
083c395
Update CSS for future rustdoc merge
GuillaumeGomez May 5, 2016
cdca084
Improve rustdoc css of "source" and "since" elements
GuillaumeGomez May 6, 2016
5071728
Add detailed error explanation for E0509
cramertj May 3, 2016
d75c079
book: fixup code in error handling tutorial
birkenfeld May 7, 2016
a7439ad
Fix minor typo in E0312
silvo38 May 8, 2016
cf8a1b0
Add E0408/E0409
Manishearth May 6, 2016
192e336
Merge pull request #1 from nrc/save-ids-fix
aochagavia May 8, 2016
84843b7
Merge E0410 into E0408
Manishearth May 6, 2016
ba17bd0
rustdoc: fix emitting duplicate implementors in .js files
birkenfeld May 9, 2016
62b19c6
Utilize `Result::unwrap_err` in more places.
frewsxcv May 6, 2016
6100b70
rustdoc: do not strip blanket impls in crate of origin
birkenfeld May 9, 2016
d394aa0
Rollup merge of #33224 - alexcrichton:create-exit-status, r=aturon
Manishearth May 9, 2016
9f5f997
Rollup merge of #33370 - aochagavia:dump, r=nrc
Manishearth May 9, 2016
57fa783
Rollup merge of #33383 - cramertj:E0509, r=Manishearth
Manishearth May 9, 2016
c45d481
Rollup merge of #33431 - GuillaumeGomez:issue-30416, r=steveklabnik
Manishearth May 9, 2016
fffaf66
Rollup merge of #33474 - frewsxcv:unwrap-err, r=alexcrichton
Manishearth May 9, 2016
35cc6b0
Rollup merge of #33480 - birkenfeld:issue-33422, r=steveklabnik
Manishearth May 9, 2016
6436b60
Rollup merge of #33496 - silvo38:master, r=apasel422
Manishearth May 9, 2016
fb382df
Rollup merge of #33509 - birkenfeld:issue-30219, r=alexcrichton
Manishearth May 9, 2016
433f907
Rollup merge of #33514 - birkenfeld:issue-29503, r=alexcrichton
Manishearth May 9, 2016
52f48bd
Rollup merge of #33493 - Manishearth:more-diag, r=Manishearth
Manishearth May 9, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 61 additions & 59 deletions src/doc/book/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -1573,8 +1573,9 @@ detail on Getopts, but there is [some good documentation][15]
describing it. The short story is that Getopts generates an argument
parser and a help message from a vector of options (The fact that it
is a vector is hidden behind a struct and a set of methods). Once the
parsing is done, we can decode the program arguments into a Rust
struct. From there, we can get information about the flags, for
parsing is done, the parser returns a struct that records matches
for defined options, and remaining "free" arguments.
From there, we can get information about the flags, for
instance, whether they were passed in, and what arguments they
had. Here's our program with the appropriate `extern crate`
statements, and the basic argument setup for Getopts:
Expand Down Expand Up @@ -1605,8 +1606,8 @@ fn main() {
print_usage(&program, opts);
return;
}
let data_path = &args[1];
let city = &args[2];
let data_path = &matches.free[0];
let city: &str = &matches.free[1];

// Do stuff with information
}
Expand Down Expand Up @@ -1680,8 +1681,8 @@ fn main() {
return;
}

let data_path = &args[1];
let city: &str = &args[2];
let data_path = &matches.free[0];
let city: &str = &matches.free[1];

let file = File::open(data_path).unwrap();
let mut rdr = csv::Reader::from_reader(file);
Expand Down Expand Up @@ -1792,13 +1793,15 @@ fn main() {
Ok(m) => { m }
Err(e) => { panic!(e.to_string()) }
};

if matches.opt_present("h") {
print_usage(&program, opts);
return;
}

let data_path = &args[1];
let city = &args[2];
let data_path = &matches.free[0];
let city: &str = &matches.free[1];

for pop in search(data_path, city) {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
Expand Down Expand Up @@ -1876,14 +1879,14 @@ when calling `search`:

```rust,ignore
...
match search(&data_file, &city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
match search(data_path, city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
}
Err(err) => println!("{}", err)
}
Err(err) => println!("{}", err)
}
...
```

Expand Down Expand Up @@ -1914,43 +1917,37 @@ fn print_usage(program: &str, opts: Options) {
println!("{}", opts.usage(&format!("Usage: {} [options] <city>", program)));
}
```
The next part is going to be only a little harder:
Of course we need to adapt the argument handling code:

```rust,ignore
...
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
...
let file = matches.opt_str("f");
let data_file = &file.as_ref().map(Path::new);

let city = if !matches.free.is_empty() {
&matches.free[0]
} else {
print_usage(&program, opts);
return;
};

match search(data_file, city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
...
let data_path = matches.opt_str("f");

let city = if !matches.free.is_empty() {
&matches.free[0]
} else {
print_usage(&program, opts);
return;
};

match search(&data_path, city) {
Ok(pops) => {
for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
}
Err(err) => println!("{}", err)
}
Err(err) => println!("{}", err)
}
...
```

In this piece of code, we take `file` (which has the type
`Option<String>`), and convert it to a type that `search` can use, in
this case, `&Option<AsRef<Path>>`. To do this, we take a reference of
file, and map `Path::new` onto it. In this case, `as_ref()` converts
the `Option<String>` into an `Option<&str>`, and from there, we can
execute `Path::new` to the content of the optional, and return the
optional of the new value. Once we have that, it is a simple matter of
getting the `city` argument and executing `search`.
We've made the user experience a bit nicer by showing the usage message,
instead of a panic from an out-of-bounds index, when `city`, the
remaining free argument, is not present.

Modifying `search` is slightly trickier. The `csv` crate can build a
parser out of
Expand Down Expand Up @@ -2000,6 +1997,8 @@ enum CliError {
And now for impls on `Display` and `Error`:

```rust,ignore
use std::fmt;

impl fmt::Display for CliError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expand All @@ -2020,13 +2019,13 @@ impl Error for CliError {
}
}

fn cause(&self) -> Option<&error::Error> {
match *self {
fn cause(&self) -> Option<&Error> {
match *self {
CliError::Io(ref err) => Some(err),
CliError::Parse(ref err) => Some(err),
// Our custom error doesn't have an underlying cause, but we could
// modify it so that it does.
CliError::NotFound() => None,
CliError::Csv(ref err) => Some(err),
// Our custom error doesn't have an underlying cause,
// but we could modify it so that it does.
CliError::NotFound => None,
}
}
}
Expand Down Expand Up @@ -2122,24 +2121,27 @@ string and add a flag to the Option variable. Once we've done that, Getopts does

```rust,ignore
...
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
opts.optflag("q", "quiet", "Silences errors and warnings.");
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
opts.optflag("q", "quiet", "Silences errors and warnings.");
...
```

Now we only need to implement our “quiet” functionality. This requires us to
tweak the case analysis in `main`:

```rust,ignore
match search(&args.arg_data_path, &args.arg_city) {
Err(CliError::NotFound) if args.flag_quiet => process::exit(1),
Err(err) => panic!("{}", err),
Ok(pops) => for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
use std::process;
...
match search(&data_path, city) {
Err(CliError::NotFound) if matches.opt_present("q") => process::exit(1),
Err(err) => panic!("{}", err),
Ok(pops) => for pop in pops {
println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
}
}
}
...
```

Certainly, we don't want to be quiet if there was an IO error or if the data
Expand Down
2 changes: 1 addition & 1 deletion src/libcollectionstest/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn test_from_utf8() {
String::from("ศไทย中华Việt Nam"));

let xs = b"hello\xFF".to_vec();
let err = String::from_utf8(xs).err().unwrap();
let err = String::from_utf8(xs).unwrap_err();
assert_eq!(err.into_bytes(), b"hello\xff".to_vec());
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
}
infer::Reborrow(span) => {
let mut err = struct_span_err!(self.tcx.sess, span, E0312,
"lifetime of reference outlines \
"lifetime of reference outlives \
lifetime of borrowed content...");
self.tcx.note_and_explain_region(&mut err,
"...the reference is valid for ",
Expand Down
96 changes: 95 additions & 1 deletion src/librustc_borrowck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,101 @@ You can find more information about borrowing in the rust-book:
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
"##,

E0509: r##"
This error occurs when an attempt is made to move out of a value whose type
implements the `Drop` trait.

Example of erroneous code:

```compile_fail
struct FancyNum {
num: usize
}

struct DropStruct {
fancy: FancyNum
}

impl Drop for DropStruct {
fn drop(&mut self) {
// Destruct DropStruct, possibly using FancyNum
}
}

fn main() {
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
let fancy_field = drop_struct.fancy; // Error E0509
println!("Fancy: {}", fancy_field.num);
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
}
```

Here, we tried to move a field out of a struct of type `DropStruct` which
implements the `Drop` trait. However, a struct cannot be dropped if one or
more of its fields have been moved.

Structs implementing the `Drop` trait have an implicit destructor that gets
called when they go out of scope. This destructor may use the fields of the
struct, so moving out of the struct could make it impossible to run the
destructor. Therefore, we must think of all values whose type implements the
`Drop` trait as single units whose fields cannot be moved.

This error can be fixed by creating a reference to the fields of a struct,
enum, or tuple using the `ref` keyword:

```
struct FancyNum {
num: usize
}

struct DropStruct {
fancy: FancyNum
}

impl Drop for DropStruct {
fn drop(&mut self) {
// Destruct DropStruct, possibly using FancyNum
}
}

fn main() {
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
let ref fancy_field = drop_struct.fancy; // No more errors!
println!("Fancy: {}", fancy_field.num);
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
}
```

Note that this technique can also be used in the arms of a match expression:

```
struct FancyNum {
num: usize
}

enum DropEnum {
Fancy(FancyNum)
}

impl Drop for DropEnum {
fn drop(&mut self) {
// Destruct DropEnum, possibly using FancyNum
}
}

fn main() {
// Creates and enum of type `DropEnum`, which implements `Drop`
let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
match drop_enum {
// Creates a reference to the inside of `DropEnum::Fancy`
DropEnum::Fancy(ref fancy_field) => // No error!
println!("It was fancy-- {}!", fancy_field.num),
}
// implicit call to `drop_enum.drop()` as drop_enum goes out of scope
}
```
"##,

}

register_diagnostics! {
Expand All @@ -664,6 +759,5 @@ register_diagnostics! {
E0504, // cannot move `..` into closure because it is borrowed
E0505, // cannot move out of `..` because it is borrowed
E0508, // cannot move out of type `..`, a non-copy fixed-size array
E0509, // cannot move out of type `..`, which defines the `Drop` trait
E0524, // two closures require unique access to `..` at the same time
}
Loading