Treat assigning the destination of a call as an assignment
This commit is contained in:
parent
092f03a07a
commit
74ce76a009
2 changed files with 42 additions and 7 deletions
|
@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
|
|||
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
|
||||
use rustc::ty::RegionVid;
|
||||
use rustc::ty::{TyCtxt, RegionVid};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_errors::Diagnostic;
|
||||
use std::collections::VecDeque;
|
||||
|
@ -67,6 +67,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
fn best_blame_constraint(
|
||||
&self,
|
||||
mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
from_region: RegionVid,
|
||||
target_test: impl Fn(RegionVid) -> bool,
|
||||
) -> (ConstraintCategory, Span, RegionVid) {
|
||||
|
@ -92,7 +93,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// Classify each of the constraints along the path.
|
||||
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
|
||||
.iter()
|
||||
.map(|&index| self.classify_constraint(index, mir))
|
||||
.map(|&index| self.classify_constraint(index, mir, tcx))
|
||||
.collect();
|
||||
debug!(
|
||||
"best_blame_constraint: categorized_path={:#?}",
|
||||
|
@ -231,6 +232,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
&self,
|
||||
index: ConstraintIndex,
|
||||
mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
) -> (ConstraintCategory, Span) {
|
||||
let constraint = self.constraints[index];
|
||||
debug!("classify_constraint: constraint={:?}", constraint);
|
||||
|
@ -254,7 +256,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
debug!("classify_constraint: terminator.kind={:?}", terminator.kind);
|
||||
match terminator.kind {
|
||||
TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
|
||||
TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
|
||||
// Classify calls differently depending on whether or not
|
||||
// the sub region appears in the destination type (so the
|
||||
// sup region is in the return type). If the return type
|
||||
// contains the sub-region, then this is either an
|
||||
// assignment or a return, depending on whether we are
|
||||
// writing to the RETURN_PLACE or not.
|
||||
//
|
||||
// The idea here is that the region is being propagated
|
||||
// from an input into the output place, so it's a kind of
|
||||
// assignment. Otherwise, if the sub-region only appears in
|
||||
// the argument types, then use the CallArgument
|
||||
// classification.
|
||||
TerminatorKind::Call { destination: Some((ref place, _)), .. } => {
|
||||
if tcx.any_free_region_meets(
|
||||
&place.ty(mir, tcx).to_ty(tcx),
|
||||
|region| self.to_region_vid(region) == constraint.sub,
|
||||
) {
|
||||
match place {
|
||||
Place::Local(mir::RETURN_PLACE) => ConstraintCategory::Return,
|
||||
_ => ConstraintCategory::Assignment,
|
||||
}
|
||||
} else {
|
||||
ConstraintCategory::CallArgument
|
||||
}
|
||||
}
|
||||
TerminatorKind::Call { destination: None, .. } => {
|
||||
ConstraintCategory::CallArgument
|
||||
}
|
||||
_ => ConstraintCategory::Other,
|
||||
}
|
||||
} else {
|
||||
|
@ -304,7 +333,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
) {
|
||||
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
||||
|
||||
let (category, span, _) = self.best_blame_constraint(mir, fr, |r| r == outlived_fr);
|
||||
let (category, span, _) = self.best_blame_constraint(
|
||||
mir,
|
||||
infcx.tcx,
|
||||
fr,
|
||||
|r| r == outlived_fr
|
||||
);
|
||||
|
||||
// Check if we can use one of the "nice region errors".
|
||||
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
|
||||
|
@ -446,10 +480,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
crate fn find_outlives_blame_span(
|
||||
&self,
|
||||
mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
fr1: RegionVid,
|
||||
fr2: RegionVid,
|
||||
) -> Span {
|
||||
let (_, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
|
||||
let (_, span, _) = self.best_blame_constraint(mir, tcx, fr1, |r| r == fr2);
|
||||
span
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1040,7 +1040,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
longer_fr, shorter_fr,
|
||||
);
|
||||
|
||||
let blame_span = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
|
||||
let blame_span = self.find_outlives_blame_span(mir, infcx.tcx, longer_fr, shorter_fr);
|
||||
|
||||
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
||||
// Shrink `fr` until we find a non-local region (if we do).
|
||||
|
@ -1128,7 +1128,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
};
|
||||
|
||||
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
|
||||
let span = self.find_outlives_blame_span(mir, longer_fr, error_region);
|
||||
let span = self.find_outlives_blame_span(mir, infcx.tcx, longer_fr, error_region);
|
||||
|
||||
// Obviously, this error message is far from satisfactory.
|
||||
// At present, though, it only appears in unit tests --
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue