Skip to content

Commit 4119762

Browse files
authored
Rollup merge of rust-lang#58788 - matthewjasper:compare-children, r=pnkfelix
Make migrate mode work at item level granularity Migrate mode now works entirely at the item level rather than the body level, ensuring that we don't lose any errors in contained closures. Closes rust-lang#58776 r? @pnkfelix
2 parents 5d2af50 + 2742b23 commit 4119762

7 files changed

+127
-25
lines changed

src/librustc/middle/expr_use_visitor.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ pub trait Delegate<'tcx> {
8282
assignment_span: Span,
8383
assignee_cmt: &mc::cmt_<'tcx>,
8484
mode: MutateMode);
85+
86+
// A nested closure or generator - only one layer deep.
87+
fn nested_body(&mut self, _body_id: hir::BodyId) {}
8588
}
8689

8790
#[derive(Copy, Clone, PartialEq, Debug)]
@@ -531,8 +534,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
531534
self.consume_expr(&base);
532535
}
533536

534-
hir::ExprKind::Closure(.., fn_decl_span, _) => {
535-
self.walk_captures(expr, fn_decl_span)
537+
hir::ExprKind::Closure(_, _, body_id, fn_decl_span, _) => {
538+
self.delegate.nested_body(body_id);
539+
self.walk_captures(expr, fn_decl_span);
536540
}
537541

538542
hir::ExprKind::Box(ref base) => {

src/librustc_borrowck/borrowck/check_loans.rs

+16
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
177177
}
178178

179179
fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) { }
180+
181+
fn nested_body(&mut self, body_id: hir::BodyId) {
182+
// rust-lang/rust#58776: MIR and AST borrow check disagree on where
183+
// certain closure errors are reported. As such migrate borrowck has to
184+
// operate at the level of items, rather than bodies. Check if the
185+
// contained closure had any errors and set `signalled_any_error` if it
186+
// has.
187+
let bccx = self.bccx;
188+
if bccx.tcx.migrate_borrowck() {
189+
if let SignalledError::NoErrorsSeen = bccx.signalled_any_error.get() {
190+
let closure_def_id = bccx.tcx.hir().body_owner_def_id(body_id);
191+
192+
bccx.signalled_any_error.set(bccx.tcx.borrowck(closure_def_id).signalled_any_error);
193+
}
194+
}
195+
}
180196
}
181197

182198
pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,

src/librustc_mir/borrow_check/mod.rs

+5-23
Original file line numberDiff line numberDiff line change
@@ -329,30 +329,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
329329
// When borrowck=migrate, check if AST-borrowck would
330330
// error on the given code.
331331

332-
// rust-lang/rust#55492: loop over parents to ensure that
333-
// errors that AST-borrowck only detects in some parent of
334-
// a closure still allows NLL to signal an error.
335-
let mut curr_def_id = def_id;
336-
let signalled_any_error = loop {
337-
match tcx.borrowck(curr_def_id).signalled_any_error {
338-
SignalledError::NoErrorsSeen => {
339-
// keep traversing (and borrow-checking) parents
340-
}
341-
SignalledError::SawSomeError => {
342-
// stop search here
343-
break SignalledError::SawSomeError;
344-
}
345-
}
346-
347-
if tcx.is_closure(curr_def_id) {
348-
curr_def_id = tcx.parent_def_id(curr_def_id)
349-
.expect("a closure must have a parent_def_id");
350-
} else {
351-
break SignalledError::NoErrorsSeen;
352-
}
353-
};
332+
// rust-lang/rust#55492, rust-lang/rust#58776 check the base def id
333+
// for errors. AST borrowck is responsible for aggregating
334+
// `signalled_any_error` from all of the nested closures here.
335+
let base_def_id = tcx.closure_base_def_id(def_id);
354336

355-
match signalled_any_error {
337+
match tcx.borrowck(base_def_id).signalled_any_error {
356338
SignalledError::NoErrorsSeen => {
357339
// if AST-borrowck signalled no errors, then
358340
// downgrade all the buffered MIR-borrowck errors
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0597]: `**greeting` does not live long enough
2+
--> $DIR/issue-58776-borrowck-scans-children.rs:10:24
3+
|
4+
LL | let res = (|| (|| &greeting)())();
5+
| -- ^^^^^^^^ - borrowed value only lives until here
6+
| | |
7+
| | borrowed value does not live long enough
8+
| capture occurs here
9+
...
10+
LL | }
11+
| - borrowed value needs to live until here
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0597`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error[E0506]: cannot assign to `greeting` because it is borrowed
2+
--> $DIR/issue-58776-borrowck-scans-children.rs:13:5
3+
|
4+
LL | let res = (|| (|| &greeting)())();
5+
| -- -------- borrow occurs due to use in closure
6+
| |
7+
| borrow of `greeting` occurs here
8+
...
9+
LL | greeting = "DEALLOCATED".to_string();
10+
| ^^^^^^^^ assignment to borrowed `greeting` occurs here
11+
...
12+
LL | println!("thread result: {:?}", res);
13+
| --- borrow later used here
14+
15+
error[E0505]: cannot move out of `greeting` because it is borrowed
16+
--> $DIR/issue-58776-borrowck-scans-children.rs:16:10
17+
|
18+
LL | let res = (|| (|| &greeting)())();
19+
| -- -------- borrow occurs due to use in closure
20+
| |
21+
| borrow of `greeting` occurs here
22+
...
23+
LL | drop(greeting);
24+
| ^^^^^^^^ move out of `greeting` occurs here
25+
...
26+
LL | println!("thread result: {:?}", res);
27+
| --- borrow later used here
28+
29+
error: aborting due to 2 previous errors
30+
31+
Some errors occurred: E0505, E0506.
32+
For more information about an error, try `rustc --explain E0505`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error[E0506]: cannot assign to `greeting` because it is borrowed
2+
--> $DIR/issue-58776-borrowck-scans-children.rs:13:5
3+
|
4+
LL | let res = (|| (|| &greeting)())();
5+
| -- -------- borrow occurs due to use in closure
6+
| |
7+
| borrow of `greeting` occurs here
8+
...
9+
LL | greeting = "DEALLOCATED".to_string();
10+
| ^^^^^^^^ assignment to borrowed `greeting` occurs here
11+
...
12+
LL | println!("thread result: {:?}", res);
13+
| --- borrow later used here
14+
15+
error[E0505]: cannot move out of `greeting` because it is borrowed
16+
--> $DIR/issue-58776-borrowck-scans-children.rs:16:10
17+
|
18+
LL | let res = (|| (|| &greeting)())();
19+
| -- -------- borrow occurs due to use in closure
20+
| |
21+
| borrow of `greeting` occurs here
22+
...
23+
LL | drop(greeting);
24+
| ^^^^^^^^ move out of `greeting` occurs here
25+
...
26+
LL | println!("thread result: {:?}", res);
27+
| --- borrow later used here
28+
29+
error: aborting due to 2 previous errors
30+
31+
Some errors occurred: E0505, E0506.
32+
For more information about an error, try `rustc --explain E0505`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// ignore-compare-mode-nll
2+
3+
// revisions: ast migrate nll
4+
5+
//[migrate]compile-flags: -Z borrowck=migrate
6+
#![cfg_attr(nll, feature(nll))]
7+
8+
fn main() {
9+
let mut greeting = "Hello world!".to_string();
10+
let res = (|| (|| &greeting)())();
11+
//[ast]~^ ERROR does not live long enough
12+
13+
greeting = "DEALLOCATED".to_string();
14+
//[migrate]~^ ERROR cannot assign
15+
//[nll]~^^ ERROR cannot assign
16+
drop(greeting);
17+
//[migrate]~^ ERROR cannot move
18+
//[nll]~^^ ERROR cannot move
19+
20+
println!("thread result: {:?}", res);
21+
}

0 commit comments

Comments
 (0)