]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/move_errors.rs
Pass cflags rather than cxxflags to LLVM as CMAKE_C_FLAGS
[rust.git] / src / librustc_mir / borrow_check / move_errors.rs
1 use core::unicode::property::Pattern_White_Space;
2
3 use rustc::mir::*;
4 use rustc::ty::{self, Ty, TyCtxt};
5 use rustc_errors::{DiagnosticBuilder,Applicability};
6 use syntax_pos::Span;
7
8 use crate::borrow_check::MirBorrowckCtxt;
9 use crate::borrow_check::prefixes::PrefixSet;
10 use crate::borrow_check::error_reporting::UseSpans;
11 use crate::dataflow::move_paths::{
12     IllegalMoveOrigin, IllegalMoveOriginKind, InitLocation,
13     LookupResult, MoveError, MovePathIndex,
14 };
15 use crate::util::borrowck_errors::{BorrowckErrors, Origin};
16
17 // Often when desugaring a pattern match we may have many individual moves in
18 // MIR that are all part of one operation from the user's point-of-view. For
19 // example:
20 //
21 // let (x, y) = foo()
22 //
23 // would move x from the 0 field of some temporary, and y from the 1 field. We
24 // group such errors together for cleaner error reporting.
25 //
26 // Errors are kept separate if they are from places with different parent move
27 // paths. For example, this generates two errors:
28 //
29 // let (&x, &y) = (&String::new(), &String::new());
30 #[derive(Debug)]
31 enum GroupedMoveError<'tcx> {
32     // Place expression can't be moved from,
33     // e.g., match x[0] { s => (), } where x: &[String]
34     MovesFromPlace {
35         original_path: Place<'tcx>,
36         span: Span,
37         move_from: Place<'tcx>,
38         kind: IllegalMoveOriginKind<'tcx>,
39         binds_to: Vec<Local>,
40     },
41     // Part of a value expression can't be moved from,
42     // e.g., match &String::new() { &x => (), }
43     MovesFromValue {
44         original_path: Place<'tcx>,
45         span: Span,
46         move_from: MovePathIndex,
47         kind: IllegalMoveOriginKind<'tcx>,
48         binds_to: Vec<Local>,
49     },
50     // Everything that isn't from pattern matching.
51     OtherIllegalMove {
52         original_path: Place<'tcx>,
53         use_spans: UseSpans,
54         kind: IllegalMoveOriginKind<'tcx>,
55     },
56 }
57
58 enum BorrowedContentSource<'tcx> {
59     DerefRawPointer,
60     DerefMutableRef,
61     DerefSharedRef,
62     OverloadedDeref(Ty<'tcx>),
63     OverloadedIndex(Ty<'tcx>),
64 }
65
66 impl BorrowedContentSource<'tcx> {
67     fn describe_for_unnamed_place(&self) -> String {
68         match *self {
69             BorrowedContentSource::DerefRawPointer => format!("a raw pointer"),
70             BorrowedContentSource::DerefSharedRef => format!("a shared reference"),
71             BorrowedContentSource::DerefMutableRef => {
72                 format!("a mutable reference")
73             }
74             BorrowedContentSource::OverloadedDeref(ty) => {
75                 if ty.is_rc() {
76                    format!("an `Rc`")
77                 } else if ty.is_arc() {
78                     format!("an `Arc`")
79                 } else {
80                     format!("dereference of `{}`", ty)
81                 }
82             }
83             BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
84         }
85     }
86
87     fn describe_for_named_place(&self) -> Option<&'static str> {
88         match *self {
89             BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
90             BorrowedContentSource::DerefSharedRef => Some("shared reference"),
91             BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
92             // Overloaded deref and index operators should be evaluated into a
93             // temporary. So we don't need a description here.
94             BorrowedContentSource::OverloadedDeref(_)
95             | BorrowedContentSource::OverloadedIndex(_) => None
96         }
97     }
98
99     fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'_, '_, 'tcx>) -> Option<Self> {
100         match func.sty {
101             ty::FnDef(def_id, substs) => {
102                 let trait_id = tcx.trait_of_item(def_id)?;
103
104                 let lang_items = tcx.lang_items();
105                 if Some(trait_id) == lang_items.deref_trait()
106                     || Some(trait_id) == lang_items.deref_mut_trait()
107                 {
108                     Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
109                 } else if Some(trait_id) == lang_items.index_trait()
110                     || Some(trait_id) == lang_items.index_mut_trait()
111                 {
112                     Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
113                 } else {
114                     None
115                 }
116             }
117             _ => None,
118         }
119     }
120 }
121
122 impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
123     pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
124         let grouped_errors = self.group_move_errors(move_errors);
125         for error in grouped_errors {
126             self.report(error);
127         }
128     }
129
130     fn group_move_errors(
131         &self,
132         errors: Vec<(Place<'tcx>, MoveError<'tcx>)>
133     ) -> Vec<GroupedMoveError<'tcx>> {
134         let mut grouped_errors = Vec::new();
135         for (original_path, error) in errors {
136             self.append_to_grouped_errors(&mut grouped_errors, original_path, error);
137         }
138         grouped_errors
139     }
140
141     fn append_to_grouped_errors(
142         &self,
143         grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
144         original_path: Place<'tcx>,
145         error: MoveError<'tcx>,
146     ) {
147         match error {
148             MoveError::UnionMove { .. } => {
149                 unimplemented!("don't know how to report union move errors yet.")
150             }
151             MoveError::IllegalMove {
152                 cannot_move_out_of: IllegalMoveOrigin { location, kind },
153             } => {
154                 // Note: that the only time we assign a place isn't a temporary
155                 // to a user variable is when initializing it.
156                 // If that ever stops being the case, then the ever initialized
157                 // flow could be used.
158                 if let Some(StatementKind::Assign(
159                     Place::Base(PlaceBase::Local(local)),
160                     box Rvalue::Use(Operand::Move(move_from)),
161                 )) = self.mir.basic_blocks()[location.block]
162                     .statements
163                     .get(location.statement_index)
164                     .map(|stmt| &stmt.kind)
165                 {
166                     let local_decl = &self.mir.local_decls[*local];
167                     // opt_match_place is the
168                     // match_span is the span of the expression being matched on
169                     // match *x.y { ... }        match_place is Some(*x.y)
170                     //       ^^^^                match_span is the span of *x.y
171                     //
172                     // opt_match_place is None for let [mut] x = ... statements,
173                     // whether or not the right-hand side is a place expression
174                     if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
175                         opt_match_place: Some((ref opt_match_place, match_span)),
176                         binding_mode: _,
177                         opt_ty_info: _,
178                         pat_span: _,
179                     }))) = local_decl.is_user_variable
180                     {
181                         let stmt_source_info = self.mir.source_info(location);
182                         self.append_binding_error(
183                             grouped_errors,
184                             kind,
185                             original_path,
186                             move_from,
187                             *local,
188                             opt_match_place,
189                             match_span,
190                             stmt_source_info.span,
191                         );
192                         return;
193                     }
194                 }
195
196                 let move_spans = self.move_spans(&original_path, location);
197                 grouped_errors.push(GroupedMoveError::OtherIllegalMove {
198                     use_spans: move_spans,
199                     original_path,
200                     kind,
201                 });
202             }
203         }
204     }
205
206     fn append_binding_error(
207         &self,
208         grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
209         kind: IllegalMoveOriginKind<'tcx>,
210         original_path: Place<'tcx>,
211         move_from: &Place<'tcx>,
212         bind_to: Local,
213         match_place: &Option<Place<'tcx>>,
214         match_span: Span,
215         statement_span: Span,
216     ) {
217         debug!(
218             "append_binding_error(match_place={:?}, match_span={:?})",
219             match_place, match_span
220         );
221
222         let from_simple_let = match_place.is_none();
223         let match_place = match_place.as_ref().unwrap_or(move_from);
224
225         match self.move_data.rev_lookup.find(match_place) {
226             // Error with the match place
227             LookupResult::Parent(_) => {
228                 for ge in &mut *grouped_errors {
229                     if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge {
230                         if match_span == *span {
231                             debug!("appending local({:?}) to list", bind_to);
232                             if !binds_to.is_empty() {
233                                 binds_to.push(bind_to);
234                             }
235                             return;
236                         }
237                     }
238                 }
239                 debug!("found a new move error location");
240
241                 // Don't need to point to x in let x = ... .
242                 let (binds_to, span) = if from_simple_let {
243                     (vec![], statement_span)
244                 } else {
245                     (vec![bind_to], match_span)
246                 };
247                 grouped_errors.push(GroupedMoveError::MovesFromPlace {
248                     span,
249                     move_from: match_place.clone(),
250                     original_path,
251                     kind,
252                     binds_to,
253                 });
254             }
255             // Error with the pattern
256             LookupResult::Exact(_) => {
257                 let mpi = match self.move_data.rev_lookup.find(move_from) {
258                     LookupResult::Parent(Some(mpi)) => mpi,
259                     // move_from should be a projection from match_place.
260                     _ => unreachable!("Probably not unreachable..."),
261                 };
262                 for ge in &mut *grouped_errors {
263                     if let GroupedMoveError::MovesFromValue {
264                         span,
265                         move_from: other_mpi,
266                         binds_to,
267                         ..
268                     } = ge
269                     {
270                         if match_span == *span && mpi == *other_mpi {
271                             debug!("appending local({:?}) to list", bind_to);
272                             binds_to.push(bind_to);
273                             return;
274                         }
275                     }
276                 }
277                 debug!("found a new move error location");
278                 grouped_errors.push(GroupedMoveError::MovesFromValue {
279                     span: match_span,
280                     move_from: mpi,
281                     original_path,
282                     kind,
283                     binds_to: vec![bind_to],
284                 });
285             }
286         };
287     }
288
289     fn report(&mut self, error: GroupedMoveError<'tcx>) {
290         let (mut err, err_span) = {
291             let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
292                 match error {
293                     GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
294                     GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
295                         (span, original_path, kind)
296                     }
297                     GroupedMoveError::OtherIllegalMove {
298                         use_spans,
299                         ref original_path,
300                         ref kind
301                     } => {
302                         (use_spans.args_or_use(), original_path, kind)
303                     },
304                 };
305             debug!("report: original_path={:?} span={:?}, kind={:?} \
306                    original_path.is_upvar_field_projection={:?}", original_path, span, kind,
307                    self.is_upvar_field_projection(original_path));
308             (
309                 match kind {
310                     IllegalMoveOriginKind::Static => {
311                         self.report_cannot_move_from_static(original_path, span)
312                     }
313                     IllegalMoveOriginKind::BorrowedContent { target_place } => {
314                         self.report_cannot_move_from_borrowed_content(
315                             original_path,
316                             target_place,
317                             span,
318                         )
319                     }
320                     IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
321                         self.infcx.tcx
322                             .cannot_move_out_of_interior_of_drop(span, ty, Origin::Mir)
323                     }
324                     IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
325                         self.infcx.tcx.cannot_move_out_of_interior_noncopy(
326                             span, ty, Some(*is_index), Origin::Mir
327                         ),
328                 },
329                 span,
330             )
331         };
332
333         self.add_move_hints(error, &mut err, err_span);
334         err.buffer(&mut self.errors_buffer);
335     }
336
337     fn report_cannot_move_from_static(
338         &mut self,
339         place: &Place<'tcx>,
340         span: Span
341     ) -> DiagnosticBuilder<'a> {
342         let mut base_static = place;
343         loop {
344             match base_static {
345                 Place::Base(_) => break,
346                 Place::Projection(box Projection { base, .. }) => base_static = base,
347             }
348         }
349
350         let description = if let Place::Base(_) = place {
351             format!("static item `{}`", self.describe_place(place).unwrap())
352         } else {
353             format!(
354                 "`{:?}` as `{:?}` is a static item",
355                 self.describe_place(place).unwrap(),
356                 self.describe_place(base_static).unwrap(),
357             )
358         };
359
360         self.infcx.tcx.cannot_move_out_of(span, &description, Origin::Mir)
361     }
362
363     fn report_cannot_move_from_borrowed_content(
364         &mut self,
365         move_place: &Place<'tcx>,
366         deref_target_place: &Place<'tcx>,
367         span: Span,
368     ) -> DiagnosticBuilder<'a> {
369         let origin = Origin::Mir;
370
371         // Inspect the type of the content behind the
372         // borrow to provide feedback about why this
373         // was a move rather than a copy.
374         let ty = deref_target_place.ty(self.mir, self.infcx.tcx).ty;
375         let upvar_field = self.prefixes(&move_place, PrefixSet::All)
376             .find_map(|p| self.is_upvar_field_projection(p));
377
378         let deref_base = match deref_target_place {
379             Place::Projection(box Projection { base, elem: ProjectionElem::Deref }) => base,
380             _ => bug!("deref_target_place is not a deref projection"),
381         };
382
383         if let Place::Base(PlaceBase::Local(local)) = *deref_base {
384             let decl = &self.mir.local_decls[local];
385             if decl.is_ref_for_guard() {
386                 let mut err = self.infcx.tcx.cannot_move_out_of(
387                     span,
388                     &format!("`{}` in pattern guard", decl.name.unwrap()),
389                     origin,
390                 );
391                 err.note(
392                     "variables bound in patterns cannot be moved from \
393                      until after the end of the pattern guard");
394                 return err;
395             }
396         }
397
398         debug!("report: ty={:?}", ty);
399         let mut err = match ty.sty {
400             ty::Array(..) | ty::Slice(..) =>
401                 self.infcx.tcx.cannot_move_out_of_interior_noncopy(
402                     span, ty, None, origin
403                 ),
404             ty::Closure(def_id, closure_substs)
405                 if def_id == self.mir_def_id && upvar_field.is_some()
406             => {
407                 let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
408                 let closure_kind = closure_kind_ty.to_opt_closure_kind();
409                 let capture_description = match closure_kind {
410                     Some(ty::ClosureKind::Fn) => {
411                         "captured variable in an `Fn` closure"
412                     }
413                     Some(ty::ClosureKind::FnMut) => {
414                         "captured variable in an `FnMut` closure"
415                     }
416                     Some(ty::ClosureKind::FnOnce) => {
417                         bug!("closure kind does not match first argument type")
418                     }
419                     None => bug!("closure kind not inferred by borrowck"),
420                 };
421
422                 let upvar = &self.upvars[upvar_field.unwrap().index()];
423                 let upvar_hir_id = upvar.var_hir_id;
424                 let upvar_name = upvar.name;
425                 let upvar_span = self.infcx.tcx.hir().span_by_hir_id(upvar_hir_id);
426
427                 let place_name = self.describe_place(move_place).unwrap();
428
429                 let place_description = if self.is_upvar_field_projection(move_place).is_some() {
430                     format!("`{}`, a {}", place_name, capture_description)
431                 } else {
432                     format!(
433                         "`{}`, as `{}` is a {}",
434                         place_name,
435                         upvar_name,
436                         capture_description,
437                     )
438                 };
439
440                 debug!(
441                     "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",
442                     closure_kind_ty, closure_kind, place_description,
443                 );
444
445                 let mut diag = self.infcx.tcx.cannot_move_out_of(span, &place_description, origin);
446
447                 diag.span_label(upvar_span, "captured outer variable");
448
449                 diag
450             }
451             _ => {
452                 let source = self.borrowed_content_source(deref_base);
453                 match (self.describe_place(move_place), source.describe_for_named_place()) {
454                     (Some(place_desc), Some(source_desc)) => {
455                         self.infcx.tcx.cannot_move_out_of(
456                             span,
457                             &format!("`{}` which is behind a {}", place_desc, source_desc),
458                             origin,
459                         )
460                     }
461                     (_, _) => {
462                         self.infcx.tcx.cannot_move_out_of(
463                             span,
464                             &source.describe_for_unnamed_place(),
465                             origin,
466                         )
467                     }
468                 }
469             },
470         };
471         let move_ty = format!(
472             "{:?}",
473             move_place.ty(self.mir, self.infcx.tcx).ty,
474         );
475         let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap();
476         let is_option = move_ty.starts_with("std::option::Option");
477         let is_result = move_ty.starts_with("std::result::Result");
478         if  is_option || is_result {
479             err.span_suggestion(
480                 span,
481                 &format!("consider borrowing the `{}`'s content", if is_option {
482                     "Option"
483                 } else {
484                     "Result"
485                 }),
486                 format!("{}.as_ref()", snippet),
487                 Applicability::MaybeIncorrect,
488             );
489         }
490         err
491     }
492
493     fn add_move_hints(
494         &self,
495         error: GroupedMoveError<'tcx>,
496         err: &mut DiagnosticBuilder<'a>,
497         span: Span,
498     ) {
499         let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap();
500         match error {
501             GroupedMoveError::MovesFromPlace {
502                 mut binds_to,
503                 move_from,
504                 ..
505             } => {
506                 let try_remove_deref = match move_from {
507                     Place::Projection(box Projection {
508                         elem: ProjectionElem::Deref,
509                         ..
510                     }) => true,
511                     _ => false,
512                 };
513                 if try_remove_deref && snippet.starts_with('*') {
514                     // The snippet doesn't start with `*` in (e.g.) index
515                     // expressions `a[b]`, which roughly desugar to
516                     // `*Index::index(&a, b)` or
517                     // `*IndexMut::index_mut(&mut a, b)`.
518                     err.span_suggestion(
519                         span,
520                         "consider removing the `*`",
521                         snippet[1..].to_owned(),
522                         Applicability::Unspecified,
523                     );
524                 } else {
525                     err.span_suggestion(
526                         span,
527                         "consider borrowing here",
528                         format!("&{}", snippet),
529                         Applicability::Unspecified,
530                     );
531                 }
532
533                 if binds_to.is_empty() {
534                     let place_ty = move_from.ty(self.mir, self.infcx.tcx).ty;
535                     let place_desc = match self.describe_place(&move_from) {
536                         Some(desc) => format!("`{}`", desc),
537                         None => format!("value"),
538                     };
539
540                     self.note_type_does_not_implement_copy(
541                         err,
542                         &place_desc,
543                         place_ty,
544                         Some(span)
545                     );
546                 } else {
547                     binds_to.sort();
548                     binds_to.dedup();
549
550                     self.add_move_error_details(err, &binds_to);
551                 }
552             }
553             GroupedMoveError::MovesFromValue { mut binds_to, .. } => {
554                 binds_to.sort();
555                 binds_to.dedup();
556                 self.add_move_error_suggestions(err, &binds_to);
557                 self.add_move_error_details(err, &binds_to);
558             }
559             // No binding. Nothing to suggest.
560             GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
561                 let span = use_spans.var_or_use();
562                 let place_ty = original_path.ty(self.mir, self.infcx.tcx).ty;
563                 let place_desc = match self.describe_place(original_path) {
564                     Some(desc) => format!("`{}`", desc),
565                     None => format!("value"),
566                 };
567                 self.note_type_does_not_implement_copy(
568                     err,
569                     &place_desc,
570                     place_ty,
571                     Some(span),
572                 );
573
574                 use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
575                 use_spans.var_span_label(
576                     err,
577                     format!("move occurs due to use{}", use_spans.describe()),
578                 );
579             },
580         }
581     }
582
583     fn add_move_error_suggestions(
584         &self,
585         err: &mut DiagnosticBuilder<'a>,
586         binds_to: &[Local],
587     ) {
588         let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
589         for local in binds_to {
590             let bind_to = &self.mir.local_decls[*local];
591             if let Some(
592                 ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
593                     pat_span,
594                     ..
595                 }))
596             ) = bind_to.is_user_variable {
597                 let pat_snippet = self.infcx.tcx.sess.source_map()
598                     .span_to_snippet(pat_span)
599                     .unwrap();
600                 if pat_snippet.starts_with('&') {
601                     let pat_snippet = pat_snippet[1..].trim_start();
602                     let suggestion;
603                     let to_remove;
604                     if pat_snippet.starts_with("mut")
605                         && pat_snippet["mut".len()..].starts_with(Pattern_White_Space)
606                     {
607                         suggestion = pat_snippet["mut".len()..].trim_start();
608                         to_remove = "&mut";
609                     } else {
610                         suggestion = pat_snippet;
611                         to_remove = "&";
612                     }
613                     suggestions.push((
614                         pat_span,
615                         to_remove,
616                         suggestion.to_owned(),
617                     ));
618                 }
619             }
620         }
621         suggestions.sort_unstable_by_key(|&(span, _, _)| span);
622         suggestions.dedup_by_key(|&mut (span, _, _)| span);
623         for (span, to_remove, suggestion) in suggestions {
624             err.span_suggestion(
625                 span,
626                 &format!("consider removing the `{}`", to_remove),
627                 suggestion,
628                 Applicability::MachineApplicable,
629             );
630         }
631     }
632
633     fn add_move_error_details(
634         &self,
635         err: &mut DiagnosticBuilder<'a>,
636         binds_to: &[Local],
637     ) {
638         let mut noncopy_var_spans = Vec::new();
639         for (j, local) in binds_to.into_iter().enumerate() {
640             let bind_to = &self.mir.local_decls[*local];
641             let binding_span = bind_to.source_info.span;
642
643             if j == 0 {
644                 err.span_label(binding_span, "data moved here");
645             } else {
646                 err.span_label(binding_span, "...and here");
647             }
648
649             if binds_to.len() == 1 {
650                 self.note_type_does_not_implement_copy(
651                     err,
652                     &format!("`{}`", bind_to.name.unwrap()),
653                     bind_to.ty,
654                     Some(binding_span)
655                 );
656             } else {
657                 noncopy_var_spans.push(binding_span);
658             }
659         }
660
661         if binds_to.len() > 1 {
662             err.span_note(
663                 noncopy_var_spans,
664                 "move occurs because these variables have types that \
665                     don't implement the `Copy` trait",
666             );
667         }
668     }
669
670     fn borrowed_content_source(&self, deref_base: &Place<'tcx>) -> BorrowedContentSource<'tcx> {
671         let tcx = self.infcx.tcx;
672
673         // Look up the provided place and work out the move path index for it,
674         // we'll use this to check whether it was originally from an overloaded
675         // operator.
676         match self.move_data.rev_lookup.find(deref_base) {
677             LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
678                 debug!("borrowed_content_source: mpi={:?}", mpi);
679
680                 for i in &self.move_data.init_path_map[mpi] {
681                     let init = &self.move_data.inits[*i];
682                     debug!("borrowed_content_source: init={:?}", init);
683                     // We're only interested in statements that initialized a value, not the
684                     // initializations from arguments.
685                     let loc = match init.location {
686                         InitLocation::Statement(stmt) => stmt,
687                         _ => continue,
688                     };
689
690                     let bbd = &self.mir[loc.block];
691                     let is_terminator = bbd.statements.len() == loc.statement_index;
692                     debug!(
693                         "borrowed_content_source: loc={:?} is_terminator={:?}",
694                         loc,
695                         is_terminator,
696                     );
697                     if !is_terminator {
698                         continue;
699                     } else if let Some(Terminator {
700                         kind: TerminatorKind::Call {
701                             ref func,
702                             from_hir_call: false,
703                             ..
704                         },
705                         ..
706                     }) = bbd.terminator {
707                         if let Some(source)
708                             = BorrowedContentSource::from_call(func.ty(self.mir, tcx), tcx)
709                         {
710                             return source;
711                         }
712                     }
713                 }
714             }
715             // Base is a `static` so won't be from an overloaded operator
716             _ => (),
717         };
718
719         // If we didn't find an overloaded deref or index, then assume it's a
720         // built in deref and check the type of the base.
721         let base_ty = deref_base.ty(self.mir, tcx).ty;
722         if base_ty.is_unsafe_ptr() {
723             BorrowedContentSource::DerefRawPointer
724         } else if base_ty.is_mutable_pointer() {
725             BorrowedContentSource::DerefMutableRef
726         } else {
727             BorrowedContentSource::DerefSharedRef
728         }
729     }
730 }