diff options
| -rw-r--r-- | src/librustc/util/ppaux.rs | 51 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/error_reporting.rs | 343 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/mod.rs | 3 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs | 13 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/region_infer/mod.rs | 8 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-30438-c.nll.stderr | 15 | ||||
| -rw-r--r-- | src/test/ui/nll/borrowed-universal-error-2.stderr | 15 | ||||
| -rw-r--r-- | src/test/ui/nll/issue-52534-1.rs | 33 | ||||
| -rw-r--r-- | src/test/ui/nll/issue-52534-1.stderr | 59 | ||||
| -rw-r--r-- | src/test/ui/nll/issue-52534.rs | 22 | ||||
| -rw-r--r-- | src/test/ui/nll/issue-52534.stderr | 13 | ||||
| -rw-r--r-- | src/test/ui/regions/regions-nested-fns-2.nll.stderr | 8 | ||||
| -rw-r--r-- | src/test/ui/regions/regions-nested-fns.nll.stderr | 8 |
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 |
