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 9 pull requests #33548

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
6fed013
middle: reset loop labels while visiting closure
birkenfeld May 2, 2016
201d9ed
add help on pattern guard
mrmiywj Apr 30, 2016
1bd4c9d
Doc improvement on std::fmt module
GuillaumeGomez May 1, 2016
38a5338
Add detailed error explanation for E0504
cramertj May 3, 2016
9d2c45d
doc: Fix tiny typo in vec-alloc.md
briangreenery May 9, 2016
d8882e2
E0061 typo fix
cramertj May 10, 2016
84034d4
typeck: if a private field exists, also check for a public method
birkenfeld May 2, 2016
de0906f
fix DFS for region error reporting
nikomatsakis May 10, 2016
a5a2f2b
Improve "since" tag placement
GuillaumeGomez May 10, 2016
b6b3b7b
Rollup merge of #33129 - GuillaumeGomez:fmt_doc, r=steveklabnik
steveklabnik May 10, 2016
1590fdd
Rollup merge of #33260 - mrmiywj:help-on-pattern-guard, r=guillaumegomez
steveklabnik May 10, 2016
fc299c0
Rollup merge of #33342 - birkenfeld:issue-26472, r=jseyfried
steveklabnik May 10, 2016
a9b9782
Rollup merge of #33345 - birkenfeld:issue-31754, r=pnkfelix
steveklabnik May 10, 2016
cb12cf0
Rollup merge of #33386 - cramertj:E0504, r=steveklabnik
steveklabnik May 10, 2016
25ce1f9
Rollup merge of #33524 - briangreenery:briangreenery-fast-and-loose, …
steveklabnik May 10, 2016
5d38a87
Rollup merge of #33528 - cramertj:E0061typeo, r=jseyfried
steveklabnik May 10, 2016
26cca1a
Rollup merge of #33539 - nikomatsakis:static-error, r=pnkfelix
steveklabnik May 10, 2016
d0580a7
Rollup merge of #33542 - GuillaumeGomez:move_since, r=steveklabnik
steveklabnik May 10, 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
2 changes: 1 addition & 1 deletion src/doc/nomicon/vec-alloc.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ LLVM needs to work with different languages' semantics and custom allocators,
it can't really intimately understand allocation. Instead, the main idea behind
allocation is "doesn't overlap with other stuff". That is, heap allocations,
stack allocations, and globals don't randomly overlap. Yep, it's about alias
analysis. As such, Rust can technically play a bit fast an loose with the notion of
analysis. As such, Rust can technically play a bit fast and loose with the notion of
an allocation as long as it's *consistent*.

Getting back to the empty allocation case, there are a couple of places where
Expand Down
12 changes: 12 additions & 0 deletions src/libcollections/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,12 +521,24 @@ use string;
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::fmt;
///
/// let s = fmt::format(format_args!("Hello, {}!", "world"));
/// assert_eq!(s, "Hello, world!".to_string());
/// ```
///
/// Please note that using [`format!`][format!] might be preferrable.
/// Example:
///
/// ```
/// let s = format!("Hello, {}!", "world");
/// assert_eq!(s, "Hello, world!".to_string());
/// ```
///
/// [format!]: ../macro.format!.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn format(args: Arguments) -> string::String {
let mut output = string::String::new();
Expand Down
26 changes: 26 additions & 0 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,32 @@ pub trait UpperExp {
///
/// * output - the buffer to write output to
/// * args - the precompiled arguments generated by `format_args!`
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::fmt;
///
/// let mut output = String::new();
/// fmt::write(&mut output, format_args!("Hello {}!", "world"))
/// .expect("Error occurred while trying to write in String");
/// assert_eq!(output, "Hello world!");
/// ```
///
/// Please note that using [`write!`][write_macro] might be preferrable. Example:
///
/// ```
/// use std::fmt::Write;
///
/// let mut output = String::new();
/// write!(&mut output, "Hello {}!", "world")
/// .expect("Error occurred while trying to write in String");
/// assert_eq!(output, "Hello world!");
/// ```
///
/// [write_macro]: ../macro.write!.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write(output: &mut Write, args: Arguments) -> Result {
let mut formatter = Formatter {
Expand Down
3 changes: 0 additions & 3 deletions src/librustc/infer/region_inference/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,9 +1240,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
orig_node_idx,
node_idx);

// figure out the direction from which this node takes its
// values, and search for concrete regions etc in that direction
let dir = graph::INCOMING;
process_edges(self, &mut state, graph, node_idx, dir);
}

Expand Down
7 changes: 6 additions & 1 deletion src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,12 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
})
}
FnKind::Closure(_) => {
self.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
// Closures have their own set of labels, save labels just
// like for foreign items above.
let saved = replace(&mut self.labels_in_fn, vec![]);
let result = self.add_scope_and_walk_fn(fk, fd, b, s, fn_id);
replace(&mut self.labels_in_fn, saved);
result
}
}
}
Expand Down
105 changes: 104 additions & 1 deletion src/librustc_borrowck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,110 @@ fn foo(a: &mut i32) {
```
"##,

E0504: r##"
This error occurs when an attempt is made to move a borrowed variable into a
closure.

Example of erroneous code:

```compile_fail
struct FancyNum {
num: u8
}

fn main() {
let fancy_num = FancyNum { num: 5 };
let fancy_ref = &fancy_num;

let x = move || {
println!("child function: {}", fancy_num.num);
// error: cannot move `fancy_num` into closure because it is borrowed
};

x();
println!("main function: {}", fancy_ref.num);
}
```

Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into
the closure `x`. There is no way to move a value into a closure while it is
borrowed, as that would invalidate the borrow.

If the closure can't outlive the value being moved, try using a reference
rather than moving:

```
struct FancyNum {
num: u8
}

fn main() {
let fancy_num = FancyNum { num: 5 };
let fancy_ref = &fancy_num;

let x = move || {
// fancy_ref is usable here because it doesn't move `fancy_num`
println!("child function: {}", fancy_ref.num);
};

x();

println!("main function: {}", fancy_num.num);
}
```

If the value has to be borrowed and then moved, try limiting the lifetime of
the borrow using a scoped block:

```
struct FancyNum {
num: u8
}

fn main() {
let fancy_num = FancyNum { num: 5 };

{
let fancy_ref = &fancy_num;
println!("main function: {}", fancy_ref.num);
// `fancy_ref` goes out of scope here
}

let x = move || {
// `fancy_num` can be moved now (no more references exist)
println!("child function: {}", fancy_num.num);
};

x();
}
```

If the lifetime of a reference isn't enough, such as in the case of threading,
consider using an `Arc` to create a reference-counted value:

```
use std::sync::Arc;
use std::thread;

struct FancyNum {
num: u8
}

fn main() {
let fancy_ref1 = Arc::new(FancyNum { num: 5 });
let fancy_ref2 = fancy_ref1.clone();

let x = thread::spawn(move || {
// `fancy_ref1` can be moved and has a `'static` lifetime
println!("child thread: {}", fancy_ref1.num);
});

x.join().expect("child thread should finish");
println!("main thread: {}", fancy_ref2.num);
}
```
"##,

E0506: r##"
This error occurs when an attempt is made to assign to a borrowed value.

Expand Down Expand Up @@ -756,7 +860,6 @@ register_diagnostics! {
E0500, // closure requires unique access to `..` but .. is already borrowed
E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
E0503, // cannot use `..` because it was mutably borrowed
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
E0524, // two closures require unique access to `..` at the same time
Expand Down
61 changes: 51 additions & 10 deletions src/librustc_const_eval/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,22 +215,63 @@ match Some("hi".to_string()) {
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.
therefore becomes unavailable in the body of the arm.

```compile_fail
The problem above can be solved by using the `ref` keyword.

```
match Some("hi".to_string()) {
Some(s) if { drop(s); false } => (),
Some(s) => {}, // use s.
Some(ref s) if s.len() == 0 => {},
_ => {},
}
```

The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
reference when using guards or refactor the entire expression, perhaps by
putting the condition inside the body of the arm.
Though this example seems innocuous and easy to solve, the problem becomes clear
when it encounters functions which consume the value:

```compile_fail
struct A{}

impl A {
fn consume(self) -> usize {
0
}
}

fn main() {
let a = Some(A{});
match a {
Some(y) if y.consume() > 0 => {}
_ => {}
}
}
```

In this situation, even the `ref` keyword cannot solve it, since borrowed
content cannot be moved. This problem cannot be solved generally. If the value
can be cloned, here is a not-so-specific solution:

```
#[derive(Clone)]
struct A{}

impl A {
fn consume(self) -> usize {
0
}
}

fn main() {
let a = Some(A{});
match a{
Some(ref y) if y.clone().consume() > 0 => {}
_ => {}
}
}
```

If the value will be consumed in the pattern guard, using its clone will not
move its ownership, so the code works.
"##,

E0009: r##"
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
method_name: ast::Name,
self_ty: ty::Ty<'tcx>,
call_expr_id: ast::NodeId)
call_expr_id: ast::NodeId,
allow_private: bool)
-> bool
{
let mode = probe::Mode::MethodCall;
Expand All @@ -92,7 +93,7 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
Err(ClosureAmbiguity(..)) => true,
Err(PrivateMatch(..)) => true,
Err(PrivateMatch(..)) => allow_private,
}
}

Expand Down
12 changes: 9 additions & 3 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2947,12 +2947,18 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,

if let Some((did, field_ty)) = private_candidate {
let struct_path = fcx.tcx().item_path_str(did);
let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
fcx.tcx().sess.span_err(expr.span, &msg);
fcx.write_ty(expr.id, field_ty);
let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
let mut err = fcx.tcx().sess.struct_span_err(expr.span, &msg);
// Also check if an accessible method exists, which is often what is meant.
if method::exists(fcx, field.span, field.node, expr_t, expr.id, false) {
err.note(&format!("a method `{}` also exists, \
perhaps you wish to call it", field.node));
}
err.emit();
} else if field.node == keywords::Invalid.name() {
fcx.write_error(expr.id);
} else if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
} else if method::exists(fcx, field.span, field.node, expr_t, expr.id, true) {
fcx.type_error_struct(field.span,
|actual| {
format!("attempted to take value of method `{}` on type \
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ fn f(a: u16, b: &str) {}

Must always be called with exactly two arguments, e.g. `f(2, "test")`.

Note, that Rust does not have a notion of optional function arguments or
Note that Rust does not have a notion of optional function arguments or
variadic functions (except for its C-FFI).
"##,

Expand Down
6 changes: 3 additions & 3 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1537,7 +1537,6 @@ impl<'a> Item<'a> {
}
}


impl<'a> fmt::Display for Item<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
debug_assert!(!self.item.is_stripped());
Expand Down Expand Up @@ -1575,6 +1574,9 @@ impl<'a> fmt::Display for Item<'a> {

write!(fmt, "</span>")?; // in-band
write!(fmt, "<span class='out-of-band'>")?;
if let Some(version) = self.item.stable_since() {
write!(fmt, "<span class='since'>{}</span>", version)?;
}
write!(fmt,
r##"<span id='render-detail'>
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
Expand Down Expand Up @@ -1922,7 +1924,6 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
generics = f.generics,
where_clause = WhereClause(&f.generics),
decl = f.decl)?;
render_stability_since_raw(w, it.stable_since(), None)?;
document(w, cx, it)
}

Expand Down Expand Up @@ -2236,7 +2237,6 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
"",
true)?;
write!(w, "</pre>")?;
render_stability_since_raw(w, it.stable_since(), None)?;

document(w, cx, it)?;
let mut fields = s.fields.iter().filter(|f| {
Expand Down
6 changes: 6 additions & 0 deletions src/librustdoc/html/static/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,12 @@ a.test-arrow {
padding-left: 10px;
}

span.since {
position: initial;
font-size: 20px;
margin-right: 5px;
}

/* Media Queries */

@media (max-width: 700px) {
Expand Down
Loading