Skip to content

Commit 29c2bb5

Browse files
rework borrowck errors so that it's harder to not set tainted
1 parent 8b7b0a0 commit 29c2bb5

File tree

7 files changed

+119
-74
lines changed

7 files changed

+119
-74
lines changed

compiler/rustc_borrowck/src/borrowck_errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
327327
verb: &str,
328328
optional_adverb_for_moved: &str,
329329
moved_path: Option<String>,
330-
) -> DiagnosticBuilder<'cx> {
330+
) -> DiagnosticBuilder<'tcx> {
331331
let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default();
332332

333333
struct_span_err!(

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
7777
if move_out_indices.is_empty() {
7878
let root_place = PlaceRef { projection: &[], ..used_place };
7979

80-
self.set_tainted_by_errors();
8180
if !self.uninitialized_error_reported.insert(root_place) {
8281
debug!(
8382
"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
@@ -107,7 +106,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
107106

108107
self.buffer_error(err);
109108
} else {
110-
if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
109+
if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
111110
if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
112111
debug!(
113112
"report_use_of_moved_or_uninitialized place: error suppressed \
@@ -217,7 +216,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
217216
place_name, partially_str, loop_message
218217
),
219218
);
220-
self.set_tainted_by_errors();
221219
if self.fn_self_span_reported.insert(fn_span) {
222220
err.span_note(
223221
// Check whether the source is accessible
@@ -299,7 +297,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
299297
}
300298
// Avoid pointing to the same function in multiple different
301299
// error messages.
302-
self.set_tainted_by_errors();
303300
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
304301
{
305302
err.span_note(
@@ -452,13 +449,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
452449
}
453450
}
454451

455-
self.set_tainted_by_errors();
456-
if let Some((_, mut old_err)) =
457-
self.move_error_reported.insert(move_out_indices, (used_place, err))
458-
{
459-
// Cancel the old error so it doesn't ICE.
460-
old_err.cancel();
461-
}
452+
self.buffer_move_error(move_out_indices, (used_place, err));
462453
}
463454
}
464455

@@ -1016,7 +1007,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10161007
return;
10171008
}
10181009

1019-
self.set_tainted_by_errors();
10201010
self.access_place_error_reported.insert((
10211011
Place { local: root_place.local, projection: root_place_projection },
10221012
borrow_span,

compiler/rustc_borrowck/src/lib.rs

+107-52
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,13 @@ fn do_mir_borrowck<'a, 'tcx>(
175175
}
176176
}
177177

178+
let mut errors = error::BorrowckErrors::new();
179+
178180
// Gather the upvars of a closure, if any.
179181
let tables = tcx.typeck_opt_const_arg(def);
180182
if let Some(ErrorReported) = tables.tainted_by_errors {
181183
infcx.set_tainted_by_errors();
184+
errors.set_tainted_by_errors();
182185
}
183186
let upvars: Vec<_> = tables
184187
.closure_min_captures_flattened(def.did.to_def_id())
@@ -205,7 +208,6 @@ fn do_mir_borrowck<'a, 'tcx>(
205208
let location_table_owned = LocationTable::new(body);
206209
let location_table = &location_table_owned;
207210

208-
let mut errors_buffer = Vec::new();
209211
let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) =
210212
match MoveData::gather_moves(&body, tcx, param_env) {
211213
Ok(move_data) => (move_data, Vec::new()),
@@ -263,7 +265,7 @@ fn do_mir_borrowck<'a, 'tcx>(
263265
&regioncx,
264266
&opt_closure_req,
265267
&opaque_type_values,
266-
&mut errors_buffer,
268+
&mut errors,
267269
);
268270

269271
// The various `flow_*` structures can be large. We drop `flow_inits` here
@@ -310,10 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>(
310312
access_place_error_reported: Default::default(),
311313
reservation_error_reported: Default::default(),
312314
reservation_warnings: Default::default(),
313-
move_error_reported: BTreeMap::new(),
314315
uninitialized_error_reported: Default::default(),
315-
errors_buffer,
316-
tainted_by_errors: false,
317316
regioncx: regioncx.clone(),
318317
used_mut: Default::default(),
319318
used_mut_upvars: SmallVec::new(),
@@ -324,9 +323,10 @@ fn do_mir_borrowck<'a, 'tcx>(
324323
region_names: RefCell::default(),
325324
next_region_name: RefCell::new(1),
326325
polonius_output: None,
326+
errors,
327327
};
328328
promoted_mbcx.report_move_errors(move_errors);
329-
errors_buffer = promoted_mbcx.errors_buffer;
329+
errors = promoted_mbcx.errors;
330330
};
331331
}
332332

@@ -344,10 +344,7 @@ fn do_mir_borrowck<'a, 'tcx>(
344344
access_place_error_reported: Default::default(),
345345
reservation_error_reported: Default::default(),
346346
reservation_warnings: Default::default(),
347-
move_error_reported: BTreeMap::new(),
348347
uninitialized_error_reported: Default::default(),
349-
errors_buffer,
350-
tainted_by_errors: false,
351348
regioncx: Rc::clone(&regioncx),
352349
used_mut: Default::default(),
353350
used_mut_upvars: SmallVec::new(),
@@ -358,6 +355,7 @@ fn do_mir_borrowck<'a, 'tcx>(
358355
region_names: RefCell::default(),
359356
next_region_name: RefCell::new(1),
360357
polonius_output,
358+
errors,
361359
};
362360

363361
// Compute and report region errors, if any.
@@ -462,24 +460,13 @@ fn do_mir_borrowck<'a, 'tcx>(
462460
})
463461
}
464462

465-
// Buffer any move errors that we collected and de-duplicated.
466-
for (_, (_, diag)) in std::mem::take(&mut mbcx.move_error_reported) {
467-
mbcx.buffer_error(diag);
468-
}
469-
470-
if !mbcx.errors_buffer.is_empty() {
471-
mbcx.errors_buffer.sort_by_key(|diag| diag.sort_span);
472-
473-
for diag in mbcx.errors_buffer.drain(..) {
474-
mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
475-
}
476-
}
463+
let tainted_by_errors = mbcx.emit_errors();
477464

478465
let result = BorrowCheckResult {
479466
concrete_opaque_types: opaque_type_values,
480467
closure_requirements: opt_closure_req,
481468
used_mut_upvars: mbcx.used_mut_upvars,
482-
tainted_by_errors: mbcx.tainted_by_errors,
469+
tainted_by_errors,
483470
};
484471

485472
let body_with_facts = if return_body_with_facts {
@@ -556,28 +543,9 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
556543
/// for the activation of the borrow.
557544
reservation_warnings:
558545
FxHashMap<BorrowIndex, (Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>)>,
559-
/// This field keeps track of move errors that are to be reported for given move indices.
560-
///
561-
/// There are situations where many errors can be reported for a single move out (see #53807)
562-
/// and we want only the best of those errors.
563-
///
564-
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
565-
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
566-
/// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
567-
/// all move errors have been reported, any diagnostics in this map are added to the buffer
568-
/// to be emitted.
569-
///
570-
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
571-
/// when errors in the map are being re-added to the error buffer so that errors with the
572-
/// same primary span come out in a consistent order.
573-
move_error_reported: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'cx>)>,
574546
/// This field keeps track of errors reported in the checking of uninitialized variables,
575547
/// so that we don't report seemingly duplicate errors.
576548
uninitialized_error_reported: FxHashSet<PlaceRef<'tcx>>,
577-
/// Errors to be reported buffer
578-
errors_buffer: Vec<Diagnostic>,
579-
/// Set to true if we emit an error during borrowck
580-
tainted_by_errors: bool,
581549
/// This field keeps track of all the local variables that are declared mut and are mutated.
582550
/// Used for the warning issued by an unused mutable local variable.
583551
used_mut: FxHashSet<Local>,
@@ -609,6 +577,8 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
609577

610578
/// Results of Polonius analysis.
611579
polonius_output: Option<Rc<PoloniusOutput>>,
580+
581+
errors: error::BorrowckErrors<'tcx>,
612582
}
613583

614584
// Check that:
@@ -1032,8 +1002,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10321002

10331003
if conflict_error || mutability_error {
10341004
debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1035-
1036-
self.set_tainted_by_errors();
10371005
self.access_place_error_reported.insert((place_span.0, place_span.1));
10381006
}
10391007
}
@@ -2055,10 +2023,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
20552023
| WriteKind::MutableBorrow(BorrowKind::Shared)
20562024
| WriteKind::MutableBorrow(BorrowKind::Shallow),
20572025
) => {
2058-
if let (Err(_), true) = (
2059-
self.is_mutable(place.as_ref(), is_local_mutation_allowed),
2060-
self.errors_buffer.is_empty(),
2061-
) {
2026+
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2027+
&& !self.has_buffered_errors()
2028+
{
20622029
// rust-lang/rust#46908: In pure NLL mode this code path should be
20632030
// unreachable, but we use `delay_span_bug` because we can hit this when
20642031
// dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
@@ -2308,14 +2275,102 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
23082275
fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
23092276
path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
23102277
}
2278+
}
2279+
2280+
mod error {
2281+
use super::*;
2282+
2283+
pub struct BorrowckErrors<'tcx> {
2284+
/// This field keeps track of move errors that are to be reported for given move indices.
2285+
///
2286+
/// There are situations where many errors can be reported for a single move out (see #53807)
2287+
/// and we want only the best of those errors.
2288+
///
2289+
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
2290+
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
2291+
/// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
2292+
/// all move errors have been reported, any diagnostics in this map are added to the buffer
2293+
/// to be emitted.
2294+
///
2295+
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
2296+
/// when errors in the map are being re-added to the error buffer so that errors with the
2297+
/// same primary span come out in a consistent order.
2298+
buffered_move_errors:
2299+
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
2300+
/// Errors to be reported buffer
2301+
buffered: Vec<Diagnostic>,
2302+
/// Set to Some if we emit an error during borrowck
2303+
tainted_by_errors: Option<ErrorReported>,
2304+
}
2305+
2306+
impl BorrowckErrors<'_> {
2307+
pub fn new() -> Self {
2308+
BorrowckErrors {
2309+
buffered_move_errors: BTreeMap::new(),
2310+
buffered: Default::default(),
2311+
tainted_by_errors: None,
2312+
}
2313+
}
2314+
2315+
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
2316+
self.tainted_by_errors = Some(ErrorReported {});
2317+
t.buffer(&mut self.buffered);
2318+
}
23112319

2312-
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
2313-
self.tainted_by_errors = true;
2314-
t.buffer(&mut self.errors_buffer);
2320+
pub fn set_tainted_by_errors(&mut self) {
2321+
self.tainted_by_errors = Some(ErrorReported {});
2322+
}
23152323
}
23162324

2317-
pub fn set_tainted_by_errors(&mut self) {
2318-
self.tainted_by_errors = true;
2325+
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2326+
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
2327+
self.errors.buffer_error(t);
2328+
}
2329+
2330+
pub fn buffer_move_error(
2331+
&mut self,
2332+
move_out_indices: Vec<MoveOutIndex>,
2333+
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
2334+
) -> bool {
2335+
if let Some((_, mut diag)) =
2336+
self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
2337+
{
2338+
// Cancel the old diagnostic so we don't ICE
2339+
diag.cancel();
2340+
false
2341+
} else {
2342+
true
2343+
}
2344+
}
2345+
2346+
pub fn emit_errors(&mut self) -> Option<ErrorReported> {
2347+
// Buffer any move errors that we collected and de-duplicated.
2348+
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
2349+
// We have already set tainted for this error, so just buffer it.
2350+
diag.buffer(&mut self.errors.buffered);
2351+
}
2352+
2353+
if !self.errors.buffered.is_empty() {
2354+
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
2355+
2356+
for diag in self.errors.buffered.drain(..) {
2357+
self.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
2358+
}
2359+
}
2360+
2361+
self.errors.tainted_by_errors
2362+
}
2363+
2364+
pub fn has_buffered_errors(&self) -> bool {
2365+
self.errors.buffered.is_empty()
2366+
}
2367+
2368+
pub fn has_move_error(
2369+
&self,
2370+
move_out_indices: &[MoveOutIndex],
2371+
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
2372+
self.errors.buffered_move_errors.get(move_out_indices)
2373+
}
23192374
}
23202375
}
23212376

compiler/rustc_borrowck/src/nll.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! The entry point of the NLL borrow checker.
22
33
use rustc_data_structures::vec_map::VecMap;
4-
use rustc_errors::Diagnostic;
54
use rustc_index::vec::IndexVec;
65
use rustc_infer::infer::InferCtxt;
76
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
@@ -373,7 +372,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
373372
regioncx: &RegionInferenceContext<'tcx>,
374373
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
375374
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
376-
errors_buffer: &mut Vec<Diagnostic>,
375+
errors: &mut crate::error::BorrowckErrors<'tcx>,
377376
) {
378377
let tcx = infcx.tcx;
379378
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@@ -418,8 +417,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
418417
err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values));
419418
}
420419

421-
// FIXME(compiler-errors): Maybe we need to set tainted here
422-
err.buffer(errors_buffer);
420+
errors.buffer_error(err);
423421
}
424422

425423
fn for_each_region_constraint(

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
287287
if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors {
288288
return Err(ErrorHandled::Reported(error_reported));
289289
}
290-
if tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors {
291-
return Err(ErrorHandled::Reported(ErrorReported {}));
290+
if let Some(error_reported) = tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors {
291+
return Err(ErrorHandled::Reported(error_reported));
292292
}
293293
}
294294
if !tcx.is_mir_available(def.did) {

compiler/rustc_const_eval/src/interpret/eval_context.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
516516
if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors {
517517
throw_inval!(AlreadyReported(error_reported));
518518
}
519-
if self.tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors {
520-
throw_inval!(AlreadyReported(rustc_errors::ErrorReported {}));
519+
if let Some(error_reported) =
520+
self.tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors
521+
{
522+
throw_inval!(AlreadyReported(error_reported));
521523
}
522524
}
523525
}

compiler/rustc_middle/src/mir/query.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ pub struct BorrowCheckResult<'tcx> {
214214
pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
215215
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
216216
pub used_mut_upvars: SmallVec<[Field; 8]>,
217-
pub tainted_by_errors: bool,
217+
pub tainted_by_errors: Option<ErrorReported>,
218218
}
219219

220220
/// The result of the `mir_const_qualif` query.

0 commit comments

Comments
 (0)