Auto merge of #33556 - steveklabnik:rollup, r=steveklabnik
Rollup of 9 pull requests - Successful merges: #33129, #33260, #33345, #33386, #33522, #33524, #33528, #33539, #33542 - Failed merges: #33342, #33475, #33517
This commit is contained in:
commit
e37f8593e4
13 changed files with 262 additions and 20 deletions
|
@ -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
|
it can't really intimately understand allocation. Instead, the main idea behind
|
||||||
allocation is "doesn't overlap with other stuff". That is, heap allocations,
|
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
|
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*.
|
an allocation as long as it's *consistent*.
|
||||||
|
|
||||||
Getting back to the empty allocation case, there are a couple of places where
|
Getting back to the empty allocation case, there are a couple of places where
|
||||||
|
|
|
@ -147,6 +147,7 @@ impl<T> RawVec<T> {
|
||||||
/// Gets the capacity of the allocation.
|
/// Gets the capacity of the allocation.
|
||||||
///
|
///
|
||||||
/// This will always be `usize::MAX` if `T` is zero-sized.
|
/// This will always be `usize::MAX` if `T` is zero-sized.
|
||||||
|
#[inline(always)]
|
||||||
pub fn cap(&self) -> usize {
|
pub fn cap(&self) -> usize {
|
||||||
if mem::size_of::<T>() == 0 {
|
if mem::size_of::<T>() == 0 {
|
||||||
!0
|
!0
|
||||||
|
|
|
@ -521,12 +521,24 @@ use string;
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::fmt;
|
/// use std::fmt;
|
||||||
///
|
///
|
||||||
/// let s = fmt::format(format_args!("Hello, {}!", "world"));
|
/// let s = fmt::format(format_args!("Hello, {}!", "world"));
|
||||||
/// assert_eq!(s, "Hello, world!".to_string());
|
/// 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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn format(args: Arguments) -> string::String {
|
pub fn format(args: Arguments) -> string::String {
|
||||||
let mut output = string::String::new();
|
let mut output = string::String::new();
|
||||||
|
|
|
@ -776,6 +776,32 @@ pub trait UpperExp {
|
||||||
///
|
///
|
||||||
/// * output - the buffer to write output to
|
/// * output - the buffer to write output to
|
||||||
/// * args - the precompiled arguments generated by `format_args!`
|
/// * 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]: ../../std/macro.write!.html
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn write(output: &mut Write, args: Arguments) -> Result {
|
pub fn write(output: &mut Write, args: Arguments) -> Result {
|
||||||
let mut formatter = Formatter {
|
let mut formatter = Formatter {
|
||||||
|
|
|
@ -1240,9 +1240,6 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
|
||||||
orig_node_idx,
|
orig_node_idx,
|
||||||
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);
|
process_edges(self, &mut state, graph, node_idx, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,12 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
FnKind::Closure(_) => {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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##"
|
E0506: r##"
|
||||||
This error occurs when an attempt is made to assign to a borrowed value.
|
This error occurs when an attempt is made to assign to a borrowed value.
|
||||||
|
|
||||||
|
@ -756,7 +860,6 @@ register_diagnostics! {
|
||||||
E0500, // closure requires unique access to `..` but .. is already borrowed
|
E0500, // closure requires unique access to `..` but .. is already borrowed
|
||||||
E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
|
E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
|
||||||
E0503, // cannot use `..` because it was mutably borrowed
|
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
|
E0505, // cannot move out of `..` because it is borrowed
|
||||||
E0508, // cannot move out of type `..`, a non-copy fixed-size array
|
E0508, // cannot move out of type `..`, a non-copy fixed-size array
|
||||||
E0524, // two closures require unique access to `..` at the same time
|
E0524, // two closures require unique access to `..` at the same time
|
||||||
|
|
|
@ -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
|
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
|
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
|
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
|
therefore becomes unavailable in the body of the arm.
|
||||||
innocuous, the problem is most clear when considering functions that take their
|
|
||||||
argument by value.
|
|
||||||
|
|
||||||
```compile_fail
|
The problem above can be solved by using the `ref` keyword.
|
||||||
|
|
||||||
|
```
|
||||||
match Some("hi".to_string()) {
|
match Some("hi".to_string()) {
|
||||||
Some(s) if { drop(s); false } => (),
|
Some(ref s) if s.len() == 0 => {},
|
||||||
Some(s) => {}, // use s.
|
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The value would be dropped in the guard then become unavailable not only in the
|
Though this example seems innocuous and easy to solve, the problem becomes clear
|
||||||
body of that arm but also in all subsequent arms! The solution is to bind by
|
when it encounters functions which consume the value:
|
||||||
reference when using guards or refactor the entire expression, perhaps by
|
|
||||||
putting the condition inside the body of the arm.
|
```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##"
|
E0009: r##"
|
||||||
|
|
|
@ -742,7 +742,7 @@ fn f(a: u16, b: &str) {}
|
||||||
|
|
||||||
Must always be called with exactly two arguments, e.g. `f(2, "test")`.
|
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).
|
variadic functions (except for its C-FFI).
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
|
|
|
@ -1537,7 +1537,6 @@ impl<'a> Item<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a> fmt::Display for Item<'a> {
|
impl<'a> fmt::Display for Item<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
debug_assert!(!self.item.is_stripped());
|
debug_assert!(!self.item.is_stripped());
|
||||||
|
@ -1575,6 +1574,9 @@ impl<'a> fmt::Display for Item<'a> {
|
||||||
|
|
||||||
write!(fmt, "</span>")?; // in-band
|
write!(fmt, "</span>")?; // in-band
|
||||||
write!(fmt, "<span class='out-of-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,
|
write!(fmt,
|
||||||
r##"<span id='render-detail'>
|
r##"<span id='render-detail'>
|
||||||
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
|
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
|
||||||
|
@ -1922,7 +1924,6 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||||
generics = f.generics,
|
generics = f.generics,
|
||||||
where_clause = WhereClause(&f.generics),
|
where_clause = WhereClause(&f.generics),
|
||||||
decl = f.decl)?;
|
decl = f.decl)?;
|
||||||
render_stability_since_raw(w, it.stable_since(), None)?;
|
|
||||||
document(w, cx, it)
|
document(w, cx, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2236,7 +2237,6 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||||
"",
|
"",
|
||||||
true)?;
|
true)?;
|
||||||
write!(w, "</pre>")?;
|
write!(w, "</pre>")?;
|
||||||
render_stability_since_raw(w, it.stable_since(), None)?;
|
|
||||||
|
|
||||||
document(w, cx, it)?;
|
document(w, cx, it)?;
|
||||||
let mut fields = s.fields.iter().filter(|f| {
|
let mut fields = s.fields.iter().filter(|f| {
|
||||||
|
|
|
@ -634,6 +634,12 @@ a.test-arrow {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.since {
|
||||||
|
position: initial;
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Media Queries */
|
/* Media Queries */
|
||||||
|
|
||||||
@media (max-width: 700px) {
|
@media (max-width: 700px) {
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
// This test checks that the error messages you get for this example
|
||||||
|
// at least mention `'a` and `'static`. The precise messages can drift
|
||||||
|
// over time, but this test used to exhibit some pretty bogus messages
|
||||||
|
// that were not remotely helpful.
|
||||||
|
|
||||||
|
// error-pattern:cannot infer
|
||||||
|
// error-pattern:cannot outlive the lifetime 'a
|
||||||
|
// error-pattern:must be valid for the static lifetime
|
||||||
|
// error-pattern:cannot infer
|
||||||
|
// error-pattern:cannot outlive the lifetime 'a
|
||||||
|
// error-pattern:must be valid for the static lifetime
|
||||||
|
|
||||||
|
struct Invariant<'a>(Option<&'a mut &'a mut ()>);
|
||||||
|
|
||||||
|
fn mk_static() -> Invariant<'static> { Invariant(None) }
|
||||||
|
|
||||||
|
fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
|
||||||
|
let bad = if x.is_some() {
|
||||||
|
x.unwrap()
|
||||||
|
} else {
|
||||||
|
mk_static()
|
||||||
|
};
|
||||||
|
f(bad);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -8,9 +8,24 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
fn main() {
|
fn main() {
|
||||||
|| {
|
|| {
|
||||||
'label: loop {
|
'label: loop {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// More cases added from issue 31754
|
||||||
|
|
||||||
|
'label2: loop {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let closure = || {
|
||||||
|
'label2: loop {}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn inner_fn() {
|
||||||
|
'label2: loop {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue