Skip to content

Commit 92cb866

Browse files
committed
Auto merge of rust-lang#139666 - lcnr:pre-revealing-use-cleanup, r=<try>
cleanup `mir_borrowck` Cleanup pulled out of rust-lang#139587. Best reviewed commit by commit. r? compiler-errors
2 parents 18a029c + 13bd7e0 commit 92cb866

File tree

11 files changed

+160
-167
lines changed

11 files changed

+160
-167
lines changed

Diff for: compiler/rustc_borrowck/src/lib.rs

+121-111
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use std::cell::RefCell;
2222
use std::marker::PhantomData;
2323
use std::ops::{ControlFlow, Deref};
2424

25+
use borrow_set::LocalsStateAtExit;
26+
use diagnostics::RegionErrors;
2527
use root_cx::BorrowCheckRootCtxt;
2628
use rustc_abi::FieldIdx;
2729
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -304,33 +306,13 @@ fn do_mir_borrowck<'tcx>(
304306
root_cx.set_tainted_by_errors(e);
305307
}
306308

307-
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
308-
for var_debug_info in &input_body.var_debug_info {
309-
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
310-
if let Some(local) = place.as_local() {
311-
if let Some(prev_name) = local_names[local]
312-
&& var_debug_info.name != prev_name
313-
{
314-
span_bug!(
315-
var_debug_info.source_info.span,
316-
"local {:?} has many names (`{}` vs `{}`)",
317-
local,
318-
prev_name,
319-
var_debug_info.name
320-
);
321-
}
322-
local_names[local] = Some(var_debug_info.name);
323-
}
324-
}
325-
}
326-
327309
// Replace all regions with fresh inference variables. This
328310
// requires first making our own copy of the MIR. This copy will
329311
// be modified (in place) to contain non-lexical lifetimes. It
330312
// will have a lifetime tied to the inference context.
331313
let mut body_owned = input_body.clone();
332314
let mut promoted = input_promoted.to_owned();
333-
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
315+
let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
334316
let body = &body_owned; // no further changes
335317

336318
let location_table = PoloniusLocationTable::new(body);
@@ -355,7 +337,7 @@ fn do_mir_borrowck<'tcx>(
355337
} = nll::compute_regions(
356338
root_cx,
357339
&infcx,
358-
free_regions,
340+
universal_regions,
359341
body,
360342
&promoted,
361343
&location_table,
@@ -368,27 +350,76 @@ fn do_mir_borrowck<'tcx>(
368350
// Dump MIR results into a file, if that is enabled. This lets us
369351
// write unit-tests, as well as helping with debugging.
370352
nll::dump_nll_mir(&infcx, body, &regioncx, &opt_closure_req, &borrow_set);
353+
polonius::dump_polonius_mir(
354+
&infcx,
355+
body,
356+
&regioncx,
357+
&opt_closure_req,
358+
&borrow_set,
359+
polonius_diagnostics.as_ref(),
360+
);
371361

372362
// We also have a `#[rustc_regions]` annotation that causes us to dump
373363
// information.
374-
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
375-
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req, diags_buffer);
376-
377-
let movable_coroutine =
378-
// The first argument is the coroutine type passed by value
379-
if let Some(local) = body.local_decls.raw.get(1)
380-
// Get the interior types and args which typeck computed
381-
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
382-
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
383-
{
384-
true
385-
} else {
386-
false
387-
};
364+
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req);
365+
366+
let used_mut_upvars = borrowck_body(
367+
root_cx,
368+
&infcx,
369+
&body,
370+
&promoted,
371+
&location_table,
372+
&move_data,
373+
&borrow_set,
374+
&regioncx,
375+
polonius_output.as_deref(),
376+
polonius_diagnostics.as_ref(),
377+
nll_errors,
378+
);
379+
380+
let result =
381+
PropagatedBorrowCheckResults { closure_requirements: opt_closure_req, used_mut_upvars };
382+
383+
let body_with_facts = if consumer_options.is_some() {
384+
Some(Box::new(BodyWithBorrowckFacts {
385+
body: body_owned,
386+
promoted,
387+
borrow_set,
388+
region_inference_context: regioncx,
389+
location_table: polonius_input.as_ref().map(|_| location_table),
390+
input_facts: polonius_input,
391+
output_facts: polonius_output,
392+
}))
393+
} else {
394+
None
395+
};
396+
397+
debug!("do_mir_borrowck: result = {:#?}", result);
398+
399+
(result, body_with_facts)
400+
}
401+
402+
fn borrowck_body<'tcx>(
403+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
404+
infcx: &BorrowckInferCtxt<'tcx>,
405+
body: &Body<'tcx>,
406+
promoted: &IndexVec<Promoted, Body<'tcx>>,
407+
location_table: &PoloniusLocationTable,
408+
move_data: &MoveData<'tcx>,
409+
borrow_set: &BorrowSet<'tcx>,
410+
regioncx: &RegionInferenceContext<'tcx>,
411+
polonius_output: Option<&PoloniusOutput>,
412+
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
413+
nll_errors: RegionErrors<'tcx>,
414+
) -> SmallVec<[FieldIdx; 8]> {
415+
let tcx = infcx.tcx;
416+
let movable_coroutine = body.coroutine.is_some()
417+
&& tcx.coroutine_movability(body.source.def_id()) == hir::Movability::Movable;
388418

419+
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
389420
// While promoteds should mostly be correct by construction, we need to check them for
390421
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
391-
for promoted_body in &promoted {
422+
for promoted_body in promoted {
392423
use rustc_middle::mir::visit::Visitor;
393424
// This assumes that we won't use some of the fields of the `promoted_mbcx`
394425
// when detecting and reporting move errors. While it would be nice to move
@@ -403,7 +434,6 @@ fn do_mir_borrowck<'tcx>(
403434
location_table: &location_table,
404435
movable_coroutine,
405436
fn_self_span_reported: Default::default(),
406-
locals_are_invalidated_at_exit,
407437
access_place_error_reported: Default::default(),
408438
reservation_error_reported: Default::default(),
409439
uninitialized_error_reported: Default::default(),
@@ -415,10 +445,11 @@ fn do_mir_borrowck<'tcx>(
415445
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
416446
region_names: RefCell::default(),
417447
next_region_name: RefCell::new(1),
418-
polonius_output: None,
419448
move_errors: Vec::new(),
420449
diags_buffer,
421-
polonius_diagnostics: polonius_diagnostics.as_ref(),
450+
451+
polonius_output,
452+
polonius_diagnostics,
422453
};
423454
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
424455
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
@@ -435,30 +466,49 @@ fn do_mir_borrowck<'tcx>(
435466
promoted_mbcx.report_move_errors();
436467
}
437468

469+
let mut local_names = IndexVec::from_elem(None, &body.local_decls);
470+
for var_debug_info in &body.var_debug_info {
471+
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
472+
if let Some(local) = place.as_local() {
473+
if let Some(prev_name) = local_names[local]
474+
&& var_debug_info.name != prev_name
475+
{
476+
span_bug!(
477+
var_debug_info.source_info.span,
478+
"local {:?} has many names (`{}` vs `{}`)",
479+
local,
480+
prev_name,
481+
var_debug_info.name
482+
);
483+
}
484+
local_names[local] = Some(var_debug_info.name);
485+
}
486+
}
487+
}
488+
438489
let mut mbcx = MirBorrowckCtxt {
439490
root_cx,
440491
infcx: &infcx,
441492
body,
442493
move_data: &move_data,
443494
location_table: &location_table,
444495
movable_coroutine,
445-
locals_are_invalidated_at_exit,
446496
fn_self_span_reported: Default::default(),
447497
access_place_error_reported: Default::default(),
448498
reservation_error_reported: Default::default(),
449499
uninitialized_error_reported: Default::default(),
450-
regioncx: &regioncx,
500+
regioncx,
451501
used_mut: Default::default(),
452502
used_mut_upvars: SmallVec::new(),
453503
borrow_set: &borrow_set,
454-
upvars: tcx.closure_captures(def),
504+
upvars: tcx.closure_captures(body.source.def_id().expect_local()),
455505
local_names,
456506
region_names: RefCell::default(),
457507
next_region_name: RefCell::new(1),
458-
polonius_output,
459508
move_errors: Vec::new(),
460509
diags_buffer,
461-
polonius_diagnostics: polonius_diagnostics.as_ref(),
510+
polonius_output,
511+
polonius_diagnostics,
462512
};
463513

464514
// Compute and report region errors, if any.
@@ -474,16 +524,6 @@ fn do_mir_borrowck<'tcx>(
474524

475525
mbcx.report_move_errors();
476526

477-
// If requested, dump polonius MIR.
478-
polonius::dump_polonius_mir(
479-
&infcx,
480-
body,
481-
&regioncx,
482-
&borrow_set,
483-
polonius_diagnostics.as_ref(),
484-
&opt_closure_req,
485-
);
486-
487527
// For each non-user used mutable variable, check if it's been assigned from
488528
// a user-declared local. If so, then put that local into the used_mut set.
489529
// Note that this set is expected to be small - only upvars from closures
@@ -508,29 +548,7 @@ fn do_mir_borrowck<'tcx>(
508548
mbcx.root_cx.set_tainted_by_errors(guar);
509549
}
510550

511-
let result = PropagatedBorrowCheckResults {
512-
closure_requirements: opt_closure_req,
513-
used_mut_upvars: mbcx.used_mut_upvars,
514-
};
515-
516-
let body_with_facts = if consumer_options.is_some() {
517-
let output_facts = mbcx.polonius_output;
518-
Some(Box::new(BodyWithBorrowckFacts {
519-
body: body_owned,
520-
promoted,
521-
borrow_set,
522-
region_inference_context: regioncx,
523-
location_table: polonius_input.as_ref().map(|_| location_table),
524-
input_facts: polonius_input,
525-
output_facts,
526-
}))
527-
} else {
528-
None
529-
};
530-
531-
debug!("do_mir_borrowck: result = {:#?}", result);
532-
533-
(result, body_with_facts)
551+
mbcx.used_mut_upvars
534552
}
535553

536554
fn get_flow_results<'a, 'tcx>(
@@ -655,13 +673,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
655673
location_table: &'a PoloniusLocationTable,
656674

657675
movable_coroutine: bool,
658-
/// This keeps track of whether local variables are free-ed when the function
659-
/// exits even without a `StorageDead`, which appears to be the case for
660-
/// constants.
661-
///
662-
/// I'm not sure this is the right approach - @eddyb could you try and
663-
/// figure this out?
664-
locals_are_invalidated_at_exit: bool,
665676
/// This field keeps track of when borrow errors are reported in the access_place function
666677
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
667678
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
@@ -709,12 +720,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
709720
/// The counter for generating new region names.
710721
next_region_name: RefCell<usize>,
711722

712-
/// Results of Polonius analysis.
713-
polonius_output: Option<Box<PoloniusOutput>>,
714-
715723
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
716724
move_errors: Vec<MoveError<'tcx>>,
717725

726+
/// Results of Polonius analysis.
727+
polonius_output: Option<&'a PoloniusOutput>,
718728
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
719729
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
720730
}
@@ -938,13 +948,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
938948
| TerminatorKind::Return
939949
| TerminatorKind::TailCall { .. }
940950
| TerminatorKind::CoroutineDrop => {
941-
// Returning from the function implicitly kills storage for all locals and statics.
942-
// Often, the storage will already have been killed by an explicit
943-
// StorageDead, but we don't always emit those (notably on unwind paths),
944-
// so this "extra check" serves as a kind of backup.
945-
for i in state.borrows.iter() {
946-
let borrow = &self.borrow_set[i];
947-
self.check_for_invalidation_at_exit(loc, borrow, span);
951+
match self.borrow_set.locals_state_at_exit() {
952+
LocalsStateAtExit::AllAreInvalidated => {
953+
// Returning from the function implicitly kills storage for all locals and statics.
954+
// Often, the storage will already have been killed by an explicit
955+
// StorageDead, but we don't always emit those (notably on unwind paths),
956+
// so this "extra check" serves as a kind of backup.
957+
for i in state.borrows.iter() {
958+
let borrow = &self.borrow_set[i];
959+
self.check_for_invalidation_at_exit(loc, borrow, span);
960+
}
961+
}
962+
// If we do not implicitly invalidate all locals on exit,
963+
// we check for conflicts when dropping or moving this local.
964+
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
948965
}
949966
}
950967

@@ -1716,22 +1733,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
17161733
// we'll have a memory leak) and assume that all statics have a destructor.
17171734
//
17181735
// FIXME: allow thread-locals to borrow other thread locals?
1719-
1720-
let (might_be_alive, will_be_dropped) =
1721-
if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1722-
// Thread-locals might be dropped after the function exits
1723-
// We have to dereference the outer reference because
1724-
// borrows don't conflict behind shared references.
1725-
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1726-
(true, true)
1727-
} else {
1728-
(false, self.locals_are_invalidated_at_exit)
1729-
};
1730-
1731-
if !will_be_dropped {
1732-
debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
1733-
return;
1734-
}
1736+
let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1737+
// Thread-locals might be dropped after the function exits
1738+
// We have to dereference the outer reference because
1739+
// borrows don't conflict behind shared references.
1740+
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1741+
true
1742+
} else {
1743+
false
1744+
};
17351745

17361746
let sd = if might_be_alive { Deep } else { Shallow(None) };
17371747

Diff for: compiler/rustc_borrowck/src/nll.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use tracing::{debug, instrument};
2121

2222
use crate::borrow_set::BorrowSet;
2323
use crate::consumers::ConsumerOptions;
24-
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
24+
use crate::diagnostics::RegionErrors;
2525
use crate::polonius::PoloniusDiagnosticsContext;
2626
use crate::polonius::legacy::{
2727
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
@@ -297,7 +297,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
297297
body: &Body<'tcx>,
298298
regioncx: &RegionInferenceContext<'tcx>,
299299
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
300-
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
301300
) {
302301
let tcx = infcx.tcx;
303302
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@@ -335,13 +334,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
335334
} else {
336335
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
337336
regioncx.annotate(tcx, &mut err);
338-
339337
err
340338
};
341339

342340
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
343-
344-
diagnostics_buffer.buffer_non_error(err);
341+
err.emit();
345342
}
346343

347344
fn for_each_region_constraint<'tcx>(

0 commit comments

Comments
 (0)