]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
New upstream version 1.38.0+dfsg1
[rustc.git] / src / librustc_mir / borrow_check / nll / explain_borrow / mod.rs
CommitLineData
9fa01778
XL
1use std::collections::VecDeque;
2
3use crate::borrow_check::borrow_set::BorrowData;
4use crate::borrow_check::error_reporting::UseSpans;
5use crate::borrow_check::nll::region_infer::{Cause, RegionName};
6use crate::borrow_check::nll::ConstraintDescription;
48663c56 7use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
0bf4aa26 8use rustc::mir::{
dc9dc135 9 CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase,
416331ca 10 Rvalue, Statement, StatementKind, TerminatorKind,
0bf4aa26 11};
9fa01778 12use rustc::ty::{self, TyCtxt};
48663c56 13use rustc::ty::adjustment::{PointerCast};
9fa01778 14use rustc_data_structures::fx::FxHashSet;
ff7c6d11 15use rustc_errors::DiagnosticBuilder;
0bf4aa26 16use syntax_pos::Span;
8faf50e0
XL
17
18mod find_use;
ff7c6d11 19
9fa01778 20pub(in crate::borrow_check) enum BorrowExplanation {
0bf4aa26
XL
21 UsedLater(LaterUseKind, Span),
22 UsedLaterInLoop(LaterUseKind, Span),
23 UsedLaterWhenDropped {
24 drop_loc: Location,
25 dropped_local: Local,
26 should_note_order: bool,
b7449926 27 },
0bf4aa26
XL
28 MustBeValidFor {
29 category: ConstraintCategory,
30 from_closure: bool,
31 span: Span,
32 region_name: RegionName,
33 opt_place_desc: Option<String>,
b7449926 34 },
0bf4aa26
XL
35 Unexplained,
36}
37
38#[derive(Clone, Copy)]
9fa01778 39pub(in crate::borrow_check) enum LaterUseKind {
0bf4aa26
XL
40 TraitCapture,
41 ClosureCapture,
42 Call,
43 FakeLetRead,
44 Other,
45}
46
47impl BorrowExplanation {
9fa01778 48 pub(in crate::borrow_check) fn is_explained(&self) -> bool {
0731742a
XL
49 match self {
50 BorrowExplanation::Unexplained => false,
51 _ => true,
52 }
53 }
dc9dc135 54 pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>(
0bf4aa26 55 &self,
dc9dc135
XL
56 tcx: TyCtxt<'tcx>,
57 body: &Body<'tcx>,
0bf4aa26
XL
58 err: &mut DiagnosticBuilder<'_>,
59 borrow_desc: &str,
532ac7d7 60 borrow_span: Option<Span>,
0bf4aa26
XL
61 ) {
62 match *self {
63 BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
64 let message = match later_use_kind {
532ac7d7
XL
65 LaterUseKind::TraitCapture => "captured here by trait object",
66 LaterUseKind::ClosureCapture => "captured here by closure",
67 LaterUseKind::Call => "used by call",
68 LaterUseKind::FakeLetRead => "stored here",
69 LaterUseKind::Other => "used here",
0bf4aa26 70 };
532ac7d7
XL
71 if !borrow_span.map(|sp| sp.overlaps(var_or_use_span)).unwrap_or(false) {
72 err.span_label(
73 var_or_use_span,
74 format!("{}borrow later {}", borrow_desc, message),
75 );
76 }
9fa01778 77 }
0bf4aa26
XL
78 BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
79 let message = match later_use_kind {
9fa01778
XL
80 LaterUseKind::TraitCapture => {
81 "borrow captured here by trait object, in later iteration of loop"
82 }
83 LaterUseKind::ClosureCapture => {
84 "borrow captured here by closure, in later iteration of loop"
85 }
86 LaterUseKind::Call => "borrow used by call, in later iteration of loop",
0bf4aa26
XL
87 LaterUseKind::FakeLetRead => "borrow later stored here",
88 LaterUseKind::Other => "borrow used here, in later iteration of loop",
89 };
90 err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
9fa01778
XL
91 }
92 BorrowExplanation::UsedLaterWhenDropped {
93 drop_loc,
94 dropped_local,
95 should_note_order,
96 } => {
dc9dc135 97 let local_decl = &body.local_decls[dropped_local];
0bf4aa26
XL
98 let (dtor_desc, type_desc) = match local_decl.ty.sty {
99 // If type is an ADT that implements Drop, then
100 // simplify output by reporting just the ADT name.
9fa01778
XL
101 ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => (
102 "`Drop` code",
532ac7d7 103 format!("type `{}`", tcx.def_path_str(adt.did)),
9fa01778 104 ),
0bf4aa26
XL
105
106 // Otherwise, just report the whole type (and use
107 // the intentionally fuzzy phrase "destructor")
9fa01778
XL
108 ty::Closure(..) => ("destructor", "closure".to_owned()),
109 ty::Generator(..) => ("destructor", "generator".to_owned()),
0bf4aa26
XL
110
111 _ => ("destructor", format!("type `{}`", local_decl.ty)),
112 };
113
114 match local_decl.name {
dc9dc135 115 Some(local_name) if !local_decl.from_compiler_desugaring() => {
9fa01778
XL
116 let message = format!(
117 "{B}borrow might be used here, when `{LOC}` is dropped \
118 and runs the {DTOR} for {TYPE}",
119 B = borrow_desc,
120 LOC = local_name,
121 TYPE = type_desc,
122 DTOR = dtor_desc
123 );
dc9dc135 124 err.span_label(body.source_info(drop_loc).span, message);
0bf4aa26
XL
125
126 if should_note_order {
127 err.note(
128 "values in a scope are dropped \
129 in the opposite order they are defined",
130 );
131 }
132 }
dc9dc135 133 _ => {
9fa01778
XL
134 err.span_label(
135 local_decl.source_info.span,
136 format!(
137 "a temporary with access to the {B}borrow \
138 is created here ...",
139 B = borrow_desc
140 ),
141 );
142 let message = format!(
143 "... and the {B}borrow might be used here, \
144 when that temporary is dropped \
145 and runs the {DTOR} for {TYPE}",
146 B = borrow_desc,
147 TYPE = type_desc,
148 DTOR = dtor_desc
149 );
dc9dc135 150 err.span_label(body.source_info(drop_loc).span, message);
0bf4aa26
XL
151
152 if let Some(info) = &local_decl.is_block_tail {
153 // FIXME: use span_suggestion instead, highlighting the
154 // whole block tail expression.
155 let msg = if info.tail_result_is_ignored {
156 "The temporary is part of an expression at the end of a block. \
157 Consider adding semicolon after the expression so its temporaries \
158 are dropped sooner, before the local variables declared by the \
159 block are dropped."
160 } else {
161 "The temporary is part of an expression at the end of a block. \
162 Consider forcing this temporary to be dropped sooner, before \
163 the block's local variables are dropped. \
164 For example, you could save the expression's value in a new \
165 local variable `x` and then make `x` be the expression \
166 at the end of the block."
167 };
168
169 err.note(msg);
170 }
171 }
172 }
9fa01778 173 }
0bf4aa26
XL
174 BorrowExplanation::MustBeValidFor {
175 category,
176 span,
177 ref region_name,
178 ref opt_place_desc,
179 from_closure: _,
180 } => {
181 region_name.highlight_region_name(err);
182
183 if let Some(desc) = opt_place_desc {
9fa01778
XL
184 err.span_label(
185 span,
186 format!(
187 "{}requires that `{}` is borrowed for `{}`",
188 category.description(),
189 desc,
190 region_name,
191 ),
192 );
0bf4aa26 193 } else {
9fa01778
XL
194 err.span_label(
195 span,
196 format!(
197 "{}requires that {}borrow lasts for `{}`",
198 category.description(),
199 borrow_desc,
200 region_name,
201 ),
202 );
0bf4aa26 203 };
9fa01778
XL
204 }
205 _ => {}
0bf4aa26
XL
206 }
207 }
b7449926
XL
208}
209
dc9dc135 210impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
0bf4aa26 211 /// Returns structured explanation for *why* the borrow contains the
48663c56 212 /// point from `location`. This is key for the "3-point errors"
0531ce1d
XL
213 /// [described in the NLL RFC][d].
214 ///
94b46f34
XL
215 /// # Parameters
216 ///
217 /// - `borrow`: the borrow in question
48663c56 218 /// - `location`: where the borrow occurs
94b46f34
XL
219 /// - `kind_place`: if Some, this describes the statement that triggered the error.
220 /// - first half is the kind of write, if any, being performed
221 /// - second half is the place being accessed
94b46f34 222 ///
0531ce1d 223 /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
9fa01778 224 pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
b7449926 225 &self,
48663c56 226 location: Location,
0531ce1d 227 borrow: &BorrowData<'tcx>,
94b46f34 228 kind_place: Option<(WriteKind, &Place<'tcx>)>,
0bf4aa26 229 ) -> BorrowExplanation {
8faf50e0 230 debug!(
48663c56
XL
231 "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
232 location, borrow, kind_place
8faf50e0
XL
233 );
234
235 let regioncx = &self.nonlexical_regioncx;
dc9dc135 236 let body = self.body;
0bf4aa26 237 let tcx = self.infcx.tcx;
ff7c6d11 238
a1dfa0c6 239 let borrow_region_vid = borrow.region;
8faf50e0
XL
240 debug!(
241 "explain_why_borrow_contains_point: borrow_region_vid={:?}",
242 borrow_region_vid
243 );
94b46f34 244
48663c56 245 let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, location);
8faf50e0
XL
246 debug!(
247 "explain_why_borrow_contains_point: region_sub={:?}",
248 region_sub
249 );
94b46f34 250
dc9dc135 251 match find_use::find(body, regioncx, tcx, region_sub, location) {
0bf4aa26 252 Some(Cause::LiveVar(local, location)) => {
dc9dc135 253 let span = body.source_info(location).span;
9fa01778 254 let spans = self
416331ca 255 .move_spans(Place::from(local).as_ref(), location)
b7449926 256 .or_else(|| self.borrow_spans(span, location));
0bf4aa26 257
48663c56 258 let borrow_location = location;
9fa01778 259 if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
0bf4aa26
XL
260 let later_use = self.later_use_kind(borrow, spans, location);
261 BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
b7449926 262 } else {
0bf4aa26
XL
263 // Check if the location represents a `FakeRead`, and adapt the error
264 // message to the `FakeReadCause` it is from: in particular,
265 // the ones inserted in optimized `let var = <expr>` patterns.
266 let later_use = self.later_use_kind(borrow, spans, location);
267 BorrowExplanation::UsedLater(later_use.0, later_use.1)
268 }
b7449926 269 }
8faf50e0 270
9fa01778
XL
271 Some(Cause::DropVar(local, location)) => {
272 let mut should_note_order = false;
dc9dc135 273 if body.local_decls[local].name.is_some() {
9fa01778 274 if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
416331ca
XL
275 if let Place {
276 base: PlaceBase::Local(borrowed_local),
277 projection: None,
278 } = place {
dc9dc135 279 if body.local_decls[*borrowed_local].name.is_some()
9fa01778
XL
280 && local != *borrowed_local
281 {
282 should_note_order = true;
283 }
284 }
285 }
286 }
287
288 BorrowExplanation::UsedLaterWhenDropped {
289 drop_loc: location,
290 dropped_local: local,
291 should_note_order,
292 }
b7449926 293 }
0bf4aa26 294
9fa01778
XL
295 None => {
296 if let Some(region) = regioncx.to_error_region_vid(borrow_region_vid) {
297 let (category, from_closure, span, region_name) =
298 self.nonlexical_regioncx.free_region_constraint_info(
dc9dc135 299 self.body,
48663c56 300 &self.upvars,
9fa01778
XL
301 self.mir_def_id,
302 self.infcx,
303 borrow_region_vid,
304 region,
305 );
306 if let Some(region_name) = region_name {
416331ca
XL
307 let opt_place_desc =
308 self.describe_place(borrow.borrowed_place.as_ref());
9fa01778
XL
309 BorrowExplanation::MustBeValidFor {
310 category,
311 from_closure,
312 span,
313 region_name,
314 opt_place_desc,
315 }
316 } else {
48663c56
XL
317 debug!("explain_why_borrow_contains_point: \
318 Could not generate a region name");
9fa01778 319 BorrowExplanation::Unexplained
0731742a
XL
320 }
321 } else {
48663c56
XL
322 debug!("explain_why_borrow_contains_point: \
323 Could not generate an error region vid");
0731742a 324 BorrowExplanation::Unexplained
0bf4aa26 325 }
b7449926 326 }
b7449926
XL
327 }
328 }
8faf50e0 329
9fa01778
XL
330 /// true if `borrow_location` can reach `use_location` by going through a loop and
331 /// `use_location` is also inside of that loop
332 fn is_use_in_later_iteration_of_loop(
b7449926
XL
333 &self,
334 borrow_location: Location,
9fa01778 335 use_location: Location,
b7449926 336 ) -> bool {
9fa01778
XL
337 let back_edge = self.reach_through_backedge(borrow_location, use_location);
338 back_edge.map_or(false, |back_edge| {
339 self.can_reach_head_of_loop(use_location, back_edge)
340 })
341 }
b7449926 342
9fa01778
XL
343 /// Returns the outmost back edge if `from` location can reach `to` location passing through
344 /// that back edge
345 fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> {
346 let mut visited_locations = FxHashSet::default();
347 let mut pending_locations = VecDeque::new();
348 visited_locations.insert(from);
349 pending_locations.push_back(from);
350 debug!("reach_through_backedge: from={:?} to={:?}", from, to,);
351
352 let mut outmost_back_edge = None;
353 while let Some(location) = pending_locations.pop_front() {
354 debug!(
355 "reach_through_backedge: location={:?} outmost_back_edge={:?}
356 pending_locations={:?} visited_locations={:?}",
357 location, outmost_back_edge, pending_locations, visited_locations
358 );
359
360 if location == to && outmost_back_edge.is_some() {
361 // We've managed to reach the use location
362 debug!("reach_through_backedge: found!");
363 return outmost_back_edge;
364 }
b7449926 365
dc9dc135 366 let block = &self.body.basic_blocks()[location.block];
9fa01778
XL
367
368 if location.statement_index < block.statements.len() {
369 let successor = location.successor_within_block();
370 if visited_locations.insert(successor) {
371 pending_locations.push_back(successor);
ff7c6d11 372 }
b7449926 373 } else {
9fa01778
XL
374 pending_locations.extend(
375 block
376 .terminator()
377 .successors()
378 .map(|bb| Location {
379 statement_index: 0,
380 block: *bb,
381 })
382 .filter(|s| visited_locations.insert(*s))
383 .map(|s| {
384 if self.is_back_edge(location, s) {
385 match outmost_back_edge {
386 None => {
387 outmost_back_edge = Some(location);
388 }
389
390 Some(back_edge)
391 if location.dominates(back_edge, &self.dominators) =>
392 {
393 outmost_back_edge = Some(location);
394 }
395
396 Some(_) => {}
397 }
398 }
399
400 s
401 }),
402 );
ff7c6d11 403 }
9fa01778
XL
404 }
405
406 None
407 }
408
409 /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the
410 /// intermediate nodes
411 fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool {
412 self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default())
413 }
414
415 fn find_loop_head_dfs(
416 &self,
417 from: Location,
418 loop_head: Location,
419 visited_locations: &mut FxHashSet<Location>,
420 ) -> bool {
421 visited_locations.insert(from);
422
423 if from == loop_head {
424 return true;
425 }
426
427 if loop_head.dominates(from, &self.dominators) {
dc9dc135 428 let block = &self.body.basic_blocks()[from.block];
9fa01778
XL
429
430 if from.statement_index < block.statements.len() {
431 let successor = from.successor_within_block();
432
433 if !visited_locations.contains(&successor)
434 && self.find_loop_head_dfs(successor, loop_head, visited_locations)
435 {
436 return true;
437 }
438 } else {
439 for bb in block.terminator().successors() {
440 let successor = Location {
441 statement_index: 0,
442 block: *bb,
443 };
b7449926 444
9fa01778
XL
445 if !visited_locations.contains(&successor)
446 && self.find_loop_head_dfs(successor, loop_head, visited_locations)
447 {
448 return true;
449 }
450 }
451 }
ff7c6d11 452 }
b7449926
XL
453
454 false
ff7c6d11 455 }
b7449926 456
9fa01778
XL
457 /// True if an edge `source -> target` is a backedge -- in other words, if the target
458 /// dominates the source.
459 fn is_back_edge(&self, source: Location, target: Location) -> bool {
dc9dc135 460 target.dominates(source, &self.body.dominators())
9fa01778
XL
461 }
462
0bf4aa26
XL
463 /// Determine how the borrow was later used.
464 fn later_use_kind(
465 &self,
466 borrow: &BorrowData<'tcx>,
467 use_spans: UseSpans,
9fa01778 468 location: Location,
0bf4aa26
XL
469 ) -> (LaterUseKind, Span) {
470 match use_spans {
471 UseSpans::ClosureUse { var_span, .. } => {
472 // Used in a closure.
473 (LaterUseKind::ClosureCapture, var_span)
9fa01778 474 }
0bf4aa26 475 UseSpans::OtherUse(span) => {
dc9dc135 476 let block = &self.body.basic_blocks()[location.block];
0bf4aa26
XL
477
478 let kind = if let Some(&Statement {
479 kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
480 ..
9fa01778
XL
481 }) = block.statements.get(location.statement_index)
482 {
0bf4aa26
XL
483 LaterUseKind::FakeLetRead
484 } else if self.was_captured_by_trait_object(borrow) {
485 LaterUseKind::TraitCapture
486 } else if location.statement_index == block.statements.len() {
487 if let TerminatorKind::Call {
9fa01778
XL
488 ref func,
489 from_hir_call: true,
490 ..
491 } = block.terminator().kind
492 {
0bf4aa26
XL
493 // Just point to the function, to reduce the chance of overlapping spans.
494 let function_span = match func {
495 Operand::Constant(c) => c.span,
416331ca
XL
496 Operand::Copy(Place {
497 base: PlaceBase::Local(l),
498 projection: None,
499 }) |
500 Operand::Move(Place {
501 base: PlaceBase::Local(l),
502 projection: None,
503 }) => {
dc9dc135 504 let local_decl = &self.body.local_decls[*l];
0bf4aa26
XL
505 if local_decl.name.is_none() {
506 local_decl.source_info.span
507 } else {
508 span
509 }
9fa01778 510 }
0bf4aa26
XL
511 _ => span,
512 };
513 return (LaterUseKind::Call, function_span);
514 } else {
515 LaterUseKind::Other
516 }
517 } else {
518 LaterUseKind::Other
519 };
520
521 (kind, span)
522 }
523 }
524 }
525
9fa01778 526 /// Checks if a borrowed value was captured by a trait object. We do this by
0bf4aa26
XL
527 /// looking forward in the MIR from the reserve location and checking if we see
528 /// a unsized cast to a trait object on our data.
529 fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
530 // Start at the reserve location, find the place that we want to see cast to a trait object.
531 let location = borrow.reserve_location;
dc9dc135 532 let block = &self.body[location.block];
0bf4aa26 533 let stmt = block.statements.get(location.statement_index);
9fa01778
XL
534 debug!(
535 "was_captured_by_trait_object: location={:?} stmt={:?}",
536 location, stmt
537 );
0bf4aa26
XL
538
539 // We make a `queue` vector that has the locations we want to visit. As of writing, this
540 // will only ever have one item at any given time, but by using a vector, we can pop from
541 // it which simplifies the termination logic.
542 let mut queue = vec![location];
543 let mut target = if let Some(&Statement {
416331ca
XL
544 kind: StatementKind::Assign(Place {
545 base: PlaceBase::Local(local),
546 projection: None,
547 }, _),
0bf4aa26 548 ..
9fa01778
XL
549 }) = stmt
550 {
0bf4aa26
XL
551 local
552 } else {
553 return false;
554 };
555
9fa01778
XL
556 debug!(
557 "was_captured_by_trait: target={:?} queue={:?}",
558 target, queue
559 );
0bf4aa26
XL
560 while let Some(current_location) = queue.pop() {
561 debug!("was_captured_by_trait: target={:?}", target);
dc9dc135 562 let block = &self.body[current_location.block];
0bf4aa26
XL
563 // We need to check the current location to find out if it is a terminator.
564 let is_terminator = current_location.statement_index == block.statements.len();
565 if !is_terminator {
566 let stmt = &block.statements[current_location.statement_index];
567 debug!("was_captured_by_trait_object: stmt={:?}", stmt);
568
569 // The only kind of statement that we care about is assignments...
9fa01778 570 if let StatementKind::Assign(place, box rvalue) = &stmt.kind {
416331ca
XL
571 let into = match place.local_or_deref_local() {
572 Some(into) => into,
573 None => {
0bf4aa26
XL
574 // Continue at the next location.
575 queue.push(current_location.successor_within_block());
576 continue;
9fa01778 577 }
0bf4aa26
XL
578 };
579
580 match rvalue {
581 // If we see a use, we should check whether it is our data, and if so
582 // update the place that we're looking for to that new place.
583 Rvalue::Use(operand) => match operand {
416331ca
XL
584 Operand::Copy(Place {
585 base: PlaceBase::Local(from),
586 projection: None,
587 })
588 | Operand::Move(Place {
589 base: PlaceBase::Local(from),
590 projection: None,
591 })
9fa01778
XL
592 if *from == target =>
593 {
416331ca 594 target = into;
9fa01778
XL
595 }
596 _ => {}
0bf4aa26
XL
597 },
598 // If we see a unsized cast, then if it is our data we should check
599 // whether it is being cast to a trait object.
48663c56
XL
600 Rvalue::Cast(
601 CastKind::Pointer(PointerCast::Unsize), operand, ty
602 ) => match operand {
416331ca
XL
603 Operand::Copy(Place {
604 base: PlaceBase::Local(from),
605 projection: None,
606 })
607 | Operand::Move(Place {
608 base: PlaceBase::Local(from),
609 projection: None,
610 })
9fa01778
XL
611 if *from == target =>
612 {
0bf4aa26
XL
613 debug!("was_captured_by_trait_object: ty={:?}", ty);
614 // Check the type for a trait object.
615 return match ty.sty {
616 // `&dyn Trait`
532ac7d7 617 ty::Ref(_, ty, _) if ty.is_trait() => true,
0bf4aa26 618 // `Box<dyn Trait>`
9fa01778 619 _ if ty.is_box() && ty.boxed_ty().is_trait() => true,
0bf4aa26
XL
620 // `dyn Trait`
621 _ if ty.is_trait() => true,
622 // Anything else.
623 _ => false,
624 };
9fa01778 625 }
0bf4aa26
XL
626 _ => return false,
627 },
9fa01778 628 _ => {}
0bf4aa26
XL
629 }
630 }
631
632 // Continue at the next location.
633 queue.push(current_location.successor_within_block());
634 } else {
635 // The only thing we need to do for terminators is progress to the next block.
636 let terminator = block.terminator();
637 debug!("was_captured_by_trait_object: terminator={:?}", terminator);
638
639 if let TerminatorKind::Call {
416331ca
XL
640 destination: Some((Place {
641 base: PlaceBase::Local(dest),
642 projection: None,
643 }, block)),
0bf4aa26
XL
644 args,
645 ..
9fa01778
XL
646 } = &terminator.kind
647 {
0bf4aa26
XL
648 debug!(
649 "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
650 target, dest, args
651 );
652 // Check if one of the arguments to this function is the target place.
653 let found_target = args.iter().any(|arg| {
416331ca
XL
654 if let Operand::Move(Place {
655 base: PlaceBase::Local(potential),
656 projection: None,
657 }) = arg {
0bf4aa26
XL
658 *potential == target
659 } else {
660 false
661 }
662 });
663
664 // If it is, follow this to the next block and update the target.
665 if found_target {
666 target = *dest;
667 queue.push(block.start_location());
668 }
669 }
670 }
671
672 debug!("was_captured_by_trait: queue={:?}", queue);
673 }
674
675 // We didn't find anything and ran out of locations to check.
676 false
677 }
678}