1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use borrow_check::{Context, MirBorrowckCtxt};
12 use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
13 use dataflow::BorrowData;
14 use rustc::mir::{Local, Location, Mir};
15 use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
16 use rustc_data_structures::fx::FxHashSet;
17 use rustc_errors::DiagnosticBuilder;
18 use util::liveness::{self, DefUse, LivenessMode};
20 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
21 pub(in borrow_check) fn explain_why_borrow_contains_point(
24 borrow: &BorrowData<'_>,
25 err: &mut DiagnosticBuilder<'_>,
27 if let Some(regioncx) = &self.nonlexical_regioncx {
28 if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) {
31 match *cause.root_cause() {
32 Cause::LiveVar(local, location) => {
33 match find_regular_use(&mir, regioncx, borrow, location, local) {
36 mir.source_info(p).span,
37 format!("borrow later used here"),
43 mir.source_info(context.loc).span,
44 "Cause should end in a LiveVar"
50 Cause::DropVar(local, location) => {
51 match find_drop_use(&mir, regioncx, borrow, location, local) {
53 let local_name = &mir.local_decls[local].name.unwrap();
56 mir.source_info(p).span,
58 "borrow later used here, when `{}` is dropped",
66 mir.source_info(context.loc).span,
67 "Cause should end in a DropVar"
74 cause.label_diagnostic(mir, err);
82 fn find_regular_use<'gcx, 'tcx>(
84 regioncx: &'tcx RegionInferenceContext,
85 borrow: &'tcx BorrowData,
86 start_point: Location,
88 ) -> Option<Location> {
89 let mut uf = UseFinder {
95 liveness_mode: LivenessMode {
96 include_regular_use: true,
104 fn find_drop_use<'gcx, 'tcx>(
106 regioncx: &'tcx RegionInferenceContext,
107 borrow: &'tcx BorrowData,
108 start_point: Location,
110 ) -> Option<Location> {
111 let mut uf = UseFinder {
117 liveness_mode: LivenessMode {
118 include_regular_use: false,
126 struct UseFinder<'gcx, 'tcx> {
127 mir: &'gcx Mir<'gcx>,
128 regioncx: &'tcx RegionInferenceContext<'tcx>,
129 borrow: &'tcx BorrowData<'tcx>,
130 start_point: Location,
132 liveness_mode: LivenessMode,
135 impl<'gcx, 'tcx> UseFinder<'gcx, 'tcx> {
136 fn find(&mut self) -> Option<Location> {
137 let mut stack = vec![];
138 let mut visited = FxHashSet();
140 stack.push(self.start_point);
141 while let Some(p) = stack.pop() {
142 if !self.regioncx.region_contains_point(self.borrow.region, p) {
146 if !visited.insert(p) {
150 let block_data = &self.mir[p.block];
151 let (defined, used) = self.def_use(p, block_data.visitable(p.statement_index));
156 if p.statement_index < block_data.statements.len() {
157 stack.push(Location {
158 statement_index: p.statement_index + 1,
167 .map(|&basic_block| Location {
179 fn def_use(&self, location: Location, thing: &MirVisitable<'tcx>) -> (bool, bool) {
180 let mut visitor = DefUseVisitor {
184 liveness_mode: self.liveness_mode,
187 thing.apply(location, &mut visitor);
189 (visitor.defined, visitor.used)
193 struct DefUseVisitor {
197 liveness_mode: LivenessMode,
200 impl<'tcx> Visitor<'tcx> for DefUseVisitor {
201 fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
202 if local == self.local {
203 match liveness::categorize(context, self.liveness_mode) {
204 Some(DefUse::Def) => self.defined = true,
205 Some(DefUse::Use) => self.used = true,