about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs7
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_set.rs16
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs8
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs340
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs192
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs28
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs221
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr8
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr15
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr15
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr8
-rw-r--r--src/test/ui/nll/issue-50716.rs2
-rw-r--r--src/test/ui/nll/issue-50716.stderr4
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.rs6
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr24
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs6
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr24
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs2
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr8
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr12
26 files changed, 559 insertions, 399 deletions
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 72db9f8da98..68aa9aeabf8 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -10,9 +10,10 @@
 
 use borrow_check::borrow_set::BorrowSet;
 use borrow_check::location::LocationTable;
+use borrow_check::nll::ToRegionVid;
 use borrow_check::nll::facts::AllFacts;
 use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
-use borrow_check::nll::ToRegionVid;
+use borrow_check::nll::type_check::AtLocation;
 use rustc::hir;
 use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
@@ -310,12 +311,10 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.sty {
                         ty::TyRef(ref_region, _, mutbl) => {
-                            let span = self.mir.source_info(location).span;
                             self.regioncx.add_outlives(
-                                span,
+                                location.boring(),
                                 ref_region.to_region_vid(),
                                 borrow_region.to_region_vid(),
-                                location.successor_within_block(),
                             );
 
                             if let Some(all_facts) = self.all_facts {
diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs
index 4c6e445293d..3bdf78ff3db 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_set.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs
@@ -8,12 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::mir::Location;
 use rustc::ty::RegionVid;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use borrow_check::nll::type_check::Locations;
 
 use std::fmt;
-use syntax_pos::Span;
 use std::ops::Deref;
 
 #[derive(Clone, Default)]
@@ -24,8 +23,8 @@ crate struct ConstraintSet {
 impl ConstraintSet {
     pub fn push(&mut self, constraint: OutlivesConstraint) {
         debug!(
-            "add_outlives({:?}: {:?} @ {:?}",
-            constraint.sup, constraint.sub, constraint.point
+            "add_outlives({:?}: {:?} @ {:?})",
+            constraint.sup, constraint.sub, constraint.locations
         );
         if constraint.sup == constraint.sub {
             // 'a: 'a is pretty uninteresting
@@ -86,9 +85,6 @@ pub struct OutlivesConstraint {
     /// Region that must be outlived.
     pub sub: RegionVid,
 
-    /// At this location.
-    pub point: Location,
-
     /// Later on, we thread the constraints onto a linked list
     /// grouped by their `sub` field. So if you had:
     ///
@@ -100,15 +96,15 @@ pub struct OutlivesConstraint {
     pub next: Option<ConstraintIndex>,
 
     /// Where did this constraint arise?
-    pub span: Span,
+    pub locations: Locations,
 }
 
 impl fmt::Debug for OutlivesConstraint {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(
             formatter,
-            "({:?}: {:?} @ {:?}) due to {:?}",
-            self.sup, self.sub, self.point, self.span
+            "({:?}: {:?}) due to {:?}",
+            self.sup, self.sub, self.locations
         )
     }
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
index 6c796ea4c73..88d9f46e340 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
@@ -82,16 +82,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let OutlivesConstraint {
                 sup,
                 sub,
-                point,
-                span,
+                locations,
                 next: _,
             } = constraint;
             with_msg(&format!(
-                "{:?}: {:?} @ {:?} due to {:?}",
+                "{:?}: {:?} due to {:?}",
                 sup,
                 sub,
-                point,
-                span
+                locations,
             ))?;
         }
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
new file mode 100644
index 00000000000..970652d8872
--- /dev/null
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs
@@ -0,0 +1,340 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
+use borrow_check::nll::region_infer::values::ToElementIndex;
+use borrow_check::nll::type_check::Locations;
+use rustc::hir::def_id::DefId;
+use rustc::infer::InferCtxt;
+use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
+use rustc::mir::{self, Location, Mir, Place, StatementKind, TerminatorKind, Rvalue};
+use rustc::ty::RegionVid;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::indexed_vec::IndexVec;
+use syntax_pos::Span;
+
+/// Constraints that are considered interesting can be categorized to
+/// determine why they are interesting. Order of variants indicates
+/// sort order of the category, thereby influencing diagnostic output.
+#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
+enum ConstraintCategory {
+    Cast,
+    Assignment,
+    Return,
+    CallArgument,
+    Other,
+    Boring,
+}
+
+impl fmt::Display for ConstraintCategory {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            ConstraintCategory::Assignment => write!(f, "assignment"),
+            ConstraintCategory::Return => write!(f, "return"),
+            ConstraintCategory::Cast => write!(f, "cast"),
+            ConstraintCategory::CallArgument => write!(f, "argument"),
+            _ => write!(f, "free region"),
+        }
+    }
+}
+
+impl<'tcx> RegionInferenceContext<'tcx> {
+    /// When reporting an error, it is useful to be able to determine which constraints influenced
+    /// the region being reported as an error. This function finds all of the paths from the
+    /// constraint.
+    fn find_constraint_paths_from_region(
+        &self,
+        r0: RegionVid
+    ) -> Vec<Vec<ConstraintIndex>> {
+        let constraints = self.constraints.clone();
+
+        // Mapping of regions to the previous region and constraint index that led to it.
+        let mut previous = FxHashMap();
+        // Regions yet to be visited.
+        let mut next = vec! [ r0 ];
+        // Regions that have been visited.
+        let mut visited = FxHashSet();
+        // Ends of paths.
+        let mut end_regions = FxHashSet();
+
+        // When we've still got points to visit...
+        while let Some(current) = next.pop() {
+            // ...take the next point...
+            debug!("find_constraint_paths_from_region: current={:?} visited={:?} next={:?}",
+                   current, visited, next);
+            // ...but make sure not to visit this point again...
+            visited.insert(current);
+
+            // ...find the edges containing it...
+            let mut upcoming = Vec::new();
+            for (index, constraint) in constraints.iter_enumerated() {
+                if constraint.sub == current {
+                    // ...add the regions that join us with to the path we've taken...
+                    debug!("find_constraint_paths_from_region: index={:?} constraint={:?}",
+                           index, constraint);
+                    let next_region = constraint.sup.clone();
+
+                    // ...unless we've visited it since this was added...
+                    if visited.contains(&next_region) {
+                        debug!("find_constraint_paths_from_region: skipping as visited");
+                        continue;
+                    }
+
+                    previous.insert(next_region, (index, Some(current)));
+                    upcoming.push(next_region);
+                }
+            }
+
+            if upcoming.is_empty() {
+                // If we didn't find any edges then this is the end of a path...
+                debug!("find_constraint_paths_from_region: new end region current={:?}", current);
+                end_regions.insert(current);
+            } else {
+                // ...but, if we did find edges, then add these to the regions yet to visit.
+                debug!("find_constraint_paths_from_region: extend next upcoming={:?}", upcoming);
+                next.extend(upcoming);
+            }
+
+        }
+
+        // Now we've visited each point, compute the final paths.
+        let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new();
+        debug!("find_constraint_paths_from_region: end_regions={:?}", end_regions);
+        for end_region in end_regions {
+            debug!("find_constraint_paths_from_region: end_region={:?}", end_region);
+
+            // Get the constraint and region that led to this end point.
+            // We can unwrap as we know if end_point was in the vector that it
+            // must also be in our previous map.
+            let (mut index, mut region) = previous.get(&end_region).unwrap();
+            debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
+
+            // Keep track of the indices.
+            let mut path: Vec<ConstraintIndex> = vec![index];
+
+            while region.is_some() && region != Some(r0) {
+                let p = previous.get(&region.unwrap()).unwrap();
+                index = p.0;
+                region = p.1;
+
+                debug!("find_constraint_paths_from_region: index={:?} region={:?}", index, region);
+                path.push(index);
+            }
+
+            // Add to our paths.
+            paths.push(path);
+        }
+
+        debug!("find_constraint_paths_from_region: paths={:?}", paths);
+        paths
+    }
+
+    /// This function will return true if a constraint is interesting and false if a constraint
+    /// is not. It is useful in filtering constraint paths to only interesting points.
+    fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool {
+        self.constraints.get(*index).filter(|constraint| {
+            debug!("constraint_is_interesting: locations={:?} constraint={:?}",
+                   constraint.locations, constraint);
+            if let Locations::Interesting(_) = constraint.locations { true } else { false }
+        }).is_some()
+    }
+
+    /// This function classifies a constraint from a location.
+    fn classify_constraint(&self, index: &ConstraintIndex,
+                           mir: &Mir<'tcx>) -> Option<(ConstraintCategory, Span)> {
+        let constraint = self.constraints.get(*index)?;
+        let span = constraint.locations.span(mir);
+        let location = constraint.locations.from_location()?;
+
+        if !self.constraint_is_interesting(index) {
+            return Some((ConstraintCategory::Boring, span));
+        }
+
+        let data = &mir[location.block];
+        let category = if location.statement_index == data.statements.len() {
+            if let Some(ref terminator) = data.terminator {
+                match terminator.kind {
+                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
+                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
+                    _ => ConstraintCategory::Other,
+                }
+            } else {
+                ConstraintCategory::Other
+            }
+        } else {
+            let statement = &data.statements[location.statement_index];
+            match statement.kind {
+                StatementKind::Assign(ref place, ref rvalue) => {
+                    if *place == Place::Local(mir::RETURN_PLACE) {
+                        ConstraintCategory::Return
+                    } else {
+                        match rvalue {
+                            Rvalue::Cast(..) => ConstraintCategory::Cast,
+                            Rvalue::Use(..) => ConstraintCategory::Assignment,
+                            _ => ConstraintCategory::Other,
+                        }
+                    }
+                },
+                _ => ConstraintCategory::Other,
+            }
+        };
+
+        Some((category, span))
+    }
+
+    /// Report an error because the universal region `fr` was required to outlive
+    /// `outlived_fr` but it is not known to do so. For example:
+    ///
+    /// ```
+    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
+    /// ```
+    ///
+    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
+    pub(super) fn report_error(
+        &self,
+        mir: &Mir<'tcx>,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        outlived_fr: RegionVid,
+        blame_span: Span,
+    ) {
+        // Obviously uncool error reporting.
+
+        let fr_name = self.to_error_region(fr);
+        let outlived_fr_name = self.to_error_region(outlived_fr);
+
+        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
+            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
+            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
+            if let Some(_error_reported) = nice.try_report() {
+                return;
+            }
+        }
+
+        let fr_string = match fr_name {
+            Some(r) => format!("free region `{}`", r),
+            None => format!("free region `{:?}`", fr),
+        };
+
+        let outlived_fr_string = match outlived_fr_name {
+            Some(r) => format!("free region `{}`", r),
+            None => format!("free region `{:?}`", outlived_fr),
+        };
+
+        let constraints = self.find_constraint_paths_from_region(fr.clone());
+        let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
+        debug!("report_error: shortest_path={:?}", path);
+
+        let mut categorized_path = path.iter().filter_map(|index| {
+            self.classify_constraint(index, mir)
+        }).collect::<Vec<(ConstraintCategory, Span)>>();
+        debug!("report_error: categorized_path={:?}", categorized_path);
+
+        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+        debug!("report_error: sorted_path={:?}", categorized_path);
+
+        if let Some((category, span)) = &categorized_path.first() {
+            let mut diag = infcx.tcx.sess.struct_span_err(
+                *span, &format!("{} requires that data must outlive {}",
+                                category, outlived_fr_string),
+            );
+
+            diag.emit();
+        } else {
+            let mut diag = infcx.tcx.sess.struct_span_err(
+                blame_span,
+                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
+            );
+
+            diag.emit();
+        }
+    }
+
+    crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
+        // Find some constraint `X: Y` where:
+        // - `fr1: X` transitively
+        // - and `Y` is live at `elem`
+        let index = self.blame_constraint(fr1, elem);
+        let region_sub = self.constraints[index].sub;
+
+        // then return why `Y` was live at `elem`
+        self.liveness_constraints.cause(region_sub, elem)
+    }
+
+    /// Tries to finds a good span to blame for the fact that `fr1`
+    /// contains `fr2`.
+    pub(super) fn blame_constraint(&self, fr1: RegionVid,
+                                   elem: impl ToElementIndex) -> ConstraintIndex {
+        // Find everything that influenced final value of `fr`.
+        let influenced_fr1 = self.dependencies(fr1);
+
+        // Try to find some outlives constraint `'X: fr2` where `'X`
+        // influenced `fr1`. Blame that.
+        //
+        // NB, this is a pretty bad choice most of the time. In
+        // particular, the connection between `'X` and `fr1` may not
+        // be obvious to the user -- not to mention the naive notion
+        // of dependencies, which doesn't account for the locations of
+        // contraints at all. But it will do for now.
+        let relevant_constraint = self.constraints
+            .iter_enumerated()
+            .filter_map(|(i, constraint)| {
+                if !self.liveness_constraints.contains(constraint.sub, elem) {
+                    None
+                } else {
+                    influenced_fr1[constraint.sup]
+                        .map(|distance| (distance, i))
+                }
+            })
+            .min() // constraining fr1 with fewer hops *ought* to be more obvious
+            .map(|(_dist, i)| i);
+
+        relevant_constraint.unwrap_or_else(|| {
+            bug!(
+                "could not find any constraint to blame for {:?}: {:?}",
+                fr1,
+                elem,
+            );
+        })
+    }
+
+    /// Finds all regions whose values `'a` may depend on in some way.
+    /// For each region, returns either `None` (does not influence
+    /// `'a`) or `Some(d)` which indicates that it influences `'a`
+    /// with distinct `d` (minimum number of edges that must be
+    /// traversed).
+    ///
+    /// Used during error reporting, extremely naive and inefficient.
+    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
+        let mut result_set = IndexVec::from_elem(None, &self.definitions);
+        let mut changed = true;
+        result_set[r0] = Some(0); // distance 0 from `r0`
+
+        while changed {
+            changed = false;
+            for constraint in &*self.constraints {
+                if let Some(n) = result_set[constraint.sup] {
+                    let m = n + 1;
+                    if result_set[constraint.sub]
+                        .map(|distance| m < distance)
+                        .unwrap_or(true)
+                    {
+                        result_set[constraint.sub] = Some(m);
+                        changed = true;
+                    }
+                }
+            }
+        }
+
+        result_set
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
index 106dd003cea..0116fbcfc88 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
@@ -44,7 +44,7 @@ impl<'this, 'tcx> dot::Labeller<'this> for RegionInferenceContext<'tcx> {
         dot::LabelText::LabelStr(format!("{:?}", n).into_cow())
     }
     fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
-        dot::LabelText::LabelStr(format!("{:?}", e.point).into_cow())
+        dot::LabelText::LabelStr(format!("{:?}", e.locations).into_cow())
     }
 }
 
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 a576dc5f7f4..09e425ff555 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -9,28 +9,28 @@
 // except according to those terms.
 
 use super::universal_regions::UniversalRegions;
-use borrow_check::nll::region_infer::values::ToElementIndex;
 use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint};
+use borrow_check::nll::type_check::Locations;
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryRegionConstraint;
-use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc::infer::region_constraints::{GenericKind, VarInfos};
 use rustc::infer::InferCtxt;
 use rustc::infer::NLLRegionVariableOrigin;
 use rustc::infer::RegionVariableOrigin;
 use rustc::mir::{
     ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
-    Mir,
+    Mir
 };
 use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
-use rustc::util::common::{self, ErrorReported};
+use rustc::util::common;
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+
 use std::rc::Rc;
-use syntax_pos::Span;
 
 mod annotation;
 mod dump_mir;
+mod error_reporting;
 mod graphviz;
 mod values;
 use self::values::{RegionValueElements, RegionValues};
@@ -154,11 +154,8 @@ pub struct TypeTest<'tcx> {
     /// The region `'x` that the type must outlive.
     pub lower_bound: RegionVid,
 
-    /// The point where the outlives relation must hold.
-    pub point: Location,
-
-    /// Where did this constraint arise?
-    pub span: Span,
+    /// Where did this constraint arise and why?
+    pub locations: Locations,
 
     /// A test which, if met by the region `'x`, proves that this type
     /// constraint is satisfied.
@@ -356,17 +353,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
     pub(super) fn add_outlives(
         &mut self,
-        span: Span,
+        locations: Locations,
         sup: RegionVid,
         sub: RegionVid,
-        point: Location,
     ) {
         assert!(self.inferred_values.is_none(), "values already inferred");
         self.constraints.push(OutlivesConstraint {
-            span,
+            locations,
             sup,
             sub,
-            point,
             next: None,
         })
     }
@@ -410,7 +405,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());
 
-        self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut());
+        self.check_universal_regions(infcx, mir, mir_def_id, outlives_requirements.as_mut());
 
         let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
 
@@ -503,12 +498,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         for type_test in &self.type_tests {
             debug!("check_type_test: {:?}", type_test);
 
-            if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) {
+            if self.eval_region_test(mir, type_test.lower_bound, &type_test.test) {
                 continue;
             }
 
             if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
-                if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
+                if self.try_promote_type_test(infcx, mir, type_test,
+                                              propagated_outlives_requirements) {
                     continue;
                 }
             }
@@ -517,9 +513,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let lower_bound_region = self.to_error_region(type_test.lower_bound);
             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(
                     region_scope_tree,
-                    type_test.span,
+                    type_test_span,
                     None,
                     type_test.generic_kind,
                     lower_bound_region,
@@ -534,8 +531,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // to report it; we could probably handle it by
                 // 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(
-                    type_test.span,
+                    type_test_span,
                     &format!("`{}` does not live long enough", type_test.generic_kind,),
                 );
             }
@@ -568,6 +566,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn try_promote_type_test<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        mir: &Mir<'tcx>,
         type_test: &TypeTest<'tcx>,
         propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
     ) -> bool {
@@ -576,8 +575,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let TypeTest {
             generic_kind,
             lower_bound,
-            point: _,
-            span,
+            locations,
             test: _,
         } = type_test;
 
@@ -601,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         propagated_outlives_requirements.push(ClosureOutlivesRequirement {
             subject,
             outlived_free_region: lower_bound_plus,
-            blame_span: *span,
+            blame_span: locations.span(mir),
         });
         true
     }
@@ -765,31 +763,30 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn eval_region_test(
         &self,
         mir: &Mir<'tcx>,
-        point: Location,
         lower_bound: RegionVid,
         test: &RegionTest,
     ) -> bool {
         debug!(
-            "eval_region_test(point={:?}, lower_bound={:?}, test={:?})",
-            point, lower_bound, test
+            "eval_region_test(lower_bound={:?}, test={:?})",
+            lower_bound, test
         );
 
         match test {
             RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
                 .iter()
-                .all(|&r| self.eval_outlives(mir, r, lower_bound, point)),
+                .all(|&r| self.eval_outlives(mir, r, lower_bound)),
 
             RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
                 .iter()
-                .any(|&r| self.eval_outlives(mir, r, lower_bound, point)),
+                .any(|&r| self.eval_outlives(mir, r, lower_bound)),
 
             RegionTest::Any(tests) => tests
                 .iter()
-                .any(|test| self.eval_region_test(mir, point, lower_bound, test)),
+                .any(|test| self.eval_region_test(mir, lower_bound, test)),
 
             RegionTest::All(tests) => tests
                 .iter()
-                .all(|test| self.eval_region_test(mir, point, lower_bound, test)),
+                .all(|test| self.eval_region_test(mir, lower_bound, test)),
         }
     }
 
@@ -799,11 +796,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         _mir: &Mir<'tcx>,
         sup_region: RegionVid,
         sub_region: RegionVid,
-        point: Location,
     ) -> bool {
         debug!(
-            "eval_outlives({:?}: {:?} @ {:?})",
-            sup_region, sub_region, point
+            "eval_outlives({:?}: {:?})",
+            sup_region, sub_region
         );
 
         let inferred_values = self
@@ -869,6 +865,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn check_universal_regions<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
     ) {
@@ -885,6 +882,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         for (fr, _) in universal_definitions {
             self.check_universal_region(
                 infcx,
+                mir,
                 mir_def_id,
                 fr,
                 &mut propagated_outlives_requirements,
@@ -903,6 +901,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn check_universal_region<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         longer_fr: RegionVid,
         propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
@@ -925,7 +924,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             );
 
             let blame_index = self.blame_constraint(longer_fr, shorter_fr);
-            let blame_span = self.constraints[blame_index].span;
+            let blame_span = self.constraints[blame_index].locations.span(mir);
 
             if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
                 // Shrink `fr` until we find a non-local region (if we do).
@@ -960,134 +959,9 @@ 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(infcx, mir_def_id, longer_fr, shorter_fr, blame_span);
+            self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, blame_span);
         }
     }
-
-    /// Report an error because the universal region `fr` was required to outlive
-    /// `outlived_fr` but it is not known to do so. For example:
-    ///
-    /// ```
-    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
-    /// ```
-    ///
-    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
-    fn report_error(
-        &self,
-        infcx: &InferCtxt<'_, '_, 'tcx>,
-        mir_def_id: DefId,
-        fr: RegionVid,
-        outlived_fr: RegionVid,
-        blame_span: Span,
-    ) {
-        // Obviously uncool error reporting.
-
-        let fr_name = self.to_error_region(fr);
-        let outlived_fr_name = self.to_error_region(outlived_fr);
-
-        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
-            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
-            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
-            if let Some(ErrorReported) = nice.try_report() {
-                return;
-            }
-        }
-
-        let fr_string = match fr_name {
-            Some(r) => format!("free region `{}`", r),
-            None => format!("free region `{:?}`", fr),
-        };
-
-        let outlived_fr_string = match outlived_fr_name {
-            Some(r) => format!("free region `{}`", r),
-            None => format!("free region `{:?}`", outlived_fr),
-        };
-
-        let mut diag = infcx.tcx.sess.struct_span_err(
-            blame_span,
-            &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
-        );
-
-        diag.emit();
-    }
-
-    crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
-        // Find some constraint `X: Y` where:
-        // - `fr1: X` transitively
-        // - and `Y` is live at `elem`
-        let index = self.blame_constraint(fr1, elem);
-        let region_sub = self.constraints[index].sub;
-
-        // then return why `Y` was live at `elem`
-        self.liveness_constraints.cause(region_sub, elem)
-    }
-
-    /// Tries to finds a good span to blame for the fact that `fr1`
-    /// contains `fr2`.
-    fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex {
-        // Find everything that influenced final value of `fr`.
-        let influenced_fr1 = self.dependencies(fr1);
-
-        // Try to find some outlives constraint `'X: fr2` where `'X`
-        // influenced `fr1`. Blame that.
-        //
-        // NB, this is a pretty bad choice most of the time. In
-        // particular, the connection between `'X` and `fr1` may not
-        // be obvious to the user -- not to mention the naive notion
-        // of dependencies, which doesn't account for the locations of
-        // contraints at all. But it will do for now.
-        let relevant_constraint = self.constraints
-            .iter_enumerated()
-            .filter_map(|(i, constraint)| {
-                if !self.liveness_constraints.contains(constraint.sub, elem) {
-                    None
-                } else {
-                    influenced_fr1[constraint.sup]
-                        .map(|distance| (distance, i))
-                }
-            })
-            .min() // constraining fr1 with fewer hops *ought* to be more obvious
-            .map(|(_dist, i)| i);
-
-        relevant_constraint.unwrap_or_else(|| {
-            bug!(
-                "could not find any constraint to blame for {:?}: {:?}",
-                fr1,
-                elem,
-            );
-        })
-    }
-
-    /// Finds all regions whose values `'a` may depend on in some way.
-    /// For each region, returns either `None` (does not influence
-    /// `'a`) or `Some(d)` which indicates that it influences `'a`
-    /// with distinct `d` (minimum number of edges that must be
-    /// traversed).
-    ///
-    /// Used during error reporting, extremely naive and inefficient.
-    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
-        let mut result_set = IndexVec::from_elem(None, &self.definitions);
-        let mut changed = true;
-        result_set[r0] = Some(0); // distance 0 from `r0`
-
-        while changed {
-            changed = false;
-            for constraint in self.constraints.iter() {
-                if let Some(n) = result_set[constraint.sup] {
-                    let m = n + 1;
-                    if result_set[constraint.sub]
-                        .map(|distance| m < distance)
-                        .unwrap_or(true)
-                    {
-                        result_set[constraint.sub] = Some(m);
-                        changed = true;
-                    }
-                }
-            }
-        }
-
-        result_set
-    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index 3100df3e8f6..27bd5042777 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -19,14 +19,12 @@ use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
 use rustc::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc::infer::{self, SubregionOrigin};
-use rustc::mir::{Location, Mir};
 use rustc::ty::subst::UnpackedKind;
 use rustc::ty::{self, TyCtxt};
-use syntax::codemap::Span;
+use syntax_pos::DUMMY_SP;
 
 crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    mir: &'a Mir<'tcx>,
     universal_regions: &'a UniversalRegions<'tcx>,
     location_table: &'a LocationTable,
     region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
@@ -41,7 +39,6 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     crate fn new(
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
-        mir: &'a Mir<'tcx>,
         universal_regions: &'a UniversalRegions<'tcx>,
         location_table: &'a LocationTable,
         region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
@@ -54,7 +51,6 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     ) -> Self {
         Self {
             tcx,
-            mir,
             universal_regions,
             location_table,
             region_bound_pairs,
@@ -91,8 +87,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
         // will start to fail.
         let ty::OutlivesPredicate(k1, r2) =
             query_constraint.no_late_bound_regions().unwrap_or_else(|| {
-                span_bug!(
-                    self.span(),
+                bug!(
                     "query_constraint {:?} contained bound regions",
                     query_constraint,
                 );
@@ -125,7 +120,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
             UnpackedKind::Type(t1) => {
                 // we don't actually use this for anything, but
                 // the `TypeOutlives` code needs an origin.
-                let origin = infer::RelateParamBound(self.span(), t1);
+                let origin = infer::RelateParamBound(DUMMY_SP, t1);
 
                 TypeOutlives::new(
                     &mut *self,
@@ -146,15 +141,12 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     ) -> TypeTest<'tcx> {
         let lower_bound = self.to_region_vid(region);
 
-        let point = self.locations.at_location().unwrap_or(Location::START);
-
         let test = self.verify_bound_to_region_test(&bound);
 
         TypeTest {
             generic_kind,
             lower_bound,
-            point,
-            span: self.span(),
+            locations: self.locations,
             test,
         }
     }
@@ -189,21 +181,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
         self.universal_regions.to_region_vid(r)
     }
 
-    fn span(&self) -> Span {
-        self.mir
-            .source_info(self.locations.from_location().unwrap_or(Location::START))
-            .span
-    }
-
     fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
-        let span = self.span();
-        let point = self.locations.at_location().unwrap_or(Location::START);
-
         self.outlives_constraints.push(OutlivesConstraint {
-            span,
+            locations: self.locations,
             sub,
             sup,
-            point,
             next: None,
         });
     }
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
index f27de92c621..d84dcc56782 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
@@ -199,7 +199,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
         });
 
         if let Some(data) = &drop_data.region_constraint_data {
-            self.cx.push_region_constraints(location.at_self(), data);
+            self.cx.push_region_constraints(location.boring(), data);
         }
 
         drop_data.dropck_result.report_overflows(
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 611050a4060..e3d20d9a8db 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -147,7 +147,6 @@ fn type_check_internal<'gcx, 'tcx>(
         region_bound_pairs,
         implicit_region_bound,
         borrowck_context,
-        mir,
     );
     let errors_reported = {
         let mut verifier = TypeVerifier::new(&mut checker, mir);
@@ -288,7 +287,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                         tcx.predicates_of(def_id).instantiate(tcx, substs);
                     type_checker.normalize_and_prove_instantiated_predicates(
                         instantiated_predicates,
-                        location,
+                        location.boring(),
                     );
                 }
 
@@ -313,10 +312,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
 
         debug!("sanitize_constant: expected_ty={:?}", expected_ty);
 
-        if let Err(terr) = self
-            .cx
-            .eq_types(expected_ty, constant.ty, location.at_self())
-        {
+        if let Err(terr) = self.cx.eq_types(expected_ty, constant.ty, location.boring()) {
             span_mirbug!(
                 self,
                 constant,
@@ -346,7 +342,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 let sty = self.sanitize_type(place, sty);
                 let ty = self.tcx().type_of(def_id);
                 let ty = self.cx.normalize(ty, location);
-                if let Err(terr) = self.cx.eq_types(ty, sty, location.at_self()) {
+                if let Err(terr) = self.cx.eq_types(ty, sty, location.boring()) {
                     span_mirbug!(
                         self,
                         place,
@@ -390,7 +386,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
             // fully apply: in effect, the rule is that if a value of some type could implement
             // Copy, then it must.
-            self.cx.prove_trait_ref(trait_ref, location);
+            self.cx.prove_trait_ref(trait_ref, location.interesting());
         }
         place_ty
     }
@@ -489,7 +485,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             ProjectionElem::Field(field, fty) => {
                 let fty = self.sanitize_type(place, fty);
                 match self.field_ty(place, base, field, location) {
-                    Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.at_self()) {
+                    Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.boring()) {
                         span_mirbug!(
                             self,
                             place,
@@ -600,7 +596,6 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     constraints: MirTypeckRegionConstraints<'tcx>,
     borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
-    mir: &'a Mir<'tcx>,
 }
 
 struct BorrowCheckContext<'a, 'tcx: 'a> {
@@ -631,7 +626,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
 /// required to hold. Normally, this is at a particular point which
 /// created the obligation, but for constraints that the user gave, we
 /// want the constraint to hold at all points.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 pub enum Locations {
     /// Indicates that a type constraint should always be true. This
     /// is particularly important in the new borrowck analysis for
@@ -666,32 +661,41 @@ pub enum Locations {
     /// assigned to `x` are of `'static` lifetime.
     All,
 
-    Pair {
-        /// The location in the MIR that generated these constraints.
-        /// This is intended for error reporting and diagnosis; the
-        /// constraints may *take effect* at a distinct spot.
-        from_location: Location,
-
-        /// The constraints must be met at this location. In terms of the
-        /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
-        /// is the `P` value.
-        at_location: Location,
-    },
+    /// A "boring" constraint (caused by the given location) is one that
+    /// the user probably doesn't want to see described in diagnostics,
+    /// because it is kind of an artifact of the type system setup.
+    ///
+    /// Example: `x = Foo { field: y }` technically creates
+    /// intermediate regions representing the "type of `Foo { field: y
+    /// }`", and data flows from `y` into those variables, but they
+    /// are not very interesting. The assignment into `x` on the other
+    /// hand might be.
+    Boring(Location),
+
+    /// An *important* outlives constraint (caused by the given
+    /// location) is one that would be useful to highlight in
+    /// diagnostics, because it represents a point where references
+    /// flow from one spot to another (e.g., `x = y`)
+    Interesting(Location),
 }
 
 impl Locations {
     pub fn from_location(&self) -> Option<Location> {
         match self {
             Locations::All => None,
-            Locations::Pair { from_location, .. } => Some(*from_location),
+            Locations::Boring(from_location) | Locations::Interesting(from_location) => {
+                Some(*from_location)
+            }
         }
     }
 
-    pub fn at_location(&self) -> Option<Location> {
-        match self {
-            Locations::All => None,
-            Locations::Pair { at_location, .. } => Some(*at_location),
-        }
+    /// Gets a span representing the location.
+    pub fn span(&self, mir: &Mir<'_>) -> Span {
+        let span_location = match self {
+            Locations::All => Location::START,
+            Locations::Boring(l) | Locations::Interesting(l) => *l,
+        };
+        mir.source_info(span_location).span
     }
 }
 
@@ -703,7 +707,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
         implicit_region_bound: Option<ty::Region<'tcx>>,
         borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
-        mir: &'a Mir<'tcx>,
     ) -> Self {
         TypeChecker {
             infcx,
@@ -713,7 +716,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             region_bound_pairs,
             implicit_region_bound,
             borrowck_context,
-            mir,
             reported_errors: FxHashSet(),
             constraints: MirTypeckRegionConstraints::default(),
         }
@@ -756,7 +758,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         if let Some(borrowck_context) = &mut self.borrowck_context {
             constraint_conversion::ConstraintConversion::new(
                 self.infcx.tcx,
-                self.mir,
                 borrowck_context.universal_regions,
                 borrowck_context.location_table,
                 self.region_bound_pairs,
@@ -797,11 +798,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         let tcx = self.tcx();
         match stmt.kind {
             StatementKind::Assign(ref place, ref rv) => {
+                // Assignments to temporaries are not "interesting";
+                // they are not caused by the user, but rather artifacts
+                // of lowering. Assignments to other sorts of places *are* interesting
+                // though.
+                let is_temp = if let Place::Local(l) = place {
+                    !mir.local_decls[*l].is_user_variable.is_some()
+                } else {
+                    false
+                };
+
+                let locations = if is_temp { location.boring() } else { location.interesting() };
+
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
-                if let Err(terr) =
-                    self.sub_types(rv_ty, place_ty, location.at_successor_within_block())
-                {
+                if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
                     span_mirbug!(
                         self,
                         stmt,
@@ -816,7 +827,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     def_id: tcx.lang_items().sized_trait().unwrap(),
                     substs: tcx.mk_substs_trait(place_ty, &[]),
                 };
-                self.prove_trait_ref(trait_ref, location);
+                self.prove_trait_ref(trait_ref, location.interesting());
             }
             StatementKind::SetDiscriminant {
                 ref place,
@@ -897,16 +908,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             TerminatorKind::DropAndReplace {
                 ref location,
                 ref value,
-                target,
-                unwind,
+                target: _,
+                unwind: _,
             } => {
                 let place_ty = location.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = value.ty(mir, tcx);
 
-                let locations = Locations::Pair {
-                    from_location: term_location,
-                    at_location: target.start_location(),
-                };
+                let locations = term_location.interesting();
                 if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
                     span_mirbug!(
                         self,
@@ -917,26 +925,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         terr
                     );
                 }
-
-                // Subtle: this assignment occurs at the start of
-                // *both* blocks, so we need to ensure that it holds
-                // at both locations.
-                if let Some(unwind) = unwind {
-                    let locations = Locations::Pair {
-                        from_location: term_location,
-                        at_location: unwind.start_location(),
-                    };
-                    if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
-                        span_mirbug!(
-                            self,
-                            term,
-                            "bad DropAndReplace ({:?} = {:?}): {:?}",
-                            place_ty,
-                            rv_ty,
-                            terr
-                        );
-                    }
-                }
             }
             TerminatorKind::SwitchInt {
                 ref discr,
@@ -944,7 +932,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 ..
             } => {
                 let discr_ty = discr.ty(mir, tcx);
-                if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.at_self()) {
+                if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.boring()) {
                     span_mirbug!(
                         self,
                         term,
@@ -984,7 +972,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                 self.prove_predicates(
                     sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
-                    term_location,
+                    term_location.boring(),
                 );
 
                 // The ordinary liveness rules will ensure that all
@@ -1026,7 +1014,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 match mir.yield_ty {
                     None => span_mirbug!(self, term, "yield in non-generator"),
                     Some(ty) => {
-                        if let Err(terr) = self.sub_types(value_ty, ty, term_location.at_self()) {
+                        if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting())
+                        {
                             span_mirbug!(
                                 self,
                                 term,
@@ -1052,12 +1041,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     ) {
         let tcx = self.tcx();
         match *destination {
-            Some((ref dest, target_block)) => {
+            Some((ref dest, _target_block)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
-                let locations = Locations::Pair {
-                    from_location: term_location,
-                    at_location: target_block.start_location(),
-                };
+                let locations = term_location.interesting();
                 if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
                     span_mirbug!(
                         self,
@@ -1092,7 +1078,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
         for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
             let op_arg_ty = op_arg.ty(mir, self.tcx());
-            if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.at_self()) {
+            if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.interesting()) {
                 span_mirbug!(
                     self,
                     term,
@@ -1320,7 +1306,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     substs: tcx.mk_substs_trait(operand_ty, &[]),
                 };
 
-                self.prove_trait_ref(trait_ref, location);
+                self.prove_trait_ref(trait_ref, location.interesting());
             },
 
             Rvalue::NullaryOp(_, ty) => {
@@ -1329,7 +1315,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     substs: tcx.mk_substs_trait(ty, &[]),
                 };
 
-                self.prove_trait_ref(trait_ref, location);
+                self.prove_trait_ref(trait_ref, location.interesting());
             }
 
             Rvalue::Cast(cast_kind, op, ty) => match cast_kind {
@@ -1345,7 +1331,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                     let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
 
-                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
+                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) {
                         span_mirbug!(
                             self,
                             rvalue,
@@ -1366,7 +1352,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     };
                     let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
 
-                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
+                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) {
                         span_mirbug!(
                             self,
                             rvalue,
@@ -1390,7 +1376,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                     let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
 
-                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
+                    if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) {
                         span_mirbug!(
                             self,
                             rvalue,
@@ -1409,7 +1395,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty.into()]),
                     };
 
-                    self.prove_trait_ref(trait_ref, location);
+                    self.prove_trait_ref(trait_ref, location.interesting());
                 }
 
                 CastKind::Misc => {}
@@ -1458,7 +1444,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 }
             };
             let operand_ty = operand.ty(mir, tcx);
-            if let Err(terr) = self.sub_types(operand_ty, field_ty, location.at_self()) {
+
+            if let Err(terr) = self.sub_types(operand_ty, field_ty, location.boring()) {
                 span_mirbug!(
                     self,
                     rvalue,
@@ -1519,8 +1506,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         *substs,
                     );
 
+                    // Hmm, are these constraints *really* boring?
                     self.push_region_constraints(
-                        location.at_self(),
+                        location.boring(),
                         &closure_constraints,
                     );
                 }
@@ -1535,53 +1523,56 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
         };
 
-        self.normalize_and_prove_instantiated_predicates(instantiated_predicates, location);
+        self.normalize_and_prove_instantiated_predicates(
+            instantiated_predicates,
+            location.boring(),
+        );
     }
 
-    fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
+    fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations) {
         self.prove_predicates(
             Some(ty::Predicate::Trait(
                 trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
             )),
-            location,
+            locations,
         );
     }
 
     fn normalize_and_prove_instantiated_predicates(
         &mut self,
         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
-        location: Location,
+        locations: Locations,
     ) {
         for predicate in instantiated_predicates.predicates {
-            let predicate = self.normalize(predicate, location);
-            self.prove_predicate(predicate, location);
+            let predicate = self.normalize(predicate, locations);
+            self.prove_predicate(predicate, locations);
         }
     }
 
     fn prove_predicates(
         &mut self,
         predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>,
-        location: Location,
+        locations: Locations,
     ) {
         for predicate in predicates {
             debug!(
-                "prove_predicates(predicate={:?}, location={:?})",
-                predicate, location,
+                "prove_predicates(predicate={:?}, locations={:?})",
+                predicate, locations,
             );
 
-            self.prove_predicate(predicate, location);
+            self.prove_predicate(predicate, locations);
         }
     }
 
-    fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, location: Location) {
+    fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, locations: Locations) {
         debug!(
             "prove_predicate(predicate={:?}, location={:?})",
-            predicate, location,
+            predicate, locations,
         );
 
         let param_env = self.param_env;
         self.fully_perform_op(
-            location.at_self(),
+            locations,
             param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
         ).unwrap_or_else(|NoSolution| {
             span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
@@ -1614,7 +1605,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn normalize<T>(&mut self, value: T, location: impl ToLocations) -> T
+    fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
     where
         T: type_op::normalize::Normalizable<'gcx, 'tcx> + Copy,
     {
@@ -1667,52 +1658,38 @@ impl MirPass for TypeckMir {
     }
 }
 
-trait AtLocation {
-    /// Creates a `Locations` where `self` is both the from-location
-    /// and the at-location. This means that any required region
-    /// relationships must hold upon entering the statement/terminator
-    /// indicated by `self`. This is typically used when processing
-    /// "inputs" to the given location.
-    fn at_self(self) -> Locations;
-
-    /// Creates a `Locations` where `self` is the from-location and
-    /// its successor within the block is the at-location. This means
-    /// that any required region relationships must hold only upon
-    /// **exiting** the statement/terminator indicated by `self`. This
-    /// is for example used when you have a `place = rv` statement: it
-    /// indicates that the `typeof(rv) <: typeof(place)` as of the
-    /// **next** statement.
-    fn at_successor_within_block(self) -> Locations;
+pub trait AtLocation {
+    /// Indicates a "boring" constraint that the user probably
+    /// woudln't want to see highlights.
+    fn boring(self) -> Locations;
+
+    /// Indicates an "interesting" edge, which is of significance only
+    /// for diagnostics.
+    fn interesting(self) -> Locations;
 }
 
 impl AtLocation for Location {
-    fn at_self(self) -> Locations {
-        Locations::Pair {
-            from_location: self,
-            at_location: self,
-        }
+    fn boring(self) -> Locations {
+        Locations::Boring(self)
     }
 
-    fn at_successor_within_block(self) -> Locations {
-        Locations::Pair {
-            from_location: self,
-            at_location: self.successor_within_block(),
-        }
+    fn interesting(self) -> Locations {
+        Locations::Interesting(self)
     }
 }
 
-trait ToLocations: fmt::Debug + Copy {
+trait NormalizeLocation: fmt::Debug + Copy {
     fn to_locations(self) -> Locations;
 }
 
-impl ToLocations for Locations {
+impl NormalizeLocation for Locations {
     fn to_locations(self) -> Locations {
         self
     }
 }
 
-impl ToLocations for Location {
+impl NormalizeLocation for Location {
     fn to_locations(self) -> Locations {
-        self.at_self()
+        self.boring()
     }
 }
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
index 84bfd6ea4f2..5a71e75d4b2 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
@@ -31,7 +31,7 @@ fn case1() {
     foo(cell, |cell_a, cell_x| {
         //~^ WARNING not reporting region error due to nll
         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-        //~^ ERROR does not outlive free region
+        //~^ ERROR argument requires that data must outlive free region
     })
 }
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index ac4efecc8ac..656c1b46a3c 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -4,11 +4,11 @@ warning: not reporting region error due to nll
 LL |     foo(cell, |cell_a, cell_x| {
    |     ^^^
 
-error: free region `ReFree(DefId(0/1:12 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]), BrAnon(1))` does not outlive free region `'_#1r`
-  --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:9
+error: argument requires that data must outlive free region `'_#1r`
+  --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20
    |
 LL |         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-   |         ^^^^^^
+   |                    ^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15
@@ -17,7 +17,7 @@ LL |       foo(cell, |cell_a, cell_x| {
    |  _______________^
 LL | |         //~^ WARNING not reporting region error due to nll
 LL | |         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |     })
    | |_____^
    |
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
index df715c52921..b25b0e25df2 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
@@ -43,7 +43,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
 #[rustc_regions]
 fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-        //~^ ERROR does not outlive free region
+        //~^ ERROR argument requires that data must outlive free region
 
         // Only works if 'x: 'y:
         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index 122e393f97a..40f215619c6 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -9,7 +9,7 @@ note: External requirements
    |
 LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
@@ -23,24 +23,23 @@ LL | |     });
    = note: number of external vids: 2
    = note: where '_#1r: '_#0r
 
-error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic`
-  --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47
+error: argument requires that data must outlive free region `ReStatic`
+  --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-   |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | /     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
 LL | |     });
-   | |_____^
+   | |______^
 
 note: No external requirements
   --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1
    |
 LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
 LL | |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |
 ...  |
 LL | |     });
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
index fdbb312572f..db9951bcc0f 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
@@ -46,7 +46,7 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
 #[rustc_regions]
 fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-        //~^ ERROR does not outlive free region
+        //~^ ERROR argument requires that data must outlive free region
         // Only works if 'x: 'y:
         demand_y(x, y, x.get())
         //~^ WARNING not reporting region error due to nll
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 8cdbc264581..d89ff028a50 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -9,7 +9,7 @@ note: External requirements
    |
 LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
    |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARNING not reporting region error due to nll
@@ -23,24 +23,23 @@ LL | |     });
    = note: number of external vids: 3
    = note: where '_#1r: '_#0r
 
-error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic`
-  --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47
+error: argument requires that data must outlive free region `ReStatic`
+  --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-   |  _______________________________________________^
-LL | |         //~^ ERROR does not outlive free region
+LL | /     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARNING not reporting region error due to nll
 LL | |     });
-   | |_____^
+   | |______^
 
 note: No external requirements
   --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1
    |
 LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
 LL | |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-LL | |         //~^ ERROR does not outlive free region
+LL | |         //~^ ERROR argument requires that data must outlive free region
 LL | |         // Only works if 'x: 'y:
 ...  |
 LL | |     });
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
index 7699d101734..316268e7e72 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
@@ -46,7 +46,7 @@ fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
         // Only works if 'x: 'y:
         demand_y(x, y, x.get())
         //~^ WARN not reporting region error due to nll
-        //~| ERROR does not outlive free region
+        //~| ERROR argument requires that data must outlive free region
     });
 }
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index 8b6cd2ea432..74c0576e03b 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -4,11 +4,11 @@ warning: not reporting region error due to nll
 LL |         demand_y(x, y, x.get())
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(4))` does not outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))`
-  --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:18
+error: argument requires that data must outlive free region `ReFree(DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]), BrAnon(2))`
+  --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
    |
 LL |         demand_y(x, y, x.get())
-   |                  ^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47
@@ -18,7 +18,7 @@ LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |         //~^ WARN not reporting region error due to nll
-LL | |         //~| ERROR does not outlive free region
+LL | |         //~| ERROR argument requires that data must outlive free region
 LL | |     });
    | |_____^
    |
diff --git a/src/test/ui/nll/issue-50716.rs b/src/test/ui/nll/issue-50716.rs
index 310600aaf9a..a41af168c3e 100644
--- a/src/test/ui/nll/issue-50716.rs
+++ b/src/test/ui/nll/issue-50716.rs
@@ -22,7 +22,7 @@ where
     for<'b> &'b T: A,
     <&'static T as A>::X: Sized
 {
-    let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static`
+    let _x = *s; //~ ERROR assignment requires that data must outlive free region `'static`
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr
index 20b03d648d9..de69f8cfbcb 100644
--- a/src/test/ui/nll/issue-50716.stderr
+++ b/src/test/ui/nll/issue-50716.stderr
@@ -1,7 +1,7 @@
-error: free region `'a` does not outlive free region `'static`
+error: assignment requires that data must outlive free region `'static`
   --> $DIR/issue-50716.rs:25:14
    |
-LL |     let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static`
+LL |     let _x = *s; //~ ERROR assignment requires that data must outlive free region `'static`
    |              ^^
 
 error: aborting due to previous error
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
index 77024c4119f..3832be6288a 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
@@ -55,7 +55,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR does not outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -67,7 +67,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR does not outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -89,7 +89,7 @@ where
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
     //~| ERROR the parameter type `T` may not live long enough
-    //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index e1218830dbb..898c995e09b 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -40,11 +40,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
 
-error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
-  --> $DIR/projection-one-region-closure.rs:55:20
+error: argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
+  --> $DIR/projection-one-region-closure.rs:55:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-closure.rs:51:1
@@ -54,7 +54,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -88,11 +88,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-closure.rs:67:20
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-closure.rs:67:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-closure.rs:62:1
@@ -102,7 +102,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -137,11 +137,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |
    = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-closure.rs:89:20
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-closure.rs:89:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-closure.rs:74:1
@@ -151,7 +151,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
 ...  |
-LL | |     //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
index fb1009c9cc8..da76193459b 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
@@ -46,7 +46,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -57,7 +57,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
@@ -78,7 +78,7 @@ where
 
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 76554e29f62..be11c6249f0 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -31,11 +31,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 3
    = note: where '_#1r: '_#2r
 
-error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
-  --> $DIR/projection-one-region-trait-bound-closure.rs:47:20
+error: argument requires that data must outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:47:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:43:1
@@ -45,7 +45,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -70,11 +70,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-trait-bound-closure.rs:58:20
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:58:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:53:1
@@ -84,7 +84,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
@@ -110,11 +110,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
 
-error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
-  --> $DIR/projection-one-region-trait-bound-closure.rs:79:20
+error: argument requires that data must outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:79:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:64:1
@@ -124,7 +124,7 @@ LL | | where
 LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
index 5307d0880d4..5e481a9626f 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
@@ -107,7 +107,7 @@ where
 {
     with_signature(cell, t, |cell, t| require(cell, t));
     //~^ WARNING not reporting region error due to nll
-    //~| ERROR does not outlive free region
+    //~| ERROR argument requires that data must outlive free region
 }
 
 #[rustc_regions]
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index c7f45692960..546384e8545 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -239,11 +239,11 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: number of external vids: 3
    = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
 
-error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
-  --> $DIR/projection-two-region-trait-bound-closure.rs:108:20
+error: argument requires that data must outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))`
+  --> $DIR/projection-two-region-trait-bound-closure.rs:108:5
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                    ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: No external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:104:1
@@ -253,7 +253,7 @@ LL | | where
 LL | |     T: Anything<'b, 'b>,
 LL | | {
 ...  |
-LL | |     //~| ERROR does not outlive free region
+LL | |     //~| ERROR argument requires that data must outlive free region
 LL | | }
    | |_^
    |
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
index cdc0c78e694..49f9044b19b 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
@@ -22,15 +22,11 @@ warning: not reporting region error due to nll
 LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: free region `` does not outlive free region `'static`
-  --> $DIR/dyn-trait-underscore.rs:16:52
+error: cast requires that data must outlive free region `'static`
+  --> $DIR/dyn-trait-underscore.rs:18:5
    |
-LL |   fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
-   |  ____________________________________________________^
-LL | |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
-LL | |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
-LL | | }
-   | |_^
+LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error