Auto merge of #45167 - pnkfelix:migrate-remaining-ast-diagnostics, r=arielb1
MIR-borrowck: Migrate remaining ast diagnostics This PR migrates all of the remaining diagnostics in `rustc_borrowck` over to `rustc_mir`, exposing them for use by both AST-borrowck and MIR-borrowck. This should hopefully resolve all remaining cases of diagnostic messages emitted from borrowck under `-Z borrowck-mir` without an origin annotation.
This commit is contained in:
commit
9c5e9a500d
6 changed files with 622 additions and 530 deletions
|
|
@ -614,11 +614,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
let partial = moved_lp.depth() > lp.depth();
|
||||
let msg = if !has_fork && partial { "partially " }
|
||||
else if has_fork && !has_common { "collaterally "}
|
||||
else { "" };
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, use_span, E0382,
|
||||
"{} of {}moved value: `{}`",
|
||||
verb, msg, nl);
|
||||
else { "" };
|
||||
let mut err = self.cannot_act_on_moved_value(use_span,
|
||||
verb,
|
||||
msg,
|
||||
&format!("{}", nl),
|
||||
Origin::Ast);
|
||||
let need_note = match lp.ty.sty {
|
||||
ty::TypeVariants::TyClosure(id, _) => {
|
||||
let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
|
||||
|
|
@ -698,10 +699,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
span: Span,
|
||||
lp: &LoanPath<'tcx>) {
|
||||
span_err!(
|
||||
self.tcx.sess, span, E0383,
|
||||
"partial reinitialization of uninitialized structure `{}`",
|
||||
self.loan_path_to_string(lp));
|
||||
self.cannot_partially_reinit_an_uninit_struct(span,
|
||||
&self.loan_path_to_string(lp),
|
||||
Origin::Ast)
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub fn report_reassigned_immutable_variable(&self,
|
||||
|
|
@ -776,8 +777,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
db
|
||||
}
|
||||
BorrowViolation(euv::ClosureCapture(_)) => {
|
||||
struct_span_err!(self.tcx.sess, error_span, E0595,
|
||||
"closure cannot assign to {}", descr)
|
||||
self.closure_cannot_assign_to_borrowed(error_span, &descr, Origin::Ast)
|
||||
}
|
||||
BorrowViolation(euv::OverloadedOperator) |
|
||||
BorrowViolation(euv::AddrOf) |
|
||||
|
|
@ -786,8 +786,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
BorrowViolation(euv::AutoUnsafe) |
|
||||
BorrowViolation(euv::ForLoop) |
|
||||
BorrowViolation(euv::MatchDiscriminant) => {
|
||||
struct_span_err!(self.tcx.sess, error_span, E0596,
|
||||
"cannot borrow {} as mutable", descr)
|
||||
self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast)
|
||||
}
|
||||
BorrowViolation(euv::ClosureInvocation) => {
|
||||
span_bug!(err.span,
|
||||
|
|
@ -869,21 +868,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
if let Some((yield_span, _)) = maybe_borrow_across_yield {
|
||||
debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span);
|
||||
struct_span_err!(self.tcx.sess,
|
||||
error_span,
|
||||
E0626,
|
||||
"borrow may still be in use when generator yields")
|
||||
.span_label(yield_span, "possible yield occurs here")
|
||||
self.cannot_borrow_across_generator_yield(error_span, yield_span, Origin::Ast)
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
let mut db = struct_span_err!(self.tcx.sess,
|
||||
error_span,
|
||||
E0597,
|
||||
"{} does not live long enough",
|
||||
msg);
|
||||
|
||||
let mut db = self.path_does_not_live_long_enough(error_span, &msg, Origin::Ast);
|
||||
let (value_kind, value_msg) = match err.cmt.cat {
|
||||
mc::Categorization::Rvalue(..) =>
|
||||
("temporary value", "temporary value created here"),
|
||||
|
|
@ -992,11 +982,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
|
||||
let descr = self.cmt_to_path_or_string(&err.cmt);
|
||||
let mut db = struct_span_err!(self.tcx.sess, error_span, E0598,
|
||||
"lifetime of {} is too short to guarantee \
|
||||
its contents can be safely reborrowed",
|
||||
descr);
|
||||
|
||||
let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast);
|
||||
let descr = match opt_loan_path(&err.cmt) {
|
||||
Some(lp) => {
|
||||
format!("`{}`", self.loan_path_to_string(&lp))
|
||||
|
|
@ -1068,12 +1054,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
let blame = cmt.immutability_blame();
|
||||
let mut err = match blame {
|
||||
Some(ImmutabilityBlame::ClosureEnv(id)) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, span, E0387,
|
||||
"{} in a captured outer variable in an `Fn` closure", prefix);
|
||||
|
||||
// FIXME: the distinction between these 2 messages looks wrong.
|
||||
let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
|
||||
let help_msg = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
|
||||
// The aliasability violation with closure captures can
|
||||
// happen for nested closures, so we know the enclosing
|
||||
// closure incorrectly accepts an `Fn` while it needs to
|
||||
|
|
@ -1084,15 +1066,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
"consider changing this closure to take self by mutable reference"
|
||||
};
|
||||
let node_id = self.tcx.hir.def_index_to_node_id(id);
|
||||
err.span_help(self.tcx.hir.span(node_id), help);
|
||||
err
|
||||
let help_span = self.tcx.hir.span(node_id);
|
||||
self.cannot_act_on_capture_in_sharable_fn(span,
|
||||
prefix,
|
||||
(help_span, help_msg),
|
||||
Origin::Ast)
|
||||
}
|
||||
_ => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, span, E0389,
|
||||
"{} in a `&` reference", prefix);
|
||||
err.span_label(span, "assignment into an immutable reference");
|
||||
err
|
||||
self.cannot_assign_into_immutable_reference(span, prefix,
|
||||
Origin::Ast)
|
||||
}
|
||||
};
|
||||
self.note_immutability_blame(&mut err, blame);
|
||||
|
|
@ -1244,17 +1226,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
Err(_) => format!("move |<args>| <body>")
|
||||
};
|
||||
|
||||
struct_span_err!(self.tcx.sess, err.span, E0373,
|
||||
"closure may outlive the current function, \
|
||||
but it borrows {}, \
|
||||
which is owned by the current function",
|
||||
cmt_path_or_string)
|
||||
.span_label(capture_span,
|
||||
format!("{} is borrowed here",
|
||||
cmt_path_or_string))
|
||||
.span_label(err.span,
|
||||
format!("may outlive borrowed value {}",
|
||||
cmt_path_or_string))
|
||||
self.cannot_capture_in_long_lived_closure(err.span,
|
||||
&cmt_path_or_string,
|
||||
capture_span,
|
||||
Origin::Ast)
|
||||
.span_suggestion(err.span,
|
||||
&format!("to force the closure to take ownership of {} \
|
||||
(and any other referenced variables), \
|
||||
|
|
|
|||
|
|
@ -9,472 +9,3 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
register_long_diagnostics! {
|
||||
|
||||
E0373: r##"
|
||||
This error occurs when an attempt is made to use data captured by a closure,
|
||||
when that data may no longer exist. It's most commonly seen when attempting to
|
||||
return a closure:
|
||||
|
||||
```compile_fail,E0373
|
||||
fn foo() -> Box<Fn(u32) -> u32> {
|
||||
let x = 0u32;
|
||||
Box::new(|y| x + y)
|
||||
}
|
||||
```
|
||||
|
||||
Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
|
||||
closed-over data by reference. This means that once `foo()` returns, `x` no
|
||||
longer exists. An attempt to access `x` within the closure would thus be
|
||||
unsafe.
|
||||
|
||||
Another situation where this might be encountered is when spawning threads:
|
||||
|
||||
```compile_fail,E0373
|
||||
fn foo() {
|
||||
let x = 0u32;
|
||||
let y = 1u32;
|
||||
|
||||
let thr = std::thread::spawn(|| {
|
||||
x + y
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Since our new thread runs in parallel, the stack frame containing `x` and `y`
|
||||
may well have disappeared by the time we try to use them. Even if we call
|
||||
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
|
||||
stack frame won't disappear), we will not succeed: the compiler cannot prove
|
||||
that this behaviour is safe, and so won't let us do it.
|
||||
|
||||
The solution to this problem is usually to switch to using a `move` closure.
|
||||
This approach moves (or copies, where possible) data into the closure, rather
|
||||
than taking references to it. For example:
|
||||
|
||||
```
|
||||
fn foo() -> Box<Fn(u32) -> u32> {
|
||||
let x = 0u32;
|
||||
Box::new(move |y| x + y)
|
||||
}
|
||||
```
|
||||
|
||||
Now that the closure has its own copy of the data, there's no need to worry
|
||||
about safety.
|
||||
"##,
|
||||
|
||||
E0382: r##"
|
||||
This error occurs when an attempt is made to use a variable after its contents
|
||||
have been moved elsewhere. For example:
|
||||
|
||||
```compile_fail,E0382
|
||||
struct MyStruct { s: u32 }
|
||||
|
||||
fn main() {
|
||||
let mut x = MyStruct{ s: 5u32 };
|
||||
let y = x;
|
||||
x.s = 6;
|
||||
println!("{}", x.s);
|
||||
}
|
||||
```
|
||||
|
||||
Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
|
||||
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
|
||||
of workarounds like `Rc`, a value cannot be owned by more than one variable.
|
||||
|
||||
If we own the type, the easiest way to address this problem is to implement
|
||||
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
|
||||
information in `x`, while leaving the original version owned by `x`. Subsequent
|
||||
changes to `x` will not be reflected when accessing `y`.
|
||||
|
||||
```
|
||||
#[derive(Copy, Clone)]
|
||||
struct MyStruct { s: u32 }
|
||||
|
||||
fn main() {
|
||||
let mut x = MyStruct{ s: 5u32 };
|
||||
let y = x;
|
||||
x.s = 6;
|
||||
println!("{}", x.s);
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, if we don't control the struct's definition, or mutable shared
|
||||
ownership is truly required, we can use `Rc` and `RefCell`:
|
||||
|
||||
```
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
struct MyStruct { s: u32 }
|
||||
|
||||
fn main() {
|
||||
let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
|
||||
let y = x.clone();
|
||||
x.borrow_mut().s = 6;
|
||||
println!("{}", x.borrow().s);
|
||||
}
|
||||
```
|
||||
|
||||
With this approach, x and y share ownership of the data via the `Rc` (reference
|
||||
count type). `RefCell` essentially performs runtime borrow checking: ensuring
|
||||
that at most one writer or multiple readers can access the data at any one time.
|
||||
|
||||
If you wish to learn more about ownership in Rust, start with the chapter in the
|
||||
Book:
|
||||
|
||||
https://doc.rust-lang.org/book/first-edition/ownership.html
|
||||
"##,
|
||||
|
||||
E0383: r##"
|
||||
This error occurs when an attempt is made to partially reinitialize a
|
||||
structure that is currently uninitialized.
|
||||
|
||||
For example, this can happen when a drop has taken place:
|
||||
|
||||
```compile_fail,E0383
|
||||
struct Foo {
|
||||
a: u32,
|
||||
}
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) { /* ... */ }
|
||||
}
|
||||
|
||||
let mut x = Foo { a: 1 };
|
||||
drop(x); // `x` is now uninitialized
|
||||
x.a = 2; // error, partial reinitialization of uninitialized structure `t`
|
||||
```
|
||||
|
||||
This error can be fixed by fully reinitializing the structure in question:
|
||||
|
||||
```
|
||||
struct Foo {
|
||||
a: u32,
|
||||
}
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) { /* ... */ }
|
||||
}
|
||||
|
||||
let mut x = Foo { a: 1 };
|
||||
drop(x);
|
||||
x = Foo { a: 2 };
|
||||
```
|
||||
"##,
|
||||
|
||||
/*E0386: r##"
|
||||
This error occurs when an attempt is made to mutate the target of a mutable
|
||||
reference stored inside an immutable container.
|
||||
|
||||
For example, this can happen when storing a `&mut` inside an immutable `Box`:
|
||||
|
||||
```compile_fail,E0386
|
||||
let mut x: i64 = 1;
|
||||
let y: Box<_> = Box::new(&mut x);
|
||||
**y = 2; // error, cannot assign to data in an immutable container
|
||||
```
|
||||
|
||||
This error can be fixed by making the container mutable:
|
||||
|
||||
```
|
||||
let mut x: i64 = 1;
|
||||
let mut y: Box<_> = Box::new(&mut x);
|
||||
**y = 2;
|
||||
```
|
||||
|
||||
It can also be fixed by using a type with interior mutability, such as `Cell`
|
||||
or `RefCell`:
|
||||
|
||||
```
|
||||
use std::cell::Cell;
|
||||
|
||||
let x: i64 = 1;
|
||||
let y: Box<Cell<_>> = Box::new(Cell::new(x));
|
||||
y.set(2);
|
||||
```
|
||||
"##,*/
|
||||
|
||||
E0387: r##"
|
||||
This error occurs when an attempt is made to mutate or mutably reference data
|
||||
that a closure has captured immutably. Examples of this error are shown below:
|
||||
|
||||
```compile_fail,E0387
|
||||
// Accepts a function or a closure that captures its environment immutably.
|
||||
// Closures passed to foo will not be able to mutate their closed-over state.
|
||||
fn foo<F: Fn()>(f: F) { }
|
||||
|
||||
// Attempts to mutate closed-over data. Error message reads:
|
||||
// `cannot assign to data in a captured outer variable...`
|
||||
fn mutable() {
|
||||
let mut x = 0u32;
|
||||
foo(|| x = 2);
|
||||
}
|
||||
|
||||
// Attempts to take a mutable reference to closed-over data. Error message
|
||||
// reads: `cannot borrow data mutably in a captured outer variable...`
|
||||
fn mut_addr() {
|
||||
let mut x = 0u32;
|
||||
foo(|| { let y = &mut x; });
|
||||
}
|
||||
```
|
||||
|
||||
The problem here is that foo is defined as accepting a parameter of type `Fn`.
|
||||
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
|
||||
they capture their context immutably.
|
||||
|
||||
If the definition of `foo` is under your control, the simplest solution is to
|
||||
capture the data mutably. This can be done by defining `foo` to take FnMut
|
||||
rather than Fn:
|
||||
|
||||
```
|
||||
fn foo<F: FnMut()>(f: F) { }
|
||||
```
|
||||
|
||||
Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
|
||||
interior mutability through a shared reference. Our example's `mutable`
|
||||
function could be redefined as below:
|
||||
|
||||
```
|
||||
use std::cell::Cell;
|
||||
|
||||
fn foo<F: Fn()>(f: F) { }
|
||||
|
||||
fn mutable() {
|
||||
let x = Cell::new(0u32);
|
||||
foo(|| x.set(2));
|
||||
}
|
||||
```
|
||||
|
||||
You can read more about cell types in the API documentation:
|
||||
|
||||
https://doc.rust-lang.org/std/cell/
|
||||
"##,
|
||||
|
||||
E0388: r##"
|
||||
E0388 was removed and is no longer issued.
|
||||
"##,
|
||||
|
||||
E0389: r##"
|
||||
An attempt was made to mutate data using a non-mutable reference. This
|
||||
commonly occurs when attempting to assign to a non-mutable reference of a
|
||||
mutable reference (`&(&mut T)`).
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0389
|
||||
struct FancyNum {
|
||||
num: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut fancy = FancyNum{ num: 5 };
|
||||
let fancy_ref = &(&mut fancy);
|
||||
fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
|
||||
println!("{}", fancy_ref.num);
|
||||
}
|
||||
```
|
||||
|
||||
Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
|
||||
immutable reference to a value borrows it immutably. There can be multiple
|
||||
references of type `&(&mut T)` that point to the same value, so they must be
|
||||
immutable to prevent multiple mutable references to the same value.
|
||||
|
||||
To fix this, either remove the outer reference:
|
||||
|
||||
```
|
||||
struct FancyNum {
|
||||
num: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut fancy = FancyNum{ num: 5 };
|
||||
|
||||
let fancy_ref = &mut fancy;
|
||||
// `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)
|
||||
|
||||
fancy_ref.num = 6; // No error!
|
||||
|
||||
println!("{}", fancy_ref.num);
|
||||
}
|
||||
```
|
||||
|
||||
Or make the outer reference mutable:
|
||||
|
||||
```
|
||||
struct FancyNum {
|
||||
num: u8
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut fancy = FancyNum{ num: 5 };
|
||||
|
||||
let fancy_ref = &mut (&mut fancy);
|
||||
// `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)
|
||||
|
||||
fancy_ref.num = 6; // No error!
|
||||
|
||||
println!("{}", fancy_ref.num);
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0595: r##"
|
||||
Closures cannot mutate immutable captured variables.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0595
|
||||
let x = 3; // error: closure cannot assign to immutable local variable `x`
|
||||
let mut c = || { x += 1 };
|
||||
```
|
||||
|
||||
Make the variable binding mutable:
|
||||
|
||||
```
|
||||
let mut x = 3; // ok!
|
||||
let mut c = || { x += 1 };
|
||||
```
|
||||
"##,
|
||||
|
||||
E0596: r##"
|
||||
This error occurs because you tried to mutably borrow a non-mutable variable.
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0596
|
||||
let x = 1;
|
||||
let y = &mut x; // error: cannot borrow mutably
|
||||
```
|
||||
|
||||
In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it
|
||||
fails. To fix this error, you need to make `x` mutable:
|
||||
|
||||
```
|
||||
let mut x = 1;
|
||||
let y = &mut x; // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
E0597: r##"
|
||||
This error occurs because a borrow was made inside a variable which has a
|
||||
greater lifetime than the borrowed one.
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0597
|
||||
struct Foo<'a> {
|
||||
x: Option<&'a u32>,
|
||||
}
|
||||
|
||||
let mut x = Foo { x: None };
|
||||
let y = 0;
|
||||
x.x = Some(&y); // error: `y` does not live long enough
|
||||
```
|
||||
|
||||
In here, `x` is created before `y` and therefore has a greater lifetime. Always
|
||||
keep in mind that values in a scope are dropped in the opposite order they are
|
||||
created. So to fix the previous example, just make the `y` lifetime greater than
|
||||
the `x`'s one:
|
||||
|
||||
```
|
||||
struct Foo<'a> {
|
||||
x: Option<&'a u32>,
|
||||
}
|
||||
|
||||
let y = 0;
|
||||
let mut x = Foo { x: None };
|
||||
x.x = Some(&y);
|
||||
```
|
||||
"##,
|
||||
|
||||
E0626: r##"
|
||||
This error occurs because a borrow in a generator persists across a
|
||||
yield point.
|
||||
|
||||
```compile_fail,E0626
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let a = &String::new(); // <-- This borrow...
|
||||
yield (); // ...is still in scope here, when the yield occurs.
|
||||
println!("{}", a);
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
At present, it is not permitted to have a yield that occurs while a
|
||||
borrow is still in scope. To resolve this error, the borrow must
|
||||
either be "contained" to a smaller scope that does not overlap the
|
||||
yield or else eliminated in another way. So, for example, we might
|
||||
resolve the previous example by removing the borrow and just storing
|
||||
the integer by value:
|
||||
|
||||
```
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let a = 3;
|
||||
yield ();
|
||||
println!("{}", a);
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
This is a very simple case, of course. In more complex cases, we may
|
||||
wish to have more than one reference to the value that was borrowed --
|
||||
in those cases, something like the `Rc` or `Arc` types may be useful.
|
||||
|
||||
This error also frequently arises with iteration:
|
||||
|
||||
```compile_fail,E0626
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let v = vec![1,2,3];
|
||||
for &x in &v { // <-- borrow of `v` is still in scope...
|
||||
yield x; // ...when this yield occurs.
|
||||
}
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
Such cases can sometimes be resolved by iterating "by value" (or using
|
||||
`into_iter()`) to avoid borrowing:
|
||||
|
||||
```
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let v = vec![1,2,3];
|
||||
for x in v { // <-- Take ownership of the values instead!
|
||||
yield x; // <-- Now yield is OK.
|
||||
}
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
If taking ownership is not an option, using indices can work too:
|
||||
|
||||
```
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let v = vec![1,2,3];
|
||||
let len = v.len(); // (*)
|
||||
for i in 0..len {
|
||||
let x = v[i]; // (*)
|
||||
yield x; // <-- Now yield is OK.
|
||||
}
|
||||
};
|
||||
b.resume();
|
||||
|
||||
// (*) -- Unfortunately, these temporaries are currently required.
|
||||
// See <https://github.com/rust-lang/rust/issues/43122>.
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
// E0385, // {} in an aliasable location
|
||||
E0598, // lifetime of {} is too short to guarantee its contents can be...
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,9 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
|
||||
#![feature(quote)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate syntax;
|
||||
extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
extern crate rustc_errors as errors;
|
||||
|
||||
|
|
@ -33,14 +32,8 @@ extern crate rustc_mir;
|
|||
pub use borrowck::check_crate;
|
||||
pub use borrowck::build_borrowck_dataflow_data_for_fn;
|
||||
|
||||
// NB: This module needs to be declared first so diagnostics are
|
||||
// registered before they are used.
|
||||
mod diagnostics;
|
||||
|
||||
mod borrowck;
|
||||
|
||||
pub mod graphviz;
|
||||
|
||||
pub use borrowck::provide;
|
||||
|
||||
__build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS }
|
||||
|
|
|
|||
|
|
@ -1259,7 +1259,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
|
|||
let mut all_errors = Vec::new();
|
||||
all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
|
||||
all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
|
||||
#[cfg(feature="llvm")]
|
||||
|
|
|
|||
|
|
@ -229,6 +229,57 @@ fn main() {
|
|||
See also https://doc.rust-lang.org/book/first-edition/unsafe.html
|
||||
"##,
|
||||
|
||||
E0373: r##"
|
||||
This error occurs when an attempt is made to use data captured by a closure,
|
||||
when that data may no longer exist. It's most commonly seen when attempting to
|
||||
return a closure:
|
||||
|
||||
```compile_fail,E0373
|
||||
fn foo() -> Box<Fn(u32) -> u32> {
|
||||
let x = 0u32;
|
||||
Box::new(|y| x + y)
|
||||
}
|
||||
```
|
||||
|
||||
Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
|
||||
closed-over data by reference. This means that once `foo()` returns, `x` no
|
||||
longer exists. An attempt to access `x` within the closure would thus be
|
||||
unsafe.
|
||||
|
||||
Another situation where this might be encountered is when spawning threads:
|
||||
|
||||
```compile_fail,E0373
|
||||
fn foo() {
|
||||
let x = 0u32;
|
||||
let y = 1u32;
|
||||
|
||||
let thr = std::thread::spawn(|| {
|
||||
x + y
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Since our new thread runs in parallel, the stack frame containing `x` and `y`
|
||||
may well have disappeared by the time we try to use them. Even if we call
|
||||
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
|
||||
stack frame won't disappear), we will not succeed: the compiler cannot prove
|
||||
that this behaviour is safe, and so won't let us do it.
|
||||
|
||||
The solution to this problem is usually to switch to using a `move` closure.
|
||||
This approach moves (or copies, where possible) data into the closure, rather
|
||||
than taking references to it. For example:
|
||||
|
||||
```
|
||||
fn foo() -> Box<Fn(u32) -> u32> {
|
||||
let x = 0u32;
|
||||
Box::new(move |y| x + y)
|
||||
}
|
||||
```
|
||||
|
||||
Now that the closure has its own copy of the data, there's no need to worry
|
||||
about safety.
|
||||
"##,
|
||||
|
||||
E0381: r##"
|
||||
It is not allowed to use or capture an uninitialized variable. For example:
|
||||
|
||||
|
|
@ -250,6 +301,104 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0382: r##"
|
||||
This error occurs when an attempt is made to use a variable after its contents
|
||||
have been moved elsewhere. For example:
|
||||
|
||||
```compile_fail,E0382
|
||||
struct MyStruct { s: u32 }
|
||||
|
||||
fn main() {
|
||||
let mut x = MyStruct{ s: 5u32 };
|
||||
let y = x;
|
||||
x.s = 6;
|
||||
println!("{}", x.s);
|
||||
}
|
||||
```
|
||||
|
||||
Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
|
||||
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
|
||||
of workarounds like `Rc`, a value cannot be owned by more than one variable.
|
||||
|
||||
If we own the type, the easiest way to address this problem is to implement
|
||||
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
|
||||
information in `x`, while leaving the original version owned by `x`. Subsequent
|
||||
changes to `x` will not be reflected when accessing `y`.
|
||||
|
||||
```
|
||||
#[derive(Copy, Clone)]
|
||||
struct MyStruct { s: u32 }
|
||||
|
||||
fn main() {
|
||||
let mut x = MyStruct{ s: 5u32 };
|
||||
let y = x;
|
||||
x.s = 6;
|
||||
println!("{}", x.s);
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, if we don't control the struct's definition, or mutable shared
|
||||
ownership is truly required, we can use `Rc` and `RefCell`:
|
||||
|
||||
```
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
struct MyStruct { s: u32 }
|
||||
|
||||
fn main() {
|
||||
let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
|
||||
let y = x.clone();
|
||||
x.borrow_mut().s = 6;
|
||||
println!("{}", x.borrow().s);
|
||||
}
|
||||
```
|
||||
|
||||
With this approach, x and y share ownership of the data via the `Rc` (reference
|
||||
count type). `RefCell` essentially performs runtime borrow checking: ensuring
|
||||
that at most one writer or multiple readers can access the data at any one time.
|
||||
|
||||
If you wish to learn more about ownership in Rust, start with the chapter in the
|
||||
Book:
|
||||
|
||||
https://doc.rust-lang.org/book/first-edition/ownership.html
|
||||
"##,
|
||||
|
||||
E0383: r##"
|
||||
This error occurs when an attempt is made to partially reinitialize a
|
||||
structure that is currently uninitialized.
|
||||
|
||||
For example, this can happen when a drop has taken place:
|
||||
|
||||
```compile_fail,E0383
|
||||
struct Foo {
|
||||
a: u32,
|
||||
}
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) { /* ... */ }
|
||||
}
|
||||
|
||||
let mut x = Foo { a: 1 };
|
||||
drop(x); // `x` is now uninitialized
|
||||
x.a = 2; // error, partial reinitialization of uninitialized structure `t`
|
||||
```
|
||||
|
||||
This error can be fixed by fully reinitializing the structure in question:
|
||||
|
||||
```
|
||||
struct Foo {
|
||||
a: u32,
|
||||
}
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) { /* ... */ }
|
||||
}
|
||||
|
||||
let mut x = Foo { a: 1 };
|
||||
drop(x);
|
||||
x = Foo { a: 2 };
|
||||
```
|
||||
"##,
|
||||
|
||||
E0384: r##"
|
||||
This error occurs when an attempt is made to reassign an immutable variable.
|
||||
For example:
|
||||
|
|
@ -272,6 +421,161 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
/*E0386: r##"
|
||||
This error occurs when an attempt is made to mutate the target of a mutable
|
||||
reference stored inside an immutable container.
|
||||
|
||||
For example, this can happen when storing a `&mut` inside an immutable `Box`:
|
||||
|
||||
```compile_fail,E0386
|
||||
let mut x: i64 = 1;
|
||||
let y: Box<_> = Box::new(&mut x);
|
||||
**y = 2; // error, cannot assign to data in an immutable container
|
||||
```
|
||||
|
||||
This error can be fixed by making the container mutable:
|
||||
|
||||
```
|
||||
let mut x: i64 = 1;
|
||||
let mut y: Box<_> = Box::new(&mut x);
|
||||
**y = 2;
|
||||
```
|
||||
|
||||
It can also be fixed by using a type with interior mutability, such as `Cell`
|
||||
or `RefCell`:
|
||||
|
||||
```
|
||||
use std::cell::Cell;
|
||||
|
||||
let x: i64 = 1;
|
||||
let y: Box<Cell<_>> = Box::new(Cell::new(x));
|
||||
y.set(2);
|
||||
```
|
||||
"##,*/
|
||||
|
||||
E0387: r##"
|
||||
This error occurs when an attempt is made to mutate or mutably reference data
|
||||
that a closure has captured immutably. Examples of this error are shown below:
|
||||
|
||||
```compile_fail,E0387
|
||||
// Accepts a function or a closure that captures its environment immutably.
|
||||
// Closures passed to foo will not be able to mutate their closed-over state.
|
||||
fn foo<F: Fn()>(f: F) { }
|
||||
|
||||
// Attempts to mutate closed-over data. Error message reads:
|
||||
// `cannot assign to data in a captured outer variable...`
|
||||
fn mutable() {
|
||||
let mut x = 0u32;
|
||||
foo(|| x = 2);
|
||||
}
|
||||
|
||||
// Attempts to take a mutable reference to closed-over data. Error message
|
||||
// reads: `cannot borrow data mutably in a captured outer variable...`
|
||||
fn mut_addr() {
|
||||
let mut x = 0u32;
|
||||
foo(|| { let y = &mut x; });
|
||||
}
|
||||
```
|
||||
|
||||
The problem here is that foo is defined as accepting a parameter of type `Fn`.
|
||||
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
|
||||
they capture their context immutably.
|
||||
|
||||
If the definition of `foo` is under your control, the simplest solution is to
|
||||
capture the data mutably. This can be done by defining `foo` to take FnMut
|
||||
rather than Fn:
|
||||
|
||||
```
|
||||
fn foo<F: FnMut()>(f: F) { }
|
||||
```
|
||||
|
||||
Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
|
||||
interior mutability through a shared reference. Our example's `mutable`
|
||||
function could be redefined as below:
|
||||
|
||||
```
|
||||
use std::cell::Cell;
|
||||
|
||||
fn foo<F: Fn()>(f: F) { }
|
||||
|
||||
fn mutable() {
|
||||
let x = Cell::new(0u32);
|
||||
foo(|| x.set(2));
|
||||
}
|
||||
```
|
||||
|
||||
You can read more about cell types in the API documentation:
|
||||
|
||||
https://doc.rust-lang.org/std/cell/
|
||||
"##,
|
||||
|
||||
E0388: r##"
|
||||
E0388 was removed and is no longer issued.
|
||||
"##,
|
||||
|
||||
E0389: r##"
|
||||
An attempt was made to mutate data using a non-mutable reference. This
|
||||
commonly occurs when attempting to assign to a non-mutable reference of a
|
||||
mutable reference (`&(&mut T)`).
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0389
|
||||
struct FancyNum {
|
||||
num: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut fancy = FancyNum{ num: 5 };
|
||||
let fancy_ref = &(&mut fancy);
|
||||
fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
|
||||
println!("{}", fancy_ref.num);
|
||||
}
|
||||
```
|
||||
|
||||
Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
|
||||
immutable reference to a value borrows it immutably. There can be multiple
|
||||
references of type `&(&mut T)` that point to the same value, so they must be
|
||||
immutable to prevent multiple mutable references to the same value.
|
||||
|
||||
To fix this, either remove the outer reference:
|
||||
|
||||
```
|
||||
struct FancyNum {
|
||||
num: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut fancy = FancyNum{ num: 5 };
|
||||
|
||||
let fancy_ref = &mut fancy;
|
||||
// `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)
|
||||
|
||||
fancy_ref.num = 6; // No error!
|
||||
|
||||
println!("{}", fancy_ref.num);
|
||||
}
|
||||
```
|
||||
|
||||
Or make the outer reference mutable:
|
||||
|
||||
```
|
||||
struct FancyNum {
|
||||
num: u8
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut fancy = FancyNum{ num: 5 };
|
||||
|
||||
let fancy_ref = &mut (&mut fancy);
|
||||
// `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)
|
||||
|
||||
fancy_ref.num = 6; // No error!
|
||||
|
||||
println!("{}", fancy_ref.num);
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0394: r##"
|
||||
A static was referred to by value by another static.
|
||||
|
|
@ -1265,12 +1569,169 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0595: r##"
|
||||
Closures cannot mutate immutable captured variables.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0595
|
||||
let x = 3; // error: closure cannot assign to immutable local variable `x`
|
||||
let mut c = || { x += 1 };
|
||||
```
|
||||
|
||||
Make the variable binding mutable:
|
||||
|
||||
```
|
||||
let mut x = 3; // ok!
|
||||
let mut c = || { x += 1 };
|
||||
```
|
||||
"##,
|
||||
|
||||
E0596: r##"
|
||||
This error occurs because you tried to mutably borrow a non-mutable variable.
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0596
|
||||
let x = 1;
|
||||
let y = &mut x; // error: cannot borrow mutably
|
||||
```
|
||||
|
||||
In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it
|
||||
fails. To fix this error, you need to make `x` mutable:
|
||||
|
||||
```
|
||||
let mut x = 1;
|
||||
let y = &mut x; // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
E0597: r##"
|
||||
This error occurs because a borrow was made inside a variable which has a
|
||||
greater lifetime than the borrowed one.
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0597
|
||||
struct Foo<'a> {
|
||||
x: Option<&'a u32>,
|
||||
}
|
||||
|
||||
let mut x = Foo { x: None };
|
||||
let y = 0;
|
||||
x.x = Some(&y); // error: `y` does not live long enough
|
||||
```
|
||||
|
||||
In here, `x` is created before `y` and therefore has a greater lifetime. Always
|
||||
keep in mind that values in a scope are dropped in the opposite order they are
|
||||
created. So to fix the previous example, just make the `y` lifetime greater than
|
||||
the `x`'s one:
|
||||
|
||||
```
|
||||
struct Foo<'a> {
|
||||
x: Option<&'a u32>,
|
||||
}
|
||||
|
||||
let y = 0;
|
||||
let mut x = Foo { x: None };
|
||||
x.x = Some(&y);
|
||||
```
|
||||
"##,
|
||||
|
||||
E0626: r##"
|
||||
This error occurs because a borrow in a generator persists across a
|
||||
yield point.
|
||||
|
||||
```compile_fail,E0626
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let a = &String::new(); // <-- This borrow...
|
||||
yield (); // ...is still in scope here, when the yield occurs.
|
||||
println!("{}", a);
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
At present, it is not permitted to have a yield that occurs while a
|
||||
borrow is still in scope. To resolve this error, the borrow must
|
||||
either be "contained" to a smaller scope that does not overlap the
|
||||
yield or else eliminated in another way. So, for example, we might
|
||||
resolve the previous example by removing the borrow and just storing
|
||||
the integer by value:
|
||||
|
||||
```
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let a = 3;
|
||||
yield ();
|
||||
println!("{}", a);
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
This is a very simple case, of course. In more complex cases, we may
|
||||
wish to have more than one reference to the value that was borrowed --
|
||||
in those cases, something like the `Rc` or `Arc` types may be useful.
|
||||
|
||||
This error also frequently arises with iteration:
|
||||
|
||||
```compile_fail,E0626
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let v = vec![1,2,3];
|
||||
for &x in &v { // <-- borrow of `v` is still in scope...
|
||||
yield x; // ...when this yield occurs.
|
||||
}
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
Such cases can sometimes be resolved by iterating "by value" (or using
|
||||
`into_iter()`) to avoid borrowing:
|
||||
|
||||
```
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let v = vec![1,2,3];
|
||||
for x in v { // <-- Take ownership of the values instead!
|
||||
yield x; // <-- Now yield is OK.
|
||||
}
|
||||
};
|
||||
b.resume();
|
||||
```
|
||||
|
||||
If taking ownership is not an option, using indices can work too:
|
||||
|
||||
```
|
||||
# #![feature(generators, generator_trait)]
|
||||
# use std::ops::Generator;
|
||||
let mut b = || {
|
||||
let v = vec![1,2,3];
|
||||
let len = v.len(); // (*)
|
||||
for i in 0..len {
|
||||
let x = v[i]; // (*)
|
||||
yield x; // <-- Now yield is OK.
|
||||
}
|
||||
};
|
||||
b.resume();
|
||||
|
||||
// (*) -- Unfortunately, these temporaries are currently required.
|
||||
// See <https://github.com/rust-lang/rust/issues/43122>.
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
// E0385, // {} in an aliasable location
|
||||
E0493, // destructors cannot be evaluated at compile-time
|
||||
E0524, // two closures require unique access to `..` at the same time
|
||||
E0526, // shuffle indices are not constant
|
||||
E0594, // cannot assign to {}
|
||||
E0598, // lifetime of {} is too short to guarantee its contents can be...
|
||||
E0625, // thread-local statics cannot be accessed at compile-time
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,6 +294,139 @@ pub trait BorrowckErrors {
|
|||
err.span_label(move_from_span, "cannot move out of here");
|
||||
err
|
||||
}
|
||||
|
||||
fn cannot_act_on_moved_value(&self,
|
||||
use_span: Span,
|
||||
verb: &str,
|
||||
optional_adverb_for_moved: &str,
|
||||
moved_path: &str,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let err = struct_span_err!(self, use_span, E0382,
|
||||
"{} of {}moved value: `{}`{OGN}",
|
||||
verb, optional_adverb_for_moved, moved_path, OGN=o);
|
||||
err
|
||||
}
|
||||
|
||||
fn cannot_partially_reinit_an_uninit_struct(&self,
|
||||
span: Span,
|
||||
uninit_path: &str,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let err = struct_span_err!(self,
|
||||
span,
|
||||
E0383,
|
||||
"partial reinitialization of uninitialized structure `{}`{OGN}",
|
||||
uninit_path, OGN=o);
|
||||
err
|
||||
}
|
||||
|
||||
fn closure_cannot_assign_to_borrowed(&self,
|
||||
span: Span,
|
||||
descr: &str,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let err = struct_span_err!(self, span, E0595, "closure cannot assign to {}{OGN}",
|
||||
descr, OGN=o);
|
||||
err
|
||||
}
|
||||
|
||||
fn cannot_borrow_path_as_mutable(&self,
|
||||
span: Span,
|
||||
path: &str,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let err = struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{OGN}",
|
||||
path, OGN=o);
|
||||
err
|
||||
}
|
||||
|
||||
fn cannot_borrow_across_generator_yield(&self,
|
||||
span: Span,
|
||||
yield_span: Span,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let mut err = struct_span_err!(self,
|
||||
span,
|
||||
E0626,
|
||||
"borrow may still be in use when generator yields{OGN}",
|
||||
OGN=o);
|
||||
err.span_label(yield_span, "possible yield occurs here");
|
||||
err
|
||||
}
|
||||
|
||||
fn path_does_not_live_long_enough(&self,
|
||||
span: Span,
|
||||
path: &str,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let err = struct_span_err!(self, span, E0597, "{} does not live long enough{OGN}",
|
||||
path, OGN=o);
|
||||
err
|
||||
}
|
||||
|
||||
fn lifetime_too_short_for_reborrow(&self,
|
||||
span: Span,
|
||||
path: &str,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let err = struct_span_err!(self, span, E0598,
|
||||
"lifetime of {} is too short to guarantee \
|
||||
its contents can be safely reborrowed{OGN}",
|
||||
path, OGN=o);
|
||||
err
|
||||
}
|
||||
|
||||
fn cannot_act_on_capture_in_sharable_fn(&self,
|
||||
span: Span,
|
||||
bad_thing: &str,
|
||||
help: (Span, &str),
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let (help_span, help_msg) = help;
|
||||
let mut err = struct_span_err!(self, span, E0387,
|
||||
"{} in a captured outer variable in an `Fn` closure{OGN}",
|
||||
bad_thing, OGN=o);
|
||||
err.span_help(help_span, help_msg);
|
||||
err
|
||||
}
|
||||
|
||||
fn cannot_assign_into_immutable_reference(&self,
|
||||
span: Span,
|
||||
bad_thing: &str,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let mut err = struct_span_err!(self, span, E0389, "{} in a `&` reference{OGN}",
|
||||
bad_thing, OGN=o);
|
||||
err.span_label(span, "assignment into an immutable reference");
|
||||
err
|
||||
}
|
||||
|
||||
fn cannot_capture_in_long_lived_closure(&self,
|
||||
closure_span: Span,
|
||||
borrowed_path: &str,
|
||||
capture_span: Span,
|
||||
o: Origin)
|
||||
-> DiagnosticBuilder
|
||||
{
|
||||
let mut err = struct_span_err!(self, closure_span, E0373,
|
||||
"closure may outlive the current function, \
|
||||
but it borrows {}, \
|
||||
which is owned by the current function{OGN}",
|
||||
borrowed_path, OGN=o);
|
||||
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
|
||||
.span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
|
||||
err
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue