]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | // Copyright 2018 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. | |
4 | // | |
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. | |
10 | ||
b7449926 | 11 | use core::unicode::property::Pattern_White_Space; |
0bf4aa26 XL |
12 | use std::fmt::{self, Display}; |
13 | ||
8faf50e0 XL |
14 | use rustc::mir::*; |
15 | use rustc::ty; | |
0bf4aa26 | 16 | use rustc_errors::{DiagnosticBuilder,Applicability}; |
8faf50e0 XL |
17 | use syntax_pos::Span; |
18 | ||
19 | use borrow_check::MirBorrowckCtxt; | |
b7449926 | 20 | use borrow_check::prefixes::PrefixSet; |
0bf4aa26 XL |
21 | use dataflow::move_paths::{ |
22 | IllegalMoveOrigin, IllegalMoveOriginKind, InitLocation, | |
23 | LookupResult, MoveError, MovePathIndex, | |
24 | }; | |
8faf50e0 XL |
25 | use util::borrowck_errors::{BorrowckErrors, Origin}; |
26 | ||
27 | // Often when desugaring a pattern match we may have many individual moves in | |
28 | // MIR that are all part of one operation from the user's point-of-view. For | |
29 | // example: | |
30 | // | |
31 | // let (x, y) = foo() | |
32 | // | |
33 | // would move x from the 0 field of some temporary, and y from the 1 field. We | |
34 | // group such errors together for cleaner error reporting. | |
35 | // | |
36 | // Errors are kept separate if they are from places with different parent move | |
37 | // paths. For example, this generates two errors: | |
38 | // | |
39 | // let (&x, &y) = (&String::new(), &String::new()); | |
40 | #[derive(Debug)] | |
41 | enum GroupedMoveError<'tcx> { | |
b7449926 | 42 | // Place expression can't be moved from, |
8faf50e0 | 43 | // e.g. match x[0] { s => (), } where x: &[String] |
b7449926 XL |
44 | MovesFromPlace { |
45 | original_path: Place<'tcx>, | |
8faf50e0 XL |
46 | span: Span, |
47 | move_from: Place<'tcx>, | |
48 | kind: IllegalMoveOriginKind<'tcx>, | |
49 | binds_to: Vec<Local>, | |
50 | }, | |
b7449926 | 51 | // Part of a value expression can't be moved from, |
8faf50e0 | 52 | // e.g. match &String::new() { &x => (), } |
b7449926 XL |
53 | MovesFromValue { |
54 | original_path: Place<'tcx>, | |
8faf50e0 XL |
55 | span: Span, |
56 | move_from: MovePathIndex, | |
57 | kind: IllegalMoveOriginKind<'tcx>, | |
58 | binds_to: Vec<Local>, | |
59 | }, | |
60 | // Everything that isn't from pattern matching. | |
61 | OtherIllegalMove { | |
b7449926 | 62 | original_path: Place<'tcx>, |
8faf50e0 XL |
63 | span: Span, |
64 | kind: IllegalMoveOriginKind<'tcx>, | |
65 | }, | |
66 | } | |
67 | ||
0bf4aa26 XL |
68 | enum BorrowedContentSource { |
69 | Arc, | |
70 | Rc, | |
71 | DerefRawPointer, | |
72 | Other, | |
73 | } | |
74 | ||
75 | impl Display for BorrowedContentSource { | |
76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
77 | match *self { | |
78 | BorrowedContentSource::Arc => write!(f, "an `Arc`"), | |
79 | BorrowedContentSource::Rc => write!(f, "an `Rc`"), | |
80 | BorrowedContentSource::DerefRawPointer => write!(f, "dereference of raw pointer"), | |
81 | BorrowedContentSource::Other => write!(f, "borrowed content"), | |
82 | } | |
83 | } | |
84 | } | |
85 | ||
8faf50e0 | 86 | impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { |
b7449926 | 87 | pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) { |
8faf50e0 XL |
88 | let grouped_errors = self.group_move_errors(move_errors); |
89 | for error in grouped_errors { | |
90 | self.report(error); | |
91 | } | |
92 | } | |
93 | ||
b7449926 XL |
94 | fn group_move_errors( |
95 | &self, | |
96 | errors: Vec<(Place<'tcx>, MoveError<'tcx>)> | |
97 | ) -> Vec<GroupedMoveError<'tcx>> { | |
8faf50e0 | 98 | let mut grouped_errors = Vec::new(); |
b7449926 XL |
99 | for (original_path, error) in errors { |
100 | self.append_to_grouped_errors(&mut grouped_errors, original_path, error); | |
8faf50e0 XL |
101 | } |
102 | grouped_errors | |
103 | } | |
104 | ||
105 | fn append_to_grouped_errors( | |
106 | &self, | |
107 | grouped_errors: &mut Vec<GroupedMoveError<'tcx>>, | |
b7449926 | 108 | original_path: Place<'tcx>, |
8faf50e0 XL |
109 | error: MoveError<'tcx>, |
110 | ) { | |
111 | match error { | |
112 | MoveError::UnionMove { .. } => { | |
113 | unimplemented!("don't know how to report union move errors yet.") | |
114 | } | |
115 | MoveError::IllegalMove { | |
116 | cannot_move_out_of: IllegalMoveOrigin { location, kind }, | |
117 | } => { | |
118 | let stmt_source_info = self.mir.source_info(location); | |
119 | // Note: that the only time we assign a place isn't a temporary | |
120 | // to a user variable is when initializing it. | |
121 | // If that ever stops being the case, then the ever initialized | |
122 | // flow could be used. | |
123 | if let Some(StatementKind::Assign( | |
124 | Place::Local(local), | |
0bf4aa26 | 125 | box Rvalue::Use(Operand::Move(move_from)), |
8faf50e0 XL |
126 | )) = self.mir.basic_blocks()[location.block] |
127 | .statements | |
128 | .get(location.statement_index) | |
129 | .map(|stmt| &stmt.kind) | |
130 | { | |
131 | let local_decl = &self.mir.local_decls[*local]; | |
132 | // opt_match_place is the | |
133 | // match_span is the span of the expression being matched on | |
134 | // match *x.y { ... } match_place is Some(*x.y) | |
135 | // ^^^^ match_span is the span of *x.y | |
136 | // | |
137 | // opt_match_place is None for let [mut] x = ... statements, | |
138 | // whether or not the right-hand side is a place expression | |
139 | if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { | |
140 | opt_match_place: Some((ref opt_match_place, match_span)), | |
141 | binding_mode: _, | |
142 | opt_ty_info: _, | |
b7449926 | 143 | pat_span: _, |
8faf50e0 XL |
144 | }))) = local_decl.is_user_variable |
145 | { | |
146 | self.append_binding_error( | |
147 | grouped_errors, | |
148 | kind, | |
b7449926 | 149 | original_path, |
8faf50e0 XL |
150 | move_from, |
151 | *local, | |
152 | opt_match_place, | |
153 | match_span, | |
154 | stmt_source_info.span, | |
155 | ); | |
156 | return; | |
157 | } | |
158 | } | |
159 | grouped_errors.push(GroupedMoveError::OtherIllegalMove { | |
160 | span: stmt_source_info.span, | |
b7449926 | 161 | original_path, |
8faf50e0 XL |
162 | kind, |
163 | }); | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | fn append_binding_error( | |
169 | &self, | |
170 | grouped_errors: &mut Vec<GroupedMoveError<'tcx>>, | |
171 | kind: IllegalMoveOriginKind<'tcx>, | |
b7449926 | 172 | original_path: Place<'tcx>, |
8faf50e0 XL |
173 | move_from: &Place<'tcx>, |
174 | bind_to: Local, | |
175 | match_place: &Option<Place<'tcx>>, | |
176 | match_span: Span, | |
177 | statement_span: Span, | |
178 | ) { | |
179 | debug!( | |
b7449926 | 180 | "append_binding_error(match_place={:?}, match_span={:?})", |
8faf50e0 XL |
181 | match_place, match_span |
182 | ); | |
183 | ||
184 | let from_simple_let = match_place.is_none(); | |
185 | let match_place = match_place.as_ref().unwrap_or(move_from); | |
186 | ||
187 | match self.move_data.rev_lookup.find(match_place) { | |
188 | // Error with the match place | |
189 | LookupResult::Parent(_) => { | |
190 | for ge in &mut *grouped_errors { | |
b7449926 | 191 | if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge { |
8faf50e0 XL |
192 | if match_span == *span { |
193 | debug!("appending local({:?}) to list", bind_to); | |
194 | if !binds_to.is_empty() { | |
195 | binds_to.push(bind_to); | |
196 | } | |
197 | return; | |
198 | } | |
199 | } | |
200 | } | |
201 | debug!("found a new move error location"); | |
202 | ||
203 | // Don't need to point to x in let x = ... . | |
204 | let (binds_to, span) = if from_simple_let { | |
205 | (vec![], statement_span) | |
206 | } else { | |
207 | (vec![bind_to], match_span) | |
208 | }; | |
b7449926 | 209 | grouped_errors.push(GroupedMoveError::MovesFromPlace { |
8faf50e0 XL |
210 | span, |
211 | move_from: match_place.clone(), | |
b7449926 | 212 | original_path, |
8faf50e0 XL |
213 | kind, |
214 | binds_to, | |
215 | }); | |
216 | } | |
217 | // Error with the pattern | |
218 | LookupResult::Exact(_) => { | |
219 | let mpi = match self.move_data.rev_lookup.find(move_from) { | |
220 | LookupResult::Parent(Some(mpi)) => mpi, | |
221 | // move_from should be a projection from match_place. | |
222 | _ => unreachable!("Probably not unreachable..."), | |
223 | }; | |
224 | for ge in &mut *grouped_errors { | |
b7449926 | 225 | if let GroupedMoveError::MovesFromValue { |
8faf50e0 XL |
226 | span, |
227 | move_from: other_mpi, | |
228 | binds_to, | |
229 | .. | |
230 | } = ge | |
231 | { | |
232 | if match_span == *span && mpi == *other_mpi { | |
233 | debug!("appending local({:?}) to list", bind_to); | |
234 | binds_to.push(bind_to); | |
235 | return; | |
236 | } | |
237 | } | |
238 | } | |
239 | debug!("found a new move error location"); | |
b7449926 | 240 | grouped_errors.push(GroupedMoveError::MovesFromValue { |
8faf50e0 XL |
241 | span: match_span, |
242 | move_from: mpi, | |
b7449926 | 243 | original_path, |
8faf50e0 XL |
244 | kind, |
245 | binds_to: vec![bind_to], | |
246 | }); | |
247 | } | |
248 | }; | |
249 | } | |
250 | ||
251 | fn report(&mut self, error: GroupedMoveError<'tcx>) { | |
252 | let (mut err, err_span) = { | |
b7449926 XL |
253 | let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind) = |
254 | match error { | |
255 | GroupedMoveError::MovesFromPlace { | |
256 | span, | |
257 | ref original_path, | |
258 | ref kind, | |
259 | .. | |
260 | } | | |
261 | GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } | | |
262 | GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => { | |
263 | (span, original_path, kind) | |
264 | }, | |
265 | }; | |
8faf50e0 | 266 | let origin = Origin::Mir; |
b7449926 XL |
267 | debug!("report: original_path={:?} span={:?}, kind={:?} \ |
268 | original_path.is_upvar_field_projection={:?}", original_path, span, kind, | |
0bf4aa26 | 269 | original_path.is_upvar_field_projection(self.mir, &self.infcx.tcx)); |
8faf50e0 XL |
270 | ( |
271 | match kind { | |
272 | IllegalMoveOriginKind::Static => { | |
0bf4aa26 | 273 | self.infcx.tcx.cannot_move_out_of(span, "static item", origin) |
8faf50e0 XL |
274 | } |
275 | IllegalMoveOriginKind::BorrowedContent { target_place: place } => { | |
276 | // Inspect the type of the content behind the | |
277 | // borrow to provide feedback about why this | |
278 | // was a move rather than a copy. | |
0bf4aa26 | 279 | let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); |
b7449926 XL |
280 | let is_upvar_field_projection = |
281 | self.prefixes(&original_path, PrefixSet::All) | |
0bf4aa26 | 282 | .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) |
b7449926 | 283 | .is_some()); |
0bf4aa26 | 284 | debug!("report: ty={:?}", ty); |
8faf50e0 | 285 | match ty.sty { |
0bf4aa26 XL |
286 | ty::Array(..) | ty::Slice(..) => |
287 | self.infcx.tcx.cannot_move_out_of_interior_noncopy( | |
288 | span, ty, None, origin | |
289 | ), | |
b7449926 XL |
290 | ty::Closure(def_id, closure_substs) |
291 | if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection | |
292 | => { | |
8faf50e0 | 293 | let closure_kind_ty = |
0bf4aa26 | 294 | closure_substs.closure_kind_ty(def_id, self.infcx.tcx); |
8faf50e0 XL |
295 | let closure_kind = closure_kind_ty.to_opt_closure_kind(); |
296 | let place_description = match closure_kind { | |
297 | Some(ty::ClosureKind::Fn) => { | |
298 | "captured variable in an `Fn` closure" | |
299 | } | |
300 | Some(ty::ClosureKind::FnMut) => { | |
301 | "captured variable in an `FnMut` closure" | |
302 | } | |
303 | Some(ty::ClosureKind::FnOnce) => { | |
304 | bug!("closure kind does not match first argument type") | |
305 | } | |
306 | None => bug!("closure kind not inferred by borrowck"), | |
307 | }; | |
b7449926 XL |
308 | debug!("report: closure_kind_ty={:?} closure_kind={:?} \ |
309 | place_description={:?}", closure_kind_ty, closure_kind, | |
310 | place_description); | |
311 | ||
0bf4aa26 | 312 | let mut diag = self.infcx.tcx.cannot_move_out_of( |
b7449926 XL |
313 | span, place_description, origin); |
314 | ||
315 | for prefix in self.prefixes(&original_path, PrefixSet::All) { | |
316 | if let Some(field) = prefix.is_upvar_field_projection( | |
0bf4aa26 | 317 | self.mir, &self.infcx.tcx) { |
b7449926 XL |
318 | let upvar_decl = &self.mir.upvar_decls[field.index()]; |
319 | let upvar_hir_id = | |
320 | upvar_decl.var_hir_id.assert_crate_local(); | |
321 | let upvar_node_id = | |
0bf4aa26 XL |
322 | self.infcx.tcx.hir.hir_to_node_id(upvar_hir_id); |
323 | let upvar_span = self.infcx.tcx.hir.span(upvar_node_id); | |
b7449926 XL |
324 | diag.span_label(upvar_span, "captured outer variable"); |
325 | break; | |
326 | } | |
327 | } | |
328 | ||
329 | diag | |
8faf50e0 | 330 | } |
0bf4aa26 XL |
331 | _ => { |
332 | let source = self.borrowed_content_source(place); | |
333 | self.infcx.tcx.cannot_move_out_of( | |
334 | span, &source.to_string(), origin | |
335 | ) | |
336 | }, | |
8faf50e0 XL |
337 | } |
338 | } | |
339 | IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { | |
0bf4aa26 | 340 | self.infcx.tcx |
8faf50e0 XL |
341 | .cannot_move_out_of_interior_of_drop(span, ty, origin) |
342 | } | |
0bf4aa26 XL |
343 | IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => |
344 | self.infcx.tcx.cannot_move_out_of_interior_noncopy( | |
345 | span, ty, Some(*is_index), origin | |
346 | ), | |
8faf50e0 XL |
347 | }, |
348 | span, | |
349 | ) | |
350 | }; | |
351 | ||
352 | self.add_move_hints(error, &mut err, err_span); | |
353 | err.buffer(&mut self.errors_buffer); | |
354 | } | |
355 | ||
356 | fn add_move_hints( | |
357 | &self, | |
358 | error: GroupedMoveError<'tcx>, | |
359 | err: &mut DiagnosticBuilder<'a>, | |
360 | span: Span, | |
361 | ) { | |
0bf4aa26 | 362 | let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); |
8faf50e0 | 363 | match error { |
b7449926 | 364 | GroupedMoveError::MovesFromPlace { |
8faf50e0 XL |
365 | mut binds_to, |
366 | move_from, | |
367 | .. | |
368 | } => { | |
b7449926 XL |
369 | let try_remove_deref = match move_from { |
370 | Place::Projection(box PlaceProjection { | |
371 | elem: ProjectionElem::Deref, | |
372 | .. | |
373 | }) => true, | |
374 | _ => false, | |
375 | }; | |
376 | if try_remove_deref && snippet.starts_with('*') { | |
377 | // The snippet doesn't start with `*` in (e.g.) index | |
378 | // expressions `a[b]`, which roughly desugar to | |
379 | // `*Index::index(&a, b)` or | |
380 | // `*IndexMut::index_mut(&mut a, b)`. | |
0bf4aa26 | 381 | err.span_suggestion_with_applicability( |
b7449926 XL |
382 | span, |
383 | "consider removing the `*`", | |
384 | snippet[1..].to_owned(), | |
0bf4aa26 | 385 | Applicability::Unspecified, |
b7449926 XL |
386 | ); |
387 | } else { | |
0bf4aa26 | 388 | err.span_suggestion_with_applicability( |
b7449926 XL |
389 | span, |
390 | "consider borrowing here", | |
391 | format!("&{}", snippet), | |
0bf4aa26 | 392 | Applicability::Unspecified, |
b7449926 | 393 | ); |
8faf50e0 | 394 | } |
b7449926 XL |
395 | |
396 | binds_to.sort(); | |
397 | binds_to.dedup(); | |
398 | self.add_move_error_details(err, &binds_to); | |
8faf50e0 | 399 | } |
b7449926 | 400 | GroupedMoveError::MovesFromValue { mut binds_to, .. } => { |
8faf50e0 XL |
401 | binds_to.sort(); |
402 | binds_to.dedup(); | |
b7449926 XL |
403 | self.add_move_error_suggestions(err, &binds_to); |
404 | self.add_move_error_details(err, &binds_to); | |
405 | } | |
406 | // No binding. Nothing to suggest. | |
407 | GroupedMoveError::OtherIllegalMove { .. } => (), | |
408 | } | |
409 | } | |
8faf50e0 | 410 | |
b7449926 XL |
411 | fn add_move_error_suggestions( |
412 | &self, | |
413 | err: &mut DiagnosticBuilder<'a>, | |
414 | binds_to: &[Local], | |
415 | ) { | |
416 | let mut suggestions: Vec<(Span, &str, String)> = Vec::new(); | |
417 | for local in binds_to { | |
418 | let bind_to = &self.mir.local_decls[*local]; | |
419 | if let Some( | |
420 | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { | |
421 | pat_span, | |
422 | .. | |
423 | })) | |
424 | ) = bind_to.is_user_variable { | |
0bf4aa26 | 425 | let pat_snippet = self.infcx.tcx.sess.source_map() |
b7449926 XL |
426 | .span_to_snippet(pat_span) |
427 | .unwrap(); | |
428 | if pat_snippet.starts_with('&') { | |
429 | let pat_snippet = pat_snippet[1..].trim_left(); | |
430 | let suggestion; | |
431 | let to_remove; | |
432 | if pat_snippet.starts_with("mut") | |
433 | && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) | |
434 | { | |
435 | suggestion = pat_snippet["mut".len()..].trim_left(); | |
436 | to_remove = "&mut"; | |
437 | } else { | |
438 | suggestion = pat_snippet; | |
439 | to_remove = "&"; | |
8faf50e0 | 440 | } |
b7449926 XL |
441 | suggestions.push(( |
442 | pat_span, | |
443 | to_remove, | |
444 | suggestion.to_owned(), | |
445 | )); | |
8faf50e0 XL |
446 | } |
447 | } | |
b7449926 XL |
448 | } |
449 | suggestions.sort_unstable_by_key(|&(span, _, _)| span); | |
450 | suggestions.dedup_by_key(|&mut (span, _, _)| span); | |
451 | for (span, to_remove, suggestion) in suggestions { | |
0bf4aa26 | 452 | err.span_suggestion_with_applicability( |
b7449926 XL |
453 | span, |
454 | &format!("consider removing the `{}`", to_remove), | |
0bf4aa26 XL |
455 | suggestion, |
456 | Applicability::MachineApplicable, | |
b7449926 | 457 | ); |
8faf50e0 XL |
458 | } |
459 | } | |
460 | ||
b7449926 XL |
461 | fn add_move_error_details( |
462 | &self, | |
463 | err: &mut DiagnosticBuilder<'a>, | |
464 | binds_to: &[Local], | |
465 | ) { | |
466 | let mut noncopy_var_spans = Vec::new(); | |
467 | for (j, local) in binds_to.into_iter().enumerate() { | |
468 | let bind_to = &self.mir.local_decls[*local]; | |
469 | let binding_span = bind_to.source_info.span; | |
470 | ||
471 | if j == 0 { | |
0bf4aa26 | 472 | err.span_label(binding_span, "data moved here"); |
b7449926 | 473 | } else { |
0bf4aa26 | 474 | err.span_label(binding_span, "...and here"); |
b7449926 | 475 | } |
8faf50e0 | 476 | |
b7449926 XL |
477 | if binds_to.len() == 1 { |
478 | err.span_note( | |
479 | binding_span, | |
480 | &format!( | |
481 | "move occurs because `{}` has type `{}`, \ | |
482 | which does not implement the `Copy` trait", | |
483 | bind_to.name.unwrap(), | |
484 | bind_to.ty | |
485 | ), | |
486 | ); | |
487 | } else { | |
488 | noncopy_var_spans.push(binding_span); | |
8faf50e0 | 489 | } |
b7449926 XL |
490 | } |
491 | ||
492 | if binds_to.len() > 1 { | |
493 | err.span_note( | |
494 | noncopy_var_spans, | |
495 | "move occurs because these variables have types that \ | |
496 | don't implement the `Copy` trait", | |
497 | ); | |
8faf50e0 XL |
498 | } |
499 | } | |
0bf4aa26 XL |
500 | |
501 | fn borrowed_content_source(&self, place: &Place<'tcx>) -> BorrowedContentSource { | |
502 | // Look up the provided place and work out the move path index for it, | |
503 | // we'll use this to work back through where this value came from and check whether it | |
504 | // was originally part of an `Rc` or `Arc`. | |
505 | let initial_mpi = match self.move_data.rev_lookup.find(place) { | |
506 | LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => mpi, | |
507 | _ => return BorrowedContentSource::Other, | |
508 | }; | |
509 | ||
510 | let mut queue = vec![initial_mpi]; | |
511 | let mut visited = Vec::new(); | |
512 | debug!("borrowed_content_source: queue={:?}", queue); | |
513 | while let Some(mpi) = queue.pop() { | |
514 | debug!( | |
515 | "borrowed_content_source: mpi={:?} queue={:?} visited={:?}", | |
516 | mpi, queue, visited | |
517 | ); | |
518 | ||
519 | // Don't visit the same path twice. | |
520 | if visited.contains(&mpi) { | |
521 | continue; | |
522 | } | |
523 | visited.push(mpi); | |
524 | ||
525 | for i in &self.move_data.init_path_map[mpi] { | |
526 | let init = &self.move_data.inits[*i]; | |
527 | debug!("borrowed_content_source: init={:?}", init); | |
528 | // We're only interested in statements that initialized a value, not the | |
529 | // initializations from arguments. | |
530 | let loc = match init.location { | |
531 | InitLocation::Statement(stmt) => stmt, | |
532 | _ => continue, | |
533 | }; | |
534 | ||
535 | let bbd = &self.mir[loc.block]; | |
536 | let is_terminator = bbd.statements.len() == loc.statement_index; | |
537 | debug!("borrowed_content_source: loc={:?} is_terminator={:?}", loc, is_terminator); | |
538 | if !is_terminator { | |
539 | let stmt = &bbd.statements[loc.statement_index]; | |
540 | debug!("borrowed_content_source: stmt={:?}", stmt); | |
541 | // We're only interested in assignments (in particular, where the | |
542 | // assignment came from - was it an `Rc` or `Arc`?). | |
543 | if let StatementKind::Assign(_, box Rvalue::Ref(_, _, source)) = &stmt.kind { | |
544 | let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); | |
545 | let ty = match ty.sty { | |
546 | ty::TyKind::Ref(_, ty, _) => ty, | |
547 | _ => ty, | |
548 | }; | |
549 | debug!("borrowed_content_source: ty={:?}", ty); | |
550 | ||
551 | if ty.is_arc() { | |
552 | return BorrowedContentSource::Arc; | |
553 | } else if ty.is_rc() { | |
554 | return BorrowedContentSource::Rc; | |
555 | } else { | |
556 | queue.push(init.path); | |
557 | } | |
558 | } | |
559 | } else if let Some(Terminator { | |
560 | kind: TerminatorKind::Call { args, .. }, | |
561 | .. | |
562 | }) = &bbd.terminator { | |
563 | for arg in args { | |
564 | let source = match arg { | |
565 | Operand::Copy(place) | Operand::Move(place) => place, | |
566 | _ => continue, | |
567 | }; | |
568 | ||
569 | let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); | |
570 | let ty = match ty.sty { | |
571 | ty::TyKind::Ref(_, ty, _) => ty, | |
572 | _ => ty, | |
573 | }; | |
574 | debug!("borrowed_content_source: ty={:?}", ty); | |
575 | ||
576 | if ty.is_arc() { | |
577 | return BorrowedContentSource::Arc; | |
578 | } else if ty.is_rc() { | |
579 | return BorrowedContentSource::Rc; | |
580 | } else { | |
581 | queue.push(init.path); | |
582 | } | |
583 | } | |
584 | } | |
585 | } | |
586 | } | |
587 | ||
588 | // If we didn't find an `Arc` or an `Rc`, then check specifically for | |
589 | // a dereference of a place that has the type of a raw pointer. | |
590 | // We can't use `place.ty(..).to_ty(..)` here as that strips away the raw pointer. | |
591 | if let Place::Projection(box Projection { | |
592 | base, | |
593 | elem: ProjectionElem::Deref, | |
594 | }) = place { | |
595 | if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() { | |
596 | return BorrowedContentSource::DerefRawPointer; | |
597 | } | |
598 | } | |
599 | ||
600 | BorrowedContentSource::Other | |
601 | } | |
8faf50e0 | 602 | } |