1
Fork 0

Auto merge of #54229 - davidtwco:issue-52534, r=pnkfelix

[nll] borrows that must be valid for a free lifetime should explain why

Fixes #52534.

r? @nikomatsakis
This commit is contained in:
bors 2018-09-23 15:00:53 +00:00
commit f49f6e73a8
21 changed files with 1340 additions and 433 deletions

View file

@ -1883,6 +1883,18 @@ impl<'tcx> Place<'tcx> {
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
Place::Projection(Box::new(PlaceProjection { base: self, elem }))
}
/// Find the innermost `Local` from this `Place`.
pub fn local(&self) -> Option<Local> {
match self {
Place::Local(local) |
Place::Projection(box Projection {
base: Place::Local(local),
elem: ProjectionElem::Deref,
}) => Some(*local),
_ => None,
}
}
}
impl<'tcx> Debug for Place<'tcx> {

View file

@ -1324,6 +1324,23 @@ impl_stable_hash_for!(struct DebruijnIndex { private });
/// Region utilities
impl RegionKind {
/// Is this region named by the user?
pub fn has_name(&self) -> bool {
match *self {
RegionKind::ReEarlyBound(ebr) => ebr.has_name(),
RegionKind::ReLateBound(_, br) => br.is_named(),
RegionKind::ReFree(fr) => fr.bound_region.is_named(),
RegionKind::ReScope(..) => false,
RegionKind::ReStatic => true,
RegionKind::ReVar(..) => false,
RegionKind::ReSkolemized(_, br) => br.is_named(),
RegionKind::ReEmpty => false,
RegionKind::ReErased => false,
RegionKind::ReClosureBound(..) => false,
RegionKind::ReCanonical(..) => false,
}
}
pub fn is_late_bound(&self) -> bool {
match *self {
ty::ReLateBound(..) => true,

View file

@ -34,7 +34,14 @@ 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_BOUND_REGION: Cell<Option<(ty::BoundRegion, usize)>> =
Cell::new(None)
}
macro_rules! gen_display_debug_body {
@ -564,12 +571,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_bound_region() -> Option<(ty::BoundRegion, usize)> {
HIGHLIGHT_REGION_FOR_BOUND_REGION.with(|hr| hr.get())
}
pub fn with_highlight_region_for_bound_region<R>(
r: ty::BoundRegion,
counter: usize,
op: impl Fn() -> R
) -> R {
HIGHLIGHT_REGION_FOR_BOUND_REGION.with(|hr| {
assert_eq!(hr.get(), None);
hr.set(Some((r, counter)));
let r = op();
@ -726,6 +755,15 @@ define_print! {
return self.print_debug(f, cx);
}
if let Some((region, counter)) = get_highlight_region_for_bound_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 +786,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 +961,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)

View file

@ -10,22 +10,26 @@
use borrow_check::{WriteKind, StorageDeadOrDrop};
use borrow_check::prefixes::IsPrefixOf;
use borrow_check::nll::explain_borrow::BorrowExplanation;
use rustc::middle::region::ScopeTree;
use rustc::mir::VarBindingForm;
use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local};
use rustc::mir::{FakeReadCause, LocalDecl, LocalKind, Location, Operand, Place};
use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind};
use rustc::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local,
LocalDecl, LocalKind, Location, Operand, Place, ProjectionElem, Rvalue, Statement,
StatementKind, TerminatorKind, VarBindingForm,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty;
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_bound_region;
use syntax_pos::Span;
use super::borrow_set::BorrowData;
use super::{Context, MirBorrowckCtxt};
use super::{InitializationRequiringAction, PrefixSet};
use borrow_check::nll::explain_borrow::BorrowContainsPointReason;
use dataflow::drop_flag_effects;
use dataflow::move_paths::indexes::MoveOutIndex;
use dataflow::move_paths::MovePathIndex;
@ -70,7 +74,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
let mut err = self.tcx.cannot_act_on_uninitialized_variable(
let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
span,
desired_action.as_noun(),
&self
@ -97,7 +101,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let msg = ""; //FIXME: add "partially " or "collaterally "
let mut err = self.tcx.cannot_act_on_moved_value(
let mut err = self.infcx.tcx.cannot_act_on_moved_value(
span,
desired_action.as_noun(),
msg,
@ -149,9 +153,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
if let Some(ty) = self.retrieve_type_for_place(place) {
let needs_note = match ty.sty {
ty::Closure(id, _) => {
let tables = self.tcx.typeck_tables_of(id);
let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
let tables = self.infcx.tcx.typeck_tables_of(id);
let node_id = self.infcx.tcx.hir.as_local_node_id(id).unwrap();
let hir_id = self.infcx.tcx.hir.node_to_hir_id(node_id);
if tables.closure_kind_origins().get(hir_id).is_some() {
false
} else {
@ -198,7 +202,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(place, _span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) {
let tcx = self.tcx;
let tcx = self.infcx.tcx;
let value_msg = match self.describe_place(place) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
@ -226,7 +230,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
move_spans.var_span_label(&mut err, "move occurs due to use in closure");
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
self.explain_why_borrow_contains_point(context, borrow, None)
.emit(self.infcx.tcx, &mut err);
err.buffer(&mut self.errors_buffer);
}
@ -236,7 +241,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(place, _span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) {
let tcx = self.tcx;
let tcx = self.infcx.tcx;
let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.args_or_use();
@ -263,7 +268,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
format!("borrow occurs due to use of `{}` in closure", desc_place)
});
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
self.explain_why_borrow_contains_point(context, borrow, None)
.emit(self.infcx.tcx, &mut err);
err.buffer(&mut self.errors_buffer);
}
@ -281,7 +287,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let span = borrow_spans.args_or_use();
let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
let tcx = self.tcx;
let tcx = self.infcx.tcx;
// FIXME: supply non-"" `opt_via` when appropriate
let mut err = match (
@ -390,7 +396,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
);
}
self.explain_why_borrow_contains_point(context, issued_borrow, None, &mut err);
self.explain_why_borrow_contains_point(context, issued_borrow, None)
.emit(self.infcx.tcx, &mut err);
err.buffer(&mut self.errors_buffer);
}
@ -417,7 +424,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
);
let drop_span = place_span.1;
let scope_tree = self.tcx.region_scope_tree(self.mir_def_id);
let scope_tree = self.infcx.tcx.region_scope_tree(self.mir_def_id);
let root_place = self
.prefixes(&borrow.borrowed_place, PrefixSet::All)
.last()
@ -445,47 +452,39 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
self.access_place_error_reported
.insert((root_place.clone(), borrow_span));
let borrow_reason = self.find_why_borrow_contains_point(context, borrow);
if let Some(WriteKind::StorageDeadOrDrop(StorageDeadOrDrop::Destructor)) = kind
{
if let Some(WriteKind::StorageDeadOrDrop(StorageDeadOrDrop::Destructor)) = kind {
// If a borrow of path `B` conflicts with drop of `D` (and
// we're not in the uninteresting case where `B` is a
// prefix of `D`), then report this as a more interesting
// destructor conflict.
if !borrow.borrowed_place.is_prefix_of(place_span.0) {
self.report_borrow_conflicts_with_destructor(
context, borrow, borrow_reason, place_span, kind);
self.report_borrow_conflicts_with_destructor(context, borrow, place_span, kind);
return;
}
}
let mut 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)
}
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(
context,
name,
&scope_tree,
&borrow,
borrow_reason,
drop_span,
borrow_span,
borrow_spans,
kind.map(|k| (k, place_span.0)),
),
None => self.report_temporary_value_does_not_live_long_enough(
context,
&scope_tree,
&borrow,
borrow_reason,
drop_span,
borrow_spans,
proper_span,
),
};
borrow_spans.args_span_label(&mut err, "value captured here");
err.buffer(&mut self.errors_buffer);
}
@ -495,31 +494,69 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
name: &String,
scope_tree: &Lrc<ScopeTree>,
borrow: &BorrowData<'tcx>,
reason: BorrowContainsPointReason<'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, reason, drop_span, borrow_span
context, name, scope_tree, borrow, drop_span, borrow_spans
);
let mut err = self.tcx.path_does_not_live_long_enough(
let borrow_span = borrow_spans.var_or_use();
let mut err = self.infcx.tcx.path_does_not_live_long_enough(
borrow_span,
&format!("`{}`", name),
Origin::Mir,
);
err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(
drop_span,
format!("`{}` dropped here while still borrowed", name),
);
let explanation = self.explain_why_borrow_contains_point(context, borrow, kind_place);
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, region_name)
);
if let Some(fn_node_id) = self.infcx.tcx.hir.as_local_node_id(self.mir_def_id) {
err.span_label(
drop_span,
format!(
"...but `{}` will be dropped here, when the function `{}` returns",
name, self.infcx.tcx.hir.name(fn_node_id),
)
);
err.note(
"functions cannot return a borrow to data owned within the function's scope, \
functions can only return borrows to data passed as arguments",
);
err.note(
"to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-\
references-and-borrowing.html#dangling-references>",
);
} else {
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));
borrow_spans.args_span_label(&mut err, "value captured here");
explanation.emit(self.infcx.tcx, &mut err);
}
self.report_why_borrow_contains_point(&mut err, reason, kind_place);
err
}
@ -527,36 +564,32 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
&mut self,
context: Context,
borrow: &BorrowData<'tcx>,
borrow_reason: BorrowContainsPointReason<'tcx>,
place_span: (&Place<'tcx>, Span),
(place, drop_span): (&Place<'tcx>, Span),
kind: Option<WriteKind>,
) {
debug!(
"report_borrow_conflicts_with_destructor(\
{:?}, {:?}, {:?}, {:?} {:?}\
{:?}, {:?}, ({:?}, {:?}), {:?}\
)",
context, borrow, borrow_reason, place_span, kind,
context, borrow, place, drop_span, kind,
);
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 drop_span = place_span.1;
let mut err = self.infcx.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir);
let (what_was_dropped, dropped_ty) = {
let place = place_span.0;
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}`, \
@ -571,17 +604,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
};
err.span_label(drop_span, label);
// Only give this note and suggestion if they could be relevant
match borrow_reason {
BorrowContainsPointReason::Liveness {..}
| BorrowContainsPointReason::DropLiveness {..} => {
// Only give this note and suggestion if they could be relevant.
let explanation = self.explain_why_borrow_contains_point(
context, borrow, kind.map(|k| (k, place)),
);
match explanation {
BorrowExplanation::UsedLater {..} |
BorrowExplanation::UsedLaterWhenDropped {..} => {
err.note("consider using a `let` binding to create a longer lived value");
}
BorrowContainsPointReason::OutlivesFreeRegion {..} => (),
},
_ => {},
}
self.report_why_borrow_contains_point(
&mut err, borrow_reason, kind.map(|k| (k, place_span.0)));
explanation.emit(self.infcx.tcx, &mut err);
err.buffer(&mut self.errors_buffer);
}
@ -598,15 +633,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
drop_span, borrow_span
);
let mut err = self
.tcx
.thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
let mut err = self.infcx.tcx.thread_local_value_does_not_live_long_enough(
borrow_span, Origin::Mir
);
err.span_label(
borrow_span,
"thread-local variables cannot be borrowed beyond the end of the function",
);
err.span_label(drop_span, "end of enclosing function is here");
err
}
@ -615,33 +651,37 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
context: Context,
scope_tree: &Lrc<ScopeTree>,
borrow: &BorrowData<'tcx>,
reason: BorrowContainsPointReason<'tcx>,
drop_span: Span,
borrow_spans: UseSpans,
proper_span: Span,
) -> DiagnosticBuilder<'cx> {
debug!(
"report_temporary_value_does_not_live_long_enough(\
{:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
{:?}, {:?}, {:?}, {:?}, {:?}\
)",
context, scope_tree, borrow, reason, drop_span, proper_span
context, scope_tree, borrow, drop_span, proper_span
);
let tcx = self.tcx;
let tcx = self.infcx.tcx;
let mut err =
tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
err.span_label(proper_span, "temporary value does not live long enough");
err.span_label(drop_span, "temporary value only lives until here");
// Only give this note and suggestion if they could be relevant
match reason {
BorrowContainsPointReason::Liveness {..}
| BorrowContainsPointReason::DropLiveness {..} => {
let explanation = self.explain_why_borrow_contains_point(context, borrow, None);
match explanation {
BorrowExplanation::UsedLater(..) |
BorrowExplanation::UsedLaterInLoop(..) |
BorrowExplanation::UsedLaterWhenDropped(..) => {
// Only give this note and suggestion if it could be relevant.
err.note("consider using a `let` binding to create a longer lived value");
}
BorrowContainsPointReason::OutlivesFreeRegion {..} => (),
},
_ => {},
}
explanation.emit(self.infcx.tcx, &mut err);
borrow_spans.args_span_label(&mut err, "value captured here");
self.report_why_borrow_contains_point(&mut err, reason, None);
err
}
@ -715,7 +755,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// check for inits
let mut any_match = false;
drop_flag_effects::for_location_inits(self.tcx, self.mir, self.move_data, l, |m| {
drop_flag_effects::for_location_inits(self.infcx.tcx, self.mir, self.move_data, l, |m| {
if m == mpi {
any_match = true;
}
@ -739,7 +779,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let loan_spans = self.retrieve_borrow_spans(loan);
let loan_span = loan_spans.args_or_use();
let tcx = self.tcx;
let tcx = self.infcx.tcx;
let mut err = tcx.cannot_assign_to_borrowed(
span,
loan_span,
@ -749,7 +789,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
self.explain_why_borrow_contains_point(context, loan, None, &mut err);
self.explain_why_borrow_contains_point(context, loan, None).emit(self.infcx.tcx, &mut err);
err.buffer(&mut self.errors_buffer);
}
@ -801,7 +841,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Some(decl) => (self.describe_place(err_place), decl.source_info.span),
};
let mut err = self.tcx.cannot_reassign_immutable(
let mut err = self.infcx.tcx.cannot_reassign_immutable(
span,
place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
from_arg,
@ -879,13 +919,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
self.append_local_to_string(local, buf)?;
}
Place::Static(ref static_) => {
buf.push_str(&self.tcx.item_name(static_.def_id).to_string());
buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
}
Place::Projection(ref proj) => {
match proj.elem {
ProjectionElem::Deref => {
let upvar_field_projection =
place.is_upvar_field_projection(self.mir, &self.tcx);
place.is_upvar_field_projection(self.mir, &self.infcx.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();
@ -947,7 +987,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
autoderef = true;
let upvar_field_projection =
place.is_upvar_field_projection(self.mir, &self.tcx);
place.is_upvar_field_projection(self.mir, &self.infcx.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();
@ -1062,10 +1102,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// the local code in the current crate, so this returns an `Option` in case
// the closure comes from another crate. But in that case we wouldn't
// be borrowck'ing it, so we can just unwrap:
let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
let node_id = self.infcx.tcx.hir.as_local_node_id(def_id).unwrap();
let freevar = self.infcx.tcx.with_freevars(node_id, |fv| fv[field.index()]);
self.tcx.hir.name(freevar.var_id()).to_string()
self.infcx.tcx.hir.name(freevar.var_id()).to_string()
}
_ => {
// Might need a revision when the fields in trait RFC is implemented
@ -1098,7 +1138,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
/// Check if a place is a thread-local static.
pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
if let Place::Static(statik) = place {
let attrs = self.tcx.get_attrs(statik.def_id);
let attrs = self.infcx.tcx.get_attrs(statik.def_id);
let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
debug!(
@ -1126,6 +1166,481 @@ 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> {
// Define a fallback for when we can't match a closure.
let fallback = || {
let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
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,
}
}
};
// In order to determine whether we need to annotate, we need to check whether the reserve
// place was an assignment into a temporary.
//
// If it was, we check whether or not that temporary is eventually assigned into the return
// place. If it was, we can add annotations about the function's return type and arguments
// and it'll make sense.
let location = borrow.reserve_location;
debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
match &self.mir[location.block].statements.get(location.statement_index) {
Some(&Statement {
kind: StatementKind::Assign(ref reservation, _),
..
}) => {
debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
// Check that the initial assignment of the reserve location is into a temporary.
let mut target = *match reservation {
Place::Local(local) if self.mir.local_kind(*local) == LocalKind::Temp => local,
_ => return None,
};
// Next, look through the rest of the block, checking if we are assigning the
// `target` (that is, the place that contains our borrow) to anything.
let mut annotated_closure = None;
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
debug!(
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
target, stmt
);
if let StatementKind::Assign(
Place::Local(assigned_to),
rvalue,
) = &stmt.kind {
debug!("annotate_argument_and_return_for_borrow: assigned_to={:?} \
rvalue={:?}", assigned_to, rvalue);
// Check if our `target` was captured by a closure.
if let Rvalue::Aggregate(
box AggregateKind::Closure(def_id, substs),
operands,
) = rvalue {
for operand in operands {
let assigned_from = match operand {
Operand::Copy(assigned_from) |
Operand::Move(assigned_from) => assigned_from,
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from
);
// Find the local from the operand.
let assigned_from_local = match assigned_from.local() {
Some(local) => local,
None => continue,
};
if assigned_from_local != target {
continue;
}
// If a closure captured our `target` and then assigned
// into a place then we should annotate the closure in
// case it ends up being assigned into the return place.
annotated_closure = self.annotate_fn_sig(
*def_id,
self.infcx.closure_sig(*def_id, *substs)
);
debug!(
"annotate_argument_and_return_for_borrow: \
annotated_closure={:?} assigned_from_local={:?} \
assigned_to={:?}",
annotated_closure, assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
// If it was assigned directly into the return place, then
// return now.
return annotated_closure;
} else {
// Otherwise, update the target.
target = *assigned_to;
}
}
// If none of our closure's operands matched, then skip to the next
// statement.
continue;
}
// Otherwise, look at other types of assignment.
let assigned_from = match rvalue {
Rvalue::Ref(_, _, assigned_from) => assigned_from,
Rvalue::Use(operand) => match operand {
Operand::Copy(assigned_from) |
Operand::Move(assigned_from) => assigned_from,
_ => continue,
},
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from={:?}", assigned_from,
);
// Find the local from the rvalue.
let assigned_from_local = match assigned_from.local() {
Some(local) => local,
None => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?}", assigned_from_local,
);
// Check if our local matches the target - if so, we've assigned our
// borrow to a new place.
if assigned_from_local != target {
continue;
}
// If we assigned our `target` into a new place, then we should
// check if it was the return place.
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?} assigned_to={:?}",
assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
// If it was then return the annotated closure if there was one,
// else, annotate this function.
return annotated_closure.or_else(fallback);
}
// If we didn't assign into the return place, then we just update
// the target.
target = *assigned_to;
}
}
// Check the terminator if we didn't find anything in the statements.
let terminator = &self.mir[location.block].terminator();
debug!(
"annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
target, terminator
);
if let TerminatorKind::Call {
destination: Some((Place::Local(assigned_to), _)),
args,
..
} = &terminator.kind {
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
assigned_to, args
);
for operand in args {
let assigned_from = match operand {
Operand::Copy(assigned_from) |
Operand::Move(assigned_from) => assigned_from,
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from,
);
if let Some(assigned_from_local) = assigned_from.local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
assigned_from_local,
);
if *assigned_to == mir::RETURN_PLACE &&
assigned_from_local == target
{
return annotated_closure.or_else(fallback);
}
}
}
}
}
_ => {}
}
// If we haven't found an assignment into the return place, then we need not add
// any annotations.
debug!("annotate_argument_and_return_for_borrow: none found");
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> {
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
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)?;
// We need to work out which arguments to highlight. We do this by looking
// at the return type, where there are three cases:
//
// 1. If there are named arguments, then we should highlight the return type and
// highlight any of the arguments that are also references with that lifetime.
// If there are no arguments that have the same lifetime as the return type,
// then don't highlight anything.
// 2. The return type is a reference with an anonymous lifetime. If this is
// the case, then we can take advantage of (and teach) the lifetime elision
// rules.
//
// We know that an error is being reported. So the arguments and return type
// must satisfy the elision rules. Therefore, if there is a single argument
// then that means the return type and first (and only) argument have the same
// lifetime and the borrow isn't meeting that, we can highlight the argument
// and return type.
//
// If there are multiple arguments then the first argument must be self (else
// it would not satisfy the elision rules), so we can highlight self and the
// return type.
// 3. The return type is not a reference. In this case, we don't highlight
// anything.
let return_ty = sig.output();
match return_ty.skip_binder().sty {
ty::TyKind::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
// This is case 1 from above, return type is a named reference so we need to
// search for relevant arguments.
let mut arguments = Vec::new();
for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
if let ty::TyKind::Ref(argument_region, _, _) = argument.sty {
if argument_region == return_region {
// Need to use the `rustc::ty` types to compare against the
// `return_region`. Then use the `rustc::hir` type to get only
// the lifetime span.
match &fn_decl.inputs[index].node {
hir::TyKind::Rptr(lifetime, _) => {
// With access to the lifetime, we can get
// the span of it.
arguments.push((*argument, lifetime.span));
},
_ => bug!("ty type is a ref but hir type is not"),
}
}
}
}
// We need to have arguments. This shouldn't happen, but it's worth checking.
if arguments.is_empty() {
return None;
}
// We use a mix of the HIR and the Ty types to get information
// as the HIR doesn't have full types for closure arguments.
let return_ty = *sig.output().skip_binder();
let mut return_span = fn_decl.output.span();
if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
if let hir::TyKind::Rptr(lifetime, _) = ty.into_inner().node {
return_span = lifetime.span;
}
}
Some(AnnotatedBorrowFnSignature::NamedFunction {
arguments,
return_ty,
return_span,
})
},
ty::TyKind::Ref(_, _, _) if is_closure => {
// This is case 2 from above but only for closures, return type is anonymous
// reference so we select
// the first argument.
let argument_span = fn_decl.inputs.first()?.span;
let argument_ty = sig.inputs().skip_binder().first()?;
// Closure arguments are wrapped in a tuple, so we need to get the first
// from that.
if let ty::TyKind::Tuple(elems) = argument_ty.sty {
let argument_ty = elems.first()?;
if let ty::TyKind::Ref(_, _, _) = argument_ty.sty {
return Some(AnnotatedBorrowFnSignature::Closure {
argument_ty,
argument_span,
});
}
}
None
},
ty::TyKind::Ref(_, _, _) => {
// This is also case 2 from above but for functions, return type is still an
// anonymous reference so we select the first argument.
let argument_span = fn_decl.inputs.first()?.span;
let argument_ty = sig.inputs().skip_binder().first()?;
let return_span = fn_decl.output.span();
let return_ty = *sig.output().skip_binder();
// We expect the first argument to be a reference.
match argument_ty.sty {
ty::TyKind::Ref(_, _, _) => {},
_ => return None,
}
Some(AnnotatedBorrowFnSignature::AnonymousFunction {
argument_ty,
argument_span,
return_ty,
return_span,
})
},
_ => {
// This is case 3 from above, return type is not a reference so don't highlight
// anything.
None
},
}
}
}
#[derive(Debug)]
enum AnnotatedBorrowFnSignature<'tcx> {
NamedFunction {
arguments: Vec<(ty::Ty<'tcx>, Span)>,
return_ty: ty::Ty<'tcx>,
return_span: Span,
},
AnonymousFunction {
argument_ty: ty::Ty<'tcx>,
argument_span: Span,
return_ty: ty::Ty<'tcx>,
return_span: Span,
},
Closure {
argument_ty: ty::Ty<'tcx>,
argument_span: Span,
}
}
impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
/// Annotate the provided diagnostic with information about borrow from the fn signature that
/// helps explain.
fn emit(
&self,
diag: &mut DiagnosticBuilder<'_>
) -> String {
match self {
AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
diag.span_label(
*argument_span,
format!("has type `{}`", self.get_name_for_ty(argument_ty, 0)),
);
self.get_region_name_for_ty(argument_ty, 0)
},
AnnotatedBorrowFnSignature::AnonymousFunction {
argument_ty,
argument_span,
return_ty,
return_span,
} => {
let argument_ty_name = self.get_name_for_ty(argument_ty, 0);
diag.span_label(
*argument_span,
format!("has type `{}`", argument_ty_name)
);
let return_ty_name = self.get_name_for_ty(return_ty, 0);
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,
)
);
diag.note(
"argument and return type have the same lifetime due to lifetime elision rules",
);
diag.note(
"to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch10-03-\
lifetime-syntax.html#lifetime-elision>",
);
self.get_region_name_for_ty(return_ty, 0)
},
AnnotatedBorrowFnSignature::NamedFunction {
arguments,
return_ty,
return_span,
} => {
// Region of return type and arguments checked to be the same earlier.
let region_name = self.get_region_name_for_ty(return_ty, 0);
for (_, argument_span) in arguments {
diag.span_label(
*argument_span,
format!("has lifetime `{}`", region_name)
);
}
diag.span_label(
*return_span,
format!(
"also has lifetime `{}`",
region_name,
)
);
diag.help(
&format!(
"use data from the highlighted arguments which match the `{}` lifetime of \
the return type",
region_name,
),
);
region_name
},
}
}
/// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
/// name where required.
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_bound_region(*br, counter, || format!("{}", ty)),
_ => format!("{}", ty),
}
}
/// Return the name of the provided `Ty` (that must be a reference)'s region with a
/// synthesized lifetime name where required.
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_bound_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.
@ -1214,9 +1729,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
if let AggregateKind::Closure(def_id, _) = **kind {
debug!("find_closure_move_span: found closure {:?}", places);
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
if let Closure(_, _, _, args_span, _) = self.tcx.hir.expect_expr(node_id).node {
if let Some(var_span) = self.tcx.with_freevars(node_id, |freevars| {
if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) {
if let Closure(
_, _, _, args_span, _
) = self.infcx.tcx.hir.expect_expr(node_id).node {
if let Some(var_span) = self.infcx.tcx.with_freevars(node_id, |freevars| {
for (v, place) in freevars.iter().zip(places) {
match place {
Operand::Copy(place) | Operand::Move(place)
@ -1253,7 +1770,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
@ -1276,16 +1792,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
if let AggregateKind::Closure(def_id, _) = **kind {
debug!("find_closure_borrow_span: found closure {:?}", places);
return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
return if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) {
let args_span = if let Closure(_, _, _, span, _) =
self.tcx.hir.expect_expr(node_id).node
self.infcx.tcx.hir.expect_expr(node_id).node
{
span
} else {
return OtherUse(use_span);
};
self.tcx
self.infcx.tcx
.with_freevars(node_id, |freevars| {
for (v, place) in freevars.iter().zip(places) {
match *place {

View file

@ -247,8 +247,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let dominators = mir.dominators();
let mut mbcx = MirBorrowckCtxt {
tcx: tcx,
mir: mir,
infcx,
mir,
mir_def_id: def_id,
move_data: &mdpe.move_data,
param_env: param_env,
@ -369,7 +369,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
}
for diag in mbcx.errors_buffer.drain(..) {
DiagnosticBuilder::new_diagnostic(mbcx.tcx.sess.diagnostic(), diag).emit();
DiagnosticBuilder::new_diagnostic(mbcx.infcx.tcx.sess.diagnostic(), diag).emit();
}
}
@ -384,7 +384,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
}
pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
mir: &'cx Mir<'tcx>,
mir_def_id: DefId,
move_data: &'cx MoveData<'tcx>,
@ -612,13 +612,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
target: _,
unwind: _,
} => {
let gcx = self.tcx.global_tcx();
let gcx = self.infcx.tcx.global_tcx();
// Compute the type with accurate region information.
let drop_place_ty = drop_place.ty(self.mir, self.tcx);
let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx);
// Erase the regions.
let drop_place_ty = self.tcx.erase_regions(&drop_place_ty).to_ty(self.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
@ -953,7 +954,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
return;
}
let gcx = self.tcx.global_tcx();
let gcx = self.infcx.tcx.global_tcx();
let drop_field = |mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
(index, field): (usize, ty::Ty<'gcx>)| {
let field_ty = gcx.normalize_erasing_regions(mir.param_env, field);
@ -971,7 +972,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// individual fields instead. This way if `foo` has a
// destructor but `bar` does not, we will only check for
// borrows of `x.foo` and not `x.bar`. See #47703.
ty::Adt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => {
ty::Adt(def, substs) if def.is_struct() && !def.has_dtor(self.infcx.tcx) => {
def.all_fields()
.map(|field| field.ty(gcx, substs))
.enumerate()
@ -991,7 +992,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
&& !self.mir.upvar_decls.is_empty() =>
{
substs
.upvar_tys(def, self.tcx)
.upvar_tys(def, self.infcx.tcx)
.enumerate()
.for_each(|field| drop_field(self, field));
}
@ -1002,7 +1003,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
&& !self.mir.upvar_decls.is_empty() =>
{
substs
.upvar_tys(def, self.tcx)
.upvar_tys(def, self.infcx.tcx)
.enumerate()
.for_each(|field| drop_field(self, field));
}
@ -1168,7 +1169,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
);
let mut error_reported = false;
let tcx = self.tcx;
let tcx = self.infcx.tcx;
let mir = self.mir;
let location = self.location_table.start_index(context.loc);
let borrow_set = self.borrow_set.clone();
@ -1206,7 +1207,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(&this.dominators, borrow, context.loc) {
assert!(allow_two_phase_borrow(&this.tcx, borrow.kind));
assert!(allow_two_phase_borrow(&this.infcx.tcx, borrow.kind));
return Control::Continue;
}
@ -1338,7 +1339,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Unique | BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(&self.tcx, bk) {
if allow_two_phase_borrow(&self.infcx.tcx, bk) {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))
@ -1413,7 +1414,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
| AggregateKind::Generator(def_id, _, _) => {
let BorrowCheckResult {
used_mut_upvars, ..
} = self.tcx.mir_borrowck(def_id);
} = self.infcx.tcx.mir_borrowck(def_id);
debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
for field in used_mut_upvars {
// This relies on the current way that by-value
@ -1427,7 +1428,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Operand::Move(ref place @ Place::Projection(_))
| Operand::Copy(ref place @ Place::Projection(_)) => {
if let Some(field) = place.is_upvar_field_projection(
self.mir, &self.tcx) {
self.mir, &self.infcx.tcx) {
self.used_mut_upvars.push(field);
}
}
@ -1546,11 +1547,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// that is merged.
let sd = if might_be_alive { Deep } else { Shallow(None) };
if places_conflict::places_conflict(self.tcx, self.mir, place, root_place, sd) {
if places_conflict::places_conflict(self.infcx.tcx, self.mir, place, root_place, sd) {
debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
// FIXME: should be talking about the region lifetime instead
// of just a span here.
let span = self.tcx.sess.source_map().end_point(span);
let span = self.infcx.tcx.sess.source_map().end_point(span);
self.report_borrowed_value_does_not_live_long_enough(
context,
borrow,
@ -1566,7 +1567,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
debug!("check_for_local_borrow({:?})", borrow);
if borrow_of_local_data(&borrow.borrowed_place) {
let err = self.tcx
let err = self.infcx.tcx
.cannot_borrow_across_generator_yield(
self.retrieve_borrow_spans(borrow).var_or_use(),
yield_span,
@ -1583,7 +1584,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
span: Span,
flow_state: &Flows<'cx, 'gcx, 'tcx>,
) {
if !self.tcx.two_phase_borrows() {
if !self.infcx.tcx.two_phase_borrows() {
return;
}
@ -1845,7 +1846,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// if type of `P` has a dtor, then
// assigning to `P.f` requires `P` itself
// be already initialized
let tcx = self.tcx;
let tcx = self.infcx.tcx;
match base.ty(self.mir, tcx).to_ty(tcx).sty {
ty::Adt(def, _) if def.has_dtor(tcx) => {
self.check_if_path_or_subpath_is_moved(
@ -1929,7 +1930,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
| Write(wk @ WriteKind::StorageDeadOrDrop(_))
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => {
if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
if self.tcx.migrate_borrowck() {
if self.infcx.tcx.migrate_borrowck() {
// rust-lang/rust#46908: In pure NLL mode this
// code path should be unreachable (and thus
// we signal an ICE in the else branch
@ -1952,7 +1953,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
location,
);
} else {
self.tcx.sess.delay_span_bug(
self.infcx.tcx.sess.delay_span_bug(
span,
&format!(
"Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
@ -2020,7 +2021,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
place: place @ Place::Projection(_),
is_local_mutation_allowed: _,
} => {
if let Some(field) = place.is_upvar_field_projection(self.mir, &self.tcx) {
if let Some(field) = place.is_upvar_field_projection(self.mir, &self.infcx.tcx) {
self.used_mut_upvars.push(field);
}
}
@ -2070,7 +2071,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
is_local_mutation_allowed,
}),
Place::Static(ref static_) => {
if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
Err(place)
} else {
Ok(RootPlace {
@ -2082,7 +2083,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Place::Projection(ref proj) => {
match proj.elem {
ProjectionElem::Deref => {
let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
let base_ty = proj.base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
// Check the kind of deref to decide
match base_ty.sty {
@ -2094,7 +2095,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// unique path to the `&mut`
hir::MutMutable => {
let mode = match place.is_upvar_field_projection(
self.mir, &self.tcx)
self.mir, &self.infcx.tcx)
{
Some(field)
if {
@ -2140,7 +2141,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..) => {
let upvar_field_projection = place.is_upvar_field_projection(
self.mir, &self.tcx);
self.mir, &self.infcx.tcx);
if let Some(field) = upvar_field_projection {
let decl = &self.mir.upvar_decls[field.index()];
debug!(

View file

@ -244,30 +244,31 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
let origin = Origin::Mir;
debug!("report: original_path={:?} span={:?}, kind={:?} \
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
original_path.is_upvar_field_projection(self.mir, &self.tcx));
original_path.is_upvar_field_projection(self.mir, &self.infcx.tcx));
(
match kind {
IllegalMoveOriginKind::Static => {
self.tcx.cannot_move_out_of(span, "static item", origin)
self.infcx.tcx.cannot_move_out_of(span, "static item", origin)
}
IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
// Inspect the type of the content behind the
// borrow to provide feedback about why this
// was a move rather than a copy.
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);
let is_upvar_field_projection =
self.prefixes(&original_path, PrefixSet::All)
.any(|p| p.is_upvar_field_projection(self.mir, &self.tcx)
.any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx)
.is_some());
match ty.sty {
ty::Array(..) | ty::Slice(..) => self
.tcx
.cannot_move_out_of_interior_noncopy(span, ty, None, origin),
ty::Array(..) | ty::Slice(..) =>
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
span, ty, None, origin
),
ty::Closure(def_id, closure_substs)
if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection
=> {
let closure_kind_ty =
closure_substs.closure_kind_ty(def_id, self.tcx);
closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
let closure_kind = closure_kind_ty.to_opt_closure_kind();
let place_description = match closure_kind {
Some(ty::ClosureKind::Fn) => {
@ -285,18 +286,18 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
place_description={:?}", closure_kind_ty, closure_kind,
place_description);
let mut diag = self.tcx.cannot_move_out_of(
let mut diag = self.infcx.tcx.cannot_move_out_of(
span, place_description, origin);
for prefix in self.prefixes(&original_path, PrefixSet::All) {
if let Some(field) = prefix.is_upvar_field_projection(
self.mir, &self.tcx) {
self.mir, &self.infcx.tcx) {
let upvar_decl = &self.mir.upvar_decls[field.index()];
let upvar_hir_id =
upvar_decl.var_hir_id.assert_crate_local();
let upvar_node_id =
self.tcx.hir.hir_to_node_id(upvar_hir_id);
let upvar_span = self.tcx.hir.span(upvar_node_id);
self.infcx.tcx.hir.hir_to_node_id(upvar_hir_id);
let upvar_span = self.infcx.tcx.hir.span(upvar_node_id);
diag.span_label(upvar_span, "captured outer variable");
break;
}
@ -304,18 +305,19 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
diag
}
_ => self
.tcx
.cannot_move_out_of(span, "borrowed content", origin),
_ => self.infcx.tcx.cannot_move_out_of(
span, "borrowed content", origin
),
}
}
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
self.tcx
self.infcx.tcx
.cannot_move_out_of_interior_of_drop(span, ty, origin)
}
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => self
.tcx
.cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index), origin),
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
span, ty, Some(*is_index), origin
),
},
span,
)
@ -331,7 +333,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
err: &mut DiagnosticBuilder<'a>,
span: Span,
) {
let snippet = self.tcx.sess.source_map().span_to_snippet(span).unwrap();
let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap();
match error {
GroupedMoveError::MovesFromPlace {
mut binds_to,
@ -394,8 +396,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
..
}))
) = bind_to.is_user_variable {
let pat_snippet = self
.tcx.sess.source_map()
let pat_snippet = self.infcx.tcx.sess.source_map()
.span_to_snippet(pat_span)
.unwrap();
if pat_snippet.starts_with('&') {

View file

@ -71,11 +71,11 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
elem: ProjectionElem::Field(upvar_index, _),
}) => {
debug_assert!(is_closure_or_generator(
base.ty(self.mir, self.tcx).to_ty(self.tcx)
base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx)
));
item_msg = format!("`{}`", access_place_desc.unwrap());
if access_place.is_upvar_field_projection(self.mir, &self.tcx).is_some() {
if access_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
let name = self.mir.upvar_decls[upvar_index.index()].debug_name;
@ -91,11 +91,11 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
item_msg = format!("`{}`", access_place_desc.unwrap());
debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr());
debug_assert!(is_closure_or_generator(
the_place_err.ty(self.mir, self.tcx).to_ty(self.tcx)
the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx)
));
reason = if access_place.is_upvar_field_projection(self.mir,
&self.tcx).is_some() {
&self.infcx.tcx).is_some() {
", as it is a captured variable in a `Fn` closure".to_string()
} else {
", as `Fn` closures cannot mutate their captured variables".to_string()
@ -116,7 +116,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
reason = ", as it is immutable for the pattern guard".to_string();
} else {
let pointer_type =
if base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() {
if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_region_ptr() {
"`&` reference"
} else {
"`*const` pointer"
@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
reason = String::new();
} else {
item_msg = format!("`{}`", access_place_desc.unwrap());
let static_name = &self.tcx.item_name(*def_id);
let static_name = &self.infcx.tcx.item_name(*def_id);
reason = format!(", as `{}` is an immutable static item", static_name);
}
}
@ -177,14 +177,14 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
let span = match error_access {
AccessKind::Move => {
err = self.tcx
err = self.infcx.tcx
.cannot_move_out_of(span, &(item_msg + &reason), Origin::Mir);
act = "move";
acted_on = "moved";
span
}
AccessKind::Mutate => {
err = self.tcx
err = self.infcx.tcx
.cannot_assign(span, &(item_msg + &reason), Origin::Mir);
act = "assign";
acted_on = "written";
@ -196,7 +196,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
let borrow_spans = self.borrow_spans(span, location);
let borrow_span = borrow_spans.args_or_use();
err = self.tcx.cannot_borrow_path_as_mutable_because(
err = self.infcx.tcx.cannot_borrow_path_as_mutable_because(
borrow_span,
&item_msg,
&reason,
@ -242,7 +242,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
elem: ProjectionElem::Field(upvar_index, _),
}) => {
debug_assert!(is_closure_or_generator(
base.ty(self.mir, self.tcx).to_ty(self.tcx)
base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx)
));
err.span_label(span, format!("cannot {ACT}", ACT = act));
@ -250,8 +250,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
let upvar_hir_id = self.mir.upvar_decls[upvar_index.index()]
.var_hir_id
.assert_crate_local();
let upvar_node_id = self.tcx.hir.hir_to_node_id(upvar_hir_id);
if let Some(Node::Binding(pat)) = self.tcx.hir.find(upvar_node_id) {
let upvar_node_id = self.infcx.tcx.hir.hir_to_node_id(upvar_hir_id);
if let Some(Node::Binding(pat)) = self.infcx.tcx.hir.find(upvar_node_id) {
if let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated,
_,
@ -274,7 +274,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
// a local variable, then just suggest the user remove it.
Place::Local(_)
if {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
snippet.starts_with("&mut ")
} else {
false
@ -317,7 +317,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
let local_decl = &self.mir.local_decls[*local];
let suggestion = match local_decl.is_user_variable.as_ref().unwrap() {
ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => {
Some(suggest_ampmut_self(self.tcx, local_decl))
Some(suggest_ampmut_self(self.infcx.tcx, local_decl))
}
ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
@ -325,7 +325,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
opt_ty_info,
..
})) => Some(suggest_ampmut(
self.tcx,
self.infcx.tcx,
self.mir,
*local,
local_decl,
@ -337,7 +337,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
..
})) => {
let pattern_span = local_decl.source_info.span;
suggest_ref_mut(self.tcx, pattern_span)
suggest_ref_mut(self.infcx.tcx, pattern_span)
.map(|replacement| (pattern_span, replacement))
}
@ -426,11 +426,11 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
..
}
) = &self.mir.basic_blocks()[location.block].terminator {
if self.tcx.parent(id) == self.tcx.lang_items().index_trait() {
let index_trait = self.infcx.tcx.lang_items().index_trait();
if self.infcx.tcx.parent(id) == index_trait {
let mut found = false;
self.tcx.for_each_relevant_impl(
self.tcx.lang_items().index_mut_trait().unwrap(),
self.infcx.tcx.for_each_relevant_impl(
self.infcx.tcx.lang_items().index_mut_trait().unwrap(),
substs.type_at(0),
|_relevant_impl| {
found = true;

View file

@ -121,9 +121,7 @@ struct DefUseVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
enum DefUseResult {
Def,
UseLive { local: Local },
UseDrop { local: Local },
}

View file

@ -11,26 +11,71 @@
use borrow_check::borrow_set::BorrowData;
use borrow_check::nll::region_infer::Cause;
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
use rustc::mir::{FakeReadCause, Local, Location, Place, TerminatorKind};
use rustc::ty::{Region, TyCtxt};
use rustc::mir::{FakeReadCause, Location, Place, TerminatorKind};
use rustc_errors::DiagnosticBuilder;
use rustc::ty::Region;
use syntax_pos::Span;
use syntax_pos::symbol::Symbol;
mod find_use;
#[derive(Copy, Clone, Debug)]
pub enum BorrowContainsPointReason<'tcx> {
Liveness {
local: Local,
location: Location,
in_loop: bool,
},
DropLiveness {
local: Local,
location: Location,
},
OutlivesFreeRegion {
outlived_region: Option<Region<'tcx>>,
},
pub(in borrow_check) enum BorrowExplanation<'tcx> {
UsedLater(bool, Option<FakeReadCause>, Span),
UsedLaterInLoop(bool, Span),
UsedLaterWhenDropped(Span, Symbol, bool),
MustBeValidFor(Region<'tcx>),
Unexplained,
}
impl<'tcx> BorrowExplanation<'tcx> {
pub(in borrow_check) fn emit<'cx, 'gcx>(
&self,
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
err: &mut DiagnosticBuilder<'_>
) {
match *self {
BorrowExplanation::UsedLater(is_in_closure, fake_read_cause, var_or_use_span) => {
let message = if is_in_closure {
"borrow later captured here by closure"
} else if let Some(FakeReadCause::ForLet) = fake_read_cause {
"borrow later stored here"
} else {
"borrow later used here"
};
err.span_label(var_or_use_span, message);
},
BorrowExplanation::UsedLaterInLoop(is_in_closure, var_or_use_span) => {
let message = if is_in_closure {
"borrow captured here by closure in later iteration of loop"
} else {
"borrow used here in later iteration of loop"
};
err.span_label(var_or_use_span, message);
},
BorrowExplanation::UsedLaterWhenDropped(span, local_name, should_note_order) => {
err.span_label(
span,
format!("borrow later used here, when `{}` is dropped", local_name),
);
if should_note_order {
err.note(
"values in a scope are dropped \
in the opposite order they are defined",
);
}
},
BorrowExplanation::MustBeValidFor(region) => {
tcx.note_and_explain_free_region(
err,
"borrowed value must be valid for ",
region,
"...",
);
},
_ => {},
}
}
}
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
@ -53,23 +98,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
context: Context,
borrow: &BorrowData<'tcx>,
kind_place: Option<(WriteKind, &Place<'tcx>)>,
err: &mut DiagnosticBuilder<'_>,
) {
let reason = self.find_why_borrow_contains_point(context, borrow);
self.report_why_borrow_contains_point(err, reason, kind_place);
}
/// Finds the reason that [explain_why_borrow_contains_point] will report
/// but doesn't add it to any message. This is a separate function in case
/// the caller wants to change the error they report based on the reason
/// that will be reported.
pub(in borrow_check) fn find_why_borrow_contains_point(
&self,
context: Context,
borrow: &BorrowData<'tcx>
) -> BorrowContainsPointReason<'tcx> {
use self::BorrowContainsPointReason::*;
) -> BorrowExplanation<'tcx> {
debug!(
"find_why_borrow_contains_point(context={:?}, borrow={:?})",
context, borrow,
@ -77,116 +106,70 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let regioncx = &self.nonlexical_regioncx;
let mir = self.mir;
let tcx = self.tcx;
let tcx = self.infcx.tcx;
let borrow_region_vid = regioncx.to_region_vid(borrow.region);
debug!(
"explain_why_borrow_contains_point: borrow_region_vid={:?}",
borrow_region_vid
);
let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc);
debug!(
"explain_why_borrow_contains_point: region_sub={:?}",
region_sub
);
match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
Some(Cause::LiveVar(local, location)) => Liveness {
local,
location,
in_loop: self.is_borrow_location_in_loop(context.loc),
},
Some(Cause::DropVar(local, location)) => DropLiveness {
local,
location,
},
None => OutlivesFreeRegion {
outlived_region: regioncx.to_error_region(region_sub),
},
}
}
/// Adds annotations to `err` for the explanation `reason`. This is a
/// separate method so that the caller can change their error message based
/// on the reason that is going to be reported.
pub (in borrow_check) fn report_why_borrow_contains_point(
&self,
err: &mut DiagnosticBuilder,
reason: BorrowContainsPointReason<'tcx>,
kind_place: Option<(WriteKind, &Place<'tcx>)>,
) {
use self::BorrowContainsPointReason::*;
debug!(
"find_why_borrow_contains_point(reason={:?}, kind_place={:?})",
reason, kind_place,
);
let mir = self.mir;
match reason {
Liveness { local, location, in_loop } => {
match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
Some(Cause::LiveVar(local, location)) => {
let span = mir.source_info(location).span;
let spans = self.move_spans(&Place::Local(local), location)
.or_else(|| self.borrow_spans(span, location));
let message = if in_loop {
if spans.for_closure() {
"borrow captured here by closure in later iteration of loop"
} else {
"borrow used here in later iteration of loop"
}
} else {
if spans.for_closure() {
"borrow later captured here by closure"
} else {
// Check if the location represents a `FakeRead`, and adapt the error
// message to the `FakeReadCause` it is from: in particular,
// the ones inserted in optimized `let var = <expr>` patterns.
match self.retrieve_fake_read_cause_for_location(&location) {
Some(FakeReadCause::ForLet) => "borrow later stored here",
_ => "borrow later used here"
}
}
};
err.span_label(spans.var_or_use(), message);
}
DropLiveness { local, location } => match &mir.local_decls[local].name {
Some(local_name) => {
err.span_label(
mir.source_info(location).span,
format!("borrow later used here, when `{}` is dropped", local_name),
);
if self.is_borrow_location_in_loop(context.loc) {
BorrowExplanation::UsedLaterInLoop(spans.for_closure(), spans.var_or_use())
} else {
// Check if the location represents a `FakeRead`, and adapt the error
// message to the `FakeReadCause` it is from: in particular,
// the ones inserted in optimized `let var = <expr>` patterns.
BorrowExplanation::UsedLater(
spans.for_closure(),
self.retrieve_fake_read_cause_for_location(&location),
spans.var_or_use()
)
}
}
Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name {
Some(local_name) => {
let mut should_note_order = false;
if let Some((WriteKind::StorageDeadOrDrop(_), place)) = kind_place {
if let Place::Local(borrowed_local) = place {
let dropped_local_scope = mir.local_decls[local].visibility_scope;
let borrowed_local_scope =
mir.local_decls[*borrowed_local].visibility_scope;
mir.local_decls[*borrowed_local].visibility_scope;
if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) {
err.note(
"values in a scope are dropped \
in the opposite order they are defined",
);
should_note_order = true;
}
}
}
}
None => {}
}
OutlivesFreeRegion { outlived_region: Some(region) } => {
self.tcx.note_and_explain_free_region(
err,
"borrowed value must be valid for ",
region,
"...",
);
}
OutlivesFreeRegion { outlived_region: None } => (),
BorrowExplanation::UsedLaterWhenDropped(
mir.source_info(location).span,
*local_name,
should_note_order
)
},
None => BorrowExplanation::Unexplained,
},
None => if let Some(region) = regioncx.to_error_region(region_sub) {
BorrowExplanation::MustBeValidFor(region)
} else {
BorrowExplanation::Unexplained
},
}
}
@ -262,4 +245,3 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
false
}
}

View file

@ -339,10 +339,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
);
let counter = &mut 1;
let fr_name = self.give_region_a_name(
infcx, mir, mir_def_id, fr, counter, &mut diag);
let fr_name = self.give_region_a_name(infcx, mir, mir_def_id, fr, counter);
fr_name.highlight_region_name(&mut diag);
let outlived_fr_name = self.give_region_a_name(
infcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
infcx, mir, mir_def_id, outlived_fr, counter);
outlived_fr_name.highlight_region_name(&mut diag);
let mir_def_name = if infcx.tcx.is_closure(mir_def_id) { "closure" } else { "function" };
@ -430,10 +431,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Otherwise, we should suggest adding a constraint on the return type.
let span = infcx.tcx.def_span(*did);
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
let suggestable_fr_name = match fr_name {
RegionName::Named(name) => format!("{}", name),
RegionName::Synthesized(_) => "'_".to_string(),
let suggestable_fr_name = if fr_name.was_named() {
format!("{}", fr_name)
} else {
"'_".to_string()
};
diag.span_suggestion_with_applicability(
span,
&format!(

View file

@ -18,36 +18,109 @@ 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;
use syntax_pos::Span;
use syntax_pos::symbol::InternedString;
/// Name of a region used in error reporting. Variants denote the source of the region name -
/// whether it was synthesized for the error message and therefore should not be used in
/// suggestions; or whether it was found from the region.
#[derive(Debug)]
pub(crate) enum RegionName {
Named(InternedString),
Synthesized(InternedString),
crate struct RegionName {
name: InternedString,
source: RegionNameSource,
}
#[derive(Debug)]
crate enum RegionNameSource {
NamedEarlyBoundRegion(Span),
NamedFreeRegion(Span),
Static,
SynthesizedFreeEnvRegion(Span, String),
CannotMatchHirTy(Span, String),
MatchedHirTy(Span),
MatchedAdtAndSegment(Span),
AnonRegionFromUpvar(Span, String),
AnonRegionFromOutput(Span, String, String),
}
impl RegionName {
fn as_interned_string(&self) -> &InternedString {
match self {
RegionName::Named(name) | RegionName::Synthesized(name) => name,
#[allow(dead_code)]
crate fn was_named(&self) -> bool {
match self.source {
RegionNameSource::NamedEarlyBoundRegion(..) |
RegionNameSource::NamedFreeRegion(..) |
RegionNameSource::Static => true,
RegionNameSource::SynthesizedFreeEnvRegion(..) |
RegionNameSource::CannotMatchHirTy(..) |
RegionNameSource::MatchedHirTy(..) |
RegionNameSource::MatchedAdtAndSegment(..) |
RegionNameSource::AnonRegionFromUpvar(..) |
RegionNameSource::AnonRegionFromOutput(..) => false,
}
}
#[allow(dead_code)]
crate fn was_synthesized(&self) -> bool {
!self.was_named()
}
#[allow(dead_code)]
crate fn name(&self) -> &InternedString {
&self.name
}
crate fn highlight_region_name(
&self,
diag: &mut DiagnosticBuilder<'_>
) {
match &self.source {
RegionNameSource::NamedFreeRegion(span) |
RegionNameSource::NamedEarlyBoundRegion(span) => {
diag.span_label(
*span,
format!("lifetime `{}` defined here", self),
);
},
RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
diag.span_label(
*span,
format!("lifetime `{}` represents this closure's body", self),
);
diag.note(&note);
},
RegionNameSource::CannotMatchHirTy(span, type_name) => {
diag.span_label(*span, format!("has type `{}`", type_name));
},
RegionNameSource::MatchedHirTy(span) => {
diag.span_label(
*span,
format!("let's call the lifetime of this reference `{}`", self),
);
},
RegionNameSource::MatchedAdtAndSegment(span) => {
diag.span_label(*span, format!("let's call this `{}`", self));
},
RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
diag.span_label(
*span,
format!("lifetime `{}` appears in the type of `{}`", self, upvar_name),
);
},
RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => {
diag.span_label(
*span,
format!("return type{} is {}", mir_description, type_name),
);
},
RegionNameSource::Static => {},
}
}
}
impl Display for RegionName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RegionName::Named(name) | RegionName::Synthesized(name) =>
write!(f, "{}", name),
}
write!(f, "{}", self.name)
}
}
@ -84,26 +157,25 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir_def_id: DefId,
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder,
) -> RegionName {
debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);
assert!(self.universal_regions.is_universal_region(fr));
let value = self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter, diag)
let value = self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter)
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_arguments(
infcx, mir, mir_def_id, fr, counter, diag,
infcx, mir, mir_def_id, fr, counter,
)
})
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_upvars(
infcx.tcx, mir, fr, counter, diag,
infcx.tcx, mir, fr, counter,
)
})
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_output(
infcx, mir, mir_def_id, fr, counter, diag,
infcx, mir, mir_def_id, fr, counter,
)
})
.unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr));
@ -122,7 +194,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir_def_id: DefId,
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;
@ -130,23 +201,28 @@ impl<'tcx> RegionInferenceContext<'tcx> {
match error_region {
ty::ReEarlyBound(ebr) => {
if ebr.has_name() {
let name = RegionName::Named(ebr.name);
self.highlight_named_span(tcx, error_region, &name, diag);
Some(name)
let span = self.get_named_span(tcx, error_region, &ebr.name);
Some(RegionName {
name: ebr.name,
source: RegionNameSource::NamedEarlyBoundRegion(span)
})
} else {
None
}
}
ty::ReStatic => Some(RegionName::Named(
keywords::StaticLifetime.name().as_interned_str()
)),
ty::ReStatic => Some(RegionName {
name: keywords::StaticLifetime.name().as_interned_str(),
source: RegionNameSource::Static
}),
ty::ReFree(free_region) => match free_region.bound_region {
ty::BoundRegion::BrNamed(_, name) => {
let name = RegionName::Named(name);
self.highlight_named_span(tcx, error_region, &name, diag);
Some(name)
let span = self.get_named_span(tcx, error_region, &name);
Some(RegionName {
name,
source: RegionNameSource::NamedFreeRegion(span),
})
},
ty::BoundRegion::BrEnv => {
@ -162,13 +238,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
bug!("Closure is not defined by a closure expr");
};
let region_name = self.synthesize_region_name(counter);
diag.span_label(
args_span,
format!(
"lifetime `{}` represents this closure's body",
region_name
),
);
let closure_kind_ty = substs.closure_kind_ty(def_id, tcx);
let note = match closure_kind_ty.to_opt_closure_kind() {
@ -186,9 +255,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
None => bug!("Closure kind not inferred in borrow check"),
};
diag.note(note);
Some(region_name)
Some(RegionName {
name: region_name,
source: RegionNameSource::SynthesizedFreeEnvRegion(
args_span,
note.to_string()
),
})
} else {
// Can't have BrEnv in functions, constants or generators.
bug!("BrEnv outside of closure.");
@ -209,27 +282,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
/// Get the span of a named region.
pub(super) fn get_span_of_named_region(
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
error_region: &RegionKind,
name: &RegionName,
) -> Span {
let scope = error_region.free_region_binding_scope(tcx);
let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
let span = tcx.sess.source_map().def_span(tcx.hir.span(node));
if let Some(param) = tcx.hir.get_generics(scope).and_then(|generics| {
generics.get_named(name.as_interned_string())
}) {
param.span
} else {
span
}
}
/// Highlight a named span to provide context for error messages that
/// Get a span of a named region to provide context for error messages that
/// mention that span, for example:
///
/// ```
@ -243,19 +296,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must
/// | outlive `'a`
/// ```
fn highlight_named_span(
fn get_named_span(
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
error_region: &RegionKind,
name: &RegionName,
diag: &mut DiagnosticBuilder<'_>,
) {
let span = self.get_span_of_named_region(tcx, error_region, name);
name: &InternedString,
) -> Span {
let scope = error_region.free_region_binding_scope(tcx);
let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
diag.span_label(
span,
format!("lifetime `{}` defined here", name),
);
let span = tcx.sess.source_map().def_span(tcx.hir.span(node));
if let Some(param) = tcx.hir
.get_generics(scope)
.and_then(|generics| generics.get_named(name))
{
param.span
} else {
span
}
}
/// Find an argument that contains `fr` and label it with a fully
@ -273,7 +331,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir_def_id: DefId,
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<RegionName> {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
@ -288,12 +345,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
arg_ty,
argument_index,
counter,
diag,
) {
return Some(region_name);
}
self.give_name_if_we_cannot_match_hir_ty(infcx, mir, fr, arg_ty, counter, diag)
self.give_name_if_we_cannot_match_hir_ty(infcx, mir, fr, arg_ty, counter)
}
fn give_name_if_we_can_match_hir_ty_from_argument(
@ -305,7 +361,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_ty: Ty<'tcx>,
argument_index: usize,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<RegionName> {
let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id)?;
let fn_decl = infcx.tcx.hir.fn_decl(mir_node_id)?;
@ -320,7 +375,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
needle_fr,
argument_ty,
counter,
diag,
),
_ => self.give_name_if_we_can_match_hir_ty(
@ -329,7 +383,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_ty,
argument_hir_ty,
counter,
diag,
),
}
}
@ -352,9 +405,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
needle_fr: RegionVid,
argument_ty: Ty<'tcx>,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> 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)
});
@ -366,12 +418,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Only add a label if we can confirm that a region was labelled.
let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index);
diag.span_label(span, format!("has type `{}`", type_name));
// 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.
Some(self.synthesize_region_name(counter))
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.
name: self.synthesize_region_name(counter),
source: RegionNameSource::CannotMatchHirTy(span, type_name),
})
} else {
None
};
@ -407,7 +461,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_ty: Ty<'tcx>,
argument_hir_ty: &hir::Ty,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<RegionName> {
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut Vec::new();
@ -432,15 +485,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let source_map = tcx.sess.source_map();
let ampersand_span = source_map.start_point(hir_ty.span);
diag.span_label(
ampersand_span,
format!(
"let's call the lifetime of this reference `{}`",
region_name
),
);
return Some(region_name);
return Some(RegionName {
name: region_name,
source: RegionNameSource::MatchedHirTy(ampersand_span),
});
}
// Otherwise, let's descend into the referent types.
@ -464,7 +512,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
needle_fr,
last_segment,
counter,
diag,
search_stack,
) {
return Some(name);
@ -509,7 +556,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
needle_fr: RegionVid,
last_segment: &'hir hir::PathSegment,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
) -> Option<RegionName> {
// Did the user give explicit arguments? (e.g., `Foo<..>`)
@ -521,11 +567,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
| hir::LifetimeName::Underscore => {
let region_name = self.synthesize_region_name(counter);
let ampersand_span = lifetime.span;
diag.span_label(
ampersand_span,
format!("let's call this `{}`", region_name)
);
return Some(region_name);
return Some(RegionName {
name: region_name,
source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
});
}
hir::LifetimeName::Implicit => {
@ -600,22 +645,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir: &Mir<'tcx>,
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<RegionName> {
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);
diag.span_label(
upvar_span,
format!(
"lifetime `{}` appears in the type of `{}`",
region_name, upvar_name
),
);
Some(region_name)
Some(RegionName {
name: region_name,
source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()),
})
}
/// Check for arguments appearing in the (closure) return type. It
@ -629,7 +668,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
mir_def_id: DefId,
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<RegionName> {
let tcx = infcx.tcx;
@ -645,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");
@ -666,23 +705,25 @@ impl<'tcx> RegionInferenceContext<'tcx> {
(mir.span, "")
};
diag.span_label(
return_span,
format!("return type{} is {}", mir_description, type_name),
);
// 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.
Some(self.synthesize_region_name(counter))
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.
name: self.synthesize_region_name(counter),
source: RegionNameSource::AnonRegionFromOutput(
return_span,
mir_description.to_string(),
type_name
),
})
}
/// Create a synthetic region named `'1`, incrementing the
/// counter.
fn synthesize_region_name(&self, counter: &mut usize) -> RegionName {
fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
let c = *counter;
*counter += 1;
RegionName::Synthesized(Name::intern(&format!("'{:?}", c)).as_interned_str())
Name::intern(&format!("'{:?}", c)).as_interned_str()
}
}

View file

@ -79,7 +79,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
next: Some(place),
kind,
mir: self.mir,
tcx: self.tcx,
tcx: self.infcx.tcx,
}
}
}

View file

@ -1848,7 +1848,7 @@ impl<'a> Parser<'a> {
P(Ty {
id: ast::DUMMY_NODE_ID,
node: TyKind::Infer,
span: self.span,
span: self.prev_span,
})
};
Ok(Arg {

View file

@ -1,17 +1,20 @@
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 {
| -- -- also has lifetime `'y`
| |
| has lifetime `'y`
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
| - ...but `x` will be dropped here, when the function `silly` returns
|
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 {
| ^^
= help: use data from the highlighted arguments which match the `'y` lifetime of the return type
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error: aborting due to previous error

View file

@ -1,17 +1,20 @@
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 {
| -- -- also has lifetime `'a`
| |
| has lifetime `'a`
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
| - ...but `v` will be dropped here, when the function `foo` returns
|
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 {
| ^^
= help: use data from the highlighted arguments which match the `'a` lifetime of the return type
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error: aborting due to previous error

View file

@ -0,0 +1,53 @@
// 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 foobazbar<'a>(x: u32, y: &'a u32) -> &'a u32 {
let x = 22;
&x
}
fn foobar<'a>(x: &'a u32) -> &'a u32 {
let x = 22;
&x
}
fn foobaz<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
let x = 22;
&x
}
fn foobarbaz<'a, 'b>(x: &'a u32, y: &'b u32, z: &'a u32) -> &'a u32 {
let x = 22;
&x
}
fn main() { }

View file

@ -0,0 +1,140 @@
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` will be dropped here, when the function `bar` returns
|
= note: argument and return type have the same lifetime due to lifetime elision rules
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch10-03-lifetime-syntax.html#lifetime-elision>
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
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` will be dropped here, when the function `foo` returns
|
= note: argument and return type have the same lifetime due to lifetime elision rules
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch10-03-lifetime-syntax.html#lifetime-elision>
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
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` will be dropped here, when the function `baz` returns
|
= note: argument and return type have the same lifetime due to lifetime elision rules
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch10-03-lifetime-syntax.html#lifetime-elision>
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
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[E0597]: `x` does not live long enough
--> $DIR/issue-52534-1.rs:35:5
|
LL | fn foobazbar<'a>(x: u32, y: &'a u32) -> &'a u32 {
| -- -- also has lifetime `'a`
| |
| has lifetime `'a`
LL | let x = 22;
LL | &x
| ^^ `x` would have to be valid for `'a`...
LL | }
| - ...but `x` will be dropped here, when the function `foobazbar` returns
|
= help: use data from the highlighted arguments which match the `'a` lifetime of the return type
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error[E0597]: `x` does not live long enough
--> $DIR/issue-52534-1.rs:40:5
|
LL | fn foobar<'a>(x: &'a u32) -> &'a u32 {
| -- -- also has lifetime `'a`
| |
| has lifetime `'a`
LL | let x = 22;
LL | &x
| ^^ `x` would have to be valid for `'a`...
LL | }
| - ...but `x` will be dropped here, when the function `foobar` returns
|
= help: use data from the highlighted arguments which match the `'a` lifetime of the return type
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error[E0597]: `x` does not live long enough
--> $DIR/issue-52534-1.rs:45:5
|
LL | fn foobaz<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
| -- has lifetime `'a` -- also has lifetime `'a`
LL | let x = 22;
LL | &x
| ^^ `x` would have to be valid for `'a`...
LL | }
| - ...but `x` will be dropped here, when the function `foobaz` returns
|
= help: use data from the highlighted arguments which match the `'a` lifetime of the return type
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error[E0597]: `x` does not live long enough
--> $DIR/issue-52534-1.rs:50:5
|
LL | fn foobarbaz<'a, 'b>(x: &'a u32, y: &'b u32, z: &'a u32) -> &'a u32 {
| -- -- -- also has lifetime `'a`
| | |
| has lifetime `'a` has lifetime `'a`
LL | let x = 22;
LL | &x
| ^^ `x` would have to be valid for `'a`...
LL | }
| - ...but `x` will be dropped here, when the function `foobarbaz` returns
|
= help: use data from the highlighted arguments which match the `'a` lifetime of the return type
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0597`.

View file

@ -0,0 +1,26 @@
// 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(x: &u32) -> &u32 {
let y;
{
let x = 32;
y = &x
}
println!("{}", y);
x
}
fn main() { }

View file

@ -0,0 +1,14 @@
error[E0597]: `x` does not live long enough
--> $DIR/issue-52534-2.rs:19:9
|
LL | y = &x
| ^^^^^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
LL |
LL | println!("{}", y);
| - borrow later used here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View file

@ -0,0 +1,30 @@
// 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 baz(_: impl FnOnce(&u32, u32) -> &u32) {
}
fn bar() {
let x = 22;
foo(|a| &x)
}
fn foobar() {
let y = 22;
baz(|first, second| &y)
}
fn main() { }

View file

@ -0,0 +1,29 @@
error[E0597]: `x` does not live long enough
--> $DIR/issue-52534.rs:22:14
|
LL | foo(|a| &x)
| - ^ `x` would have to be valid for `'0`...
| |
| has type `&'0 u32`
LL | }
| - ...but `x` will be dropped here, when the function `bar` returns
|
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error[E0597]: `y` does not live long enough
--> $DIR/issue-52534.rs:27:26
|
LL | baz(|first, second| &y)
| ----- ^ `y` would have to be valid for `'0`...
| |
| has type `&'0 u32`
LL | }
| - ...but `y` will be dropped here, when the function `foobar` returns
|
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references>
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.