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<'tcx>,
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"
73 Cause::UniversalRegion(region_vid) => {
74 if let Some(region) = regioncx.to_error_region(region_vid) {
75 self.tcx.note_and_explain_free_region(
77 "borrowed value must be valid for ",
91 fn find_regular_use<'gcx, 'tcx>(
93 regioncx: &'tcx RegionInferenceContext,
94 borrow: &'tcx BorrowData,
95 start_point: Location,
97 ) -> Option<Location> {
98 let mut uf = UseFinder {
104 liveness_mode: LivenessMode {
105 include_regular_use: true,
106 include_drops: false,
113 fn find_drop_use<'gcx, 'tcx>(
115 regioncx: &'tcx RegionInferenceContext,
116 borrow: &'tcx BorrowData,
117 start_point: Location,
119 ) -> Option<Location> {
120 let mut uf = UseFinder {
126 liveness_mode: LivenessMode {
127 include_regular_use: false,
135 struct UseFinder<'gcx, 'tcx> {
136 mir: &'gcx Mir<'gcx>,
137 regioncx: &'tcx RegionInferenceContext<'tcx>,
138 borrow: &'tcx BorrowData<'tcx>,
139 start_point: Location,
141 liveness_mode: LivenessMode,
144 impl<'gcx, 'tcx> UseFinder<'gcx, 'tcx> {
145 fn find(&mut self) -> Option<Location> {
146 let mut stack = vec![];
147 let mut visited = FxHashSet();
149 stack.push(self.start_point);
150 while let Some(p) = stack.pop() {
151 if !self.regioncx.region_contains_point(self.borrow.region, p) {
155 if !visited.insert(p) {
159 let block_data = &self.mir[p.block];
160 let (defined, used) = self.def_use(p, block_data.visitable(p.statement_index));
165 if p.statement_index < block_data.statements.len() {
166 stack.push(Location {
167 statement_index: p.statement_index + 1,
176 .map(|&basic_block| Location {
188 fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> (bool, bool) {
189 let mut visitor = DefUseVisitor {
193 liveness_mode: self.liveness_mode,
196 thing.apply(location, &mut visitor);
198 (visitor.defined, visitor.used)
202 struct DefUseVisitor {
206 liveness_mode: LivenessMode,
209 impl<'tcx> Visitor<'tcx> for DefUseVisitor {
210 fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
211 if local == self.local {
212 match liveness::categorize(context, self.liveness_mode) {
213 Some(DefUse::Def) => self.defined = true,
214 Some(DefUse::Use) => self.used = true,