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
@ -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
|
||||
|
@ -147,6 +147,7 @@ impl<T> RawVec<T> {
|
||||
/// Gets the capacity of the allocation.
|
||||
///
|
||||
/// This will always be `usize::MAX` if `T` is zero-sized.
|
||||
#[inline(always)]
|
||||
pub fn cap(&self) -> usize {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
!0
|
||||
|
@ -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();
|
||||
|
@ -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]: ../../std/macro.write!.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn write(output: &mut Write, args: Arguments) -> Result {
|
||||
let mut formatter = Formatter {
|
||||
|
@ -1240,9 +1240,6 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, '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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
@ -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
|
||||
|
@ -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##"
|
||||
|
@ -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).
|
||||
"##,
|
||||
|
||||
|
@ -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());
|
||||
@ -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">
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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| {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(unused)]
|
||||
fn main() {
|
||||
|| {
|
||||
'label: loop {
|
||||
}
|
||||
};
|
||||
|
||||
// More cases added from issue 31754
|
||||
|
||||
'label2: loop {
|
||||
break;
|
||||
}
|
||||
|
||||
let closure = || {
|
||||
'label2: loop {}
|
||||
};
|
||||
|
||||
fn inner_fn() {
|
||||
'label2: loop {}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user