parent
6d2987ca03
commit
3a185a510d
24 changed files with 274 additions and 23 deletions
|
@ -21,6 +21,7 @@ use rustc_data_structures::control_flow_graph::ControlFlowGraph;
|
|||
use rustc_serialize as serialize;
|
||||
use hir::def::CtorKind;
|
||||
use hir::def_id::DefId;
|
||||
use mir::visit::MirVisitable;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
|
||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
|
@ -868,6 +869,14 @@ impl<'tcx> BasicBlockData<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> {
|
||||
if index < self.statements.len() {
|
||||
&self.statements[index]
|
||||
} else {
|
||||
&self.terminator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for TerminatorKind<'tcx> {
|
||||
|
|
|
@ -14,7 +14,6 @@ use rustc::mir::{BorrowKind, Field, Local, Location, Operand};
|
|||
use rustc::mir::{Place, ProjectionElem, Rvalue, Statement, StatementKind};
|
||||
use rustc::ty::{self, RegionKind};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -134,19 +133,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
err.emit();
|
||||
}
|
||||
|
||||
fn explain_why_borrow_contains_point(
|
||||
&self,
|
||||
context: Context,
|
||||
borrow: &BorrowData<'_>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) {
|
||||
if let Some(regioncx) = &self.nonlexical_regioncx {
|
||||
if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) {
|
||||
cause.label_diagnostic(self.mir, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
|
||||
/// the local assigned at `location`.
|
||||
/// This is done by searching in statements succeeding `location`
|
||||
|
|
210
src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
Normal file
210
src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
Normal file
|
@ -0,0 +1,210 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::{Context, MirBorrowckCtxt};
|
||||
use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
|
||||
use dataflow::BorrowData;
|
||||
use rustc::mir::{Local, Location, Mir};
|
||||
use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use util::liveness::{self, DefUse, LivenessMode};
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
pub(in borrow_check) fn explain_why_borrow_contains_point(
|
||||
&self,
|
||||
context: Context,
|
||||
borrow: &BorrowData<'_>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) {
|
||||
if let Some(regioncx) = &self.nonlexical_regioncx {
|
||||
if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) {
|
||||
let mir = self.mir;
|
||||
|
||||
cause.label_diagnostic(mir, err);
|
||||
|
||||
match *cause.root_cause() {
|
||||
Cause::LiveVar(local, location) => {
|
||||
match find_regular_use(&mir, regioncx, borrow, location, local) {
|
||||
Some(p) => {
|
||||
err.span_label(
|
||||
mir.source_info(p).span,
|
||||
format!("borrow later used here"),
|
||||
);
|
||||
}
|
||||
|
||||
None => {
|
||||
span_bug!(
|
||||
mir.source_info(context.loc).span,
|
||||
"Cause should end in a LiveVar"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cause::DropVar(local, location) => {
|
||||
match find_drop_use(&mir, regioncx, borrow, location, local) {
|
||||
Some(p) => {
|
||||
let local_name = &mir.local_decls[local].name.unwrap();
|
||||
|
||||
err.span_label(
|
||||
mir.source_info(p).span,
|
||||
format!(
|
||||
"borrow later used here, when `{}` is dropped",
|
||||
local_name
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
None => {
|
||||
span_bug!(
|
||||
mir.source_info(context.loc).span,
|
||||
"Cause should end in a DropVar"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_regular_use<'gcx, 'tcx>(
|
||||
mir: &'gcx Mir,
|
||||
regioncx: &'tcx RegionInferenceContext,
|
||||
borrow: &'tcx BorrowData,
|
||||
start_point: Location,
|
||||
local: Local,
|
||||
) -> Option<Location> {
|
||||
let mut uf = UseFinder {
|
||||
mir,
|
||||
regioncx,
|
||||
borrow,
|
||||
start_point,
|
||||
local,
|
||||
liveness_mode: LivenessMode {
|
||||
include_regular_use: true,
|
||||
include_drops: false,
|
||||
},
|
||||
};
|
||||
|
||||
uf.find()
|
||||
}
|
||||
|
||||
fn find_drop_use<'gcx, 'tcx>(
|
||||
mir: &'gcx Mir,
|
||||
regioncx: &'tcx RegionInferenceContext,
|
||||
borrow: &'tcx BorrowData,
|
||||
start_point: Location,
|
||||
local: Local,
|
||||
) -> Option<Location> {
|
||||
let mut uf = UseFinder {
|
||||
mir,
|
||||
regioncx,
|
||||
borrow,
|
||||
start_point,
|
||||
local,
|
||||
liveness_mode: LivenessMode {
|
||||
include_regular_use: false,
|
||||
include_drops: true,
|
||||
},
|
||||
};
|
||||
|
||||
uf.find()
|
||||
}
|
||||
|
||||
struct UseFinder<'gcx, 'tcx> {
|
||||
mir: &'gcx Mir<'gcx>,
|
||||
regioncx: &'tcx RegionInferenceContext<'tcx>,
|
||||
borrow: &'tcx BorrowData<'tcx>,
|
||||
start_point: Location,
|
||||
local: Local,
|
||||
liveness_mode: LivenessMode,
|
||||
}
|
||||
|
||||
impl<'gcx, 'tcx> UseFinder<'gcx, 'tcx> {
|
||||
fn find(&mut self) -> Option<Location> {
|
||||
let mut stack = vec![];
|
||||
let mut visited = FxHashSet();
|
||||
|
||||
stack.push(self.start_point);
|
||||
while let Some(p) = stack.pop() {
|
||||
if !self.regioncx.region_contains_point(self.borrow.region, p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !visited.insert(p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let block_data = &self.mir[p.block];
|
||||
let (defined, used) = self.def_use(p, block_data.visitable(p.statement_index));
|
||||
|
||||
if used {
|
||||
return Some(p);
|
||||
} else if !defined {
|
||||
if p.statement_index < block_data.statements.len() {
|
||||
stack.push(Location {
|
||||
statement_index: p.statement_index + 1,
|
||||
..p
|
||||
});
|
||||
} else {
|
||||
stack.extend(
|
||||
block_data
|
||||
.terminator()
|
||||
.successors()
|
||||
.iter()
|
||||
.map(|&basic_block| Location {
|
||||
statement_index: 0,
|
||||
block: basic_block,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn def_use(&self, location: Location, thing: &MirVisitable<'tcx>) -> (bool, bool) {
|
||||
let mut visitor = DefUseVisitor {
|
||||
defined: false,
|
||||
used: false,
|
||||
local: self.local,
|
||||
liveness_mode: self.liveness_mode,
|
||||
};
|
||||
|
||||
thing.apply(location, &mut visitor);
|
||||
|
||||
(visitor.defined, visitor.used)
|
||||
}
|
||||
}
|
||||
|
||||
struct DefUseVisitor {
|
||||
defined: bool,
|
||||
used: bool,
|
||||
local: Local,
|
||||
liveness_mode: LivenessMode,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for DefUseVisitor {
|
||||
fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
|
||||
if local == self.local {
|
||||
match liveness::categorize(context, self.liveness_mode) {
|
||||
Some(DefUse::Def) => self.defined = true,
|
||||
Some(DefUse::Use) => self.used = true,
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ use util::pretty::{self, ALIGN};
|
|||
use self::mir_util::PassWhere;
|
||||
|
||||
mod constraint_generation;
|
||||
pub mod explain_borrow;
|
||||
pub(crate) mod region_infer;
|
||||
mod renumber;
|
||||
mod subtype_constraint_generation;
|
||||
|
|
|
@ -1229,4 +1229,22 @@ impl Cause {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn root_cause(&self) -> &Cause {
|
||||
match self {
|
||||
Cause::LiveVar(..) |
|
||||
Cause::DropVar(..) |
|
||||
Cause::LiveOther(..) |
|
||||
Cause::UniversalRegion(..) => {
|
||||
self
|
||||
}
|
||||
|
||||
Cause::Outlives {
|
||||
original_cause,
|
||||
..
|
||||
} => {
|
||||
original_cause.root_cause()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
#![feature(const_fn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(i128_type)]
|
||||
#![feature(inclusive_range_syntax)]
|
||||
#![feature(inclusive_range)]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir
|
||||
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause
|
||||
|
||||
// Test that a structure which tries to store a pointer to `y` into
|
||||
// `p` (indirectly) fails to compile.
|
||||
|
|
|
@ -6,6 +6,9 @@ error[E0597]: `y` does not live long enough
|
|||
...
|
||||
37 | }
|
||||
| - borrowed value only lives until here
|
||||
38 |
|
||||
39 | deref(p);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#5r...
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
// basically checking that the MIR type checker correctly enforces the
|
||||
// closure signature.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause -Zverbose
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@ error[E0597]: `y` does not live long enough
|
|||
38 | //~^ ERROR `y` does not live long enough [E0597]
|
||||
39 | }
|
||||
| - borrowed value only lives until here
|
||||
40 |
|
||||
41 | deref(p);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#6r...
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
//
|
||||
// except that the closure does so via a second closure.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause -Zverbose
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@ error[E0597]: `y` does not live long enough
|
|||
...
|
||||
36 | }
|
||||
| - borrowed value only lives until here
|
||||
37 |
|
||||
38 | deref(p);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#4r...
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// `'b`. This relationship is propagated to the closure creator,
|
||||
// which reports an error.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause -Zverbose
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ error[E0597]: `y` does not live long enough
|
|||
...
|
||||
36 | }
|
||||
| - borrowed value only lives until here
|
||||
37 |
|
||||
38 | deref(p);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#4r...
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// a variety of errors from the older, AST-based machinery (notably
|
||||
// borrowck), and then we get the NLL error at the end.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=compare
|
||||
// compile-flags:-Znll -Zborrowck=compare -Znll-dump-cause
|
||||
|
||||
struct Map {
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as imm
|
|||
43 | Some(v) => {
|
||||
44 | map.set(String::new()); // Both AST and MIR error here
|
||||
| ^^^ mutable borrow occurs here
|
||||
...
|
||||
47 | return v;
|
||||
| - borrow later used here
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll -Znll-dump-cause
|
||||
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
|
|||
...
|
||||
31 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
32 | // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
|
||||
33 | }
|
||||
| - borrow later used here, when `foo` is dropped
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll -Znll-dump-cause
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ error[E0506]: cannot assign to `x` because it is borrowed
|
|||
...
|
||||
31 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
32 | }
|
||||
| - borrow later used here, when `foo` is dropped
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll -Znll-dump-cause
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
|
|||
...
|
||||
32 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
33 | // FIXME ^ This currently errors and it should not.
|
||||
34 | }
|
||||
| - borrow later used here, when `foo` is dropped
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll -Znll-dump-cause
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ error[E0506]: cannot assign to `x` because it is borrowed
|
|||
| ------ borrow of `x` occurs here
|
||||
26 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
27 | }
|
||||
| - borrow later used here, when `wrap` is dropped
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue