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