about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2018-08-07 21:30:01 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2018-08-14 20:35:46 +0100
commit74ce76a00964bc648b3639ea565359e477b7002b (patch)
tree6f444185afe908b19c06a60176914c74dfc17f11
parent092f03a07aa075c6b5cfecc47a8be6e133073819 (diff)
downloadrust-74ce76a00964bc648b3639ea565359e477b7002b.tar.gz
rust-74ce76a00964bc648b3639ea565359e477b7002b.zip
Treat assigning the destination of a call as an assignment
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs45
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs4
2 files changed, 42 insertions, 7 deletions
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index c2670389e2d..3a83db3ad6a 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -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
     }
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index f7dfa5a7ae5..ebcc044093a 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -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 --