Fix #58497.
closure_kind: &str,
borrowed_path: &str,
capture_span: Span,
+ scope: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
closure_span,
E0373,
- "{} may outlive the current function, but it borrows {}, which is owned by the current \
- function",
- closure_kind,
- borrowed_path,
+ "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
+ which is owned by the current {scope}",
);
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
.span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
//
// then just use the normal error. The closure isn't escaping
// and `move` will not help here.
+ (
+ Some(name),
+ BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
+ ) => self.report_escaping_closure_capture(
+ borrow_spans,
+ borrow_span,
+ &RegionName {
+ name: self.synthesize_region_name(),
+ source: RegionNameSource::Static,
+ },
+ ConstraintCategory::CallArgument(None),
+ var_or_use_span,
+ &format!("`{}`", name),
+ "block",
+ ),
(
Some(name),
BorrowExplanation::MustBeValidFor {
category,
span,
&format!("`{}`", name),
+ "function",
),
(
name,
Some(err)
}
+ #[instrument(level = "debug", skip(self))]
fn report_escaping_closure_capture(
&mut self,
use_span: UseSpans<'tcx>,
category: ConstraintCategory<'tcx>,
constraint_span: Span,
captured_var: &str,
+ scope: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use();
None => "closure",
};
- let mut err =
- self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
+ let mut err = self.cannot_capture_in_long_lived_closure(
+ args_span,
+ kind,
+ captured_var,
+ var_span,
+ scope,
+ );
err.span_suggestion_verbose(
sugg_span,
&format!(
if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
err.note(
"async blocks are not executed immediately and must either take a \
- reference or ownership of outside variables they use",
+ reference or ownership of outside variables they use",
);
} else {
- let msg = format!("function requires argument type to outlive `{}`", fr_name);
+ let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
err.span_note(constraint_span, &msg);
}
}
/// First span returned points to the location of the conflicting use
/// Second span if `Some` is returned in the case of closures and points
/// to the use of the path
+ #[instrument(level = "debug", skip(self))]
fn later_use_kind(
&self,
borrow: &BorrowData<'tcx>,
let block = &self.body.basic_blocks[location.block];
let kind = if let Some(&Statement {
- kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
+ kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)),
..
}) = block.statements.get(location.statement_index)
{
- LaterUseKind::FakeLetRead
+ if let Some(l) = place.as_local()
+ && let local_decl = &self.body.local_decls[l]
+ && local_decl.ty.is_closure()
+ {
+ LaterUseKind::ClosureCapture
+ } else {
+ LaterUseKind::FakeLetRead
+ }
} else if self.was_captured_by_trait_object(borrow) {
LaterUseKind::TraitCapture
} else if location.statement_index == block.statements.len() {
/// increment the counter.
///
/// This is _not_ idempotent. Call `give_region_a_name` when possible.
- fn synthesize_region_name(&self) -> Symbol {
+ pub(crate) fn synthesize_region_name(&self) -> Symbol {
let c = self.next_region_name.replace_with(|counter| *counter + 1);
Symbol::intern(&format!("'{:?}", c))
}
fn main() {
let mut c = {
let mut p = Point {x: "1".to_string(), y: "2".to_string() };
- || {
+ || { //~ ERROR closure may outlive the current block, but it borrows `p`
let x = &mut p.x;
println!("{:?}", p);
- //~^ ERROR `p` does not live long enough
}
};
c();
-error[E0597]: `p` does not live long enough
- --> $DIR/borrowck-3.rs:13:29
+error[E0373]: closure may outlive the current block, but it borrows `p`, which is owned by the current block
+ --> $DIR/borrowck-3.rs:11:9
|
-LL | let mut c = {
- | ----- borrow later stored here
-LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() };
LL | || {
- | -- value captured here
+ | ^^ may outlive borrowed value `p`
LL | let x = &mut p.x;
LL | println!("{:?}", p);
- | ^ borrowed value does not live long enough
-...
-LL | };
- | - `p` dropped here while still borrowed
+ | - `p` is borrowed here
+ |
+note: block requires argument type to outlive `'1`
+ --> $DIR/borrowck-3.rs:9:9
+ |
+LL | let mut c = {
+ | ^^^^^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+ |
+LL | move || {
+ | ++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
fn main() {
let _f = {
let x = 0;
- || x //~ ERROR `x` does not live long enough
+ || x //~ ERROR closure may outlive the current block, but it borrows `x`
};
_f;
}
-error[E0597]: `x` does not live long enough
- --> $DIR/unboxed-closure-region.rs:8:12
+error[E0373]: closure may outlive the current block, but it borrows `x`, which is owned by the current block
+ --> $DIR/unboxed-closure-region.rs:8:9
|
-LL | let _f = {
- | -- borrow later stored here
-LL | let x = 0;
LL | || x
- | -- ^ borrowed value does not live long enough
+ | ^^ - `x` is borrowed here
| |
- | value captured here
-LL | };
- | - `x` dropped here while still borrowed
+ | may outlive borrowed value `x`
+ |
+note: block requires argument type to outlive `'1`
+ --> $DIR/unboxed-closure-region.rs:6:9
+ |
+LL | let _f = {
+ | ^^
+help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
+ |
+LL | move || x
+ | ++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
category,
span,
&format!("`{}`", name),
+ "function",
),
(
ref name,