diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 6876b1490f376..0359eb9b95d1b 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -119,6 +119,39 @@ impl<'tcx> Place<'tcx> { proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem), } } + + /// If this is a field projection, and the field is being projected from a closure type, + /// then returns the index of the field being projected. Note that this closure will always + /// be `self` in the current MIR, because that is the only time we directly access the fields + /// of a closure type. + pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>, + tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option { + let place = if let Place::Projection(ref proj) = self { + if let ProjectionElem::Deref = proj.elem { + &proj.base + } else { + self + } + } else { + self + }; + + match place { + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Field(field, _ty) => { + let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); + + if base_ty.is_closure() || base_ty.is_generator() { + Some(field) + } else { + None + } + }, + _ => None, + }, + _ => None, + } + } } pub enum RvalueInitializationState { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3dca7768d704e..5dca01f8842a0 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -726,7 +726,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { - if let Some(field) = self.is_upvar_field_projection(&proj.base) { + let upvar_field_projection = place.is_upvar_field_projection( + self.mir, &self.tcx); + if let Some(field) = upvar_field_projection { let var_index = field.index(); let name = self.mir.upvar_decls[var_index].debug_name.to_string(); if self.mir.upvar_decls[var_index].by_ref { @@ -785,7 +787,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ProjectionElem::Field(field, _ty) => { autoderef = true; - if let Some(field) = self.is_upvar_field_projection(place) { + let upvar_field_projection = place.is_upvar_field_projection( + self.mir, &self.tcx); + if let Some(field) = upvar_field_projection { let var_index = field.index(); let name = self.mir.upvar_decls[var_index].debug_name.to_string(); buf.push_str(&name); diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 2e0ab522e3a4b..62bf2b0abe4c7 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1214,7 +1214,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } Operand::Move(ref place @ Place::Projection(_)) | Operand::Copy(ref place @ Place::Projection(_)) => { - if let Some(field) = self.is_upvar_field_projection(place) { + if let Some(field) = place.is_upvar_field_projection( + self.mir, &self.tcx) { self.used_mut_upvars.push(field); } } @@ -1803,7 +1804,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place: place @ Place::Projection(_), is_local_mutation_allowed: _, } => { - if let Some(field) = self.is_upvar_field_projection(&place) { + if let Some(field) = place.is_upvar_field_projection(self.mir, &self.tcx) { self.used_mut_upvars.push(field); } } @@ -1866,7 +1867,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Mutably borrowed data is mutable, but only if we have a // unique path to the `&mut` hir::MutMutable => { - let mode = match self.is_upvar_field_projection(&proj.base) + let mode = match place.is_upvar_field_projection( + self.mir, &self.tcx) { Some(field) if { @@ -1911,7 +1913,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..) => { - if let Some(field) = self.is_upvar_field_projection(place) { + let upvar_field_projection = place.is_upvar_field_projection( + self.mir, &self.tcx); + if let Some(field) = upvar_field_projection { let decl = &self.mir.upvar_decls[field.index()]; debug!( "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}", @@ -1965,28 +1969,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } } - - /// If this is a field projection, and the field is being projected from a closure type, - /// then returns the index of the field being projected. Note that this closure will always - /// be `self` in the current MIR, because that is the only time we directly access the fields - /// of a closure type. - fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option { - match *place { - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(field, _ty) => { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); - - if base_ty.is_closure() || base_ty.is_generator() { - Some(field) - } else { - None - } - } - _ => None, - }, - _ => None, - } - } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index c1b73fac89388..c89dc889b5e39 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -22,6 +22,7 @@ use std::fmt; use syntax_pos::Span; mod region_name; +mod var_name; /// Constraints that are considered interesting can be categorized to /// determine why they are interesting. Order of variants indicates @@ -30,7 +31,9 @@ mod region_name; enum ConstraintCategory { Cast, Assignment, + AssignmentToUpvar, Return, + CallArgumentToUpvar, CallArgument, Other, Boring, @@ -39,10 +42,12 @@ enum ConstraintCategory { impl fmt::Display for ConstraintCategory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - ConstraintCategory::Assignment => write!(f, "assignment"), + ConstraintCategory::Assignment | + ConstraintCategory::AssignmentToUpvar => write!(f, "assignment"), ConstraintCategory::Return => write!(f, "return"), ConstraintCategory::Cast => write!(f, "cast"), - ConstraintCategory::CallArgument => write!(f, "argument"), + ConstraintCategory::CallArgument | + ConstraintCategory::CallArgumentToUpvar => write!(f, "argument"), _ => write!(f, "free region"), } } @@ -130,8 +135,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, index: ConstraintIndex, mir: &Mir<'tcx>, + _infcx: &InferCtxt<'_, '_, 'tcx>, ) -> (ConstraintCategory, Span) { let constraint = self.constraints[index]; + debug!("classify_constraint: constraint={:?}", constraint); let span = constraint.locations.span(mir); let location = constraint.locations.from_location().unwrap_or(Location::START); @@ -140,8 +147,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let data = &mir[location.block]; + debug!("classify_constraint: location={:?} data={:?}", location, data); let category = if location.statement_index == data.statements.len() { if let Some(ref terminator) = data.terminator { + debug!("classify_constraint: terminator.kind={:?}", terminator.kind); match terminator.kind { TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment, TerminatorKind::Call { .. } => ConstraintCategory::CallArgument, @@ -152,14 +161,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } else { let statement = &data.statements[location.statement_index]; + debug!("classify_constraint: statement.kind={:?}", statement.kind); match statement.kind { StatementKind::Assign(ref place, ref rvalue) => { + debug!("classify_constraint: place={:?} rvalue={:?}", place, rvalue); if *place == Place::Local(mir::RETURN_PLACE) { ConstraintCategory::Return } else { match rvalue { Rvalue::Cast(..) => ConstraintCategory::Cast, - Rvalue::Use(..) => ConstraintCategory::Assignment, + Rvalue::Use(..) | + Rvalue::Aggregate(..) => ConstraintCategory::Assignment, _ => ConstraintCategory::Other, } } @@ -208,7 +220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Classify each of the constraints along the path. let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter() - .map(|&index| self.classify_constraint(index, mir)) + .map(|&index| self.classify_constraint(index, mir, infcx)) .collect(); debug!("report_error: categorized_path={:?}", categorized_path); @@ -218,30 +230,100 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Get a span let (category, span) = categorized_path.first().unwrap(); + + let category = match ( + category, + self.universal_regions.is_local_free_region(fr), + self.universal_regions.is_local_free_region(outlived_fr), + ) { + (ConstraintCategory::Assignment, true, false) => + &ConstraintCategory::AssignmentToUpvar, + (ConstraintCategory::CallArgument, true, false) => + &ConstraintCategory::CallArgumentToUpvar, + (category, _, _) => category, + }; + + debug!("report_error: category={:?}", category); + match category { + ConstraintCategory::AssignmentToUpvar | + ConstraintCategory::CallArgumentToUpvar => + self.report_closure_error(mir, infcx, mir_def_id, fr, outlived_fr, category, span), + _ => + self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category, span), + } + } + + fn report_closure_error( + &self, + mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, '_, 'tcx>, + mir_def_id: DefId, + fr: RegionVid, + outlived_fr: RegionVid, + category: &ConstraintCategory, + span: &Span, + ) { + let fr_name_and_span = self.get_var_name_and_span_for_region( + infcx.tcx, mir, fr); + let outlived_fr_name_and_span = self.get_var_name_and_span_for_region( + infcx.tcx, mir,outlived_fr); + + if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() { + return self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category, + span); + } + + let diag = &mut infcx.tcx.sess.struct_span_err( + *span, &format!("borrowed data escapes outside of closure"), + ); + + if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span { + if let Some(name) = outlived_fr_name { + diag.span_label( + outlived_fr_span, + format!("`{}` is declared here, outside of the closure body", name), + ); + } + } + + if let Some((fr_name, fr_span)) = fr_name_and_span { + if let Some(name) = fr_name { + diag.span_label( + fr_span, + format!("`{}` is a reference that is only valid in the closure body", name), + ); + + diag.span_label(*span, format!("`{}` escapes the closure body here", name)); + } + } + + diag.emit(); + } + + fn report_general_error( + &self, + mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, '_, 'tcx>, + mir_def_id: DefId, + fr: RegionVid, + outlived_fr: RegionVid, + category: &ConstraintCategory, + span: &Span, + ) { let diag = &mut infcx.tcx.sess.struct_span_err( - *span, - &format!("unsatisfied lifetime constraints"), // FIXME + *span, &format!("unsatisfied lifetime constraints"), // FIXME ); - // Figure out how we can refer let counter = &mut 1; - let fr_name = self.give_region_a_name(infcx.tcx, mir, mir_def_id, fr, counter, diag); + let fr_name = self.give_region_a_name( + infcx.tcx, mir, mir_def_id, fr, counter, diag); let outlived_fr_name = self.give_region_a_name( - infcx.tcx, - mir, - mir_def_id, - outlived_fr, - counter, - diag, - ); + infcx.tcx, mir, mir_def_id, outlived_fr, counter, diag); - diag.span_label( - *span, - format!( - "{} requires that `{}` must outlive `{}`", - category, fr_name, outlived_fr_name, - ), - ); + diag.span_label(*span, format!( + "{} requires that `{}` must outlive `{}`", + category, fr_name, outlived_fr_name, + )); diag.emit(); } 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 fc0e64d0a8a66..c0eca026331ba 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 @@ -12,10 +12,9 @@ use borrow_check::nll::region_infer::RegionInferenceContext; use borrow_check::nll::ToRegionVid; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::mir::{Local, Mir}; +use rustc::mir::Mir; use rustc::ty::subst::{Substs, UnpackedKind}; use rustc::ty::{self, RegionVid, Ty, TyCtxt}; -use rustc_data_structures::indexed_vec::Idx; use rustc_errors::DiagnosticBuilder; use syntax::ast::Name; use syntax::symbol::keywords; @@ -63,11 +62,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag) .or_else(|| { self.give_name_if_anonymous_region_appears_in_arguments( - tcx, mir, mir_def_id, fr, counter, diag, - ) + tcx, mir, mir_def_id, fr, counter, diag) }) .or_else(|| { - self.give_name_if_anonymous_region_appears_in_upvars(tcx, mir, fr, counter, diag) + self.give_name_if_anonymous_region_appears_in_upvars( + tcx, mir, fr, counter, diag) }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_output(tcx, mir, fr, counter, diag) @@ -139,24 +138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag: &mut DiagnosticBuilder<'_>, ) -> Option { let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); - let argument_index = self - .universal_regions - .unnormalized_input_tys - .iter() - .skip(implicit_inputs) - .position(|arg_ty| { - debug!( - "give_name_if_anonymous_region_appears_in_arguments: arg_ty = {:?}", - arg_ty - ); - tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr) - })?; - - debug!( - "give_name_if_anonymous_region_appears_in_arguments: \ - found {:?} in argument {} which has type {:?}", - fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index], - ); + let argument_index = self.get_argument_index_for_region(tcx, fr)?; let arg_ty = self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index]; @@ -172,10 +154,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { return Some(region_name); } + let (_argument_name, argument_span) = self.get_argument_name_and_span_for_region( + mir, argument_index); + let region_name = self.synthesize_region_name(counter); - let argument_local = Local::new(argument_index + implicit_inputs + 1); - let argument_span = mir.local_decls[argument_local].source_info.span; diag.span_label( argument_span, format!("lifetime `{}` appears in this argument", region_name,), @@ -440,42 +423,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { counter: &mut usize, diag: &mut DiagnosticBuilder<'_>, ) -> Option { - let upvar_index = self - .universal_regions - .defining_ty - .upvar_tys(tcx) - .position(|upvar_ty| { - debug!( - "give_name_if_anonymous_region_appears_in_upvars: upvar_ty = {:?}", - upvar_ty, - ); - tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr) - })?; - - let upvar_ty = self - .universal_regions - .defining_ty - .upvar_tys(tcx) - .nth(upvar_index); - - debug!( - "give_name_if_anonymous_region_appears_in_upvars: \ - found {:?} in upvar {} which has type {:?}", - fr, upvar_index, upvar_ty, - ); - + let upvar_index = self.get_upvar_index_for_region(tcx, fr)?; + let (upvar_name, upvar_span) = self.get_upvar_name_and_span_for_region(tcx, mir, + upvar_index); let region_name = self.synthesize_region_name(counter); - let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local(); - let upvar_node_id = tcx.hir.hir_to_node_id(upvar_hir_id); - let upvar_span = tcx.hir.span(upvar_node_id); - let upvar_name = tcx.hir.name(upvar_node_id); diag.span_label( upvar_span, - format!( - "lifetime `{}` appears in the type of `{}`", - region_name, upvar_name, - ), + format!("lifetime `{}` appears in the type of `{}`", region_name, upvar_name), ); Some(region_name) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs new file mode 100644 index 0000000000000..f1c3a7489ee8f --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs @@ -0,0 +1,145 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use borrow_check::nll::region_infer::RegionInferenceContext; +use borrow_check::nll::ToRegionVid; +use rustc::mir::{Local, Mir}; +use rustc::ty::{RegionVid, TyCtxt}; +use rustc_data_structures::indexed_vec::Idx; +use syntax::codemap::Span; +use syntax_pos::symbol::Symbol; + +impl<'tcx> RegionInferenceContext<'tcx> { + crate fn get_var_name_and_span_for_region( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + mir: &Mir<'tcx>, + fr: RegionVid, + ) -> Option<(Option, Span)> { + debug!("get_var_name_and_span_for_region(fr={:?})", fr); + assert!(self.universal_regions.is_universal_region(fr)); + + debug!("get_var_name_and_span_for_region: attempting upvar"); + self.get_upvar_index_for_region(tcx, fr) + .map(|index| { + let (name, span) = self.get_upvar_name_and_span_for_region(tcx, mir, index); + (Some(name), span) + }) + .or_else(|| { + debug!("get_var_name_and_span_for_region: attempting argument"); + self.get_argument_index_for_region(tcx, fr) + .map(|index| self.get_argument_name_and_span_for_region(mir, index)) + }) + } + + /// Search the upvars (if any) to find one that references fr. Return its index. + crate fn get_upvar_index_for_region( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + fr: RegionVid, + ) -> Option { + let upvar_index = self + .universal_regions + .defining_ty + .upvar_tys(tcx) + .position(|upvar_ty| { + debug!( + "get_upvar_index_for_region: upvar_ty = {:?}", + upvar_ty, + ); + tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr) + })?; + + let upvar_ty = self + .universal_regions + .defining_ty + .upvar_tys(tcx) + .nth(upvar_index); + + debug!( + "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}", + fr, upvar_index, upvar_ty, + ); + + Some(upvar_index) + } + + /// Given the index of an upvar, finds its name and the span from where it was + /// declared. + crate fn get_upvar_name_and_span_for_region( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + mir: &Mir<'tcx>, + upvar_index: usize, + ) -> (Symbol, Span) { + let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local(); + let upvar_node_id = tcx.hir.hir_to_node_id(upvar_hir_id); + debug!("get_upvar_name_and_span_for_region: upvar_node_id={:?}", upvar_node_id); + + let upvar_name = tcx.hir.name(upvar_node_id); + let upvar_span = tcx.hir.span(upvar_node_id); + debug!("get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}", + upvar_name, upvar_span); + + (upvar_name, upvar_span) + } + + /// Search the argument types for one that references fr (which should be a free region). + /// Returns Some(_) with the index of the input if one is found. + /// + /// NB: In the case of a closure, the index is indexing into the signature as seen by the + /// user - in particular, index 0 is not the implicit self parameter. + crate fn get_argument_index_for_region( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + fr: RegionVid, + ) -> Option { + let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); + let argument_index = self + .universal_regions + .unnormalized_input_tys + .iter() + .skip(implicit_inputs) + .position(|arg_ty| { + debug!( + "get_argument_index_for_region: arg_ty = {:?}", + arg_ty + ); + tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr) + })?; + + debug!( + "get_argument_index_for_region: found {:?} in argument {} which has type {:?}", + fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index], + ); + + Some(argument_index) + } + + /// Given the index of an argument, finds its name (if any) and the span from where it was + /// declared. + crate fn get_argument_name_and_span_for_region( + &self, + mir: &Mir<'tcx>, + argument_index: usize, + ) -> (Option, Span) { + let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); + let argument_local = Local::new(implicit_inputs + argument_index + 1); + debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local); + + let argument_name = mir.local_decls[argument_local].name; + let argument_span = mir.local_decls[argument_local].source_info.span; + debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}", + argument_name, argument_span); + + (argument_name, argument_span) + } + +} diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index 5a1f1986fcf05..64086cb07917d 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -4,15 +4,15 @@ warning: not reporting region error due to nll LL | give_any(|y| x = Some(y)); | ^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/issue-45983.rs:17:18 | LL | let x = None; - | - lifetime `'2` appears in the type of `x` + | - `x` is declared here, outside of the closure body LL | give_any(|y| x = Some(y)); - | - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2` + | - ^^^^^^^^^^^ `y` escapes the closure body here | | - | lifetime `'1` appears in this argument + | `y` is a reference that is only valid in the closure body error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-45983.rs:17:18 diff --git a/src/test/ui/borrowck/issue-7573.nll.stderr b/src/test/ui/borrowck/issue-7573.nll.stderr index 5904e98753694..b0fbcd3ad9f39 100644 --- a/src/test/ui/borrowck/issue-7573.nll.stderr +++ b/src/test/ui/borrowck/issue-7573.nll.stderr @@ -4,17 +4,17 @@ warning: not reporting region error due to nll LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); | ^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/issue-7573.rs:32:9 | LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); - | ---------------- lifetime `'2` appears in the type of `lines_to_use` + | ---------------- `lines_to_use` is declared here, outside of the closure body LL | //~^ NOTE cannot infer an appropriate lifetime LL | let push_id = |installed_id: &CrateId| { - | - let's call the lifetime of this reference `'1` + | ------------ `installed_id` is a reference that is only valid in the closure body ... LL | lines_to_use.push(installed_id); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr index 4f7843b72489c..1a18817e94365 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr @@ -4,15 +4,15 @@ warning: not reporting region error due to nll LL | with_int(|y| x = Some(y)); | ^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/regions-escape-bound-fn-2.rs:18:18 | LL | let mut x = None; - | ----- lifetime `'2` appears in the type of `x` + | ----- `x` is declared here, outside of the closure body LL | with_int(|y| x = Some(y)); - | - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2` + | - ^^^^^^^^^^^ `y` escapes the closure body here | | - | lifetime `'1` appears in this argument + | `y` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr index 9b107ae08b477..62ea9a0854bde 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr @@ -4,15 +4,15 @@ warning: not reporting region error due to nll LL | with_int(|y| x = Some(y)); | ^^^^^^^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/regions-escape-bound-fn.rs:18:18 | LL | let mut x: Option<&isize> = None; - | ----- lifetime `'2` appears in the type of `x` + | ----- `x` is declared here, outside of the closure body LL | with_int(|y| x = Some(y)); - | - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2` + | - ^^^^^^^^^^^ `y` escapes the closure body here | | - | lifetime `'1` appears in this argument + | `y` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr index 8095330154d4c..44eead9fb5a98 100644 --- a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr @@ -4,15 +4,15 @@ warning: not reporting region error due to nll LL | with_int(&mut |y| x = Some(y)); | ^^^^^^^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/regions-escape-unboxed-closure.rs:16:23 | LL | let mut x: Option<&isize> = None; - | ----- lifetime `'2` appears in the type of `x` + | ----- `x` is declared here, outside of the closure body LL | with_int(&mut |y| x = Some(y)); - | - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2` + | - ^^^^^^^^^^^ `y` escapes the closure body here | | - | lifetime `'1` appears in this argument + | `y` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr b/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr index c8c8ef8215ae2..8658c618bf24c 100644 --- a/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr +++ b/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr @@ -22,37 +22,37 @@ warning: not reporting region error due to nll LL | f = Some(x); | ^^^^^^^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/expect-region-supply-region.rs:28:9 | LL | let mut f: Option<&u32> = None; - | ----- lifetime `'2` appears in the type of `f` + | ----- `f` is declared here, outside of the closure body LL | closure_expecting_bound(|x| { - | - lifetime `'1` appears in this argument + | - `x` is a reference that is only valid in the closure body LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure - | ^^^^^^^^^^^ free region requires that `'1` must outlive `'2` + | ^^^^^^^^^^^ `x` escapes the closure body here -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/expect-region-supply-region.rs:38:9 | LL | let mut f: Option<&u32> = None; - | ----- lifetime `'2` appears in the type of `f` + | ----- `f` is declared here, outside of the closure body LL | closure_expecting_bound(|x: &u32| { - | - let's call the lifetime of this reference `'1` + | - `x` is a reference that is only valid in the closure body LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure - | ^^^^^^^^^^^ free region requires that `'1` must outlive `'2` + | ^^^^^^^^^^^ `x` escapes the closure body here -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/expect-region-supply-region.rs:52:9 | LL | let mut f: Option<&u32> = None; - | ----- lifetime `'2` appears in the type of `f` + | ----- `f` is declared here, outside of the closure body ... LL | closure_expecting_bound(|x: &'x u32| { - | - let's call the lifetime of this reference `'1` + | - `x` is a reference that is only valid in the closure body ... LL | f = Some(x); - | ^^^^^^^^^^^ free region requires that `'1` must outlive `'2` + | ^^^^^^^^^^^ `x` escapes the closure body here error: aborting due to 3 previous errors diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr index 19e10ba6da8b9..e26b1956d5e81 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr @@ -4,11 +4,13 @@ warning: not reporting region error due to nll LL | static_val(x); //~ ERROR cannot infer | ^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/dyn-trait.rs:32:5 | +LL | fn with_dyn_debug_static<'a>(x: Box) { + | - `x` is a reference that is only valid in the closure body LL | static_val(x); //~ ERROR cannot infer - | ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^ `x` escapes the closure body here error: aborting due to previous error diff --git a/src/test/ui/issue-16683.nll.stderr b/src/test/ui/issue-16683.nll.stderr index d789f580b2738..f9dda27da0985 100644 --- a/src/test/ui/issue-16683.nll.stderr +++ b/src/test/ui/issue-16683.nll.stderr @@ -10,13 +10,13 @@ warning: not reporting region error due to nll LL | self.a(); //~ ERROR cannot infer | ^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/issue-16683.rs:14:9 | LL | fn b(&self) { - | - let's call the lifetime of this reference `'1` + | ----- `self` is a reference that is only valid in the closure body LL | self.a(); //~ ERROR cannot infer - | ^^^^^^^^ argument requires that `'1` must outlive `'a` + | ^^^^^^^^ `self` escapes the closure body here error: aborting due to previous error diff --git a/src/test/ui/issue-17758.nll.stderr b/src/test/ui/issue-17758.nll.stderr index 124fc6f0b3998..5775135aefc5f 100644 --- a/src/test/ui/issue-17758.nll.stderr +++ b/src/test/ui/issue-17758.nll.stderr @@ -10,13 +10,13 @@ warning: not reporting region error due to nll LL | self.foo(); | ^^^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/issue-17758.rs:17:9 | LL | fn bar(&self) { - | - let's call the lifetime of this reference `'1` + | ----- `self` is a reference that is only valid in the closure body LL | self.foo(); - | ^^^^^^^^^^ argument requires that `'1` must outlive `'a` + | ^^^^^^^^^^ `self` escapes the closure body here error: aborting due to previous error 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 8fd5e898c8d9b..d51ba8201aaa6 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,16 +4,16 @@ warning: not reporting region error due to nll LL | foo(cell, |cell_a, cell_x| { | ^^^ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20 | LL | foo(cell, |cell_a, cell_x| { - | ------ ------ lifetime `'1` appears in this argument + | ------ ------ `cell_x` is a reference that is only valid in the closure body | | - | lifetime `'2` appears in this argument + | `cell_a` is declared here, outside of the closure body LL | //~^ WARNING not reporting region error due to nll LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure - | ^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | ^^^^^^^^^^^^ `cell_x` escapes the closure body here note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15 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 f65e7161ca8c5..3177cd7c28f64 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 @@ -23,16 +23,18 @@ LL | | }); = note: number of external vids: 2 = note: where '_#1r: '_#0r -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5 | +LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { + | ------ `cell_a` is a reference that is only valid in the closure body LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | | //~^ ERROR LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll LL | | }); - | |______^ argument requires that `'a` must outlive `'static` + | |______^ `cell_a` escapes the closure body here note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1 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 f1b2c9f198d69..089c88abcdd4a 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 @@ -23,16 +23,18 @@ LL | | }); = note: number of external vids: 3 = note: where '_#1r: '_#0r -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5 | +LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { + | ------ `cell_a` is a reference that is only valid in the closure body LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { LL | | //~^ ERROR LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARNING not reporting region error due to nll LL | | }); - | |______^ argument requires that `'a` must outlive `'static` + | |______^ `cell_a` escapes the closure body here note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1 diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr index 48862166f897f..8acf2ef51ecd2 100644 --- a/src/test/ui/nll/issue-50716.stderr +++ b/src/test/ui/nll/issue-50716.stderr @@ -1,8 +1,11 @@ -error: unsatisfied lifetime constraints +error: borrowed data escapes outside of closure --> $DIR/issue-50716.rs:25:14 | +LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) + | - `s` is a reference that is only valid in the closure body +... LL | let _x = *s; //~ ERROR - | ^^ assignment requires that `'a` must outlive `'static` + | ^^ `s` escapes the closure body here error: aborting due to previous error