Auto merge of #52566 - pnkfelix:buffer-nll-errors-for-z-borrowck-migrate, r=nikomatsakis
Buffer NLL errors Buffer the errors generated during MIR-borrowck (aka NLL). This is the first big step towards resolving issue #46908.
This commit is contained in:
commit
8dbbd81f7e
@ -1086,6 +1086,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
) {
|
||||
self.construct_generic_bound_failure(region_scope_tree,
|
||||
span,
|
||||
origin,
|
||||
bound_kind,
|
||||
sub)
|
||||
.emit()
|
||||
}
|
||||
|
||||
pub fn construct_generic_bound_failure(
|
||||
&self,
|
||||
region_scope_tree: ®ion::ScopeTree,
|
||||
span: Span,
|
||||
origin: Option<SubregionOrigin<'tcx>>,
|
||||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'a>
|
||||
{
|
||||
// Attempt to obtain the span of the parameter so we can
|
||||
// suggest adding an explicit lifetime bound to it.
|
||||
let type_param_span = match (self.in_progress_tables, bound_kind) {
|
||||
@ -1139,14 +1156,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
trait_item_def_id,
|
||||
}) = origin
|
||||
{
|
||||
self.report_extra_impl_obligation(
|
||||
return self.report_extra_impl_obligation(
|
||||
span,
|
||||
item_name,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id,
|
||||
&format!("`{}: {}`", bound_kind, sub),
|
||||
).emit();
|
||||
return;
|
||||
);
|
||||
}
|
||||
|
||||
fn binding_suggestion<'tcx, S: fmt::Display>(
|
||||
@ -1229,7 +1245,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
if let Some(origin) = origin {
|
||||
self.note_region_origin(&mut err, &origin);
|
||||
}
|
||||
err.emit();
|
||||
err
|
||||
}
|
||||
|
||||
fn report_sub_sup_conflict(
|
||||
|
@ -849,7 +849,7 @@ impl<'tcx> CommonTypes<'tcx> {
|
||||
///
|
||||
/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/ty.html
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TyCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
pub struct TyCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
gcx: &'a GlobalCtxt<'gcx>,
|
||||
interners: &'a CtxtInterners<'tcx>
|
||||
}
|
||||
|
@ -88,6 +88,18 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||
self.cancel();
|
||||
}
|
||||
|
||||
/// Buffers the diagnostic for later emission.
|
||||
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
|
||||
// We need to use `ptr::read` because `DiagnosticBuilder`
|
||||
// implements `Drop`.
|
||||
let diagnostic;
|
||||
unsafe {
|
||||
diagnostic = ::std::ptr::read(&self.diagnostic);
|
||||
::std::mem::forget(self);
|
||||
};
|
||||
buffered_diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
pub fn is_error(&self) -> bool {
|
||||
match self.level {
|
||||
Level::Bug |
|
||||
|
@ -58,7 +58,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Some(name) => format!("`{}`", name),
|
||||
None => "value".to_owned(),
|
||||
};
|
||||
self.tcx
|
||||
let mut err = self.tcx
|
||||
.cannot_act_on_uninitialized_variable(
|
||||
span,
|
||||
desired_action.as_noun(),
|
||||
@ -66,9 +66,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
.describe_place_with_options(place, IncludingDowncast(true))
|
||||
.unwrap_or("_".to_owned()),
|
||||
Origin::Mir,
|
||||
)
|
||||
.span_label(span, format!("use of possibly uninitialized {}", item_msg))
|
||||
.emit();
|
||||
);
|
||||
err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
} else {
|
||||
let msg = ""; //FIXME: add "partially " or "collaterally "
|
||||
|
||||
@ -143,7 +143,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
);
|
||||
err.span_label(span, format!("move out of {} occurs here", value_msg));
|
||||
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
pub(super) fn report_use_while_mutably_borrowed(
|
||||
@ -194,8 +194,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
);
|
||||
|
||||
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
|
||||
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
/// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
|
||||
@ -391,7 +390,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
||||
self.explain_why_borrow_contains_point(context, issued_borrow, None, &mut err);
|
||||
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
||||
@ -513,7 +512,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
format!("`{}` dropped here while still borrowed", name),
|
||||
);
|
||||
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
fn report_scoped_temporary_value_does_not_live_long_enough(
|
||||
@ -535,7 +534,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
);
|
||||
err.note("consider using a `let` binding to increase its lifetime");
|
||||
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
fn report_unscoped_local_value_does_not_live_long_enough(
|
||||
@ -563,7 +562,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
err.span_label(drop_span, "borrowed value only lives until here");
|
||||
|
||||
self.explain_why_borrow_contains_point(context, borrow, kind_place, &mut err);
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
fn report_unscoped_temporary_value_does_not_live_long_enough(
|
||||
@ -589,7 +588,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
err.span_label(drop_span, "temporary value only lives until here");
|
||||
|
||||
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
pub(super) fn report_illegal_mutation_of_borrowed(
|
||||
@ -608,7 +607,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
||||
self.explain_why_borrow_contains_point(context, loan, None, &mut err);
|
||||
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
/// Reports an illegal reassignment; for example, an assignment to
|
||||
@ -679,7 +678,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
err.span_label(span, msg);
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ use rustc::mir::{Terminator, TerminatorKind};
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::{self, ParamEnv, TyCtxt};
|
||||
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||
@ -148,6 +149,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
let mir = &mir; // no further changes
|
||||
let location_table = &LocationTable::new(mir);
|
||||
|
||||
let mut errors_buffer = Vec::new();
|
||||
let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<MoveError<'tcx>>>) =
|
||||
match MoveData::gather_moves(mir, tcx) {
|
||||
Ok(move_data) => (move_data, None),
|
||||
@ -214,6 +216,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
&mut flow_inits,
|
||||
&mdpe.move_data,
|
||||
&borrow_set,
|
||||
&mut errors_buffer,
|
||||
);
|
||||
let regioncx = Rc::new(regioncx);
|
||||
|
||||
@ -252,6 +255,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
access_place_error_reported: FxHashSet(),
|
||||
reservation_error_reported: FxHashSet(),
|
||||
moved_error_reported: FxHashSet(),
|
||||
errors_buffer,
|
||||
nonlexical_regioncx: regioncx,
|
||||
used_mut: FxHashSet(),
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
@ -287,10 +291,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
|
||||
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
|
||||
|
||||
let used_mut = mbcx.used_mut;
|
||||
|
||||
for local in mbcx
|
||||
.mir
|
||||
.mut_vars_and_args_iter()
|
||||
.filter(|local| !mbcx.used_mut.contains(local))
|
||||
.filter(|local| !used_mut.contains(local))
|
||||
{
|
||||
if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
|
||||
let local_decl = &mbcx.mir.local_decls[local];
|
||||
@ -311,16 +317,22 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
let span = local_decl.source_info.span;
|
||||
let mut_span = tcx.sess.codemap().span_until_non_whitespace(span);
|
||||
|
||||
tcx.struct_span_lint_node(
|
||||
let mut err = tcx.struct_span_lint_node(
|
||||
UNUSED_MUT,
|
||||
vsi[local_decl.source_info.scope].lint_root,
|
||||
span,
|
||||
"variable does not need to be mutable",
|
||||
).span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
|
||||
.emit();
|
||||
);
|
||||
err.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned());
|
||||
|
||||
err.buffer(&mut mbcx.errors_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
for diag in mbcx.errors_buffer.drain(..) {
|
||||
DiagnosticBuilder::new_diagnostic(mbcx.tcx.sess.diagnostic(), diag).emit();
|
||||
}
|
||||
|
||||
let result = BorrowCheckResult {
|
||||
closure_requirements: opt_closure_req,
|
||||
used_mut_upvars: mbcx.used_mut_upvars,
|
||||
@ -331,7 +343,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
result
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
mir: &'cx Mir<'tcx>,
|
||||
@ -366,8 +377,10 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
/// at the time we detect and report a reservation error.
|
||||
reservation_error_reported: FxHashSet<Place<'tcx>>,
|
||||
/// This field keeps track of errors reported in the checking of moved variables,
|
||||
/// so that we don't report report seemingly duplicate errors.
|
||||
/// so that we don't report seemingly duplicate errors.
|
||||
moved_error_reported: FxHashSet<Place<'tcx>>,
|
||||
/// Errors to be reported buffer
|
||||
errors_buffer: Vec<Diagnostic>,
|
||||
/// This field keeps track of all the local variables that are declared mut and are mutated.
|
||||
/// Used for the warning issued by an unused mutable local variable.
|
||||
used_mut: FxHashSet<Local>,
|
||||
@ -1354,13 +1367,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
debug!("check_for_local_borrow({:?})", borrow);
|
||||
|
||||
if borrow_of_local_data(&borrow.borrowed_place) {
|
||||
self.tcx
|
||||
let err = self.tcx
|
||||
.cannot_borrow_across_generator_yield(
|
||||
self.retrieve_borrow_span(borrow),
|
||||
yield_span,
|
||||
Origin::Mir,
|
||||
)
|
||||
.emit();
|
||||
);
|
||||
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ enum GroupedMoveError<'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||
pub(crate) fn report_move_errors(&self, move_errors: Vec<MoveError<'tcx>>) {
|
||||
pub(crate) fn report_move_errors(&mut self, move_errors: Vec<MoveError<'tcx>>) {
|
||||
let grouped_errors = self.group_move_errors(move_errors);
|
||||
for error in grouped_errors {
|
||||
self.report(error);
|
||||
@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
}
|
||||
|
||||
fn report(&self, error: GroupedMoveError<'tcx>) {
|
||||
fn report(&mut self, error: GroupedMoveError<'tcx>) {
|
||||
let (mut err, err_span) = {
|
||||
let (span, kind): (Span, &IllegalMoveOriginKind) = match error {
|
||||
GroupedMoveError::MovesFromMatchPlace { span, ref kind, .. }
|
||||
@ -286,7 +286,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
self.add_move_hints(error, &mut err, err_span);
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
fn add_move_hints(
|
||||
|
@ -378,7 +378,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
// Does this place refer to what the user sees as an upvar
|
||||
|
@ -19,10 +19,10 @@ use rustc::ty::{RegionVid, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use util::liveness::{self, DefUse, LivenessMode};
|
||||
|
||||
crate fn find<'cx, 'gcx: 'tcx, 'tcx: 'cx>(
|
||||
mir: &'cx Mir<'tcx>,
|
||||
regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
crate fn find<'tcx>(
|
||||
mir: &Mir<'tcx>,
|
||||
regioncx: &Rc<RegionInferenceContext<'tcx>>,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
region_vid: RegionVid,
|
||||
start_point: Location,
|
||||
) -> Option<Cause> {
|
||||
|
@ -23,6 +23,7 @@ use rustc::infer::InferCtxt;
|
||||
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir};
|
||||
use rustc::ty::{self, RegionKind, RegionVid};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_errors::Diagnostic;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Debug;
|
||||
use std::env;
|
||||
@ -91,6 +92,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> (
|
||||
RegionInferenceContext<'tcx>,
|
||||
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
|
||||
@ -120,6 +122,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
flow_inits,
|
||||
move_data,
|
||||
elements,
|
||||
errors_buffer,
|
||||
);
|
||||
|
||||
if let Some(all_facts) = &mut all_facts {
|
||||
@ -190,7 +193,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
});
|
||||
|
||||
// Solve the region constraints.
|
||||
let closure_region_requirements = regioncx.solve(infcx, &mir, def_id);
|
||||
let closure_region_requirements = regioncx.solve(infcx, &mir, def_id, errors_buffer);
|
||||
|
||||
// Dump MIR results into a file, if that is enabled. This let us
|
||||
// write unit-tests, as well as helping with debugging.
|
||||
@ -205,7 +208,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
|
||||
// We also have a `#[rustc_nll]` annotation that causes us to dump
|
||||
// information
|
||||
dump_annotation(infcx, &mir, def_id, ®ioncx, &closure_region_requirements);
|
||||
dump_annotation(infcx, &mir, def_id, ®ioncx, &closure_region_requirements, errors_buffer);
|
||||
|
||||
(regioncx, polonius_output, closure_region_requirements)
|
||||
}
|
||||
@ -323,6 +326,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>(
|
||||
mir_def_id: DefId,
|
||||
regioncx: &RegionInferenceContext,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.closure_base_def_id(mir_def_id);
|
||||
@ -357,14 +361,15 @@ fn dump_annotation<'a, 'gcx, 'tcx>(
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
err.emit();
|
||||
err.buffer(errors_buffer);
|
||||
} else {
|
||||
let mut err = tcx
|
||||
.sess
|
||||
.diagnostic()
|
||||
.span_note_diag(mir.span, "No external requirements");
|
||||
regioncx.annotate(&mut err);
|
||||
err.emit();
|
||||
|
||||
err.buffer(errors_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use borrow_check::nll::universal_regions::DefiningTy;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
|
||||
impl<'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Write out our state into the `.mir` files.
|
||||
pub(crate) fn annotate(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
match self.universal_regions.defining_ty {
|
||||
|
@ -18,6 +18,7 @@ use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKi
|
||||
use rustc::ty::RegionVid;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_errors::Diagnostic;
|
||||
use std::fmt;
|
||||
use syntax_pos::Span;
|
||||
|
||||
@ -199,6 +200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
fr: RegionVid,
|
||||
outlived_fr: RegionVid,
|
||||
blame_span: Span,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
||||
|
||||
@ -247,9 +249,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
match category {
|
||||
ConstraintCategory::AssignmentToUpvar |
|
||||
ConstraintCategory::CallArgumentToUpvar =>
|
||||
self.report_closure_error(mir, infcx, mir_def_id, fr, outlived_fr, category, span),
|
||||
self.report_closure_error(
|
||||
mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer),
|
||||
_ =>
|
||||
self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category, span),
|
||||
self.report_general_error(
|
||||
mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer),
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,6 +266,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
outlived_fr: RegionVid,
|
||||
category: &ConstraintCategory,
|
||||
span: &Span,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
let fr_name_and_span = self.get_var_name_and_span_for_region(
|
||||
infcx.tcx, mir, fr);
|
||||
@ -269,11 +274,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
infcx.tcx, mir,outlived_fr);
|
||||
|
||||
if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
|
||||
return self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category,
|
||||
span);
|
||||
return self.report_general_error(
|
||||
mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer);
|
||||
}
|
||||
|
||||
let diag = &mut infcx.tcx.sess.struct_span_err(
|
||||
let mut diag = infcx.tcx.sess.struct_span_err(
|
||||
*span, &format!("borrowed data escapes outside of closure"),
|
||||
);
|
||||
|
||||
@ -297,7 +302,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
diag.buffer(errors_buffer);
|
||||
}
|
||||
|
||||
fn report_general_error(
|
||||
@ -309,23 +314,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
outlived_fr: RegionVid,
|
||||
category: &ConstraintCategory,
|
||||
span: &Span,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
let diag = &mut infcx.tcx.sess.struct_span_err(
|
||||
let mut diag = infcx.tcx.sess.struct_span_err(
|
||||
*span, &format!("unsatisfied lifetime constraints"), // FIXME
|
||||
);
|
||||
|
||||
let counter = &mut 1;
|
||||
let fr_name = self.give_region_a_name(
|
||||
infcx.tcx, mir, mir_def_id, fr, counter, diag);
|
||||
infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
|
||||
let outlived_fr_name = self.give_region_a_name(
|
||||
infcx.tcx, mir, mir_def_id, outlived_fr, counter, diag);
|
||||
infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
|
||||
|
||||
diag.span_label(*span, format!(
|
||||
"{} requires that `{}` must outlive `{}`",
|
||||
category, fr_name, outlived_fr_name,
|
||||
));
|
||||
|
||||
diag.emit();
|
||||
diag.buffer(errors_buffer);
|
||||
}
|
||||
|
||||
// Find some constraint `X: Y` where:
|
||||
|
@ -30,6 +30,7 @@ use rustc::util::common;
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_errors::Diagnostic;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -360,11 +361,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> Option<ClosureRegionRequirements<'gcx>> {
|
||||
common::time(
|
||||
infcx.tcx.sess,
|
||||
&format!("solve_nll_region_constraints({:?})", mir_def_id),
|
||||
|| self.solve_inner(infcx, mir, mir_def_id),
|
||||
|| self.solve_inner(infcx, mir, mir_def_id, errors_buffer),
|
||||
)
|
||||
}
|
||||
|
||||
@ -373,6 +375,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> Option<ClosureRegionRequirements<'gcx>> {
|
||||
self.propagate_constraints(mir);
|
||||
|
||||
@ -387,9 +390,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
None
|
||||
};
|
||||
|
||||
self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());
|
||||
self.check_type_tests(
|
||||
infcx, mir, mir_def_id, outlives_requirements.as_mut(), errors_buffer);
|
||||
|
||||
self.check_universal_regions(infcx, mir, mir_def_id, outlives_requirements.as_mut());
|
||||
self.check_universal_regions(
|
||||
infcx, mir, mir_def_id, outlives_requirements.as_mut(), errors_buffer);
|
||||
|
||||
let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
|
||||
|
||||
@ -476,6 +481,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
@ -502,13 +508,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
if let Some(lower_bound_region) = lower_bound_region {
|
||||
let region_scope_tree = &tcx.region_scope_tree(mir_def_id);
|
||||
let type_test_span = type_test.locations.span(mir);
|
||||
infcx.report_generic_bound_failure(
|
||||
infcx.construct_generic_bound_failure(
|
||||
region_scope_tree,
|
||||
type_test_span,
|
||||
None,
|
||||
type_test.generic_kind,
|
||||
lower_bound_region,
|
||||
);
|
||||
).buffer(errors_buffer);
|
||||
} else {
|
||||
// FIXME. We should handle this case better. It
|
||||
// indicates that we have e.g. some region variable
|
||||
@ -520,10 +526,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// iterating over the universal regions and reporting
|
||||
// an error that multiple bounds are required.
|
||||
let type_test_span = type_test.locations.span(mir);
|
||||
tcx.sess.span_err(
|
||||
tcx.sess.struct_span_err(
|
||||
type_test_span,
|
||||
&format!("`{}` does not live long enough", type_test.generic_kind,),
|
||||
);
|
||||
).buffer(errors_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -834,6 +840,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
// The universal regions are always found in a prefix of the
|
||||
// full list.
|
||||
@ -851,6 +858,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
mir_def_id,
|
||||
fr,
|
||||
&mut propagated_outlives_requirements,
|
||||
errors_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -870,6 +878,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
mir_def_id: DefId,
|
||||
longer_fr: RegionVid,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
debug!("check_universal_region(fr={:?})", longer_fr);
|
||||
|
||||
@ -924,7 +933,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// Note: in this case, we use the unapproximated regions
|
||||
// to report the error. This gives better error messages
|
||||
// in some cases.
|
||||
self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, blame_span);
|
||||
self.report_error(
|
||||
mir, infcx, mir_def_id, longer_fr, shorter_fr, blame_span, errors_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ use std::rc::Rc;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use transform::{MirPass, MirSource};
|
||||
use util::liveness::LivenessResults;
|
||||
use rustc_errors::Diagnostic;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
@ -102,6 +103,7 @@ mod liveness;
|
||||
/// constraints for the regions in the types of variables
|
||||
/// - `flow_inits` -- results of a maybe-init dataflow analysis
|
||||
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
||||
/// - `errors_buffer` -- errors are sent here for future reporting
|
||||
pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
@ -115,6 +117,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> MirTypeckRegionConstraints<'tcx> {
|
||||
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
|
||||
let mut constraints = MirTypeckRegionConstraints {
|
||||
@ -140,14 +143,13 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
&universal_regions.region_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
Some(&mut borrowck_context),
|
||||
Some(errors_buffer),
|
||||
|cx| {
|
||||
liveness::generate(cx, mir, liveness, flow_inits, move_data);
|
||||
|
||||
cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
constraints
|
||||
}
|
||||
|
||||
@ -159,6 +161,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, F>(
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
errors_buffer: Option<&mut Vec<Diagnostic>>,
|
||||
mut extra: F,
|
||||
)
|
||||
where F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>)
|
||||
@ -180,7 +183,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, F>(
|
||||
|
||||
if !errors_reported {
|
||||
// if verifier failed, don't do further checks to avoid ICEs
|
||||
checker.typeck_mir(mir);
|
||||
checker.typeck_mir(mir, errors_buffer);
|
||||
}
|
||||
|
||||
extra(&mut checker);
|
||||
@ -202,7 +205,7 @@ enum FieldAccessError {
|
||||
/// The sanitize_XYZ methods here take an MIR object and compute its
|
||||
/// type, calling `span_mirbug` and returning an error type if there
|
||||
/// is a problem.
|
||||
struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b + 'tcx, 'tcx: 'b> {
|
||||
struct TypeVerifier<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
|
||||
cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
last_span: Span,
|
||||
@ -611,7 +614,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
/// constraints needed for it to be valid and well-typed. Along the
|
||||
/// way, it accrues region constraints -- these can later be used by
|
||||
/// NLL region checking.
|
||||
struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
last_span: Span,
|
||||
@ -1227,7 +1230,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
fn check_local(&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
local: Local,
|
||||
local_decl: &LocalDecl<'tcx>,
|
||||
errors_buffer: &mut Option<&mut Vec<Diagnostic>>)
|
||||
{
|
||||
match mir.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||
// return values of normal functions are required to be
|
||||
@ -1255,14 +1263,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
// slot or local, so to find all unsized rvalues it is enough
|
||||
// to check all temps, return slots and locals.
|
||||
if let None = self.reported_errors.replace((ty, span)) {
|
||||
span_err!(
|
||||
self.tcx().sess,
|
||||
let mut diag = struct_span_err!(self.tcx().sess,
|
||||
span,
|
||||
E0161,
|
||||
"cannot move a value of type {0}: the size of {0} \
|
||||
cannot be statically determined",
|
||||
ty
|
||||
);
|
||||
ty);
|
||||
if let Some(ref mut errors_buffer) = *errors_buffer {
|
||||
diag.buffer(errors_buffer);
|
||||
} else {
|
||||
// we're allowed to use emit() here because the
|
||||
// NLL migration will be turned on (and thus
|
||||
// errors will need to be buffered) *only if*
|
||||
// errors_buffer is Some.
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1742,12 +1757,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
|
||||
fn typeck_mir(&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
mut errors_buffer: Option<&mut Vec<Diagnostic>>)
|
||||
{
|
||||
self.last_span = mir.span;
|
||||
debug!("run_on_mir: {:?}", mir.span);
|
||||
|
||||
for (local, local_decl) in mir.local_decls.iter_enumerated() {
|
||||
self.check_local(mir, local, local_decl);
|
||||
self.check_local(mir, local, local_decl, &mut errors_buffer);
|
||||
}
|
||||
|
||||
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
|
||||
@ -1812,7 +1830,7 @@ impl MirPass for TypeckMir {
|
||||
|
||||
let param_env = tcx.param_env(def_id);
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, |_| ());
|
||||
type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, None, |_| ());
|
||||
|
||||
// For verification purposes, we just ignore the resulting
|
||||
// region constraint sets. Not our problem. =)
|
||||
|
@ -34,8 +34,8 @@ pub trait MirWithFlowState<'tcx> {
|
||||
fn flow_state(&self) -> &DataflowState<Self::BD>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
|
||||
where 'tcx: 'a, BD: BitDenotation
|
||||
impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
|
||||
where BD: BitDenotation
|
||||
{
|
||||
type BD = BD;
|
||||
fn node_id(&self) -> NodeId { self.node_id }
|
||||
|
@ -53,8 +53,8 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
_nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
|
||||
}
|
||||
|
||||
fn precompute_borrows_out_of_scope<'a, 'tcx>(
|
||||
mir: &'a Mir<'tcx>,
|
||||
fn precompute_borrows_out_of_scope<'tcx>(
|
||||
mir: &Mir<'tcx>,
|
||||
regioncx: &Rc<RegionInferenceContext<'tcx>>,
|
||||
borrows_out_of_scope_at_location: &mut FxHashMap<Location, Vec<BorrowIndex>>,
|
||||
borrow_index: BorrowIndex,
|
||||
|
Loading…
Reference in New Issue
Block a user