summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/lib.rs')
-rw-r--r--compiler/rustc_borrowck/src/lib.rs104
1 files changed, 49 insertions, 55 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 74b4e4a0c..73ea7314b 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -5,6 +5,7 @@
#![feature(let_chains)]
#![feature(min_specialization)]
#![feature(never_type)]
+#![feature(once_cell)]
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
@@ -39,6 +40,7 @@ use rustc_span::{Span, Symbol};
use either::Either;
use smallvec::SmallVec;
+use std::cell::OnceCell;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
@@ -124,10 +126,7 @@ pub fn provide(providers: &mut Providers) {
};
}
-fn mir_borrowck<'tcx>(
- tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx BorrowCheckResult<'tcx> {
+fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &BorrowCheckResult<'_> {
let (input_body, promoted) = tcx.mir_promoted(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
@@ -336,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- dominators: Dominators::dummy(), // not used
+ dominators: Default::default(),
upvars: Vec::new(),
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
region_names: RefCell::default(),
@@ -349,8 +348,6 @@ fn do_mir_borrowck<'tcx>(
};
}
- let dominators = body.basic_blocks.dominators();
-
let mut mbcx = MirBorrowckCtxt {
infcx,
param_env,
@@ -367,7 +364,7 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- dominators,
+ dominators: Default::default(),
upvars,
local_names,
region_names: RefCell::default(),
@@ -537,7 +534,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
borrow_set: Rc<BorrowSet<'tcx>>,
/// Dominators for MIR
- dominators: Dominators<BasicBlock>,
+ dominators: OnceCell<Dominators<BasicBlock>>,
/// Information about upvars not necessarily preserved in types or MIR
upvars: Vec<Upvar<'tcx>>,
@@ -644,7 +641,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
self.check_activations(loc, span, flow_state);
match &term.kind {
- TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => {
+ TerminatorKind::SwitchInt { discr, targets: _ } => {
self.consume_operand(loc, (discr, span), flow_state);
}
TerminatorKind::Drop { place, target: _, unwind: _ } => {
@@ -866,7 +863,6 @@ enum WriteKind {
/// local place can be mutated.
//
// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications:
-// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`.
// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and
// `is_declared_mutable()`.
// - Take flow state into consideration in `is_assignable()` for local variables.
@@ -1055,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
- if !is_active(&this.dominators, borrow, location) {
+ if !is_active(this.dominators(), borrow, location) {
assert!(allow_two_phase_borrow(borrow.kind));
return Control::Continue;
}
@@ -1135,20 +1131,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
- // Special case: you can assign an immutable local variable
- // (e.g., `x = ...`) so long as it has never been initialized
- // before (at this point in the flow).
- if let Some(local) = place_span.0.as_local() {
- if let Mutability::Not = self.body.local_decls[local].mutability {
- // check for reassignments to immutable local variables
- self.check_if_reassignment_to_immutable_state(
- location, local, place_span, flow_state,
- );
- return;
- }
- }
-
- // Otherwise, use the normal access permission rules.
self.access_place(
location,
place_span,
@@ -1557,24 +1539,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
- fn check_if_reassignment_to_immutable_state(
- &mut self,
- location: Location,
- local: Local,
- place_span: (Place<'tcx>, Span),
- flow_state: &Flows<'cx, 'tcx>,
- ) {
- debug!("check_if_reassignment_to_immutable_state({:?})", local);
-
- // Check if any of the initializations of `local` have happened yet:
- if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
- // And, if so, report an error.
- let init = &self.move_data.inits[init_index];
- let span = init.span(&self.body);
- self.report_illegal_reassignment(location, place_span, span, place_span.0);
- }
- }
-
fn check_if_full_path_is_moved(
&mut self,
location: Location,
@@ -2040,12 +2004,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// partial initialization, do not complain about mutability
// errors except for actual mutation (as opposed to an attempt
// to do a partial initialization).
- let previously_initialized =
- self.is_local_ever_initialized(place.local, flow_state).is_some();
+ let previously_initialized = self.is_local_ever_initialized(place.local, flow_state);
// at this point, we have set up the error reporting state.
- if previously_initialized {
- self.report_mutability_error(place, span, the_place_err, error_access, location);
+ if let Some(init_index) = previously_initialized {
+ if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
+ // If this is a mutate access to an immutable local variable with no projections
+ // report the error as an illegal reassignment
+ let init = &self.move_data.inits[init_index];
+ let assigned_span = init.span(&self.body);
+ self.report_illegal_reassignment(location, (place, span), assigned_span, place);
+ } else {
+ self.report_mutability_error(place, span, the_place_err, error_access, location)
+ }
true
} else {
false
@@ -2059,12 +2030,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) -> Option<InitIndex> {
let mpi = self.move_data.rev_lookup.find_local(local);
let ii = &self.move_data.init_path_map[mpi];
- for &index in ii {
- if flow_state.ever_inits.contains(index) {
- return Some(index);
- }
- }
- None
+ ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied()
}
/// Adds the place into the used mutable variables set
@@ -2207,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// `self.foo` -- we want to double
// check that the location `*self`
// is mutable (i.e., this is not a
- // `Fn` closure). But if that
+ // `Fn` closure). But if that
// check succeeds, we want to
// *blame* the mutability on
// `place` (that is,
@@ -2253,6 +2219,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
}
+
+ fn dominators(&self) -> &Dominators<BasicBlock> {
+ self.dominators.get_or_init(|| self.body.basic_blocks.dominators())
+ }
}
mod error {
@@ -2278,6 +2248,7 @@ mod error {
/// same primary span come out in a consistent order.
buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+ buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
/// Diagnostics to be reported buffer.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
@@ -2289,6 +2260,7 @@ mod error {
BorrowckErrors {
tcx,
buffered_move_errors: BTreeMap::new(),
+ buffered_mut_errors: Default::default(),
buffered: Default::default(),
tainted_by_errors: None,
}
@@ -2339,12 +2311,34 @@ mod error {
}
}
+ pub fn get_buffered_mut_error(
+ &mut self,
+ span: Span,
+ ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+ self.errors.buffered_mut_errors.remove(&span)
+ }
+
+ pub fn buffer_mut_error(
+ &mut self,
+ span: Span,
+ t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ count: usize,
+ ) {
+ self.errors.buffered_mut_errors.insert(span, (t, count));
+ }
+
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
diag.buffer(&mut self.errors.buffered);
}
+ for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+ if count > 10 {
+ diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+ }
+ diag.buffer(&mut self.errors.buffered);
+ }
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);