about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/util/ppaux.rs51
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs343
-rw-r--r--src/librustc_mir/borrow_check/mod.rs3
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs13
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs8
-rw-r--r--src/test/ui/issues/issue-30438-c.nll.stderr15
-rw-r--r--src/test/ui/nll/borrowed-universal-error-2.stderr15
-rw-r--r--src/test/ui/nll/issue-52534-1.rs33
-rw-r--r--src/test/ui/nll/issue-52534-1.stderr59
-rw-r--r--src/test/ui/nll/issue-52534.rs22
-rw-r--r--src/test/ui/nll/issue-52534.stderr13
-rw-r--r--src/test/ui/regions/regions-nested-fns-2.nll.stderr8
-rw-r--r--src/test/ui/regions/regions-nested-fns.nll.stderr8
13 files changed, 438 insertions, 153 deletions
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 9a1add26bb0..cae8e96acfc 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -34,7 +34,13 @@ use hir;
 thread_local! {
     /// Mechanism for highlighting of specific regions for display in NLL region inference errors.
     /// Contains region to highlight and counter for number to use when highlighting.
-    static HIGHLIGHT_REGION: Cell<Option<(RegionVid, usize)>> = Cell::new(None)
+    static HIGHLIGHT_REGION_FOR_REGIONVID: Cell<Option<(RegionVid, usize)>> = Cell::new(None)
+}
+
+thread_local! {
+    /// Mechanism for highlighting of specific regions for display in NLL's 'borrow does not live
+    /// long enough' errors. Contains a region to highlight and a counter to use.
+    static HIGHLIGHT_REGION_FOR_REGION: Cell<Option<(ty::BoundRegion, usize)>> = Cell::new(None)
 }
 
 macro_rules! gen_display_debug_body {
@@ -564,12 +570,34 @@ pub fn parameterized<F: fmt::Write>(f: &mut F,
     PrintContext::new().parameterized(f, substs, did, projections)
 }
 
-fn get_highlight_region() -> Option<(RegionVid, usize)> {
-    HIGHLIGHT_REGION.with(|hr| hr.get())
+fn get_highlight_region_for_regionvid() -> Option<(RegionVid, usize)> {
+    HIGHLIGHT_REGION_FOR_REGIONVID.with(|hr| hr.get())
 }
 
-pub fn with_highlight_region<R>(r: RegionVid, counter: usize, op: impl FnOnce() -> R) -> R {
-    HIGHLIGHT_REGION.with(|hr| {
+pub fn with_highlight_region_for_regionvid<R>(
+    r: RegionVid,
+    counter: usize,
+    op: impl FnOnce() -> R
+) -> R {
+    HIGHLIGHT_REGION_FOR_REGIONVID.with(|hr| {
+        assert_eq!(hr.get(), None);
+        hr.set(Some((r, counter)));
+        let r = op();
+        hr.set(None);
+        r
+    })
+}
+
+fn get_highlight_region_for_region() -> Option<(ty::BoundRegion, usize)> {
+    HIGHLIGHT_REGION_FOR_REGION.with(|hr| hr.get())
+}
+
+pub fn with_highlight_region_for_region<R>(
+    r: ty::BoundRegion,
+    counter: usize,
+    op: impl Fn() -> R
+) -> R {
+    HIGHLIGHT_REGION_FOR_REGION.with(|hr| {
         assert_eq!(hr.get(), None);
         hr.set(Some((r, counter)));
         let r = op();
@@ -726,6 +754,15 @@ define_print! {
                 return self.print_debug(f, cx);
             }
 
+            if let Some((region, counter)) = get_highlight_region_for_region() {
+                if *self == region {
+                    return match *self {
+                        BrNamed(_, name) => write!(f, "{}", name),
+                        BrAnon(_) | BrFresh(_) | BrEnv => write!(f, "'{}", counter)
+                    };
+                }
+            }
+
             match *self {
                 BrNamed(_, name) => write!(f, "{}", name),
                 BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
@@ -748,7 +785,7 @@ define_print! {
 define_print! {
     () ty::RegionKind, (self, f, cx) {
         display {
-            if cx.is_verbose || get_highlight_region().is_some() {
+            if cx.is_verbose || get_highlight_region_for_regionvid().is_some() {
                 return self.print_debug(f, cx);
             }
 
@@ -923,7 +960,7 @@ impl fmt::Debug for ty::FloatVid {
 
 impl fmt::Debug for ty::RegionVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if let Some((region, counter)) = get_highlight_region() {
+        if let Some((region, counter)) = get_highlight_region_for_regionvid() {
             debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter);
             return if *self == region {
                 write!(f, "'{:?}", counter)
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 9b148eedd71..600d052cafb 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -13,16 +13,16 @@ use borrow_check::prefixes::IsPrefixOf;
 use borrow_check::nll::explain_borrow::BorrowExplanation;
 use rustc::middle::region::ScopeTree;
 use rustc::mir::{
-    BindingForm, BorrowKind, ClearCrossCrate, Field, FakeReadCause, Local,
-    LocalDecl, LocalKind, Location, Operand, Place,
-    ProjectionElem, Rvalue, Statement, StatementKind,
-    VarBindingForm,
+    AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local,
+    LocalDecl, LocalKind, Location, Operand, Place, ProjectionElem, Rvalue, Statement,
+    StatementKind, VarBindingForm,
 };
+use rustc::hir::def_id::DefId;
 use rustc::ty;
-use rustc::hir;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc::util::ppaux::with_highlight_region_for_region;
 use syntax_pos::Span;
 
 use super::borrow_set::BorrowData;
@@ -462,7 +462,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             }
         }
 
-        let mut err = match &self.describe_place(&borrow.borrowed_place) {
+        let err = match &self.describe_place(&borrow.borrowed_place) {
             Some(_) if self.is_place_thread_local(root_place) =>
                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span),
             Some(name) => self.report_local_value_does_not_live_long_enough(
@@ -471,7 +471,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 &scope_tree,
                 &borrow,
                 drop_span,
-                borrow_span,
+                borrow_spans,
                 kind.map(|k| (k, place_span.0)),
             ),
             None => self.report_temporary_value_does_not_live_long_enough(
@@ -479,12 +479,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 &scope_tree,
                 &borrow,
                 drop_span,
+                borrow_spans,
                 proper_span,
             ),
         };
 
-        borrow_spans.args_span_label(&mut err, "value captured here");
-
         err.buffer(&mut self.errors_buffer);
     }
 
@@ -495,16 +494,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         scope_tree: &Lrc<ScopeTree>,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
-        borrow_span: Span,
+        borrow_spans: UseSpans,
         kind_place: Option<(WriteKind, &Place<'tcx>)>,
     ) -> DiagnosticBuilder<'cx> {
         debug!(
             "report_local_value_does_not_live_long_enough(\
              {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
              )",
-            context, name, scope_tree, borrow, drop_span, borrow_span
+            context, name, scope_tree, borrow, drop_span, borrow_spans
         );
 
+        let borrow_span = borrow_spans.var_or_use();
         let mut err = self.infcx.tcx.path_does_not_live_long_enough(
             borrow_span,
             &format!("`{}`", name),
@@ -512,46 +512,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         );
 
         let explanation = self.explain_why_borrow_contains_point(context, borrow, kind_place);
-        if let Some((
-            arg_name,
-            arg_span,
-            return_name,
-            return_span,
-        )) = self.find_name_and_ty_of_values() {
-            err.span_label(
-                arg_span,
-                format!("has lifetime `{}`", arg_name)
-            );
-
-            err.span_label(
-                return_span,
-                format!(
-                    "{}has lifetime `{}`",
-                    if arg_name == return_name { "also " } else { "" },
-                    return_name
-                )
-            );
+        if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
+            let region_name = annotation.emit(&mut err);
 
             err.span_label(
                 borrow_span,
-                format!("`{}` would have to be valid for `{}`", name, return_name),
-            );
-
-            err.span_label(
-                drop_span,
-                format!("but `{}` dropped here while still borrowed", name),
+                format!("`{}` would have to be valid for `{}`", name, region_name)
             );
+            err.span_label(drop_span, format!("but `{}` dropped here while still borrowed", name));
 
             if let BorrowExplanation::MustBeValidFor(..) = explanation { } else {
                 explanation.emit(self.infcx.tcx, &mut err);
             }
         } else {
             err.span_label(borrow_span, "borrowed value does not live long enough");
+            err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
 
-            err.span_label(
-                drop_span,
-                format!("`{}` dropped here while still borrowed", name),
-            );
+            borrow_spans.args_span_label(&mut err, "value captured here");
 
             explanation.emit(self.infcx.tcx, &mut err);
         }
@@ -576,19 +553,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.var_or_use();
 
-        let mut err = self.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir);
+        let mut err = self.infcx.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir);
 
         let (what_was_dropped, dropped_ty) = {
             let desc = match self.describe_place(place) {
                 Some(name) => format!("`{}`", name.as_str()),
                 None => format!("temporary value"),
             };
-            let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
+            let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
             (desc, ty)
         };
 
         let label = match dropped_ty.sty {
-            ty::Adt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() => {
+            ty::Adt(adt, _) if adt.has_dtor(self.infcx.tcx) && !adt.is_box() => {
                 match self.describe_place(&borrow.borrowed_place) {
                     Some(borrowed) =>
                         format!("here, drop of {D} needs exclusive access to `{B}`, \
@@ -615,7 +592,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             _ => {},
         }
 
-        explanation.emit(self.tcx, &mut err);
+        explanation.emit(self.infcx.tcx, &mut err);
 
         err.buffer(&mut self.errors_buffer);
     }
@@ -651,6 +628,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         scope_tree: &Lrc<ScopeTree>,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
+        borrow_spans: UseSpans,
         proper_span: Span,
     ) -> DiagnosticBuilder<'cx> {
         debug!(
@@ -678,67 +656,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         }
         explanation.emit(self.infcx.tcx, &mut err);
 
-        err
-    }
-
-    fn find_name_and_ty_of_values(
-        &self,
-    ) -> Option<(String, Span, String, Span)> {
-        let mir_node_id = self.infcx.tcx.hir.as_local_node_id(self.mir_def_id)?;
-        let fn_decl = self.infcx.tcx.hir.fn_decl(mir_node_id)?;
-
-        // If there is one argument and this error is being reported, that means
-        // that the lifetime of the borrow could not be made to match the single
-        // argument's lifetime. We can highlight it.
-        //
-        // If there is more than one argument and this error is being reported, that
-        // means there must be a self parameter - as otherwise there would be an error
-        // from lifetime elision and not this. So we highlight the self parameter.
-        let arg = fn_decl.inputs
-            .first()
-            .and_then(|ty| {
-                if let hir::TyKind::Rptr(
-                    hir::Lifetime { name, span, ..  }, ..
-                ) = ty.node {
-                    Some((name, span))
-                } else {
-                    None
-                }
-            });
-
-        let ret = if let hir::FunctionRetTy::Return(ret_ty) = &fn_decl.output {
-            if let hir::Ty {
-                node: hir::TyKind::Rptr(hir::Lifetime { name, span, ..  }, ..),
-                ..
-            } = ret_ty.clone().into_inner() {
-                Some((name, span))
-            } else {
-                None
-            }
-        } else {
-            None
-        };
-
-        let (arg_name, arg_span) = arg?;
-        let (return_name, return_span) = ret?;
-
-        let lifetimes_match = arg_name == return_name;
-
-        let arg_name = if arg_name.is_elided() {
-            "'0".to_string()
-        } else {
-            format!("{}", arg_name.ident())
-        };
-
-        let return_name = if return_name.is_elided() && lifetimes_match {
-            "'0".to_string()
-        } else if return_name.is_elided() {
-            "'1".to_string()
-        } else {
-            format!("{}", return_name.ident())
-        };
+        borrow_spans.args_span_label(&mut err, "value captured here");
 
-        Some((arg_name, arg_span, return_name, return_span))
+        err
     }
 
     fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveOutIndex> {
@@ -1222,6 +1142,220 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             None
         }
     }
+
+    /// Annotate argument and return type of function and closure with (synthesized) lifetime for
+    /// borrow of local value that does not live long enough.
+    fn annotate_argument_and_return_for_borrow(
+        &self,
+        borrow: &BorrowData<'tcx>,
+    ) -> Option<AnnotatedBorrowFnSignature> {
+        // There are two cases that need handled: when a closure is involved and
+        // when a closure is not involved.
+        let location = borrow.reserve_location;
+        let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
+
+        match self.mir[location.block].statements.get(location.statement_index) {
+            // When a closure is involved, we expect the reserve location to be an assignment
+            // to a temporary local, which will be followed by a closure.
+            Some(&Statement {
+                kind: StatementKind::Assign(Place::Local(local), _),
+                ..
+            }) if self.mir.local_kind(local) == LocalKind::Temp => {
+                // Look for the statements within this block after assigning to a local to see
+                // if we have a closure. If we do, then annotate it.
+                for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
+                    if let StatementKind::Assign(
+                        _,
+                        Rvalue::Aggregate(
+                            box AggregateKind::Closure(def_id, substs),
+                            _
+                        )
+                    ) = stmt.kind {
+                        return self.annotate_fn_sig(
+                            def_id,
+                            self.infcx.closure_sig(def_id, substs)
+                        );
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        // If this is not the case, then return if we're currently on a closure (as we
+        // don't have a substs to get the PolyFnSig) or attempt to get the arguments
+        // and return type of the function.
+        if is_closure {
+            None
+        } else {
+            let ty = self.infcx.tcx.type_of(self.mir_def_id);
+            match ty.sty {
+                ty::TyKind::FnDef(_, _) | ty::TyKind::FnPtr(_) =>
+                    self.annotate_fn_sig(
+                        self.mir_def_id,
+                        self.infcx.tcx.fn_sig(self.mir_def_id)
+                    ),
+                _ => None,
+            }
+        }
+    }
+
+    /// Annotate the first argument and return type of a function signature if they are
+    /// references.
+    fn annotate_fn_sig(
+        &self,
+        did: DefId,
+        sig: ty::PolyFnSig<'tcx>,
+    ) -> Option<AnnotatedBorrowFnSignature> {
+        let is_closure = self.infcx.tcx.is_closure(did);
+        let fn_node_id = self.infcx.tcx.hir.as_local_node_id(did)?;
+        let fn_decl = self.infcx.tcx.hir.fn_decl(fn_node_id)?;
+
+        // If there is one argument and this error is being reported, that means
+        // that the lifetime of the borrow could not be made to match the single
+        // argument's lifetime. We can highlight it.
+        //
+        // If there is more than one argument and this error is being reported, that
+        // means there must be a self parameter - as otherwise there would be an error
+        // from lifetime elision and not this. So we highlight the self parameter.
+        let argument_span = fn_decl.inputs.first()?.span;
+        let argument_ty = sig.inputs().skip_binder().first()?;
+        if is_closure {
+            // Closure arguments are wrapped in a tuple, so we need to get the first
+            // from that.
+            let argument_ty = if let ty::TyKind::Tuple(elems) = argument_ty.sty {
+                let argument_ty = elems.first()?;
+                if let ty::TyKind::Ref(_, _, _) = argument_ty.sty {
+                    argument_ty
+                } else {
+                    return None;
+                }
+            } else {
+                return None
+            };
+
+            Some(AnnotatedBorrowFnSignature::Closure {
+                argument_ty,
+                argument_span,
+            })
+        } else if let ty::TyKind::Ref(argument_region, _, _) = argument_ty.sty {
+            // We only consider the return type for functions.
+            let return_span = fn_decl.output.span();
+
+            let return_ty = sig.output();
+            let (return_region, return_ty) = if let ty::TyKind::Ref(
+                return_region, _, _
+            ) = return_ty.skip_binder().sty {
+                (return_region, *return_ty.skip_binder())
+            } else {
+                return None;
+            };
+
+            Some(AnnotatedBorrowFnSignature::Function {
+                argument_ty,
+                argument_span,
+                return_ty,
+                return_span,
+                regions_equal: return_region == argument_region,
+            })
+        } else {
+            None
+        }
+    }
+}
+
+#[derive(Debug)]
+enum AnnotatedBorrowFnSignature<'tcx> {
+    Function {
+        argument_ty: ty::Ty<'tcx>,
+        argument_span: Span,
+        return_ty: ty::Ty<'tcx>,
+        return_span: Span,
+        regions_equal: bool,
+    },
+    Closure {
+        argument_ty: ty::Ty<'tcx>,
+        argument_span: Span,
+    }
+}
+
+impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
+    fn emit(
+        &self,
+        diag: &mut DiagnosticBuilder<'_>
+    ) -> String {
+        let (argument_ty, argument_span) = match self {
+            AnnotatedBorrowFnSignature::Function {
+                argument_ty,
+                argument_span,
+                ..
+            } => (argument_ty, argument_span),
+            AnnotatedBorrowFnSignature::Closure {
+                argument_ty,
+                argument_span,
+            } => (argument_ty, argument_span),
+        };
+
+        let (argument_region_name, argument_ty_name) = (
+            self.get_region_name_for_ty(argument_ty, 0),
+            self.get_name_for_ty(argument_ty, 0),
+        );
+        diag.span_label(
+            *argument_span,
+            format!("has type `{}`", argument_ty_name)
+        );
+
+        // Only emit labels for the return value when we're annotating a function.
+        if let AnnotatedBorrowFnSignature::Function {
+            return_ty,
+            return_span,
+            regions_equal,
+            ..
+        } = self {
+            let counter = if *regions_equal { 0 } else { 1 };
+            let (return_region_name, return_ty_name) = (
+                self.get_region_name_for_ty(return_ty, counter),
+                self.get_name_for_ty(return_ty, counter)
+            );
+
+            let types_equal = return_ty_name == argument_ty_name;
+            diag.span_label(
+                *return_span,
+                format!(
+                    "{}has type `{}`",
+                    if types_equal { "also " } else { "" },
+                    return_ty_name,
+                )
+            );
+
+            return_region_name
+        } else {
+            argument_region_name
+        }
+    }
+
+    fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
+        // We need to add synthesized lifetimes where appropriate. We do
+        // this by hooking into the pretty printer and telling it to label the
+        // lifetimes without names with the value `'0`.
+        match ty.sty {
+            ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _) |
+            ty::TyKind::Ref(ty::RegionKind::ReSkolemized(_, br), _, _) =>
+                with_highlight_region_for_region(*br, counter, || format!("{}", ty)),
+            _ => format!("{}", ty),
+        }
+    }
+
+    fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
+        match ty.sty {
+            ty::TyKind::Ref(region, _, _) => match region {
+                ty::RegionKind::ReLateBound(_, br) |
+                ty::RegionKind::ReSkolemized(_, br) =>
+                    with_highlight_region_for_region(*br, counter, || format!("{}", region)),
+                _ => format!("{}", region),
+            }
+            _ => bug!("ty for annotation of borrow region is not a reference"),
+        }
+    }
 }
 
 // The span(s) associated to a use of a place.
@@ -1351,7 +1485,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
         use self::UseSpans::*;
         use rustc::hir::ExprKind::Closure;
-        use rustc::mir::AggregateKind;
 
         let local = match self.mir[location.block]
             .statements
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 5a08d227998..06884875598 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -618,7 +618,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx);
 
                 // Erase the regions.
-                let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).to_ty(self.infcx.tcx);
+                let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty)
+                    .to_ty(self.infcx.tcx);
 
                 // "Lift" into the gcx -- once regions are erased, this type should be in the
                 // global arenas; this "lift" operation basically just asserts that is true, but
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index 875348ac819..be05e006608 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -18,7 +18,7 @@ use rustc::infer::InferCtxt;
 use rustc::mir::Mir;
 use rustc::ty::subst::{Substs, UnpackedKind};
 use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
-use rustc::util::ppaux::with_highlight_region;
+use rustc::util::ppaux::with_highlight_region_for_regionvid;
 use rustc_errors::DiagnosticBuilder;
 use syntax::ast::{Name, DUMMY_NODE_ID};
 use syntax::symbol::keywords;
@@ -406,7 +406,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         argument_ty: Ty<'tcx>,
         counter: &mut usize,
     ) -> Option<RegionName> {
-        let type_name = with_highlight_region(needle_fr, *counter, || {
+        let type_name = with_highlight_region_for_regionvid(needle_fr, *counter, || {
             infcx.extract_type_name(&argument_ty)
         });
 
@@ -420,9 +420,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index);
 
             Some(RegionName {
-                // This counter value will already have been used, so this function will increment it
-                // so the next value will be used next and return the region name that would have been
-                // used.
+                // This counter value will already have been used, so this function will increment
+                // it so the next value will be used next and return the region name that would
+                // have been used.
                 name: self.synthesize_region_name(counter),
                 source: RegionNameSource::CannotMatchHirTy(span, type_name),
             })
@@ -683,7 +683,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             return None;
         }
 
-        let type_name = with_highlight_region(fr, *counter, || infcx.extract_type_name(&return_ty));
+        let type_name = with_highlight_region_for_regionvid(
+            fr, *counter, || infcx.extract_type_name(&return_ty));
 
         let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
 
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 1250bd78047..75f14a6bbda 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -652,14 +652,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
     }
 
-    pub fn universal_regions_outlived_by<'a>(
-        &'a self,
-        r: RegionVid
-    ) -> impl Iterator<Item = RegionVid> + 'a {
-        let borrow_scc = self.constraint_sccs.scc(r);
-        self.scc_values.universal_regions_outlived_by(borrow_scc)
-    }
-
     /// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot
     /// prove to be satisfied. If this is a closure, we will attempt to
     /// "promote" this type-test into our `ClosureRegionRequirements` and
diff --git a/src/test/ui/issues/issue-30438-c.nll.stderr b/src/test/ui/issues/issue-30438-c.nll.stderr
index 28e63b2d36b..6d8a750d3d0 100644
--- a/src/test/ui/issues/issue-30438-c.nll.stderr
+++ b/src/test/ui/issues/issue-30438-c.nll.stderr
@@ -1,17 +1,16 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/issue-30438-c.rs:19:5
    |
+LL | fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y <Test<'z> as Trait>::Out where 'z: 'static {
+   |                      ------------     ---------------------------- has type `&'y <Test<'z> as Trait>::Out`
+   |                      |
+   |                      has type `&'y Test<'z>`
+LL |     let x = Test { s: "this cannot last" };
 LL |     &x
-   |     ^^ borrowed value does not live long enough
+   |     ^^ `x` would have to be valid for `'y`
 LL |     //~^ ERROR: `x` does not live long enough
 LL | }
-   | - `x` dropped here while still borrowed
-   |
-note: borrowed value must be valid for the lifetime 'y as defined on the function body at 17:10...
-  --> $DIR/issue-30438-c.rs:17:10
-   |
-LL | fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y <Test<'z> as Trait>::Out where 'z: 'static {
-   |          ^^
+   | - but `x` dropped here while still borrowed
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/borrowed-universal-error-2.stderr b/src/test/ui/nll/borrowed-universal-error-2.stderr
index 867e473af2c..b414c399884 100644
--- a/src/test/ui/nll/borrowed-universal-error-2.stderr
+++ b/src/test/ui/nll/borrowed-universal-error-2.stderr
@@ -1,17 +1,16 @@
 error[E0597]: `v` does not live long enough
   --> $DIR/borrowed-universal-error-2.rs:16:5
    |
+LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
+   |               ----------     ------- has type `&'a u32`
+   |               |
+   |               has type `&'a (u32,)`
+LL |     let v = 22;
 LL |     &v
-   |     ^^ borrowed value does not live long enough
+   |     ^^ `v` would have to be valid for `'a`
 LL |     //~^ ERROR `v` does not live long enough [E0597]
 LL | }
-   | - `v` dropped here while still borrowed
-   |
-note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
-  --> $DIR/borrowed-universal-error-2.rs:14:8
-   |
-LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
-   |        ^^
+   | - but `v` dropped here while still borrowed
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-52534-1.rs b/src/test/ui/nll/issue-52534-1.rs
new file mode 100644
index 00000000000..a6f3f9fbd3c
--- /dev/null
+++ b/src/test/ui/nll/issue-52534-1.rs
@@ -0,0 +1,33 @@
+// Copyright 2018 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.
+
+#![feature(nll)]
+#![allow(warnings)]
+
+struct Test;
+
+impl Test {
+    fn bar(&self, x: &u32) -> &u32 {
+        let x = 22;
+        &x
+    }
+}
+
+fn foo(x: &u32) -> &u32 {
+    let x = 22;
+    &x
+}
+
+fn baz(x: &u32) -> &&u32 {
+    let x = 22;
+    &&x
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/issue-52534-1.stderr b/src/test/ui/nll/issue-52534-1.stderr
new file mode 100644
index 00000000000..7b89336dabf
--- /dev/null
+++ b/src/test/ui/nll/issue-52534-1.stderr
@@ -0,0 +1,59 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/issue-52534-1.rs:19:9
+   |
+LL |     fn bar(&self, x: &u32) -> &u32 {
+   |            -----              ---- has type `&'0 u32`
+   |            |
+   |            has type `&'0 Test`
+LL |         let x = 22;
+LL |         &x
+   |         ^^ `x` would have to be valid for `'0`
+LL |     }
+   |     - but `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/issue-52534-1.rs:25:5
+   |
+LL | fn foo(x: &u32) -> &u32 {
+   |           ----     ---- also has type `&'0 u32`
+   |           |
+   |           has type `&'0 u32`
+LL |     let x = 22;
+LL |     &x
+   |     ^^ `x` would have to be valid for `'0`
+LL | }
+   | - but `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/issue-52534-1.rs:30:6
+   |
+LL | fn baz(x: &u32) -> &&u32 {
+   |           ----     ----- has type `&'0 &'0 u32`
+   |           |
+   |           has type `&'0 u32`
+LL |     let x = 22;
+LL |     &&x
+   |      ^^ `x` would have to be valid for `'0`
+LL | }
+   | - but `x` dropped here while still borrowed
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/issue-52534-1.rs:30:6
+   |
+LL |     &&x
+   |      ^^ temporary value does not live long enough
+LL | }
+   | - temporary value only lives until here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 28:1...
+  --> $DIR/issue-52534-1.rs:28:1
+   |
+LL | / fn baz(x: &u32) -> &&u32 {
+LL | |     let x = 22;
+LL | |     &&x
+LL | | }
+   | |_^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/issue-52534.rs b/src/test/ui/nll/issue-52534.rs
new file mode 100644
index 00000000000..c75af27f83d
--- /dev/null
+++ b/src/test/ui/nll/issue-52534.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+#![feature(nll)]
+#![allow(warnings)]
+
+fn foo(_: impl FnOnce(&u32) -> &u32) {
+}
+
+fn bar() {
+    let x = 22;
+    foo(|a| &x)
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/issue-52534.stderr b/src/test/ui/nll/issue-52534.stderr
new file mode 100644
index 00000000000..c92a4230e1e
--- /dev/null
+++ b/src/test/ui/nll/issue-52534.stderr
@@ -0,0 +1,13 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/issue-52534.rs:19:14
+   |
+LL |     foo(|a| &x)
+   |           -  ^ `x` would have to be valid for `'0`
+   |           |
+   |           has type `&'0 u32`
+LL | }
+   | - but `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/regions/regions-nested-fns-2.nll.stderr b/src/test/ui/regions/regions-nested-fns-2.nll.stderr
index 1b5bb7d5007..3f64806cc0f 100644
--- a/src/test/ui/regions/regions-nested-fns-2.nll.stderr
+++ b/src/test/ui/regions/regions-nested-fns-2.nll.stderr
@@ -2,15 +2,13 @@ error[E0597]: `y` does not live long enough
   --> $DIR/regions-nested-fns-2.rs:18:25
    |
 LL |         |z| {
-   |         --- value captured here
+   |           - has type `&'0 isize`
 LL |             //~^ ERROR E0373
 LL |             if false { &y } else { z }
-   |                         ^ borrowed value does not live long enough
+   |                         ^ `y` would have to be valid for `'0`
 LL |         });
 LL | }
-   | - `y` dropped here while still borrowed
-   |
-   = note: borrowed value must be valid for the static lifetime...
+   | - but `y` dropped here while still borrowed
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-nested-fns.nll.stderr b/src/test/ui/regions/regions-nested-fns.nll.stderr
index 4bb602d572f..eab06e8b90f 100644
--- a/src/test/ui/regions/regions-nested-fns.nll.stderr
+++ b/src/test/ui/regions/regions-nested-fns.nll.stderr
@@ -25,15 +25,13 @@ error[E0597]: `y` does not live long enough
   --> $DIR/regions-nested-fns.rs:19:15
    |
 LL |     ignore::<Box<for<'z> FnMut(&'z isize)>>(Box::new(|z| {
-   |                                                      --- value captured here
+   |                                                        - has type `&'0 isize`
 LL |         ay = x;
 LL |         ay = &y;
-   |               ^ borrowed value does not live long enough
+   |               ^ `y` would have to be valid for `'0`
 ...
 LL | }
-   | - `y` dropped here while still borrowed
-   |
-   = note: borrowed value must be valid for the static lifetime...
+   | - but `y` dropped here while still borrowed
 
 error: unsatisfied lifetime constraints
   --> $DIR/regions-nested-fns.rs:23:68